Pointcuts are queries on JoinPoints combined with binding of context data to that will be useful during advice execution. The Pointcut locates the join points that match the input criteria, remembering the found join points as well as the the criteria that yielded no matches (mostly useful for debugging Pointcut definitions)
Since Pointcuts are queries, they can be composed, i.e., unions and intersections of them can be computed, yielding new Pointcuts.
# File lib/aquarium/aspects/pointcut.rb, line 250 def self.make_attribute_reading_writing_options options_hash result = {} [:writing, :changing, :reading].each do |attr_key| next if options_hash[attr_key].nil? or options_hash[attr_key].to_s.empty? result[:attributes] ||= Set.new([]) result[:attribute_options] ||= Set.new([]) result[:attributes].merge(Aquarium::Utils::ArrayUtils.make_array(options_hash[attr_key])) attr_opt = attr_key == :reading ? :readers : :writers result[:attribute_options] << attr_opt end result end
Construct a Pointcut for methods in types or objects.
Pointcut.new :join_points => [...] | :type{s} => [...] | :object{s} => [...] {, :method{s} => [], :method_options => [...], :attribute{s} => [...], :attribute_options[...]}
where the “{}” indicate optional elements. Most of the arguments have many synonyms, shown below, to promote an English-like DSL.
The options include the following.
Specify one or an array of join_points.
:join_points => join_point || [join_point_list]
:join_point => join_point || [join_point_list]
:for_join_points => join_point || [join_point_list]
:for_join_point => join_point || [join_point_list]
:on_join_points => join_point || [join_point_list]
:on_join_point => join_point || [join_point_list]
:within_join_points => join_point || [join_point_list]
:within_join_point => join_point || [join_point_list]
Specify a type, type name, type name regular expression or an array of the same. (Mixed is allowed.)
:types => type || [type_list]
:type => type || [type_list]
:for_types => type || [type_list]
:for_type => type || [type_list]
:on_types => type || [type_list]
:on_type => type || [type_list]
:within_types => type || [type_list]
:within_type => type || [type_list]
Specify a type, type name, type name regular expression or an array of the same. (Mixed is allowed.) The ancestors or descendents will also be found. To find both ancestors and descendents, use both options.
:types_and_descendents => type || [type_list]
:type_and_descendents => type || [type_list]
:types_and_ancestors => type || [type_list]
:type_and_ancestors => type || [type_list]
:for_types_and_ancestors => type || [type_list]
:for_type_and_ancestors => type || [type_list]
:on_types_and_descendents => type || [type_list]
:on_type_and_descendents => type || [type_list]
:on_types_and_ancestors => type || [type_list]
:on_type_and_ancestors => type || [type_list]
:within_types_and_descendents => type || [type_list]
:within_type_and_descendents => type || [type_list]
:within_types_and_ancestors => type || [type_list]
:within_type_and_ancestors => type || [type_list]
Specify a type, type name, type name regular expression or an array of the same. (Mixed is allowed.) The nested (enclosed) types will also be found.
:types_and_nested_types => type || [type_list]
:type_and_nested_types => type || [type_list]
:types_and_nested => type || [type_list]
:type_and_nested => type || [type_list]
:for_types_and_nested_types => type || [type_list]
:for_type_and_nested_types => type || [type_list]
:for_types_and_nested => type || [type_list]
:for_type_and_nested => type || [type_list]
:on_types_and_nested_types => type || [type_list]
:on_type_and_nested_types => type || [type_list]
:on_types_and_nested => type || [type_list]
:on_type_and_nested => type || [type_list]
:within_types_and_nested_types => type || [type_list]
:within_type_and_nested_types => type || [type_list]
:within_types_and_nested => type || [type_list]
:within_type_and_nested => type || [type_list]
:objects => object || [object_list]
:object => object || [object_list]
:for_objects => object || [object_list]
:for_object => object || [object_list]
:on_objects => object || [object_list]
:on_object => object || [object_list]
:within_objects => object || [object_list]
:within_object => object || [object_list]
An “internal” flag used by Aspect::DSL#pointcut. When no object or type
is specified explicitly, the value of :default_objects will be used, if
defined. Aspect::DSL#pointcut sets the value to self
, so the
user doesn’t have to specify a type or object in the contexts where that
would be useful, e.g., pointcuts defined within a type for join
points within itself. WARNING: This flag is subject to
change, so don’t use it explicitly!
:default_objects => object || [object_list]
:default_object => object || [object_list]
A method name, name regular expession or an array of the same. By default,
if neither :methods
nor :attributes
are
specified, all public instance methods will be found, with the method
option :exclude_ancestor_methods
implied, unless explicit
method options are given.
:methods => method || [method_list]
:method => method || [method_list]
:within_methods => method || [method_list]
:within_method => method || [method_list]
:calling => method || [method_list]
:calls_to => method || [method_list]
:invoking => method || [method_list]
:invocations_of => method || [method_list]
:sending_message_to => method || [method_list]
One or more options supported by Aquarium::Finders::MethodFinder.
The :exclude_ancestor_methods
option is most useful.
:method_options => [options]
An attribute name, regular expession or array of the same. WARNING This is syntactic sugar for the corresponding attribute readers and/or writers methods. The actual attribute accesses are not advised, which can lead to unexpected behavior. A goal before V1.0 is to support actual attribute accesses, if possible.
:attributes => attribute || [attribute_list]
:attribute => attribute || [attribute_list]
:reading => attribute || [attribute_list]
:writing => attribute || [attribute_list]
:changing => attribute || [attribute_list]
:accessing => attribute || [attribute_list]
If :reading
is specified, just attribute readers are matched.
If :writing
is specified, just attribute writers are matched.
If :accessing
is specified, both readers and writers are
matched. Any matches will be joined with the matched
:methods.
.
One or more of :readers
, :reader
(synonymous),
:writers
, and/or :writer
(synonymous). By
default, both readers and writers are matched. :reading =>
...
is synonymous with :attributes => ...,
:attribute_options => [:readers]
. :writing => ...
and :changing => ...
are synonymous with :attributes
=> ..., :attribute_options => [:writers]
. :accessing
=> ...
is synonymous with :attributes => ...
.
:attribute_options => [options]
Exclude the specified “things” from the matched join points. If pointcuts are excluded, they should be subsets of the matched pointcuts. Otherwise, the resulting pointcut will be empty!
:exclude_pointcuts => pc || [pc_list]
:exclude_pointcut => pc || [pc_list]
:exclude_join_points => jp || [jp_list]
:exclude_join_point => jp || [jp_list]
:exclude_types => type || [type_list]
:exclude_types => type || [type_list]
:exclude_type => type || [type_list]
:exclude_types_and_descendents => type || [type_list]
:exclude_type_and_descendents => type || [type_list]
:exclude_types_and_ancestors => type || [type_list]
:exclude_type_and_ancestors => type || [type_list]
:exclude_types_and_nested_types => type || [type_list]
:exclude_type_and_nested_types => type || [type_list]
:exclude_types_and_nested => type || [type_list]
:exclude_type_and_nested => type || [type_list]
:exclude_objects => object || [object_list]
:exclude_object => object || [object_list]
:exclude_methods => method || [method_list]
:exclude_method => method || [method_list]
:exclude_attributes => attribute || [attribute_list]
:exclude_attribute => attribute || [attribute_list]
The exclude_
prefix works with the synonyms of the options
shown.
::new also accepts all the “universal” options documented in Aquarium::Utils::OptionsUtils.
# File lib/aquarium/aspects/pointcut.rb, line 191 def initialize options = {} init_specification options, CANONICAL_OPTIONS, (ATTRIBUTE_OPTIONS_VALUES + Advice::KINDS_IN_PRIORITY_ORDER) do finish_specification_initialization end return if noop init_candidate_types init_candidate_objects init_candidate_join_points init_join_points end
# File lib/aquarium/aspects/pointcut.rb, line 280 def self.validate_attribute_options spec_hash, options_hash raise Aquarium::Utils::InvalidOptions.new(":all is not yet supported for :attributes.") if spec_hash[:attributes] == Set.new([:all]) if options_hash[:reading] and (options_hash[:writing] or options_hash[:changing]) unless options_hash[:reading].eql?(options_hash[:writing]) or options_hash[:reading].eql?(options_hash[:changing]) raise Aquarium::Utils::InvalidOptions.new(":reading and :writing/:changing can only be used together if they refer to the same set of attributes.") end end end
# File lib/aquarium/aspects/pointcut_composition.rb, line 24 def and pointcut2 result = Aquarium::Aspects::Pointcut.new result.specification = specification.and(pointcut2.specification) do |value1, value2| value1 & value2 # value1.intersection_using_eql_comparison value2 end result.join_points_matched = join_points_matched.intersection_using_eql_comparison pointcut2.join_points_matched result.join_points_not_matched = join_points_not_matched.intersection_using_eql_comparison pointcut2.join_points_not_matched result.candidate_types = candidate_types.intersection pointcut2.candidate_types result.candidate_objects = candidate_objects.intersection pointcut2.candidate_objects result end
# File lib/aquarium/aspects/pointcut.rb, line 220 def empty? return join_points_matched.empty? && join_points_not_matched.empty? end
Two Considered equivalent only if the same join points matched and not_matched sets are equal, the specifications are equal, and the candidate types and candidate objects are equal. if you care only about the matched join points, then just compare join_points_matched
# File lib/aquarium/aspects/pointcut.rb, line 207 def eql? other object_id == other.object_id || (self.class == other.class && specification == other.specification && candidate_types == other.candidate_types && candidate_types_excluded == other.candidate_types_excluded && candidate_objects == other.candidate_objects && join_points_matched == other.join_points_matched && join_points_not_matched == other.join_points_not_matched) end
# File lib/aquarium/aspects/pointcut.rb, line 263 def finish_specification_initialization @specification.merge! Pointcut.make_attribute_reading_writing_options(@original_options) # Map the method options to their canonical values: @specification[:method_options] = Aquarium::Finders::MethodFinder.init_method_options(@specification[:method_options]) use_default_objects_if_defined unless any_type_related_options_given? Pointcut::validate_attribute_options @specification, @original_options init_methods_specification end
# File lib/aquarium/aspects/pointcut.rb, line 272 def init_methods_specification match_all_methods if ((no_methods_specified? and no_attributes_specified?) or all_methods_specified?) end
# File lib/aquarium/aspects/pointcut.rb, line 224 def inspect "Pointcut: {specification: #{specification.inspect}, candidate_types: #{candidate_types.inspect}, candidate_types_excluded: #{candidate_types_excluded.inspect}, candidate_objects: #{candidate_objects.inspect}, join_points_matched: #{join_points_matched.inspect}, join_points_not_matched: #{join_points_not_matched.inspect}}" end
# File lib/aquarium/aspects/pointcut_composition.rb, line 9 def or pointcut2 result = Aquarium::Aspects::Pointcut.new result.specification = specification.or(pointcut2.specification) do |value1, value2| value1.union_using_eql_comparison value2 end result.join_points_matched = join_points_matched.union_using_eql_comparison pointcut2.join_points_matched result.join_points_not_matched = join_points_not_matched.union_using_eql_comparison pointcut2.join_points_not_matched result.candidate_types = candidate_types.union pointcut2.candidate_types result.candidate_objects = candidate_objects.union pointcut2.candidate_objects result end
# File lib/aquarium/aspects/pointcut.rb, line 301 def all_methods_specified? methods_spec = @specification[:methods].to_a methods_spec.include?(:all) or methods_spec.include?(:all_methods) end
# File lib/aquarium/aspects/pointcut.rb, line 293 def match_all_methods @specification[:methods] = Set.new([:all]) end
# File lib/aquarium/aspects/pointcut.rb, line 306 def no_attributes_specified? @specification[:attributes].nil? or @specification[:attributes].empty? end
# File lib/aquarium/aspects/pointcut.rb, line 297 def no_methods_specified? @specification[:methods].nil? or @specification[:methods].empty? end