Advanced Ruby


Published on

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

Published in: Technology, Education
  • Be the first to comment

No Downloads
Total views
On SlideShare
From Embeds
Number of Embeds
Embeds 0
No embeds

No notes for slide
  • Anonymous chunk of code - Equivalent styles – {} and do...end
  • - Can be associated with methods - Method invokes the block using ‘yield’
  • Can have parameters Used in: iterators for wrapping actions (e.g.
  • - A block converted to an object - Lambda – same as, except: - Proc objects checks the number of parameters passed - scope of return in lambda is the block scope, not enclosing scope.
  • Can convert a code block into a Proc object by using ‘&’
  • - functions can be assigned to variables - can be passed as parameters - can be returned from methods
  • A stored block (stored in a variable) with a closed context Context is fixed to the context where the Proc object was created Associated with a block (and hence a Proc object) is all the context in which the block was defined: the value of self and the methods, variables, and constants in scope. Part of the magic of Ruby is that the block can still use all this original scope information even if the environment in which it was defined would otherwise have disappeared. In other languages, this facility is called a closure.
  • Ruby has Open classes – that allow you to: Add a method to an existing class Add a method to an object of a class
  • Simplified version of what rails does in ActiveSupport::CoreExtensions::Numeric::Time
  • The method added is called a singleton method
  • Every object in Ruby has its own singleton class aka eigenclass Singleton methods live in this singleton class Singleton class is: an object (instance of Class) anonymous – has no name REMEMBER – classes are objects too – (instances of class Class). the singleton class of a class is called a metaclass .
  • The two approaches here are equivalent (ignoring a minor point regarding the scope of constants)
  • Can use extend instead opening class to make methods in module available
  • A common use of the class << notation is for class method definitions. The above three ways of defining a class method are equivalent
  • Normally singleton methods are only available to the object they belong to. An exception is class methods – they are available to subclasses
  • alias_method :new_id, :existing_id
  • Using class_eval . class_eval should be called on a class self.class is the same as Echo
  • self.class is the same as Echo
  • - allows entire execution context to be saved - could be used instead of threads - shared concurrency - have complete control instead of letting Thread scheduler decide.
  • The following statements are handy in using (or not using) symbols: A Ruby symbol looks like a colon followed by characters. (:mysymbol) A Ruby symbol is a thing that has both a number (integer) and a string. The value of a Ruby symbol's string part is the name of the symbol, minus the leading colon. A Ruby symbol cannot be changed at runtime. Neither its string representation nor its integer representation can be changed at runtime. Ruby symbols are useful in preventing modification. Like most other things in Ruby, a symbol is an object. When designing a program, you can usually use a string instead of a symbol. Except when you must guarantee that the string isn't modified. Symbol objects do not have the rich set of instance methods that String objects do. After the first usage of :mysymbol all further useages of :mysymbol take no further memory -- they're all the same object. Ruby symbols save memory over large numbers of identical literal strings. Ruby symbols enhance runtime speed to at least some degree.
  • Advanced Ruby

    1. 1. Advanced Ruby Beyond the Basics
    2. 2. Blocks { puts 'Hello' } do puts 'Hello' end
    3. 3. Blocks def call_block puts 'Start of method' # you can call the block using the yield keyword yield yield puts 'End of method' end # invoke call_block {puts 'In the block' } >> Start of method In the block In the block End of method
    4. 4. Blocks def call_block_with_params puts 'Start of method' yield 'foo' , 'bar' puts 'End of method' end # invoke call_block_with_params {|a,b| puts "#{a} #{b}" } >> Start of method foo bar End of method
    5. 5. Exercise 1 <ul><li>For the class ‘Exercise1’ </li></ul><ul><ul><li>Implement method ‘greet’ to: </li></ul></ul><ul><ul><ul><li>Accept an array of names and a block </li></ul></ul></ul><ul><ul><ul><li>That joins all the names together with ‘and’ </li></ul></ul></ul><ul><ul><li>Implement method ‘invoke’ to: </li></ul></ul><ul><ul><ul><li>Call the ‘greet’ method, passing it the names ‘joe’ and ‘fred’ </li></ul></ul></ul><ul><ul><ul><li>And pass greet a block that adds “Hello” in front of the names returned from ‘greet’ </li></ul></ul></ul><ul><ul><ul><li>Should return “Hello joe and fred” </li></ul></ul></ul>
    6. 6. Proc objects p = { puts &quot;Hello&quot; } p .call l = lambda { puts &quot;Hello&quot; } l .call
    7. 7. Proc vs lambda def return_test l = lambda { return } l .call puts &quot;Still here!&quot; p = { return } p .call puts &quot;You won't see this.&quot; end return_test >> Still here!
    8. 8. Convert Blocks to Proc objects def grab_block (&block) block .call end grab_block {puts &quot;Hello&quot; }
    9. 9. Higher Order Functions proc = lambda{puts 'Hello' } proc .call def hello (proc) puts &quot;start of method&quot; proc .call puts &quot;end of method&quot; end # invoke hello proc >> Hello >> start of method Hello end of method
    10. 10. Closures >> a = 1 @a = 2 original class Holder def call_block (pr) a = 101 @a = 102 pr .call end end class Creator def create_block a = 1 @a = 2 lambda do puts &quot;a = #{a}&quot; puts &quot;@a = #@a&quot; puts yield end end end block = { &quot;original&quot; } Holder .new.call_block block
    11. 11. Metaprogramming <ul><li>Add/remove classes dynamically </li></ul><ul><li>Add/remove methods dynamically </li></ul><ul><li>Change existing methods </li></ul><ul><li>Intercept messages to objects </li></ul><ul><li>Useful for DSLs </li></ul>
    12. 12. Adding methods to a class class Object def greet puts &quot;Hello&quot; end end obj = obj .greet >> Hello obj2 = obj2 .greet >> Hello
    13. 13. Adding methods to a class - example 3.hours .from_now class Fixnum def hours self * 60 * 60 end def from_now Time .now + self end end
    14. 14. Adding a method to an object obj = def obj .greet puts &quot;Hello&quot; end obj .greet >> Hello obj2 = obj2 .greet >> undefined method `greet' for #<Object:0x2bae594>
    15. 15. Singleton Class object Singleton class class module
    16. 16. Adding methods to singleton class s = &quot;Hello&quot; class << s def twice self + &quot; &quot; + self end end puts s .twice >> Hello Hello def s .twice self + &quot; &quot; + self end
    17. 17. Using modules module M def greet puts &quot;Hello&quot; end end obj = class << obj include M end obj.greet obj = obj.extend(M) obj.greet
    18. 18. Class method definitions class String class << self def hello &quot;hello&quot; end end end class << String def hello &quot;hello&quot; end end def String def self .hello &quot;hello&quot; end end
    19. 19. Class methods and inheritance class C singleton class of C class D singleton class of D extends lookup path object
    20. 20. Exercise 2 <ul><li>Add a method to the already existing class ‘Account’ </li></ul><ul><li>Create file ‘account_transfer_to.rb’ and “re-open” the Account class. </li></ul><ul><li>To run the specs: spec . </li></ul>
    21. 21. Exercise 3 <ul><li>Add a method to an instance of a class </li></ul><ul><li>Edit the file ‘account_instance_transfer_to_spec.rb’ </li></ul><ul><li>Implement the ‘transfer_to’ method here, for account1 only. </li></ul>
    22. 22. Method Aliasing class C def hi puts &quot;hello&quot; end end class C alias_method :original_hi , :hi def hi puts &quot;greetings“ original_hi end end obj = obj .hi >> greetings hello
    23. 23. Exercise 4 <ul><li>Alias an existing method </li></ul><ul><li>implement the ‘number_of_withdrawals’ and ‘number_of_deposits’ methods in a new file: ‘account_auditing.rb’ </li></ul><ul><li>Reopen Account class and define @number_of_withdrawals and @number_of_deposits </li></ul><ul><li>Alias original withdraw, deposit and initialize methods, and implement new versions. </li></ul>
    24. 24. Method_missing class Echo def method_missing method_sym, *args puts &quot;#{method_sym}: #{args.inspect}&quot; end end Echo .new.yell &quot;Hello&quot; , &quot;world!&quot; Echo .new.say &quot;Good&quot; , &quot;bye!&quot; >> yell: [&quot;Hello&quot;, &quot;world!&quot;] say: [&quot;Good&quot;, &quot;bye!&quot;]
    25. 25. Exercise 5 <ul><li>Using method_missing </li></ul><ul><li>Implement Remember class from scratch </li></ul><ul><li>Remember class should accept any method, and store the method and any parameters in a history array </li></ul>
    26. 26. Dynamically add methods >> &quot;defining method yell“ &quot;yell: [&quot;Hello&quot;, &quot;world!&quot;]“ &quot;yell: [&quot;good&quot;, &quot;bye&quot;]&quot;
    27. 27. Dynamically add methods class Echo def method_missing method_sym, *args p &quot;defining method #{method_sym}&quot; self .class.class_eval <<-EOF def #{method_sym.to_s} *args p &quot;#{method_sym}: &quot; + args.inspect end EOF send (method_sym, *args) end end Echo .new.yell &quot;Hello&quot; , &quot;world!&quot; Echo .new.yell &quot;good&quot; , &quot;bye&quot; >> &quot;defining method yell“ &quot;yell: [&quot;Hello&quot;, &quot;world!&quot;]“ &quot;yell: [&quot;good&quot;, &quot;bye&quot;]&quot;
    28. 28. Dynamically add methods class Echo def method_missing method_sym, *args p &quot;defining method #{method_sym}&quot; Echo .class_eval <<-EOF def #{method_sym.to_s} *args p &quot;#{method_sym}: &quot; + args.inspect end EOF send (method_sym, *args) end end Echo .new.yell &quot;Hello&quot; , &quot;world!&quot; Echo .new.yell &quot;good&quot; , &quot;bye&quot; >> &quot;defining method yell“ &quot;yell: [&quot;Hello&quot;, &quot;world!&quot;]“ &quot;yell: [&quot;good&quot;, &quot;bye&quot;]&quot;
    29. 29. Dynamically add instance methods >> &quot;new_method: [&quot;blah&quot;]&quot;
    30. 30. Dynamically add instance methods >> &quot;new_method: [&quot;blah&quot;]&quot;
    31. 31. Exercise 6 <ul><li>Dynamically add methods to a class at runtime </li></ul><ul><li>Use method_missing the first time a method is called, but define the missing method on the class </li></ul><ul><li>Subsequent calls to that method then won’t have to use method_missing. </li></ul>
    32. 32. Further Reading <ul><li>Ruby for Rails book (ch13) – David A. Black </li></ul><ul><li>Seeing Metaclasses Clearly </li></ul><ul><li>Dwemthy’s Array </li></ul><ul><li>Ruby metaprogramming techniques </li></ul>
    33. 33. The End
    34. 34. Extra Stuff <ul><li>Continuations </li></ul><ul><li>Symbols </li></ul>
    35. 35. Continuations def strange callcc {|continuation| return continuation} print &quot;Back in method. &quot; end print &quot;Before method. &quot; continuation = strange() print &quot;After method. &quot; continuation .call if continuation Before method. After method. Back in method. After method. RETURN THIS
    36. 36. Symbols <ul><li>:this_is_a_symbol </li></ul><ul><li>:’This is also a symbol’ </li></ul><ul><li>Has both integer and string representations </li></ul><ul><li>Is immutable </li></ul><ul><li>Quicker to lookup than strings </li></ul><ul><li>Quicker to compare </li></ul><ul><li>No need to construct a string literal when doing lookups </li></ul>