Day 2 ~ 13: Ruby 認定試験による勉強

 / #cebu #ruby

ソースコードの文字コードをUS-ASCIIに設定のマジックコメント

# 1. coding: us-ascii
# 2. encoding: us-ascii
# 3. -*- charset: us-ascii -*-
# 4. CODING: US-ASCII

1,2,4 は同義で、正解。3 は Python。

例外処理(begin rescue ensure end

Wikipedia

プログラムの上位の処理から呼び出されている下位の処理で継続不能、または継続すれば支障をきたす異常事態に陥ったとき、制御を呼び出し元の上位の処理に返し安全な状態になるよう回復処理をすること。

begin
# 例外が起こりうるコード1
rescue => # 変数(例外オブジェクトの代入)
# 例外が起きた場合のコード2
ensure
# 例外の有無に関わらず、実行するコード3
end

1 で例外が起きなかったら、表示結果は 1 且つ 3 の表示結果、起きた場合は 2 且つ 3 の表示結果となる。 例外処理コードとして、ensure が用いられないパターンもある。 その他、rescue のなかで retry を用い、begin が成功するまで繰り返す処理がる。(無限ループ注意)

定数と変数

下コードの実行結果は『10 と表示された後、警告が表示され 100 と表示される。』

MAX=10
print MAX
MAX=100
print MAX

Ruby において、アルファベット大文字から始まる識別子(ABC や Abc)は定数。 他言語では定数を再定義しようとすると、警告が出て、結果、再定義できない。 Ruby においては、警告が出たのち、そのままデータがオーバーライトされる。

可変長引数

def foo(*a)
p a
end
foo(1,2,3)
#実行結果 [1,2,3]

*を 1 個つけると、引数を複数指定でき、引数は配列として受け取られる。 *を 2 個つけると、オプション引数となり、Hash として受け取られる。

def sum (##AAA##)
total = 0
a.each {|i| total += i }
return total
end
puts sum(1, 2, 3, 4, 5)
=>15

範囲オブジェクトとeach

.to_i

文字列を 10 進数の表現と見なして整数に変換します。

#引数baseを取ることもでき、その引数で何進数かを示す。
#デフォルト値は10であり、引数指定しない場合は10進数となる。
変数.to_i(2)

範囲オブジェクト

def hoge
x = 0
(1...5).each do |i|
x += 1
end
puts x
end
hoge
#実行結果 4

まず『数 A...数 B』に関して、これは A から B まで繰り返すの意。ただし、B は含まれない。 そのため、『1...5』は、1 から 4 までの 4 回分繰り返す。 一方で、『1..5』は 5 を含み、1 から 5 までの 5 回分繰り返す。 因みに、『1..5』『101..105』『2001..2005』だろうと 5 回分。

#範囲オブジェクト等:問題
a = [1,2,3,4]
#ここに代入する式を選択して下さい。
a.each do |i|
print i, " "
end
#実行結果
1 2 3
# 選択肢
1: a[0..3], 2: a[0..-2], 3: a[0...-2], 4: a[0...-3],
5: a[3,0], 6: a[0,3], 7: a[2,0], 8: a[0,2]
# 答えは2と6

1 から 10 まで表示 s るコードを選べ

  1. (1.10).each do |i| puts i end
  2. (1..10).each do |i| puts i end
  3. (1...10).each do |i| puts i end
  4. (1....10).each do |i| puts i end

ans => 2

定義されているのは、点2つと点 3 つ。 2つは2から 10 以下、3 つは2から 10 未満

upto

money = 1000
オブジェクト.upto(max) do |i|
実行処理
end
money = 100
1.upto(3) do |i|
money = money * 1.1
end
puts money.to_i

upto メソッドは、変数に「対象オブジェクトが持つ数値」から「max」までを順に代入しながら、処理実行。 1 回繰り返すごとに 1 ずつ数値は増加します(ここでは1から3までの 3 回。『1..3』と同義)。 また、downto メソッドもあり、これは 1 回繰り返すごとに 1 ずつ数値が減少する。 times メソッドも参照すべし。

step

オブジェクト.step(limit, stepno) do |変数|
実行する処理1
実行する処理2
end

はじめに、stemno を『数値間隔』とするとわかりやすい。 対象オブジェクトを持つ数字から順に代入しながら、処理を実行。 1 回繰り返すごとに、stepno で指定した数値間隔ごとに、数値が増加する。

範囲オブジェクト、uptoメソッドまとめ

money = 1000
rate = 1.1
2001.upto(2004) do |i|
money = money * rate
puts "I got #{money.to_i} in #{i}."
end
#実行結果
# I got 1100 in 2001.
# I got 1210 in 2002.
# I got 1331 in 2003.
# I got 1464 in 2004.

これは、下とも書ける

money = 1000
rate = 1.1
(2001..2004).each do |i|
money *= rate
puts "I got #{money.to_i} in #{i}."
end

変数、定数いろいろ

  • ローカル変数
    • アルファベット小文字または`_'で始まる識別子
  • グローバル変数
    • $で始まり、宣言が必要なく、プログラムのどこからでも参照できる。
    • 初期化されていないグローバル変数を参照した場合、値は nil。
  • インスタンス変数
    • @で始まり、特定のオブジェクトに属する。
    • そのクラスまたはサブクラスのメソッドから参照できます。
    • 初期化されていないインスタンス変数を参照した場合、値は nil。
  • クラス変数
    • @@で始まり、クラス定義のなかで定義される
    • クラスの特異メソッド、インスタンスメソッドなどから参照/代入ができる。
  • 定数
    • アルファベット大文字で始まる。
    • 他の言語では『定数』なので、再定義しようとしても、警告が出て、再定義できない。
    • Ruby では、再定義しようとすると、警告が出るが、再定義できてしまう。

super

親クラスのメソッドを呼び出す

class User
attr_accessor:say
def initialize
@say = "Hello"
end
end
class Oriver < User
def initialize
super
end
end
oriver = User.new
puts oriver.say
#実行結果:Hello
#この時、superメソッドは親クラスのUserから、@sayを呼び出している

attr_accerssor(attr_readerとattr_writer)

  • attr_accerssor はゲッターとセッターの機能があるアクセスメソッド
  • インスタンス変数の値はクラス内からしか取得できない。
  • クラス外からインスタンス変数を取得更新するには、ゲッター、セッターが必要
    • Progate の PHP の方なら説明がちゃんとあった。

include (モジュール名, モジュール名, ...)

クラスやモジュールに、他のモジュールをインクルードする。 引数にはモジュールを指定し、上の様に複数指定できる。

Math module

浮動小数点演算をサポートするモジュール。

#円の面積
include Math
def area r
return r * r * PI
end
#球の体積
def volume r
return (4/3) * r * r * r * PI
end
#πの値
puts PI #結果:3.141592653589793
area(2) #結果:12.566370614359172
volume (2) : 25.132741228718345

これは便利。

演算子のオーバーライド

Ruby の場合、演算子の多くがただのメソッドとして定義。

再定義できる演算子

| ^ & <=> == === =~ > >= < <= << >>
+ - * / % ** ~ +@ -@ [] []= ` ! != !~

再定義不可の演算子

演算子の組合せである自己代入演算子は再定義できない。

= ?: .. ... not && and || or ::

演算子の定義方法

# 二項演算子
def +(other) # obj + other
def -(other) # obj - other
# 単項プラス/マイナス
def +@ # +obj
def -@ # -obj
# 要素代入
def foo=(value) # obj.foo = value
# [] と []=
def [](key) # obj[key]
def []=(key, value) # obj[key] = value
def []=(key, key2, value) # obj[key, key2] = value
# バッククォート記法
def `(arg) # `arg` または %x(arg)

メソッドのオーバーライドと比較演算子

##比較演算子と<< :問題
class Employee
attr_reader :id
attr_accessor :name
def initialize id, name
@id = id
@name = name
end
def to_s
return "#{@id}:#{@name}"
end
#ここに代入する式を選択して下さい。
end
employees = []
employees << Employee.new("3","Tanaka")
employees << Employee.new("1","Suzuki")
employees << Employee.new("2","Sato")
employees.sort!
employees.each do |employee| puts employee end
# 実行結果
1:Suzuki
2:Sato
3:Tanaka
# 選択肢
# 1 (答え)
def <=> other
return self.id <=> other.id
end

比較演算子 <=>

12
a < b-1
a == b0
a > b1
比較不可nil

<< とは

<<<演算子(メソッド)は、左辺の配列(レシーバ)の末尾に右辺のオブジェクトを要素として加えます。

#例
animals = ["dog", "cat", "mouse"]
animals << "pig"
p animals
["dog", "cat", "mouse", "pig"]

&& & and|| | or の違い

#問題
a = [1,2,3,4]
b = [1,3,5,7]
#ここに代入する式を選択して下さい。
c = XXXX
c.each {|i| print i, " " }
#出力結果
1 3
#選択肢
1: a+b, 2: a-b, 3: a & b, 4: a && b, 5: a | b, 6: a || b
#解答 3
  • &&演算子
    • 左辺の評価結果が false の場合は、右辺を評価せずに次の処理に進む
  • || 演算子
    • 左辺の評価結果が true の場合は、右辺を評価せずに次の処理に進む
  • |演算子と&演算子
    • 左辺の評価結果に関係なく、右辺を評価する

配列のメソッド

適切なものを選べ

# 問題選択肢
1. find_allとselectは同じ動作をする。
2. mapとcollectは同じ動作をする。
3. findとselectは同じ動作をする。
4. firstは先頭要素を削除し、その要素を返す。
5. concatは非破壊的メソッドである。
6. concat!は破壊的メソッドである。
#解答
1と2

select と find_all

同じ動作を、条件に合う配列をそのまま出力

#select
[1, 2, 3, 4, 5].select{ |v| v % 2 == 1 }
=> [1, 3, 5]
#find_all
[1, 2, 3, 4, 5].find_all{ |v| v % 2 == 1 }
=> [1, 3, 5]

map と collect

同じ動作をし、条件にある配列を true or false で出力

#map
[1, 2, 3, 4, 5].map{ |v| v % 2 == 1 }
=> [true, false, true, false, true]
#collect
[1, 2, 3, 4, 5].collect{ |v| v % 2 == 1 }
=> [true, false, true, false, true]

find

findは先頭要素だけ出力

#find
[1, 2, 3, 4, 5].find{ |v| v % 2 == 1 }
=> 1

破壊的メソッドconcat

concat!は定義されていない

val = [ "a", "b" ]
c=> ["a", "b"]
val.concat( ["c", "d"] ) #=> [ "a", "b", "c", "d" ]
=> ["a", "b", "c", "d"]l
puts val
a
b
c
d

最後、val の値が変化しているところ、、要注意

zip[array]

コード結果を選べ

a1=%w(a b)
a2=%w(x y)
a3=a1.zip(a2)
p a3.first
# 選択肢
1: "a", 2: ["a"], 3: ["a", "x"], 4: ["a", "b"], 5. 例外が発生する。
# 解答

instance method Array#zip

zipメソッドは、配列の要素を引数の配列other_arrayの要素と組み合わせ、配列の配列を作成して返します。行と列を入れ替えるが、足りない要素はnilで埋められ、余分な要素は捨てられます。

arr1 = [1, 2, 3]
arr2 = [4, 5]
arr3 = [6, 7, 8, 9]
p arr1.zip(arr2, arr3)
[[1, 4, 6], [2, 5, 7], [3, nil, 8]]

実行結果になるように、##AAA##に記述するコードを選んでください

a = ["a", "b", "c"]
b = [1, 2, 3]
##AAA##
#実行結果
["a", 1]
["b", 2]
["c", 3]
#選択肢
a.zip(b).each{|x| p x }
a.zip(b){|x| p x }
[a, b].zip{|x, y| p [x, y] }
[a, b].transpose.each{|x, y| p [x, y] }
#答え 1,2,4

行と列を入れ替える。足りない要素は nil を返す

%w()

配列を作る。配列の要素はスペース区切りで指定する。 式の展開はされない。

slice()

実行結果をかけ

a = [1,2,3,4,5]
p a.slice(1,3)
#答え

要参照

slice メソッドは、[]メソッドの別名です。配列から引数で指定した位置の要素を取り出して返す。

equal

実行結果を書け

a = "abc"
b = "abc"
print a.eql? b
print a.equal? b
print a == b
# =>
# true false true

eql?

ハッシュの内部で「同じキーかどうか」を調べるために使われるメソッドで、今回はレシーバ abc が引数 abc と同じかどうか調べている

eqal?(object)

レシーバ obj と引数 other_obj が同じオブジェクトなら true、別のオブジェクトなら false を返す。 objent 絡みなので、変数名が違うと、false を返すのだろう。。。?

型の取り扱い:エラーにならないものを選べ

select

  1. puts 5 + "Hello"
  2. puts "Hello" + 5
  3. puts "Hello" * 5
  4. puts 5 * "Hello"

integerとstring

勘違いしていた 例えば、puts hoge + "ほげ"であっても、hoge が整数型の変数なら、hoge ほげと返す

concatとchopとchomp:実行結果を書け

s1 = "Hoge"
s2 = "Fuga"
s1.concat(s2)
s1.chop
s1.chomp
s1 + s2
puts s1
# => ?

concat

破壊的メソッド。<<push() に似ている

chop

文字列の末尾から 1 文字を取り除いた新しい文字列を返す。 \r\n で終わっている場合だけは、 \r\n の 2 文字を取り除きます。

chomp

文字列の末尾の改行文字を取り除いた新しい文字列を返す。 改行文字は"\n"、"\r\n"、"\r"のどれでも取り除きます

# irb
s1 = "Hoge"
s2 = "Fuga"
s1.concat(s2)
# .c=> "HogeFuga"
# chopでs1末尾のeが取り除かれる
s1.chop
# => "HogeFug"
# s1に改行文字は含まれていない
s1.chomp
# => "HogeFuga"
# 文字型同士の和は可能
s1 + s2
# => "HogeFugaFuga"
# concatの破壊的性質により、s1.concat(s2)の時点で、s1がHogeFugaに。
puts s1
# HogeFuga

[]メソッド

s = "123456789"
p s[1,4]
# =>
# "2345"

まず、範囲オブジェクトの類だと思っていた。

要参照: [] (Array)

slice()の別名

[]

[]メソッドは、配列から引数で指定した位置の要素を取り出して返します。引数には、整数(位置)、整数 2 つ(位置と数)、範囲を指定できます。

{}

Hash 作成

invert

キーを値に、値をキーにしたハッシュを作成

% 等々

回答を選択しから選べ

member = [10, "Tanaka"]
print "ID:%2d Name:%s" #ここに代入する式を選択して下さい。
member
# 実行結果
ID:10 Name:Tanaka
# 選択肢
1: , ,2. +
3. % ,4. .format
#答え %

key

has_key?メソッドは、ハッシュが引数 key と同じキーを持っていれば true、なければ false を返します。 key?メソッド、include?, member?メソッドは、has_key?の別名

delete_all

検索で delete hash はヒットするが、delete_all hash はヒットしない

Hashクラス

ハッシュオブジェクトの元になっているクラス

select uncorrect

  1. delete はキーを指定してキーと値の組を削除する。
  2. remove はキーと値の組を削除する。
  3. fetch は与えられたキーに関連付けられた値を返す。
  4. clear はハッシュの要素をすべて削除する。

ans => 1, 4

実行結果をかけ

#{} の問題
v = {}
v.class
#出力答え Hash

実行結果をかけ

#invert array : 問題
v = {:v1 => 1, :v2 => v}
v.invert
#出力答え {1=>:v1, nil=>:v2}

適切な選択肢を

#配列、シンボル 問題
h = #ここに代入する式を選択して下さい。
p h
#選択肢
1: {a:1,b:2,c:3}, 2: {a=1,b=2,c=3}
3. Hash[:a, 1, :b, 2, :c, 3], 4: {:a1,:b2,:c3}
#実行結果
{ :a => 1, :b => 2, :c => 3 }
#答え 4

select

  1. {} で空の Hash オブジェクトを生成できる。
  2. [] で空の Hash オブジェクトを生成できる。
  3. invert でキーと値を入れ替えることができる。
  4. key に対応する値を取り出すメソッドとして、has_key?(key)、key?(key)、get_ key(key)などが用意されている。
  5. すべての要素を削除するには、delete_all を使用する。

=> ans 3と2(答えを忘れた。あとでまた調べる)

delete

ハッシュから引数 key と同じキーを探して、キーと値を削除。レシーバ自身を変更するメソッド

fetch

ハッシュから引数で指定したキーの値を取り出して返します。[]メソッドと機能は同じ。だがキーが存在しないときの動作が異なる

clear

キーと値をすべて削除し、ハッシュを空にします。レシーバ自身を変更するメソッド

%d%s, %

%d

数字を文字列にしている

sprintf("%d", 4);
=> "4"
# %2d 2桁の文字列を返す
sprintf("%2d", 4);
=> " 4"
# %02d 2桁の文字列を返す。桁数が足りない場合は、前に0を追加。
sprintf("%02d", 4);
=> "04"

%s

シンボル:をつける。式の展開はされない。

ioクラス

実行結果を

# ファイルdataの内容はabcdefg
File.open("data") do |io|
while not io.eof?
print io.read(1)
io.seek(0,IO::SEEK_SET)
end
end
#答え: aが表示され続ける

CPU が 6 割、メモリ6GB 食われてた。

EOFとは

End of File の略

ioクラスメソッド、SEEK_SET

instance method IO#seek

ファイルポインタを whence の位置から offset だけ移動させます。 offset 位置への移動が成功すれば 0 を返します

ファイル上の文字にポインタなる住所のようで住所じゃないものがある。らしい 今回は、io.seek(0,I/O::SEEK_SET)でオフセットを 0 に指定しているため、 文字の読み込みが最初の a からすすまない(ずっと a が読み込まれる)らしい

strgtime

実行結果にあう、選択肢を選べ

# 問題
t = Time.gm(1970,1,1)
puts t.strftime("#ここに代入する式を選択")
# => 1970/01/01
#選択肢
1, %y/%m/%d ,2, %Y/%M/%d
3, %y/%M/%d ,4, %Y/%m/%d
#答え:4

strgtimeメソッド

instance method Time#strftime

strgtimeで代表的なもの

1234567
4桁の西暦2桁の西暦時刻
%Y%y%m%d%H%M%S

Rubyの予約語

予約語を選べ

# 問題
while rand
goto class const
#答え whileとclass

予約語: すでに Ruby 側で定義されている言葉。自分で使おうとしても使えない。

to_s

実行結果をかけ

# 問題
x = 0
[1,2,3].each do |x|
print x.to_s + " "
end
puts x
#解答 1 2 3 0
# 1,2,3は表示上は数字型だか、実は文字型

to_s:整数型データを文字型に変換する

検証コード

x = 0
[1,2,3].each do |x|
print x.to_s + " "
print x.to_s.class
end
puts x
# =>
# x = 0
[1,2,3].each do |x|
print x.to_s + " "
print x.to_s.class
o_s.class
end
puts x
# 0
# => nil

Rubyの偽の値

#問題
nil 0 "" false 0.0 NULL
#解答 nil と false

例外処理: 適切な選択肢を

# 問題
y = false
y ##AAA## (raise "failed")
puts("succeeded!")
#選択肢
1, | ,2, || ,3, & ,4, &&
#答え &&

&&演算子

&&演算子は左辺の評価結果が false の場合は、右辺を評価せずに次の処理に進む。 || 演算子は、左辺の評価結果が true の場合は、右辺を評価せずに次の処理に進む。 |演算子と&演算子は、左辺の評価結果に関係なく、右辺を評価する。

raise 例外

raise は例外を投げるので、それ以降の処理を飛ばす それを捕捉したい場合は、begin rescue end を使う

今回の場合、raise が実行されると puts("succeeded!")が実行されないのを、考慮

gsub

実行するとどうなる

# 問題
HOGE = "hoge"
HOGE.gsub!("hoge", "piyo")
print HOGE
# 答え 警告は発生せず、「piyo」が表示される。

gsub! :破壊的メソッド

アルファベット大文字で始まる識別子は定数は定数なので、新たに代入する際には警告が発生します。 しかし、gsub!は破壊的メソッドを呼び出しているだけなので、警告は発生せず、文字列は「piyo」に書き換わります。

例外

正しい記述を選べ

  1. begin によって例外を捕捉する際は、例外の可能性がある処理を begin から rescue の間に記述する。
  2. 1つの処理に対して複数の rescue は、指定できない。
  3. 例外オブジェクトのメソッド stacktrace により、例外スタックを取得できる。
  4. ensure は、必ず記述する必要がある

ans => 1

stacktraceとは

stack trace - 「分かりそう」で「分からない」でも「分かった」気になれるIT用語辞典

エラーが発生したときに表示される内容で、そのエラーが発生するまでの過程(どんな処理がどの順番で呼び出されたかの流れ)を、ざっくりと表示したもの

エラーコード

次のコードの ##AAA##ZeroDivisionError が発生したときの処理を記述したい。適切なコードを選択

# 問題
begin
puts 10 / 0 #ZeroDivisionError
##AAA##
print "ZeroDivisionException:", ex.message
end
  1. rescue ZeroDivisionError = ex
  2. rescue ZeroDivisionError ex
  3. rescue ZeroDivisionError -> ex
  4. rescue ZeroDivisionError => ex

ans => 3

試してみて

begin
puts "hello"
puts 10 / 0
puts "good afternoon"
puts "good afternoon"
puts "good afternoon"
puts "good afternoon"
puts "good afternoon"
puts "good afternoon"
rescue ZeroDivisionError => ex
puts "good bye"
print "ZeroDivisionException:", ex.message
end
begin
puts "hello"
puts 10 / 0
puts "good afternoon"
puts "good afternoon"
puts "good afternoon"
puts "good afternoon"
puts "good afternoon"
puts "good afternoon"
rescue Exception => ex
puts "good bye1111111"
print "message:", ex.message
rescue ZeroDivisionError => ex
puts "good bye2222222"
print "ZeroDivisionException:", ex.message
end

参照: Ruby 例外について

?A

コード実行どうなる

# 問題
p ?A
#答え "A"

=>

#コード1
p "A".ord
# => 65
#コード2
p 65.chr
#=> "A"

65とは

Unicode 上の A の番号的な

クラスの継承

# エラーにならないものを選べ
class Hoge < Object ; end
class Hoge << Object ; end
class Hoge < Kernel ; end
class Hoge << Kernel ; end
# A 1のみ

クラスの継承は< なお、Kernel はモジュールなので不可

module Kernel

Kernel.call
=>Module

すべてのクラスから参照できるメソッドを定義しているモジュール。 Object クラスはこのモジュールをインクルードしています。Object クラスのメソッドは実際にはこのモジュールで定義されています。

to_i(n)

to_i メソッドは、文字列を n 進数の表現と見なして整数に変換。文字列の先頭から 10 進数と見なせる部分を切り取って変換し、見なせる部分がなければ 0 を返す。

p "12abc".to_i =>123
p "abc12".to_i =>0
p "ab12c".to_i =>0
p "1abc2".to_i =>`1

正規表現

s = "a;b:c;d:e;f"
p s.split (/:|;/)
=>["a", "b", "c", "d", "e", "f"]
p "abc def 123 ghi 456".scan(/\d+/).length
=> 2

\dは 10 進数なので、10 進数から始まる部分を配列で返し(scan)、その要素の数 length を返してる

配列と範囲オブジェクト

a=[1,2,3,4]
a[1,3] => [2,3,4]
a[1..3] => [2,3,4]
a[1...3] => [2,3]
a[1....3] => error
a[2..-1] => [3,4]

範囲オブジェクトは文字列にも使える

a="abcdefghijk"
a[1,3] = "x"
p a # => "axefghijk"
a[1..3] = "x"
p a # => "axefghijk"
a[1...3] = "x"
p a # => "axdefghijl"

&と&&、|と||

a = [1,2,3,4]
b = [1,3,5,7]
p a & b =>[1, 3]
p a && b =>[1, 3, 5, 7]
p a | b =>[1, 2, 3, 4, 5, 7]
p a || b =>[1, 2, 3, 4]
1作用
&日本語の”且つ”と同じ。
&&左辺が真なら、右辺を評価して、右辺を返す
``
`

※パイプ=『|』。エスケープできなかった

破壊的メソッド delete_if = reject!

ブロックの戻り値が真になった要素を削除。なお、reject は非破壊的

a= [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
a.delete_if{|v| v % 2 == 0 }
=>[1, 3, 5, 7, 9]
p a => [1, 3, 5, 7, 9]

enum.each_with_index {|item, idx| block }

繰り返しごとにブロック引数 item には各要素が入り、idx には 0,1,2 と番号が入る

a = ["apple", "orange", "grape", "pine"]
a.each_with_index{ |item, i| print i, ":", item, "\n" }
=>
0:apple
1:orange
2:grape
3:pine

array.each_index {|index| block }

『ほぼ』each_with_index と同じ。繰り返しごとにブロック引数には各要素のインデックス(位置)の整数が入ります。戻り値はレシーバ自身

hash.each_pair {|key, val| block }

each と同じ

hash.each_key {|key| block }

繰り返しごとにブロック引数 key にはキーが入る。

hash.each_value {|val| block }

繰り返しごとにブロック引数 val にはキーの値が入る。each_何たらが他にも結構あるので、見ておこう

破壊的メソッド: shift とunshift

shift メソッドは、配列の最初の要素を削除し、その要素を返します。レシーバ自身を変更するメソッドです。配列が空のときは nil を返します。

s = ["one","two","three"]
s.shift => "one" ※先頭のoneを削除
s.shift => "two" ※先頭のtwoを削除
s.unshift => ["three"] ※引数が無いので、何もしてない
s.push "four" => ["three", "four"]
p s =>["three", "four"]

compact()uniq()

a = [:a,:a,:b,:c]
a[5] = :e
a.concat([:a,:b,:c])
a.compact
a.uniq
p a
=> [:a, :a, :b, :c, nil, :e, :a, :b, :c]

concat, compact, uniq のうち、破壊的メソッドは concat のみなので、結果、元の配列 a に影響を及ぼすのは concat のみ

concat() 破壊的メソッド

push()<< と同じ

配列の末尾に引数を結合。感嘆符が無い破壊的メソッド

conpact 非破壊的

配列から nil を取り除いた、新しい配列を作成感嘆符がついた conpact!が破壊的。

uniq 非破壊的

配列から重複した要素を取り除いて、新しい配列を作成感嘆符が付くと破壊的に。

arr = [1, 2, 5, 5, 1, 3, 1, 2, 4, 3]
p arr.uniq
[1, 2, 5, 3, 4]

map

collect

a = [1, 2, 3, 4, 5, 6]
a.collect {|v| v * 2}
=> [2, 4, 6, 8, 10, 12]
a.inject {|v| v * 2}
=> 32
a.each {|v| v * 2}
=> [1, 2, 3, 4, 5, 6]
a.map {|v| v * 2}
=>[2, 4, 6, 8, 10, 12]
a.select {|v| v * 2}
=> [1, 2, 3, 4, 5, 6]
a.execute {|v| v * 2}
=> error undefined method

どうしたらinjectが32になるか、リファレンス見ても理解できない

%w記法

配列を作る

sarray = %w(Apple Orange Grape)
sarray.each {|v| print v, " "}
#
Apple Orange Grape

transpose

zip と同様、行と列を入れ替える。要素が足りない場合、例外 IndexError を発生。

EOB

次のコードは正しく動きません。修正案を。

s = <<EOB
Hello, Ruby World.
Hi, Ruby World.
Goodbye, Ruby World.
EOB
#解答
5行目のEOBの前の空白を削除する。

encoding

puts "hello".encoding.name
UTF-8
=> nil

chop 非破壊的

文字列の末尾から 1 文字を取り除いた新しい文字列を返す。!が付くと、破壊的

chomp 非破壊的

文字列の末尾の改行文字を取り除いた新しい文字列を返す。! が付くと、破壊的

^ キャレット

名をキャレット、否定をする

puts "0123456789-".delete("^13-56-")
=> 13456-

13456-に該当『しない』ものを削除している

scan(string)

指定した正規表現のパターンとマッチする部分を文字列からすべて取り出し、配列にして返す。

p "HogeHOGEhoge"[/[A-Z][^A-Z]+/]
=> "Hoge"

大文字と小文字のアルファベットで構成される文字列を返している

invert(hash)

hash のキーと値を入れ替える

h = {1 => "Hoge", 2=> "Piyo", 3=>"fuga"}
p h.invert
#
{“Hoge”=>1, “Piyo”=>2,“fuga”=>3 }

update と sort

a = {"Foo" => "Hoge", "Bar" => "Piyo", "Baz" => "Fuga"}
b = {"Foo" => "hoge", "Bar" => "piyo", "Baz" => "fuga"}
p a.update(b).sort{ |a, b| a[1] <=> b[1] }
[["Baz", "fuga"], ["Foo", "hoge"], ["Bar", "piyo"]]

update

わかりづらい

sort

配列の要素をソートした新しい配列を返します。要素 1 と要素 2 の比較結果が-1 なら要素 1 が先、0 なら同じ、1 なら要素 2 が先となります。

ルート

次のコードは、ファイル test . txt を読み、文字を逆順に書き込む処理です。「##AAA##」に入る適切な記述を選びなさい。

open("test.txt","##AAA##") do |f|
data = f.read.chomp
data.reverse!
f.rewind
f.write data
end
#選択肢
# a, w, r, a+, r+, w+

組み込み関数 open の第 2 引数には、ファイルのオープン モードを指定します。

  • r、w、a に + をつけると、読み書き両用でオープンします。
  • w+ を指定すると元ファイルの内容を空にします。
  • a+ を指定すると、追記モードとなり、 元のファイルを書き換えることができません。

chr と ord は対義語的

puts 65.chr => "A"
puts "a".ord => 97

コードポイントの話。n.chr は,n で登録されている文字を返す。string.ord は string のコードポイントを返す。メソッドの意味は覚えてるけど、もう『65 を見たら A』と覚えるしか。

securerandom Module

安全な乱数発生器のためのインタフェースを提供するモジュール

require 'securerandom'
SecureRandom.urlsafe_base64

urlsafe_base64

ランダムで URL-safe な base64 文字列を生成して返します。