Module: Decorate

Defined in:
lib/decorate.rb,
lib/decorate/create_alias.rb

Defined Under Namespace

Modules: AroundDecorator, BeforeDecorator, Memoize, ModuleMethod, PrivateMethod, ProtectedMethod, PublicMethod Classes: BlockDecorator

Constant Summary collapse

VERSION =
"0.3.0"

Class Method Summary collapse

Class Method Details

.clear_decoratorsObject

Clear the current threads decorator stack. Returns the old stack as an Enumerable.



29
30
31
32
33
# File 'lib/decorate.rb', line 29

def self.clear_decorators
  stack = (Thread.current[:_decorator_stack_] ||= []).dup
  Thread.current[:_decorator_stack_].clear
  stack
end

.create_alias(klass, method_name, id) ⇒ Object

Create a private alias for the instance method named method_name of class klass. The string representation of id will be part of the alias to ease debugging. This method makes sure that the alias doesn’t redefine an existing method.

Returns the name of the new alias.

In the simplest case, the alias will be "#{method_name}without#{id}".



12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# File 'lib/decorate/create_alias.rb', line 12

def self.create_alias(klass, method_name, id)
  basename = "#{method_name}_without_#{id}"

  i = 0
  new_name = basename
  loop {
    break unless klass.method_defined?(new_name)
    i += 1
    new_name = "#{basename}_#{i}"
  }

  klass.send(:alias_method, new_name, method_name)
  klass.send(:private, new_name)
  new_name
end

.decorate(decorator = nil, &block) ⇒ Object

Add a decorator that will be applied to the next method definition. Either pass an object that responds to decorate(klass, method_name) or a block. The block will be wrapped in a BlockDecorator.

Example:

def trace_def
  Decorate.decorate { |klass, method_name|
    puts "Method #{method_name.inspect} defined in #{klass.inspect}"
  }
end

class Foo
  trace_def
  def bar
    # ...
  end
end
# prints: Method :bar defined in Foo


55
56
57
58
59
60
61
62
63
# File 'lib/decorate.rb', line 55

def self.decorate(decorator = nil, &block)
  if decorator.nil?
    raise "decorator argument or block required" if block.nil?
    decorator = BlockDecorator.new(block)
  elsif block
    raise "won't accept block if decorator argument is given"
  end
  push_decorator(decorator)
end

.process_decorators(klass, method_name) ⇒ Object

Apply the current threads decorator stack to the specified method.

Decorate hooks into Module#method_added and Object#singleton_method_added to call this method.



69
70
71
72
73
# File 'lib/decorate.rb', line 69

def self.process_decorators(klass, method_name)
  Decorate.clear_decorators.reverse!.each { |decorator|
    decorator.decorate(klass, method_name)
  }
end

.push_decorator(decorator) ⇒ Object

Push a decorator on the current threads decorator stack. A decorator is an object that responds to decorate taking a class and a method name (symbol) as arguments.

Raises:

  • (TypeError)


22
23
24
25
# File 'lib/decorate.rb', line 22

def self.push_decorator(decorator)
  raise TypeError, "#{decorator} not a decorator" unless decorator
  (Thread.current[:_decorator_stack_] ||= []).push(decorator)
end