メタプログラミング以前


参考：http://www.atmarkit.co.jp/ait/articles/1409/29/news035.html

#メソッド

##method(引数)による定義

```rb
def parrot(word)
  puts word
end

parrot("meow") # => meow
```

##引数のデフォルト値

```rb
def parrot(word="default word")
  puts word
end

parrot("meow") # => meow
parrot # =>  default word
```


##括弧の省略
メソッドの定義、実行時には括弧を省略できる

```rb
def parrot word
  puts word
end

parrot "test" # => test
```

括弧の省略はしないほうがよい。
ただ、RubyおよびRailsではあえて括弧を付さないケースがある

attr_accessor, before_filter, validateなど

##メソッドの返り値

メソッドは必ずオブジェクトを返す。
返す値は、最後に評価されたオブジェクトとなる

```rb
def sum(x,y)
  x+y
end

def redundant_sum(x,y)
  return x+y
end

p sum(21,21)
p redundant_sum(x,y)
```

##可変長引数
`*`を使うことで,可変長引数をとることができる

```rb

def sum(*args)
  puts args.class
  args.inject(:+)
end

p sum(1,2,3,4,5)
p sum
```

##キーワード引数
引数の順番や内容を管理するための方法

```rb
def basic_form(a: "a", b: ["b", "b", "b"], c: :c)
  puts "a(#{a.class}): #{a}"
  puts "b(#{b.class}): #{b}"
  puts "c(#{c.class}): #{c}"
end

def complex_form(a, *b, c: "c", d:)
  puts "a(#{a.class}): #{a}"
  puts "b(#{b.class}): #{b}"
  puts "c(#{c.class}): #{c}"
  puts "d(#{d.class}): #{d}"
end

basic_form(a: 2)
# => a(Fixnum): 2
# => b(Array): ["b", "b", "b"]
# => c(Symbol): c

basic_form(b: 2)
# => a(String): a
# => b(Fixnum): 2
# => c(Symbol): c

basic_form(c: :borrow)
# => a(String): a
# => b(Array): ["b", "b", "b"]
# => c(Symbol): borrow

basic_form
# => a(String): a
# => b(Array): ["b", "b", "b"]
# => c(Symbol): c

complex_form("aa", "bb", c: 2, d: :borrow)
# => a(String): aa
# => b(Array): ["bb"]
# => c(Fixnum): 2
# => d(Symbol): borrow

complex_form("aa", d: :borrow)
# => a(String): aa
# => b(Array): []
# => c(String): c
# => d(Symbol): borrow

complex_form("aa", "bb", d: :borrow)
# => (String): aa
# => b(Array): ["bb"]
# => c(String): c
# => d(Symbol): borrow

complex_form("aa", "bb", "cc", d: :borrow)
# => a(String): aa
# => b(Array): ["bb", "cc"]
# => c(String): c
# => d(Symbol): borrow
```

#ブロック
メソッドに処理そのものを引数として渡す

```rb
def repeat(n)
  for i in 1..n
    puts "#{i} =>"
    yield
  end
end

repeat(3) {puts "pyonpyon"}

repeat(3) do
  puts "pyonpyon" 
end

repeat 3 do
  puts "pyonpyon" 
end
```

ブロック引数があるかどうかで処理を分ける

```rb
def arithmetic_sequence(init: 1, diff: 1, count: 10)
  current = init
  if block_given?
    p "1 block"
    count.times do
      yield(current)
      current += diff
    end
  else
    p "no block"
    Array.new.tap do |a|
      count.times do
        a << current
        current += diff
      end
    end
  end
end

p arithmetic_sequence
# => "no block"
# => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
p arithmetic_sequence.class
# => "no block"
# => Array

a = arithmetic_sequence do |n|
  puts n
end
# => "1 block"
# => 1
# => 2
# => 3
# => 4
# => 5
# => 6
# => 7
# => 8
# => 9
# => 10
p a.class
# => Fixnum
p a
# => 10
```

#Proc, lambda
ブロックをオブジェクト化したもの。Proc.newとlambdaは、
細かい点で挙動が異なる
http://qa.atmarkit.co.jp/q/68
が今は触れない

```rb
procedure1 = Proc.new { |word| puts word }
procedure2 = proc {|word| puts word}

procedure3 = lambda {|word| puts word}
procedure4 = ->(word) {puts word}
procedure5 = -> {puts "cluck"}

p procedure1.class
p procedure2.class
p procedure3.class
p procedure4.class
p procedure5.class


procedure1.call("meow")
procedure2.call("quack")
procedure3.call("oink")
procedure4.call("borrow")
procedure5.call
```

ブロックを使うか、Procを使うかは、あくまで書き方の違いで、
ブロックを使う→オブジェクト化される（Procクラスのオブジェクトになる)ので代わりはない

```rb
def repeat1(n)
  for i in 1..n
    puts "#{i} =>"
    yield
  end
end

def repeat2(n, &procedure)
  for i in 1..n
    puts "#{i} =>"
    procedure.call
  end
end

repeat1 3 do |x|
  p x
end

procedure = -> {puts "quack"}
repeat1(3, &procedure)
repeat2(3, &procedure)
repeat1(3) {puts "meow"}
repeat2(3) {puts "meow"}
```
repeat1,2とも同じ結果がかえる。

##Proc.newかlambdaか
挙動の違いがある。元記事の著者およびコメントでは，lambdaを使う方が多いもよう。

例：returnの扱い

```rb
def hoge
  procedure = Proc.new {return "return from Proc.new"}
  procedure.call
  return "return from hoge"
end

def fuga
  procedure = lambda {return "return from lambda"}
  procedure.call
  return "return from fuga"
end

puts hoge
# => return from Proc.new
puts fuga
# => return from fuga
```

#クロージャ
Procオブジェクトは、手続きだけでなく、環境（たとえば変数）を包み込みオブジェクト化をしている。

```rb
def increase
  n = 0
  -> {n += 5}
end

3.times {p increase.call}

increase_proc = increase
3.times {p increase_proc.call}
```