Rubyに入門してみたときのhello world的なコード。
Object.methods.grepとか忘れそうなので、メモしておく。
教科書
- メタプログラミングRuby
副読本
- プログラミング言語Ruby
hello_ruby.rb
# coding:utf-8
# プログラミング言語Ruby
# 2.4.1 プログラムのエンコーディングの指定
# プログラミング言語Ruby
# 2.4.2 ソースエンコーディングとデフォルト外部/内部エンコーディング
# 9.7.2を読む必要がある。
puts Encoding.default_external #デフォルト外部エンコーディング
puts Encoding.default_internal #デフォルト内部エンコーディング
puts Encoding.locale_charmap #現在のロケール
#★コメントの練習
# この部分はコメント
=begin
この部分もコメント
=end
#★関数定義の練習
# 関数定義があとに来ていた場合、エラーになる(http://www.rubylife.jp/ini/method/index2.html)●1・・・あとで調べよう。
# かならずメソッドは実際に呼び出されるよりも前に定義されていなければならない。
def test(*param) #引数に配列を渡す場合、アスタリスクをつける
param.each { |i|
puts "test(*param) : #{i}"
}
# test(param) ☆1
end
=begin
メモ
①
testメソッド内で
test.ancestors <---継承チェーンを吐き出すObjectクラスのメソッド
をよぶと
test.rb:8: stack level too deep (SystemStackError)
が発生する。
なぜだろうか。
1. testは、ローカル変数として認識されたのか?
→main内で適当な変数でやってみるか・・・☆2
→NoMethodErrorになっちゃった。
2. それとも再帰的にtestメソッドとして認識されたのか?
→SystemStackErrorがおきるとしたら、再帰なんじゃないかなと思うが、
適当な関数をわざと再帰で呼び出すと同じエラーがでるんだろうか?☆1
→うお・・・・CTRL_C + C !。まってたら出るかもしれんが、違うような気もする。
②
・プログラミング言語 Ruby 第6章
多くの言語は、対応するオブジェクトを持たない関数とレシーバオブジェクトから起動される
メソッドを区別するが、Rubyの場合純粋オブジェクト指向言語なので、
すべてのメソッドは、本物ののメソッドであり、少なくとも一つのオブジェクトと対応付けられている。
対応するオブジェクトのないグローバル関数のようにみえるが、実は、Objectのプライベートメソッドとして、
定義されている。
・メタプログラミングRuby」の動的ディスパッチの機構を使って、呼出してみよう。★1
→できた
・「メタプログラミングRuby」のメソッドのGrep(methos.grep)により、表示してみよう。
→Object.methods.grep(/test/)では表示されなかった★2
なぜ・・・?
→プログラミング言語 Ruby 8.4.1によると、methodsは、すべてのpublicメソッドの名前
となっている。private_methodsを使おう★3
→表示された。ちなみに、Ruby v2.0だと文字列ではなくシンボル(:が付いたもの)を返す仕様になっている。v1.8では文字列。
・動的ディスパッチとprivate_methods.grepをeachで組み合わせてみる。パターンディスパッチ★4
→できた。パターンディスパッチは関数ポインタ配列の呼出しっぽい感じだな。C#のdelegateとかも同じだっけか。
想定している用途:
ログ解析でIDごとに違う解析ロジックを呼びだす(パラメータの中にさらに階層化されたログが含まれている場合)に使えるか。
その場合は、動的なrequire/include、シンボルをどう定義するか、マッチさせるパターンを考える必要があるか。
・配列をうけとらんtestって名前がを含んだprivate_methodがあったらどうすんの?死ぬの?★5
→死んだ。ArgumentErrorの例外を処理すればいいのかな?
=end
=begin
#★5 配列をうけとらんtestって名前がを含んだprivate_methodがあったらどうすんの?死ぬの?→死んだ。
# ここを有効化すると以下のエラーが発生する。
#test.rb:58:in `test2': wrong number of arguments (1 for 0) (ArgumentError)
# from test.rb:97:in `block in <main>'
# from test.rb:96:in `each'
# from test.rb:96:in `<main>'
def test2
i=i+1
puts("test2")
end
=end
#####################
#
# Hello world的な処理ここから
#
####################
puts "ruby?"
#クラスの定義
class MyClass
def test
puts "MyClass.test"
end
end
myclass = MyClass.new()
myclass.test() #=>MyClass.test
#継承
class MySubClass < MyClass
def test #オーバライドしてみる。
puts "MySubClass.test"
end
end
my_sub_class = MySubClass.new()
my_sub_class.test() #=>MySubClass.test
p my_sub_class.object_id #=>17341950
=begin
my_sub_class.set_var(5678) #=>あとでオープンクラスによって定義されるがさすがに未来の予知はできないので、test.rb:108:in `<main>': undefined method `set_var' (NoMethodError)となる。当たり前ですが。
=end
10.times { |i|
puts " #{i+1} times"
}
num = 100
p num
p num.object_id
arraytest = [0, 1, 2, 3, 4]
arraytest.each { |x| # eachに関しては、プログラミング言語Ruby 5.3.2Enumerableオブジェクトを見る。eachは、コレクションに属する個々の要素を引数として、付属ブロックを呼び出す。{}ないが付属ブロック。おそらくブロックは、引数をとれるのであろう。5.4.4 ブロックへの引数わたし。yield i,jといった形で引数を渡せる。おそらく、各コレクションでeachがオーバライドされているであろう。
puts "arraytest.each=#{x}"
}
#プログラミング言語Ruby 3.2.1.6 バッククォートによるコマンド実行
#・・・ってPathはどうなんだろね。
print `dir` #=>スクリプトのあるフォルダのようだ。`
print %x[echo %PATH%] #=>Windowsの環境変数そのもののようだ。
p Object.ancestors #=>[Object, Kernel, BasicObject]
#☆2 1. testは、ローカル変数として認識されたのか?
# →main内で適当な変数でやってみるか・・・☆2
# →NoMethodErrorになっちゃった。ブランクスルーされている?
#p num.ancestors #=>test.rb:85:in `<main>': undefined method `ancestors' for 100:Fixnum (NoMethodError)
#☆1 SystemStackErrorがおきるとしたら、再帰なんじゃないかなと思うが、適当な関数をわざと再帰で呼び出すと同じエラーがでるんだろうか?☆
#test(arraytest) #=>うお・・・・CTRL_C + C !。まってたら出るかもしれんが、違うような気もする。
#★1 動的ディスパッチにより、testを呼び出す。Object#send()を使うと、privateメソッドも強制的に呼び出すことができる。
Object.send(:test,arraytest) #=>[0, 1, 2, 3, 4]
#★2 Object.methods.grep(/test/)では表示されなかった。・・・プログラミング言語 Ruby 8.4.1 methodsは、public_methodのシンボルを返すからだ・・・
# p Object.methods #=>[:allocate, :new, :superclass, :freeze, :===, :==, :<=>, :<, :<=, :>, :>=,・・・_, :__id__]
p Object.methods.grep(/test/) #=>[]
#★3
p Object.private_methods.grep(/test/) #=>[:test]
#★4
=begin
Object.send(Object.private_methods.grep(/test/).sub(/[\[\]]/, ""), ["aaa", "bbbb"])
# grepが配列を返してくることに気がつかずsubを使おうとして、test.rb:83:in `<main>': undefined method `sub' for [:test]:Array (NoMethodError)・・・はまった・・・
=end
Object.private_methods.grep(/test/).each { |private_method_symbol|
Object.send(private_method_symbol, ["aaa", "bbbb"])
}
#3.2.1.5 ヒアドキュメント
p <<HERE
here 1st
HERE
p <<THERE
-----------
there 1st
-----------
THERE
print(str_here_doc = <<HERE + <<THERE)
here 2nd
HERE
-----------
there 2nd
-----------
THERE
p <<HERE + <<THERE
here test
HERE
there test
THERE
puts "------open class start------"
class MySubClass #オープンクラスしてみる。クラスの再オープン
@var = 0 #クラスインスタンス変数です。プライベートのメンバ変数
def set_var(var)
@var = var
end
end
my_sub_class_opened = MySubClass.new()
my_sub_class_opened.set_var(1234) #=>1234
p my_sub_class_opened.object_id #=>17335070
#オープンクラス前につくったオブジェクトでset_varできるんかな?
my_sub_class.set_var(5678) #=>できる。マジか・・・
p my_sub_class.object_id #=>さっきと同じobject_idだ!17341950.な、なんだってー。オブジェクトを再生成しているわけではないということか!
puts "------open class end------"
puts "------for-do-end start------"
for lang in ["ruby", "php", "perl"] do
puts "#{lang}"
end
puts "------for-do-end end------"
puts "------each start------"
["ruby", "php", "perl"].each { |lang|
puts "#{lang}"
}
puts "------each end------"
puts "------loop start------"
loop_index = 0
loop {
loop_index += 1
puts "#{loop_index}"
if loop_index == 3 then
break
end
}
puts "------loop end------"
puts "----method start------"
#レシーバなしで呼び出されるメソッドを関数的メソッドという
include Math
puts sqrt(2)
puts "----method end------"
puts "----inheritance start------"
class MySubSubClass < MySubClass
@var = 1111111111111
def get_var()
@var
end
end
subsubc = MySubSubClass.new()
puts subsubc.set_var(13123213213213)
puts MySubSubClass.ancestors
#puts subsubc.get_var()
puts "----inheritance end------"
# *の練習
puts("abcdefghi\n"* 20)
puts "----chop! start----"
# 破壊的メソッドをリテラルに使うと?
puts "12312".chop!
puts "12312" # 別にふつうに表示された。リテラルは、違うオブジェクトとして扱われている?
puts "12312".object_id
puts "12312".object_id
puts "12312".object_id
puts "12312".object_id
#リテラルは、違うオブジェクト
puts "----chop! end----"
puts "----string start----"
puts "あ".length
puts "あ".size
puts "----string end----"
#####################
#
# Hello world的な処理ここまで
#
####################
=begin
# 関数定義があとに来ていた場合、エラーになる。
def test(*param) #引数に配列を渡す場合、アスタリスクをつける
param.each { |i|
puts "#{i}"
}
end
=end
__END__
puts "ここは実行されない。"