本書は、Rubyのチュートリアルです。 Rubyは、比較的習得が容易なオブジェクト指向スクリプティング言語です。 まつもとゆきひろによって開発されました。 Ruby on Railsの記述言語として選ばれたことで有名になりましたが、ウェブアプリケーション以外にもシステム管理やネットワークアプリケーションなどさまざまな用途に用いられます。

Wikipedia
Wikipedia
ウィキペディアRubyの記事があります。

準備編集

rubyインタープリターの準備編集

まずはrubyインタープリターを用意しましょう[1]。 インタープリターとは、あなたが書いたスクリプトを読んでそれを実行してくれるソフトウェアです。 Ruby公式サイトの「ダウンロード」ページから、 それぞれの環境に合ったインタープリターをダウンロードして下さい。 具体的なインストール手順は環境によって違うので、「Rubyのインストール」を参照して下さい。

準備ができたら、試しにコマンドラインからインタープリターを呼び出してみましょう。

バージョンを確かめる
% ruby --version
ruby 3.2.0 (2022-12-25 revision a528908271) [amd64-freebsd13]
バージョンは、環境によって異なります。

2022年12月現在、ruby-1.x は全てEoL(End-of-Life;サポート終了)、 ruby-2.x は 2.7 がセキュリティメンテナンス、それ以外はEoL、 ruby-3.x は 3.0 - 3.2 がノーマルメンテナンス、3.2 がプレビューです[2]

もしご自身の環境の ruby のバージョンが既にサポート終了しているのであれば、サポートされているバージョンへのアップデートを検討してください。 本書では ruby-2.7 以降を想定しています。

ミススペルすると
% ruby --vertion
ruby: invalid option --vertion  (-h will show valid options) (RuntimeError)
versionの綴りが違うとこの様なメッセーが出ます。案内に従って ruby -h を実行してみましょう。
コマンドラインオプションの説明
% ruby -h
Usage: ruby [switches] [--] [programfile] [arguments]
  -0[octal]       specify record separator (\0, if no argument)
  -a              autosplit mode with -n or -p (splits $_ into $F)
  -c              check syntax only
  -Cdirectory     cd to directory before executing your script
  -d              set debugging flags (set $DEBUG to true)
  -e 'command'    one line of script. Several -e's allowed. Omit [programfile]
  -Eex[:in]       specify the default external and internal character encodings
  -Fpattern       split() pattern for autosplit (-a)
  -i[extension]   edit ARGV files in place (make backup if extension supplied)
  -Idirectory     specify $LOAD_PATH directory (may be used more than once)
  -l              enable line ending processing
  -n              assume 'while gets(); ... end' loop around your script
  -p              assume loop like -n but print line also like sed
  -rlibrary       require the library before executing your script
  -s              enable some switch parsing for switches after script name
  -S              look for the script using PATH environment variable
  -v              print the version number, then turn on verbose mode
  -w              turn warnings on for your script
  -W[level=2|:category]     set warning level; 0=silence, 1=medium, 2=verbose
  -x[directory]   strip off text before #!ruby line and perhaps cd to directory
  --jit           enable JIT for the platform, same as --mjit (experimental)
  --mjit          enable C compiler-based JIT compiler (experimental)
  -h              show this message, --help for more info
これもバージョンによって表示が異なります。

[TODO:其々のコマンドラインオプションの説明は割愛しましたが、ワンライナーを書くときに役に立つ -nle など代表的な組合わせをコラム(?)で紹介すべきでしょう]

Hello, World!編集

他の多くのチュートリアルがそうであるように、 私たちもまずはRubyの世界にあいさつすることから始めましょう。 hello.rbというファイルを作り(Rubyではスクリプトファイルに.rbという拡張子を付けることが通例となっています)、次のように書いて保存して下さい。

hello.rb
puts 'Hello, World!'

それではこのスクリプトを実行してみましょう。コマンドラインから次のようにタイプして下さい。

% ruby hello.rb
Hello, World!
%

この1行のスクリプトは、メソッドputs に文字リテラル'Hello, World!'を渡し呼出しています。

irb編集

irb(Interactive Ruby) は、Rubyを対話的に実行するためのコマンドシェル[3]です[4]

irbで 'Hello, World!'
% irb
irb(main):001:0> puts "Hello, world!"
Hello, world!
=> nil
irb(main):002:0> exit
%
  1. シェルから irb を起動
  2. puts "Hello, world!"と入力し、エンターを押して評価しています。
  3. Hello, world!puts メソッドの出力です。
  4. => nil は、puts メソッドの戻値です。
  5. exit で irb を終了しています。
  6. シェルのプロンプトに復帰

irbのインストール編集

環境によっては、rubyインタプリターとは別にirbを追加でインストールしないと、irbは使えない場合もあります。

もし、irb がインストールされていないのであれば、実行環境のパッケージマネージャーで irb を検索しインストールしてください。

また、rubygems にも irb のパッケージがあるので

 % sudo gem install irb

でインストールできます。

変数編集

オブジェクトを変数に代入するには

変数名 = オブジェクト

の様に代入演算子 = を使います。

変数へのオブジェクトの代入と参照
a = 1
p a
a = "abc"
p a
a = [1, 2, 3]
p a
b = a
p b
b[1] = 999
p a
表示結果
1
"abc"
[1, 2, 3]
[1, 2, 3] 
[1, 999, 3]
  1. 変数 a に整数 1 を代入
  2. メソッド p に a を引数とした呼出し
    • 変数 a を使った参照
    • 1 が表示される
  3. 変数 a に文字列 "abc" を代入
  4. "abc" が表示される
  5. 変数 a に配列 [1, 2, 3] を代入
  6. [1, 2, 3] が表示される
  7. 変数 b に変数 a が参照しているオブジェクトを代入
    • ここでは、配列 [1, 2, 3]
  8. やはり、[1, 2, 3] が表示される
  9. 変数 b の参照している配列の1番目の要素に 999 を代入
    • これは変数ではなく配列の要素への代入
    • 配列の先頭は0番目
  10. 変数 a を使って参照すると
    • 1番目の要素が 999 に書換わって [1, 999, 3] となっている

代入は、オブジェクトに後から参照するための名前(変数名)をつけることに他なりません。 このため、変数の参照するオブジェクトを別の変数に代入すると「別名」を作ることになります。

puts メソッドと p メソッド
putsメソッドはオブジェクトにto_sメソッドで適用した結果を表示します。

これに対し、pメソッドはオブジェクトにinspectメソッドで適用した結果を表示します。

putsとp
puts "Hello, world!"
p "Hello, world!"
実行結果
Hello, world!
"Hello, world!"


オブジェクト編集

Ruby では、多くのものがオブジェクトで、オブジェクトは1つのクラスに属しています。 他のオブジェクト指向プログラミング言語では、整数や文字列などはメソッドをプリミティブとして別扱いし、 ラッパーをオブジェクトを用意することでメソッドがないことを補っていますが、 Ruby では整数や文字列など基本的なデータ型もオブジェクトでメソッドを持ちます。

オブジェクトのクラスを調べる編集

オブジェクトのクラスを調べるには、 .class メソッドを使います。

$ irb    
irb(main):001:0> 0.class
=> Integer
irb(main):002:0> "abc".class
=> String
irb(main):003:0> [1,2,3].class
=> Array
irb(main):004:0> ({a:2, b:3, c:5, d:7}).class
=> Hash
irb(main):005:0> (1...99).class
irb(main):005:0> (1...99).class
=> Range

全てのクラスのスーパークラス Object編集

Object は全てのクラスのスーパークラスです。

式と演算子編集

式 (expression) や演算子 (operator) について説明します。

Rubyにはい可能な演算子があります。

  • 代入演算子
  • 比較演算子
  • 算術演算子
  • ビット演算子
  • 論理演算子
  • 文字列演算子
  • 条件(三項)演算子
  • カンマ演算子

オブジェクトとメソッド演算子編集

演算子はオブジェクトのメソッドの特殊な形で、二項演算子の場合は左辺のオブジェクトがレシーバーになります。

Object(==, ===, =~)
  Array(+, -, *, &, <<, <=>, ==, [], []=)
  Hash(==, ===, [], []=)
  String(%, *, +, <<, <=>, ==, =~, [], []=)
  Numeric(+, -, <=>)
    Float(+, -, *, /, %, **, ==, <, >, <=, >=, <=>)
    Integer(+, -, *, /, %, **, ==, <=, >=, <=>, <<, >>, [], &, |, ^, ~, **)
  Range(==, ===)
  Regexp(==, ===, =~)

演算子の優先順位と結合方向編集

演算子には優先順位 (結合力の強さ) と結合方向があります。

a + b - c

( a + b ) - c 

と同じ(加減算は左結合)。

a + b * c

a + ( b * c )

と同じ(乗除算は加減算より優先順位が高い)。

a = b = 0

a = ( b = 0 )

と同じ(代入は右結合)。

様々なクラス・オブジェクトとリテラル編集

Ruby では、変数に束縛することが出来るものは全てオブジェクトです。 オブジェクトは必ず1つのクラスに属しています。 全てのクラスにリテラル表現があるわけではありませんが、組込みライブラリーの主要なクラスにはリテラル表現が用意されています。

数値クラス編集

数値クラスは整数クラスあるいは浮動小数点数クラスです。

数値クラス
p 2 + 6
p 2.0 + 6
p 2 + 6.0
p 2.0 + 6.0
p 2.class
p 2.methods
p 2.0.class
p 2.0.methods
表示結果
8
8.0
8.0
8.0
Integer
[:anybits?, :nobits?, :downto, :times, :pred, :pow, :**, :<=>, :<<, :>>, :<=, :>=, :==, :===, :next, :lcm, :digits, :[], :~, :gcd, :gcdlcm, :-@, :upto, :%, :chr, :&, :*, :+, :bit_length, :inspect, :-, :/, :integer?, :even?, :odd?, :size, :succ, :<, :>, :ord, :to_int, :to_s, :to_i, :to_f, :to_r, :div, :divmod, :fdiv, :^, :coerce, :modulo, :remainder, :abs, :magnitude, :zero?, :floor, :ceil, :round, :truncate, :numerator, :|, :denominator, :rationalize, :allbits?, :dup, :arg, :real?, :+@, :rect, :polar, :real, :imaginary, :imag, :abs2, :angle, :phase, :conjugate, :rectangular, :to_c, :conj, :infinite?, :finite?, :eql?, :singleton_method_added, :quo, :clone, :i, :nonzero?, :step, :positive?, :negative?, :between?, :clamp, :singleton_class, :itself, :taint, :tainted?, :untaint, :untrust, :untrusted?, :trust, :methods, :singleton_methods, :protected_methods, :private_methods, :public_methods, :instance_variables, :instance_variable_get, :instance_variable_set, :instance_variable_defined?, :remove_instance_variable, :instance_of?, :kind_of?, :is_a?, :display, :hash, :public_send, :class, :frozen?, :tap, :then, :yield_self, :extend, :method, :public_method, :singleton_method, :define_singleton_method, :=~, :!~, :nil?, :respond_to?, :freeze, :object_id, :send, :to_enum, :enum_for, :__send__, :!, :__id__, :instance_eval, :instance_exec, :!=, :equal?]
Float 
[:arg, :-@, :**, :<=>, :<=, :>=, :==, :===, :angle, :phase, :positive?, :nan?, :infinite?, :finite?, :next_float, :prev_float, :eql?, :%, :*, :+, :inspect, :-, :/, :<, :>, :to_int, :to_s, :to_i, :to_f, :to_r, :divmod, :fdiv, :quo, :coerce, :modulo, :abs, :magnitude, :zero?, :floor, :ceil, :round, :truncate, :numerator, :denominator, :rationalize, :negative?, :hash, :dup, :real?, :+@, :rect, :polar, :real, :imaginary, :imag, :abs2, :conjugate, :rectangular, :to_c, :conj, :integer?, :singleton_method_added, :div, :clone, :i, :remainder, :nonzero?, :step, :between?, :clamp, :singleton_class, :itself, :taint, :tainted?, :untaint, :untrust, :untrusted?, :trust, :methods, :singleton_methods, :protected_methods, :private_methods, :public_methods, :instance_variables, :instance_variable_get, :instance_variable_set, :instance_variable_defined?, :remove_instance_variable, :instance_of?, :kind_of?, :is_a?, :display, :public_send, :class, :frozen?, :tap, :then, :yield_self, :extend, :method, :public_method, :singleton_method, :define_singleton_method, :=~, :!~, :nil?, :respond_to?, :freeze, :object_id, :send, :to_enum, :enum_for, :__send__, :!, :__id__, :instance_eval, :instance_exec, :!=, :equal?]

浮動小数点数リテラルは、小数点以下が 0 でも 6. の様に 0 を省略できません

文字列クラス編集

文字列リテラルは ' あるいは " で囲います。 上の例の、'Hello World!' が文字リテラルの一例です。

文字列クラス
p "2" + "6"
p "abc" * 6
p "→%d" % 6
p "2".concat "6"
p "abc".class
p "abc".methods
表示結果
"26"
"abcabcabcabcabcabc"
"→6"
"26"
String 
[:unicode_normalized?, :encode!, :unicode_normalize, :ascii_only?, :unicode_normalize!, :to_r, :encode, :to_c, :include?, :%, :*, :+, :unpack, :unpack1, :count, :partition, :+@, :-@, :<=>, :<<, :sum, :==, :===, :next, :=~, :[], :[]=, :empty?, :casecmp, :eql?, :insert, :casecmp?, :match?, :bytesize, :match, :next!, :succ!, :index, :upto, :replace, :rindex, :chr, :clear, :byteslice, :getbyte, :setbyte, :freeze, :scrub, :scrub!, :dump, :inspect, :intern, :upcase, :downcase, :capitalize, :swapcase, :upcase!, :undump, :length, :size, :downcase!, :succ, :swapcase!, :hex, :capitalize!, :split, :chars, :oct, :grapheme_clusters, :concat, :codepoints, :lines, :bytes, :to_str, :end_with?, :start_with?, :reverse, :reverse!, :sub, :to_s, :to_i, :to_f, :rjust, :center, :prepend, :crypt, :ord, :chomp, :strip, :to_sym, :ljust, :delete_prefix, :delete_suffix, :lstrip, :gsub, :scan, :chomp!, :sub!, :gsub!, :rstrip, :delete_prefix!, :chop, :lstrip!, :rstrip!, :chop!, :delete_suffix!, :strip!, :tr_s, :delete, :squeeze, :tr!, :tr, :delete!, :squeeze!, :each_line, :each_byte, :tr_s!, :each_codepoint, :each_grapheme_cluster, :slice, :slice!, :each_char, :encoding, :force_encoding, :b, :valid_encoding?, :rpartition, :hash, :between?, :clamp, :<=, :>=, :<, :>, :singleton_class, :dup, :itself, :taint, :tainted?, :untaint, :untrust, :untrusted?, :trust, :methods, :singleton_methods, :protected_methods, :private_methods, :public_methods, :instance_variables, :instance_variable_get, :instance_variable_set, :instance_variable_defined?, :remove_instance_variable, :instance_of?, :kind_of?, :is_a?, :display, :public_send, :class, :frozen?, :tap, :then, :yield_self, :extend, :clone, :method, :public_method, :singleton_method, :define_singleton_method, :!~, :nil?, :respond_to?, :object_id, :send, :to_enum, :enum_for, :__send__, :!, :__id__, :instance_eval, :instance_exec, :!=, :equal?]

文字オブジェクトの + 演算子は、concatメソッドの別名です。 この様に、同じ演算子でも左辺に来るオブジェクトによって行われる処理が変わります。

式展開編集

" で囲んだ文字列リテラル中には #{ 式 }の形で式を埋込む事ができます。 ' で囲んだ文字列リテラル中では #{ 式 }の形で式は展開されません。

文字列リテラルに式を埋込んだ例
表示結果
文字列リテラルに式を埋込んだ例
p "12 + 8 = #{12 + 8}"
p %|"abc".upcase = #{"abc".upcase}|
表示結果
"12 + 8 = 20" 
"\"abc\".upcase = ABC"

文字リテラル編集

p ?a
p ?字
p ?😈
p ?😈.class

実行結果

"a"
"字"
"😈"
String

正規表現クラスと正規表現リテラル編集

配列クラスと配列式編集

ハッシュクラスとハッシュ式編集

範囲クラスと範囲演算子式編集

範囲演算子式は、範囲クラス(Range)のリテラルで開始 .. 終了の形式です。

Rangeオブジェクト
r = (0..9)
p r
p r.class
r.each {|x| p x }
実行結果
0..9
Range
0
1
2
3
4
5
6
7
8
9
putsメソッドはオブジェクトにto_sメソッドで適用した結果を表示するのに対し、pメソッドはオブジェクトにinspectメソッドで適用した結果を表示します。
putsとp
puts "Hello, world!"
p "Hello, world!"
実行結果
Hello, world! 
"Hello, world!"


シンボル編集

%記法編集

メソッド編集

メソッド(method)は、処理の塊に名前を付けて再利用する仕組みです。

一般的なプログラミング言語でのサブルーチン・プロシージャあるいは命令と呼ばれるものと共通する特徴を持ちますが、主語に相当するオブジェクトがあるところが異なります。

メソッドはキーワード def を使って定義します。

コード
def hello()
  puts "Hell World!"
end

hello()
self.hello()
表示結果
Hell World!
Hell World!
  1. メソッド hello の定義の開始
  2. メソッド hello の本体
  3. メソッド hello の定義の終了
  4.  
  5. メソッド hello の呼出し
  6. メソッド helloselfを明示して呼出し

仮引数を伴ったメソッド編集

メソッドには、仮引数としてオブジェクトを渡すことができます。

仮引数を伴ったメソッド
def show_sum(a, b)
  puts a + b
end

show_sum(1, 3)
show_sum(5, 2)
表示結果
4
7

戻り値を返すメソッド編集

メソッドは、戻り値としてオブジェクトを返すことができます。

戻り値を返すメソッドの例
def get_sum(a, b)
  return a + b
end

puts get_sum(1, 3)
puts get_sum(5, 2)
表示結果
4
7

変数のスコープ編集

メソッドの中で作られた変数のスコープはメソッドローカルです。

変数のスコープ
a = 100
x = 99
def get_sum(a, b)
  x = 0
  return a + b
end

puts [a,x]
puts get_sum(1, 3)
puts get_sum(5, 2)
表示結果
100
99
4
7
1行目で 100 が代入された変数 a は、メソッド get_sum の仮引数 a とは関係なく 100 のまま
2行目で 99 が代入された変数 x は、メソッド get_sum の中で 0 が代入された x とは関係なく 99 のまま

この様に、メソッドの中からはメソッドの外の変数を(仮引数を介すなどの手段を取らない限り)参照出来ません。 また、メソッドをスコープとする変数をメソッドの呼出し元から参照できません。

Rubyと変数宣言
「メソッドの中で作られた」と、やや歯切れの悪い表現ですが、Ruby では変数を「宣言」しません。

強いて言うならば、最初の代入が変数の宣言です。


メソッドの引数リストを囲む括弧の省略
メソッドの引数リストを囲む括弧 p() は、曖昧さのない場合は省略可能です。

上の例は、puts(s)と書く代わりに、put s と書く事ができます。

コード
s = 'Hello World!'
puts s
表示結果
Hello World!


クラス編集

ユーザー定義クラス編集

都市間の大圏距離編集

Go/メソッドとインターフェースの都市間の大圏距離を求めるメソッドを追加した例を、Rubyに移植しました。

都市間の大圏距離
class GeoCoord
    attr_accessor :longitude, :latitude

    def initialize(longitude, latitude)
        @longitude, @latitude = longitude, latitude
    end
    def to_s() 
	    ew, ns = "東経", "北緯"
	    long, lat = @longitude, @latitude
	    ew, long = "西経", -long if long < 0.0
	    ns, lat = "南緯", -lat if lat < 0.0
	    "(#{ew}: #{long}, #{ns}: #{lat})"
    end
    def distance(other)
    	i, r = Math::PI / 180, 6371.008
	    Math.acos(Math.sin(@latitude * i) * Math.sin(other.latitude * i) +
		    Math.cos(@latitude * i) * Math.cos(other.latitude * i) * Math.cos(@longitude * i - other.longitude * i)) * r
	end
end
def GeoCoord(longitude, latitude)
    GeoCoord.new(longitude, latitude)
end

Sites = {
    "東京駅":                   GeoCoord(139.7673068, 35.6809591),
    "シドニー・オペラハウス":   GeoCoord(151.215278, -33.856778),
    "グリニッジ天文台":         GeoCoord(-0.0014, 51.4778),
}

Sites.each{|name, gc|
    puts "#{name}: #{gc}"
}

keys, len = Sites.keys, Sites.size
keys.each_with_index{|x, i|
    y = keys[(i + 1) % len]
	puts "#{x} - #{y}: #{Sites[x].distance(Sites[y])} [km]"
}
実行結果
東京駅: (東経: 139.7673068, 北緯: 35.6809591)
シドニー・オペラハウス: (東経: 151.215278, 南緯: 33.856778)
グリニッジ天文台: (西経: 0.0014, 北緯: 51.4778)
東京駅 - シドニー・オペラハウス: 7823.269299386704 [km]
シドニー・オペラハウス - グリニッジ天文台: 16987.2708377249 [km]
グリニッジ天文台 - 東京駅: 9560.546566490015 [km]

包含と継承編集

JavaScript/クラス#包含と継承を、Rubyに移植しました。

包含と継承
class Point
  def initialize(x = 0, y = 0)
    @x, @y = x, y
  end
  def inspect() "x:#{@x}, y:#{@y}" end
  def move(dx = 0, dy = 0)
    @x, @y = @x + dx, @y + dy
    self
  end
end

class Shape
  def initialize(x = 0, y = 0)
    @location = Point.new(x, y)
  end
  def inspect() @location.inspect() end
  def move(x, y)
    @location.move(x, y)
    self
  end
end

class Rectangle < Shape 
  def initialize(x = 0, y = 0, width = 0, height = 0)
    super(x, y)
    @width, @height = width, height
  end
  def inspect() "#{super()}, width:#{@width}, height:#{@height}" end
end

rct = Rectangle.new(12, 32, 100, 50)

p ["rct=", rct]
p ['rct.instance_of?( Rectangle ) => ', rct.instance_of?(Rectangle)]
p ['rct.instance_of?( Shape ) => ', rct.instance_of?(Shape)]
p ['rct.instance_of?( Point ) => ', rct.instance_of?(Point)]
rct.move(11, 21)
p ["rct=", rct]
実行結果
["rct=", x:12, y:32, width:100, height:50]
["rct.instance_of?( Rectangle ) => ", true]
["rct.instance_of?( Shape ) => ", false]
["rct.instance_of?( Point ) => ", false]
["rct=", x:23, y:53, width:100, height:50]

制御構造編集

制御構造(せいぎょこうぞう、control flow)とは、「順次」「分岐」「反復」という基本的な処理のことを言います。

Rubyの真理値
制御構造は「条件式」が真であるか偽であるかによって分岐や反復の振る舞いが変わります。

では「条件式」が真・偽はどの様に決まるのでしょう?

Rubyでは false あるいは nil であると偽、それ以外が真です。

なので 0[](空のArray) も {}(空のHash)も真です。

条件分岐編集

Rubyの条件分岐には、if, untilcaseの3つの構文があります。

if編集

ifは条件式によって実行・否を切り替える構造構文で、評価した式の値を返すので条件演算子でもあります。

ifの例
a = 0.0 / 0.0

if a < 0
    puts "minus"
elsif a > 0
    puts "plus"
elsif a == 0
    puts "zero"
else
    puts a
end

puts(
    if a < 0
        "minus"
    elsif a > 0
        "plus"
    elsif a == 0
        "zero"
    else
        a
    end
)
表示結果
NaN
NaN
elsif節
ifは、オプショナルな elsif 節を設け、条件式が偽であった時に別の条件に合致した処理を実行させることが出来ます。
else節
ifは、オプショナルな else 節を設け、条件式が偽であった時に処理を実行させることが出来ます。
ifは値を返すので、メソッドの実引数に使うことが出来ますし、代入演算の右辺にも使えます。

後置のif編集

Rubyには、Perlのような後置のifがあります。

後置のifの例
n = 0

puts "nは0" if n == 0
puts "nは1" if n == 1
表示結果
nは0

unless文編集

unless文(アンレスぶん、unless statement)は条件式によって実行・否を切り替える構造構文ですが、ifとは条件式に対する挙動が逆です。

unless文の例
a = 0.0 / 0.0

unless a == 0
    puts "Non-zero"
else
    puts a
end
表示結果
Non-zero
else節
unless文は、オプショナルな else 節を設け、条件式が真であった時に処理を実行させることが出来ます。
また、unless文は elsif 節は持てません。

後置のunless編集

Rubyには、Perlのような後置のunlessがあります。

後置のunlessの例
n = 0

puts "nは0" unless n == 0
puts "nは1" unless n == 1
表示結果
nは1ではない

case編集

caseは、複数の条件式によって処理を降る分ける用途の為に用意されています。

caseの例
n = 2

case n
when 1
    puts "one"
when 2
    puts "two"
when 3
    puts "three"
else
    puts "other"
end
表示結果
two
C言語系のswitch文に慣れた人はbreakがないことに気がつくと思います。Rubyのcaseはfall throughしませんし、fall throughさせる方法もありません。
when節が定数でなく式を受付ける事を使ったトリック編集

ifを使ったコードをcaseに書き換えてみましょう。

case true トリック
a = 0.0 / 0.0

case true
when a < 0
    puts "minus"
when a > 0
    puts "plus"
when a == 0
    puts "zero"
else
    puts a
end
表示結果
NaN

このコードは when 節の式の値とcaseの式を === で比較し、最初に一致した when に対応する文が実行される事を利用しています。

JavaScriptのswitch文のcase節にも式が使えるので、同じトリックが使えます。

繰返し編集

Rubyには、他のプログラミング言語のような繰返し文と、イテレーターメソッドがあります。

繰返し構文編集

Rubyの繰返し文には、while文 until for文 と loop文 の4つがあります[5]

while文編集

while文(ホワイルぶん、while statement)は条件がである間、文を実行しつづけます。

構文
while 条件式 [ do ]
    
    
      
    文n
end
do は省略できます。
while文のコード例
i = 0
while i < 5 do
    puts i
    i += 1
end
2行目の i < 5が真の間、次の2行を繰返します。
4行目の i += 1i = i + 1 の構文糖
実行結果
0
1
2
3 
4
until編集

until(アンティルぶん、until statement)は条件がである間、文を実行しつづけます。while文とは条件に対する挙動が逆です。

構文
until 条件式 [ do ]
    
    
      
    文n
end
do は省略できます。
untilのコード例
i = 0
until i == 3 do
    puts i
    i += 1
end
2行目の i == 3が偽の間、次の2行を繰返します。
実行結果
0
1
2
for文編集

Rubyにもfor文がありますが、多くの言語でfroeach文と呼ばれるもので、C言語系のfor (;;)とは異なります。

for文の構文
for 変数 in コレクション
  
end
コレクションは Range, Array, Hash など内部構造を持つオブジェクトです。

Rangeオブジェクトとfor文編集

Rangeオブジェクトは、整数の区間を表し範囲演算子 開始 ... 終了 で生成します。

コード
rng = 1..3
puts rng.class
for n in rng do
  puts "テキスト";
end
実行結果
Range
テキスト
テキスト
テキスト

Arrayオブジェクトとfor文編集

Arrayオブジェクトは、任意の Ruby オブジェクトを要素として持つことができます。 配列式[要素1, 要素2, … 要素n] で生成します。

コード
animals = ["ネコ", "金魚", "ハムスター"]

puts animals.class
for animal in animals do
  puts "動物 #{animal}"
end
実行結果
動物 ネコ
動物 金魚
動物 ハムスター

Hashオブジェクトとfor文編集

Hashオブジェクトは、任意の Ruby オブジェクトをキーに、任意の Ruby オブジェクトを値に持つことができる連想配列です。 Hash式{キー1 => 値1, キー2 => 値2, キーn => 値n} で生成します。 また、キーが Symbol の場合 Hash式{キー1: 値1, キー2: 値2, キーn: 値n} で生成することが出来ます。

コード
animals = {cat: "ネコ", gold_fish: "金魚", hamster: "ハムスター"}

puts animals.class
for en, animal in animals do
  puts "動物 #{en}: #{animal}"
end
実行結果
Hash
動物 cat: ネコ
動物 gold_fish: 金魚
動物 hamster: ハムスター

このように、Rubyのfor文は多様なコレクションを受け付けます。

loop文編集

loop文(ループぶん、loop statement)は永久ループを提供します。

構文
until [ do ]
    
    
      
    文n
end
loop文のコード例
i = 1
loop
    puts "%b" % i
    i <<= 1
    break if i > 2**80
end
実行結果
0b1
0b10
0b100
0b1000
0b10000
0b100000
0b1000000
0b10000000 
0b100000000
5行目の、break if i > 2**80でループを脱出するようにしています。この様に break や return あるいは例外が上がらないとループは永久に終わりません。
このコードは、Rubyにはない do-while文を模倣する例にもなっています。

イテレーターメソッド編集

eachメソッド編集

上述 for を使った配列の処理と、同じ処理を、次のようにコレクションのeachメソッドを使っても書けます。

コード
rng = 1..3
puts rng.class
rng.each do
  puts "テキスト";
end

animals = ["ネコ", "金魚", "ハムスター"]

animals.each do |animal|
  puts "ペット:#{animal}"
end

animals = {cat: "ネコ", gold_fish: "金魚", hamster: "ハムスター"}

puts animals.class
animals.each do |en, animal|
  puts "動物 #{en}: #{animal}"
end
実行結果:
Range
テキスト
テキスト
テキスト
ペット:ネコ
ペット:金魚
ペット:ハムスター
Hash
動物 cat: ネコ
動物 gold_fish: 金魚
動物 hamster: ハムスター
eachメソッドを使ったハック
普段あまり使うことはありませんが、配列のeachメソッドは戻値を返します。

通常は配列自身ですが、breakでループを中断すると nil を返します。 この特徴を利用すると、ZigやPythonのループと結合したelseの様に「ループを完走したときだけ実行する処理」を記述できます。

100以下の素数を求めるコード
primes = []
(2..100).each do |i|
  primes.push(i) if primes.each do |prime|
    break if i % prime == 0
  end
end
p primes
実行結果:
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]
素数集合(primes)から1つ素数(prime)を取出し、候補(i)をそれで割り、割切れたら break します。
break すると each は nil を返し、素数集合への候補の追加は行われません。


Integer#times編集

Integer#timesは与えられたブロックをオブジェクトの示す整数値回くりかえします。

コード
3.times{ puts 'Hello, world!' }
実行結果
Hello, world!
Hello, world!
Hello, world!
繰返したい処理が2行以上ある場合
3.times {
  puts 'Hello'
  puts 'World'
  puts ''
}
実行結果
Hello
World

Hello
World

Hello
World
ループ変数を使た例
3.times do |i|
  puts "#{i}の倍は#{2 * i}"
end
実行結果
0の倍は0
1の倍は2
2の倍は4
ブロックを伴わないtimesメソッド
iter = 3.times
puts iter.class
puts iter.next # 0
puts iter.next # 1
puts iter.next # 2
# puts iter.next #  `next': StopIteration: iteration reached an end
実行結果
Enumerator
0
1
2
Integer#times にブロックを渡さないと、Enumeratorオブジェクトが返ります。
Enumeratorオブジェクトは外部イテレーターと呼ばれnextメソッドで反復を行えます。

lazy編集

イテレーション メソッドでメソッド チェインを使うと、中間結果としてに大きなコレクションができてしまいます。 lazyを使うと、遅延評価を行いこれを避けることができます。 Enumableをプログラミング/ジェネレターに変換していると捉えることができます。

lazy
print "non lazy: "
p (0...10).filter{ |i| 
    print "#{i} "
    i % 2 == 0 
}.map { | i |
    print "(#{i}) "
    i
}.first(3)

print "lazy: "
p (0...10).lazy.filter{ |i| 
    print "#{i} "
    i % 2 == 0 
}.map { | i |
    print "(#{i}) "
    i
}.first(3)
実行結果
non lazy: 0 1 2 3 4 5 6 7 8 9 (0) (2) (4) (6) (8) [0, 2, 4] 
lazy: 0 (0) 1 2 (2) 3 4 (4) [0, 2, 4]

高階関数編集

lambda編集

無名関数を定義するにはKernel.#lambdaを使用します。Proc.newも近い機能を提供しますが、lambda のほうがより厳密で、引数の数が異なるって場合エラーとなります。

lambda {|x, y| x + y }[2, 3] # => 5

lambdaが返すProcオブジェクトにアクセスするにはブラケットを使用します。callメソッドを呼んでも同じことです。

HTTPクライアント編集

open-uriを使用すると簡単ですが、より高度なインタフェースが必要な場合はNet::HTTPを使用します。

require 'open-uri'
puts open('http://www.example.com/').read

open-uriは組み込みのopenメソッド(Kernel.#open)をオーバーライドします。ワンライナーで書くこともできます。

% ruby -ropen-uri -e 'puts open(ARGV.shift).read' http://www.example.com/

ARGVはコマンドライン引数の配列、Array#shiftメソッドは最初の要素を取り出します。

関連項目編集

脚註編集

  1. ^ インタープリターを ruby、スクリプティング言語を Ruby とかき分けます。
  2. ^ Ruby Maintenance Branches
  3. ^ REPL (Read Eval Print Loop)
  4. ^ irb は ruby インタープリターと違いスクリプトの実行には必須なプログラムではありませんが、対話的にコードを評価出来るのが便利です。
  5. ^ do-while文はありません。loopの最後にbreak if 式を設け実現します
このページ「Ruby」は、まだ書きかけです。加筆・訂正など、協力いただける皆様の編集を心からお待ちしております。また、ご意見などがありましたら、お気軽にトークページへどうぞ。