lib/aquarium/aspects/pointcut.rb in aquarium-0.3.1 vs lib/aquarium/aspects/pointcut.rb in aquarium-0.4.0
- old
+ new
@@ -194,29 +194,40 @@
end
alias to_s inspect
CANONICAL_OPTIONS = {
- "types" => %w[type for_type for_types on_type on_types in_type in_types within_type within_types],
- "objects" => %w[object for_object for_objects on_object on_objects in_object in_objects within_object within_objects],
- "join_points" => %w[join_point for_join_point for_join_points on_join_point on_join_points within_join_point within_join_points],
+ "types" => %w[type class classes module modules],
+ "types_and_descendents" => %w[type_and_descendents class_and_descendents classes_and_descendents module_and_descendents modules_and_descendents],
+ "types_and_ancestors" => %w[type_and_ancestors class_and_ancestors classes_and_ancestors module_and_ancestors modules_and_ancestors],
+ "objects" => %w[object],
+ "join_points" => %w[join_point],
"methods" => %w[method within_method within_methods calling invoking calls_to invocations_of sending_message_to sending_messages_to],
"attributes" => %w[attribute accessing],
"method_options" => %w[method_option restricting_methods_to],
"attribute_options" => %w[attribute_option],
- "types_and_descendents" => %w[type_and_descendents on_type_and_descendents on_types_and_descendents within_type_and_descendents within_types_and_descendents],
- "types_and_ancestors" => %w[type_and_ancestors on_type_and_ancestors on_types_and_ancestors within_type_and_ancestors within_types_and_ancestors],
"default_objects" => %w[default_object]
}
- %w[types objects join_points methods types_and_descendents types_and_ancestors].each do |key|
- CANONICAL_OPTIONS["exclude_#{key}"] = CANONICAL_OPTIONS[key].map {|x| "exclude_#{x}"}
+ %w[types types_and_descendents types_and_ancestors objects join_points ].each do |thing|
+ roots = CANONICAL_OPTIONS[thing].dup + [thing]
+ CANONICAL_OPTIONS["exclude_#{thing}"] = roots.map {|x| "exclude_#{x}"}
+ %w[for on in within].each do |prefix|
+ roots.each do |root|
+ CANONICAL_OPTIONS[thing] << "#{prefix}_#{root}"
+ end
+ end
end
CANONICAL_OPTIONS["methods"].dup.each do |synonym|
CANONICAL_OPTIONS["methods"] << "#{synonym}_methods_matching"
end
- CANONICAL_OPTIONS["exclude_pointcuts"] = %w[exclude_pointcut exclude_on_pointcut exclude_on_pointcuts exclude_within_pointcut exclude_within_pointcuts]
-
+ CANONICAL_OPTIONS["exclude_methods"] = []
+ CANONICAL_OPTIONS["methods"].each do |synonym|
+ CANONICAL_OPTIONS["exclude_methods"] << "exclude_#{synonym}"
+ end
+ CANONICAL_OPTIONS["exclude_pointcuts"] = ["exclude_pointcut"] +
+ %w[for on in within].map {|prefix| ["exclude_#{prefix}_pointcuts", "exclude_#{prefix}_pointcut"]}.flatten
+
ATTRIBUTE_OPTIONS = %w[reading writing changing]
ALL_ALLOWED_OPTIONS = ATTRIBUTE_OPTIONS +
CANONICAL_OPTIONS.keys.inject([]) {|ary,i| ary << i << CANONICAL_OPTIONS[i]}.flatten
@@ -337,12 +348,22 @@
end
def init_join_points
@join_points_matched = Set.new
@join_points_not_matched = Set.new
- find_join_points_for :type, (candidate_types - candidate_types_excluded), make_all_method_names
- find_join_points_for :object, candidate_objects, make_all_method_names
+ types = candidate_types - candidate_types_excluded
+ method_names = make_method_names
+ attribute_method_names = make_attribute_method_names
+ unless types.empty?
+ find_join_points_for(:type, types, method_names) unless method_names.empty?
+ find_join_points_for(:type, types, attribute_method_names) unless attribute_method_names.empty?
+ end
+ unless candidate_objects.empty?
+ find_join_points_for(:object, candidate_objects, method_names) unless method_names.empty?
+ find_join_points_for(:object, candidate_objects, attribute_method_names) unless attribute_method_names.empty?
+ end
+ subtract_attribute_writers if attributes_read_only?
add_join_points_for_candidate_join_points
remove_excluded_join_points
end
def add_join_points_for_candidate_join_points
@@ -362,11 +383,11 @@
end
def find_methods_for type_or_object_sym, candidates, which_methods
return Aquarium::Finders::FinderResult::NIL_OBJECT if candidates.matched.size == 0
Aquarium::Finders::MethodFinder.new.find type_or_object_sym => candidates.matched_keys,
- :methods => which_methods,
+ :methods => which_methods.to_a,
:exclude_methods => @specification[:exclude_methods],
:options => method_options
end
def add_join_points search_results, type_or_object_sym
@@ -383,67 +404,74 @@
:instance_method => is_instance_methods?)
end
end
end
+ def subtract_attribute_writers
+ @join_points_matched.reject! do |jp|
+ jp.method_name.to_s[-1..-1] == '='
+ end
+ end
+
def is_instance_methods?
not @specification[:method_options].include? :class
end
- def make_all_method_names
- @specification[:methods] +
- make_attribute_method_names(@specification[:attributes], @specification[:attribute_options]) -
- @specification[:exclude_methods]
+ def make_method_names
+ @specification[:methods] - @specification[:exclude_methods]
end
- def make_attribute_method_names attribute_name_regexps_or_names, attribute_options = []
- readers = make_attribute_readers attribute_name_regexps_or_names
- return readers if read_only attribute_options
+ def make_attribute_method_names
+ readers = make_attribute_readers
+ return readers if attributes_read_only?
writers = make_attribute_writers readers
- return writers if write_only attribute_options
+ return writers if attributes_write_only?
return readers + writers
end
- def make_attribute_readers attributes
- readers = attributes.map do |regexp_or_name|
+ # Because Ruby 1.8 regexp library doesn't support negative look behinds, we really
+ # can't set the regular expression to exclude a trailing = reliably. Instead,
+ # #init_join_points above will remove any writer methods, if necessary.
+ def make_attribute_readers
+ readers = @specification[:attributes].map do |regexp_or_name|
+ expr1 = regexp_or_name.kind_of?(Regexp) ? regexp_or_name.source : regexp_or_name.to_s
+ expr = remove_trailing_equals_and_or_dollar(remove_leading_colon_or_at_sign(expr1))
if regexp_or_name.kind_of? Regexp
- exp = remove_trailing_equals_and_or_dollar regexp_or_name.source
- Regexp.new(remove_leading_colon_or_at_sign(exp + '.*\b$'))
+ Regexp.new(remove_leading_colon_or_at_sign(expr))
else
- exp = remove_trailing_equals_and_or_dollar regexp_or_name.to_s
- remove_leading_colon_or_at_sign(exp.to_s)
+ expr
end
end
Set.new(readers.sort_by {|exp| exp.to_s})
end
-
- def make_attribute_writers attributes
- writers = attributes.map do |regexp_or_name|
+
+ def make_attribute_writers reader_methods
+ writers = reader_methods.map do |regexp_or_name|
+ expr = regexp_or_name.kind_of?(Regexp) ? regexp_or_name.source : regexp_or_name.to_s
if regexp_or_name.kind_of? Regexp
- # remove the "\b$" from the end of the reader expression, if present.
- Regexp.new(remove_trailing_equals_and_or_dollar(regexp_or_name.source) + '=$')
+ Regexp.new(expr+'.*=$')
else
- regexp_or_name + '='
+ expr + '='
end
end
Set.new(writers.sort_by {|exp| exp.to_s})
end
- def read_only attribute_options
- read_option(attribute_options) && !write_option(attribute_options)
+ def attributes_read_only?
+ read_option && !write_option
end
- def write_only attribute_options
- write_option(attribute_options) && !read_option(attribute_options)
+ def attributes_write_only?
+ write_option && !read_option
end
- def read_option attribute_options
- attribute_options.include?(:readers) or attribute_options.include?(:reader)
+ def read_option
+ @specification[:attribute_options].include?(:readers) or @specification[:attribute_options].include?(:reader)
end
- def write_option attribute_options
- attribute_options.include?(:writers) or attribute_options.include?(:writer)
+ def write_option
+ @specification[:attribute_options].include?(:writers) or @specification[:attribute_options].include?(:writer)
end
def method_options
@specification[:method_options].to_a.map {|mo| mo == :all_methods ? :all : mo }
end