とみたまさひろ
2020-02-15
Nagano.rb #5
#naganorb
1997〜 当時は 1.1
〜2018/9 長野 Ruby で開発
2018/10〜 東京 not Ruby
最近ちょっとだけ Ruby
https://ja.wikipedia.org/wiki/アドベントカレンダー
アドベントカレンダー (Advent calendar) は、クリスマスまでの期間に日数を数えるために使用されるカレンダーである。待降節の期間(イエス・キリストの降誕を待ち望む期間)に窓を毎日ひとつずつ開けていくカレンダーである。すべての窓を開け終わるとクリスマスを迎えたことになる。
インターネット上などで、12月の1日から25日までに、特定のテーマに沿って毎日ブログなどに記事を投稿していくという企画がある。元々のアドベントカレンダーになぞらえて、この企画もアドベントカレンダーと呼ばれている。特にプログラミングに関連するアドベントカレンダーの企画が多数行われている。
対話型Ruby
Ruby 2.7 で大幅に機能向上
入力1文字毎に処理してるため
きっとそのうち改善される
ブロック引数には名前をつける必要があった
[5, 2, 4, 1, 3].sort { |a, b| a <=> b } #=> [1, 2, 3, 4, 5]
いちいち名前を考えなくてもいい場合
_
+数字(1〜9) を使えるようになった
[5, 2, 4, 1, 3].sort { _1 <=> _2 } #=> [1, 2, 3, 4, 5]
_1
, _2
, … は今までローカル変数だったので
混在させると warning
_2 = 99
[5, 2, 4, 1, 3].sort { _1 <=> _2 } #=> [5, 2, 4, 1, 3]
# warning: `_2' is reserved for numbered parameter;
# consider another name
他の言語にはあるらしい(しらない)
ArrayやHashなどのオブジェクトの構造をマッチング
(experimental)
Array
obj = [0, [1, 2, 3]]
case obj
in [a, [b, *c]]
p a #=> 0
p b #=> 1
p c #=> [2, 3]
end
Hash
obj = {a: 0, b: 1, c: 2}
case obj
in {a: 0, x: 1}
# ここは通らない
in {a: 0, b: var}
p var #=> 1
end
適合するパターンが無ければエラー
obj = [1, "hoge"]
case obj
in {a: var}
# 適合しない
in [a, b, c]
# 適合しない
end
#=> [1, "hoge"] (NoMatchingPatternError)
elseも書ける
obj = [1, "hoge"]
case obj
in {a: var}
# 適合しない
in [a, b, c]
# 適合しない
else
"no match"
end
#=> "no match"
ifで条件指定も
def hoge(obj)
case obj
in [a, b] if a == b.to_i
true
else
false
end
end
hoge [123, "123"] #=> true
hoge [123, "456"] #=> false
hoge "xxxx" #=> false
型(クラス)指定
def hoge(obj)
case obj
in [String => s, Integer => n]
s * n
in [a, b]
a + b
end
end
hoge ["abc", 2] #=> "abcabc"
hoge [3, 4] #=> 7
組み込みクラスだけじゃなくて
自分でもパターン定義可能らしい
詳しくは RubyKaigi 2019 の発表を
Pattern matching - New feature in Ruby 2.7
https://rubykaigi.org/2019/presentations/k_tsj.html
Rubyのキーワード引数はHashの表記を使用
{:hoge => 123, :fuga => 456}
キーがシンボルの場合 (Ruby 1.9〜)
{hoge: 123, fuga: 456}
def foo(a, b, opts)
a #=> 1
b #=> 2
opts #=> {hoge: 123, fuga: 456}
end
foo(1, 2, {hoge: 123, fuga: 456})
引数末尾のHashは {
}
を省略可
def foo(a, b, opts)
a #=> 1
b #=> 2
opts #=> {hoge: 123, fuga: 456}
end
foo(1, 2, hoge: 123, fuga: 456)
キーワード引数っぽい
Ruby 2.0〜
def foo(a, b, hoge: nil, fuga: nil)
a #=> 1
b #=> 2
hoge #=> 123
fuga #=> 456
end
foo(1, 2, hoge: 123, fuga: 456)
def foo(hash={}, key: nil)
end
foo({a: 123})
# `foo': unknown keyword: :a (ArgumentError)
def foo(hash={}, key: nil)
hash #=> {"a"=>123}
key #=> 456
end
h = {"a" => 123, :key => 456}
foo(h)
Ruby 3 では Hash とキーワード引数を分離する予定
そのために 2.7 で warning
def foo(hash={}, key: nil)
end
h = {:key => 456}
foo(h)
# warning: Using the last argument as keyword parameters is
# deprecated; maybe ** should be added to the call
def foo(hash={}, key: nil)
end
h = {"a" => 123, :key => 456}
foo(h)
# warning: Splitting the last argument into positional
# and keyword parameters is deprecated
範囲オブジェクトのリテラル表記
r = (3..9)
2.6 から終端省略可能
r = (3..)
r.each { |i| p i } # 無限ループ
r = (..9)
# イテレータとしては使えない
r.each { |i| p i } # can't iterate from NilClass
# 両端省略は不可
r = (..) # syntax error, unexpected ')'
require 'sequel'
db = Sequel::Database.new
db[:table].where(col: 3..9).sql
#=> SELECT * FROM table WHERE ((col >= 3) AND (col <= 9))
db[:table].where(col: 3..).sql
#=> SELECT * FROM table WHERE (col >= 3)
db[:table].where(col: ..9).sql
#=> SELECT * FROM table WHERE (col <= 9)
メソッド呼び出しは .
の前後で改行可能
"hoge".upcase
"hoge".
upcase
"hoge"
.upcase
.
終わりの行の後にコメント行を挟む
"hoge".
# コメント
upcase
2.7からはこっちも可能
"hoge"
# コメント
.upcase
フラグメント化したメモリを再配置
「GC」?
長時間動き続けるプロセスで
肥大化したプロセスメモリを小さくできるかも
require 'date'
Date.today.jisx0301 #=> "R02.02.15"
「プロと読み解くRuby 2.7 NEWS」
https://techlife.cookpad.com/entry/2019/12/25/121834