@autonomous
chris.spring@gmail.com
Going steady with
Ruby
1. {}, proc{}, ->{}
2. meta programming
3. modules
1) blocks,!
procs and!
lambdas
(1..3).each do |i|
puts i
end
# => 1
# => 2
# => 3
(1..3).each{ |i| puts i }
(1..3).each do |i|
puts i
end
# => 1
# => 2
# => 3
(1..3).each{ |i| puts i }
def each
for i in collection
yield i
end
end
def some_method(*arguments)
# ... pre conditions
yield( some_result )
# ... post conditions
end
def some_method(*arguments, &block)
# ... pre conditions
block.call( some_result )
# ... post conditions
end
file = File.new('credit_cards.txt', 'w')
file.puts 'XXXX XXXX XXXX 5534'
file.close
File.new('credit_cards.txt', 'w') do |file|
file.puts 'XXXX XXXX XXXX 5534'
end
Vs.
proc{} vs lambda{}
p = proc{ |i| puts "proc #{i}" }
p.call("hey!")
# => proc hey!
!
!
!
!
l = lambda{ |i| puts "lamb #{i}" }
l.call('yo!')
# => lamb yo!
p = proc{ |i| puts "proc #{i}" }
l = lambda{ |i| puts "lamb #{i}" }
!
(1..3).each(&p)
# => proc 1
# => proc 2
# => proc 3
!
(1..3).each(&l)
# => lamb 1
# => lamb 2
# => lamb 3
def do_something(a_p, b_l, &block)
print a_p.call()
print block.call()
print b_l.call()
end
!
!
p = proc{ "I'm a " }
l = lambda{ " and I'm ok!" }
!
!
do_something(p, l){ "lumberjack" }
# => I'm a lumberjack and I'm ok!
p.class
# => Proc
p.inspect
# => “#<Proc:0x0000010194d8b8@(irb):97>"
!
!
l.class
# => Proc
l.inspect
# => "#<Proc:0x0000010190cd68@(irb):98 (lambda)>"
p = proc{|i| puts i}
p.call()
# => nil
!
p.call(1)
# => 1
!
p.call(1, 2, 3)
# => 1
l = lambda{|i| puts i}
l.call()
# ArgumentError: wrong number of arguments
(0 for 1)
!
l.call(1)
# => 1
!
l.call(1, 2, 3)
# ArgumentError: wrong number of arguments
(3 for 1)
def proc_return
p = proc{ return ‘Never ' }
p.call
'Always '
end
!
!
def lambda_return
l = lambda{ return 'eat your vegetables!'}
l.call
'give up!'
end
!
!
"#{proc_return} #{lambda_return}"
Never give up!
2) META PROGRAMMING!
send :<3
class Statistics
def initialize(account)
@account = account
end
!
def increment_counts(metric, by=1)
case metric
when :sent
@account.increment_sent_count(by)
when :viewed
@account.increment_viewed_count(by)
when :bounced
@account.increment_bounced_count(by)
end
end
end
class Statistics
def initialize(account)
@account = account
end
!
def increment_counts(metric, by=1)
method = "increment_#{metric}_count"
@account.send(method, by)
end
end
class Account
# ...
private
def schedule_billing
# ...
end
end
!
class BillingRunner
def initialize(account)
@account
end
!
def run!
# ...
@account.send(:schedule_billing)
# ...
end
end
class Account
# ...
private
def schedule_billing
# ...
end
end
!
class BillingRunner
def initialize(account)
@account
end
!
def run!
# ...
@account.send(:schedule_billing)
# ...
end
end
define_method :awesome {}
class User
def admin!
@role = :admin
end
!
def admin?
@role == :admin
end
!
def client!
@role = :client
end
!
def client?
@role == :client
end
end
class User
ROLES = %i(admin client)
!
ROLES.each do |role|
define_method "#{role}?" do
@role == role
end
!
define_method "#{role}!" do
@role = role
end
end
end
%i(admin client supervisor technician vendor manager)
method_missing m, *args, &b
class KeyValueStore
def initialize(store={})
@store = store
end
!
def insert(key, value)
@store[key] = value
end
end
!
store = KeyValueStore.new
store.respond_to?(:insert)
# => true
!
store.insert(:one, 1)
!
m = store.method(:insert)
m.call(:two, 2)
!
store.instance_variable_get('@store')
# => {one: 1, two: 2}
class KeyValueStore
def initialize(store={})
@store = store
end
!
def insert(key, value)
@store[key] = value
end
end
!
store = KeyValueStore.new
store.respond_to?(:insert)
# => true
!
store.insert(:one, 1)
!
m = store.method(:insert)
m.call(:two, 2)
!
store.instance_variable_get('@store')
# => {one: 1, two: 2}
class KeyValueStore
# ...
!
def method_missing(method_name, *args, &block)
if @store.respond_to?(method_name)
@store.send(method_name, *args, &block)
else
super
end
end
!
def respond_to_missing?(method_name, include_private)
@store.respond_to?(method_name) || super
end
end
kv = KeyValueStore.new
kv.insert(:three, 3)
!
kv.respond_to?(:include?) # => true
kv.include?(:three) # => true
!
m = kv.method(:include?)
m.call(:four) # => false
!
kv.keys # => [:three]
kv.values # => [3]
3) Modules
module Mathematics
class Plane
# ...
end
end
!
!
module Airport
class Plane
# ...
end
end
module TehForce
def sense
'... a disturbance in the force'
end
end
!
class Person
include TehForce
# ...
end
!
p = Person.new
p.sense
# => "... a disturbance in the force"
Person = Class.new()
p = Person.new
!
!
p.sense
# NoMethodError: undefined method `sense' …
!
!
p.extend TehForce
p.sense
# => "... a disturbance in the force"
module UserDianostics
def perform_diagnostics
check_counts
validate_dates
find_orphans
end
!
# ....
end
!
user = User.find(some_id)
user.extend UserDianostics
user.perform_diagnostics
module RepublicPersonnel
def storm_trooper
Person.new
end
end
!
!
class CloningVat
extend RepublicPersonnel
end
!
!
CloningVat.storm_trooper
# => #<Person:0x0000010187c150>
Person = Class.new()
CloningVat = Class.new()
!
!
CloningVat.storm_trooper
# => NoMethodError: undefined method
`storm_trooper' …
!
!
CloningVat.extend RepublicPersonnel
CloningVat.storm_trooper
# => #<Person:0x0000010187c150>
include and extend?
module SomeMixin
module ClassMethods
# ...
end
module InstanceMethods
# ...
end
def self.included(receiver)
receiver.extend ClassMethods
receiver.send :include, InstanceMethods
end
end
A contrived example…
admin = Administrator.new
admin.allowed_to_toggle_alarm? # => true
admin.allowed_to_visit_facebook? # => false
!
lacky = Lacky.new
lacky.allowed_to_be_seen? # => true
lacky.allowed_to_be_heard? # => false
lacky.allowed_to_make_eye_contact? # => false
class Administrator
include Permissions
!
can :toggle_alarm
end
!
admin = Administrator.new
admin.allowed_to_toggle_alarm? # => true
admin.allowed_to_visit_facebook? # => false
class Lacky
include Permissions
!
can :be_seen
end
!
lacky = Lacky.new
lacky.allowed_to_be_seen? # => true
lacky.allowed_to_be_heard? # => false
module Permissions
module ClassMethods
def can(do_something)
define_method "allowed_to_#{do_something}?" do
true
end
end
end
!
module InstanceMethods
def method_missing(*args, &block)
method_name = args[0]
if method_name && method_name =~ /allowed_to_.*?/
false
else
super
end
end
end
!
def self.included(receiver)
receiver.extend ClassMethods
receiver.send :include, InstanceMethods
end
end
Thanks for
Listening
Questions?

Steady with ruby