PERL X RUBY CONF 2018
2018-08-04
function add(x)
function addX(y)
return y + x
return addX
variable add1 = add(1)
variable add5 = add(5)
assert add1(3) = 4
assert add5(3) = 8
rb(main):001:0> parent = "Hello" # 메인 영역
=> "Hello"
irb(main):002:0> 3.times do
irb(main):003:1* child = "World" # 코드 블록 안 영역
irb(main):004:1> puts "#{parent}, #{child}!"
irb(main):005:1> end
Hello, World!
Hello, World!
Hello, World!
=> 3
irb(main):006:0> puts "#{child}" # 하위 코드 블록 안 영역을 접근할 수 없다
NameError: undefined local variable or method `child' for main:Object
from (irb):6
from /Users/wagurano/.rbenv/versions/2.4.1/bin/irb:11:in `<main>'
irb(main):007:0>
# 자유 변수는 상위 스코프에서 선언한다
irb(main):001:0> double_lambda = lambda do |parent|
# 'parent'가 자유 변수
irb(main):002:1* lambda do
irb(main):003:2* child = "World"
irb(main):004:2> "#{parent}, #{child}!"
irb(main):005:2> end
irb(main):006:1> end
=> #<Proc:0x007f8ce211f4b0@(irb):1 (lambda)>
irb(main):007:0> double_lambda.call("Hello")
=> #<Proc:0x007f8ce20f5e08@(irb):2 (lambda)>
irb(main):008:0> double_lambda.call("Hello").call()
# 바로 실행할 수 없고, 실행하려면 .call()를 쓴다
=> "Hello, World!"
irb(main):009:0>
class Counter
def initialize
@x = 0
end
def print
"counter = #{@x}"
end
def up
@x += 1
end
def down
@x -= 1
end
endirb(main):001:0> c = Counter.new
=> #<Counter:0x007fbc6309ed28 @x=0>
irb(main):002:0> c.up
=> 1
irb(main):003:0> c.up
=> 2
irb(main):004:0> c.print
=> "counter = 2"
irb(main):005:0> c.down
=> 1
irb(main):006:0> c.down
=> 0
irb(main):007:0> c.down
=> -1Counter = lambda do
x = 0
print = lambda { "counter = #{x}" }
up = lambda { x += 1 }
down = lambda { x -= 1 }
{ print: print, up: up, down: down }
end
irb(main):001:0> lc = Counter.call
=> {:print=>#<Proc:0x007f8fd39efbc8@/lambda_counter.rb:4 (lambda)>,
:up=>#<Proc:0x007f8fd39efba0@/lambda_counter.rb:5 (lambda)>,
:down=>#<Proc:0x007f8fd39efb78@/lambda_counter.rb:6 (lambda)>}
irb(main):002:0> lc[:up].call
=> 1
irb(main):003:0> lc[:up].call
=> 2
irb(main):004:0> lc[:up].call
=> 3
irb(main):005:0> lc[:down].call
=> 2
irb(main):006:0> xlc = Counter.call
=> {:print=>#<Proc:0x007f8fd397c2e0@/lambda_counter.rb:4 (lambda)>,
:up=>#<Proc:0x007f8fd397c240@/lambda_counter.rb:5 (lambda)>,
:down=>#<Proc:0x007f8fd397c218@/lambda_counter.rb:6 (lambda)>}
irb(main):007:0> xlc[:print].call
=> "counter = 0"
irb(main):008:0> lc[:print].call
=> "counter = 2"# 함수를 파라미터로 넘긴다
irb(main):001:0> validation = lambda { |x| not x.nil? }
=> #<Proc:0x007ffd9c217798@(irb):1 (lambda)>
irb(main):002:0> validation.call(nil)
=> false
irb(main):003:0> validation.call("hi")
=> true
irb(main):004:0> def post_param(rule)
irb(main):005:1> lambda do |value|
irb(main):006:2* rule.call(value)
irb(main):007:2> end
irb(main):008:1> end
=> :post_param
irb(main):009:0> post_param(validation).call("hi")
=> true
irb(main):010:0> post_param(validation).call(nil)
=> false
require 'ostruct'
class Crawler
attr_reader :page
def initialize(page)
@page = page
end
def get
@page.body
end
end
class Mailer
attr_reader :page, :callbacks
def initialize(page, callbacks)
@page = page
@callbacks = callbacks
end
def start
result = page.get
if result
callbacks[:on_success].call(result)
else
callbacks[:on_error].call
end
end
endirb(main):001:0> nice_weather =
OpenStruct.new(body: "sunny day")
=> #<OpenStruct body="sunny day">
irb(main):002:0>
Mailer.new(Crawler.new(nice_weather),
on_success: lambda { |x|
puts "Mail #{x} to user@rorlab.org" },
on_error: lambda {
puts "Mail to error@rorlab.org" }
).start
Mail sunny day to user@rorlab.org
=> nil
irb(main):008:0* error_weather =
OpenStruct.new(body: nil)
=> #<OpenStruct body=nil>
irb(main):009:0>
Mailer.new(Crawler.new(error_weather),
on_success: lambda { |x|
puts "Mail #{x} to user@rorlab.org" },
on_error: lambda {
puts "Mail to error@rorlab.org" }
).start
Mail to error@rorlab.org
=> nil# 반복 탐색 iteration
irb(main):001:0> %w(Hello Ruby World).each { |x| puts x }
Hello
Ruby
World
=> ["Hello", "Ruby", "World"]
# 리소스 관리, 전/후처리
irb(main):001:0> File.open('/etc/passwd', 'r') do |f|
irb(main):002:1* puts f.path
irb(main):003:1> puts f.ctime
irb(main):004:1> puts f.size
irb(main):005:1> end
/etc/passwd
2014-03-14 21:55:30 +0900
5253
=> nil
# 객체 생성
@client = Twitter::REST::Client.new do |config|
config.consumer_key = "user key"
config.consumer_secret = "user secret"
config.access_token = "token"
config.access_token_secret = "token secret"
end
irb(main):001:0> def template
irb(main):002:1> yield
irb(main):003:1> end
=> :template
irb(main):004:0> template
LocalJumpError: no block given (yield)
from (irb):2:in `template'
from (irb):4
from /.rbenv/versions/2.4.1/bin/irb:11:in `<main>'
irb(main):005:0> template { [1,2] }
=> [1, 2]
irb(main):006:0> def template
irb(main):007:1> yield if block_given?
irb(main):008:1> end
=> :template
irb(main):009:0> template
=> nil
irb(main):010:0> template { [1,2] }
=> [1, 2]
irb(main):001:0> def template
irb(main):002:1> yield
irb(main):003:1> end
=> :template
irb(main):004:0> template { puts "say somehting" }
say somehting
=> nil
irb(main):005:0> template { return 1 + 2 }
LocalJumpError: unexpected return
from (irb):5:in `block in irb_binding'
from (irb):2:in `template'
from (irb):5
from /.rbenv/versions/2.4.1/bin/irb:11:in `<main>'
irb(main):006:0> template { [1,2] }
=> [1, 2]
irb(main):007:0> template { [1,2] << 3}
=> [1, 2, 3]
irb(main):008:0> template
LocalJumpError: no block given (yield)
from (irb):2:in `template'
from (irb):8
from /.rbenv/versions/2.4.1/bin/irb:11:in `<main>'파라미터 개수가 많으면 에러가 발생하지 않으나 부족하면 에러 발생
block 안에서 사용하는 변수를 파라미터로 넘기지 않으면 nil
irb(main):010:0* def template(x, y)
irb(main):011:1> yield(x, y)
irb(main):012:1> end
template("Hello","World") { |a, b| "#{a}, #{b}!" }
=> "Hello, World!"
template("Hello") { |a, b| "#{a}, #{b}!" }
ArgumentError: wrong number of arguments (given 1, expected 2)
from (irb):10:in `template'
template("Hello", "Ruby", "World") { |a, b| "#{a}, #{b}!" }
ArgumentError: wrong number of arguments (given 3, expected 2)
from (irb):10:in `template'
irb(main):016:0> def template(x, y)
irb(main):017:1> yield(x, y, "z")
irb(main):018:1> end
template("Hello", "World!") { |a, b| "#{a}, #{b}!" }
=> "Hello, World!!"
irb(main):020:0>
irb(main):021:0* k, v = 1
irb(main):022:0> k # 1
irb(main):023:0> v # nil
irb(main):024:0> def template(x)
irb(main):025:1> yield(x)
irb(main):026:1> end
irb(main):027:0> template("Hello") { |a, b| "#{a}, #{b}!" }
=> "Hello, !"block: local variable
# |; local |
rb(main):001:0> x = "parent"
=> "parent"
irb(main):002:0> 3.times { x = "child" }
=> 3
irb(main):003:0> x
=> "child"
irb(main):004:0> x = "parent"
=> "parent"
irb(main):005:0> 3.times { |;x| x = "child" }
=> 3
irb(main):006:0> x
=> "parent"
# proc: block of code as an object
# proc은 block과 달리 객체이다. block은 anonymous function 이다
rb(main):001:0> %w(hello ruby world).map(&:upcase)
=> ["HELLO", "RUBY", "WORLD"]
irb(main):002:0> %w(hello ruby world).map{ |x| x.upcase }
=> ["HELLO", "RUBY", "WORLD"]
# proc 실행하는 방법
rb(main):001:0> x = proc { |a, b| "#{a}, #{b}!" }
=> #<Proc:0x007fb531954a78@(irb):1>
irb(main):002:0> x.call("Hello", "World")
=> "Hello, World!"
irb(main):003:0> x.("Hello", "World")
=> "Hello, World!"
irb(main):004:0> x === ["Hello", "World"]
rb(main):006:0* x["Hello", "World"]
=> "Hello, World!"
# lamba is a special proc.
irb(main):007:0> y = lambda { |a, b| "#{a}, #{b}!" }
=> #<Proc:0x007fb5318b3e98@(irb):7 (lambda)>
irb(main):008:0> y.call("Hello", "World")
=> "Hello, World!"
irb(main):009:0> y = ->(a,b) { "#{a}, #{b}!" }
=> #<Proc:0x007fb53204f580@(irb):9 (lambda)>
irb(main):010:0> y.call("Hello", "World")
=> "Hello, World!"
irb(main):011:0>
# proc은 lambda와 달리 파라미터 개수가 맞지 않아도 된다
irb(main):001:0> x = proc { |x, y| "#{x}, #{y}!" }
=> #<Proc:0x007fcb3c1a0018@(irb):1>
irb(main):002:0> y = lambda { |x, y| "#{x}, #{y}!" }
=> #<Proc:0x007fcb3c867a40@(irb):2 (lambda)>
irb(main):003:0> x.call("Hello", "World")
=> "Hello, World!"
irb(main):004:0> y.call("Hello", "World")
=> "Hello, World!"
irb(main):005:0> x.call("Hello")
=> "Hello, !"
irb(main):006:0> y.call("Hello")
ArgumentError: wrong number of arguments (given 1, expected 2)
from (irb):2:in `block in irb_binding'
from (irb):6
from /.rbenv/versions/2.4.1/bin/irb:11:in `<main>'
irb(main):007:0> x.call("Hello", "Ruby", "World")
=> "Hello, Ruby!"
irb(main):008:0> y.call("Hello", "Ruby", "World")
ArgumentError: wrong number of arguments (given 3, expected 2)
from (irb):2:in `block in irb_binding'
from (irb):8
from /.rbenv/versions/2.4.1/bin/irb:11:in `<main>'# lambda는 return을 써도 되지만 proc은 ruturn을 쓸 수 없다
irb(main):010:0* k = proc { return }
=> #<Proc:0x007fcb3c047428@(irb):10>
irb(main):011:0> v = lambda { return }
=> #<Proc:0x007fcb3c034918@(irb):11 (lambda)>
irb(main):012:0> k.call
LocalJumpError: unexpected return
from (irb):10:in `block in irb_binding'
from (irb):12
from /.rbenv/versions/2.4.1/bin/irb:11:in `<main>'
irb(main):013:0> v.call
=> nil
# Proc#curry 파라미터를 하나씩 넘겨서, 중간 과정을 저장할 수 있다.
irb(main):001:0> balance_index = lambda { |x, y, z| 3*x - 2*t + z }
=> #<Proc:0x007fbc8a05ce38@(irb):1 (lambda)>
irb(main):002:0> balance_index.call(3,4,5)
NameError: undefined local variable or method `t' for main:Object
from (irb):1:in `block in irb_binding'
from (irb):2
from /.rbenv/versions/2.4.1/bin/irb:11:in `<main>'
irb(main):003:0> balance_index = lambda { |x, y, z| 3*x - 2*y + z }
=> #<Proc:0x007fbc8a126508@(irb):3 (lambda)>
irb(main):004:0> balance_index.call(3,4,5)
=> 6
irb(main):005:0> curry_index = lambda { |x, y, z| 3*x - 2*y + z }.curry
=> #<Proc:0x007fbc8a8bac38 (lambda)>
irb(main):006:0> balance_index.call(3,4,5)
=> 6
irb(main):007:0> curry_index.call(3,4,5)
=> 6
irb(main):008:0> curry_index.call(3).call(4).call(5)
=> 6
irb(main):009:0> balance_index.call(3).call(4).call(5)
ArgumentError: wrong number of arguments (given 1, expected 3)
from (irb):3:in `block in irb_binding'
from (irb):9
from /.rbenv/versions/2.4.1/bin/irb:11:in `<main>'irb(main):011:0* balance_index_c = lambda { |x|
lambda { |y| lambda { |z| 3*x - 2*y + z } } }
=> #<Proc:0x007fbc8a902f88@(irb):11 (lambda)>
irb(main):012:0> balance_index.call(3,4,5)
=> 6
irb(main):013:0> balance_index_c.call(3,4,5)
ArgumentError: wrong number of arguments (given 3, expected 1)
from (irb):11:in `block in irb_binding'
from (irb):13
from /.rbenv/versions/2.4.1/bin/irb:11:in `<main>'
irb(main):014:0> balance_index_c.call(3).call(4).call(5)
=> 6
rb(main):015:0>
irb(main):016:0* xy_index = curry_index.call(3).call(4)
=> #<Proc:0x007fbc8a8d0560 (lambda)>
irb(main):017:0> xy_index.call(5)
=> 6
irb(main):018:0> xy_index.call(0)
=> 1
irb(main):019:0> xy_index.call(10)
=> 11rb(main):020:0> sum_template = lambda do |op, from, to|
irb(main):021:1* (from..to).inject { |result, x| result + op.call(x) }
irb(main):022:1> end
=> #<Proc:0x007fbc8a04ea40@(irb):20 (lambda)>
irb(main):023:0> sum = sum.call(lambda{|x| x},1,10)
NoMethodError: undefined method `call' for nil:NilClass
from (irb):23
from /.rbenv/versions/2.4.1/bin/irb:11:in `<main>'
irb(main):024:0> sum = sum_template.call(lambda{|x| x},1,10)
=> 55
irb(main):025:0> sum = sum_template.call(lambda{|x| x*x},1,10)
=> 385
irb(main):026:0> sum = sum_template.call(lambda{|x| x*x*x},1,10)
=> 3025
irb(main):027:0> sum = sum_template.call(lambda{|x| x*2},1,10)
=> 109
https://pragprog.com/book/btrubyclo/mastering-ruby-closures