LL温泉2008 Rubyチュートリアル


LL温泉2008 Rubyチュートリアル
を見てたらチュートリアルがもっさりあったのでやってみた。


回答例も公開されているようです。


最初は

オブジェクトにメソッドを追加する方法(slide45)
当初この辺りを調べてたんだけど。。。気付いたらチュートリアルやってた。。。
・def obj.foo
・fooを持ったモジュールをobjにextend
・objのクラスでdef foo
・fooを持ったモジュールをクラスにinclude

チュートリアル

slide#21
カウントさせよう
obj = Object.new
def obj.count_up
  # この中身を書くだけでできるはず
end
obj.count_up #=> 1
obj.count_up #=> 2
obj.count_up #=> 3
obj = Object.new
def obj.count_up
  @count ||= 0
  @count += 1
end
>> obj.count_up
=> 1
>> obj.count_up
=> 2
>> obj.count_up
=> 3
slide#29 1
文字列の中から数字のみを抜き出すpickup_numberメソッド
def pickup_number(str)
  str.scan(/\d+/)
end
str = "aaa123bbb456ccc"
pickup_number str
slide#29 2
SymbolかStringのオブジェクトを渡すと、末尾に _onsen が付いたSymbolを返す onsenizeメソッド
def onsenize(opt)
  "#{opt}_onsen".to_sym if opt.kind_of?(String) or opt.kind_of?(Symbol)
end
onsenize 'hoge'
onsenize :fuga
onsenize ['mogu']
slide#29 3
s = "ABC" に対して以下の違いは何?
s << "D"
s += "D"

問題の意図がよくわかんなかったけど
+を使うと新しい文字列オブジェクトが作られるってことでいいのかな?




slide31 1
get_at([1,2,3], :first) => 1
get_at([1,2,3], :last) => 3
となるようなget_atメソッド
def get_at(ar, sym)
  return ar[0] if sym == :first
  return ar[-1] if sym == :last
end
?> get_at([1,2,3], :first)
=> 1
>> get_at([1,2,3], :last)
=> 3


回答より抜粋

def get_at(array, position)
  array.send(position)
end

なるほど。こういう書き方もできるのか。

slide31 2
カンマ区切りの文字列をバラして、ソートするsplit_sortメソッド
def split_sort(str)
  str.split(',').map(&:strip).sort
end

?> split_sort 'def,123,abc,foo'
=> ["123", "abc", "def", "foo"]
>> split_sort 'def, 123, abc, foo'
=> ["123", "abc", "def", "foo"]
slide31 3
数値のみで構成される配列の要素の合計を求めるsum_arrayメソッド
def sum_array(ar)
  ar.inject(0){ |sum,i| sum += i }
end
>> sum_array([1,2,3,4,5])
=> 15
slide33 1
Hashと文字列を渡すと、キーの一部が該当する値を配列で返す、select_valuesメソッド
def select_values(hash, val)
  hash.find_all{ |k,v| k.to_s.include?(val) }.map{ |x| x[1] }
end

?> select_values({:a => 'abc', :aa => 'aabbcc', :x => '123'}, 'a')
=> ["abc", "aabbcc"]
>> select_values({:a => 'abc', :aa => 'aabbcc', :x => '123'}, 'x')
=> ["123"]

これは最後のmapがダメだなぁ。


回答より抜粋

def select_values(hash, search)
  hash.map{|key,value| value if key.include?(string)}.compact
end

なるほど。mapで取り出して、条件に合わないもの(nil)はcompactで取り除くと。

slide33 1
複数のHashの足し算をするmerge_hashメソッド(キーが重複したら上書きね)。
def merge_hash(*hashes) って感じで
def merge_hash(*hashes)
  hashes.inject({}) { |hash_all, h| hash_all.merge!(h) }
end

hash1 = {:a => 'abc', :aa => 'aabbcc', :x => '123'}
hash2 = {:b => 'bcd', :bb => 'bbccdd', :y => '456'}
hash3 = {:a => 'cde', :aa => 'ccddee', :x => '789'}
merge_hash(hash1, hash2, hash3)
slide33 1
どんなHashでもJSONのオブジェクトになる文字列 "{'キー': '値'}"にしちゃう、to_jsonメソッド
class Hash
  def to_json
    res = []
    self.each do |k,v|
      if v.kind_of?(Hash)
        res << "'#{k.to_s}': '#{v.to_json}'"
      else
        res << "'#{k.to_s}': '#{v}'"
      end
    end
    "{#{res.join(',')}}"
  end
end


h = {:a => 'abc', :aa => 'aabbcc', :x => '123'}
h.to_json

#配列の入れ子
hash1 = {:a => 'abc', :aa => 'aabbcc', :x => '123'}
hash2 = {:b => 'bcd', :bb => 'bbccdd', :y => '456', :hash => hash1 }
hash2.to_json()


と書いてみたが、「どんなHash」の意味を取り違えていた。
回答を見るとArrayを考慮している。

def to_json(obj)
  if obj.is_a?(Hash)
    '{' << obj.map{|key, value| "'#{key.to_s}': #{to_json(value)}" }.join(',') << '}'
  elsif obj.is_a?(Array)
    '[' << obj.map{|item| to_json(item)}.join(',')  << ']'
  elsif obj.is_a?(String)
    "'#{obj.to_s}'"
  else
    obj.to_s
  end
end
to_json(tree1)
slide34
可変引数で、最後は名前付きの引数
obj.foo(1, 2, '3')
 => [1, 2, 3] {:name => "A", :no => 1}
obj.foo(1, 2, :name => "B")
 => [1, 2] {:name => "B", :no => 1}
obj.foo(:name => "B")
 => [] {:name => "B", :no => 1}
というfooをよろしく


この問題よくわかんないけど書いてみた。

obj = Object.new
def obj.foo(*options)
  name = 'A'
  no = 1

  if options[-1].kind_of?(Hash)
    name = options[-1][:name] if options[-1].has_key?(:name)
    no   = options[-1][:no]   if options[-1].has_key?(:no)
  end

  hash = { :name => name, :no => no }
  "#{options[0...-1].inspect} #{hash.inspect}"
end

obj.foo(1, 2, 3)
obj.foo(1, 2, :name => "B")
obj.foo(:name => "B")
slide43
左のコードを実行したら、下のように出力されるlogメソッド。
{}のブロックは、do...endに置き換えた方が分かるかも。

def foo
  log("in foo"){ yield("FOO") }
end
def bar
  log("in bar") do
    foo do |v|
      log("in block for foo"){ yield(v) }
    end
  end
end
bar do |v|
  log("in block for bar"){ v * 3 }
end

in bar before
in foo before
in block for foo before
in block for bar before
in block for bar after
in block for foo after
in foo after
in bar after
=> "FOOFOOFOO"


全然分からんかったけど、書いたら動いた。。。

def log(msg)
  puts "#{msg} before"
  yield(msg)
  puts "#{msg} after"
end
slide53 1
文字列の配列から各要素をn回繰り返し、それらをカンマで区切った文字列を返す
repeat_joinメソッド
def repeat_join(strings, count=1)
  strings.map{|str| string*count }.join(',')
end

?> repeat_join(['A','B','XYZ'])
=> "A,B,XYZ"
?> repeat_join(['A','B','XYZ'], 10)
=> "AAAAAAAAAA,BBBBBBBBBB,XYZXYZXYZXYZXYZXYZXYZXYZXYZXYZ"
slide53 2
数値のみで構成される配列の要素から奇数を抽出して合計を出すodd_sumメソッド
def odd_sum(numbers)
  numbers.inject(0){ |sum, i| sum += (i % 2 == 1)? i : 0 }
end

odd_sum([1,2,3,4,5])