gabrielg-extended_observers 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Gabriel Gironda
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,9 @@
1
+ = extended_observers
2
+
3
+ I needed to use an observer to observe multiple models, but only wanted to observe certain sets of changes on each one. There was also a bug where calling observe twice in an ActiveRecord Observer would clear out any previous list of observed classes. This patch adds both the :on option and refactors the workings of the observe method to not clear out models from previous declarations
4
+
5
+ See also: https://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets/1639
6
+
7
+ == Copyright
8
+
9
+ Copyright (c) 2009 Gabriel Gironda. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,56 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "extended_observers"
8
+ gem.summary = %Q{TODO}
9
+ gem.email = "gabriel.gironda@gmail.com"
10
+ gem.homepage = "http://github.com/gabrielg/extended_observers"
11
+ gem.authors = ["Gabriel Gironda"]
12
+
13
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
14
+ end
15
+ rescue LoadError
16
+ puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
17
+ end
18
+
19
+ require 'rake/testtask'
20
+ Rake::TestTask.new(:test) do |test|
21
+ test.libs << 'lib' << 'test'
22
+ test.pattern = 'test/**/*_test.rb'
23
+ test.verbose = true
24
+ end
25
+
26
+ begin
27
+ require 'rcov/rcovtask'
28
+ Rcov::RcovTask.new do |test|
29
+ test.libs << 'test'
30
+ test.pattern = 'test/**/*_test.rb'
31
+ test.verbose = true
32
+ end
33
+ rescue LoadError
34
+ task :rcov do
35
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
36
+ end
37
+ end
38
+
39
+
40
+ task :default => :test
41
+
42
+ require 'rake/rdoctask'
43
+ Rake::RDocTask.new do |rdoc|
44
+ if File.exist?('VERSION.yml')
45
+ config = YAML.load(File.read('VERSION.yml'))
46
+ version = "#{config[:major]}.#{config[:minor]}.#{config[:patch]}"
47
+ else
48
+ version = ""
49
+ end
50
+
51
+ rdoc.rdoc_dir = 'rdoc'
52
+ rdoc.title = "extended_observers #{version}"
53
+ rdoc.rdoc_files.include('README*')
54
+ rdoc.rdoc_files.include('lib/**/*.rb')
55
+ end
56
+
data/VERSION.yml ADDED
@@ -0,0 +1,4 @@
1
+ ---
2
+ :major: 0
3
+ :minor: 0
4
+ :patch: 1
@@ -0,0 +1,65 @@
1
+ require 'active_support'
2
+ require 'active_record'
3
+ require 'active_record/observer'
4
+
5
+ # Monkey patch until http://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets/1639
6
+ # gets accepted.
7
+ module ActiveRecord
8
+ class Observer
9
+ write_inheritable_hash :observable_updates, {}
10
+ class << self
11
+
12
+ # Attaches the observer to the supplied model classes.
13
+ def observe(*models)
14
+ options = models.extract_options!
15
+ set_watch_options(models, options)
16
+ models = constantize_models(models)
17
+ already_observed = read_inheritable_attribute(:observed_classes)
18
+ write_inheritable_attribute(:observed_classes, Set.new(Array(already_observed)) + Set.new(models))
19
+ end
20
+
21
+ private
22
+
23
+ def set_watch_options(models, options)
24
+ on_methods = options.inject([]) do |methods,(key,val)|
25
+ if [:before, :after].include?(key)
26
+ methods.concat(Array(val).map {|v| :"#{key}_#{v}"})
27
+ elsif key == :on
28
+ methods.concat(Array(val).map(&:to_sym))
29
+ end
30
+ methods
31
+ end
32
+ constantize_models(models).each do |model|
33
+ existing = (obs = read_inheritable_attribute(:observable_updates)) ? obs[model] : []
34
+ write_inheritable_hash(:observable_updates, model => Array(existing) + on_methods)
35
+ end
36
+ end
37
+
38
+ def constantize_models(models)
39
+ models.flatten.collect { |model| model.is_a?(Symbol) ? model.to_s.camelize.constantize : model }
40
+ end
41
+
42
+ end # << self
43
+
44
+ # Send observed_method(object) if the method exists.
45
+ def update(observed_method, object) #:nodoc:
46
+ send(observed_method, object) if listening_for?(object, observed_method)
47
+ end
48
+
49
+ def observed_classes
50
+ self.class.read_inheritable_attribute(:observed_classes) || Set.new([self.class.observed_class].compact.flatten)
51
+ end
52
+
53
+ protected
54
+
55
+ def listening_for?(object, observed_method)
56
+ respond_to?(observed_method) && watching?(object, observed_method)
57
+ end
58
+
59
+ def watching?(object, observed_method)
60
+ observed = self.class.read_inheritable_attribute(:observable_updates)
61
+ observed[object.class].blank? || observed[object.class].include?(observed_method.to_sym)
62
+ end
63
+
64
+ end # Observer
65
+ end # ActiveRecord
@@ -0,0 +1,86 @@
1
+ require 'test_helper'
2
+ require 'ruby-debug'
3
+
4
+ # Don't really need a DB connection for these tests
5
+ class ActiveRecord::Base
6
+ def self.columns; []; end
7
+ end
8
+
9
+ class Topic < ActiveRecord::Base; end
10
+ class Developer < ActiveRecord::Base; end
11
+ class Reply < ActiveRecord::Base; end
12
+
13
+ class ActivityObserver < ActiveRecord::Observer
14
+ observe :topic, :after => [:create, :destroy], :before => :update
15
+ observe :topic, :developer, :on => [:before_destroy, 'before_save']
16
+ observe :reply
17
+ end
18
+
19
+ class ExtendedObserversTest < ActiveRecord::TestCase
20
+
21
+ def setup
22
+ @observer = ActivityObserver.instance
23
+ end
24
+
25
+ context "observing a topic" do
26
+
27
+ topic = Topic.new
28
+
29
+ should "observe after_create on Topic" do
30
+ @observer.expects(:after_create).with(topic)
31
+ topic.send(:notify, :after_create)
32
+ end
33
+
34
+ should "observe after_destroy on Topic" do
35
+ @observer.expects(:after_destroy).with(topic)
36
+ topic.send(:notify, :after_destroy)
37
+ end
38
+
39
+ should "observe before_update on Topic" do
40
+ @observer.expects(:before_update).with(topic)
41
+ topic.send(:notify, :before_update)
42
+ end
43
+
44
+ should "observe before_destroy on Topic" do
45
+ @observer.expects(:before_destroy).with(topic)
46
+ topic.send(:notify, :before_destroy)
47
+ end
48
+
49
+ should "observe before_save on Topic" do
50
+ @observer.expects(:before_save).with(topic)
51
+ topic.send(:notify, :before_save)
52
+ end
53
+
54
+ should "ignore after_save and after_validation on topic" do
55
+ @observer.expects(:after_save).with(topic).never
56
+ @observer.expects(:after_validation).with(topic).never
57
+ topic.send(:notify, :after_save)
58
+ topic.send(:notify, :after_validation)
59
+ end
60
+
61
+ end # observing a topic
62
+
63
+ context "observing a developer" do
64
+ developer = Developer.new
65
+
66
+ should "observe before_destroy on Developer" do
67
+ @observer.expects(:before_destroy).with(developer)
68
+ developer.send(:notify, :before_destroy)
69
+ end
70
+
71
+ should "observe before_save on Developer" do
72
+ @observer.expects(:before_save).with(developer)
73
+ developer.send(:notify, :before_save)
74
+ end
75
+
76
+ end
77
+
78
+ should "observe all callbacks on Reply" do
79
+ reply = Reply.new
80
+ ActiveRecord::Callbacks::CALLBACKS.each do |callback|
81
+ @observer.expects(callback).with(reply)
82
+ reply.send(:notify, callback)
83
+ end
84
+ end
85
+
86
+ end
@@ -0,0 +1,10 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+ require 'shoulda'
4
+
5
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
6
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
7
+ require 'extended_observers'
8
+
9
+ class Test::Unit::TestCase
10
+ end
metadata ADDED
@@ -0,0 +1,61 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: gabrielg-extended_observers
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Gabriel Gironda
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-04-23 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description:
17
+ email: gabriel.gironda@gmail.com
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files:
23
+ - LICENSE
24
+ - README.rdoc
25
+ files:
26
+ - LICENSE
27
+ - README.rdoc
28
+ - Rakefile
29
+ - VERSION.yml
30
+ - lib/extended_observers.rb
31
+ - test/extended_observers_test.rb
32
+ - test/test_helper.rb
33
+ has_rdoc: true
34
+ homepage: http://github.com/gabrielg/extended_observers
35
+ post_install_message:
36
+ rdoc_options:
37
+ - --charset=UTF-8
38
+ require_paths:
39
+ - lib
40
+ required_ruby_version: !ruby/object:Gem::Requirement
41
+ requirements:
42
+ - - ">="
43
+ - !ruby/object:Gem::Version
44
+ version: "0"
45
+ version:
46
+ required_rubygems_version: !ruby/object:Gem::Requirement
47
+ requirements:
48
+ - - ">="
49
+ - !ruby/object:Gem::Version
50
+ version: "0"
51
+ version:
52
+ requirements: []
53
+
54
+ rubyforge_project:
55
+ rubygems_version: 1.2.0
56
+ signing_key:
57
+ specification_version: 3
58
+ summary: TODO
59
+ test_files:
60
+ - test/extended_observers_test.rb
61
+ - test/test_helper.rb