Let’s 行数削減

こんにちは、冗長コード量産検定1級所持の嶋村です。

これは active? メソッドを満たす Hoge オブジェクトを配列で返してくれるメソッド。

def active_hoges hoges = Hoge.all hoges.map do |hoge| next if hoge.active? hoges.delete(hoge) end hoges.to_a end

全件取得してから非activeを削除してる。長いね。プログラミング始めたてかな。

each

each で頑張れるのでは。

最初から配列用意してそれ返せば to_a もなくて楽ね。

def active_hoges actives = [] Hoge.all.each { |hoge| actives.push(hoge) if hoge.active? } actives end

3行。ふむ。

inject

inject とかあったなぁ。

def active_hoges Hoge.all.inject([]) { |actives, hoge| actives.push(hoge) if hoge.active? } end

1行。行数は素晴らしいけど可読性はどうなんでしょう。横に長えし。

と思ったら無効な Hoge が存在するとnilで返ってきた。詰み。

reject

条件を満たす要素を配列から削除

def active_hoges Hoge.all.reject { |hoge| hoge.active? } end

いやこれ逆ーーーーー

def active_hoges Hoge.all.reject { |hoge| !hoge.active? } end

これか

と思ったら Rubocop に select 使えと怒られた

select
Hash#select は自身の要素から特定の条件を満たす要素だけを採用した新たなハッシュを生成して返すもの。Hash#rejectはその論理反転であり,自身の要素から特定の条件を満たす要素だけを取り除いた新たなハッシュを生成して返すもの。

https://qiita.com/scivola/items/8900207d04a3794dd167

これじゃん…

def active_hoges Hoge.all.select { |hoge| hoge.active? } end

したらまだ冗長と怒れれる

def active_hoges Hoge.all.select { :active? } end

でもこれだと結果がおかしい

これだと ActiveRecord_Relation#select になるのでは?やりたいのは Enumerable#select の方だな…

と思って調べると ActiveRecordのRelation は Enumerable をインクルードしてるらしい

selectもfindと同じように、引数を渡すかコードブロックを渡すか挙動が変わります。引数(カラム名)を渡した時のselectは、引数のカラムの値だけを取ってきて、その値のみが入ったオブジェクトを返すものです。( SQLクエリは “SELECT `args` FROM table_name …” のようになります)。コードブロックを渡した時のselectは、Arrayのselectです。コードブロックに渡したときtrueを返すものの配列を返します。

https://spirits.appirits.com/doruby/8831/

コードブロックを渡すと Array の select として動くらしい。

Hoge.all.select { |hoge| hoge.active? } の挙動がまさにそう。

いやまった

def active_hoges Hoge.all.select(&:active?) end

これで動いた

& 使うときはコードブロックじゃなく普通の()

ちなみにこの & については下記記事参照

before

def active_hoges hoges = Hoge.all hoges.map do |hoge| next if hoge.active? hoges.delete(hoge) end hoges.to_a end

after

def active_hoges Hoge.all.select(&:active?) end

う〜ん、短い。嬉しい。

追記

ActiveRelation を返してくれる scope 用意すればいいのでは。

配列にしたい用事があるなら to_a すればいいし。

scope :active, -> { where(...) }