Module: DR::MetaModule

Included in:
DynamicModule
Defined in:
lib/drain/ruby_ext/meta_ext.rb

Overview

helping with metaprograming facilities usage: Module Foo; extend DR::MetaModule; include_complete Ploum; end

Instance Method Summary collapse

Instance Method Details

#add_method(name = nil, method) ⇒ Object

essentially like define_method, but can pass a Method or an UnboundMethod see also dr/core_ext which add UnboundMethod#to_proc so we could instead use define_method(name,&method) and it would work



149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
# File 'lib/drain/ruby_ext/meta_ext.rb', line 149

def add_method(name=nil,method)
  name=method.name unless name
  name=name.to_sym
  #if we have a (bound) method, we can convert it to a proc, but the
  #'self' inside it keeps being the 'self' of the original object (even
  #in instance_eval).
  #Since usually we'll want to change the self, it's better to unbind it
  method=method.unbind if method.class==Method
  case method
  when UnboundMethod
    #here the block passed is evaluated using instance_eval, so self is the
    #object calling, not the current module
    define_method name do |*args,&block|
      method.bind(self).call(*args,&block)
    end
  else
    #if method is a block/Proc, this is the same as define_method(name,method)
    define_method(name,&method)
  end
end

#add_methods(*args) ⇒ Object



170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
# File 'lib/drain/ruby_ext/meta_ext.rb', line 170

def add_methods(*args)
  return if args.empty?
  if Module === args.first
    mod=args.shift
    #we include methods from mod, the arguments should be method names
    if args.size == 1 and Hash === args.first
      #we have a hash {new_name => old_name}
      args.first.each do |k,v|
        add_method(k,mod.instance_method(v.to_sym))
      end
    else
      args.each do |m|
        add_method(mod.instance_method(m.to_sym))
      end
    end
  else
    if args.size == 1 and Hash === args.first
      #we have a hash {new_name => method}
      args.first.each do |k,v|
        add_method(k,v)
      end
    else
      args.each do |m|
        add_method(m)
      end
    end
  end
end

#full_include(other) ⇒ Object

module Z def x; "x"; end end module Enumerable extend MetaModule full_include Z end Array.new.x => "x"



123
124
125
126
127
128
129
130
131
# File 'lib/drain/ruby_ext/meta_ext.rb', line 123

def full_include other
  include other
  if self.class == Module
    this = self
    ObjectSpace.each_object Module do |mod|
      mod.send :include, this if mod < self
    end
  end
end

#get_unbound_method(method_name, &block) ⇒ Object

Taken from sinatra/base.rb: return an unbound method from a block, with owner the current module Conversely, from a (bound) method, calling to_proc (hence &m) gives a lambda Note: rather than doing m=get_unbound_method('',&block);m.bind(obj).call(args) one could do obj.instance_exec(args,&block)



139
140
141
142
143
144
# File 'lib/drain/ruby_ext/meta_ext.rb', line 139

def get_unbound_method(method_name, &block)
  define_method(method_name, &block)
  method = instance_method method_name
  remove_method method_name
  method
end

#include_ancestors(m) ⇒ Object

include_ancestor includes all modules ancestor, so one can do singleton_class.include_ancestors(m) to have a fully featured extend



100
101
102
103
104
105
# File 'lib/drain/ruby_ext/meta_ext.rb', line 100

def include_ancestors(m)
  ancestors=m.respond_to?(:ancestors) ? m.ancestors : m.singleton_class.ancestors
  ancestors.reverse.each do |m|
    include m if m.class==Module
  end
end

#include_complete(obj) ⇒ Object

include a module and extend its singleton_class (along with its ancestors)



108
109
110
111
112
113
# File 'lib/drain/ruby_ext/meta_ext.rb', line 108

def include_complete(obj)
  ancestors=Meta.all_ancestors(obj)
  ancestors.reverse.each do |m|
    include m if m.class==Module
  end
end

#includes_extends_host_with(instance_module = nil, class_module = nil, hooks: [:included,:extended]) ⇒ Object

When included/extended (according to :hooks, add the following instance and class methods)



78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/drain/ruby_ext/meta_ext.rb', line 78

def includes_extends_host_with(instance_module=nil, class_module=nil, hooks: [:included,:extended])
  @_include_module ||= []
  @_extension_module ||= []
  @_include_module << instance_module
  @_extension_module << class_module
  hooks.each do |hook|
    define_singleton_method hook do |base|
      #we use send here because :include is private in Module
      @_include_module.each do |m|
        m=const_get(m) if ! Module===m
        base.send(:include, m)
      end
      @_extension_module.each do |m|
        m=const_get(m) if ! Module===m
        base.extend(m)
      end
    end
  end
end