36
Advanced Ruby Beyond the Basics

Advanced Ruby

  • Upload
    alkeshv

  • View
    988

  • Download
    0

Embed Size (px)

DESCRIPTION

Ruby - beyond the basics. Covers Blocks, Procs, lambda, Higher Order Functions, Closures, Metaprogramming, Continuations, Symbols.

Citation preview

Page 1: Advanced Ruby

Advanced Ruby

Beyond the Basics

Page 2: Advanced Ruby

Blocks{ puts 'Hello' }

do puts 'Hello'end

Page 3: Advanced Ruby

Blocksdef call_block puts 'Start of method' # you can call the block using the yield keyword yield yield puts 'End of method' end # invokecall_block {puts 'In the block'}

>> Start of methodIn the blockIn the blockEnd of method

Page 4: Advanced Ruby

Blocks

def call_block_with_params puts 'Start of method' yield 'foo', 'bar' puts 'End of method' end# invokecall_block_with_params{|a,b| puts "#{a} #{b}"}

>> Start of methodfoo barEnd of method

Page 5: Advanced Ruby

Exercise 1

• For the class ‘Exercise1’– Implement method ‘greet’ to:• Accept an array of names and a block• That joins all the names together with ‘and’

– Implement method ‘invoke’ to:• Call the ‘greet’ method, passing it the names ‘joe’ and

‘fred’• And pass greet a block that adds “Hello” in front of the

names returned from ‘greet’• Should return “Hello joe and fred”

Page 6: Advanced Ruby

Proc objects

p = Proc.new { puts "Hello" }p.call

l = lambda { puts "Hello" }l.call

Page 7: Advanced Ruby

Proc vs lambdadef return_test l = lambda { return } l.call puts "Still here!" p = Proc.new { return } p.call puts "You won't see this."end

return_test

>> Still here!

Page 8: Advanced Ruby

Convert Blocks to Proc objects

def grab_block(&block) block.callend

grab_block {puts "Hello"}

Page 9: Advanced Ruby

Higher Order Functionsproc = lambda{puts 'Hello'}proc.call

def hello(proc) puts "start of method" proc.call puts "end of method"end# invokehello proc

>> Hello

>> start of methodHelloend of method

Page 10: Advanced Ruby

Closures

>> a = 1@a = 2original

class Holder def call_block(pr) a = 101 @a = 102 pr.call endendclass Creator def create_block a = 1 @a = 2 lambda do puts "a = #{a}" puts "@a = #@a" puts yield end endendblock = Creator.new.create_block { "original" }Holder.new.call_block block

Page 11: Advanced Ruby

Metaprogramming

• Add/remove classes dynamically• Add/remove methods dynamically• Change existing methods• Intercept messages to objects

• Useful for DSLs

Page 12: Advanced Ruby

Adding methods to a classclass Object def greet puts "Hello" endend

obj = Object.newobj.greet

>> Hello

obj2 = Object.newobj2.greet

>> Hello

Page 13: Advanced Ruby

Adding methods to a class - example

3.hours.from_now

class Fixnum def hours self * 60 * 60 end def from_now Time.now + self endend

Page 14: Advanced Ruby

Adding a method to an objectobj = Object.new

def obj.greet puts "Hello" end

obj.greet

>> Hello

obj2 = Object.newobj2.greet

>> undefined method `greet' for #<Object:0x2bae594>

Page 15: Advanced Ruby

Singleton Class

object

Singleton class

class

module

Page 16: Advanced Ruby

Adding methods to singleton classs = "Hello"

class << s def twice self + " " + self endend

puts s.twice

>> Hello Hello

def s.twice self + " " + selfend

Page 17: Advanced Ruby

Using modulesmodule M def greet puts "Hello" endend

obj = C.newclass << obj include Mend

obj.greet

obj = C.newobj.extend(M)obj.greet

Page 18: Advanced Ruby

Class method definitionsclass String class << self def hello "hello" end endend

class << String def hello "hello" endend

def String def self.hello "hello" endend

Page 19: Advanced Ruby

Class methods and inheritance

class C singleton class of C

class D singleton class of D

extends

lookup pathobject

Page 20: Advanced Ruby

Exercise 2

• Add a method to the already existing class ‘Account’

• Create file ‘account_transfer_to.rb’ and “re-open” the Account class.

• To run the specs: spec .

Page 21: Advanced Ruby

Exercise 3

• Add a method to an instance of a class• Edit the file

‘account_instance_transfer_to_spec.rb’• Implement the ‘transfer_to’ method here, for

account1 only.

Page 22: Advanced Ruby

Method Aliasingclass C def hi puts "hello" endend

class C alias_method :original_hi, :hi def hi puts "greetings“ original_hi endend

obj = C.newobj.hi

>> greetingshello

Page 23: Advanced Ruby

Exercise 4

• Alias an existing method• implement the ‘number_of_withdrawals’ and

‘number_of_deposits’ methods in a new file: ‘account_auditing.rb’

• Reopen Account class and define @number_of_withdrawals and @number_of_deposits

• Alias original withdraw, deposit and initialize methods, and implement new versions.

Page 24: Advanced Ruby

Method_missing

class Echo def method_missing method_sym, *args puts "#{method_sym}: #{args.inspect}" endend

Echo.new.yell "Hello", "world!"Echo.new.say "Good", "bye!"

>> yell: ["Hello", "world!"]say: ["Good", "bye!"]

Page 25: Advanced Ruby

Exercise 5

• Using method_missing• Implement Remember class from scratch• Remember class should accept any method,

and store the method and any parameters in a history array

Page 26: Advanced Ruby

Dynamically add methods

>> "defining method yell“"yell: [\"Hello\", \"world!\"]“"yell: [\"good\", \"bye\"]"

Page 27: Advanced Ruby

Dynamically add methodsclass Echo

def method_missing method_sym, *args p "defining method #{method_sym}" self.class.class_eval <<-EOF def #{method_sym.to_s} *args p "#{method_sym}: " + args.inspect end EOF send(method_sym, *args) endend

Echo.new.yell "Hello", "world!"Echo.new.yell "good", "bye">> "defining method yell“

"yell: [\"Hello\", \"world!\"]“"yell: [\"good\", \"bye\"]"

Page 28: Advanced Ruby

Dynamically add methodsclass Echo

def method_missing method_sym, *args p "defining method #{method_sym}" Echo.class_eval <<-EOF def #{method_sym.to_s} *args p "#{method_sym}: " + args.inspect end EOF send(method_sym, *args) endend

Echo.new.yell "Hello", "world!"Echo.new.yell "good", "bye">> "defining method yell“

"yell: [\"Hello\", \"world!\"]“"yell: [\"good\", \"bye\"]"

Page 29: Advanced Ruby

Dynamically add instance methods

>> "new_method: [\"blah\"]"

Page 30: Advanced Ruby

Dynamically add instance methods

>> "new_method: [\"blah\"]"

Page 31: Advanced Ruby

Exercise 6

• Dynamically add methods to a class at runtime• Use method_missing the first time a method

is called, but define the missing method on the class

• Subsequent calls to that method then won’t have to use method_missing.

Page 32: Advanced Ruby

Further Reading

• Ruby for Rails book (ch13) – David A. Black• Seeing Metaclasses Clearly• Dwemthy’s Array• Ruby metaprogramming techniques

Page 33: Advanced Ruby

The End

Page 34: Advanced Ruby

Extra Stuff

• Continuations• Symbols

Page 35: Advanced Ruby

Continuationsdef strange callcc {|continuation| return continuation} print "Back in method. "end

print "Before method. "continuation = strange()print "After method. "continuation.call if continuation

Before method. After method. Back in method. After method. RETURN THIS

Page 36: Advanced Ruby

Symbols

• :this_is_a_symbol• :’This is also a symbol’• Has both integer and string representations• Is immutable• Quicker to lookup than strings• Quicker to compare• No need to construct a string literal when

doing lookups