Class: Peeek::Hook

Inherits:
Object
  • Object
show all
Defined in:
lib/peeek/hook.rb,
lib/peeek/hook/linker.rb,
lib/peeek/hook/instance.rb,
lib/peeek/hook/singleton.rb,
lib/peeek/hook/specifier.rb

Defined Under Namespace

Classes: Instance, Linker, Singleton, Specifier

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(object, method_name, linker_class) {|call| ... } ⇒ Hook

Initialize the hook.

Parameters:

  • object (Module, Class, Object)

    a target object that hook

  • method_name (Symbol)

    method name of the object

  • linker_class (Class)

    class of an object to link the hook

Yields:

  • (call)

    process a call to the method. give optionally

Yield Parameters:

Raises:

  • (ArgumentError)


69
70
71
72
73
74
75
76
77
# File 'lib/peeek/hook.rb', line 69

def initialize(object, method_name, linker_class, &process)
  raise ArgumentError, "invalid as linker class, #{Linker.classes.join(' or ')} are valid" unless Linker.classes.include?(linker_class)
  @object = object
  @method_name = method_name
  @linker = linker_class.new(object, method_name)
  @process = process
  @calls = Calls.new
  raise ArgumentError, "can't create a hook of instance method to an instance of any class" if self.class.any_instance?(object) and instance?
end

Instance Attribute Details

#callsPeeek::Calls (readonly)

Returns calls to the method that the hook captured.

Returns:

  • (Peeek::Calls)

    calls to the method that the hook captured



89
90
91
# File 'lib/peeek/hook.rb', line 89

def calls
  @calls
end

#method_nameSymbol (readonly)

Returns method name of the object.

Returns:

  • (Symbol)

    method name of the object



85
86
87
# File 'lib/peeek/hook.rb', line 85

def method_name
  @method_name
end

#objectModule, ... (readonly)

Returns a target object that hook.

Returns:

  • (Module, Class, Object)

    a target object that hook



81
82
83
# File 'lib/peeek/hook.rb', line 81

def object
  @object
end

Class Method Details

.any_instance?(object) ⇒ Boolean

Determine if an object is an instance of any class.

Parameters:

  • object (Module, Class, Object)

    an object

Returns:

  • (Boolean)

    whether an object is an instance of any class



58
59
60
# File 'lib/peeek/hook.rb', line 58

def self.any_instance?(object)
  !any_module?(object)
end

.any_module?(object) ⇒ Boolean

Determine if an object is a module or a class.

Parameters:

  • object (Module, Class, Object)

    an object

Returns:

  • (Boolean)

    whether an object is a module or a class



50
51
52
# File 'lib/peeek/hook.rb', line 50

def self.any_module?(object)
  object.class == Module || object.class == Class
end

.create(object, method_spec) {|call| ... } ⇒ Peeek::Hook

Create a hook to method of an object. The hook can apply to a instance method or a singleton method.

Examples:

Hook to an instance method

Peeek::Hook.create(IO, '#puts')
  # => #<Peeek::Hook IO#puts>

# Hook implicitly to the instance method if the object is a module or
# a class.
Peeek::Hook.create(IO, :puts)
  # => #<Peeek::Hook IO#puts>

# Can't hook to the instance method if the object is an instance of any
# class.
Peeek::Hook.create($stdout, '#puts')
  # => raise #<ArgumentError: can't create a hook of instance method to an instance of any class>

Hook to an singleton method

Peeek::Hook.create($stdout, '.puts')
  # => #<Peeek::Hook #<IO:<STDOUT>>.puts>

# hook implicitly to the singleton method if the object is an instance
# of any class.
Peeek::Hook.create($stdout, :puts)
  # => #<Peeek::Hook #<IO:<STDOUT>>.puts>

Parameters:

  • object (Module, Class, Object)

    a target object that hook

  • method_spec (String, Symbol)

    method specifier of the object

Yields:

  • (call)

    process a call to the method. give optionally

Yield Parameters:

Returns:



40
41
42
43
44
# File 'lib/peeek/hook.rb', line 40

def self.create(object, method_spec, &process)
  linker_class, method_name = parse(method_spec)
  linker_class = any_module?(object) ? Instance : Singleton unless linker_class
  new(object, method_name, linker_class, &process)
end

Instance Method Details

#defined?Boolean

Determine if the method is defined in the object

Returns:

  • (Boolean)

    whether the method is defined in the object



108
109
110
# File 'lib/peeek/hook.rb', line 108

def defined?
  @linker.defined?
end

#inspectObject



143
144
145
146
147
148
# File 'lib/peeek/hook.rb', line 143

def inspect
  state = []
  state << 'linked' if linked?
  state_string = state.empty? ? '' : " (#{state * ', '})"
  "#<#{self.class} #{self}#{state_string}>"
end

#instance?Boolean

Determine if the hook to an instance method.

Returns:

  • (Boolean)

    whether the hook to an instance method



94
95
96
# File 'lib/peeek/hook.rb', line 94

def instance?
  @linker.is_a?(Instance)
end

Link the hook to the method.



120
121
122
123
124
125
126
127
# File 'lib/peeek/hook.rb', line 120

def link
  unless linked?
    @original_method = @linker.target_method
    @linker.link(&method(:call))
  end

  self
end

#linked?Boolean

Determine if the hook is linked to the method

Returns:

  • (Boolean)

    whether the hook is linked to the method



115
116
117
# File 'lib/peeek/hook.rb', line 115

def linked?
  instance_variable_defined?(:@original_method)
end

#singleton?Boolean

Determine if the hook to a singleton method.

Returns:

  • (Boolean)

    whether the hook to a singleton method



101
102
103
# File 'lib/peeek/hook.rb', line 101

def singleton?
  @linker.is_a?(Singleton)
end

#to_sObject



139
140
141
# File 'lib/peeek/hook.rb', line 139

def to_s
  @object.inspect + @linker.method_prefix + @method_name.to_s
end

Unlink the hook from the method.



130
131
132
133
134
135
136
137
# File 'lib/peeek/hook.rb', line 130

def unlink
  if linked?
    @linker.unlink(@original_method)
    remove_instance_variable(:@original_method)
  end

  self
end