aquarium 0.4.1 → 0.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. data/Aquarium-IDEA.ipr +252 -0
  2. data/Aquarium-IDEA.iws +493 -0
  3. data/Aquarium.ipr +1 -1
  4. data/Aquarium.iws +133 -138
  5. data/CHANGES +63 -0
  6. data/ParseTreePlay.rb +25 -0
  7. data/README +55 -3
  8. data/RELEASE-PLAN +9 -1
  9. data/TODO.rb +175 -15
  10. data/examples/aspect_design_example.rb +13 -1
  11. data/examples/aspect_design_example_spec.rb +20 -2
  12. data/examples/introductions_example.rb +35 -0
  13. data/examples/introductions_example_spec.rb +37 -0
  14. data/examples/method_missing_example.rb +2 -1
  15. data/lib/aquarium/aspects/advice.rb +127 -74
  16. data/lib/aquarium/aspects/aspect.rb +139 -72
  17. data/lib/aquarium/aspects/default_objects_handler.rb +6 -4
  18. data/lib/aquarium/aspects/exclusion_handler.rb +15 -3
  19. data/lib/aquarium/aspects/join_point.rb +60 -55
  20. data/lib/aquarium/aspects/pointcut.rb +153 -124
  21. data/lib/aquarium/aspects/pointcut_composition.rb +1 -1
  22. data/lib/aquarium/dsl/aspect_dsl.rb +13 -5
  23. data/lib/aquarium/dsl/object_dsl.rb +4 -2
  24. data/lib/aquarium/extras/design_by_contract.rb +9 -5
  25. data/lib/aquarium/finders.rb +1 -0
  26. data/lib/aquarium/finders/finder_result.rb +13 -5
  27. data/lib/aquarium/finders/method_finder.rb +75 -70
  28. data/lib/aquarium/finders/pointcut_finder.rb +166 -0
  29. data/lib/aquarium/finders/type_finder.rb +104 -62
  30. data/lib/aquarium/utils/array_utils.rb +1 -1
  31. data/lib/aquarium/utils/invalid_options.rb +2 -0
  32. data/lib/aquarium/utils/name_utils.rb +3 -2
  33. data/lib/aquarium/utils/nil_object.rb +7 -3
  34. data/lib/aquarium/utils/options_utils.rb +38 -27
  35. data/lib/aquarium/utils/set_utils.rb +2 -2
  36. data/lib/aquarium/utils/type_utils.rb +11 -0
  37. data/lib/aquarium/version.rb +1 -1
  38. data/spec/aquarium/aspects/advice_spec.rb +147 -32
  39. data/spec/aquarium/aspects/aspect_invocation_spec.rb +252 -43
  40. data/spec/aquarium/aspects/aspect_spec.rb +148 -88
  41. data/spec/aquarium/aspects/aspect_with_nested_types_spec.rb +40 -34
  42. data/spec/aquarium/aspects/aspect_with_subtypes_spec.rb +39 -3
  43. data/spec/aquarium/aspects/join_point_spec.rb +190 -227
  44. data/spec/aquarium/aspects/pointcut_spec.rb +24 -1
  45. data/spec/aquarium/dsl/aspect_dsl_spec.rb +17 -17
  46. data/spec/aquarium/finders/method_finder_spec.rb +8 -2
  47. data/spec/aquarium/finders/pointcut_finder_spec.rb +193 -0
  48. data/spec/aquarium/finders/pointcut_finder_spec_test_classes.rb +90 -0
  49. data/spec/aquarium/finders/type_finder_spec.rb +17 -0
  50. data/spec/aquarium/finders/type_finder_with_descendents_and_ancestors_spec.rb +4 -4
  51. data/spec/aquarium/finders/type_finder_with_nested_types.rb +47 -0
  52. data/spec/aquarium/utils/nil_object_spec.rb +21 -0
  53. data/spec/aquarium/utils/type_utils_sample_nested_types.rb +51 -0
  54. data/spec/aquarium/utils/type_utils_spec.rb +18 -1
  55. metadata +13 -3
@@ -2,7 +2,7 @@ require 'aquarium/aspects/pointcut'
2
2
  require 'aquarium/utils/array_utils'
3
3
 
4
4
  # == Pointcut (composition)
5
- # Since Pointcuts are queries, they can be composed, _i.e.,_ unions and intersections of
5
+ # Since Pointcuts are queries, they can be composed, <i>i.e.,</i> unions and intersections of
6
6
  # them can be computed, yielding new Pointcuts.
7
7
  class Aquarium::Aspects::Pointcut
8
8
 
@@ -1,10 +1,6 @@
1
1
  require 'aquarium/aspects/aspect'
2
2
  require 'aquarium/utils/type_utils'
3
3
 
4
- # Convenience methods added to the current type to provide a low-level AOP DSL.
5
- # If you don't want these methods added to a type, then only require aspect.rb
6
- # and create instances of Aspect.
7
-
8
4
  module Aquarium
9
5
  module DSLMethods
10
6
 
@@ -54,6 +50,18 @@ module Aquarium
54
50
  end
55
51
  end
56
52
 
53
+ # Include this module to add convenience class-level methods to a type, which provide
54
+ # a low-level AOP DSL. For example, instead of writing
55
+ #
56
+ # Aspect.new :around, :calls_to => ...
57
+ #
58
+ # You can write the following instead.
59
+ #
60
+ # include Aspect::DSL
61
+ # ...
62
+ # around :calls_to => ...
63
+ # If you don't want these methods added to a type, then only require aspect.rb
64
+ # and create instances of Aspect, as in the first example.
57
65
  module DSL
58
66
  include Aquarium::DSLMethods
59
67
  # Add the methods as class, not instance, methods.
@@ -62,7 +70,7 @@ module Aquarium
62
70
  end
63
71
  end
64
72
 
65
- # Backwards compatibility with old name.
73
+ # Backwards compatibility with old name. (Deprecated)
66
74
  module Aspects
67
75
  module DSL
68
76
  module AspectDSL
@@ -1,7 +1,9 @@
1
1
  require 'aquarium/dsl/aspect_dsl'
2
2
 
3
- # Add aspect convenience methods to Object. Only require this
4
- # file if you really want these methods on all objects in your runtime!
3
+ # Add the Aquarium::DSL convenience methods to Object. Only require this
4
+ # file if you <i>really</i> want these methods on all objects in your runtime!
5
+ # For example, Rails already adds <tt>before</tt> and <tt>after</tt> methods
6
+ # to object, so including this file is not compatible!
5
7
  class Object
6
8
  include Aquarium::DSL
7
9
  end
@@ -1,12 +1,16 @@
1
- # A simple Design by Contract module. Adds advice to test that the contract, which is specified with
2
- # a block passes. Note that it doesn't attempt to handle the correct behavior under contract
3
- # inheritance.
4
- # Warning: This module automatically includes Aquarium::DSL into the class with
5
- # the contract and it adds the :precondition, :postcondition, and the :invariant methods to Object!
6
1
  require 'aquarium'
7
2
 
8
3
  module Aquarium
4
+ # == Extras
5
+ # These modules are <i>not</i> included automatically when you <tt>require 'aquarium'</tt>. You have to
6
+ # include them explicitly.
9
7
  module Extras
8
+ # A simple Design by Contract module. Adds advice to test that the contract, which is specified with
9
+ # a block passes. Note that it doesn't attempt to handle the correct behavior under contract
10
+ # inheritance. A usage example is included in the Examples as part of the distribution and it is also
11
+ # shown on the web site.
12
+ # *Warning*: This module automatically includes Aquarium::DSL into the class with
13
+ # the contract and it adds the :precondition, :postcondition, and the :invariant methods to Object!
10
14
  module DesignByContract
11
15
  include Aquarium::Aspects
12
16
 
@@ -1,3 +1,4 @@
1
1
  require 'aquarium/finders/finder_result'
2
2
  require 'aquarium/finders/type_finder'
3
3
  require 'aquarium/finders/method_finder'
4
+ require 'aquarium/finders/pointcut_finder'
@@ -3,6 +3,9 @@ require 'aquarium/extensions'
3
3
 
4
4
  module Aquarium
5
5
  module Finders
6
+ # == FinderResult
7
+ # Wraps hashes that hold the results of various *Finder utilities. The #not_matched method returns specified
8
+ # inputs that did not result in a successful find.
6
9
  class FinderResult
7
10
  include Aquarium::Utils::HashUtils
8
11
  include Aquarium::Utils::SetUtils
@@ -32,12 +35,12 @@ module Aquarium
32
35
 
33
36
  NIL_OBJECT = FinderResult.new unless const_defined?(:NIL_OBJECT)
34
37
 
35
- # Convenience method to get the keys for the matched.
38
+ # Convenience method to get the keys for the matches.
36
39
  def matched_keys
37
40
  @matched.keys
38
41
  end
39
42
 
40
- # Convenience method to get the keys for the items that did not match.
43
+ # Convenience method to get the keys for the items that did not result in matches.
41
44
  def not_matched_keys
42
45
  @not_matched.keys
43
46
  end
@@ -49,8 +52,12 @@ module Aquarium
49
52
  end
50
53
 
51
54
  # "Or" two results together
55
+ #--
56
+ # We use dup here and in other methods, rather than FinderResult.new, so that new subclass
57
+ # objects are returned correctly!
58
+ #++
52
59
  def or other_result
53
- result = FinderResult.new
60
+ result = dup
54
61
  result.matched = hash_union(matched, other_result.matched)
55
62
  result.not_matched = hash_union(not_matched, other_result.not_matched)
56
63
  result
@@ -61,7 +68,7 @@ module Aquarium
61
68
 
62
69
  # "And" two results together
63
70
  def and other_result
64
- result = FinderResult.new
71
+ result = dup
65
72
  result.matched = hash_intersection(matched, other_result.matched)
66
73
  result.not_matched = hash_intersection(not_matched, other_result.not_matched)
67
74
  result
@@ -71,7 +78,7 @@ module Aquarium
71
78
  alias :& :and
72
79
 
73
80
  def minus other_result
74
- result = FinderResult.new
81
+ result = dup
75
82
  result.matched = matched - other_result.matched
76
83
  result.not_matched = not_matched - other_result.not_matched
77
84
  result
@@ -101,6 +108,7 @@ module Aquarium
101
108
 
102
109
  alias :to_s :inspect
103
110
 
111
+ # Were there no matches?
104
112
  def empty?
105
113
  matched.empty?
106
114
  end
@@ -9,91 +9,92 @@ require File.dirname(__FILE__) + '/finder_result'
9
9
  # Find methods and types and objects.
10
10
  module Aquarium
11
11
  module Finders
12
+ # == MethodFinder
13
+ # Locate methods in specified types or objects.
12
14
  class MethodFinder
13
15
  include Aquarium::Utils::ArrayUtils
14
16
  include Aquarium::Utils::OptionsUtils
15
17
 
16
- # Returns a Aquarium::Finders::FinderResult for the hash of types, type names, and/or regular expressions
17
- # and the corresponding method name <b>symbols</b> found.
18
+ # Returns a Aquarium::Finders::FinderResult, where the "matched" keys are the input
19
+ # types, type names, and/or regular expressions, and objects for which matches were found and the
20
+ # corresponding values are the method name <i>symbols</i> that were found.
18
21
  # Method names, not method objects, are always returned, because we can only get
19
22
  # method objects for instance methods if we have an instance!
23
+ # The keys in the "not_matched" part of the FinderResult are the specified types and objects
24
+ # for which no matches were found.
20
25
  #
21
- # finder_result = MethodFinder.new.find :types => ... {, :methods => ..., :method_options => [...]}
22
- # where
23
- # "{}" indicate optional arguments
26
+ # The options are as follows:
27
+ # ==== Types
28
+ # All the options supported by TypeFinder#find.
24
29
  #
25
- # <tt>:types => types_and_type_names_and_regexps</tt>::
26
- # <tt>:type => types_and_type_names_and_regexps</tt>::
27
- # <tt>:for_types => types_and_type_names_and_regexps</tt>::
28
- # <tt>:for_type => types_and_type_names_and_regexps</tt>::
29
- # <tt>:on_types => types_and_type_names_and_regexps</tt>::
30
- # <tt>:on_type => types_and_type_names_and_regexps</tt>::
31
- # <tt>:in_types => types_and_type_names_and_regexps</tt>::
32
- # <tt>:in_type => types_and_type_names_and_regexps</tt>::
33
- # <tt>:within_types => types_and_type_names_and_regexps</tt>::
34
- # <tt>:within_type => types_and_type_names_and_regexps</tt>::
35
- # One or more types, type names and/or regular expessions to match.
36
- # Specify one or an array of values.
30
+ # ==== Objects
31
+ # One or more objects to match.
32
+ # Specify one or an array of values.
33
+ # *Note*: String or symbol objects will be treated as type names!
34
+ # * <tt>:objects => objects</tt>
35
+ # * <tt>:object => objects</tt>
36
+ # * <tt>:for_objects => objects</tt>
37
+ # * <tt>:for_object => objects</tt>
38
+ # * <tt>:on_objects => objects</tt>
39
+ # * <tt>:on_object => objects</tt>
40
+ # * <tt>:in_objects => objects</tt>
41
+ # * <tt>:in_object => objects</tt>
42
+ # * <tt>:within_objects => objects</tt>
43
+ # * <tt>:within_object => objects</tt>
37
44
  #
38
- # <tt>:objects => objects</tt>::
39
- # <tt>:object => objects</tt>::
40
- # <tt>:for_objects => objects</tt>::
41
- # <tt>:for_object => objects</tt>::
42
- # <tt>:on_objects => objects</tt>::
43
- # <tt>:on_object => objects</tt>::
44
- # <tt>:in_objects => objects</tt>::
45
- # <tt>:in_object => objects</tt>::
46
- # <tt>:within_objects => objects</tt>::
47
- # <tt>:within_object => objects</tt>::
48
- # One or more objects to match.
49
- # Specify one or an array of values.
50
- # Note: Currently, string or symbol objects will be misinterpreted as type names!
45
+ # ==== Methods
46
+ # One or more method names and/or regular expressions to match.
47
+ # Specify one or an array of values. If <tt>:all</tt> or <tt>:all_methods</tt>
48
+ # is specified, all methods in the types or objects will be matched, subject
49
+ # to the search options described below. That is, <tt>:all</tt> is equivalent
50
+ # to the regular expression /.+/.
51
+ # * <tt>:methods => method_names_and_regexps</tt>
52
+ # * <tt>:method => method_names_and_regexps</tt>
53
+ # * <tt>:within_methods => method_names_and_regexps</tt>
54
+ # * <tt>:within_method => method_names_and_regexps</tt>
55
+ # * <tt>:calling => method_names_and_regexps</tt>
56
+ # * <tt>:invoking => method_names_and_regexps</tt>
57
+ # * <tt>:calls_to => method_names_and_regexps</tt>
58
+ # * <tt>:sending_message_to => method_names_and_regexps</tt>
59
+ # * <tt>:sending_messages_to => method_names_and_regexps</tt>
51
60
  #
52
- # <tt>:methods => method_names_and_regexps</tt>::
53
- # <tt>:method => method_names_and_regexps</tt>::
54
- # <tt>:within_methods => method_names_and_regexps</tt>::
55
- # <tt>:within_method => method_names_and_regexps</tt>::
56
- # <tt>:calling => method_names_and_regexps</tt>::
57
- # <tt>:invoking => method_names_and_regexps</tt>::
58
- # <tt>:calls_to => method_names_and_regexps</tt>::
59
- # <tt>:sending_message_to => method_names_and_regexps</tt>::
60
- # <tt>:sending_messages_to => method_names_and_regexps</tt>::
61
- # One or more method names and regular expressions to match.
62
- # Specify one or an array of values. If :all or :all_methods is specified, all
63
- # methods will be matched. That is, these special values are equivalent to the
64
- # the regular expression /.+/.
65
- #
66
- # <tt>:exclude_methods => method_names_and_regexps</tt>::
67
- # <tt>:exclude_method => method_names_and_regexps</tt>::
68
- # <tt>:exclude_&lt;other_method_synonyms&gt; => method_names_and_regexps</tt>::
69
- # One or more method names and regular expressions to exclude from the match.
70
- # Specify one or an array of values.
71
- #
72
- # <tt>:method_options => options</tt>::
73
- # <tt>:method_option => options</tt>::
74
- # <tt>:options => options</tt>::
75
- # <tt>:restricting_methods_to => options</tt>::
76
- # By default, searches for public instance methods. Specify one or more
77
- # of the following options for alternatives. You can combine any of the
78
- # <tt>:public</tt>, <tt>:protected</tt>, and <tt>:private</tt>, as well as
79
- # <tt>:instance</tt> and <tt>:class</tt>.
61
+ # ==== Methods Options
62
+ # By default, the searches are restricted to public instance methods.
63
+ # * <tt>:method_options => options</tt>
64
+ # * <tt>:method_option => options</tt>
65
+ # * <tt>:options => options</tt>
66
+ # * <tt>:restricting_methods_to => options</tt>
80
67
  #
81
- # <tt>:public</tt> or <tt>:public_methods</tt>:: Search for public methods (default).
82
- # <tt>:private</tt> or <tt>:private_methods</tt>:: Search for private methods.
68
+ # Note, the <tt>:options</tt> synonym is deprecated.
69
+ #
70
+ # Here are the allowed "options". Specify one or more of them. Any combination is allowed.
71
+ # <tt>:public</tt> or <tt>:public_methods</tt>:: Search for public methods (default).
72
+ # <tt>:private</tt> or <tt>:private_methods</tt>:: Search for private methods.
83
73
  # <tt>:protected</tt> or <tt>:protected_methods</tt>:: Search for protected methods.
84
- # <tt>:instance</tt> or <tt>:instance_methods</tt>:: Search for instance methods.
85
- # <tt>:class</tt> or <tt>:class_methods</tt>:: Search for class methods.
86
- # <tt>:singleton</tt> or <tt>:singleton_methods</tt>:: Search for singleton methods. (Using :class for objects
87
- # won't work and :class, :public, :protected, and :private are ignored when
88
- # looking for singleton methods.)
89
- # <tt>:exclude_ancestor_methods</tt>:: Suppress "ancestor" methods. This
90
- # means that if you search for a override method +foo+ in a
91
- # +Derived+ class that is defined in the +Base+ class, you won't find it!
74
+ # <tt>:instance</tt> or <tt>:instance_methods</tt>:: Search for instance methods.
75
+ # <tt>:class</tt> or <tt>:class_methods</tt>:: Search for class methods.
76
+ # <tt>:singleton</tt> or <tt>:singleton_methods</tt>:: Search for singleton methods.
77
+ #
78
+ # Note: specifying <tt>:class</tt> when objects are specified won't work.
79
+ # Also, <tt>:class</tt>, <tt>:public</tt>, <tt>:protected</tt>, and <tt>:private</tt>
80
+ # are ignored when looking for singleton methods.
81
+ #
82
+ # ==== Excluded Types, Objects, or Methods
83
+ # Exclude one or more types, objects, or methods from the match.
84
+ # Specify one or an array of values.
85
+ # * <tt>:exclude_methods => method_names_and_regexps</tt>
86
+ # * <tt>:exclude_method => method_names_and_regexps</tt>
87
+ # * <tt>:exclude_ancestor_methods</tt> - Suppress "ancestor" methods.
88
+ # The <tt>exclude_</tt> prefix can be used with any of the synonyms for the other options.
89
+ # *WARNING*: the <tt>:exclude_ancestor_methods</tt> option means that
90
+ # if you search for a override method +foo+ in a derived class and +foo+ is
91
+ # defined in the base class, you won't find it!
92
92
  #
93
93
  def find options = {}
94
94
  init_specification options, CANONICAL_OPTIONS do
95
95
  finish_specification_initialization
96
96
  end
97
+ warn_if_deprecated_options_used options
97
98
  return Aquarium::Finders::FinderResult.new if nothing_to_find?
98
99
  types_and_objects = input_types + input_objects
99
100
  method_names_or_regexps = input_methods
@@ -111,7 +112,6 @@ module Aquarium
111
112
 
112
113
  NIL_OBJECT = MethodFinder.new unless const_defined?(:NIL_OBJECT)
113
114
 
114
- # TODO remove (or deprecate) the "options" option!
115
115
  METHOD_FINDER_CANONICAL_OPTIONS = {
116
116
  "objects" => %w[object for_object for_objects on_object on_objects in_object in_objects within_object within_objects],
117
117
  "methods" => %w[method within_method within_methods calling invoking invocations_of calls_to sending_message_to sending_messages_to],
@@ -171,7 +171,12 @@ module Aquarium
171
171
  all_recognized_method_option_symbols.include? sym
172
172
  end
173
173
 
174
- protected
174
+ private
175
+
176
+ def warn_if_deprecated_options_used options
177
+ return unless options[:options]
178
+ logger.warn "The :options => ... option is now deprecated. Please use :method_options instead."
179
+ end
175
180
 
176
181
  def do_find_all_by types_and_objects, method_names_or_regexps
177
182
  types_and_objects = make_array types_and_objects
@@ -0,0 +1,166 @@
1
+ require 'aquarium/utils'
2
+ require 'aquarium/finders/finder_result'
3
+
4
+ # Finds pointcuts by name, either class variables, class constants or both.
5
+ module Aquarium
6
+ module Finders
7
+ # == PointcutFinder
8
+ # Locate named pointcuts in specified types or objects.
9
+ class PointcutFinder
10
+ include Aquarium::Utils::OptionsUtils
11
+
12
+ POINTCUT_FINDER_CANONICAL_OPTIONS = {}
13
+ ['', 'constants_', 'class_variables_'].each do |prefix|
14
+ POINTCUT_FINDER_CANONICAL_OPTIONS["#{prefix}matching"] = ["#{prefix}with_names_matching", "#{prefix}named"]
15
+ end
16
+
17
+ CANONICAL_OPTIONS = Aquarium::Finders::TypeFinder::CANONICAL_OPTIONS.merge(POINTCUT_FINDER_CANONICAL_OPTIONS)
18
+ canonical_options_given_methods CANONICAL_OPTIONS
19
+ canonical_option_accessor CANONICAL_OPTIONS
20
+
21
+ # Returns a Aquarium::Finders::FinderResult, where the "matched" keys are the input
22
+ # types, type names, and/or regular expressions, and objects for which matches were found and the
23
+ # corresponding values are the class constant or variable pointcuts that were found.
24
+ # The keys in the "not_matched" part of the FinderResult are the specified types and objects
25
+ # for which no matches were found.
26
+ #
27
+ # The options are as follows:
28
+ # ==== Types
29
+ # All the options supported by TypeFinder#find.
30
+ #
31
+ # ==== Pointcut Names
32
+ # A name, regular expression or an array of the same. (Mixed allowed.) In the types searched, the
33
+ # names will be matched against class constants <i>and</i> class variable pointcut definitions.
34
+ # * <tt>:matching => a variable/constant name, regular expression, or array of the same</tt>
35
+ # * <tt>:with_names_matching => same</tt>
36
+ # * <tt>:named => same</tt>
37
+ #
38
+ # A name, regular expression or an array of the same that will be matched against pointcuts that
39
+ # are class constants <i>only</i>.
40
+ # * <tt>:constants_matching => a variable/constant name, regular expression, or array of the same</tt>
41
+ # * <tt>:constants_with_names_matching => same</tt>
42
+ # * <tt>:constants_named => same</tt>
43
+ #
44
+ # A name, regular expression or an array of the same that will be matched against pointcuts that
45
+ # are class variables <i>only</i>.
46
+ # * <tt>:class_variables_matching => a variable/constant name, regular expression, or array of the same</tt>
47
+ # * <tt>:class_variables_with_names_matching => same</tt>
48
+ # * <tt>:class_variables_named => same</tt>
49
+ #
50
+ def find options = {}
51
+ init_specification options, CANONICAL_OPTIONS do
52
+ finish_specification_initialization
53
+ end
54
+ result = do_find_pointcuts unless noop
55
+ unset_specification
56
+ result
57
+ end
58
+
59
+ class PoincutFinderResult < Aquarium::Finders::FinderResult
60
+ # Return an array with the found pointcuts.
61
+ def found_pointcuts
62
+ matched.values.inject([]) {|pcs, set| pcs += set.to_a; pcs}
63
+ end
64
+ end
65
+
66
+ private
67
+
68
+ POINTCUT_FINDER_CANONICAL_OPTIONS_KEYS_AS_SYMBOLS = POINTCUT_FINDER_CANONICAL_OPTIONS.keys.map {|k| k.intern}
69
+
70
+ def finish_specification_initialization
71
+ raise Aquarium::Utils::InvalidOptions.new("No options specified") unless any_types_given?
72
+ end
73
+
74
+ # Hack. Since the finder could be reused, unset the specification created by #find.
75
+ def unset_specification
76
+ @specification = {}
77
+ end
78
+
79
+ def do_find_pointcuts
80
+ types_search_result = Aquarium::Finders::TypeFinder.new.find specification_without_pointcut_names
81
+ return types_search_result if types_search_result.matched.empty?
82
+ types = types_search_result.matched.keys
83
+ pointcuts = PoincutFinderResult.new
84
+ unless any_names_given?
85
+ pointcuts << find_constant_pointcuts(types)
86
+ pointcuts << find_class_variable_pointcuts(types)
87
+ return pointcuts
88
+ end
89
+ names = matching_given
90
+ unless names.empty?
91
+ pointcuts << find_constant_pointcuts(types, names)
92
+ pointcuts << find_class_variable_pointcuts(types, names)
93
+ end
94
+ names = constants_matching_given
95
+ unless names.empty?
96
+ pointcuts << find_constant_pointcuts(types, names)
97
+ end
98
+ names = class_variables_matching_given
99
+ unless names.empty?
100
+ pointcuts << find_class_variable_pointcuts(types, names)
101
+ end
102
+ pointcuts
103
+ end
104
+
105
+ def find_constant_pointcuts types, names = :all
106
+ pointcuts = PoincutFinderResult.new
107
+ types.each do |t|
108
+ candidates = t.constants.select {|c| matches_name(c, names)}
109
+ candidates.each do |c|
110
+ if t.const_defined? c
111
+ con = t.const_get c
112
+ pointcuts.append_matched({t => con}) if con.kind_of?(Aquarium::Aspects::Pointcut)
113
+ end
114
+ end
115
+ end
116
+ pointcuts
117
+ end
118
+
119
+ def find_class_variable_pointcuts types, names = :all
120
+ pointcuts = PoincutFinderResult.new
121
+ types.each do |t|
122
+ candidates = t.class_variables.select {|c| matches_name(c, to_class_variable_name(names))}
123
+ candidates.each do |c|
124
+ con = t.send :class_variable_get, c
125
+ pointcuts.append_matched({t => con}) if con.kind_of?(Aquarium::Aspects::Pointcut)
126
+ end
127
+ end
128
+ pointcuts
129
+ end
130
+
131
+ def matches_name candidate, names
132
+ return true if names == :all
133
+ if names.kind_of? Regexp
134
+ names.match candidate
135
+ elsif names.kind_of?(String) or names.kind_of?(Symbol)
136
+ names.to_s.eql? candidate
137
+ else
138
+ names.inject(false) {|matches, name| matches = true if matches_name(candidate, name); matches}
139
+ end
140
+ end
141
+
142
+ def to_class_variable_name names
143
+ return names if names == :all
144
+ if names.kind_of? Regexp
145
+ names # no change
146
+ elsif names.kind_of?(String) or names.kind_of?(Symbol)
147
+ names.to_s =~ /^@@/ ? names.to_s : "@@#{names}"
148
+ else
149
+ names.inject([]) {|result, name| result << to_class_variable_name(name); result}
150
+ end
151
+ end
152
+
153
+ def any_types_given?
154
+ types_given? or types_and_descendents_given? or types_and_ancestors_given?
155
+ end
156
+
157
+ def any_names_given?
158
+ matching_given? or constants_matching_given? or class_variables_matching_given?
159
+ end
160
+
161
+ def specification_without_pointcut_names
162
+ @specification.reject {|key,v| POINTCUT_FINDER_CANONICAL_OPTIONS_KEYS_AS_SYMBOLS.include?(key)}
163
+ end
164
+ end
165
+ end
166
+ end