Class: Contracts::AnnotatedMethod
- Inherits:
-
Object
- Object
- Contracts::AnnotatedMethod
- Defined in:
- lib/contracts.rb
Instance Method Summary collapse
-
#initialize(method, annotations) ⇒ AnnotatedMethod
constructor
A new instance of AnnotatedMethod.
- #invoke(receiver, *args, &blk) ⇒ Object
Constructor Details
#initialize(method, annotations) ⇒ AnnotatedMethod
Returns a new instance of AnnotatedMethod.
55 56 57 58 59 60 61 62 63 64 65 |
# File 'lib/contracts.rb', line 55 def initialize(method, annotations) @method = method @before_annotations = annotations.select { |annotation| annotation.respond_to?(:before_call) } @after_annotations = annotations.select { |annotation| annotation.respond_to?(:after_call) } @exception_annotations = annotations.select { |annotation| annotation.respond_to?(:on_exception) } annotations.each do |annotation| annotation.method = method end end |
Instance Method Details
#invoke(receiver, *args, &blk) ⇒ Object
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 |
# File 'lib/contracts.rb', line 67 def invoke(receiver, *args, &blk) # # Some contracts might need a per-invocation scope. If that is the take # their before_call method will return their specific scope, and we'll # carry that over to the after_call and on_exception calls. # # Since this is potentially costly we do rather not create a combined # scope object unless we really need it; also there is an optimized # code path for after_call's in effect. (Not for on_exception though; # since they should only occur in exceptional situations they can carry # a bit of performance penalty just fine.) # # TODO: This could be improved by having a each annotation take care of # each individual call; a first experiment to do that, however, failed. annotation_scopes = nil @before_annotations.each do |annotation| next unless annotation_scope = annotation.before_call(receiver, *args, &blk) annotation_scopes ||= {} annotation_scopes[annotation.object_id] = annotation_scope end # instance methods are UnboundMethod, class methods are Method. rv = @method.is_a?(Method) ? @method.call(*args, &blk) : @method.bind(receiver).call(*args, &blk) if annotation_scopes @after_annotations.each do |annotation| annotation.after_call(annotation_scopes[annotation.object_id], rv, receiver, *args, &blk) end else @after_annotations.each do |annotation| annotation.after_call(nil, rv, receiver, *args, &blk) end end return rv rescue StandardError => exc @exception_annotations.each do |annotation| annotation.on_exception(annotation_scopes && annotation_scopes[annotation.object_id], exc, receiver, *args, &blk) end raise exc end |