Ruby allows metaprogramming through dynamically modifying program constructs at runtime. This includes defining classes and methods dynamically, adding methods to existing classes and objects, and manipulating language semantics. Some key Ruby metaprogramming techniques are open classes/monkey patching, method_missing, define_method, eval, and hook methods. Metaprogramming can help write domain-specific languages and validation macros, but comes with costs like a steeper learning curve and reduced comprehensibility.
4. • Inspired by Lisp, Smalltalk and Perl
• Interpreted (REPL)
• Object oriented (almost everything is an object)
• Dynamically and strongly typed
• Duck typing
• Optimized for programmer happiness
5. Code examples
• Interactive Ruby
• Logical operators and duck typing
• Methods
• Arrays & Hashes
• Code blocks and yield
• Classes, Objects
• Modules and Mixins
Code Samples - 001 to 004
6. What is metaprogramming?
• Manipulating language constructs at runtime
• Define classes on the fly
• Add methods to objects
• Wrap methods with custom before/after behavior
• Create domain specific languages
8. The Ruby object model
• Every value in Ruby is an object
• Ruby object is a structure that contains
• Some flags (frozen, tainted etc)
• Array of instance variables
• Reference to the class
• What is missing?
Code Samples - 005
9. Where are the methods?
• Methods exist only in classes, not objects
• The methods of an object are the instance methods of its class
• Ruby has methods for discovering methods including
Object#methods, Module#instance_methods
• Methods can be turned into objects using Object#method
Code Samples - 006
10. Blocks, Procs, Lambdas
• Blocks are just chunks of code between do … end or { .. }
• Methods can take a single block as an implicit parameter, and yield
control to the block
• Blocks can be turned into objects using
• Proc.new
• lambda or ->
• The & operator
• Blocks are closures, they capture the surrounding scope
• Lambdas are closer to methods than Procs
Code Samples - 007
11. Classes
• Every object is an instance of some class
• Classes are objects too. A class is an instance of Class.
• The name of the class (i.e, String) is a constant that refers to
the Class object.
• The class keyword is a scope operator where
• Inside you can write code that is executable
• self refers to the Class object
• Classes can be created dynamically with Class.new
Code Samples - 008
12. Inheritance
• All classes (except one) have exactly one superclass
• If not otherwise specified, the superclass is Object
• Object in turn inherits from BasicObject, which is the
object Ruby class that doesn’t have a superclass.
• A class’s superclass can be obtained with the superclass
method.
• The entire chain of superclasses can be obtained with the
ancestors method.
Code Samples - 009
14. Modules
• Modules are like classes, but different in a few ways
• Provide a scope for defining methods
• Modules are objects of class Module
• Cannot create new objects from modules
• Modules do not participate in the inheritance hierarchy
directly, but can be included in the ancestors chain in
interesting ways.
15. include and prepend
• Both include and prepend insert the module into the
ancestors chain of the calling class (or module)
• include inserts directly above the caller
• prepend inserts directly below the caller
• This affects what super means when used in the methods
Code Samples - 009
16. Singleton Methods
• Ruby allows for defining methods on individual objects
• They are defined only on the object, not available for
others objects of the same class
• Class methods are a special case of the singleton
methods. They are actually singleton methods where the
object happens to be a class.
Code Samples - 010
18. Singleton Classes
• Recall that methods live only in classes, not objects.
• Singleton methods cannot live in the object’s class, since
that is shared by all the other objects.
• Ruby creates a special singleton class for each object.
Also known as meta class, virtual class or eigen class.
• You can access it with singleton_class method or this
syntax class << object ; end
Code Samples - 011
19. Object#extend
• Including a module get the module’s instance methods,
not the singleton methods (class methods)
• So include the module in the singleton class
• Or equivalently; use extend
• extend module - make module’s instance methods also
be singleton methods
22. Open Classes
• You can reopen any class and add methods to it
• You can reopen any module and add methods to it
• You can reopen any object and add methods to it
• A.K.A monkey patching
• Can use refinements to control the scope of changes
Code Samples - 012
23. method_missing
• If Ruby cannot find a method in the ancestors chain, it invokes
method_missing
• Classes can redefine method_missing to respond to messages
(“Ghost Methods”)
• Some downsides
• respond_to? Lies unless you also redefine
respond_to_missing?
• Ghost methods cannot be discovered with reflection
• However, can be very useful sometimes: https://github.com/
jimweirich/builder
24. define_method
• define_method is a singleton method defined in the
Module class
• Takes a string/symbol, and a block to create a named
instance method on the calling class
• Useful for defining families of related methods
Code Samples - 014
25. Scope Gates
• There are exactly three places where a program leaves the
previous scope behind and open a new one
• Class definitions
• Module definitions
• Methods
• Overcoming scope gates
• Flattening the scope
• Shared scope
Code Samples - 015
26. Writing a DSL
Code Samples - 016, 017
RedFlag is a monitor utility for the people in the sales department.
It should send the sales folks a message when an order is late, when total
sales are too low...basically, whenever one of many different things
happens.
Sales wants to monitor dozens of different events, and the list is bound to
change every week or so.
27. The eval family of methods
Code Samples - 016, 017
• Kernel#eval can be used to evaluate any strings of code
• Module#class_eval - evaluates a block in the context of
an existing class
• BasicObject#instance_eval - evaluates a block in the
context of a specific object. Redefines self to be the
receiver
• class_exec and instance_exec can pass arguments to the
block
28. Hook methods
Code Samples - 018
• Object model is an eventful place and lots of things
happen there as your code runs like
• Classes are inherited
• Modules are mixed into classes (include, append)
• Methods are defined, undefined and removed
29. Code that writes code
Code Samples - 019
• Your boss wants a class macro attr_checked
• It should take the name of the attribute, as well as a block
• The block is used for validation
• If you assign a value to an attribute and the block doesn’t
turn true for that value, then you get an exception
• A class should gain access to attr_checked only when it
includes a CheckedAttributes module
30. Cons of Metaprogramming
• Learning curve for new developers
• Not easy to find symbols using grep
• Not easy to comprehend
• Needs more unit tests
• Need to be more careful when extending
31. – Zen Master Programmer
“There is no such thing as Metaprogramming.
It’s just programming all the way down.”