blog.waterlow.work

Ruby, Rails, js, etc...

【備忘録】Atomの今後使っていきたいキーバインディング

目的

勉強の復習と自分用チートシート目的。 最近Atom実践入門という本を読んで、まだまだAtomには知らない機能がたくさんあることを改めて感じました。

Atom実践入門──進化し続けるハッカブルなエディタ (WEB+DB PRESS plus)

Atom実践入門──進化し続けるハッカブルなエディタ (WEB+DB PRESS plus)

特にキーバインドに関しては、マウスカーソルでやるものをキーボードで完結させることができるためいろいろなことを効率化できる可能性があるのですが、いかんせん覚えづらいです。
そこで今回は、復習と自分用チートシート目的で、使えそうなキーバインドをまとめてみることにしました。

キーバインドまとめ

カーソル移動系

alt-shift-v:ページ最上部(カスタマイズ
alt-v :1ページ上(カスタマイズ
alt-shift-v:1行上
ctrl-b:1つ左
alt-b:1単語左
ctrl-a:行頭
ctrl-f:1つ右
alt-f:1単語右
ctrl-e:行末
ctrl-n:1行下
ctlr-v :1ページ下(カスタマイズ
ctrl-shift-v:ページ最下部(カスタマイズ

文字列操作系

ctrl-h:1文字削除(backspace)
ctrl-d:1文字削除(delete)
alt-h:1単語削除(backspace)
alt-d:1単語削除(delete)

検索系(cmd-fかcmd-shift-Fで検索窓を開いてから)

shift, shift-tab:テキストフィールドを行ったり来たり
alt-cmd-/正規表現使う/使わない([.*]みたいなボタン)
alt-cmd-c:大小文字区別しない/する([Aa]みたいなボタン)

その他

cmd-r:関数定義(symbols view)

Git Plus系

要インストール
shift-cmd-a a:add all & commit
shift-cmd-h:Git Plusの操作一覧(コマンドパレット風fizzy finder)

※以下キーバインドではないですが、よく使いそうなので
操作一覧でplを入力してenter:git pull
操作一覧でnb〃:git checkout -b
操作一覧でda〃:git diff

term3系

要インストール
cmd-k t t:ターミナルオープン

まとめ

ひとまず、今後使っていこうというキーバインドのみまとめてみました。自分用備忘録なので、今後もちょいちょいちょい追加していこうと思います。
いろんな人のキーバインドやおすすめパッケージ等知りたいな-と思いました。
あと、基本的に「エンター以外はホームポジションから動かないようにする」がモチベーションだったのですが、ちょいちょいカスタマイズしているうちに、emacsvimキーバインドそのまま使ったほうがいいかなという気がしてきました^^;

やること

この記事のアップデート
暇な時にキーバインドやパッケージを調べる

参考

blog.jnito.com

【Rails】DatabaseCleaner導入でテストが遅くなった話

現在仕事のrailsプロジェクトで、feature specの導入のところでdatabase_cleanerの設定でいろいろ時間を費やしたため、時間を費やした箇所についてまとめておこうと思います。 その時のRailsバージョン/Rubyバージョン:3.2.11/1.9.3。古い!

DatabaseCleanerとは

github.com databaseのお掃除をしてくれるgem。主にrspecやminitestの際に、「テストが終わったらテストデータを全部消したい」みたいなモチベーションで使われる。

使い方

簡潔にまとまっている記事がたくさんあるので省略します。

【Ruby on Rails】Database Cleanerによるテストデータの消去 | Developers.IO
RSpec + database_cleaner で永続的なマスターデータを扱う - 彼女からは、おいちゃんと呼ばれています

困ったところ(今回のメイン)

DatabaseCleanerを使いはじめると、急にテストが遅くなる

rspecである程度テストが書いてあるプロジェクトにDatabaseCleanerを入れてみたのですがテストが急に遅くなりました。 今回実施した導入方法は以下になります。
* Gemfile

gem 'database_cleaner'
  • spec/spec_helper.rb
RSpec.configure do |config|

  # これより前の設定は省略...
 
  # config.use_transactional_fixturesはコメントアウト
  # config.use_transactional_fixtures = true
  
  config.before(:suite) do
    DatabaseCleaner.strategy = :truncation
  end

  config.before(:each) do
    DatabaseCleaner.start
  end

  config.after(:each) do
    DatabaseCleaner.clean
  end

log/test.logをみていると、同じクエリログが何回も出ていました。よくよく調べてみるとspec/fixturesディレクトリで定義しているfixtureをテストのたびにDBにinsertしてtruncateしているようでした。DatabaseCleanerを入れるまでは以下の設定が入っていたのでfixtureは一番最初にinsertして、テスト毎に入れたり消したりされることはありません。DBのクリーンはrspecに入っている機能で行う模様です。

config.use_transactional_fixtures = true
config.global_fixtures = :all

解決方法

spec/spec_helper.rbのDatabaseCleanerのstrategyをtransactionにしました。

  # これより前の設定は省略

  # config.use_transactional_fixtures = true
  # config.global_fixtures = :all
  
  config.before(:suite) do
    DatabaseCleaner.clean_with(:truncation)
    dir = "#{Rails.root}/spec/fixtures"
    Dir["#{dir}/*.yml"].map { |f| f[(dir.size + 1)..-5] }.each do |fixture_file|
      ActiveRecord::Fixtures.create_fixtures(dir, fixture_file)
    end
  end

  config.before(:each) do
    DatabaseCleaner.strategy = :transaction
  end

  config.before(:each) do
    DatabaseCleaner.start
  end

  config.after(:each) do
    DatabaseCleaner.clean
  end

要約すると、①fixtureは自力で入れる。②DatabaseCleanerのstrategyをtransactionにする。
です。rspecのtransactionを使うとfeature specは上手く動かない場合があるのですが、DatabaseCleanerの場合はひとまず大丈夫そうでした。
テストの速度も以前通りになりました。

その他

他のプロジェクト(Rails4系)でtruncate→transactionの設定を試したところ、残念ながらテストは早くならず逆に遅くなってしまいました。
テーブル数、データ量等の違いによって結果が異なりそうなので、ベストな設定はこれ!というものはなさそう。実は、パーフェクトRuby on Railsにはfeature spec用の設定としてはまた若干違った設定が書かれています。
他にもいろいろ設定があるようで、DatabaseCleaner.strategy = :truncation:exceptというオプションを与えてtruncateするテーブルを制限する方法もあるようです。

悩んでるポイントはみんな同じ!?「Rubyistのためのテストコード相談会」の質疑応答まとめ - give IT a try

database_cleaner transactionの設定 - Qiita

まとめ

rspecやDatabaseCleanerの設定にはいろいろあるので、テストの量やDBの状態に応じてベストな設定を模索していきましょう。
もっと良い設定があればぜひ教えてほしいです!

【Ruby】配列の&と|の機能について

特殊なルールで配列を並び直す。たとえば
['いち', 'に', '', 'よん', 'なな', 'ご']
から
['に', 'よん','いち', 'ご', 'なな']
を作りたい(奇数が優先、2で割る等の数値演算はできない)ときはどうするか。
①まず以下のようにやることを思いついた。

['いち', '', '', 'よん', 'なな', '']
  .reject { |v| v.nil? || v == '' }
  .sort_by { |v| %w(に よん ろく はち いち さん ご なな).index(v) }

②ドキュメントを読んでいた時にArray#|のところで「preserving the order from the original array」という記述があり
 Array#&もやっぱりそうだった

%w(に よん ろく はち いち さん ご なな) &
['いち', '', '', 'よん', 'なな', '']

めでたしめでたし。これを期に、必要に迫られる前にドキュメントを読んでおくくせを付けておこうと思います! もっと良い方法がありましたらぜひ。

【ActiveRecord】exists?の引数にwhereクエリの内容を書いてみたらうまくいかない。

Person.exists?(1) # => true
# SELECT  1 AS one FROM `job_offers`  WHERE `job_offers`.`id` = 1 LIMIT 1
Person.exists?('id = 1') #=> false
# SELECT  1 AS one FROM `job_offers`  WHERE `job_offers`.`id` = 0 LIMIT 1

なぜか?
exists?にArrayもしくはHashを引数で渡すと、where(condition).limit(1)とほぼ同じ挙動をする。
それ以外の引数を渡すと主キーでの検索を行おうとする。
ただし、findではなくPerson.where(id: 'id = 1')が呼ばれ、(この後はソースを読み切れていないが)エラーにならずWHERE job_offers.id = 0なんてクエリが発行されてしまうらしい。

解決策
whereと同じような挙動を期待する場合はArrayもしくはHashを与えれば良い。 したがって今回の場合であれば

Person.exists?(['id = 1']) #=> true
# SELECT  1 AS one FROM `job_offers`  WHERE (id = 1) LIMIT 1

となる。(カッコが付いてしまうのは仕方なさそう。) ActiveRecord:: FinderMethods#exists?

railsエンジニアの勉強法(読む本とか)まとめ

初心者レベルを脱却するための記事とか読む本とか、いろいろと溜まってきたのでまとめておこうと思います。
勉強するのは常に一人なので、歩みは非常に鈍いのですが…

Rails で "とりあえず動くコード" を書けるようになった人が次に遭遇する問題とそれを解決してくれる本まとめ - 彼女からは、おいちゃんと呼ばれています

Rails Tutorial以前 - Web系エンジニア入門レベルを達成するには - - 国境の南

新卒ソフトウェアエンジニアのための技術書100冊 - クックパッド開発者ブログ


やること多々ですね!!
デザインパターンとかオブジェクト指向をちゃんと勉強したければJavaはある程度読めたほうが良さそう。「オブジェクト指向のこころ」という本を読んでいて思いました。

[追記 6/19]
Railsアプリケーション構築ガイド — Railsアプリケーション構築ガイド
Ruby on Rails チュートリアル:実例を使って Rails を学ぼう
Rails Girls - Japanese

【ruby】モジュールをextendした時の動き

タイトルそのまんまです。 疑問だったのでいろいろ調べてみたのですが、メタプログラミングRubyの特異クラスのところを読んでいたらわかりました。 オブジェクトからモジュールをextendすると、そのメソッドはオブジェクトのクラスではなく特異クラスに入る。

class Object
  def eigenclass
    class << self; self; end
  end
end

class C; end

module M
  def my_singleton_method
    'obj#my_singleton_method()'
  end
end

obj = C.new
obj.extend M

obj.eigenclass.instance_methods.grep(/my_/) #=>[:my_singleton_method]
obj.class.instance_methods.grep(/my_/) #=>[]

だから、もしオブジェクトに対してextendする予定のモジュールに定数とか名前空間を更に定義している場合、外からは非常にアクセスしづらい。

class C
  C_VAL = :c
end

module M
  M_VAL = :m
end

obj = C.new
obj.extend M
obj.class::C_VAL #=> :c
obj.singleton_class::M_VAL #=> :m
obj.class::M_VAL #=> uninitialized constant C::M_VAL

もし2つモジュールをインクルードするとどうなるかというと…

class C; end
module M; end
module N; end

obj = C.new
obj.extend M
obj.extend N
obj.singleton_class.ancestors
# => [M, C, Object, Kernel, BasicObject]

特異クラスで継承が行われる。

【Google Analytics】簡単!メルマガの開封数を取得する方法

お仕事で使ったTipsです。 メールマガジン(以下メルマガ)がどのくらいの人に開封されているかを探る方法のメモです。
※以下の方法はHTMLメールの開封数しか取れません。簡単に言うとimgタグを使ってサーバにリクエストを送るものです。

前提として日本語の記事があまりない

リクエストを独自のサーバに送らせて計測するやり方は各自でやっているかと思うのですが
Google Analytics メール 開封」等のキーワードで調べても大抵以下の記事のようにクリック数の取得方法を解説した記事が出てきます。

記事の中では開封率はクリック数を見るのに比べて難しいというふうな記載もあります。まだクリック数の取得はやったことがないのですが、そちらのほうが簡単なのでしょうか?

やり方

では実際どうやるのかというと、以下のやり方を参考にします。

MailChimpというアプリを使っているようですが、今回は使いません。上記のURLを参考に、以下のようなimgタグをHTMLメールに埋め込みます。

<img src="http://www.google-analytics.com/collect?v=1&tid=UA-XXXXXXX-YY&cid=*|UNIQID|*&t=event&ec=email&ea=open&el=*|UNIQID|*" />

tidにはご自身のアナリティクスのトラッキングIDを入れましょう。
cidは、送信するメールをれぞれに異なる値を設定しておけば1回でも開封されたかどうかを見ることができるようになります。
elは計測上必要(日毎に図りたいorABテストしたい…)な場合は入れましょう。erbを使って"el=#{Date.today.strftime('%Y%m%d')}_#{test ? 'A' : 'B'}"的な感じで入れればアナリティクス側で出し分けられます。

以上、メルマガ開封数を測る方法でした。アナリティクスの使い方はいろいろありそうなので、便利な使い方があったらもっと知りたいですね!

参考