sentinel 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.textile CHANGED
@@ -2,6 +2,8 @@ h1. Sentinel
2
2
 
3
3
  Transparent (unobtrusive) Observers for your Rubies.
4
4
 
5
+ Does Sentinel helps your daily work with Ruby? So, "please recommend me in Work With Rails":http://workingwithrails.com/recommendation/new/person/9370-lucas-h-ngaro and thanks for your kindness! :)
6
+
5
7
  h2. Why?
6
8
 
7
9
  Developed for an specific need we had at "Busk":http://www.busk.com, Sentinel is a very small library that provides a way to add what we call "Transparent Observers" to your Ruby code. This means that you do not need to modify the observed methods (following the most common implementation of Observers), just use a mixin and declare your observers.
@@ -49,16 +51,20 @@ class MyClass
49
51
  end
50
52
  </pre>
51
53
 
52
- And... that's it! Every time the subject (in this case, MyClass) method is called, the specified observer method will be called *before* it, then it will run normally. The parameters passed to the subject method are passed to the observer method via the *args array. The options hash contains the key :subject, which contains the actual subject object in case you want to use it, like below:
54
+ And... that's it! Every time the subject (in this case, MyClass) method is called, the specified observer method will be called too. By default, the observer method is called *before* the subject method, but you can call it *after* the execution (will see it in the next example).
55
+
56
+ The parameters passed to the subject method are passed to the observer method via the *args array. The options hash contains the key :subject, which contains the actual subject object and the key :result, which contains the return of the observed method in case you intercepted the call after its execution.
57
+
58
+ Below is a more "advanced" use of the observers:
53
59
 
54
60
  <pre>
55
61
  class MyObserver
56
62
  include Sentinel
57
63
 
58
- observe MyClass, :instance_method
64
+ observe MyClass, :instance_method, :intercept => :after
59
65
 
60
66
  def self.notify(options, *args)
61
- puts "Called from #{options[:subject]} with arguments #{args.inspect}"
67
+ puts "Called from #{options[:subject]} with arguments #{args.inspect} and returned #{options[:result]}"
62
68
  end
63
69
  end
64
70
  </pre>
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.4.0
1
+ 0.5.0
data/lib/sentinel.rb CHANGED
@@ -10,14 +10,28 @@ module Sentinel
10
10
  sentinel = self
11
11
 
12
12
  options = {
13
- :method_to_notify => :notify
13
+ :method_to_notify => :notify,
14
+ :intercept => :before
14
15
  }.merge(options)
15
16
 
17
+ if options[:intercept] == :before
18
+ calls = <<-CODE
19
+ sentinel.send("#{options[:method_to_notify]}", observer_opt, *args)
20
+ self.send("#{method_name}_without_observer", *args)
21
+ CODE
22
+ else
23
+ calls = <<-CODE
24
+ result = self.send("#{method_name}_without_observer", *args)
25
+ observer_opt[:result] = result
26
+ sentinel.send("#{options[:method_to_notify]}", observer_opt, *args)
27
+ result
28
+ CODE
29
+ end
30
+
16
31
  body = <<-CODE
17
32
  define_method "#{method_name}_with_observer" do |*args|
18
33
  observer_opt = {:subject => self}
19
- sentinel.send("#{options[:method_to_notify]}", observer_opt, *args)
20
- self.send("#{method_name}_without_observer", *args)
34
+ #{calls}
21
35
  end
22
36
 
23
37
  alias_method "#{method_name}_without_observer", method_name
@@ -1,14 +1,10 @@
1
1
  class SentinelSubject
2
2
  def instance_method
3
- "hi from instance method!"
4
- end
5
-
6
- def new_method
7
- "hi from new method!"
3
+ 42
8
4
  end
9
5
 
10
6
  def self.class_method
11
- "hi from class method!"
7
+ 42
12
8
  end
13
9
 
14
10
  def instance_method_with_params(*params)
@@ -18,12 +14,4 @@ class SentinelSubject
18
14
  def self.class_method_with_params(*params)
19
15
  "hi from class method with params!"
20
16
  end
21
-
22
- def instance_returning_something
23
- 42
24
- end
25
-
26
- def self.class_returning_something
27
- 42
28
- end
29
17
  end
@@ -2,74 +2,103 @@ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
2
  require File.expand_path(File.dirname(__FILE__) + '/fixtures/my_observer')
3
3
  require File.expand_path(File.dirname(__FILE__) + '/fixtures/sentinel_subject')
4
4
 
5
- describe Sentinel, "defining an observer for a method" do
6
- before(:all) do
5
+ describe Sentinel do
6
+ before(:each) do
7
7
  MyObserver.send(:include, Sentinel)
8
8
  end
9
+
10
+ after(:each) do
11
+ # reload the file to undefine the observer methods (would cause 'stack level too deep' errors otherwise)
12
+ load File.expand_path(File.dirname(__FILE__) + '/fixtures/sentinel_subject.rb')
13
+ end
9
14
 
10
- context "with the minimum required options" do
11
- it "should notify the specified Observer when calling a class method" do
15
+ context "basic premises" do
16
+ it "should not modify the subject method output when called before it" do
17
+ MyObserver.send(:observe, SentinelSubject, :class_method, :class_method => true)
12
18
  MyObserver.send(:observe, SentinelSubject, :instance_method)
13
- MyObserver.expects(:notify)
14
-
15
- SentinelSubject.new.instance_method
16
- end
17
19
 
18
- it "should notify the specified Observer when calling an instance method" do
19
- MyObserver.send(:observe, SentinelSubject, :class_method, :class_method => true)
20
- MyObserver.expects(:notify)
20
+ MyObserver.expects(:notify).twice
21
21
 
22
- SentinelSubject.class_method
22
+ SentinelSubject.class_method.should == 42
23
+ SentinelSubject.new.instance_method.should == 42
23
24
  end
24
-
25
- it "should not modify the observed methods output" do
26
- MyObserver.send(:observe, SentinelSubject, :class_returning_something, :class_method => true)
27
- MyObserver.send(:observe, SentinelSubject, :instance_returning_something)
25
+
26
+ it "should not modify the subject method output when called after it" do
27
+ MyObserver.send(:observe, SentinelSubject, :class_method, :class_method => true, :intercept => :after)
28
+ MyObserver.send(:observe, SentinelSubject, :instance_method, :intercept => :after)
28
29
 
29
30
  MyObserver.expects(:notify).twice
30
31
 
31
- SentinelSubject.class_returning_something.should == 42
32
- SentinelSubject.new.instance_returning_something.should == 42
32
+ SentinelSubject.class_method.should == 42
33
+ SentinelSubject.new.instance_method.should == 42
33
34
  end
35
+
36
+ it "should pass all parameters of the observed methods to the observer" do
37
+ MyObserver.send(:observe, SentinelSubject, :class_method_with_params, :class_method => true)
38
+ MyObserver.send(:observe, SentinelSubject, :instance_method_with_params)
34
39
 
35
- context "observing methods with parameters" do
36
- it "should pass all parameters of the observed methods to the Observer" do
37
- MyObserver.send(:observe, SentinelSubject, :class_method_with_params, :class_method => true)
38
- MyObserver.send(:observe, SentinelSubject, :instance_method_with_params)
40
+ subject = SentinelSubject.new
39
41
 
40
- subject = SentinelSubject.new
42
+ MyObserver.expects(:notify).once.with({:subject => SentinelSubject}, "texto", 1)
43
+ MyObserver.expects(:notify).once.with({:subject => subject}, "texto", 1)
41
44
 
42
- MyObserver.expects(:notify).once.with({:subject => SentinelSubject}, "texto", 1)
43
- MyObserver.expects(:notify).once.with({:subject => subject}, "texto", 1)
44
-
45
- SentinelSubject.class_method_with_params("texto", 1)
46
- subject.instance_method_with_params("texto", 1)
47
- end
45
+ SentinelSubject.class_method_with_params("texto", 1)
46
+ subject.instance_method_with_params("texto", 1)
48
47
  end
48
+ end
49
49
 
50
- context "observing methods using a different Observer method" do
51
- it "should call the specified method in the observe call" do
52
- MyObserver.send(:observe, SentinelSubject, :new_method, :method_to_notify => :another_method)
53
- MyObserver.expects(:another_method)
50
+ context "with the default options" do
51
+ it "should notify the specified observer when calling an instance method" do
52
+ MyObserver.send(:observe, SentinelSubject, :instance_method)
53
+ MyObserver.expects(:notify)
54
54
 
55
- SentinelSubject.new.new_method
56
- end
55
+ SentinelSubject.new.instance_method
57
56
  end
58
- end
59
57
 
60
- context "without the minimum required options" do
61
- it "should raise ArgumentError when the observer of an instance method is not defined" do
62
- MyObserver.expects(:notify).never
63
- SentinelSubject.expects(:observe).raises(ArgumentError)
58
+ it "should notify the specified observer when calling a class method" do
59
+ MyObserver.send(:observe, SentinelSubject, :class_method, :class_method => true)
60
+ MyObserver.expects(:notify)
64
61
 
65
- SentinelSubject.send(:observe, :instance_method) rescue nil
62
+ SentinelSubject.class_method
66
63
  end
64
+
65
+ it "should be called before the method execution" do
66
+ MyObserver.send(:observe, SentinelSubject, :instance_method)
67
+ subject = SentinelSubject.new
68
+
69
+ MyObserver.expects(:notify).once.with({:subject => subject})
67
70
 
68
- it "should raise ArgumentError when the observer of a class method is not defined" do
69
- MyObserver.expects(:notify).never
70
- SentinelSubject.expects(:observe).raises(ArgumentError)
71
+ subject.instance_method
72
+ end
73
+ end
74
+
75
+ context "with user-specified options" do
76
+ context "when observing methods using a different observer method" do
77
+ it "should call the specified observer method when the subject method is called" do
78
+ MyObserver.send(:observe, SentinelSubject, :instance_method, :method_to_notify => :another_method)
79
+ MyObserver.send(:observe, SentinelSubject, :class_method, :method_to_notify => :another_method, :class_method => true)
80
+
81
+ MyObserver.expects(:another_method).twice
82
+
83
+ SentinelSubject.new.instance_method
84
+ SentinelSubject.class_method
85
+ end
86
+ end
87
+
88
+ context "when intercepting the call after the method execution" do
89
+ it "should pass the result of the execution to the observer" do
90
+ MyObserver.send(:observe, SentinelSubject, :instance_method, :intercept => :after)
91
+ MyObserver.send(:observe, SentinelSubject, :class_method, :intercept => :after, :class_method => true)
92
+
93
+ subject = SentinelSubject.new
94
+
95
+ MyObserver.expects(:notify).once.with({:subject => subject, :result => 42})
96
+ MyObserver.expects(:notify).once.with({:subject => SentinelSubject, :result => 42})
71
97
 
72
- SentinelSubject.send(:observe, :class_method, :class_method => true) rescue nil
98
+ subject.instance_method
99
+ SentinelSubject.class_method
100
+ end
73
101
  end
74
102
  end
103
+
75
104
  end
metadata CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
6
  - 0
7
- - 4
7
+ - 5
8
8
  - 0
9
- version: 0.4.0
9
+ version: 0.5.0
10
10
  platform: ruby
11
11
  authors:
12
12
  - "Lucas H\xC3\xBAngaro"
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-04-19 00:00:00 -03:00
17
+ date: 2010-04-26 00:00:00 -03:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency