The document provides an overview of advanced Ruby concepts including blocks, procs, lambdas, higher order functions, closures, metaprogramming, dynamically adding methods, and continuations. Key points covered include using yield to call blocks, the differences between procs and lambdas, using blocks and procs as arguments to methods, closures allowing access to outer scope variables, adding and removing classes/methods dynamically at runtime, intercepting undefined messages with method_missing, and continuations allowing non-local returns.
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. 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.
6. Proc objects p = Proc.new { puts "Hello" } p .call l = lambda { puts "Hello" } l .call
7. Proc vs lambda def 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!
8. Convert Blocks to Proc objects def grab_block (&block) block .call end grab_block {puts "Hello" }
9. Higher Order Functions proc = lambda{puts 'Hello' } proc .call def hello (proc) puts "start of method" proc .call puts "end of method" end # invoke hello proc >> Hello >> start of method Hello end of method
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 "a = #{a}" puts "@a = #@a" puts yield end end end block = Creator.new.create_block { "original" } Holder .new.call_block block
11.
12. Adding methods to a class class Object def greet puts "Hello" end end obj = Object.new obj .greet >> Hello obj2 = Object.new obj2 .greet >> Hello
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. Adding a method to an object obj = Object.new def obj .greet puts "Hello" end obj .greet >> Hello obj2 = Object.new obj2 .greet >> undefined method `greet' for #<Object:0x2bae594>
16. Adding methods to singleton class s = "Hello" class << s def twice self + " " + self end end puts s .twice >> Hello Hello def s .twice self + " " + self end
17. Using modules module M def greet puts "Hello" end end obj = C.new class << obj include M end obj.greet obj = C.new obj.extend(M) obj.greet
18. Class method definitions class String class << self def hello "hello" end end end class << String def hello "hello" end end def String def self .hello "hello" end end
19. Class methods and inheritance class C singleton class of C class D singleton class of D extends lookup path object
20.
21.
22. Method Aliasing class C def hi puts "hello" end end class C alias_method :original_hi , :hi def hi puts "greetings“ original_hi end end obj = C.new obj .hi >> greetings hello
23.
24. Method_missing class Echo def method_missing method_sym, *args puts "#{method_sym}: #{args.inspect}" end end Echo .new.yell "Hello" , "world!" Echo .new.say "Good" , "bye!" >> yell: ["Hello", "world!"] say: ["Good", "bye!"]
35. Continuations def 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
36.
Editor's Notes
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. File.open)
- A block converted to an object - Lambda – same as Proc.new, 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.