opal-vienna 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +3 -0
- data/.travis.yml +8 -0
- data/Gemfile +7 -0
- data/README.md +294 -0
- data/Rakefile +7 -0
- data/config.ru +8 -0
- data/lib/opal-vienna.rb +1 -0
- data/lib/opal/vienna.rb +7 -0
- data/lib/opal/vienna/version.rb +5 -0
- data/opal-vienna.gemspec +26 -0
- data/opal/vienna.rb +5 -0
- data/opal/vienna/adapters/base.rb +45 -0
- data/opal/vienna/adapters/local.rb +50 -0
- data/opal/vienna/adapters/rest.rb +97 -0
- data/opal/vienna/eventable.rb +35 -0
- data/opal/vienna/history_router.rb +44 -0
- data/opal/vienna/model.rb +222 -0
- data/opal/vienna/observable.rb +90 -0
- data/opal/vienna/observable_array.rb +73 -0
- data/opal/vienna/output_buffer.rb +13 -0
- data/opal/vienna/record_array.rb +31 -0
- data/opal/vienna/router.rb +85 -0
- data/opal/vienna/template_view.rb +41 -0
- data/opal/vienna/view.rb +93 -0
- data/spec/eventable_spec.rb +94 -0
- data/spec/history_router_spec.rb +47 -0
- data/spec/model/accessing_attributes_spec.rb +29 -0
- data/spec/model/as_json_spec.rb +28 -0
- data/spec/model/attribute_spec.rb +22 -0
- data/spec/model/initialize_spec.rb +42 -0
- data/spec/model/load_spec.rb +17 -0
- data/spec/model/persistence_spec.rb +84 -0
- data/spec/model_spec.rb +84 -0
- data/spec/observable_array_spec.rb +130 -0
- data/spec/observable_spec.rb +116 -0
- data/spec/output_buffer_spec.rb +37 -0
- data/spec/record_array_spec.rb +50 -0
- data/spec/route_spec.rb +89 -0
- data/spec/router_spec.rb +103 -0
- data/spec/spec_helper.rb +53 -0
- data/spec/template_view_spec.rb +47 -0
- data/spec/vendor/jquery.js +2 -0
- data/spec/view_spec.rb +78 -0
- metadata +181 -0
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class AccessingAttributesSpec < Vienna::Model
|
4
|
+
attributes :first_name, :last_name
|
5
|
+
|
6
|
+
def last_name=(name)
|
7
|
+
raise "Cannot set last_name"
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
describe Vienna::Model do
|
12
|
+
|
13
|
+
let(:model) { AccessingAttributesSpec.new }
|
14
|
+
|
15
|
+
describe "#[]" do
|
16
|
+
it "retrieves attributes from the model" do
|
17
|
+
model[:first_name].should be_nil
|
18
|
+
model.first_name = "Adam"
|
19
|
+
model[:first_name].should eq("Adam")
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe "#[]=" do
|
24
|
+
it "sets attributes on the model" do
|
25
|
+
model[:first_name] = "Adam"
|
26
|
+
model.first_name.should eq("Adam")
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Vienna::Model do
|
4
|
+
describe "#as_json" do
|
5
|
+
let(:model) { User.new }
|
6
|
+
|
7
|
+
it "returns a hash" do
|
8
|
+
expect(model.as_json).to be_kind_of(Hash)
|
9
|
+
end
|
10
|
+
|
11
|
+
it "contains all attributes on model" do
|
12
|
+
expect(model.as_json).to eq({ "foo" => nil, "bar" => nil, "baz" => nil })
|
13
|
+
|
14
|
+
model.foo = "Adam"
|
15
|
+
expect(model.as_json).to eq({ "foo" => "Adam", "bar" => nil, "baz" => nil })
|
16
|
+
|
17
|
+
model.bar = "Beynon"
|
18
|
+
|
19
|
+
expect(model.as_json).to eq({ "foo" => "Adam", "bar" => "Beynon", "baz" => nil })
|
20
|
+
end
|
21
|
+
|
22
|
+
it "includes the id, if set" do
|
23
|
+
model.id = 42
|
24
|
+
|
25
|
+
expect(model.as_json).to eq({ "id" => 42, "foo" => nil, "bar" => nil, "baz" => nil })
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Vienna::Model do
|
4
|
+
describe ".attribute" do
|
5
|
+
let(:model) { User.new }
|
6
|
+
|
7
|
+
it "should create a reader method for attribute" do
|
8
|
+
expect(model).to respond_to(:foo)
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should create a writer method for attribute" do
|
12
|
+
expect(model).to respond_to(:foo=)
|
13
|
+
end
|
14
|
+
|
15
|
+
describe "writer" do
|
16
|
+
it "sets value on model" do
|
17
|
+
model.foo = 'Tommy'
|
18
|
+
expect(model.foo).to eq('Tommy')
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Vienna::Model do
|
4
|
+
describe "#initialize" do
|
5
|
+
it "should have all nil values for attributes when passed no attrs" do
|
6
|
+
model = User.new
|
7
|
+
|
8
|
+
expect(model.foo).to be_nil
|
9
|
+
expect(model.bar).to be_nil
|
10
|
+
expect(model.baz).to be_nil
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should set a given value for a given attributes" do
|
14
|
+
model = User.new foo: 3.142
|
15
|
+
|
16
|
+
expect(model.foo).to eq(3.142)
|
17
|
+
expect(model.bar).to be_nil
|
18
|
+
expect(model.baz).to be_nil
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should be able to set many attributes" do
|
22
|
+
model = User.new foo: 'hello', bar: 'world', baz: 42
|
23
|
+
|
24
|
+
expect(model.foo).to eq('hello')
|
25
|
+
expect(model.bar).to eq('world')
|
26
|
+
expect(model.baz).to eq(42)
|
27
|
+
end
|
28
|
+
|
29
|
+
it "creates @attributes as an empty hash" do
|
30
|
+
model = User.new
|
31
|
+
model.instance_variable_get(:@attributes).should eq({})
|
32
|
+
end
|
33
|
+
|
34
|
+
it "marks the model as being a new record" do
|
35
|
+
expect(User.new).to be_new_record
|
36
|
+
end
|
37
|
+
|
38
|
+
it "marks the model as not being loaded" do
|
39
|
+
expect(User.new).to_not be_loaded
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Vienna::Model do
|
4
|
+
describe "#load" do
|
5
|
+
let(:model) { SimpleModel.new }
|
6
|
+
|
7
|
+
it "marks the model instance as loaded" do
|
8
|
+
model.load({})
|
9
|
+
expect(model).to be_loaded
|
10
|
+
end
|
11
|
+
|
12
|
+
it "marks the model as not being a new record" do
|
13
|
+
model.load({})
|
14
|
+
expect(model).to_not be_new_record
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Vienna::Model do
|
4
|
+
let(:model_class) { SimpleModel }
|
5
|
+
let(:model) { model_class.new }
|
6
|
+
let(:loaded_model) { model_class.load(:first_name => "Adam", id: 872) }
|
7
|
+
describe "#did_destroy" do
|
8
|
+
it "triggers a :destroy event on the record" do
|
9
|
+
called = false
|
10
|
+
model.on(:destroy) { called = true }
|
11
|
+
model.did_destroy
|
12
|
+
called.should eq(true)
|
13
|
+
end
|
14
|
+
|
15
|
+
it "triggers a :destroy event on the class" do
|
16
|
+
called = false
|
17
|
+
model_class.on(:destroy) { called = true }
|
18
|
+
model.did_destroy
|
19
|
+
called.should eq(true)
|
20
|
+
end
|
21
|
+
|
22
|
+
it "removes the record from the class identity_map" do
|
23
|
+
loaded_model.did_destroy
|
24
|
+
model_class.identity_map[loaded_model.id].should eq(nil)
|
25
|
+
end
|
26
|
+
|
27
|
+
it "removes the record from the class record_array" do
|
28
|
+
loaded_model.did_destroy
|
29
|
+
model_class.all.should_not include(loaded_model)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe '#destroyed?' do
|
34
|
+
it 'is false for "living" models' do
|
35
|
+
model.destroyed?.should be_falsey
|
36
|
+
end
|
37
|
+
|
38
|
+
it "is true for destroyed models" do
|
39
|
+
loaded_model.did_destroy
|
40
|
+
loaded_model.destroyed?.should be_truthy
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe "#did_create" do
|
45
|
+
it "sets @new_record to false" do
|
46
|
+
model.did_create
|
47
|
+
model.new_record?.should eq(false)
|
48
|
+
end
|
49
|
+
|
50
|
+
it "adds record to class identity_map" do
|
51
|
+
model.id = 863
|
52
|
+
model.did_create
|
53
|
+
model.class.identity_map[863].should eq(model)
|
54
|
+
end
|
55
|
+
|
56
|
+
it "adds record to class record array" do
|
57
|
+
model.class.all.should == []
|
58
|
+
model.did_create
|
59
|
+
model.class.all.should == [model]
|
60
|
+
end
|
61
|
+
|
62
|
+
it "triggers a :create event on the record" do
|
63
|
+
called = false
|
64
|
+
model.on(:create) { called = true }
|
65
|
+
model.did_create
|
66
|
+
called.should eq(true)
|
67
|
+
end
|
68
|
+
|
69
|
+
it "triggers a :create event on the class" do
|
70
|
+
called = false
|
71
|
+
model.class.on(:create) { called = true }
|
72
|
+
model.did_create
|
73
|
+
called.should eq(true)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
describe ".all" do
|
78
|
+
it "is a record array of all models" do
|
79
|
+
model.class.all.should == []
|
80
|
+
model.did_create
|
81
|
+
model.class.all.should == [model]
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
data/spec/model_spec.rb
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Vienna::Model do
|
4
|
+
describe ".new" do
|
5
|
+
it "should set @new_record to true" do
|
6
|
+
SimpleModel.new.new_record?.should eq(true)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
describe ".primary_key" do
|
11
|
+
it "should have a default primary key" do
|
12
|
+
SimpleModel.primary_key.should eq(:id)
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should be changeable" do
|
16
|
+
AdvancedModel.primary_key.should eq(:title)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe ".load" do
|
21
|
+
it "raises an ArgumentError if no id present" do
|
22
|
+
lambda {
|
23
|
+
SimpleModel.load({})
|
24
|
+
}.should raise_error(ArgumentError)
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should be able to load models with own primary_key" do
|
28
|
+
AdvancedModel.load(title: 100).should be_kind_of(AdvancedModel)
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should set @new_record to false on the model" do
|
32
|
+
model = SimpleModel.load(id: 42)
|
33
|
+
model.new_record?.should eq(false)
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should cache model" do
|
37
|
+
SimpleModel.identity_map[8].should be_nil
|
38
|
+
model = SimpleModel.load(id: 8)
|
39
|
+
SimpleModel.identity_map[8].should eq(model)
|
40
|
+
end
|
41
|
+
|
42
|
+
it "saves the model in .all record array" do
|
43
|
+
SimpleModel.all.should == []
|
44
|
+
model = SimpleModel.load(id: 10)
|
45
|
+
SimpleModel.all.should == [model]
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should update existing models" do
|
49
|
+
foo = SimpleModel.load(id: 9, name: 'Adam')
|
50
|
+
bar = SimpleModel.load(id: 9, name: 'Beynon')
|
51
|
+
foo.should equal(bar)
|
52
|
+
foo.name.should eq("Beynon")
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
describe ".load_json" do
|
57
|
+
it "should load a model from native json/js object" do
|
58
|
+
obj = `{"id": 13, "name": "Bob"}`
|
59
|
+
model = SimpleModel.load_json obj
|
60
|
+
model.id.should eq(13)
|
61
|
+
model.name.should eq("Bob")
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
describe ".adapter" do
|
66
|
+
it "sets a new instance of the passed adapter as @adapter" do
|
67
|
+
klass = Class.new(Vienna::Model) do
|
68
|
+
adapter Vienna::Adapter
|
69
|
+
end
|
70
|
+
|
71
|
+
klass.instance_variable_get(:@adapter).should be_kind_of(Vienna::Adapter)
|
72
|
+
end
|
73
|
+
|
74
|
+
it "returns the adapter set on the model subclass" do
|
75
|
+
klass = Class.new(Vienna::Model) { adapter Vienna::Adapter }
|
76
|
+
klass.adapter.should be_kind_of(Vienna::Adapter)
|
77
|
+
end
|
78
|
+
|
79
|
+
it "raises an error when no adapter set on model subclass" do
|
80
|
+
klass = Class.new(Vienna::Model)
|
81
|
+
lambda { klass.adapter }.should raise_error(Exception)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,130 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'vienna/observable_array'
|
3
|
+
|
4
|
+
class ObservableArraySpec
|
5
|
+
include Vienna::ObservableArray
|
6
|
+
end
|
7
|
+
|
8
|
+
describe Vienna::ObservableArray do
|
9
|
+
let(:klass) { ObservableArraySpec }
|
10
|
+
let(:empty) { klass.new }
|
11
|
+
let(:foobar) { klass.new([:foo, :bar]) }
|
12
|
+
|
13
|
+
describe ".new" do
|
14
|
+
it "takes an optional content" do
|
15
|
+
klass.new.content.should == []
|
16
|
+
klass.new([1, 2, 3]).content.should == [1, 2, 3]
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe "#<<" do
|
21
|
+
it "pushes each object into the content" do
|
22
|
+
empty << :foo
|
23
|
+
empty << :bar
|
24
|
+
empty << :baz
|
25
|
+
|
26
|
+
empty.content.should == [:foo, :bar, :baz]
|
27
|
+
end
|
28
|
+
|
29
|
+
it "generates a change event for starting index and single added item" do
|
30
|
+
expect(empty).to receive(:array_content_did_change).once.with(0, 0, 1)
|
31
|
+
empty << :some_object
|
32
|
+
|
33
|
+
expect(foobar).to receive(:array_content_did_change).once.with(2, 0, 1)
|
34
|
+
foobar << :other_object
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe "#delete" do
|
39
|
+
it "deletes the object from the content array" do
|
40
|
+
foobar.delete :foo
|
41
|
+
foobar.content.should == [:bar]
|
42
|
+
end
|
43
|
+
|
44
|
+
it "notifies observers with single remove object" do
|
45
|
+
expect(foobar).to receive(:array_content_did_change).once.with(1, 1, 0)
|
46
|
+
foobar.delete :bar
|
47
|
+
end
|
48
|
+
|
49
|
+
it "has no effect when object not present" do
|
50
|
+
expect(foobar).to_not receive(:array_content_did_change)
|
51
|
+
foobar.delete :baz
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
describe "#insert" do
|
56
|
+
it "adds the object to the content array at specified index" do
|
57
|
+
empty.insert 0, :foo
|
58
|
+
empty.content.should == [:foo]
|
59
|
+
|
60
|
+
foobar.insert 1, :baz
|
61
|
+
foobar.content.should == [:foo, :baz, :bar]
|
62
|
+
end
|
63
|
+
|
64
|
+
it "notifies observers with single added object at index" do
|
65
|
+
expect(empty).to receive(:array_content_did_change).once.with(0, 0, 1)
|
66
|
+
empty.insert 0, :omg
|
67
|
+
|
68
|
+
expect(foobar).to receive(:array_content_did_change).once.with(1, 0, 1)
|
69
|
+
foobar.insert 1, :wow
|
70
|
+
end
|
71
|
+
|
72
|
+
it "raises an ArgumentError for index out of range" do
|
73
|
+
expect { empty.insert 2, :foo }.to raise_error(ArgumentError)
|
74
|
+
expect { foobar.insert 90, :foo }.to raise_error(ArgumentError)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
describe "#clear" do
|
79
|
+
it "removes all items from the content array" do
|
80
|
+
empty.clear
|
81
|
+
empty.content.should == []
|
82
|
+
|
83
|
+
foobar.clear
|
84
|
+
foobar.content.should == []
|
85
|
+
end
|
86
|
+
|
87
|
+
it "notifies observers to remove all existing objects" do
|
88
|
+
expect(empty).to receive(:array_content_did_change).once.with(0, 0, 0)
|
89
|
+
empty.clear
|
90
|
+
|
91
|
+
expect(foobar).to receive(:array_content_did_change).once.with(0, 2, 0)
|
92
|
+
foobar.clear
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
describe "#array_content_did_change" do
|
97
|
+
it "triggers a :size attribute change" do
|
98
|
+
called = false
|
99
|
+
empty.add_observer(:size) { called = true }
|
100
|
+
empty.clear
|
101
|
+
|
102
|
+
called.should == true
|
103
|
+
end
|
104
|
+
|
105
|
+
it "triggers a :content attribute change" do
|
106
|
+
called = false
|
107
|
+
empty.add_observer(:content) { called = true }
|
108
|
+
empty.clear
|
109
|
+
|
110
|
+
called.should == true
|
111
|
+
end
|
112
|
+
|
113
|
+
it "triggers a :empty? attribute change" do
|
114
|
+
called = false
|
115
|
+
empty.add_observer(:empty?) { called = true }
|
116
|
+
empty.clear
|
117
|
+
|
118
|
+
called.should == true
|
119
|
+
end
|
120
|
+
|
121
|
+
it "notifies each observer added using add_array_observer" do
|
122
|
+
observer = double(:observer)
|
123
|
+
expect(observer).to receive(:array_did_change).once.with(empty, 0, 0, 0)
|
124
|
+
|
125
|
+
empty.add_array_observer observer
|
126
|
+
|
127
|
+
empty.clear
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'vienna/observable'
|
3
|
+
|
4
|
+
class ObservableSpec
|
5
|
+
include Vienna::Observable
|
6
|
+
|
7
|
+
attr_accessor :foo, :bar, :baz
|
8
|
+
|
9
|
+
def baz=(b)
|
10
|
+
@baz = b + 10
|
11
|
+
end
|
12
|
+
|
13
|
+
def bar=(b)
|
14
|
+
@bar = b
|
15
|
+
"#bar"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe Vienna::Observable do
|
20
|
+
|
21
|
+
let(:object) { ObservableSpec.new }
|
22
|
+
|
23
|
+
describe "#replace_writer_for" do
|
24
|
+
it "still calls the original method using super" do
|
25
|
+
object.replace_writer_for(:foo)
|
26
|
+
object.baz = 100
|
27
|
+
object.baz.should eq(110)
|
28
|
+
end
|
29
|
+
|
30
|
+
it "does not add a setter unless an existing attribute= method exists" do
|
31
|
+
object.replace_writer_for(:bob)
|
32
|
+
object.should_not respond_to(:bob=)
|
33
|
+
end
|
34
|
+
|
35
|
+
it "the new writer calls attribute_did_change with attribute name" do
|
36
|
+
object.replace_writer_for(:foo)
|
37
|
+
def object.attribute_did_change(attribute); @_called = attribute; end
|
38
|
+
|
39
|
+
object.instance_variable_get(:@_called).should be_nil
|
40
|
+
object.foo = 100
|
41
|
+
object.instance_variable_get(:@_called).should eq(:foo)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe "#add_observer" do
|
46
|
+
it "handlers can be added to observe specific attributes" do
|
47
|
+
count = 0
|
48
|
+
object.add_observer(:foo) { count += 1 }
|
49
|
+
|
50
|
+
object.foo = 100
|
51
|
+
count.should eq(1)
|
52
|
+
|
53
|
+
object.foo = 150
|
54
|
+
count.should eq(2)
|
55
|
+
end
|
56
|
+
|
57
|
+
it "allows more than one handler to be added for an attribute" do
|
58
|
+
result = []
|
59
|
+
object.add_observer(:foo) { result << :first }
|
60
|
+
object.add_observer(:foo) { result << :second }
|
61
|
+
|
62
|
+
object.foo = 42
|
63
|
+
result.should eq([:first, :second])
|
64
|
+
|
65
|
+
object.foo = 3.142
|
66
|
+
result.should eq([:first, :second, :first, :second])
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
describe "#attribute_did_change" do
|
71
|
+
it "does not break for an object with no observers" do
|
72
|
+
object.attribute_did_change(:foo_bar)
|
73
|
+
end
|
74
|
+
|
75
|
+
it "does not break when given an attriubte with no observers (but another observable exists)" do
|
76
|
+
object.add_observer(:foo) {}
|
77
|
+
object.attribute_did_change(:bar)
|
78
|
+
end
|
79
|
+
|
80
|
+
it "passes new value to each handler" do
|
81
|
+
result = nil
|
82
|
+
object.add_observer(:foo) { |val| result = val }
|
83
|
+
|
84
|
+
object.foo = 42
|
85
|
+
result.should eq(42)
|
86
|
+
|
87
|
+
object.foo = 3.142
|
88
|
+
result.should eq(3.142)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
describe "#remove_observer" do
|
93
|
+
it "has no effect when no observers setup for attribute" do
|
94
|
+
object.remove_observer(:foo, proc {})
|
95
|
+
end
|
96
|
+
|
97
|
+
it "has no effect if the handler doesnt exist for attribute" do
|
98
|
+
p = proc {}
|
99
|
+
object.add_observer(:foo) {}
|
100
|
+
object.remove_observer(:foo, p)
|
101
|
+
end
|
102
|
+
|
103
|
+
it "removes an existing handler for given attribute" do
|
104
|
+
count = 0
|
105
|
+
handler = proc { count += 1 }
|
106
|
+
object.add_observer(:foo, &handler)
|
107
|
+
|
108
|
+
object.foo = 42
|
109
|
+
count.should eq(1)
|
110
|
+
|
111
|
+
object.remove_observer(:foo, handler)
|
112
|
+
object.foo = 49
|
113
|
+
count.should eq(1)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|