Ruby Metaprogramming Cheat Sheet
Covers method_missing, define_method, class_eval/instance_eval, hooks like included/inherited, and building simple DSLs in idiomatic Ruby.
Dynamically Defining Methods
`define_method` creates methods at runtime, closing over local variables.
class Product ATTRS = [:name, :price, :sku] ATTRS.each do |attr| define_method(attr) { instance_variable_get("@#{attr}") } define_method("#{attr}=") { |val| instance_variable_set("@#{attr}", val) } endendp = Product.newp.name = "Widget"p.name # => "Widget"
`method_missing` & `respond_to_missing?`
Intercept calls to undefined methods — always pair with respond_to_missing? for correctness.
class DynamicProxy def initialize(data) @data = data end def method_missing(name, *args) key = name.to_s if key.end_with?('=') @data[key.chomp('=')] = args.first elsif @data.key?(key) @data[key] else super # important: fall back for truly unknown methods end end def respond_to_missing?(name, include_private = false) @data.key?(name.to_s.chomp('=')) || super endendobj = DynamicProxy.new({'title' => 'Ruby'})obj.title # => "Ruby"obj.respond_to?(:title) # => true
`class_eval`, `instance_eval` & Hooks
Reopen classes at runtime and hook into inheritance/inclusion events.
class Base def self.inherited(subclass) puts "#{subclass} inherited from #{self}" endendmodule Trackable def self.included(base) puts "Trackable included in #{base}" base.extend(ClassMethods) end module ClassMethods def track(attr) define_method("track_#{attr}") { send(attr) } end endendString.class_eval do def shout upcase + "!" endend"hi".shout # => "HI!"
Building a Small DSL
Combine `instance_eval` with blocks to get clean, declarative-looking configuration syntax.
class Router def initialize(&block) @routes = [] instance_eval(&block) if block_given? end def get(path, to:) @routes << { verb: :get, path: path, handler: to } end def routes @routes endendrouter = Router.new do get '/users', to: 'users#index' get '/users/:id', to: 'users#show'endrouter.routes # => [{verb: :get, path: "/users", ...}, ...]
Core Metaprogramming Hooks
Reference for the most-used reflective methods.
- method_missing- intercepts calls to undefined methods on an object
- respond_to_missing?- must be overridden alongside method_missing for respond_to? correctness
- define_method- defines a method at runtime, can close over local variables
- class_eval / instance_eval- evaluate a block/string in the context of a class or object
- included / extended / inherited- module/class hooks fired on include, extend, subclassing
- send / public_send- invoke a method by symbol name, bypassing/respecting visibility
- instance_variable_get/set- read/write ivars dynamically by name
Prefer define_method over method_missing whenever the set of dynamic methods is known ahead of time (e.g. from a list of attributes) — it's faster, shows up correctly in respond_to? without extra code, and gives clean backtraces.
Explore Topics
Professional Web Designing Services
- Responsive Websites
- E-commerce Solutions
- SEO Friendly Design
- Fast & Secure
- Support & Maintenance