class Module
Public Instance Methods
# File lib/utilrb/module/include.rb, line 22 def __include_single_module(mod) if mod.const_defined?(:ModuleExtension) if is_a?(Module) unless const_defined?(:ModuleExtension) const_set(:ModuleExtension, Module.new) end const_get(:ModuleExtension).class_eval do __instance_include__ mod.const_get(:ModuleExtension) end extend mod.const_get(:ModuleExtension) end # Do nothing on classes end if mod.const_defined?(:ClassExtension) if !is_a?(Class) unless const_defined?(:ClassExtension) const_set(:ClassExtension, Module.new) end const_get(:ClassExtension).class_eval do __instance_include__ mod.const_get(:ClassExtension) end else extend mod.const_get(:ClassExtension) end end __instance_include__ mod end
Support for attributes that are enumerables. This methods defines two methods:
obj.attr_name # => enumerable
obj.each_name(key = nil) { |value| ... } # => obj
The first one returns the enumerable object itself. The second one iterates
on the values in attr_name. If key is not nil, then attr_name
is supposed to be a hash of enumerables, and key is used to
select the enumerable to iterate on.
The following calls are equivalent
obj.attr_name.each { |value| ... }
obj.each_name { |value| ... }
And these two are equivalent:
obj.attr_name[key].each { |value| ... }
obj.each_name(key) { |value| ... }
enumerator is the name of the enumeration method we should
use. init_block, if given, should return the value at which we
should initialize attr_name.
# File lib/utilrb/module/attr_enumerable.rb, line 25 def attr_enumerable(name, attr_name = name, enumerator = :each, &init_block) class_eval do attribute(attr_name, &init_block) end class_eval <<-EOF, __FILE__, __LINE__+1 def each_#{name}(key = nil, &iterator) return unless #{attr_name} if key #{attr_name}[key].#{enumerator}(&iterator) else #{attr_name}.#{enumerator}(&iterator) end self end EOF end
Defines a name? predicate, and if writable is true a name=
method. Note that name can end with '?', in which case
the ending '?' is removed.
The methods use the @name instance variable internally
# File lib/utilrb/module/attr_predicate.rb, line 7 def attr_predicate(name, writable = false) attr_name = name.to_s.gsub(/\?$/, '') attr_reader attr_name alias_method "#{attr_name}?", attr_name remove_method attr_name if writable class_eval "def #{attr_name}=(value); @#{attr_name} = !!value end", __FILE__, __LINE__+1 end end
Creates enum_#{name} method which returs an Enumerator object
for the each_#{enum_name} method. This enumerator is created
once.
If with_arg is true, it is supposed that the 'each_'
method requires one argument, which is given in argument of the
'enum' method. In that case, an enumerator is created for each
argument
# File lib/utilrb/module/cached_enum.rb, line 21 def cached_enum(enum_name, name, with_arg) include CachedValuesSupport if with_arg class_eval <<-EOD, __FILE__, __LINE__+1 def enum_#{name}(arg) @enum_#{name} ||= Hash.new cached_variables << :@enum_#{name} @enum_#{name}[arg] ||= enum_for(:each_#{enum_name}, arg) end EOD else class_eval <<-EOD, __FILE__, __LINE__+1 def enum_#{name} cached_variables << :@enum_#{name} @enum_#{name} ||= enum_for(:each_#{enum_name}) end EOD end end
# File lib/utilrb/module/const_defined_here_p.rb, line 3 def const_defined_here?(name) const_defined?(name, false) end
Emulate block-passing by converting the block into a Proc object and passing it to the given block as last argument dule)
For instance
define_method('my_method') do |a, &block| end
Is written as
define_method_with_block('my_method') do |block, a| end
The block is given first to allow the following construct:
define_method_with_block('my_method') do |block, *args| end
block is nil if no block is given during the
method call
# File lib/utilrb/module/define_method.rb, line 21 def define_method_with_block(name, &mdef) class_eval <<-EOD, __FILE__, __LINE__+1 def #{name}(*args, &block) dmwb_#{name}_user_definition(block, *args) end EOD define_method("dmwb_#{name}_user_definition", &mdef) end
:call-seq
define_or_reuse(name, value) -> value
define_or_reuse(name) { ... } -> value
Defines a new constant under a given module, or reuse the already-existing value if the constant is already defined.
In the first form, the method gets its value from its argument. In the second case, it calls the provided block
# File lib/utilrb/module/define_or_reuse.rb, line 12 def define_or_reuse(name, value = nil) if const_defined_here?(name) const_get(name) else module_eval do const_set(name, (value || yield)) end end end
This defines a name instance method on the given class which
accepts zero or one argument
Without any argument, it acts as a getter for the +@name+ attribute. With
one argument, it acts instead as a setter for the same attribute and
returns self. If a block has been given to dsl_attribute, any
new value is passed to the block, whose return value is actually saved in
the instance variable. This block can therefore both filter the value
(convert it to a desired form) and validate it.
The goal of this method is to have a nicer way to handle attribute in DSLs: instead of
model = create_model do
self.my_model_attribute = 'bla'
if (my_model_attribute)
<do something>
end
end
(or worse, using set_ and get_ prefixes), we can do
model = create_model do
my_model_attribute 'bla', arg0, arg1, ...
if (my_model_attribute)
<do something>
end
end
# File lib/utilrb/module/dsl_attribute.rb, line 37 def dsl_attribute(*names, &filter_block) if names.size > 1 && filter_block raise ArgumentError, "multiple names as argument are only supported if no block is given" end names.each do |name| class_eval do if filter_block define_method("__dsl_attribute__#{name}__filter__", &filter_block) end define_method(name) do |*value| if value.empty? instance_variable_get("@#{name}") elsif filter_block if filter_block.arity >= 0 && value.size != filter_block.arity raise ArgumentError, "too many arguments. Got #{value.size}, expected #{filter_block.arity}" end filtered_value = send("__dsl_attribute__#{name}__filter__", *value) instance_variable_set("@#{name}", filtered_value) self else if value.size == 1 instance_variable_set("@#{name}", value.first) else instance_variable_set("@#{name}", value) end self end end end end end
Includes a module in this one, with support for class extensions
If a module defines a ClassExtension submodule, then
-
if it is included in a module, the target's ClassExtension module includes the source ClassExtension (and if there is no ClassExtension in the target, it is created)
-
if it is included in a Class, the ClassExtension module extends the class.
# File lib/utilrb/module/include.rb, line 16 def include(*mods) mods.each do |mod| __include_single_module(mod) end end
It so happens that this method to determine whether a class is a singleton class is valid for ruby 2.0 and breaks on 2.1 … However (!) on 2.1 singleton_class? is defined
# File lib/utilrb/module/singleton_class_p.rb, line 6 def singleton_class? if instance_variable_defined?(:@__utilrb_singleton_class) @__utilrb_singleton_class else @__utilrb_singleton_class = (ancestors.first != self) end end