Skip to content

eventide-project/record-invocation

Repository files navigation

record_invocation

Record method invocations, query the invocations, and use predicates to verify a method's invocation

Example

class SomeClass
  include RecordInvocation

  def some_method(some_parameter)
    record_invocation(binding)
  end

  record def some_recorded_method(some_parameter)
    :some_result
  end
end

recorder = SomeClass.new

recorder.some_method('some argument')

recorder.invoked?(:some_method)
# => true

recorder.invocation(:some_method)
# => <Invocation:0x.. 
 @method_name=:some_method, 
 @parameters={:some_parameter=>"some argument"}>

# Recorded method

recorder.some_recorded_method('some other argument')
# => :some_result

recorder.invoked?(:some_recorded_method)
# => true

recorder.invocation(:some_recorded_method)
# => <Invocation:0x..
 @method_name=:some_recorded_method,
 @parameters={:some_parameter=>"some other argument"}>

Recording Invocations of an Object

In order to enable method invocations recording capabilities for an object, the RecordInvocation module needs to be included in the object's class.

class SomeClass
  include RecordInvocation
end

The record_invocation Method

Invocations can be recorded by passing the current binding to the record_invocation method.

class SomeClass
  include RecordInvocation

  def some_method(some_parameter, some_other_parameter)
    record_invocation(binding)
  end
end

recorder = SomeClass.new

recorder.some_method('some argument', 'some other argument')

recorder.invocation(:some_method)
# => #<Invocation:0x...
 @method_name=:some_method,
 @parameters={:some_parameter=>"some argument", :some_other_parameter=>"some other argument"}>

The record Macro

The record macro allows any method to be recorded. The method's implementation doesn't have to be specialized in any way, and the method's natural behavior and return value are unchanged.

class SomeClass
  include RecordInvocation

  record def some_recorded_method(some_parameter)
    :some_result
  end
end

recorder = SomeClass.new

recorder.some_recorded_method('some other argument')
# => :some_result

recorder.invoked?(:some_recorded_method)
# => true

recorder.invocation(:some_recorded_method)
# => <Invocation:0x..
 @method_name=:some_recorded_method,
 @parameters={:some_parameter=>"some other argument"}>

## Querying Invocations

An invocation can be retrieved based on its method name and parameter values.

### By Method Name

``` ruby
recorder.some_method('some argument', 'some other argument')

recorder.invocation(:some_method)
# => #<Invocation:0x...
 @method_name=:some_method,
 @parameters={:some_parameter=>"some argument", :some_other_parameter=>"some other argument"}>

### By Method Name and Parameter Values

recorder.invocation(:some_method, some_parameter: 'some argument')
# => #<Invocation:0x...
 @method_name=:some_method,
 @parameters={:some_parameter=>"some argument", :some_other_parameter=>"some other argument"}>

recorder.invocation(:some_method, some_other_parameter: 'some other argument')
# => #<Invocation:0x...
 @method_name=:some_method,
 @parameters={:some_parameter=>"some argument", :some_other_parameter=>"some other argument"}>

recorder.invocation(:some_method, some_parameter: 'some argument', some_other_parameter: 'some other argument')
# => #<Invocation:0x...
 @method_name=:some_method,
 @parameters={:some_parameter=>"some argument", :some_other_parameter=>"some other argument"}>

Assuring Exactly One Invocation

If more than one invocation is found, only the first invocation will be returned using the invocation method.

If a method should have only been invoked once, the one_invocation method will raise an error rather than return the first invocation in cases where the method was invoked more than once.

recorder.some_method('some argument', 'some other argument')
recorder.some_method('some argument', 'yet another argument')

recorder.one_invocation(:some_method)
# => More than one invocation record matches (Method Name: :some_method, Parameters: {}) (RecordInvocation::Error)

recorder.one_invocation(:some_method, some_parameter: 'some argument')
# => More than one invocation record matches (Method Name: :some_method, Parameters: {:some_parameter=>"some argument"}) (RecordInvocation::Error)

If only one invocation of the method was recorded, then that invocation will be returned, just as it does with the invocation method.

recorder.some_method('some argument', 'some other argument')

recorder.one_invocation(:some_method, some_parameter: 'some argument')
# => #<Invocation:0x...
 @method_name=:some_method,
 @parameters={:some_parameter=>"some argument", :some_other_parameter=>"some other argument"}>

Retrieving More than One Invocation

If a method is invoked more than once, multiple invocation records can be retrieved.

recorder.some_method('some argument', 'some other argument')
recorder.some_method('another argument', 'yet another argument')

recorder.invocations(:some_method)
# => [#<Invocation:0x...
  @method_name=:some_method,
  @parameters={:some_parameter=>"some argument", :some_other_parameter=>"some other argument"}>,
 #<Invocation:0x...
  @method_name=:some_method,
  @parameters={:some_parameter=>"another argument", :some_other_parameter=>"yet another argument"}>]

recorder.invocations(:some_random_method)
# => []

recorder.invocations(:some_method, some_parameter: 'some argument')
# => [#<Invocation:0x...
  @method_name=:some_method,
  @parameters={:some_parameter=>"some argument", :some_other_parameter=>"some other argument"}>]

recorder.invocations(:some_method, some_other_parameter: 'some other argument')
# => [#<Invocation:0x...
  @method_name=:some_method,
  @parameters={:some_parameter=>"some argument", :some_other_parameter=>"some other argument"}>]

recorder.invocations(:some_method, some_parameter: 'some argument', some_other_parameter: 'some other argument')
# => [#<Invocation:0x...
  @method_name=:some_method,
  @parameters={:some_parameter=>"some argument", :some_other_parameter=>"some other argument"}>]

Detecting Invocations

RecordInvocation provides predicates for detecting whether an invocation has been made.

recorder.some_method('some argument', 'some other argument')

recorder.invoked?(:some_method)
# => true

recorder.invoked?(:some_random_method)
# => false

recorder.invoked?(:some_method, some_parameter: 'some argument')
# => true

recorder.invoked?(:some_method, some_other_parameter: 'some other argument')
# => true

recorder.invoked?(:some_method, some_parameter: 'some argument', some_other_parameter: 'some other argument')
# => true

Detecting Exactly One Invocation

If a method should have only been invoked once, the invoked_once? predicate will raise an error if more than one matching invocation is detected.

recorder.some_method('some argument', 'some other argument')
recorder.some_method('some argument', 'yet another argument')

recorder.invoked_once?(:some_method)
# => More than one invocation record matches (Method Name: :some_method, Parameters: {}) (RecordInvocation::Error)

recorder.invoked_once?(:some_method, some_parameter: 'some argument')
# => More than one invocation record matches (Method Name: :some_method, Parameters: {:some_parameter=>"some argument"}) (RecordInvocation::Error)

If only one invocation of the method was recorded, then the invoked? predicate will respond affirmatively.

recorder.some_method('some argument', 'some other argument')

recorder.invoked_once?(:some_method, some_parameter: 'some argument')
# => true

The methods of the recorder may conflict with the methods implemented on the RecordInvocation module. If so, a secondary set of method names may be used to access the diagnostic functions provided by RecordInvocation:

  • __invocation
  • __invocations
  • __invoked?
  • __invoked_once?
  • __record_invocation

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 4

  •  
  •  
  •  
  •