Reading — step 1 of 5
Learn
define_method lets you create methods at runtime. Used heavily by Rails (has_many, validates).
class Config
[:host, :port, :db_name, :user].each do |attr|
define_method(attr) { @config[attr] }
define_method("#{attr}=") { |v| @config[attr] = v }
end
def initialize
@config = {}
end
end
c = Config.new
c.host = "localhost"
c.port = 5432
puts c.host # "localhost"
This generates 8 methods (4 readers + 4 writers) without writing each by hand.
Naming with send / public_send:
class User
attr_accessor :name, :email
end
user = User.new
fields = { name: "Ada", email: "[email protected]" }
fields.each { |k, v| user.send("#{k}=", v) }
send calls a method by name (string or symbol). public_send respects access modifiers. send bypasses them — useful but dangerous.
instance_variable_set / instance_variable_get:
user.instance_variable_set(:@name, "Linus")
puts user.instance_variable_get(:@name)
The @ prefix is required.
method_defined? and respond_to?:
User.method_defined?(:name) # true if instance method exists
user.respond_to?(:name) # true if instance can answer
Real-world example: Rails-style attr_accessor from scratch:
class Module
def my_attr_accessor(*names)
names.each do |name|
define_method(name) { instance_variable_get("@#{name}") }
define_method("#{name}=") { |v| instance_variable_set("@#{name}", v) }
end
end
end
class Foo
my_attr_accessor :a, :b, :c
end
Reopening Module like this adds my_attr_accessor to ALL classes — Ruby's permissive inheritance. Powerful + occasionally dangerous.
Discussion
Ask a question, share an insight, or help someone who’s stuck.
Sign in to post a comment or reply.
Loading…