Metaprogramming Ruby 2: Program Like the Ruby Pros (Facets of Ruby)

Author: Paolo Perrotta
4.0
This Month Stack Overflow 2

Comments

by anonymous   2019-07-21

The answer has to do with self and scopes

There are three ways to create a new scope in ruby. Classes, Modules, and Methods.

Your class creates a scope, and each of your methods create a scope that contain bindings specific to them. Closures are special though. A closure will grab the bindings that are around when you define the block and the block specific bindings disappear after the block ends. For example:

def my_method
  #Method scope
  x = "Goodbye"
  yield("Cruel")
end

x = "Hello"
#Closure says "I am going to grab the local bindings from my scope
my_method {|y| "#{x}, #{y} world" }

When ever you write the code

obj.define_singleton_method(:say1) { msg }

The only local bindings the closure grabs is 'obj' This can be demonstrated by modifying the code like so:

def d2(obj)
   puts "in the scope of method :d2, I have acces to the :msg method: #{methods.include?(:msg)}"
   puts "---"

    obj.define_singleton_method(:say2) do 
      puts "in the scope of this closure, I have acces to the :msg method: #{methods.include?(:msg)}"
      puts "Things I do have access to: "
      puts methods
      puts local_variables
    end
  end

A simple print statement of the most important part of ruby, self, will show you that you are operating in different scopes. Check out the code below:

def d2(obj)
   puts "in the scope of method :d2, I am operating as #{self}"
   puts "---"

    obj.define_singleton_method(:say2) do 
      puts "in the scope of this closure, I am operating as #{self}"
    end
end

So in short, the reason is because of scope. Whenever you declare bound = msg you are making the contents of msg local to the method and then the closure then can pick up the local binding value of msg.

If you want to read more about how this works, I highly recommend "The Pragmatic Programmers - Metaprogramming Ruby" You will learn a lot about self, and closures. http://www.amazon.com/Metaprogramming-Ruby-Program-Like-Facets/dp/1941222129

----EDIT---- "Why is"

def p Proc.new { msg } end

different than

def d2(obj) obj.define_singleton_method(:say2) { msg } end

It is different because self inside the block is different. Inside the method definition "p", the block has access to instance variables and methods, whereas the method "d2" has a block that only has access to Object. We can prove this with a little monkeypatching. Add this code:

class Object def msg "GoodBye" end

by anonymous   2019-07-21

New answer:

So you're asking how this is possible.

In ruby everything is object (or almost). For example:

String.class # Class

The class of String is Class, so String is an instance of Class.

The ruby model object is not easy to understand at the first sight when you come from C++ or Java.

When you do:

class String
  def abc
    "hey"
  end
end
puts "foo".abc #hey

You're reopening the class String and define a new instance method abc. You can also add a new method to the String class thanks to the keyword self, like this:

class String
  def self.abc
    "hey from class :)"
  end
end
puts String.abc #hey from class :)

Here, you're adding a abc method to the String object itself.

If you're interested to learn how ruby works in depth, there is a lot of book, one of my favorite is this one:https://www.amazon.co.uk/Metaprogramming-Ruby-Program-Like-Facets/dp/1941222129

as Tiago said, the class reopening method is called Monkey patching and you have to use it sparingly :)

Previous answer:

You can use the self keyword, like this:

class String
  def self.abc
    "hey from class :)"
  end
end

puts String.abc #hey from class :)
by cnnrjcbsn   2017-08-19
I'm just a little over a year out of school myself, so I'm far from an expert, but happy to share some things that come to mind.

I haven't had a chance to look through it in-depth yet, but this looks pretty interesting: https://github.com/donnemartin/system-design-primer

As far as things that have had an important impact in my learning path, I do have a few Ruby books I really like (the key here is to get your hands dirty with code as you read along): - https://www.amazon.com/Ruby-Under-Microscope-Illustrated-Int... - https://www.amazon.com/Metaprogramming-Ruby-Program-Like-Fac... - https://gumroad.com/l/rebuilding_rails

I think reading about (and looking at the code) for things you use and trying to understand how they work under the hood has been super useful: http://aosabook.org/en/index.html

Having smart people around to learn from is extremely helpful too.

Happy to chat more if you'd like. Just drop me a line: connor[at]opendoor[dot]com