class Module
def alias_attribute(new_name, old_name)
e.subject = "Megastars"
e.subject? # => true
e.subject # => "Superstars"
e.title # => "Superstars"
e = Email.find(1)
end
alias_attribute :subject, :title
class Email < Content
end
# has a title attribute
class Content < ActiveRecord::Base
Example:
getter, setter, and query methods.
Allows you to make aliases for attributes, which includes
def alias_attribute(new_name, old_name) module_eval <<-STR, __FILE__, __LINE__ + 1 def #{new_name}; self.#{old_name}; end # def subject; self.title; end def #{new_name}?; self.#{old_name}?; end # def subject?; self.title?; end def #{new_name}=(v); self.#{old_name} = v; end # def subject=(v); self.title = v; end STR end
def alias_method_chain(target, feature)
alias_method :foo?, :foo_with_feature?
alias_method :foo_without_feature?, :foo?
is equivalent to
alias_method_chain :foo?, :feature
Query and bang methods (foo?, foo!) keep the same punctuation:
And both aliases are set up for you.
alias_method_chain :foo, :feature
With this, you simply do:
alias_method :foo, :foo_with_feature
alias_method :foo_without_feature, :foo
Encapsulates the common pattern of:
def alias_method_chain(target, feature) # Strip out punctuation on predicates or bang methods since # e.g. target?_without_feature is not a valid method name. aliased_target, punctuation = target.to_s.sub(/([?!=])$/, ''), $1 yield(aliased_target, punctuation) if block_given? with_method, without_method = "#{aliased_target}_with_#{feature}#{punctuation}", "#{aliased_target}_without_#{feature}#{punctuation}" alias_method without_method, target alias_method target, with_method case when public_method_defined?(without_method) public target when protected_method_defined?(without_method) protected target when private_method_defined?(without_method) private target end end
def anonymous?
m.name # => "M"
M = m # => m gets a name here as a side-effect
m = Module.new # creates an anonymous module
via the +module+ or +class+ keyword or by an explicit assignment:
A module gets a name when it is first assigned to a constant. Either
m.name # => ""
m = Module.new
M.name # => "M"
module M; end
A module may or may not have a name.
def anonymous? # Uses blank? because the name of an anonymous class is an empty # string in 1.8, and nil in 1.9. name.blank? end
def attr_accessor_with_default(sym, default = nil, &block)
attr_accessor_with_default(:element_name) { name.underscore }
in scope of self:
To give attribute :element_name a dynamic default value, evaluated
=> 26
some_person.age
some_person.age = 26
=> 25
some_person.age
end
attr_accessor_with_default :age, 25
class Person
To give attribute :age the initial value 25:
Declare an attribute accessor with an initial default return value.
def attr_accessor_with_default(sym, default = nil, &block) raise 'Default value or block required' unless !default.nil? || block define_method(sym, block_given? ? block : Proc.new { default }) module_eval(<<-EVAL, __FILE__, __LINE__ + 1) def #{sym}=(value) # def age=(value) class << self; attr_reader :#{sym} end # class << self; attr_reader :age end @#{sym} = value # @age = value end # end EVAL end
def attr_internal_accessor(*attrs)
Declares an attribute reader and writer backed by an internally-named instance
def attr_internal_accessor(*attrs) attr_internal_reader(*attrs) attr_internal_writer(*attrs) end
def attr_internal_ivar_name(attr)
def attr_internal_ivar_name(attr) Module.attr_internal_naming_format % attr end
def attr_internal_reader(*attrs)
def attr_internal_reader(*attrs) attrs.each do |attr| module_eval "def #{attr}() #{attr_internal_ivar_name(attr)} end", __FILE__, __LINE__ end end
def attr_internal_writer(*attrs)
def attr_internal_writer(*attrs) attrs.each do |attr| module_eval "def #{attr}=(v) #{attr_internal_ivar_name(attr)} = v end", __FILE__, __LINE__ end end
def delegate(*methods)
Foo.new.zoo # returns nil
end
delegate :zoo, :to => :bar, :allow_nil => true
end
@bar = bar
def initialize(bar = nil)
attr_accessor :bar
class Foo
Foo.new.zoo # raises NoMethodError exception (you called nil.zoo)
end
delegate :zoo, :to => :bar
end
@bar = bar
def initialize(bar = nil)
attr_accessor :bar
class Foo
+nil+ instead with the +:allow_nil+ option.
no matter whether +nil+ responds to the delegated method. You can get a
If the delegate object is +nil+ an exception is raised, and that happens
invoice.customer_address # => "Vimmersvej 13"
invoice.customer_name # => "John Doe"
invoice = Invoice.new(john_doe)
end
delegate :name, :address, :to => :client, :prefix => :customer
class Invoice < Struct.new(:client)
It is also possible to supply a custom prefix.
invoice.client_address # => "Vimmersvej 13"
invoice.client_name # => "John Doe"
invoice = Invoice.new(john_doe)
john_doe = Person.new("John Doe", "Vimmersvej 13")
end
delegate :name, :address, :to => :client, :prefix => true
class Invoice < Struct.new(:client)
Person = Struct.new(:name, :address)
delegated to.
is true, the delegate methods are prefixed with the name of the object being
Delegates can optionally be prefixed using the :prefix option. If the value
Foo.new.max # => 11
Foo.new.min # => 4
Foo.new.sum # => 6
end
delegate :max, :to => :@instance_array
delegate :min, :to => :@@class_array
delegate :sum, :to => :CONSTANT_ARRAY
end
@instance_array = [8,9,10,11]
def initialize
@@class_array = [4,5,6,7]
CONSTANT_ARRAY = [0,1,2,3]
class Foo
by providing them as a symbols:
Methods can be delegated to instance variables, class variables, or constants
Foo.new.goodbye # => "goodbye"
end
delegate :hello, :goodbye, :to => :greeter
belongs_to :greeter
class Foo < ActiveRecord::Base
Multiple delegates to the same target are allowed:
Foo.new.goodbye # => NoMethodError: undefined method `goodbye' for #
Foo.new.hello # => "hello"
end
delegate :hello, :to => :greeter
belongs_to :greeter
class Foo < ActiveRecord::Base
end
end
"goodbye"
def goodbye
end
"hello"
def hello
class Greeter < ActiveRecord::Base
Delegation is particularly useful with Active Record associations:
or string). At least one method and the :to option are required.
and the name of the target object via the :to option (also a symbol
as your own. Pass one or more methods (specified as symbols or strings)
Provides a delegate class method to easily expose contained objects' methods
def delegate(*methods) options = methods.pop unless options.is_a?(Hash) && to = options[:to] raise ArgumentError, "Delegation needs a target. Supply an options hash with a :to key as the last argument (e.g. delegate :hello, :to => :greeter)." end if options[:prefix] == true && options[:to].to_s =~ /^[^a-z_]/ raise ArgumentError, "Can only automatically set the delegation prefix when delegating to a method." end prefix = options[:prefix] && "#{options[:prefix] == true ? to : options[:prefix]}_" file, line = caller.first.split(':', 2) line = line.to_i methods.each do |method| on_nil = if options[:allow_nil] 'return' else %(raise "#{self}##{prefix}#{method} delegated to #{to}.#{method}, but #{to} is nil: \#{self.inspect}") end module_eval(<<-EOS, file, line - 5) if instance_methods(false).map(&:to_s).include?("#{prefix}#{method}") remove_possible_method("#{prefix}#{method}") end def #{prefix}#{method}(*args, &block) # def customer_name(*args, &block) #{to}.__send__(#{method.inspect}, *args, &block) # client.__send__(:name, *args, &block) rescue NoMethodError # rescue NoMethodError if #{to}.nil? # if client.nil? #{on_nil} # return # depends on :allow_nil else # else raise # raise end # end end # end EOS end end
def deprecate(*method_names)
deprecate :bar => 'message'
deprecate :foo
Declare that a method has been deprecated.
def deprecate(*method_names) ActiveSupport::Deprecation.deprecate_methods(self, *method_names) end
def duplicable?
def duplicable? false end
def instance_method_names(*args)
def instance_method_names(*args) instance_methods(*args).map(&:to_s) end
def local_constant_names
Returns the names of the constants defined locally rather than the
def local_constant_names local_constants.map { |c| c.to_s } end
def local_constants
previous versions it may miss some constants if their definition in some
not in an ancestor. This method is exact if running under Ruby 1.9. In
Returns the constants that have been defined locally by this object and
def local_constants inherited = {} ancestors.each do |anc| next if anc == self anc.constants.each { |const| inherited[const] = anc.const_get(const) } end constants.select do |const| !inherited.key?(const) || inherited[const].object_id != const_get(const).object_id end end
def local_constants #:nodoc:
def local_constants #:nodoc: constants(false) end
def mattr_accessor(*syms)
end
self.paypal_url = "www.sandbox.paypal.com"
mattr_accessor :paypal_url
self.google_api_key = "123456789"
mattr_accessor :google_api_key
module AppConfiguration
just like the native attr* accessors for instance attributes.
Extends the module object with module and instance accessors for class attributes,
def mattr_accessor(*syms) mattr_reader(*syms) mattr_writer(*syms) end
def mattr_reader(*syms)
def mattr_reader(*syms) options = syms.extract_options! syms.each do |sym| class_eval(<<-EOS, __FILE__, __LINE__ + 1) @@#{sym} = nil unless defined? @@#{sym} def self.#{sym} @@#{sym} end EOS unless options[:instance_reader] == false class_eval(<<-EOS, __FILE__, __LINE__ + 1) def #{sym} @@#{sym} end EOS end end end
def mattr_writer(*syms)
def mattr_writer(*syms) options = syms.extract_options! syms.each do |sym| class_eval(<<-EOS, __FILE__, __LINE__ + 1) def self.#{sym}=(obj) @@#{sym} = obj end EOS unless options[:instance_writer] == false class_eval(<<-EOS, __FILE__, __LINE__ + 1) def #{sym}=(obj) @@#{sym} = obj end EOS end end end
def method_names(*args)
def method_names(*args) methods(*args).map(&:to_s) end
def parent
Module.new.parent # => Object
M.parent # => Object
The parent of top-level and anonymous modules is Object.
X.parent # => M
M::N.parent # => M
X = M::N
end
end
module N
module M
Returns the module which contains this one according to its name.
def parent parent_name ? ActiveSupport::Inflector.constantize(parent_name) : Object end
def parent_name
Returns the name of the module containing this one.
def parent_name unless defined? @parent_name @parent_name = name =~ /::[^:]+\Z/ ? $`.freeze : nil end @parent_name end
def parents
X.parents # => [M, Object]
M::N.parents # => [M, Object]
M.parents # => [Object]
X = M::N
end
end
module N
module M
nested outwards. The receiver is not contained within the result.
Returns all the parents of this module according to its name, ordered from
def parents parents = [] if parent_name parts = parent_name.split('::') until parts.empty? parents << ActiveSupport::Inflector.constantize(parts * '::') parts.pop end end parents << Object unless parents.include? Object parents end
def reachable? #:nodoc:
def reachable? #:nodoc: !anonymous? && name.constantize.equal?(self) rescue NameError false end
def redefine_method(method, &block)
def redefine_method(method, &block) remove_possible_method(method) define_method(method, &block) end
def remove_possible_method(method)
def remove_possible_method(method) remove_method(method) rescue NameError end
def synchronize(*methods)
synchronize :expire, :with => :@@lock
end
...
def expire
@@lock = Mutex.new
class SharedCache
Example:
constant, or instance or class variable.
The :with option should be a symbol or string, and can represent a method,
#synchronize and yields to a block) must be provided as a final :with option.
particular mutex. A mutex (either a Mutex, or any object that responds to
Synchronize access around a method, delegating synchronization to a
def synchronize(*methods) options = methods.extract_options! unless options.is_a?(Hash) && with = options[:with] raise ArgumentError, "Synchronization needs a mutex. Supply an options hash with a :with key as the last argument (e.g. synchronize :hello, :with => :@mutex)." end methods.each do |method| aliased_method, punctuation = method.to_s.sub(/([?!=])$/, ''), $1 if method_defined?("#{aliased_method}_without_synchronization#{punctuation}") raise ArgumentError, "#{method} is already synchronized. Double synchronization is not currently supported." end module_eval(<<-EOS, __FILE__, __LINE__ + 1) def #{aliased_method}_with_synchronization#{punctuation}(*args, &block) # def expire_with_synchronization(*args, &block) #{with}.synchronize do # @@lock.synchronize do #{aliased_method}_without_synchronization#{punctuation}(*args, &block) # expire_without_synchronization(*args, &block) end # end end # end EOS alias_method_chain method, :synchronization end end