LoginSignup
0
1

RubySilverメモ

Last updated at Posted at 2023-12-25

目的

Rubyの実務数年。実装やレビューにおいて困っている事は特に無いが、RubySilverに触れることで更に理解を深め、発想の引き出しを増やしたい。

教材

組み込み定数

組み込み定数
STDIN 標準入力
STDOUT 標準出力
STDERR 標準エラー出力
DATA スクリプトの __END__ プログラム以降にアクセスする
ENV 環境変数
ARGF スクリプトに指定した引数をファイル名とみなし、それらのファイルを連結した1つの仮想ファイルを表す
ARGV スクリプトに与えられた引数を表す配列
RUBY_VERSION Rubyのバージョン
RUBY_RELEASE_DATE Rubyのリリース日
RUBY_PLATFORM プラットフォーム

組み込み変数

予約語一覧

BEGIN    class    ensure   nil      self     when
END      def      false    not      super    while
alias    defined? for      or       then     yield
and      do       if       redo     true     __LINE__
begin    else     in       rescue   undef    __FILE__
break    elsif    module   retry    unless   __ENCODING__
case     end      next     return   until

予約語はクラス名、変数名などに用いることはできません。ただし接頭辞$, @、@@が先頭についたものは予約語とは見なされません。
また、def のあとやメソッド呼び出しのピリオドのあとなどメソッド名であるとはっきり分かる場所ではメソッド名として用いることができます。

ローカル変数とメソッド名が同じ場合の挙動

hoge = 0

def hoge
  5 * 100
end

p hoge
実行結果
0

変数の定義が優先される

現場ではまずやらない書き方だけど理解しておくことが大切。

シンボルと文字列

Rubyの内部実装では、メソッド名や変数名、定数名、クラス名などの`名前'を整数で管理しています。これは名前を直接文字列として処理するよりも速度面で有利だからです。そしてその整数をRubyのコード上で表現したものがシンボルです。

シンボルは、ソース上では文字列のように見え、内部では整数として扱われる、両者を仲立ちするような存在です。

名前を管理するという役割上、シンボルと文字列は一対一に対応します。また、文字列と違い、immutable (変更不可)であり、同値ならば必ず同一です。

p str1 = "aaa".object_id #=> 60
p str2 = "aaa".object_id #=> 80
p sym1 = :aaa.object_id  #=> 1082908
p sym2 = :aaa.object_id  #=> 1082908

シンボルは内部では整数として扱われるため、文字列よりも処理が速い。
よって、単にラベルとして扱いたい場合には文字列よりもシンボルの方が効率が良い。

1行で書く

本来改行すべきところに;(セミコロン)を書く。

クラス

class OriginalError < StandardError; end # ここ

begin
  # raise StandardError
  raise OriginalError
rescue OriginalError => e
  puts "1: #{e.class}"
rescue => e
  puts "2: #{e.class}"
end

#=> 1: OriginalError

メソッド

def add(num1, num2); p num1 + num2; end

add(1, 2) #=> 3

条件分岐

a = 2

if a == 1; p 'a'; elsif a == 2; p 'b'; else; p 'c'; end  #=> "b"

多重代入

foo, bar = [1, 2]     #=> foo = 1; bar = 2
foo, bar = 1, 2       #=> foo = 1; bar = 2
foo, bar = 1          #=> foo = 1; bar = nil

foo, bar, baz = 1, 2  #=> foo = 1; bar = 2; baz = nil
foo, bar = 1, 2, 3    #=> foo = 1; bar = 2
foo = 1, 2, 3         #=> foo = [1, 2, 3]
*foo = 1, 2, 3        #=> foo = [1, 2, 3]
foo,*bar = 1, 2, 3    #=> foo = 1; bar = [2, 3]

一部を括弧で囲う場合

(a, b), c = 1, 2, 3

p a  #=> 1
p b  #=> nil
p c  #=> 2

上記のように行うと 「(a, b)」 と 「c」 に対してそれぞれの値を代入を行う。

引数

可変長引数

第一引数が可変長

def hoge(*n1, n2)
  p n1
  p n2
end

hoge 1, 2, 3, 4
実行結果
[1, 2, 3]
4

第二引数が可変長

def hoge(n1, *n2)
  p n1
  p n2
end

hoge 1, 2, 3, 4
実行結果
1
[2, 3, 4]

複数の引数を可変長にするとsyntax errorとなる

例)
hoge(n1, *n2, *n3)
hoge(*n1, n2, *n3)
hoge(*n1, *n2, *n3)
#=> syntax error, unexpected `end', expecting end-of-input

キーワード引数

def foo(a:, b:, c:400)
  p a + b + c
end

foo(a: 100, b: 200, c: 300) #=> 600
foo(a: 100, b: 200)         #=> 700
foo(a: 100)                 #=> sample.rb:1:in `foo': missing keyword: :b (ArgumentError)
foo(a: 100, b: 200, d: 300) #=> sample.rb:1:in `foo': unknown keyword: :d (ArgumentError)

デフォルト値がないキーワード引数を省略したり、
存在しないキーワード引数を指定すると、ArgumentErrorになる

オプション引数

Rubyにおけるハッシュのように自由にキーワードと値のペアで引数を記述し、それを引き渡せる機能です。そして引き渡した引数はメソッドの内部でハッシュのように扱えます。

def sample(**args)
  p args
  args.each do |key, value|
    puts "key: #{key}, value: #{value}"
  end
end

sample(a: 100, b: 200, c: 300)
#=> {:a=>100, :b=>200, :c=>300}
#   key: a, value: 100
#   key: b, value: 200
#   key: c, value: 300

演算子式

==, eql? equal?(オブジェクトの同値性と同一性)

x = 1
y = 1.0

a1 = "aaa"
a2 = 'aaa'
rails c
irb(main):005:0> x == y
=> true
irb(main):006:0> x.eql? y
=> false
irb(main):007:0> x.equal? y
=> false
irb(main):008:0> x.equal?(1)
=> true
irb(main):009:0> a1 == a2
=> true
irb(main):010:0> a1.eql? a2
=> true
irb(main):011:0> a1.equal? a2
=> false
  • ==はオブジェクトの内容が等しいか
  • eql?はhashのkeyとして等しいか
  • equal?はobject_idが等しいか

===

そのクラスかどうか

p String === "ruby"  #=> true
p String === 1       #=> false

p Integer === 1      #=> true
p Integer === "ruby" #=> false

範囲に含まれるか

p (1..10) === 10      #=> true
p (1...10) === 10     #=> false

p ('a'..'z') === 'z'  #=> true
p ('a'...'z') === 'z' #=> false

正規表現にmatchするか

p /[0-9]{3}/ === "sample987" #=> true
p /[0-9]{3}/ === "sample"    #=> false

<=> (UFO演算子)

p 1000 <=> 999   #=> 1
p 1000 <=> 1000  #=> 0
p 999  <=> 1000  #=> -1

左辺 と 右辺 を比較し、左辺 が大きい時に1、等しい時に 0、小さい時に-1、比較できない時に nil を返す

StringやArrayにもある

&&

左辺を評価し、結果が偽であった場合はその値(つまり nil か false) を返します。左辺の評価結果が真であった場合には右辺を評価しその結果を返します。 and は同じ働きをする優先順位の低い演算子です。

andとの優先度の違い

p 'a' && 'b'  #=> "b"
p 'a' and 'b' #=> "a"
a1 = [1,2,3]
a2 = [4,2,3]

p a1 &&  a2  #=> [4, 2, 3]
p a1 and a2  #=> [1, 2, 3]

nilまたはfalseであれば偽、それ以外はすべて真」として扱われる。
また、and&&に比べ優先順位が低い。

どちらかがnilやfalseの場合

a1 = nil
a2 = false
a3 = [1, 2, 3]

p a1 && a3 # 左辺がnil
p a3 && a1 # 右辺がnil
p a2 && a3 # 左辺がfalse
p a3 && a2 # 右辺がfalse
実行結果
nil
nil
false
false

比較対象がnilとfalseの場合は、左辺を返す

p (nil && false)  #=> nil
p (false && nil)  #=> false

||

左辺を評価し、結果が真であった場合にはその値を返します。左辺の評価結果が偽であった場合には右辺を評価しその評価結果を返します。 or は同じ働きをする優先順位の低い演算子です。

両辺nilやfalseではない場合

a1 = [1,2,3]
a2 = [4,2,3]

p a1 || a2  #=> [1, 2, 3]

比較対象がnilとfalseの場合は、右辺を返す

p (nil || false)  #=> false
p (false || nil)  #=> nil

orとの優先度の違い

p false || true  #=> true
p false or true  #=> false

クラス変数

例1
class Super
  @@foo = 0

  def foo
    @@foo
  end

  def foo=(value)
    @@foo = value
  end
end

class Sub < Super
  @@foo = 0

  def foo
    @@foo
  end

  def foo=(value)
    @@foo = value
  end
end

super1 = Super.new
super1.foo += 100
super2 = Super.new
super2.foo += 200
sub1 = Sub.new
sub1.foo += 50

puts "#{super1.foo}/#{super2.foo}/#{sub1.foo}" #=> 350/350/350
例2
class Super
  @@i = 0
  
  def self.count
    @@i += 1
  end
end

class Sub < Super; end

puts Super.count #=> 1
puts Sub.count   #=> 2
puts Super.count #=> 3

クラス変数はクラス全体で共有され、クラスメソッド内やスーパークラス・サブクラスでも共有される。

ヒアドキュメント

EOD (End of Documentの略)
EOF (End of Fileの略)
EOL (End of Lineの略)
EOM (End of Messageの略)
EOS (End of Stringの略)
EOT (End of Textの略)

text = <<EOF
         Ruby,
           Silver
EOF

p text #=> "         Ruby,\n           Silver\n"

終端行をインデントしているためエラー発生

text = <<EOF
         Ruby,
           Silver
         EOF

p text #=> can't find string "EOF" anywhere before EOF

開始ラベルを<<-識別子のようにする事で、終端行をインデント出来る

text = <<-EOF
          Ruby,
            Silver
          EOF

puts text #=> "          Ruby,\n            Silver\n"

開始ラベルを<<~識別子のようにする事で、空白の無い文字列として変数に格納

text = <<~EOF
          Ruby,
            Silver
          EOF

p text #=> #=> "Ruby,\n  Silver\n"

Array

複数の要素を持つ配列を生成する様々な方法

# 例1
['ruby'] * 3                     # 中身の要素が、すべて同一のオブジェクト
%w(ruby) * 3                     # 同一

# 例2
Array.new(3, 'ruby')             # 同一

# 例3
Array.new(3).fill('ruby')        # 同一

# 例4
Array.new(3) { 'ruby' }          # 別々

# 例5
'rubyrubyruby'.scan('ruby')      # 別々

# 例6
[] << 'ruby' << 'ruby' << 'ruby' # 別々
実行結果
["ruby", "ruby", "ruby"]

定義の仕方によって、オブジェクトの中身が異なるため注意。
下記はArray.new(3, '初期値')Array.new(3) { '初期値' }の違い。

arr1 = Array.new(3, 'ruby')
arr1.each { |el| p el.object_id }
#=> 60
#   60
#   60
arr1[0].replace('RUBY')
p arr1 #=> ["RUBY", "RUBY", "RUBY"]

arr2 = Array.new(3) { 'ruby' }
arr2.each { |el| p el.object_id }
#=> 80
#   100
#   120
arr2[0].replace('RUBY')
p arr2 #=> ["RUBY", "ruby", "ruby"]
  • Array.new(3, '初期値')は要素が全て同一のオブジェクトを生成する
  • Array.new(3) { '初期値' }は要素が全て別々のオブジェクトを生成する

文字列にアスタリスクをつけるだけでもArrayを作成出来る

*"a"  #=> ["a"]

一つの変数に多重代入した場合

obj = 'a', 'b'
p obj #=> ["a", "b"]

連番の要素を持つ配列を生成する様々な方法

# 例1
(1..10).to_a

# 例2
[*1..10]

# 例3
Array(1..10)

# 例4
(1..10).map { |i| i }

# 例5
(1..10).collect { |i| i }
実行結果
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
  • 文字列でも同様。
    • 例)[*'a'..'z']

#map#collectは同じ動作をする

要素の追加(いきなりn番目の要素を指定)

arr = [1]
arr[4] = 100
rails c
irb(main):001:0> arr = [1]
=> [1]
irb(main):002:0> arr[4] = 100
=> 100
irb(main):003:0> arr
=> [1, nil, nil, nil, 100]

指定した要素分を参照・代入する

参照

arr = ['a', 'b', 'c', 'd', 'e']
p arr[1, 3]  #=> ["b", "c", "d"]

インデックス1から、3つ分の要素を取得。

代入(指定範囲内)

arr = ['a', 'b', 'c', 'd', 'e']
arr[1, 3] = ['z'] # 'z' でも同じ
p arr #=> ["a", "z", "e"]
arr = ['a', 'b', 'c', 'd', 'e']
arr[1, 3] = 'x', 'y', 'z' # ['x', 'y', 'z'] でも同じ
p arr #=> ["a", "x", "y", "z", "e"]

指定数よりも過小 or 同じ場合は、代入した値に置き換わるイメージ。

代入(指定した範囲を超えた場合)

arr = ['a', 'b', 'c', 'd', 'e']
arr[1, 2] = 'x', 'y', 'z'
p arr #=> ["a", "x", "y", "z", "d", "e"]

指定数よりも余剰の場合は、全て代入された上で、元の要素が後続にずれる。

集合(Array)

a1 = [100, 100, 100, 200, 300]
a2 = [400, 100, 300]

puts "和集合: #{a1 | a2}"
puts "積集合: #{a1 & a2}"
puts "差集合: #{a1 - a2}"
実行結果
和集合: [100, 200, 300, 400]
積集合: [100, 300]
差集合: [200]

Array#sort

配列の内容をソートします。要素同士の比較は <=> 演算子を使って行います。sort はソートされた配列を生成して返します。 sort! は self を破壊的にソートし、self を返します。
(省略)
ブロックは第1引数が大きいなら正の整数、両者が等しいなら0、そして第1引数の方が小さいなら負の整数を返さなければいけません。両者を比較できない時は nil を返します。

ary = [7, 2, 9, 1, 4, 3, 6, 8, 0, 5]

ary.sort!{ |a, b| b <=> a } # 降順に並べ替え
ary  #=> [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]

ary.reverse!
ary  #=> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

<=>演算子で比較できない要素があると、ArgumentErrorが発生する

['a', 'b', 'c', 1, 2, 3].sort #=> comparison of String with 1 failed (ArgumentError)

Array#zip

自身と引数に渡した配列の各要素からなる配列の配列を生成して返します。生成される配列の要素数は self の要素数と同じです。
ブロック付きで呼び出した場合は、 self と引数に渡した配列の各要素を順番にブロックに渡します。

p [1,2,3].zip([4,5,6], [7,8,9])
# => [[1, 4, 7], [2, 5, 8], [3, 6, 9]]

p [1,2].zip([:a,:b,:c], [:A,:B,:C,:D])
# => [[1, :a, :A], [2, :b, :B]]

p [1,2,3,4,5].zip([:a,:b,:c], [:A,:B,:C,:D])
# => [[1, :a, :A], [2, :b, :B],
#     [3, :c, :C], [4, nil, :D], [5, nil, nil]]

p [1,2,3].zip([4,5,6], [7,8,9]) { |ary| p ary }
# => [1, 4, 7]
#    [2, 5, 8]
#    [3, 6, 9]
#    nil

Array#product

レシーバの配列と引数で与えられた配列(複数可)のそれぞれから要素を1個ずつとって配列とし,それらのすべての配列を要素とする配列を返します。

返される配列の長さは,レシーバと引数で与えられた配列の長さのすべての積になります。

[1, 2].product([3, 4])  #=> [[1, 3], [1, 4], [2, 3], [2, 4]]

Array#transpose

自身を行列と見立てて、行列の転置(行と列の入れ換え)を行います。
転置した配列を生成して返します。
空の配列に対しては空の配列を生成して返します。

[[1, 3], [1, 4], [2, 3], [2, 4]].transpose  #=> [[1, 1, 2, 2], [3, 4, 3, 4]]

Array#slice

指定された自身の部分配列を返します。

p [1, 2, 3, 4].slice(2, 1) #=> [2]
p [0, 1, 2].slice(0, 2)    #=> [0, 1]
p [0, 1, 2].slice(2..3)    #=> [2]
p [0, 1, 2].slice(10, 1)   #=> nil

Array#join

[1, 2, 3].join('-') #=> "1-2-3"

*でも同じことが可能

[1, 2, 3] * '-' #=> "1-2-3"

Array#shift

配列の先頭の要素を取り除いてそれを返します。引数を指定した場合はその個数だけ取り除き、それを配列で返します。
空配列の場合、n が指定されていない場合は nil を、指定されている場合は空配列を返します。
また、n が自身の要素数より少ない場合はその要素数の配列を返します。どちらの場合も自身は空配列となります。

arr = [0, 1, 2, 3, 4]
p arr.shift          #=> 0
p arr                #=> [1, 2, 3, 4]

p [].shift           #=> nil
p [].shift(1)        #=> []

破壊的メソッド

Array#prepend

指定された obj を引数の最後から順番に配列の先頭に挿入します。引数を指定しなければ何もしません。

arr = [1,2,3]
arr.unshift
p arr             #=> [1, 2, 3]
arr.unshift 0
p arr             #=> [0, 1, 2, 3]
arr.unshift [0]
p arr             #=> [[0], 0, 1, 2, 3]
arr.unshift 1, 2
p arr             #=> [1, 2, [0], 0, 1, 2, 3]

破壊的メソッド

Array#pop

自身の末尾から要素を取り除いてそれを返します。引数を指定した場合はその個数だけ取り除き、それを配列で返します。

arr = [1, [2, 3], 4]
p arr.pop        # => 4
p arr.pop        # => [2, 3]
p arr            # => [1]

p arr.pop        # => 1
p arr.pop        # => nil
p arr            # => []

arr = [1, 2, 3]
p arr.pop(2)     #=> [2, 3]
p arr            #=> [1]

破壊的メソッド

Array#each_index

各要素のインデックスに対してブロックを評価します。

[*'a'..'c'].each_index { |i| p i }
# => 0
#    1
#    2

Array#clear

配列の要素をすべて削除して空にします。

ary = ['a', 'b']
ary.clear

p ary #=> []

破壊的メソッド

Hash

Hashの定義

key = Class.new
value = 10000

# 例1
hash = {key => value}

# 例2
hash = Hash.new
hash[key] = value

# 例3
hash = Hash[key, value]

# 例4
hash = {}
hash.store(key, value)

キーが重複している場合

hash = { a: 100, b: 200, c: 300, a: 10, c: 20 }
実行結果
irb(main):001:0> { a: 100, b: 200, c: 300, a: 10, c: 20 }
(irb):1: warning: key :a is duplicated and overwritten on line 1
(irb):1: warning: key :c is duplicated and overwritten on line 1
=> {:b=>200, :a=>10, :c=>20}

警告が出る。後ろのバリューに上書きされる。

Hashのvalueを複数取得する

hash = { apple: 100, grape: 300 }

p hash.values_at(:apple, :grape)  #=> [100, 300]

HashをArrayにする

{a: 100, b: 200}.to_a  #=> [[:a, 100], [:b, 200]]

キーが存在するかどうか調べる

hash = { apple: 100, grape: 300 }

p hash.has_key?(:apple) #=> true
p hash.key?(:apple)     #=> true
p hash.include?(:apple) #=> true
p hash.member?(:apple)  #=> true

メソッドの引数にHashを渡す

def sample(a, b, c)
  p c
end

sample 'a', 'b', {c: 'c', d: 'd', e: 'e'} #=> {:c=>"c", :d=>"d", :e=>"e"}
sample 'a', 'b', c: 'c', d: 'd', e: 'e'   #=> {:c=>"c", :d=>"d", :e=>"e"}

波括弧を省略した場合も、Hashとして渡される

Hash#invert

値からキーへのハッシュを作成して返します。
異なるキーに対して等しい値が登録されている場合、最後に定義されている値が使用されます。

h = { "a" => 0, "b" => 100, "c" => 200, "d" => 300, "e" => 300 }

p h.invert  #=> {0=>"a", 100=>"b", 200=>"c", 300=>"e"}
h = {a: 100, b: 100}

p h.invert  #=> {100=>:b}

Hash#clear

ハッシュの中身を空にします。
空にした後のselfを返します。デフォルト値の設定はクリアされません。

h = {apple: 100, grape: 300}
h.clear

p h  #=> {}

破壊的メソッド

Enumerable

Enumerable#partition

a, = (1..5).partition(&:odd?)

p a  #=> [1, 3, 5]
rails c
irb(main):001:0> (1..5).partition(&:odd?)
=> [[1, 3, 5], [2, 4]]

a =はともかくa, =っていう書き方でもエラーなく出来るんだな・・。

Enumerable#each_cons

要素を重複ありで n 要素ずつに区切り、ブロックに渡して繰り返します。
ブロックを省略した場合は重複ありで n 要素ずつ繰り返す Enumerator を返します。

(1..10).each_cons(3){ |v| p v }
# => [1, 2, 3]
#    [2, 3, 4]
#    [3, 4, 5]
#    [4, 5, 6]
#    [5, 6, 7]
#    [6, 7, 8]
#    [7, 8, 9]
#    [8, 9, 10]

実務ではまだ見かけたことないけど競プロとかで使えそう。

Numeric

Numeric#abs2

自身の絶対値の 2 乗を返します。

p 5.abs2     # => 25
p -5.abs2    # => 25
p 5.0.abs2   # => 25.0
p -5.0.abs2  # => 25.0

Numeric#step

self からはじめ step を足しながら limit を越える前までブロックを繰り返します。
step は負の数も指定できます。また、limit や step には Float なども指定できます。

rails c
irb(main):001:0> 2.step(5){|n| p n}
2
3
4
5
=> 2
irb(main):002:0> 1.1.step(1.5, 0.1) {|n| p n}
1.1
1.2000000000000002
1.3
1.4000000000000001
1.5
=> 1.1
irb(main):003:0> 10.step(6, -1){|n| p n}
10
9
8
7
6
=> 10
irb(main):004:0> 3.step(by:2, to:10){|n| p n}
3
5
7
9
=> 3
irb(main):005:0> 1.step(5,1){|n| p n}
1
2
3
4
5
=> 1

浮動小数点数の 0.1 は 2進数では正確な表現ができない
(2進数で 0.1は 0.00011001100....となる)

String

String#delete

delete(*strs) -> String
self から strs に含まれる文字を取り除いた文字列を生成して返します。

p 'Ruby on Rails'.delete('Rails') #=> "uby on "
p '0123456789'.delete('0-48-')    #=> "5679"

delete('0-48-') は、'0-4'で0〜4までの数字を取り除き、'8-'では範囲指定とは見なされず、8-を削除している。

String#split

str1 = '10;20:30;40'
p str1.split(';|:')  #=> ["10;20:30;40"]
p str1.split(/;|:/)  #=> ["10", "20", "30", "40"]

str2 = 'a,b,c,d'
p str2.split(/,/, 2) #=> ["a", "b,c,d"]

str3 = 'A-B-C'
p str3.split /(-)/   #=> ["A", "-", "B", "-", "C"]

String#strip

p "  abc  \r\n".strip    #=> "abc"
p "abc\n".strip          #=> "abc"
p "  abc".strip          #=> "abc"
p "abc".strip            #=> "abc"
p "  \0  abc  \0".strip  # => "\000  abc"   # 右側のみ "\0" も取り除く

str = "\tabc\n"
p str.strip              #=> "abc"
p str                    #=> "\tabc\n" (元の文字列は変化しない)

文字列の先頭と末尾の空白文字(\t\r\n\f\v)を取り除く。

String#chomp

p "foo\n".chomp             # => "foo"
p "foo\n".chomp("\n")       # => "foo"
p "foo\r\n".chomp("\r\n")   # => "foo"

$/ = "\n"   # デフォルト値と同じ
p "foo\r".chomp    # => "foo"
p "foo\r\n".chomp  # => "foo"
p "foo\n".chomp    # => "foo"
p "foo\n\r".chomp  # => "foo\n"

p "string\n".chomp(nil)  # => "string\n"

p "foo\r\n\n".chomp("")  # => "foo"
p "foo\n\r\n".chomp("")  # => "foo"
p "foo\n\r\r".chomp("")  # => "foo\n\r\r"

末尾から改行コードを取り除く。

String#chop

rails c
irb(main):001:0> str = "Sample   \r\n"
=> "Sample   \r\n"
irb(main):002:0> str.chop
=> "Sample   "
irb(main):003:0> str.chop
=> "Sample   "
irb(main):004:0> "Sample".chop
=> "Sampl"
irb(main):005:0> ''.chop
=> ""

末尾の文字を取り除く。空白は取り除かない。
ただし、文字列の末尾が"\r\n"であれば、2文字とも取り除く。

String#to_i

arr = [
  "a".to_i(36),  # 36進数の "a" を10進数に変換すると 10 になる。
  "070".to_i(0), # to_i(0)は文字列を適切な進数として解釈する。結果として、56(8進数の70を10進数に変換した結果)が配列に格納される。
  nil.to_i,      # nil は整数に変換されると 0 になる。
  "0b0001".to_i  # "0b0001"は2進数。10進数に変換すると 1 になる。
]

p arr #=> [10, 56, 0, 0]

Time

時刻を表すクラスです。
Time.now は現在の時刻を返します。

t = Time.now + (60 * 60 * 24) # 実行時の日時から24時間後(86400秒後)の日時
p t

Date

書式文字列 意味
%x 日付(%m/%d/%y)
%m 月を表す数字(01-12)
%M 分(00-59)
%d 日(01-31)
%D 日付(%m/%d/%y)
%y 西暦の下2桁(00-99)
%Y 西暦を表す数(9999)
require 'date'

d1 = Date.new(2024, 12, 25)
p d1.strftime('%x')       #=> "12/25/24"
p d1.strftime('%D')       #=> "12/25/24"
p d1.strftime('%m/%d/%Y') #=> "12/25/2024"
p d1.strftime('%M/%d/%y') #=> "00/25/24"

d2 = Date.parse('2024-12-25')
p d2 += 10                #=> #<Date: 2025-01-04 ((2460680j,0s,0n),+0s,2299161j)>
p d2.year                 #=> 2025
p d2.strftime('%a')       #=> "Sat"

Dir

ディレクトリの操作を行うためのクラスです。

Dir.chdir('/Users/sample/Desktop/Ruby')
p Dir.pwd # "/Users/sample/Desktop/Ruby"

Thread

スレッドを表すクラスです。スレッドとはメモリ空間を共有して同時に実行される制御の流れです。 Thread を使うことで並行プログラミングが可能になります。

Threadクラスのオブジェクトを生成するメソッド

Thread.new
Thread.fork
Thread.start

File

r: 読み込み
r+: 読み書き 書き込み時はファイル文頭から上書き
w: 新規書き込み(ファイルが既に存在していればその内容を空に。)
w+: 読み書き 書き込み時は既存の内容を削除して新規作成
a: 追記書き込み
a+: 読み書き 書き込み時はファイル末尾に追記

'a'

sample.rb
File.open('sample.txt', 'a') do |f|
  f.write("waiwai 1\n")
  f.write("waiwai 2\n")
end

実行:ruby sample.rb

sample.txt
waiwai 1
waiwai 2
# 改行

もう一度実行:ruby sample.rb

sample.txt
waiwai 1
waiwai 2
waiwai 1
waiwai 2
# 改行

'w'

sample.rb
File.open('sample.txt', 'w') do |f|
  f.write("waiwai 1\n")
  f.seek(0, IO::SEEK_SET) # ファイルポインタを0の位置まで移動する
  f.write("waiwai 2\n")
end

実行:ruby sample.rb

sample.txt
waiwai 2
# 改行

もう一度実行:ruby sample.rb

sample.txt
waiwai 2
# 改行

ファイルポインタの位置を変えて実行

sample.rb
File.open('sample.txt', 'w') do |f|
  f.write("waiwai 1\n")
  f.seek(3, IO::SEEK_SET) # ファイルポインタを3の位置まで移動する
  f.write("waiwai 2\n")
end

実行:ruby sample.rb

sample.txt
waiwaiwai 2
# 改行

r+

sample.txt(実行前)
recode 1
recode 2
recode 3
open('sample.txt', 'r+') do |f|
  data = f.read.upcase
  f.rewind # ファイルポインタを先頭に移動
  f.puts data
end
sample.txt(実行後)
RECODE 1
RECODE 2
RECODE 3
# 改行

'a+'

sample.txt(実行前)
recode 1
recode 2
recode 3
open('sample.txt', 'a+') do |f|
  data = f.read.upcase
  f.rewind # ファイルポインタを先頭に移動
  f.puts data
end
sample.txt(実行後)
recode 1
recode 2
recode 3RECODE 1
RECODE 2
RECODE 3
# 改行

w+

sample.txt(実行前)
recode 1
recode 2
recode 3
open('sample.txt', 'w+') do |f|
  data = f.read.upcase
  f.rewind # ファイルポインタを先頭に移動
  f.puts data
end
sample.txt(実行後)
# 改行1
# 改行2

join

File.join('sample', 'ruby', 'silver') #=> "sample/ruby/silver"

問題例

※ 実行結果を問う問題(実際は選択式)

例1

p "ruby" * 3 **2
実行結果
"rubyrubyrubyrubyrubyrubyrubyrubyruby"

3の2乗分増えている。

例2

a = [100, 200, 300, 500, 700]
b = [100, 300, 400, 700, 800]
c = false || true ? true && false ? a | b : a & b : b ;
p c
実行結果
[100, 300, 700]
  • false || truetrue
  • true && falsefalse
  • よって、a & b(積集合)の値が表示される
  • シンプルなイメージにすると以下
    • c = false || true ? 三項演算子 : b ;
      • 三項演算子の中で、もう一度三項演算子を使っている

例3

10.times{ |i| print i == 2..i == 5 ? 'T' : 'F' }
実行結果
FFTTTTFFFF
  • i == 2..i == 5という書き方が出来る

例4

arr = []
arr << 10 && false
true || arr << 20
false && arr << 30
false || arr << 40

p arr
実行結果
[10, 40]
  • &&演算子:左辺が真と評価された場合のみ、右辺も評価される。
  • ||演算子:左辺が偽と評価された場合のみ、右辺が評価される。

例5

p [1, 2, 3].inject{|x, y| x + y ** 2} rescue p $!
p [1, 2, 3].inject(0){|x, y| x + y ** 2} rescue p $!
p [1, 2, 3].inject([]){|x, y| x << y ** 2} rescue p $!
p [1, 2, 3].inject {|x, y| x + y ** 2} rescue p $!
p [1, 2, 3].inject do|x, y| x + y ** 2 end rescue p $!
実行結果
14
14
[1, 4, 9]
14
#<LocalJumpError: no block given>

do ... end{ ... }を比べた場合、{ ... }の方が結合度が強い

#injectdo...endを使用する場合は、以下のようにする

result = [1, 2, 3].inject(0) do |x, y|
  x + y ** 2
end

p result  #=> 14

Enumerable#inject

リストのたたみこみ演算を行います。

numbers = [1,90,40,39,29,10,30,50,69]
num = numbers.inject do |i, j|
  i > j ? i : j # 2つの整数値を比較し、より大きな値を取り出しそれをブロックに渡す
end

p num #=> 90

前回のブロックの戻り値をブロックに渡して繰り返し実行する

$! とは

最後に例外が発生したときの Exception オブジェクトです。該当する例外がないときは nil です。
Kernel.#raise によって設定されます。
この変数はスレッドローカル、読み取り専用です。

例6

def hoge(step = 1)
  current = 0
  Proc.new {
    current += step
  }
end

p1 = hoge
p2 = hoge(5)

p1.call
p1.call
p1.call
p2.call
p2.call

p p2.call
実行結果
15

Proc

Proc がローカル変数のスコープを保持している

  • 今回の場合、#hogeは一度しか呼ばれていない
    • よって、ローカル変数currentの初期化も一回のみ
    • 途中でp2 = hoge(3)等として#hogeを呼び出せばcurrentは初期化される
  • Procはローカル変数のスコープを保持している
    • p2.callが呼ばれる度に5ずつインクリメントされる
    • p1p1で値を保持している

例7

class SuperCalc
  attr_reader :s
  def initialize(x, y)
   @s = x * y
  end
end

class SubCalc < SuperCalc
  attr_reader :v
  def initialize(x, y, z)
    super(x, y)
    @v = x * y * z
  end
end

obj = SubCalc.new(2,5,7)
puts "#{obj.s}, #{obj.v}"
実行結果
10, 70
  • superを使えば、親クラスの同名のメソッドを呼び出すことが可能。
  • superには通常のメソッドと同じように引数も指定可能。

例8

p "Ruby Silver".class
p String.superclass

class Hoge; end
class Foo < Hoge; end

p Hoge.superclass
p Foo.superclass
実行結果
String
Object
Object
Hoge

#classはオブジェクトのクラス、#superclassはそのクラスのスーパークラスを返す。明示的にスーパークラスを指定しない場合は、Objectがスーパークラスとなる。

例9

foo = ['a', 'b', 'c']
bar = foo
baz = foo.dup

bar[3] = 'd'
p foo
p bar
p baz
実行結果
["a", "b", "c", "d"]
["a", "b", "c", "d"]
["a", "b", "c"]

変数 foobar は同じ配列オブジェクトを参照している。

p foo.object_id #=> 60
p bar.object_id #=> 60
p baz.object_id #=> 80

例10

class Object
  def food
    p 'rice'
  end
end

['a', 'b'].food
{a: 1, b: 2}.food
実行結果
"rice"
"rice"

Arrayクラス、Hashクラス共にObjectクラスを継承している。
Rubyでは組み込みクラスを含め、定義済みのクラスに対してメソッド追加・既存メソッドの書き換えが可能。

例11

print "waiwai\n" unless false || nil
実行結果
waiwai

unless false || nilの条件は、if !false && !nilと同じ意味(ドモルガンの法則

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1