lib/credentials/rule.rb in credentials-2.2.3 vs lib/credentials/rule.rb in credentials-2.3.0
- old
+ new
@@ -31,11 +31,11 @@
# There are two exceptions to this behaviour. Firstly,
# if the rule specifies an array, then the argument will
# match any element of that array:
# class User
# credentials do |user|
- # user.can :fight, [ :shatner, :gandhi ]
+ # user.can [ :punch, :fight ], [ :shatner, :gandhi ]
# end
# end
#
# user.can? :fight, :gandhi # => true
#
@@ -45,20 +45,24 @@
# credentials do |user|
# user.can :fight, :self # SPOILER ALERT
# end
# end
def match?(*args)
- return false unless arity == args.length
+ values = args.last.is_a?(Hash) ? args.pop : {}
+ return false unless arity == args.length
+
parameters.zip(args).each do |expected, actual|
case expected
when :self then return false unless actual == args.first
when Array then return false unless expected.any? { |item| (item === actual) || (item == :self && actual == args.first) }
else return false unless expected === actual
end
end
+
result = true
+ result = result && (options.keys & Credentials::Prepositions).inject(true) { |memo, key| memo && evaluate_preposition(args.first, options[key], values[key]) }
result = result && evaluate_condition(options[:if], :|, *args) unless options[:if].nil?
result = result && !evaluate_condition(options[:unless], :&, *args) unless options[:unless].nil?
result
end
@@ -81,8 +85,35 @@
!!condition.call(receiver, *args)
else
raise ArgumentError, "invalid :if or :unless option (expected Symbol or Proc, or array thereof; got #{condition.class})"
end
end
+ end
+
+ def evaluate_preposition(object, expected, actual)
+ return true if expected.nil?
+ return false if actual.nil?
+ return true if expected === actual
+
+ single = expected.to_s
+ plural = single.respond_to?(:pluralize) ? single.pluralize : single + "s"
+
+ lclass, rclass = [ object.class.name, actual.class.name ].map do |s|
+ s.gsub(/^.*::/, '').
+ gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').
+ tr("-", "_").
+ downcase
+ end
+
+ if object.respond_to?(:id) && actual.respond_to?(:"#{lclass}_id")
+ return true if actual.send(:"#{lclass}_id") == object.id
+ end
+
+ if actual.respond_to?(:id) && object.respond_to?(:"#{rclass}_id")
+ return true if object.send(:"#{rclass}_id") == actual.id
+ end
+
+ (object.respond_to?(single) && (object.send(single) == actual)) || (object.respond_to?(plural) && (object.send(plural).include?(actual)))
end
end
end
\ No newline at end of file