Class: Module

Inherits:
Object show all
Defined in:
lib/utilrb/module/include.rb,
lib/utilrb/module/ancestor_p.rb,
lib/utilrb/module/cached_enum.rb,
lib/utilrb/module/is_singleton.rb,
lib/utilrb/module/define_method.rb,
lib/utilrb/module/dsl_attribute.rb,
lib/utilrb/module/attr_predicate.rb,
lib/utilrb/module/attr_enumerable.rb,
lib/utilrb/module/define_or_reuse.rb,
lib/utilrb/module/singleton_class_p.rb,
lib/utilrb/module/const_defined_here_p.rb

Instance Method Summary collapse

Instance Method Details

#__include_single_module(mod) ⇒ Object


22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# 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

#attr_enumerable(name, attr_name = name, enumerator = :each, &init_block) ⇒ Object

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.


25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# 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

#attr_predicate(name, writable = false) ⇒ Object

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


7
8
9
10
11
12
13
14
15
16
# 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

#cached_enum(enum_name, name, with_arg) ⇒ Object

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


21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# 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

#const_defined_here?(name) ⇒ Boolean


3
4
5
# File 'lib/utilrb/module/const_defined_here_p.rb', line 3

def const_defined_here?(name)
    const_defined?(name, false)
end

#define_method_with_block(name, &mdef) ⇒ Object

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


21
22
23
24
25
26
27
28
# 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

#define_or_reuse(name, value = nil) ⇒ Object

: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


12
13
14
15
16
17
18
19
20
# 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

#dsl_attribute(*names, &filter_block) ⇒ Object

call-seq:

dsl_attribute(name)
dsl_attribute(name,name2,name3)
dsl_attribute(name) { |value| ... }

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

37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# 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

#has_ancestor?(klass) ⇒ Boolean

:nodoc:


2
3
4
# File 'lib/utilrb/module/ancestor_p.rb', line 2

def has_ancestor?(klass) # :nodoc:
    self <= klass
end

#include(*mods) ⇒ Object

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.


16
17
18
19
20
# File 'lib/utilrb/module/include.rb', line 16

def include(*mods)
    mods.each do |mod|
        __include_single_module(mod)
    end
end

#is_singleton?Object


5
# File 'lib/utilrb/module/is_singleton.rb', line 5

alias :is_singleton? :singleton_class?

#singleton_class?Boolean

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


6
7
8
9
10
11
12
# 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