lib/aquarium/aspects/pointcut.rb in aquarium-0.1.6 vs lib/aquarium/aspects/pointcut.rb in aquarium-0.1.7
- old
+ new
@@ -46,15 +46,15 @@
#
# <tt>:methods => method || [method_list]</tt>::
# <tt>:method => method || [method_list]</tt>::
# One or an array of methods, method names and/or method regular expessions to match.
# By default, unless :attributes are specified, searches for public instance methods
- # with the method option :suppress_ancestor_methods implied, unless explicit method
+ # with the method option :exclude_ancestor_methods implied, unless explicit method
# options are given.
#
# <tt>:method_options => [options]</tt>::
- # One or more options supported by Aquarium::Finders::MethodFinder. The :suppress_ancestor_methods
+ # One or more options supported by Aquarium::Finders::MethodFinder. The :exclude_ancestor_methods
# option is most useful.
#
# <tt>:attributes => attribute || [attribute_list]</tt>::
# <tt>:attribute => attribute || [attribute_list]</tt>::
# One or an array of attribute names and/or regular expessions to match.
@@ -86,12 +86,11 @@
candidate_objects == other.candidate_objects &&
join_points_matched == other.join_points_matched &&
join_points_not_matched == other.join_points_not_matched)
end
- alias :== :eql?
- alias :=== :eql?
+ alias :== :eql?
def empty?
return join_points_matched.empty? && join_points_not_matched.empty?
end
@@ -121,10 +120,14 @@
@specification[:method_options] = Set.new(make_array(options[:method_options]))
@specification[:attribute_options] = Set.new(make_array(options[:attribute_options]) )
@specification[:types] = Set.new(make_array(options[:types], options[:type]))
@specification[:objects] = Set.new(make_array(options[:objects], options[:object]))
@specification[:join_points] = Set.new(make_array(options[:join_points], options[:join_point]))
+ @specification[:exclude_types] = Set.new(make_array(options[:exclude_type], options[:exclude_types]))
+ @specification[:exclude_objects] = Set.new(make_array(options[:exclude_object], options[:exclude_objects]))
+ @specification[:exclude_join_points] = Set.new(make_array(options[:exclude_join_point], options[:exclude_join_points]))
+ @specification[:exclude_methods] = Set.new(make_array(options[:exclude_method], options[:exclude_methods]))
@specification[:default_object] = Set.new(make_array(options[:default_object]))
use_default_object_if_defined unless (types_given? || objects_given?)
@specification[:attributes] = Set.new(make_array(options[:attributes], options[:attribute]))
raise Aquarium::Utils::InvalidOptions.new(":all is not yet supported for :attributes.") if @specification[:attributes] == Set.new([:all])
init_methods_specification options
@@ -134,11 +137,14 @@
@specification[:methods] = Set.new(make_array(options[:methods], options[:method]))
@specification[:methods].add(:all) if @specification[:methods].empty? and @specification[:attributes].empty?
end
def validate_options options
- knowns = %w[object objects type types join_point join_points method methods attribute attributes method_options attribute_options default_object].map {|x| x.intern}
+ knowns = %w[object objects type types join_point join_points
+ exclude_object exclude_objects exclude_type exclude_types exclude_join_point exclude_join_points exclude_method exclude_methods
+ method methods attribute attributes
+ method_options attribute_options default_object].map {|x| x.intern}
unknowns = options.keys - knowns
raise Aquarium::Utils::InvalidOptions.new("Unknown options specified: #{unknowns.inspect}") if unknowns.size > 0
end
def self.read_only attribute_options
@@ -167,23 +173,42 @@
not (#{name}_given.nil? or #{name}_given.empty?)
end
EOF
end
+ %w[types objects join_points methods].each do |name|
+ class_eval(<<-EOF, __FILE__, __LINE__)
+ def exclude_#{name}_given
+ @specification[:exclude_#{name}]
+ end
+
+ def exclude_#{name}_given?
+ not (exclude_#{name}_given.nil? or exclude_#{name}_given.empty?)
+ end
+ EOF
+ end
+
private
def init_candidate_types
explicit_types, type_regexps_or_names = @specification[:types].partition do |type|
- is_type? type
+ Aquarium::Utils::TypeUtils.is_type? type
end
- @candidate_types = Aquarium::Finders::TypeFinder.new.find :types => type_regexps_or_names
- @candidate_types.append_matched(make_hash(explicit_types) {|x| Set.new([])}) # Append already-known types
+ excluded_explicit_types, excluded_type_regexps_or_names = @specification[:exclude_types].partition do |type|
+ Aquarium::Utils::TypeUtils.is_type? type
+ end
+ possible_types = Aquarium::Finders::TypeFinder.new.find :types => type_regexps_or_names, :exclude_types => excluded_type_regexps_or_names
+ possible_types.append_matched(make_hash(explicit_types) {|x| Set.new([])})
+ @candidate_types = possible_types - Aquarium::Finders::TypeFinder.new.find(:types => excluded_type_regexps_or_names)
+ @candidate_types.matched.delete_if {|type, value| excluded_explicit_types.include? type}
end
def init_candidate_objects
object_hash = {}
- @specification[:objects].each {|o| object_hash[o] = Set.new([])}
+ (@specification[:objects].flatten - @specification[:exclude_objects].flatten).each do |o|
+ object_hash[o] = Set.new([])
+ end
@candidate_objects = Aquarium::Finders::FinderResult.new object_hash
end
def init_candidate_join_points
@candidate_join_points = Aquarium::Finders::FinderResult.new
@@ -202,16 +227,14 @@
find_join_points_for :type, candidate_types, make_all_method_names
find_join_points_for :object, candidate_objects, make_all_method_names
add_join_points_for_candidate_join_points
end
- def is_type? candidate_type
- candidate_type.kind_of?(Module) || candidate_type.kind_of?(Class)
- end
-
def add_join_points_for_candidate_join_points
- @join_points_matched += @candidate_join_points.matched.keys
+ @join_points_matched += @candidate_join_points.matched.keys.find_all do |jp|
+ not (is_excluded_join_point?(jp) or is_excluded_type_or_object?(jp.type_or_object) or is_excluded_method?(jp.method_name))
+ end
@join_points_not_matched += @candidate_join_points.not_matched.keys
end
def find_join_points_for type_or_object_sym, candidates, method_names
results = find_methods_for type_or_object_sym, candidates, method_names
@@ -219,12 +242,13 @@
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,
- :options => @specification[:method_options].to_a
+ :methods => which_methods,
+ :exclude_methods => @specification[:exclude_methods],
+ :options => @specification[:method_options].to_a
end
def add_join_points search_results, type_or_object_sym
add_join_points_to @join_points_matched, search_results.matched, type_or_object_sym
add_join_points_to @join_points_not_matched, search_results.not_matched, type_or_object_sym
@@ -241,12 +265,43 @@
end
end
end
def make_all_method_names
- @specification[:methods] + Pointcut.make_attribute_method_names(@specification[:attributes], @specification[:attribute_options])
+ @specification[:methods] +
+ Pointcut.make_attribute_method_names(@specification[:attributes], @specification[:attribute_options]) -
+ @specification[:exclude_methods]
end
+ def is_excluded_join_point? jp
+ @specification[:exclude_join_points].include? jp
+ end
+
+ def is_excluded_type_or_object? type_or_object
+ return true if @specification[:exclude_objects].include?(type_or_object)
+ @specification[:exclude_types].find do |t|
+ case t
+ when String: type_or_object.name.eql?(t)
+ when Symbol: type_or_object.name.eql?(t.to_s)
+ when Regexp: type_or_object.name =~ t
+ end
+ end
+ end
+
+ def is_excluded_method? method
+ is_explicitly_excluded_method?(method) or matches_excluded_method_regex?(method)
+ end
+
+ def is_explicitly_excluded_method? method
+ @specification[:exclude_methods].include? method
+ end
+
+ def matches_excluded_method_regex? method
+ regexs = @specification[:exclude_methods].find_all {|s| s.kind_of? Regexp}
+ return false if regexs.empty?
+ regexs.find {|re| method.to_s =~ re}
+ end
+
def self.make_attribute_readers attributes
readers = attributes.map do |regexp_or_name|
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$'))