Skip to content
Skills Library
Programming · Building & coding

ruby-metaprogramming

/ruby-metaprogramming

Use when working with Ruby metaprogramming features including dynamic method definition, method_missing, class_eval, define_method, and reflection.

Repository
han ↗
Licence
Apache-2.0
Last repository change
08.09.2026

Assessment and security

95/ 100Class: good
Format25 / 25
Frontmatter with name and description, valid name, description up to 1,024 characters, name matching the folder.
Discoverability25 / 25
Description explains when to use the skill, has a reasonable length and uses third person.
Content30 / 35
At least 150 words and at most 500 lines, headings, step lists, examples or code.
Hygiene15 / 15
No placeholders such as TODO, no Windows paths, with a licence.
Riskno signals detected in the scan
Files in this package
1
Scripts
0
HTML comments
0
URLs in SKILL.md
0
Deprecation

No signals detected. Repository changed on 08.09.2026, without references to retired models or APIs.

Licence

Apache-2.0, otwarta: można używać i zmieniać, z zachowaniem licencji i informacji o zmianach.

What it does and when to use it

Use when working with Ruby metaprogramming features including dynamic method definition, method_missing, class_eval, define_method, and reflection.

Original author description

Use when working with Ruby metaprogramming features including dynamic method definition, method_missing, class_eval, define_method, and reflection.

How it works

  1. Dynamic Method Definition
  2. Method Missing
  3. send and publicsend
  4. Class Macros
  5. Singleton Methods
  6. Eigenclass (Singleton Class)
  7. Reflection and Introspection
  8. Hook Methods
  9. DSL Creation
  10. Dynamic Class Creation
Original SKILL.md headings · 523 lines, 1,150 words
SKILL.md preview
---
name: ruby-metaprogramming
user-invocable: false
description: Use when working with Ruby metaprogramming features including dynamic method definition, method_missing, class_eval, define_method, and reflection.
allowed-tools:
  - Bash
  - Read
  - Write
  - Edit
---

# Ruby Metaprogramming

Master Ruby's powerful metaprogramming capabilities to write code that writes code. Ruby's dynamic nature makes it exceptionally good at metaprogramming.

## Dynamic Method Definition

### define_method

```ruby
class Person
  [:name, :age, :email].each do |attribute|
    define_method(attribute) do
      instance_variable_get("@#{attribute}")
    end

    define_method("#{attribute}=") do |value|
      instance_variable_set("@#{attribute}", value)
    end
  end
end

person = Person.new
person.name = "Alice"
puts person.name  # "Alice"
```

### class_eval and instance_eval

```ruby
# class_eval - Evaluates code in context of a class
class MyClass
end

MyClass.class_eval do
  def hello
    "Hello from class_eval"
  end
end

puts MyClass.new.hello

# instance_eval - Evaluates code in context of an instance
obj = Object.new
obj.instance_eval do
  def greet
    "Hello from instance_eval"
  end
end

puts obj.greet
```

### module_eval

```ruby
module MyModule
end

MyModule.module_eval do
  def self.info
    "Module metaprogramming"
  end
end

puts MyModule.info
```

## Method Missing

### Basic method_missing

```ruby
class DynamicFinder
  def initialize(data)
    @data = data
  end

  def method_missing(method_name, *args)
    if method_name.to_s.start_with?("find_by_")
      attribute = method_name.to_s.sub("find_by_", "")
      @data.find { |item| item[attribute.to_sym] == args.first }
    else
      super
    end
  end

  def respond_to_missing?(method_name, include_private = false)
    method_name.to_s.start_with?("find_by_") || super
  end
end

users = [
  { name: "Alice", age: 30 },
  { name: "Bob", age: 25 }
]

finder = DynamicFinder.new(users)
puts finder.find_by_name("Alice")  # {:name=>"Alice", :age=>30}
```

### Const Missing

```ruby
class DynamicConstants
  def self.const_missing(const_name)
    puts "Constant #{const_name} not found, creating it..."
    const_set(const_name, "Dynamic value for #{const_name}")
  end
end

puts DynamicConstants::SOMETHING  # "Dynamic value for SOMETHING"
```

## send and public_send

```ruby
class Calculator
  def add(x, y)
    x + y
  end

  private

  def secret_method
    "This is private"
  end
end

calc = Calculator.new

# send can call any method (including private)
puts calc.send(:add, 3, 4)           # 7
puts calc.send(:secret_method)       # "This is private"

# public_send only calls public methods
puts calc.public_send(:add, 3, 4)    # 7
# calc.public_send(:secret_method)   # NoMethodError
```

## Class Macros

```ruby
class ActiveModel
  def self.attr_with_history(attribute)
    define_method(attribute) do
      instance_variable_get("@#{attribute}")
    end

    define_method("#{attribute}=") do |value|
      history = instance_variable_get("@#{attribute}_history") || []
      history << value
      instance_variable_set("@#{attribute}_history", history)
      instance_variable_set("@#{attribute}", value)
    end

    define_method("#{attribute}_history") do
      instance_variable_get("@#{attribute}_history") || []
    end
  end
end

class Person < ActiveModel
  attr_with_history :name
end

person = Person.new
person.name = "Alice"
person.name = "Alicia"
puts person.name_history.inspect  # ["Alice", "Alicia"]
```

## Singleton Methods

```ruby
obj = "hello"

# Define method on single instance
def obj.shout
  self.upcase + "!!!"
end

puts obj.shout  # "HELLO!!!"

# Using define_singleton_method
obj.define_singleton_method(:whisper) do
  self.downcase + "..."
end

puts obj.whisper  # "hello..."
```

## Eigenclass (Singleton Class)

```ruby
class Person
  def self.species
    "Homo sapiens"
  end
end

# Accessing eigenclass
eigenclass = class << Person
  self
end

puts eigenclass  # #<Class:Person>

# Adding class methods via eigenclass
class Person
  class << self
    def count
      @@count ||= 0
    end

    def increment_count
      @@count ||= 0
      @@count += 1
    end
  end
end

Person.increment_count
puts Person.count  # 1
```

## Reflection and Introspection

### Object Introspection

```ruby
class MyClass
  def public_method; end
  protected
  def protected_method; end
  private
  def private_method; end
end

obj = MyClass.new

# List methods
puts obj.methods.include?(:public_method)
puts obj.private_methods.include?(:private_method)
puts obj.protected_methods.include?(:protected_method)

# Check method existence
puts obj.respond_to?(:public_method)       # true
puts obj.respond_to?(:private_method)      # false
puts obj.respond_to?(:private_method, true) # true (include private)

# Get method object
method = obj.method(:public_method)
puts method.class  # Method
```

### Class Introspection

```ruby
class Parent
  def parent_method; end
end

class Child < Parent
  def child_method; end
end

# Inheritance chain
puts Child.ancestors  # [Child, Parent, Object, Kernel, BasicObject]

# Instance methods
puts Child.instance_methods(false)  # Only Child's methods

# Class variables and instance variables
class Person
  @@count = 0
  def initialize(name)
    @name = name
  end
end

puts Person.class_variables        # [:@@count]
person = Person.new("Alice")
puts person.instance_variables     # [:@name]
```

## Hook Methods

### Inheritance Hooks

```ruby
class BaseClass
  def self.inherited(subclass)
    puts "#{subclass} inherited from #{self}"
    subclass.instance_variable_set(:@inherited_at, Time.now)
  end
end

class ChildClass < BaseClass
end
# Output: ChildClass inherited from BaseClass
```

### Method Hooks

```ruby
module Monitored
  def self.included(base)
    base.extend(ClassMethods)
  end

  module ClassMethods
    def method_added(method_name)
      puts "Method #{method_name} was added to #{self}"
    end

    def method_removed(method_name)
      puts "Method #{method_name} was removed from #{self}"
    end
  end
end

class MyClass
  include Monitored

  def my_method
  end
  # Output: Method my_method was added to MyClass
end
```

### included and extended

```ruby
module MyModule
  def self.included(base)
    puts "#{self} included in #{base}"
    base.extend(ClassMethods)
  end

  def self.extended(base)
    puts "#{self} extended by #{base}"
  end

  module ClassMethods
    def class_method
      "I'm a class method"
    end
  end

  def instance_method
    "I'm an instance method"
  end
end

class MyClass
  include MyModule  # Adds instance_method as instance method
end

class AnotherClass
  extend MyModule   # Adds instance_method as class method
end
```

## DSL Creation

```ruby
class RouteBuilder
  def initialize
    @routes = {}
  end

  def get(path, &block)
    @routes[path] = { method: :get, handler: block }
  end

  def post(path, &block)
    @routes[path] = { method: :post, handler: block }
  end

  def routes
    @routes
  end
end

# DSL usage
builder = RouteBuilder.new
builder.instance_eval do
  get "/users" do
    "List of users"
  end

  post "/users" do
    "Create user"
  end
end

puts builder.routes
```

## Dynamic Class Creation

```ruby
# Create class dynamically
MyClass = Class.new do
  define_method :greet do
    "Hello from dynamic class"
  end
end

puts MyClass.new.greet

# Create class with inheritance
Parent = Class.new do
  def parent_method
    "From parent"
  end
end

Child = Class.new(Parent) do
  def child_method
    "From child"
  end
end

child = Child.new
puts child.parent_method
puts child.child_method
```

## Object Extension

```ruby
module Greetable
  def greet
    "Hello!"
  end
end

obj = Object.new
obj.extend(Greetable)
puts obj.greet  # "Hello!"

# Only this instance has the method
another_obj = Object.new
# another_obj.greet  # NoMethodError
```

## Binding and eval

```ruby
def get_binding(param)
  local_var = "local value"
  binding
end

b = get_binding("test")

# Evaluate code in the binding context
puts eval("param", b)      # "test"
puts eval("local_var", b)  # "local value"

# instance_eval with binding
class MyClass
  def initialize
    @value = 42
  end
end

obj = MyClass.new
puts obj.instance_eval { @value }  # 42
```

## TracePoint

```ruby
trace = TracePoint.new(:call, :return) do |tp|
  puts "#{tp.event}: #{tp.method_id} in #{tp.defined_class}"
end

trace.enable

def my_method
  "Hello"
end

my_method

trace.disable
```

## Best Practices

1. **Use metaprogramming sparingly** - it can make code hard to understand
2. **Always implement respond_to_missing?** when using method_missing
3. **Prefer define_method over class_eval** when possible
4. **Document metaprogramming heavily** - it's not obvious what's happening
5. **Use public_send over send** to respect visibility
6. **Cache metaprogrammed methods** to avoid repeated definition
7. **Test metaprogrammed code thoroughly** - bugs can be subtle

## Anti-Patterns

❌ **Don't overuse method_missing** - it's slow and hard to debug
❌ **Don't use eval with user input** - major security risk
❌ **Don't metaprogram when simple code works** - clarity over cleverness
❌ **Don't forget to call super** in method_missing
❌ **Don't create methods without documenting them** - IDE support breaks

## Common Use Cases

- **ORMs** (ActiveRecord) - Dynamic finders, associations
- **DSLs** - Route definitions, configurations
- **Decorators** - Method wrapping and enhancement
- **Mocking/Stubbing** - Test frameworks
- **Attribute definition** - Custom accessors with behavior

## Related Skills

- ruby-oop - Understanding classes and modules
- ruby-blocks-procs-lambdas - For callbacks and dynamic behavior
- ruby-gems - Many gems use metaprogramming extensively

Versions

The database has no other skills named ruby-metaprogramming.

Database snapshot: 13.11.2026 · package version 97e733513215 (SHA-256 digest of the entire package)

Downloads in the last 30 days: 0 · ranking

Report a problem with this skill: harmful content, incorrect descriptions or an author’s removal request.

Similar skills

  • 100ruby-metaprogramming-idiomatic
    Use this skill when authoring dynamic Domain-Specific Languages (DSLs), method_missing hooks, and class macros in Ruby.
  • 90ruby-pro
    Write idiomatic Ruby code with metaprogramming, Rails patterns, and performance optimization. Specializes in Ruby on Rails, gem development, and testing frameworks. Use for Ruby refactoring, optimization, or complex Ruby features.
  • 100ruby
    Expert Ruby programming assistance covering blocks, metaprogramming, Bundler, gems, and modern Ruby 3.x features. Use when developing Rails web apps, writing CLI utilities, or managing Ruby gems.
  • 100ruby-expert
    Expert-level Ruby development with Rails, modern features, testing, and best practices. Use when the user mentions Ruby on Rails, RSpec, gem, Sinatra, or metaprogramming, or when the task involves Ruby 3+ Features, Object-Oriented, Functional Features, or Pattern Matching.
  • 100ruby-guide
    Ruby language guardrails, patterns, and best practices for AI-assisted development. Use when working with Ruby files (.rb), Gemfile, Rakefile, or when the user mentions Ruby. Provides block/proc patterns, metaprogramming guidelines, Bundler conventions, and testing standards…
  • 95ruby-oop
    Use when working with Ruby's object-oriented programming features including classes, modules, inheritance, mixins, and method visibility.

Feedback and reports

Your message goes to Bartosz Sokoliński. An email address is needed only for a reply. See the privacy policy.