Skip to content

Commit

Permalink
Fixed bug with set_observer
Browse files Browse the repository at this point in the history
  • Loading branch information
Nathan Stults committed Oct 4, 2010
1 parent e54103a commit a010102
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 56 deletions.
103 changes: 53 additions & 50 deletions lib/observables/base.rb
Original file line number Diff line number Diff line change
@@ -1,75 +1,78 @@
require 'active_support/concern'
require "active_support/notifications/fanout"
require 'active_support/core_ext/object/duplicable'
require 'active_support/core_ext/array/extract_options'

module Observables
module Base
extend ActiveSupport::Concern

def notifier
@notifier ||= ActiveSupport::Notifications::Fanout.new
end
module InstanceMethods
def notifier
@notifier ||= ActiveSupport::Notifications::Fanout.new
end

def subscribe(pattern=nil,&block)
notifier.subscribe(pattern,&block)
end
def subscribe(pattern=nil,&block)
notifier.subscribe(pattern,&block)
end

def unsubscribe(subscriber)
notifier.unsubscribe(subscriber)
end
def unsubscribe(subscriber)
notifier.unsubscribe(subscriber)
end

def dup
super.tap {|s|s.make_observable}
end
def dup
super.tap {|s|s.make_observable}
end

def set_observer(new_owner,opts={},&block)
raise "An owner was not provided. If you are trying to disown an observable object, please use 'disown' instead" unless new_owner
raise "This observable object is already owner by another object. Please call 'disown' to remove the previous owner" if @owner_subscription
@owner = new_owner
pattern = opts[:pattern] || /.*/
callback_method = opts[:callback_method] || :child_changed
@owner_subscription = subscribe(pattern) do |*args|
block ? block.call(self,*args) :
@owner.send(callback_method,self,*args) if @owner.respond_to?(callback_method)
def set_observer(*args,&block)
clear_observer
opts = args.extract_options!
@_observer_owner = args.pop
pattern = opts[:pattern] || /.*/
callback_method = opts[:callback_method] || :child_changed
@_owner_subscription = subscribe(pattern) do |*args|
block ? block.call(self,*args) :
(@_observer_owner.send(callback_method,self,*args) if @_observer_owner && @_observer_owner.respond_to?(callback_method))
end
end
end

def clear_observer
unsubscribe(@owner_subscription) if @owner_subscription
@owner_subscription = nil
end
def clear_observer
unsubscribe(@_owner_subscription) if @_owner_subscription
@_owner_subscription = nil
end

protected
protected

def changing(change_type,opts={})
args = create_event_args(change_type,opts)
notifier.publish "before_#{change_type}".to_sym, args
yield.tap do
notifier.publish "after_#{change_type}".to_sym, args
def changing(change_type,opts={})
args = create_event_args(change_type,opts)
notifier.publish "before_#{change_type}".to_sym, args
yield.tap do
notifier.publish "after_#{change_type}".to_sym, args
end
end
end

def create_event_args(change_type,opts={})
args = {:change_type=>change_type, :current_values=>self}.merge(opts)
class << args
def changes
chgs, cur_values = self[:changes], self[:current_values]
chgs && chgs.respond_to?(:call) ? chgs.call(cur_values) : chgs
end
def create_event_args(change_type,opts={})
args = {:change_type=>change_type, :current_values=>self}.merge(opts)
class << args
def changes
chgs, cur_values = self[:changes], self[:current_values]
chgs && chgs.respond_to?(:call) ? chgs.call(cur_values) : chgs
end

def method_missing(method)
self.keys.include?(method) ? self[method] : super
def method_missing(method)
self.keys.include?(method) ? self[method] : super
end
end
args.delete(:current)
args
end
args.delete(:current)
args
end

def changes_for(change_type,trigger_method,*args,&block)
#This method should return a lambda that takes the current
#value of the collection as an argument, and returns
#the expected changes that will result from trigger_method
nil
def changes_for(change_type,trigger_method,*args,&block)
#This method should return a lambda that takes the current
#value of the collection as an argument, and returns
#the expected changes that will result from trigger_method
nil
end
end

module ClassMethods
Expand Down
4 changes: 2 additions & 2 deletions observables.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ require File.expand_path('../lib/observables/version', __FILE__)

Gem::Specification.new do |s|
s.name = 'observables'
s.homepage = 'http://github.com/jnunemaker/observables'
s.homepage = 'http://github.com/PlasticLizard/observables'
s.summary = 'Observable arrays and hashes'
s.require_path = 'lib'
#s.default_executable = ''
s.authors = ['Nathan Stults']
s.email = ['hereiam@sonic.net']
#s.executables = ['mmconsole']
#s.executables = ['']
s.version = Observables::Version
s.platform = Gem::Platform::RUBY
s.files = Dir.glob("{bin,examples,lib,rails,test}/**/*") + %w[LICENSE README.rdoc]
Expand Down
4 changes: 1 addition & 3 deletions test/test_array_watcher.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,7 @@ class TestArrayWatcher < Test::Unit::TestCase
context "An array which has included Observables::ArrayWatcher" do
setup do
@ary = Array.new([1,2,3]).tap do |a|
class << a
include Observables::ArrayWatcher
end
a.make_observable
end
end

Expand Down
17 changes: 16 additions & 1 deletion test/test_base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,21 @@ def changed_args; @changed_args; end
assert_equal 1, events.length
assert_equal :before_a_change, events.pop
end
should "stop notifying the parent after disown is called" do
should "notify the parent via argless block" do
events = []
@obs.set_observer(@parent, :pattern=>/before/){events << 1}
@obs.send(:changing, :a_change){1==1}
assert_equal 1, events.length
end
should "notify via block when no owner is given" do
events = []
my_ary = [1,2,3]
my_ary.make_observable
my_ary.set_observer(:pattern=>/before/){events << 1}
my_ary << 1
assert_equal 1, events.length
end
should "stop notifying the parent after clear_observer is called" do
events = []
@obs.set_observer(@parent){|*args|events << args}
@obs.send(:changing,:a_change){1==1}
Expand All @@ -107,6 +121,7 @@ def changed_args; @changed_args; end
@obs.send(:changing,:a_change){1==1}
assert_equal 2, events.length
end

end
end
end

0 comments on commit a010102

Please sign in to comment.