Module: Util::AddedMethods

Extended by:
AddedMethods
Included in:
AddedMethods
Defined in:
lib/nuggets/util/added_methods.rb

Overview

Watch for added methods and record them. Inspired by unroller, <unroller.rubyforge.org/classes/Unroller.html#M000034>.

Example:

require 'rubygems'
require 'nuggets/util/added_methods/init'

require 'some/library/or/whatever'

matches = Util::AddedMethods.find(
  :name  => 'method_name',
  :class => SomeClass  # optional
)

# get the class(es) where matching method(s) were defined
matches.each { |am| puts am.klass  # also am[:klass] or am[:class] }

# assume the first one is the one we're looking for
am = matches.first

# is it a singleton method?
puts am.singleton?

# where exactly has it been defined?
puts "#{am.file}, line #{am.line}"

# now get its source
puts am  # implies #to_s, you can also call #extract_source directly

TODO:

  • multi-line statements in irb w/o ruby2ruby? (=> extract_source)

  • polishing!

Defined Under Namespace

Classes: AddedMethod

Constant Summary collapse

HISTFILENAME =
'(Readline::HISTORY)'.freeze

Instance Method Summary collapse

Instance Method Details

#all_methodsObject



246
247
248
249
# File 'lib/nuggets/util/added_methods.rb', line 246

def all_methods
  init_all_methods
  ALL_METHODS
end

#callback(*args, &inner_block) ⇒ Object



191
192
193
194
# File 'lib/nuggets/util/added_methods.rb', line 191

def callback(*args, &inner_block)
  callback_args = [identify_added_method(*args << caller), caller, inner_block]
  callbacks.each { |name, callback| callback[*callback_args] }
end

#callbacksObject



186
187
188
189
# File 'lib/nuggets/util/added_methods.rb', line 186

def callbacks
  init_callbacks
  CALLBACKS
end

#define_callback(name, regexp = //, klasses = [], &outer_block) ⇒ Object

Raises:

  • (TypeError)


196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
# File 'lib/nuggets/util/added_methods.rb', line 196

def define_callback(name, regexp = //, klasses = [], &outer_block)
  raise TypeError, "wrong argument type #{name.class} (expected Symbol)" unless name.is_a?(Symbol)
  raise "callback with name #{name} already exists" if callbacks.assoc(name)

  raise TypeError, "wrong argument type #{regexp.class} (expected Regexp)" unless regexp.is_a?(Regexp)
  raise TypeError, "wrong argument type #{klasses.class} (expected container object)" unless klasses.respond_to?(:empty?) && klasses.respond_to?(:include?)

  callbacks << [name, lambda { |am, callstack, inner_block|
    method, klass = am.name, am.klass

    return if %w[method_added singleton_method_added].include?(method)

    return unless klasses.empty? || klasses.include?(klass.to_s)
    return unless method =~ regexp

    if outer_block || inner_block
      outer_block[am] if outer_block
      inner_block[am] if inner_block
    else
      msg = "[#{am.base}] Adding #{'singleton ' if am.singleton?}method #{klass}##{method}"

      msg << if irb?(callstack)
        " in (irb:#{IRB.conf[:MAIN_CONTEXT].instance_variable_get(:@line_no)})"
      else
        " at #{where(callstack)}"
      end

      puts msg
    end
  }]
end

#find(conditions = {}) ⇒ Object



251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
# File 'lib/nuggets/util/added_methods.rb', line 251

def find(conditions = {})
  conditions = conditions.dup

  class_condition = conditions.delete(:class)
  file_condition  = conditions.delete(:file)

  results = []

  all_methods.each { |klass, files|
    if class_condition
      next unless class_condition.is_a?(Array) ? class_condition.include?(klass) : klass == class_condition
    end

    files.each { |file, entries|
      if file_condition
        next unless file_condition.is_a?(Regexp) ? file =~ file_condition : file == file_condition
      end

      entries.each { |am|
        results << am if conditions.all? { |key, value|
          case value
            when Array, Range then value.include?(am[key])
            when Regexp       then value =~ am[key].to_s
            else                   value == am[key]
          end
        }
      }
    }
  }

  results
end

#find_by_class(*classes) ⇒ Object



284
285
286
287
# File 'lib/nuggets/util/added_methods.rb', line 284

def find_by_class(*classes)
  conditions = classes.last.is_a?(Hash) ? classes.pop : {}
  find(conditions.merge(:class => classes))
end

#find_by_name(*names) ⇒ Object



289
290
291
292
# File 'lib/nuggets/util/added_methods.rb', line 289

def find_by_name(*names)
  conditions = names.last.is_a?(Hash) ? names.pop : {}
  find(conditions.merge(:name => names.map { |m| m.to_s }))
end

#find_one_by_name_or_class(name_or_class, conditions = {}) ⇒ Object Also known as: []



294
295
296
297
298
299
# File 'lib/nuggets/util/added_methods.rb', line 294

def find_one_by_name_or_class(name_or_class, conditions = {})
  (name_or_class.is_a?(Class) ?
    find_by_class(name_or_class) :
    find_by_name(name_or_class)
  ).last
end

#init(regexp = nil, klasses = [], &block) ⇒ Object



178
179
180
181
182
183
184
# File 'lib/nuggets/util/added_methods.rb', line 178

def init(regexp = nil, klasses = [], &block)
  init_script_lines
  patch_readline_history

  define_callback(:__init, regexp, klasses, &block) if regexp
  install_callbacks
end

#install_callbacks(bases = [Object, Class, Module, Kernel]) ⇒ Object



237
238
239
240
241
242
243
244
# File 'lib/nuggets/util/added_methods.rb', line 237

def install_callbacks(bases = [Object, Class, Module, Kernel])
  bases.each { |base|
    [base, singleton_class(base)].each { |b|
      b.send(:define_method, :method_added)           { |id| AddedMethods.callback(b, self, id, false) }
      b.send(:define_method, :singleton_method_added) { |id| AddedMethods.callback(b, self, id, true)  }
    }
  }
end

#remove_callback(name) ⇒ Object



228
229
230
# File 'lib/nuggets/util/added_methods.rb', line 228

def remove_callback(name)
  callbacks.delete_if { |n, _| n == name }
end

#replace_callback(name, regexp = nil, klasses = [], &outer_block) ⇒ Object



232
233
234
235
# File 'lib/nuggets/util/added_methods.rb', line 232

def replace_callback(name, regexp = nil, klasses = [], &outer_block)
  remove_callback(name)
  define_callback(name, regexp, klasses, &outer_block)
end