ここでは、良く使う Ruby の決まり文句を集める予定です。大半の式は irb で直接動作を確かめることができます。# => の右辺ば左辺の式を評価したときの結果を示します。irb に入力するのは # => の左辺のみです。
Ruby を使っていて最初に引っかかるのは代入の仕様です。Ruby の代入はオブジェクトへのリファレンスを作るだけなので、もとの変数の内容を変えると代入した先の変数の値も変化してしまいます。
irb(main):001:0> a = [1,2] [1, 2] irb(main):002:0> b = a [1, 2] irb(main):003:0> a[0] = "changed" "changed" irb(main):004:0> b ["changed", 2]
値だけを代入するにはメソッド dup でオブジェクトのコピーをとってから代入します。
irb(main):005:0> a = [1,2] [1, 2] irb(main):006:0> b = a.dup [1, 2] irb(main):007:0> a[0] = "changed" "changed" irb(main):008:0> b [1, 2]
name = gets.chop; puts "hello, #{name}. nice to meet you." name = gets.chomp; puts "hello, #{name}. nice to meet you."
フラットファイルのデータベースを使うときに必要です。
['apple', 'orange', 'banana'].join(':') # => "apple:orange:banana" "apple:orange:banana".split(/:/) # => ["apple", "orange", "banana"] "hello | world".split(/\s+\|\s+/) # => ["hello", "world"] "The time is 3:45".scan(/\d+/) # => ["3", "45"]
検索
puts "mathch" if "hello, world" =~ /l*/ ['dog', 'cat', 'rat'].find_all( /at/ ) # => ["cat", "rat"] def findre( re, str ) if str =~ re "#$`[#$&]#$'" else "not found" end end findre( /h.*o/, "hello, world" )
置換
"hello, world".gsub(/wo.*/, 'there') # => "hello, there" ['dog', 'cat', 'rat'].collect {|s| s.gsub(/.at/, 'bat') # => ["dog", "bat", "bat"]
[1, 2, 3, 4, 5].collect {|x| x * x } # => [1, 4, 9, 16, 25] (1..5).collect {|x| x + 10} # => [11, 12, 13, 14, 15] ["H", "A", "L"].collect {|c| c.succ}
自分用のプログラムはフィルターで作るのが便利です。フィルターは gets と puts を使うだけで簡単に作れます。フィルターを引数無しで起動すると、コマンドラインからデータを入力できます。Ruby の場合フィルターの引数には < を省略してファイル名をとることができます。この場合引数のファイルのデータが利用されます。フィルターの出力をファイルにするには > のリダイレクトを使います。
ファイル名:mean.rb
#!/usr/local/bin/ruby n, totoal, ss = 0, 0, 0 while ( data = gets ) x = data.to_f n += 1 total += x ss += x * x end mean = total / n sd = Math.sqrt( ss / n - mean * mean ) puts "n = #{n}, total = #{total}, mean = #{mean}, sd = #{sd}"
実行例
$ ./mean.rb 1 2 3 (Ctrl-d) n = 3, total = 6.0, mean = 2.0, sd = 0.8164965809 $ ./mean.rb data.txt n = 5, total = 15.0, mean = 3.0, sd = 1.414213562
LIFO(スタック)
a = [] # a => [] a.push('a') # a => ["a"] a.push('b') # a => ["a", "b"] b = a.pop # a => ["a"], b => "b" c = a.pop # a => [], c => "a" d = a.pop # a => [], d => nil
FIFO(キュー)
a = [] a.push('a', 'b') # a => ["a", "b"] a.push('c') # a => ["a", "b", "c"] b = a.shift # a => ["b", "c"], b => "a"
読みもどし
a = ['b', 'c'] a.unshift('a') # a => ["a", "b", "c"]
require "cgi" CGI.escapeHTML("a < b && a > d") # => "a < b && a > d" CGI.unescapeHTML("a < b && a > d") # => "a < b && a > d"
HTML の特殊文字をエスケープするフィルター
#!/usr/local/bin/ruby require "cgi" while ( a = gets ) puts CGI.escapeHTML( a ) end
cgi.rb の CGI::escapeHTML(string) のコード
def CGI::escapeHTML(string) string.gsub(/&/n, '&').gsub(/\"/n, '"').gsub(/>/n, '>').gsub(/</n, '<') end
def dim( row, column ) (0...row).collect { Array.new(column).fill(0) } end
メソッドから複数の戻り値を返したいときがあります。Ruby では多重代入ができるので、メソッドからの戻り値を配列で返すと、複数の戻り値をメソッドから返したように見せることができます。
def test a = [1,2] b = "apple" [a, b] end c, d = test puts c.inspect puts d
メソッドの引数に二次元配列を渡すときに、元の配列の内容を変えたくない場合があります。そこでメソッド内のローカル変数に引数のコピーを渡すつもりで temp = arry.dup としても、メソッドの中から抜けたときにもとの配列の内容も書き変わってしまいます。
$ irb irb(main):001:0> def test( arry ) irb(main):002:1> temp = arry.dup irb(main):003:1> temp[0][0] = "changed" irb(main):004:1> temp irb(main):005:1> end nil irb(main):006:0> a = [[1,2],[3,4]] [[1, 2], [3, 4]] irb(main):007:0> test( a ) [["changed", 2], [3, 4]] irb(main):008:0> a [["changed", 2], [3, 4]]
これは dup メソッドによるコピーの仕様が"浅い"コピーであるためではないかと思います。次のようにすれば、メソッド内で"深い"コビーをとることができます。
irb(main):009:0> def test( arry ) irb(main):010:1> temp = arry.collect{|c| c.dup } irb(main):011:1> temp[0][0] = "changed" irb(main):012:1> temp irb(main):013:1> end nil irb(main):014:0> a = [[1,2],[3,4]] [[1, 2], [3, 4]] irb(main):015:0> test( a ) [["changed", 2], [3, 4]] irb(main):016:0> a [[1, 2], [3, 4]]
Marshal モジュールを利用するとどんなオブジェクトの「深い」コピーもとれます。
irb(main):001:0> a = [[1, 2],[3, 4]] [[1, 2], [3, 4]] irb(main):002:0> b = Marshal.load( Marshal.dump( a )) [[1, 2], [3, 4]] irb(main):003:0> a[0][0] = 'changed' "changed" irb(main):004:0> a [["changed", 2], [3, 4]] irb(main):005:0> b [[1, 2], [3, 4]] irb(main):006:0>
irb(main):001:0> begin irb(main):002:1* srand irb(main):003:1> for i in 1..6 irb(main):004:2> puts rand(6)+1 irb(main):005:2> end irb(main):006:1> end
irb は Ruby を対話的に使えて便利ですが、ちょっと長いプログラムをためすのは編集ができないので不便です。次のようにすれば vi を使ってプログラムを編集できます。
irb(main):001:1> system 'vi temp.rb'
編集が終了したら次のようにして実行します。
irb(main):002:1> system 'ruby temp.rb'
実行が失敗してもう一度編集したいときは Ctrl-p で system 'vi temp.rb' をコマンドライン上に呼び出して Ret キーを押します。
改行に関係なくストリームの整数データを一気に取得する方法です
data = $stdin.read.scan(/[+-]*\d+/)
print ARGF.read.gsub(/\/\*.*?\*\//m, "")
gp = IO.popen("gnuplot -persist", "w") gp.puts 'plot "-" w l' (-2).step(3, 0.1) do |x| y = x * (x + 1) * (x - 2) gp.puts "#{x} #{y}" end gp.puts "end" gp.close