LoginSignup
64
63

More than 5 years have passed since last update.

best-ruby を読んでこんな書き方できたのかと思った記法 10 選

Last updated at Posted at 2016-07-24

いろいろな Ruby の記法をまとめている best-ruby を読んで、こんな書き方できたんだなあと思ったものをまとめました。

1. |= による代入

| は和集合を表す演算子ですが、

[1, 2, 3] | [2, 4]
#=> [1, 2, 3, 4]

= をつけると、和集合をそのまま変数に代入出来ます。

array = [1, 2, 3]
array |= [2, 4]

p array
#=> [1, 2, 3, 4]

<< を使って同じ事するよりちょっと簡単に書けます。

array = [1, 2, 3]

array << 2
array << 4

p array.uniq
#=> [1, 2, 3, 4]

ちょっと便利。

2. Array#assoc

下記のように、配列の配列を Hash のように扱い、キーに対応する値を取得出来ます。

a = [%w(key1 value1), %w(key2 value2)]

a.assoc('key1')
#=> ["key1", "value1"]
a.assoc('key2')
#=> ["key2", "value2"]
a.assoc('key3')
#=> nil

rassoc で値から取得する事もできます。

a.rassoc('value1')
#=> ["key1", "value1"]
a.rassoc('value2')
#=> ["key2", "value2"]

あんまり、こういう形式で配列持つことないけど、何かの時に使えるかな...?

3. Kernel#at_exit

与えられたブロックを、プログラム終了時に実行します。

3.times do |i|
  at_exit { puts "at_exit#{i}" }
end

at_exit { puts 'at_exit' }

puts 'main_end'

# result
# main_end
# at_exit
# at_exit2
# at_exit1
# at_exit0

先に記述した式ほど、後に実行されます。

また、END でも同じことが出来ますが、ブロック内に記述した場合は最初の一回しか有効になりません。

3.times do |i|
  END { puts "END#{i}" }
end

END { puts 'END' }

puts 'main_end'

# result
# main_end
# END
# END0

ちょっとしたスクリプト書く際に使えるかも。

4. #{} で囲まなくても文中の変数を表示できる

インスタンス変数、クラス変数、グローバル変数は #{} で囲む必要がなかったみたいです。

@instance = 'インスタンス変数'
@@class = 'クラス変数'
$global = 'グローバル変数'
variable = '変数'
CONSTANT = '定数'

"#@instance, #@@class, #$global, #variable, #CONSTANT"
#=> "インスタンス変数, クラス変数, グローバル変数, #variable, #CONSTANT"

@, $ で変数って見分けがつくからですかね?
少しでもタイプ数を減らしたい!という方は!チーム開発で入れたら怒られそうだけど...

5. dump オプション

Ruby を実行する際に dump オプションを渡すと実行の debug などを出力してくれます。

ruby -e 'puts { is_this_a_block }' --dump parsetree
ruby -e 'puts { is_this_a_block }' --dump parsetree_with_comment

# Output yacc's debug info when ruby parsing code.
ruby -e 'puts { is_this_a_block }' --dump yydebug

# Check ruby code syntax whether OK.
ruby -e 'puts { is_this_a_block }' --dump syntax

# Output yarv instructions info of compiled ruby code.
ruby -e 'puts { is_this_a_block }' --dump insns

シンタックスにミスがないか見てくれる --dump syntax は良いですね。

6. C の printf みたいに % で変数を表示する

"#{...}" こう表示する以外の選択肢を考えたことなかったんですが、%で変数を渡せるんですね。

puts '%s: %03d' % ['Num', 42]
#=> Num: 042
puts '%s: %f' % ['Num', 42]
#=> Num: 42.000000

フォーマット指定するときわざわざ sprintf 使っていたので、知れてよかった。

7. begin ... で複数行キャッシュする

ワンライナーの場合は、インスタンス変数などを ||= でよくキャッシュしますが、

def hoge
  @hoge ||= 'hogehoge' 
end

複数行の場合は、以下のようにしないとキャッシュ出来ないと思ってました。

def hoge
  return @hoge if @hoge

  a = 'hogehoge'
  b = 'fugafuga'
  @hoge = a + b
end

||= begin ... end と書いてもキャッシュされるんですね。

def hoge
  @hoge ||= begin
    a = 'hogehoge'
    b = 'fugafuga'
    a + b
  end
end

これはいろいろなところで使えそうだ!!

8. Hash#fetch

Hash#fetch でも Hash の値を取得することが出来るんですね。

params = {var: 42}

params.fetch(:var)
#=> 42

指定した key がなかった場合に nil じゃなくて、値を指定できるのが良いですね。

params[:missing]
#=> nil
params.fetch(:missing, 42)
#=> 42
params.fetch(:missing) {|key| "#{key} is not found" }
#=> "missing is not found"

default を指定しないと例外を発生します。

params.fetch(:missing)
#=> KeyError: key not found: :missing
#   from (pry):64:in `fetch'

必須のパラメーターで

raise if params[:id].nil?

みたいなブロックを入れてる場合は fetch を使った方がいいですね。

9. PStore, YAML::Store

わざわざ DB 用意したくないけど、ちょろっとデータストア使いたいって時に便利です。

require 'pstore'

db = PStore.new('mydatabase.pstore')

db.transaction do
  db[:name1] = 'hogehoge さん'
  db[:age1] = 20
end

db.transaction do
  db[:name2] = 'fugafuga さん'
  db[:age2] = 30
end

これで mydatabase.pstore にバイナリファイルで保存されます。データを読み込みたい場合は、transaction(true) としてあげます。

require 'pstore'

db = PStore.new('mydatabase.pstore')

db.transaction(true) do
  p db[:name1]
  p db[:age1]
  p db[:name2]
  p db[:age2]
end

# => "hogehoge さん"
# 20
# "fugafuga さん"
# 30

良いですね!ただ、name1, name2 のように key を変えないといけないのがなあ...。DB のようには使えないか。
ちなみに 存在する key を調べたい場合は #roots を呼びます。

db.transaction { db.roots }
#=> [:name1, :age1, :name2, :age2]

毎回 #transaction を呼び出さないといけないのも辛い...。

また、PStore はバイナリ形式で保存しますが、YAML::Store を使うと、YAML で保存することも出来ます。

require 'yaml/store'
db = YAML::Store.new('mydatabase.yml')

db.transaction do
  db[:name1] = 'hogehoge さん'
  db[:age1] = 20
end

db.transaction do
  db[:name2] = 'fugafuga さん'
  db[:age2] = 30
end

#=> ---
# :name1: hogehoge さん
# :age1: 20
# :name2: fugafuga さん
# :age2: 30

簡単!
不便な点はありますが、使い方は簡単なので、これもちょっとしたスクリプト書く際に便利ですね。

10. ObjectSpace

ObjectSpace.each_object(String) do |object|
  p object
end

実行するとすごいことになります。。。
ObjectSpace.each_object(String) で存在している String クラスのオブジェクトを全部取ってきて、イテレートするんですね。ObjectSpace なんてクラスがあったとは。

ちなみにクラスごとのオブジェクトの数は count_objects で取れるようです。

ObjectSpace.count_objects
#=> 
{:TOTAL=>939121,
 :FREE=>463526,
 :T_OBJECT=>19063,
 :T_CLASS=>11016,
 :T_MODULE=>1823,
 :T_FLOAT=>12,
 :T_STRING=>261008,
 :T_REGEXP=>4040,
 :T_ARRAY=>65256,
 :T_HASH=>7917,
 :T_STRUCT=>762,
 :T_BIGNUM=>15,
 :T_FILE=>19,
 :T_DATA=>57822,
 :T_MATCH=>198,
 :T_COMPLEX=>1,
 :T_RATIONAL=>903,
 :T_SYMBOL=>1115,
 :T_NODE=>41880,
 :T_ICLASS=>2745}

以上です!まだまだ、知らない記法・メソッドがいっぱいあるなあ!

64
63
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
64
63