save_queue 0.2.3 → 0.3.0
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/.gitignore +13 -4
- data/.travis.yml +4 -1
- data/CONTRIBUTING.md +120 -0
- data/HISTORY.md +11 -0
- data/LICENSE +13 -4
- data/README.md +282 -55
- data/Rakefile +10 -3
- data/lib/save_queue/exceptions.rb +13 -0
- data/lib/save_queue/object.rb +41 -18
- data/lib/save_queue/object_queue.rb +87 -0
- data/lib/save_queue/plugins/notification/object.rb +35 -0
- data/lib/save_queue/plugins/notification/queue.rb +25 -0
- data/lib/save_queue/plugins/notification.rb +15 -0
- data/lib/save_queue/plugins/validation/exceptions.rb +12 -0
- data/lib/save_queue/plugins/validation/queue.rb +16 -17
- data/lib/save_queue/plugins/validation.rb +4 -17
- data/lib/save_queue/ruby1.9/observer.rb +204 -0
- data/lib/save_queue/uniq_queue.rb +38 -0
- data/lib/save_queue/version.rb +1 -1
- data/lib/save_queue.rb +1 -0
- data/save_queue.gemspec +4 -3
- data/spec/notification/notification_spec.rb +45 -0
- data/spec/notification/object_spec.rb +54 -0
- data/spec/notification/queue_spec.rb +28 -0
- data/spec/object_queue_spec.rb +155 -0
- data/spec/object_spec.rb +208 -0
- data/spec/save_queue_spec.rb +75 -0
- data/spec/support/object_helpers.rb +10 -0
- data/spec/support/queue_helpers.rb +26 -0
- data/spec/uniq_queue_spec.rb +132 -0
- data/spec/validation/queue_spec.rb +139 -0
- data/spec/validation/validation_spec.rb +42 -0
- metadata +35 -20
- data/lib/save_queue/plugins/validation/object.rb +0 -25
- data/lib/save_queue/queue.rb +0 -45
- data/spec/save_queue_usage_spec.rb +0 -311
- data/spec/support/mock_helpers.rb +0 -17
- data/spec/validation_spec.rb +0 -126
@@ -0,0 +1,54 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "save_queue/plugins/notification/object"
|
3
|
+
|
4
|
+
class NotifyObject
|
5
|
+
include SaveQueue
|
6
|
+
include SaveQueue::Plugins::Notification::Object
|
7
|
+
end
|
8
|
+
|
9
|
+
describe SaveQueue::Plugins::Notification::Object do
|
10
|
+
|
11
|
+
it "should register observer on queue to #queue_changed_event method" do
|
12
|
+
NotifyObject.queue_class.any_instance.should_receive(:add_observer).with do |observer, method|
|
13
|
+
observer.is_a?(NotifyObject) and method == :queue_changed_event
|
14
|
+
end
|
15
|
+
NotifyObject.new
|
16
|
+
end
|
17
|
+
|
18
|
+
let(:queue) do
|
19
|
+
queue_class = Class.new
|
20
|
+
queue_class.stub(:include?).with(Hooks).and_return(true)
|
21
|
+
|
22
|
+
queue_class
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should raise an exception if queue does not respond to #add_observer" do
|
26
|
+
queue.any_instance.stub(:respond_to?).with(:add_observer).and_return(false)
|
27
|
+
NotifyObject.queue_class = queue
|
28
|
+
expect { NotifyObject.new }.to raise_error(RuntimeError, /add_observer/)
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should not raise an exception if queue respond to #add_observer" do
|
32
|
+
queue.any_instance.stub(:respond_to?).with(:add_observer).and_return(true)
|
33
|
+
queue.any_instance.stub(:add_observer)
|
34
|
+
NotifyObject.queue_class = queue
|
35
|
+
expect { NotifyObject.new }.to_not raise_error
|
36
|
+
end
|
37
|
+
|
38
|
+
describe "#queue_changed_event" do
|
39
|
+
let(:object) do
|
40
|
+
NotifyObject.any_instance.stub(:create_queue)
|
41
|
+
NotifyObject.new
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should mark self as changed" do
|
45
|
+
object.should_receive(:mark_as_changed)
|
46
|
+
object.send :queue_changed_event, true, stub(:some_object)
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should not mark self as changed if result of adding element to a queue was false" do
|
50
|
+
object.should_not_receive(:mark_as_changed)
|
51
|
+
object.send :queue_changed_event, false, stub(:some_object)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "save_queue/plugins/notification/queue"
|
3
|
+
|
4
|
+
class NotifyQueue < SaveQueue::ObjectQueue
|
5
|
+
include SaveQueue::Plugins::Notification::Queue
|
6
|
+
end
|
7
|
+
|
8
|
+
describe SaveQueue::Plugins::Notification::Queue do
|
9
|
+
let(:queue) { NotifyQueue.new }
|
10
|
+
|
11
|
+
[:add, :<<, :push].each do |method|
|
12
|
+
describe "##{method}" do
|
13
|
+
let(:element) { new_element }
|
14
|
+
|
15
|
+
it "should notify observers about change" do
|
16
|
+
queue.should_receive(:changed)
|
17
|
+
queue.should_receive(:notify_observers)
|
18
|
+
queue.send method, element
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should notify observer, provided result of a method call and input object" do
|
22
|
+
queue.should_receive(:changed)
|
23
|
+
queue.should_receive(:notify_observers).with(true, element)
|
24
|
+
queue.send method, element
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,155 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "save_queue/object_queue"
|
3
|
+
|
4
|
+
describe SaveQueue::ObjectQueue do
|
5
|
+
let(:queue) { SaveQueue::ObjectQueue.new }
|
6
|
+
let(:element) { new_element(:element) }
|
7
|
+
|
8
|
+
[:add, :<<, :push].each do |method|
|
9
|
+
describe "##{method}" do
|
10
|
+
#it "should add only objects that implement SaveQueue::Object interface" do
|
11
|
+
it "should accept objects that respond to #save and #has_unsaved_changes?" do
|
12
|
+
element = stub(:element, :save => true, :has_unsaved_changes? => true)
|
13
|
+
expect{ queue.send method, element }.not_to raise_error
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should not accept objects that does not respond to #save" do
|
17
|
+
element.unstub(:save)
|
18
|
+
expect{ queue.send method, element }.to raise_error ArgumentError, "#{element.inspect} does not respond to #save"
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should not accept objects that does not respond to #has_unsaved_changes?" do
|
22
|
+
element.unstub(:has_unsaved_changes?)
|
23
|
+
expect{ queue.send method, element }.to raise_error ArgumentError, "#{element.inspect} does not respond to #has_unsaved_changes?"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
it "#<< method should be able to add objects in chain" do
|
29
|
+
queue << new_element << new_element
|
30
|
+
queue.should have(2).elements
|
31
|
+
end
|
32
|
+
|
33
|
+
describe "#save" do
|
34
|
+
it "should save all object in queue" do
|
35
|
+
5.times do
|
36
|
+
element = stub(:element, :has_unsaved_changes? => true)
|
37
|
+
element.should_receive(:save).once
|
38
|
+
queue << element
|
39
|
+
end
|
40
|
+
|
41
|
+
queue.save
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should save an object if it has unsaved changes" do
|
45
|
+
element = stub(:element)
|
46
|
+
element.stub(:has_unsaved_changes?).and_return(true)
|
47
|
+
element.should_receive(:save).once
|
48
|
+
|
49
|
+
queue << element
|
50
|
+
queue.save
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should not save an object if it has not been changed" do
|
54
|
+
element = stub(:element)
|
55
|
+
element.stub(:has_unsaved_changes?).and_return(false)
|
56
|
+
element.should_not_receive(:save)
|
57
|
+
|
58
|
+
queue << element
|
59
|
+
queue.save
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should save an object if it has changed state after been added to a queue" do
|
63
|
+
element = new_element(:element, :changed => false, :saved => true)
|
64
|
+
|
65
|
+
queue << element
|
66
|
+
|
67
|
+
element.stub(:has_unsaved_changes?).and_return(true)
|
68
|
+
|
69
|
+
element.should_receive(:save).once.and_return(true)
|
70
|
+
queue.save
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
context "at least one object in queue was not saved" do
|
75
|
+
before(:each) do
|
76
|
+
@objects ={}
|
77
|
+
queue << @objects[:valid1] = new_element(:valid1)
|
78
|
+
queue << @objects[:valid2] = new_element(:valid2)
|
79
|
+
queue << @objects[:not_changed] = new_element(:not_changed, :changed => false, :saved => true)
|
80
|
+
queue << @objects[:unsaved_but_changed] = new_element(:unsaved_but_changed, :changed => true, :saved => false)
|
81
|
+
queue << @objects[:saved] = new_element(:saved, :changed => true, :saved => true)
|
82
|
+
queue << @objects[:valid3] = new_element(:valid3)
|
83
|
+
end
|
84
|
+
|
85
|
+
describe "#save!" do
|
86
|
+
it "should set errors" do
|
87
|
+
expect {queue.save!}.to raise_error
|
88
|
+
|
89
|
+
queue.errors[:save].should_not be_empty
|
90
|
+
queue.errors.should eq :save => { :processed => @objects.values_at(:valid1, :valid2, :not_changed),
|
91
|
+
:saved => @objects.values_at(:valid1, :valid2),
|
92
|
+
:failed => @objects[:unsaved_but_changed],
|
93
|
+
:pending => @objects.values_at(:not_changed, :saved, :valid3) }
|
94
|
+
end
|
95
|
+
|
96
|
+
it "should raise SaveQueue::FailedSaveError" do
|
97
|
+
expect{ queue.save! }.to raise_error(SaveQueue::FailedSaveError) {|error| \
|
98
|
+
error.context.should == { :processed => @objects.values_at(:valid1, :valid2, :not_changed),
|
99
|
+
:saved => @objects.values_at(:valid1, :valid2),
|
100
|
+
:failed => @objects[:unsaved_but_changed],
|
101
|
+
:pending => @objects.values_at(:not_changed, :saved, :valid3) }
|
102
|
+
}
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
describe "#save" do
|
107
|
+
it "should return false" do
|
108
|
+
queue.save.should be_false
|
109
|
+
end
|
110
|
+
|
111
|
+
it "should set errors" do
|
112
|
+
queue.save
|
113
|
+
|
114
|
+
queue.errors[:save].should_not be_empty
|
115
|
+
queue.errors.should eq :save => { :processed => @objects.values_at(:valid1, :valid2, :not_changed),
|
116
|
+
:saved => @objects.values_at(:valid1, :valid2),
|
117
|
+
:failed => @objects[:unsaved_but_changed],
|
118
|
+
:pending => @objects.values_at(:not_changed, :saved, :valid3) }
|
119
|
+
end
|
120
|
+
|
121
|
+
it "should not raise SaveQueue::FailedSaveError" do
|
122
|
+
expect{ queue.save }.not_to raise_error(SaveQueue::FailedSaveError)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
context "after fixing all failed objects" do
|
127
|
+
before(:each) do
|
128
|
+
queue.save.should be_false
|
129
|
+
@objects[:unsaved_but_changed].stub(:save).and_return(true)
|
130
|
+
end
|
131
|
+
|
132
|
+
it "should save all pending objects" do
|
133
|
+
@objects.values_at(:saved, :valid3).each do |object|
|
134
|
+
object.should_receive(:save).once
|
135
|
+
end
|
136
|
+
|
137
|
+
queue.save.should be_true
|
138
|
+
end
|
139
|
+
|
140
|
+
it "should not save already saved objects" do
|
141
|
+
pending "rewrite this test as integration"
|
142
|
+
@objects.values_at(:valid1, :valid2, :not_changed).each do |object|
|
143
|
+
object.should_not_receive(:save)
|
144
|
+
end
|
145
|
+
|
146
|
+
queue.save.should be_true
|
147
|
+
end
|
148
|
+
|
149
|
+
it "should not have any errors" do
|
150
|
+
queue.save
|
151
|
+
queue.errors.should be_empty
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
data/spec/object_spec.rb
ADDED
@@ -0,0 +1,208 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "save_queue/object"
|
3
|
+
|
4
|
+
describe SaveQueue::Object do
|
5
|
+
let(:object) { new_object }
|
6
|
+
|
7
|
+
describe "#has_unsaved_changes?" do
|
8
|
+
it "should return true for changed object" do
|
9
|
+
object.mark_as_changed
|
10
|
+
object.should have_unsaved_changes
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should return false for unchanged object" do
|
14
|
+
object.mark_as_saved
|
15
|
+
object.should_not have_unsaved_changes
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should return false for new object" do
|
19
|
+
klass = Class.new
|
20
|
+
klass.send :include, SaveQueue::Object
|
21
|
+
|
22
|
+
klass.new.should_not have_unsaved_changes
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe "marks" do
|
27
|
+
it "should change state of an object" do
|
28
|
+
object.mark_as_saved
|
29
|
+
object.should_not have_unsaved_changes
|
30
|
+
object.mark_as_changed
|
31
|
+
object.should have_unsaved_changes
|
32
|
+
object.mark_as_saved
|
33
|
+
object.should_not have_unsaved_changes
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe "#save!" do
|
38
|
+
it "should delegate to save" do
|
39
|
+
object.save_queue.should_receive(:save!).once
|
40
|
+
object.save!
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe "#save" do
|
45
|
+
it "should save queue" do
|
46
|
+
object.save_queue.should_receive(:save).once
|
47
|
+
object.save
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should save itself" do
|
51
|
+
klass = Class.new do
|
52
|
+
def save
|
53
|
+
"saved!"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
klass.send :include, SaveQueue::Object
|
58
|
+
klass.new.save.should == "saved!"
|
59
|
+
end
|
60
|
+
|
61
|
+
context "object could not be saved" do
|
62
|
+
let(:object) do
|
63
|
+
klass = Class.new do
|
64
|
+
def save
|
65
|
+
false
|
66
|
+
end
|
67
|
+
end
|
68
|
+
klass.send :include, SaveQueue::Object
|
69
|
+
klass.new
|
70
|
+
end
|
71
|
+
|
72
|
+
it "should return false" do
|
73
|
+
object.save.should == false
|
74
|
+
end
|
75
|
+
|
76
|
+
it "should not save queue" do
|
77
|
+
object.save_queue.should_not_receive(:save)
|
78
|
+
object.save
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
|
83
|
+
it "should not circle" do
|
84
|
+
other_object = new_object
|
85
|
+
|
86
|
+
object.mark_as_changed
|
87
|
+
other_object.mark_as_changed
|
88
|
+
|
89
|
+
|
90
|
+
object .save_queue.add other_object
|
91
|
+
other_object.save_queue.add object
|
92
|
+
|
93
|
+
$object_counter = mock :counter
|
94
|
+
$object_counter.should_receive(:increment).once
|
95
|
+
|
96
|
+
def object.save
|
97
|
+
result = super
|
98
|
+
$object_counter.increment
|
99
|
+
|
100
|
+
result
|
101
|
+
end
|
102
|
+
|
103
|
+
$other_object_counter = mock :counter
|
104
|
+
$other_object_counter.should_receive(:increment).once
|
105
|
+
|
106
|
+
def other_object.save
|
107
|
+
result = super
|
108
|
+
$other_object_counter.increment
|
109
|
+
|
110
|
+
result
|
111
|
+
end
|
112
|
+
|
113
|
+
#object.should_receive(:save).once.and_return(true)
|
114
|
+
#@base.should_receive(:save).once.and_return(true)
|
115
|
+
other_object.save.should be_true
|
116
|
+
end
|
117
|
+
|
118
|
+
describe "multiple queues" do
|
119
|
+
let(:other_object) { new_object }
|
120
|
+
|
121
|
+
it "should save object only once" do
|
122
|
+
target = new_object
|
123
|
+
target.mark_as_changed
|
124
|
+
|
125
|
+
object .save_queue.add target
|
126
|
+
other_object.save_queue.add target
|
127
|
+
|
128
|
+
$counter = mock :counter
|
129
|
+
$counter.should_receive(:increment).once
|
130
|
+
|
131
|
+
def target.save
|
132
|
+
result = super
|
133
|
+
$counter.increment
|
134
|
+
|
135
|
+
result
|
136
|
+
end
|
137
|
+
|
138
|
+
#target.should_receive(:save).once.and_return(true)
|
139
|
+
object.save.should be_true
|
140
|
+
other_object.save.should be_true
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
describe "queue" do
|
146
|
+
let(:queue_class) { Class.new(SaveQueue::ObjectQueue) }
|
147
|
+
let(:other_queue_class) { Class.new(SaveQueue::ObjectQueue) }
|
148
|
+
|
149
|
+
it "should mapped to SaveQueue::ObjectQueue by default" do
|
150
|
+
klass = new_class
|
151
|
+
klass.queue_class.should be SaveQueue::ObjectQueue
|
152
|
+
end
|
153
|
+
|
154
|
+
describe "queue class change" do
|
155
|
+
it "before initialization should be possible" do
|
156
|
+
klass = new_class
|
157
|
+
klass.queue_class = other_queue_class
|
158
|
+
klass.new.save_queue.should be_kind_of other_queue_class
|
159
|
+
end
|
160
|
+
|
161
|
+
it "after initialization should not affect already created queue" do
|
162
|
+
klass = new_class
|
163
|
+
klass.queue_class = queue_class
|
164
|
+
object = klass.new
|
165
|
+
|
166
|
+
object.save_queue.should be_a queue_class
|
167
|
+
object.class.queue_class = other_queue_class
|
168
|
+
object.save_queue.should_not be_kind_of other_queue_class
|
169
|
+
object.save_queue.should be_a queue_class
|
170
|
+
end
|
171
|
+
|
172
|
+
it "should check dependencies for Hooks module" do
|
173
|
+
klass = new_class
|
174
|
+
expect{ klass.queue_class = Class.new }.to raise_error(RuntimeError, /Hooks/)
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
describe "inheritance" do
|
179
|
+
let(:klass) { new_class }
|
180
|
+
|
181
|
+
it "should inherit settings of parent class" do
|
182
|
+
klass.queue_class = queue_class
|
183
|
+
|
184
|
+
child = Class.new(klass)
|
185
|
+
child.queue_class.should == queue_class
|
186
|
+
end
|
187
|
+
|
188
|
+
it "should not override settings of parent class" do
|
189
|
+
klass.queue_class = queue_class
|
190
|
+
|
191
|
+
child = Class.new(klass)
|
192
|
+
child.queue_class = other_queue_class
|
193
|
+
child.queue_class.should == other_queue_class
|
194
|
+
|
195
|
+
klass.queue_class.should == queue_class
|
196
|
+
end
|
197
|
+
|
198
|
+
|
199
|
+
it "include SaveQueue::Object should not override settings of parent class" do
|
200
|
+
klass.queue_class = queue_class
|
201
|
+
|
202
|
+
child = Class.new(klass)
|
203
|
+
child.send :include, SaveQueue::Object
|
204
|
+
child.queue_class.should == queue_class
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "save_queue/object"
|
3
|
+
|
4
|
+
describe SaveQueue do
|
5
|
+
describe "#include" do
|
6
|
+
it "should include SaveQueue::Object" do
|
7
|
+
klass = Class.new
|
8
|
+
klass.send :include, SaveQueue
|
9
|
+
|
10
|
+
klass.should include SaveQueue::Object
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "functional" do
|
15
|
+
it "README example should work" do
|
16
|
+
article = Article.new
|
17
|
+
|
18
|
+
tag_objects = []
|
19
|
+
3.times do
|
20
|
+
tag = Tag.new
|
21
|
+
tag.change_attribute :title, "new tag"
|
22
|
+
tag.should_receive(:save).once
|
23
|
+
tag_objects << tag
|
24
|
+
end
|
25
|
+
article.tags = tag_objects
|
26
|
+
|
27
|
+
tag = Tag.new
|
28
|
+
tag.change_attribute :title, "single tag"
|
29
|
+
tag.should_receive(:save).once
|
30
|
+
article.add_tag tag
|
31
|
+
|
32
|
+
# that will save article and all tags in this article if article
|
33
|
+
# and tags are valid, and if article.save and all tag.save returns true
|
34
|
+
# You may also use #save! method, that will trigger save_queue.save! and
|
35
|
+
# raise SaveQueue::FailedSaveError on fail
|
36
|
+
article.save.should be_true
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
|
42
|
+
|
43
|
+
require 'save_queue'
|
44
|
+
class Article
|
45
|
+
include SaveQueue
|
46
|
+
|
47
|
+
def change_attribute attr, value
|
48
|
+
@attributes ||= {}
|
49
|
+
@attributes[attr] = value
|
50
|
+
mark_as_changed # call this and object will be marked for save
|
51
|
+
end
|
52
|
+
|
53
|
+
def tags= tag_objects
|
54
|
+
@tags = tag_objects
|
55
|
+
mark_as_changed
|
56
|
+
save_queue.add_all tag_objects
|
57
|
+
end
|
58
|
+
|
59
|
+
def add_tag tag
|
60
|
+
@tags ||= []
|
61
|
+
@tags << tag
|
62
|
+
save_queue.add tag # or use <<, push methods
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
|
67
|
+
class Tag
|
68
|
+
include SaveQueue
|
69
|
+
|
70
|
+
def change_attribute attr, value
|
71
|
+
@attributes ||= {}
|
72
|
+
@attributes[attr] = value
|
73
|
+
mark_as_changed # call this and object will be marked for save
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
def fill_queue
|
2
|
+
5.times do
|
3
|
+
queue << new_element
|
4
|
+
end
|
5
|
+
end
|
6
|
+
|
7
|
+
def new_element(name = :element, options = {})
|
8
|
+
element = stub(name)
|
9
|
+
element.stub(:save).and_return(options.has_key?(:saved) ? options[:saved] : true)
|
10
|
+
element.stub(:has_unsaved_changes?).and_return(options.has_key?(:changed) ? options[:changed] : true)
|
11
|
+
|
12
|
+
element
|
13
|
+
end
|
14
|
+
|
15
|
+
def new_velement(options = {:valid => true})
|
16
|
+
object = new_element
|
17
|
+
object.stub(:valid?).and_return(options[:valid])
|
18
|
+
object
|
19
|
+
end
|
20
|
+
|
21
|
+
def new_queue_class(options = {})
|
22
|
+
queue_class = Class.new
|
23
|
+
queue_class.stub(:include?).with(Hooks).and_return(true)
|
24
|
+
|
25
|
+
queue_class
|
26
|
+
end
|
@@ -0,0 +1,132 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "save_queue/uniq_queue"
|
3
|
+
|
4
|
+
describe SaveQueue::UniqQueue do
|
5
|
+
let(:queue) { SaveQueue::UniqQueue.new }
|
6
|
+
#let(:element) { new_element(:element) }
|
7
|
+
|
8
|
+
[:size, :count].each do |method|
|
9
|
+
describe "##{method}" do
|
10
|
+
it "should return 0 for empty queue" do
|
11
|
+
queue.send(method).should be_zero
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should count elements in queue" do
|
15
|
+
3.times do
|
16
|
+
queue << new_element
|
17
|
+
end
|
18
|
+
|
19
|
+
queue.send(method).should == 3
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe "#new" do
|
25
|
+
it "should be empty queue" do
|
26
|
+
queue.should have(0).elements
|
27
|
+
queue.should be_empty
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
[:add, :<<, :push].each do |method|
|
32
|
+
describe "##{method}" do
|
33
|
+
let(:element) { new_element }
|
34
|
+
it "should add object to a queue" do
|
35
|
+
queue.should be_empty
|
36
|
+
|
37
|
+
queue.send(method, new_element)
|
38
|
+
queue.should_not be_empty
|
39
|
+
queue.should have(1).elements
|
40
|
+
|
41
|
+
queue.send(method, new_element)
|
42
|
+
queue.should_not be_empty
|
43
|
+
queue.should have(2).elements
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should add object to a queue once" do
|
47
|
+
queue.should be_empty
|
48
|
+
|
49
|
+
queue.send(method, element)
|
50
|
+
queue.should have(1).elements
|
51
|
+
|
52
|
+
queue.send(method, element)
|
53
|
+
queue.should have(1).elements
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should return true" do
|
57
|
+
queue.send(method, element).should === true
|
58
|
+
end
|
59
|
+
|
60
|
+
it "should return false if element was not added" do
|
61
|
+
queue.send(method, element)
|
62
|
+
queue.should have(1).elements
|
63
|
+
|
64
|
+
queue.send(method, element).should === false
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
describe "#add_all" do
|
70
|
+
it "should delegate to #add" do
|
71
|
+
queue.should_receive(:add).exactly(3).times
|
72
|
+
queue.add_all [1,2,3]
|
73
|
+
end
|
74
|
+
|
75
|
+
it "should act as #add if single argument passed" do
|
76
|
+
queue.should_receive(:add).once
|
77
|
+
queue.add_all 1
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
|
82
|
+
describe "#clear" do
|
83
|
+
it "should clear the queue" do
|
84
|
+
fill_queue
|
85
|
+
#expect{ queue.clear }.to change{ queue.count }.from(5).to(0)
|
86
|
+
queue.should_not be_empty
|
87
|
+
queue.clear
|
88
|
+
queue.should be_empty
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
describe "#pop" do
|
93
|
+
it "should remove last element from queue and return it back" do
|
94
|
+
queue << new_element(:first)
|
95
|
+
queue << new_element
|
96
|
+
queue << new_element
|
97
|
+
last = new_element(:last)
|
98
|
+
queue << last
|
99
|
+
|
100
|
+
result = nil
|
101
|
+
expect{ result = queue.pop }.to change{ queue.count }.by(-1)
|
102
|
+
result.should_not be_nil
|
103
|
+
result.should be last
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
describe "#shift" do
|
108
|
+
it "should remove first element from queue and return it back" do
|
109
|
+
first = new_element(:first)
|
110
|
+
queue << first
|
111
|
+
queue << new_element
|
112
|
+
queue << new_element
|
113
|
+
queue << new_element(:last)
|
114
|
+
|
115
|
+
result = nil
|
116
|
+
expect{ result = queue.shift }.to change{ queue.count }.by(-1)
|
117
|
+
result.should_not be_nil
|
118
|
+
result.should be first
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
describe "delegates" do
|
123
|
+
let(:queue_var) { queue.instance_variable_get("@queue") }
|
124
|
+
|
125
|
+
SaveQueue::UniqQueue::DELEGATED_METHODS.each do |method|
|
126
|
+
it "##{method}\tshould delegate to @queue##{method}" do
|
127
|
+
queue_var.should_receive(method).once
|
128
|
+
queue.send method
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|