1/27(水)にNTT-ATさんの会議室にてkawasaki.rb #032を開催しました。
togetterのまとめはこちら
パーフェクトRuby読書会
「5-1-4 繰り返し処理」まで終えました。
4-3-2 オブジェクトの変更を禁止する
Object#freezeを呼び出すと、レシーバへの破壊的な操作を禁止することができます。
1
2
3
4
s = "hoge"
s.freeze # 変更を禁止する
s.frozen? # => true
s << "2" # can't modify frozen String (RuntimeError)
以下のように、Hashの変更も禁止されます。
1
2
DEFAULT_CONST = {foo: 123}.freeze
DEFAULT_CONST[:foo] = 456
ただし、以下のような再代入は禁止されません。
1
2
3
i = 1
i.freeze # 変更を禁止する
i += 2 # 再代入なので例外は発生しない
4-3-3 オブジェクトをコピーする
オブジェクトをコピーするにはObject#dupやObject#cloneを用います。どちらのメソッドも汚染状態を含めてコピーされます。
1
2
3
4
5
6
7
8
9
10
11
original = Object.new
p original.object_id # => 70295490884320
original.freeze
dup = original.dup
p dup.object_id # => 70295490884200
p dup.frozen? # => false
clone = original.clone
p clone.object_id # => 70138977021500
p clone.frozen? # => true # cloneではfreezeの情報もコピーされる
Arrayでの挙動も調べてみました
1
2
3
4
5
6
7
8
value = 'foo'
array = [value]
array_dup = array.dup
array_clone = array.clone
p value.object_id # => 70265087245460
p array_dup[0].object_id # => 70265087245460
p array_clone[0].object_id # => 70265087245460
dupした配列に破壊的な変更を加えてみます。
1
2
3
array_dup[0] << "2"
p array_dup[0] # => "foo2"
p array[0] # => "foo2"
このように、オリジナルのarrayにも破壊的な変更が加えられます。
これを避けるには、 Marshal.load/dump
を使用してコピーすればよいのではないか?という話題になりました。
1
2
3
4
5
array_dump = Marshal.load(Marshal.dump(array))
p array_dump[0].object_id # => 70265086490020
array_dump[0] << "0"
p array_dump[0] # => "foo20"
p array[0] # => "foo2"
この場合、コピー先の破壊的変更はオリジナルに影響を与えません。(ただしパフォーマンスは度外視)
4-3-4 汚染されたオブジェクト
Rubyには、セーフレベルという危険な操作を防ぐ機能があります。
※セーフレベル2以降は2.3.0より廃止されました。くわしくはこちらをご確認ください。
Rubyでは、外部から入力されたものは汚染されたオブジェクトとして扱われます。オブジェクトが汚染されているかどうかはObject#tainted?で確認できます。
1
2
3
4
5
6
7
p $SAFE # => 0
p ENV['HOME'].tainted? # => true
o = Object.new
p o.tainted? # => false
o.taint # オブジェクトを汚染させる
p o.tainted? # => true
一度上げたセーフレベルを下げることはできません。
1
2
3
4
$SAFE = 1
$SAFE = 0 # => SecurityError: tried to downgrade safe level from 1 to 0
rcfile = ENV["HOME"] + '/test_file'
セーフレベル1では、汚染されたオブジェクトを使ってファイルを削除することを禁止できます。 ※なおpryで試した場合、pryの履歴を残す挙動によりファイル操作以外でも例外が発生することが確認されました。
1
2
3
4
$SAFE = 1
rcfile = ENV["HOME"] + '/test_file'
File.unlink rcfile # unlink: Insecure operation - unlink (SecurityError)
5章
5-1 Numeric
全ての数値クラスはNumericクラスから派生します。
1
2
3
4
5
6
p Integer.ancestors # => [Integer, Numeric, Comparable, Object, PP::ObjectMixin, Kernel, BasicObject]
p Float.ancestors # => [Float, Numeric, Comparable, Object, PP::ObjectMixin, Kernel, BasicObject]
p Rational.ancestors # => [Rational, Numeric, Comparable, Object, PP::ObjectMixin, Kernel, BasicObject]
p Complex.ancestors # => [Complex, Numeric, Comparable, Object, PP::ObjectMixin, Kernel, BasicObject]
p Fixnum.ancestors # => [Fixnum, Integer, Numeric, Comparable, Object, PP::ObjectMixin, Kernel, BasicObject]
p Bignum.ancestors # => [Bignum, Integer, Numeric, Comparable, Object, PP::ObjectMixin, Kernel, BasicObject]
数値クラスには、いくつかの述語メソッドが定義されています。
その中の zero?
や nonzero?
はいつ使えば良いのか?という話になり、以下のように使うことでスマートに記述することができる、という話になりました。
1
2
3
4
ary = [1, 0, 3]
p ary.select(&:zero?) # => [0]
p ary.reject(&:zero?) # => [1, 3]
p ary.select(&:nonzero?) # => [1, 3]
5-1-1 算術演算
除算はInt同士だと結果もIntになる、という話をしました。
1
2
3
4
5
6
p 10 / 3 # => 3
p 10.0 /3 # => 3.3333333333333335
num = 10
p num / 3 # => 3
p num.to_f / 3 # => 3.3333333333333335
5-1-2 比較演算
同値であればIntとFloatを比較してもtrueとなる、という話をしました。
1
123 == 123.0 # => true
5-1-3 丸め操作
round
, ceil
, floor
, truncate
についての挙動は以下のようになります。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
p 1.4.round # => 1
p 1.5.round # => 2
p -1.5.round # => -2
p 1.4.ceil # => 2
p 1.5.ceil # => 2
p -1.5.ceil # => -1
p -1.4.ceil # => -1
p 1.5.floor # => 1
p 1.4.floor # => 1
p -1.4.floor # => -2
p 1.5.truncate # => 1
p -1.5.truncate # => -1
p 1.6.truncate # => 1
p 1.7.truncate # => 1
p 1.9.truncate # => 1
p -0.9.truncate # => 0
p -1.9.truncate # => -1
5-1-4 繰り返し処理
繰り返しのためのメソッドとしてNumeric#step
があります。
1
2
3
4
5
6
3.step 5 do |num|
puts num
end
# 3
# 4
# 5
第二引数に増加していく数値を指定できます。
1
2
3
1.2.step 2.0, 0.2 do |num|
puts num
end
他にもよく使うメソッドとして upto
があります。
1
2
3
3.upto(5) do |num|
puts num
end
今回のiruby notebookは以下のとおりです。
セッション
今日はLTの発表はなく、RubyおよびRailsについてのトークをしました。
RailsのEnum使ってる?
Rails4で追加されたEnumですが、プロダクションでどれだけ使っているか?という質問がありました。
会場ではあまり意識的に使っているようではありませんでしたが、同一クラス内で重複するキーが使えないなど、ハマりどころはありそうです。
また、同じハマりどころとしてdefault_scopeがあげられました。
参考: Railsのdefault_scopeは悪だ!(default_scope is evil) ということらしい
管理画面どうやって作ってる?
Railsでサービスを作る際、管理画面をどのように作っているかという質問がありました。
回答としてRailsAdminを使うか、Gemに依存したくなければScaffoldで作った方が良い、ということがあげられました。
また、RailsのMountable Engineを使う方法もあげられました。
次回予告
次回は2016/2/24(水)開催予定です。ご参加お待ちしております。
寄稿者について
松久保 敬人 (@Peranikov)
RailsからiOSアプリ開発を経て今はDDDとScalaの人。
お酒を投稿するサイトPuhaar!を運営しています。