Class: Aspekt::Pointcut

Inherits:
Object
  • Object
show all
Defined in:
lib/aspekt/pointcut.rb

Overview

Instance Method Summary collapse

Methods inherited from Object

all

Constructor Details

#initialize(*matchers) ⇒ Pointcut

Constructor takes for arguments Hash with keys class(es) or object(s) and method(s), or Array of Hash-es.

Example

Pointcut for object method

pointcut = Aspekt::Pointcut.new(type: :String, method: :to_s)
pointcut = Aspekt::Pointcut.new(type: /String/, method: /to_s/)
pointcut = Aspekt::Pointcut.new(type: String, method: 'to_s')

Pointcut for class method (singleton method)

pointcut = Aspekt::Pointcut.new(instance: String, method: :new)
pointcut = Aspekt::Pointcut.new(type: (class String; class<<self; self; end; end, method: :new)
pointcut = Aspekt::Pointcut.new(instance: some_object, method: /some_singleton_method/)

Pointcut with more than a one matcher

pointcut = Aspekt::Pointcut.new(
                                {type: String, method: :capitalize},
                                {types: [String, Array], methods: [/a/, /o/]},
                                {instances: [String, /Arr/], method: /new|try/}
                                )

Reasoning behind :type and :instance

Parameters:

  • Array ({:type => Class|::Object|String|Symbol|Regexp, :instance => ::Object})

Raises:

  • (ArgumentError)


41
42
43
44
45
# File 'lib/aspekt/pointcut.rb', line 41

def initialize *matchers
  raise ArgumentError, "must have matchers" if matchers.length == 0 

  matchers.each { |matcher| add_matcher matcher }
end

Instance Method Details

#has_matchers_for?(opts) ⇒ Boolean

Argument Hash with keys :class or :object and :method for checking if Pointcut is matching with a object or a class.

Example

pointcut = Aspekt::Pointcut.new(class: :SomeClass, method: :some_method).has_matchers_for?(class: SomeClass, method: :some_method)
pointcut = Aspekt::Pointcut.new(object: :SomeClass, method: :some_method).has_matchers_for?(object: SomeClass, method: :some_method)

Parameters:

  • Array ({:type => Class|::Object|Symbol|Regexp, :instance => ::Object, :method => Symbol})

Returns:

  • (Boolean)

Raises:

  • (ArgumentError)


93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
# File 'lib/aspekt/pointcut.rb', line 93

def has_matchers_for? opts
  raise ArgumentError, "has to include keys 'instance' or 'type', may include 'method'." unless opts[:instance] or opts[:type]

  # matcher_branch - from where to search matcher, thing - class or object
  matcher_branch, thing = case 
  when opts[:instance]; [self[:instances], opts[:instance]];
  when opts[:type];     [self[:types], opts[:type]];
  end
    
  matchers_for_thing = matcher_branch.keys.including_same thing
  
  unless matchers_for_thing.length == 0
    return true unless opts[:method]  # we have no method matching and object is matching
    matcher_objects_methods = matcher_branch.values_at(*matchers_for_thing).flatten
    return true if matcher_objects_methods.include_same?(opts[:method]) # one of the matching object has matching method
  end

  return false # opts[:object] existed but no matcher was found
end

#matchingObject

Finds currently existing all Objects for this Pointcut. Returns Object and its method matchers.

Example

pointcut = Pointcut.new(types: [/Strin/, /^Hash$/, :ThisClassDoesNotExist)], instance: Array, methods: [/to/, :send])
pointcut_matching_types     = pointcut.matching[:types]       # will be: {String: [/to/, :send], Hash: [/to/, :send]}
pointcut_matching_instances = pointcut.matching[:instances]   # will be: {Array: [/to/, :send]}

# if now ThisClassDoesNotExist will be defined and #matching is called again, then it will also contain it.


124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
# File 'lib/aspekt/pointcut.rb', line 124

def matching
  matching = {}

  defined_classes = nil # this will be created for Regexp object matcher, if needed

  self.each do |type, object_matchers|
    matching[type] = {}

    object_matchers.each do |object_matcher, methods|
      case object_matcher
      when Symbol
        begin
          matching_class = object_matcher.to_s.split(/::/).inject(Object) {|a, b| a.const_get(b) } # throws NameError if does not exist
          matching[type][matching_class] = methods
        rescue NameError
        end
      when Regexp
        defined_classes ||= ObjectSpace.each_object(Class).to_a # do it when need it
        defined_classes.select {|defined_class| matching[type][defined_class] = methods if object_matcher.match(defined_class.name) }
      else
        matching[type][object_matcher] = methods
      end
    end

  end

  return matching
end