save_queue 0.3.0 → 0.4.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.
@@ -5,35 +5,25 @@ describe SaveQueue::ObjectQueue do
5
5
  let(:queue) { SaveQueue::ObjectQueue.new }
6
6
  let(:element) { new_element(:element) }
7
7
 
8
- [:add, :<<, :push].each do |method|
8
+ ADD_METHODS.each do |method|
9
9
  describe "##{method}" do
10
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)
11
+ it "should accept objects that respond to #save" do
12
+ element = stub(:element, :save => true)
13
13
  expect{ queue.send method, element }.not_to raise_error
14
14
  end
15
15
 
16
16
  it "should not accept objects that does not respond to #save" do
17
- element.unstub(:save)
17
+ element = stub(:element)
18
18
  expect{ queue.send method, element }.to raise_error ArgumentError, "#{element.inspect} does not respond to #save"
19
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
20
  end
26
21
  end
27
22
 
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
23
  describe "#save" do
34
- it "should save all object in queue" do
24
+ it "should save all objects in queue" do
35
25
  5.times do
36
- element = stub(:element, :has_unsaved_changes? => true)
26
+ element = stub
37
27
  element.should_receive(:save).once
38
28
  queue << element
39
29
  end
@@ -41,66 +31,67 @@ describe SaveQueue::ObjectQueue do
41
31
  queue.save
42
32
  end
43
33
 
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
34
+ it "should clear itself if saved successfully" do
35
+ #queue.should_receive(:clear).once
36
+ queue.save.should be_true
37
+ queue.should be_empty
51
38
  end
52
39
 
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
-
40
+ it "should fail if element#save returns boolean false" do
41
+ element = new_element
42
+ element.stub(:save).and_return(false)
58
43
  queue << element
59
- queue.save
44
+ queue.save.should be_false
60
45
  end
61
46
 
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)
47
+ it "should not fail if element#save returns other than boolean false" do
48
+ ["", 0, nil, "string", true, Class.new].each do |value|
49
+ element = new_element
50
+ element.stub(:save).and_return(value)
51
+ queue << element
52
+ end
68
53
 
69
- element.should_receive(:save).once.and_return(true)
70
- queue.save
54
+ queue.save.should be_true
71
55
  end
72
56
  end
73
57
 
74
58
  context "at least one object in queue was not saved" do
75
59
  before(:each) do
76
60
  @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)
61
+ queue << @objects[:valid1] = new_element(:valid1)
62
+ queue << @objects[:valid2] = new_element(:valid2)
63
+ queue << @objects[:unsaved] = new_element(:unsaved, :saved => false)
64
+ queue << @objects[:saved] = new_element(:saved, :saved => true)
65
+ queue << @objects[:valid3] = new_element(:valid3)
83
66
  end
84
67
 
85
68
  describe "#save!" do
86
69
  it "should set errors" do
87
- expect {queue.save!}.to raise_error
70
+ queue.save! rescue nil
88
71
 
89
72
  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) }
73
+ queue.errors.should eq :save => { :saved => @objects.values_at(:valid1, :valid2),
74
+ :failed => @objects[:unsaved],
75
+ :pending => @objects.values_at(:saved, :valid3) }
94
76
  end
95
77
 
96
78
  it "should raise SaveQueue::FailedSaveError" do
97
79
  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) }
80
+ error.context.should == { :saved => @objects.values_at(:valid1, :valid2),
81
+ :failed => @objects[:unsaved],
82
+ :pending => @objects.values_at(:saved, :valid3) }
102
83
  }
103
84
  end
85
+
86
+ # TODO remove duplication
87
+ it "should not clear queue" do
88
+ queue.should_not_receive(:clear)
89
+ queue.save! rescue nil
90
+ end
91
+
92
+ it "should not remove/add elements from/to queue" do
93
+ expect { queue.save! rescue nil }.to_not change { queue.size }.to raise_error
94
+ end
104
95
  end
105
96
 
106
97
  describe "#save" do
@@ -112,40 +103,39 @@ describe SaveQueue::ObjectQueue do
112
103
  queue.save
113
104
 
114
105
  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) }
106
+ queue.errors.should eq :save => { :saved => @objects.values_at(:valid1, :valid2),
107
+ :failed => @objects[:unsaved],
108
+ :pending => @objects.values_at(:saved, :valid3) }
119
109
  end
120
110
 
121
111
  it "should not raise SaveQueue::FailedSaveError" do
122
112
  expect{ queue.save }.not_to raise_error(SaveQueue::FailedSaveError)
123
113
  end
114
+
115
+ it "should not clear queue" do
116
+ queue.should_not_receive(:clear)
117
+ queue.save
118
+ end
119
+
120
+ it "should not remove/add elements from/to queue" do
121
+ expect { queue.save }.to_not change { queue.size }
122
+ end
124
123
  end
125
124
 
126
125
  context "after fixing all failed objects" do
127
126
  before(:each) do
128
127
  queue.save.should be_false
129
- @objects[:unsaved_but_changed].stub(:save).and_return(true)
128
+ @objects[:unsaved].stub(:save).and_return(true)
130
129
  end
131
130
 
132
- it "should save all pending objects" do
133
- @objects.values_at(:saved, :valid3).each do |object|
131
+ it "should save all objects" do
132
+ @objects.each_value do |object|
134
133
  object.should_receive(:save).once
135
134
  end
136
135
 
137
136
  queue.save.should be_true
138
137
  end
139
138
 
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
139
  it "should not have any errors" do
150
140
  queue.save
151
141
  queue.errors.should be_empty
data/spec/object_spec.rb CHANGED
@@ -4,205 +4,166 @@ require "save_queue/object"
4
4
  describe SaveQueue::Object do
5
5
  let(:object) { new_object }
6
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
7
  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
8
+ context "object" do
9
+ it "should call #save! on queue" do
10
+ object.save_queue.should_receive(:save!).once
11
+ object.save!
12
+ end
49
13
 
50
- it "should save itself" do
51
- klass = Class.new do
52
- def save
53
- "saved!"
14
+ context "original class has #save! method defined" do
15
+ it "should call that method" do
16
+ object =
17
+ Class.new do
18
+ include SaveQueue::Object
19
+ attr_reader :save_called
20
+ def save!
21
+ @save_called = true
22
+ end
23
+ end.new
24
+
25
+ expect{ object.save! }.to change { object.save_called }.from(nil).to(true)
54
26
  end
55
- end
56
27
 
57
- klass.send :include, SaveQueue::Object
58
- klass.new.save.should == "saved!"
59
- end
28
+ #it "call #save! 5 time in a row should call super#save! 5 times" do
29
+ # object = new_count_object
30
+ # expect do
31
+ # 5.times { object.save }
32
+ # end.to change { object.save_call_count }.from(0).to(5)
33
+ #end
34
+
35
+ context "and it raises an Exception" do
36
+ let(:object) do
37
+ Class.new do
38
+ include SaveQueue::Object
39
+ def save!
40
+ raise RuntimeError
41
+ end
42
+ end.new
43
+ end
60
44
 
61
- context "object could not be saved" do
62
- let(:object) do
63
- klass = Class.new do
64
- def save
65
- false
45
+ it "should raise an Exception" do
46
+ expect{ object.save! }.to raise_error(RuntimeError)
66
47
  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
48
 
76
- it "should not save queue" do
77
- object.save_queue.should_not_receive(:save)
78
- object.save
49
+ it "should not save queue" do
50
+ object.save_queue.should_not_receive(:save)
51
+ object.save! rescue nil
52
+ end
53
+ end
79
54
  end
80
55
  end
81
56
 
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
57
+ #it "should not circle" do
58
+ # object = new_count_object
59
+ # other_object = new_count_object
60
+ #
61
+ # object.save_queue.add other_object
62
+ # other_object.save_queue.add object
63
+ #
64
+ # other_object.save.should be_true
65
+ #
66
+ # other_object.save_call_count.should == 1
67
+ # object.save_call_count.should == 1
68
+ #end
92
69
 
93
- $object_counter = mock :counter
94
- $object_counter.should_receive(:increment).once
70
+ end
95
71
 
96
- def object.save
97
- result = super
98
- $object_counter.increment
72
+ describe "#save" do
99
73
 
100
- result
74
+ context "object" do
75
+ it "should save queue" do
76
+ object.save_queue.should_receive(:save).once
77
+ object.save
101
78
  end
102
79
 
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
80
+ context "original class has #save method defined" do
81
+ it "should call that method (save object)" do
82
+ object =
83
+ Class.new do
84
+ include SaveQueue::Object
85
+ attr_reader :save_called
86
+ def save
87
+ @save_called = true
88
+ end
89
+ end.new
90
+
91
+ expect{ object.save }.to change { object.save_called }.from(nil).to(true)
92
+ end
109
93
 
110
- result
111
- end
94
+ it "call #save 5 time in a row should call super#save 5 times" do
95
+ object = new_count_object
112
96
 
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
97
+ expect do
98
+ 5.times { object.save }
99
+ end.to change { object.save_call_count }.from(0).to(5)
100
+ end
117
101
 
118
- describe "multiple queues" do
119
- let(:other_object) { new_object }
102
+ context "and it return false" do
103
+ let(:object) { object_that_return(false) }
120
104
 
121
- it "should save object only once" do
122
- target = new_object
123
- target.mark_as_changed
105
+ it "should return false" do
106
+ object.save.should be_false
107
+ end
124
108
 
125
- object .save_queue.add target
126
- other_object.save_queue.add target
109
+ it "should not save queue" do
110
+ object.save_queue.should_not_receive(:save)
111
+ object.save
112
+ end
113
+ end
127
114
 
128
- $counter = mock :counter
129
- $counter.should_receive(:increment).once
115
+ context "and it return true" do
116
+ let(:object) { object_that_return(true) }
130
117
 
131
- def target.save
132
- result = super
133
- $counter.increment
118
+ it "should return true if queue saved successfully" do
119
+ object.save.should be_true
120
+ end
134
121
 
135
- result
122
+ it "should return false if queue not saved successfully" do
123
+ object.save_queue.stub(:save => false)
124
+ object.save.should be_false
125
+ end
136
126
  end
137
127
 
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
128
+ context "and it return nil" do
129
+ let(:object) { object_that_return(nil) }
144
130
 
145
- describe "queue" do
146
- let(:queue_class) { Class.new(SaveQueue::ObjectQueue) }
147
- let(:other_queue_class) { Class.new(SaveQueue::ObjectQueue) }
131
+ it "should return true if queue saved successfully" do
132
+ object.save.should eq true
133
+ end
148
134
 
149
- it "should mapped to SaveQueue::ObjectQueue by default" do
150
- klass = new_class
151
- klass.queue_class.should be SaveQueue::ObjectQueue
152
- end
135
+ it "should return false if queue not saved successfully" do
136
+ object.save_queue.stub(:save => false)
137
+ object.save.should eq false
138
+ end
139
+ end
153
140
 
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
141
+ context "and it return not a boolean value" do
142
+ let(:object) { object_that_return("some string") }
160
143
 
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
144
+ it "should return object#save result if queue saved successfully" do
145
+ object.save.should == "some string"
146
+ end
171
147
 
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/)
148
+ it "should return false if queue not saved successfully" do
149
+ object.save_queue.stub(:save => false)
150
+ object.save.should eq false
151
+ end
152
+ end
175
153
  end
176
154
  end
177
155
 
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
156
+ it "should not circle" do
157
+ object = new_count_object
158
+ other_object = new_count_object
197
159
 
160
+ object.save_queue.add other_object
161
+ other_object.save_queue.add object
198
162
 
199
- it "include SaveQueue::Object should not override settings of parent class" do
200
- klass.queue_class = queue_class
163
+ other_object.save.should be_true
201
164
 
202
- child = Class.new(klass)
203
- child.send :include, SaveQueue::Object
204
- child.queue_class.should == queue_class
205
- end
165
+ other_object.save_call_count.should == 1
166
+ object.save_call_count.should == 1
206
167
  end
207
168
  end
208
169
  end
@@ -10,66 +10,4 @@ describe SaveQueue do
10
10
  klass.should include SaveQueue::Object
11
11
  end
12
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
13
  end
@@ -7,4 +7,35 @@ def new_class
7
7
  klass.send :include, SaveQueue::Object
8
8
 
9
9
  klass
10
+ end
11
+
12
+ def changed_object_for(klass)
13
+ object = klass.new
14
+ object.mark_as_changed
15
+ object
16
+ end
17
+
18
+ def new_count_object
19
+ target_class = new_class
20
+ target_class.send :include, Count_mod
21
+ target_class.new
22
+ end
23
+
24
+ module Count_mod
25
+ def save_call_count
26
+ @save_call_count.to_i
27
+ end
28
+
29
+ def save
30
+ @save_call_count ||= 0
31
+ @save_call_count += 1
32
+ end
33
+ end
34
+
35
+ def object_that_return(value = nil, &block)
36
+ Class.new do
37
+ include SaveQueue::Object
38
+ s = block_given? ? block : lambda { value }
39
+ define_method :save, &s
40
+ end.new
10
41
  end
@@ -7,7 +7,6 @@ end
7
7
  def new_element(name = :element, options = {})
8
8
  element = stub(name)
9
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
10
 
12
11
  element
13
12
  end
@@ -24,3 +23,6 @@ def new_queue_class(options = {})
24
23
 
25
24
  queue_class
26
25
  end
26
+
27
+
28
+ ADD_METHODS = %w[add << push]