Ruby Goldへの道 day1
以下のサイトでruby gold取得に向けて毎日一回Goldチャレンジを行い間違えた問題を簡単にまとめる。 rex.libertyfish.co.jp
簡単な自己紹介
1日目 得点 32点/100点中
50問中16問正解。逆に言うと34問間違い。。。
間違えた問題について復習する
- selfはnewされたオブジェクトのクラス
class Fuga def initialize p self.class end end class Hoge < Fuga end Hoge.new #=> Hoge
- 特異クラス内で宣言されたメソッドは特異メソッド
class Hoge class << Hoge def fuga '特異メソッドだよん' end end def fuga 'インスタンスメソッドだよん' end end p Hoge.new.fuga #=> "インスタンスメソッドだよん" p Hoge.fuga #=> "特異メソッドだよん"
-t, -fオプションはない
オープンクラスによる影響をローカルにとどめる為にRefinementがある
RefinementはModule#refineで呼び出すことができModule#usingで定義したRefinementを有効化できる
class Hoge def fuga 200 end end module R refine Hoge do # Refinementを呼び出す def fuga 100 end end end puts Hoge.new.fuga #=> 200 using R # Refinementを有効か puts Hoge.new.fuga #=> 100
- Procはcallの際に引数の数を省略され不足の引数にはnilが代入される
local = 0 p1 = Proc.new { |arg1, arg2| arg1, arg2 = arg1.to_i, arg2.to_i local += [arg1, arg2].max } p1.call("1", "2") #=> 2 p1.call("7", "5") #=> 2 + 7 = 9 p1.call("9") #=> 9 + 9 = 18 p local # => 18
- 定数はレキシカルに決定される
レキシカル...静的??
module M1 class C1 CONST = "class_C1" end class C2 < C1 CONST = "class_C2" module M2 CONST = "module_M2" class Ca CONST = "class_Ca" end class Cb < Ca p CONST #=> "module_M2" end end end end
- ブロック引数は仮引数の中で最後に記述する
def hoge(&block, *args) block.call(*args) end hoge(1,2,3,4) do |*args| p args.length > 0 ? "hello" : args end
- initializeはpublicなどでアクセス修飾子をつけたとしても、privateから変わることはない。
class Hoge public def initialize end end p Hoge.new.private_methods.include? :initialize #=> true
- loadはrequire同様に外部ライブラリを読み込む
外部ライブラリではなくモジュールを読み込むとエラーになる
module M def foo super puts "M#foo" end end class C2 def foo puts "C2#foo" end end class C < C2 def foo super puts "C#foo" end load M end C.new.foo #=> no implicit conversion of Module into String (TypeError)
- method_missingは継承チェーンをたどった末にメソッド が見つからなかったら呼び出される
module M def method_missing(id, *args) puts "M#method_missing" end end class A include M def method_missing(id, *args) puts "A#method_missing" end end class B < A def method_missing(id, *args) puts "B#method_missing" end end obj = B.new obj.dummy_method #=> B#method_missing
- クラス/モジュールに定義されているクラス変数 name の値を返す
class S @@val = 0 def initialize @@val += 1 end end class C < S class << C @@val += 1 end def initialize @@val += 1 super end end C.new C.new S.new S.new p C.class_variable_get(:@@val) #=> 7
- キーワード引数は省略することができない
def foo(arg:) puts arg end foo 100 #=> wrong number of arguments (given 1, expected 0; required keyword: arg) (ArgumentError)
- クラス変数が更新されるタイミング
クラスメソッドが定義された
C.newが呼び出された
superからCのinitializeを呼び出された
S.newが呼び出された
class S @@val = 0 def initialize @@val += 1 end end class C < S class << C @@val += 1 end end C.new C.new S.new S.new p C.class_variable_get(:@@val) #=> 5
- Dateクラス同士の減算はRationalになる
require 'date' d = Date.today - Date.new(2015,10,1) p d.class #=> Rational
- Procオブジェクトをメソッドで実行するにはブロックに変換する必要がある
val = 100 def method(val) yield(15 + val) end _proc = Proc.new{|arg| val + arg } p method(val, &_proc.to_proc) #=> 215 # &_proc.to_procと&_procはブロックに変換できる
- ブロック変数に可変長引数はそのまま受け取る
def hoge(*args, &block) block.call(args) end hoge(1,2,3,4) do |*args| p args.length < 0 ? "hello" : args #=> [[1, 2, 3, 4]] end
- each_charとto_enum(:each_char)は同じ結果が返ってくる
enum = "apple".to_enum(:each_char) # enum = "apple".each_char p enum.next #=> "a" p enum.next #=> "p" p enum.next #=> "p" p enum.next #=> "l" p enum.next #=> "e"
- 特異クラス定義の中でクラス変数を定義してもレキシカルに決定される
class C @@val = 10 end module B @@val = 30 end module M include B @@val = 20 class << C p @@val #=> 20 end end
- :fishはSymbolクラスのオブジェクト
begin print "liberty" + :fish.to_s rescue TypeError print "TypeError." rescue print "Error." else print "Else." ensure print "Ensure." end #=> libertyfishElse.Ensure.
- andは左辺が真であれば、右辺の結果を返します。左辺が偽であれば、左辺の結果を返す
優先順位が低いのでputs v2が評価される
p v1 = 1 / 2 == 0 #=> true p v2 = !!v1 or raise RuntimeError #=> true puts v2 and false #=> true
__method__
はメソッドの中で呼び出すとそのメソッドに名になる
def awesome_method __method__ end p awesome_method #=> :awesome_method
- 引数名に&を付与することでブロック引数になる
def bar(&block) block.yield end bar do puts "hello, world" #=> hello, world end
- Module.nestingはネストの状態を表示する
module SuperMod module BaseMod p Module.nesting #=> [SuperMod::BaseMod, SuperMod] end end
- superを実行した場合にもRefinementが影響する
class C end module M refine C do def m1(value) super value - 100 # 300 - 100 end end end class C def m1(value) value - 100 # 200 - 100 end end using M class K < C def m1(value) super value - 100 # 400 - 100 # Refinementが有効なのでsuperはモジュールMにあるm1を参照する end end puts K.new.m1 400 #=> 100
- String#scanはマッチした部分文字列を配列で返す
p "Matz is my tEacher".scan(/[is|my]/).length #=> 4
- attr_accessorはattr_readerとattr_writerを同時に定義したもの
class C attr_accessor :v # ここ # 同じ def v=(other) @v = other end def v @v end # 同じ attr_reader :v attr_writer :v end c = C.new c.v = 100 p c.v class C end
- 定数の探索順位はクラス内 -> スーパークラス -> クラス探索順に行われる
class Human NAME = "Unknown" def name NAME end end class Noguchi < Human NAME = "Hideyo" end puts Noguchi.new.name #=> Unknown
- between?で値を比較するためには、Comparableをincludeする必要がある
# falsetrueになるように class Company include Comparable # XXXX attr_reader :id attr_accessor :name def initialize id, name @id = id @name = name end def to_s "#{id}:#{name}" end def <=> other # YYYY self.id <=> other.id end end c1 = Company.new(3, 'Liberyfish') c2 = Company.new(2, 'Freefish') c3 = Company.new(1, 'Freedomfish') print c1.between?(c2, c3) print c2.between?(c3, c1)
class Array def succ_each(step = 1) return enum_for(:succ_each, step) unless block_given? each do |int| yield int + step end end end p [98, 99, 100].succ_each(2).map {|succ_chr| succ_chr.chr} # ["d", "e", "f"] [101, 102, 103].succ_each(5) do |succ_chr| p succ_chr.chr # "j" # "k" # "l" end
- freezeはオブジェクトの破壊的な変更を禁止する
配列の破壊的な変更を禁止するが、配列の要素の破壊的な変更は禁止しない
array = ["a", "b", "c"].freeze array.each do |chr| chr.upcase! end p array #=> ["A", "B", "C"]
require 'json' json = <<JSON { "price":100, "order_code":200, "order_date":"2018/09/20", "tax":0.8 } JSON hash = JSON.load json p hash #=> { "price"=>100, "order_code"=>200, "order_date"=>"2018/09/20", "tax"=>0.8 }
- Stringクラスはクラスメソッドnewでインスタンスを生成する
p Class.method_defined? :new #=> true p String.method_defined? :new #=> false p Class.singleton_class.method_defined? :new #=> true p String.singleton_class.method_defined? :new #=> true
- 定数の特徴
- 代入を行うと警告が発生するが、値は変更される
- 中身を直接変更した場合は値が変わる。ただし、警告は発生しない
CONST_LIST_A = ['001', '002', '003'] begin CONST_LIST_A.map{|id| id << 'hoge'} rescue end CONST_LIST_B = ['001', '002', '003'].freeze begin CONST_LIST_B.map{|id| id << 'hoge'} rescue end CONST_LIST_C = ['001', '002', '003'].freeze begin CONST_LIST_C.map!{|id| id << 'hoge'} rescue end CONST_LIST_D = ['001', '002', '003'].freeze begin CONST_LIST_D.push('add') rescue end p CONST_LIST_A #=> ["001hoge", "002hoge", "003hoge"] p CONST_LIST_B #=> ["001hoge", "002hoge", "003hoge"] p CONST_LIST_C #=> ["001", "002", "003"] p CONST_LIST_D #=> ["001", "002", "003"]