syrup_form_object 0.0.7 → 0.0.8

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/.travis.yml CHANGED
@@ -2,3 +2,6 @@ language: ruby
2
2
  rvm:
3
3
  - 2.0.0
4
4
  - 1.9.3
5
+ gemfile:
6
+ - gemfiles/rails3_2.gemfile
7
+ - gemfiles/rails4_0.gemfile
data/Gemfile CHANGED
@@ -1,3 +1,7 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
3
  gemspec
4
+
5
+ group :development do
6
+ gem 'rails', '~> 4.0'
7
+ end
@@ -0,0 +1,7 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec path: '../'
4
+
5
+ group :development do
6
+ gem 'rails', '~> 3.2'
7
+ end
@@ -0,0 +1,7 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec path: '../'
4
+
5
+ group :development do
6
+ gem 'rails', '~> 4.0'
7
+ end
data/lib/syrup.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  module Syrup
2
2
  end
3
3
 
4
+ require 'syrup/form'
4
5
  require 'syrup/form_object'
data/lib/syrup/form.rb ADDED
@@ -0,0 +1,5 @@
1
+ module Syrup::Form
2
+ end
3
+
4
+ require 'syrup/form/standalone'
5
+ require 'syrup/form/wrapped'
@@ -0,0 +1,27 @@
1
+ module Syrup::Form::Standalone
2
+ extend ActiveSupport::Concern
3
+
4
+ included do
5
+ def self.model_name
6
+ ActiveModel::Name.new(self, nil, self.class.name)
7
+ end
8
+ end
9
+
10
+ def persisted?
11
+ false
12
+ end
13
+
14
+ def new_record?
15
+ true
16
+ end
17
+
18
+
19
+ def readonly?
20
+ false
21
+ end
22
+
23
+ def wrapped?
24
+ false
25
+ end
26
+
27
+ end
@@ -0,0 +1,43 @@
1
+ module Syrup::Form::Wrapped
2
+ extend ActiveSupport::Concern
3
+
4
+ included do
5
+ alias_method :wrapped, @wrapped_class
6
+ alias_method :wrapped=, "#{@wrapped_class}="
7
+
8
+ def self.model_name
9
+ @wrapped_class.to_s.camelize.constantize.model_name
10
+ end
11
+ end
12
+
13
+ def method_missing(*params)
14
+ wrapped.send *params
15
+ end
16
+
17
+ def responds_to?(*params)
18
+ super || wrapped.responds_to?(*params)
19
+ end
20
+
21
+ def find_relations(params)
22
+ if params.is_a?(Hash)
23
+ super(params)
24
+ else
25
+ self.wrapped= self.wrapped.class.find(params)
26
+ end
27
+ end
28
+
29
+ def wrapped?
30
+ true
31
+ end
32
+
33
+ def new_record?
34
+ wrapped.new_record?
35
+ end
36
+
37
+ def persisted?
38
+ wrapped.persisted?
39
+ end
40
+
41
+
42
+ end
43
+
@@ -5,9 +5,17 @@ class Syrup::FormObject
5
5
 
6
6
  extend ActiveModel::Naming
7
7
  include ActiveModel::Conversion
8
- include ActiveModel::Validations
8
+ extend ActiveModel::Callbacks
9
+
10
+ include ActiveRecord::Persistence
11
+ include ActiveRecord::Transactions
12
+ include ActiveRecord::Validations
13
+ include ActiveModel::Validations::Callbacks
14
+ include ActiveSupport::Callbacks
15
+ include ActiveRecord::Callbacks
9
16
 
10
17
  class << self
18
+
11
19
  def accepts_nested_attributes_for(*relations)
12
20
  relations.each do |relation|
13
21
  build_attributes_setter relation
@@ -40,8 +48,12 @@ class Syrup::FormObject
40
48
 
41
49
  def wraps(klass)
42
50
  has_one(klass)
43
- alias_method :wrapped, klass
44
- alias_method :wrapped=, "#{klass}="
51
+ @wrapped_class = klass
52
+ include Syrup::Form::Wrapped
53
+ end
54
+
55
+ def standalone
56
+ include Syrup::Form::Standalone
45
57
  end
46
58
 
47
59
  def find(params)
@@ -51,16 +63,16 @@ class Syrup::FormObject
51
63
  form
52
64
  end
53
65
 
54
- end
55
-
56
- def method_missing(*params)
57
- wrapped.send *params
58
- end
66
+ def connection
67
+ ActiveRecord::Base.connection
68
+ end
59
69
 
60
- def responds_to?(*params)
61
- super || wrapped.responds_to?(*params)
62
70
  end
63
71
 
72
+ def remember_transaction_record_state(*); end
73
+ def restore_transaction_record_state(*); end
74
+ def clear_transaction_record_state(*); end
75
+ def self.reflect_on_association(*); end
64
76
  def initialize(params={})
65
77
  build_relations
66
78
  build(params)
@@ -79,14 +91,10 @@ class Syrup::FormObject
79
91
  end
80
92
 
81
93
  def find_relations(params)
82
- if params.is_a?(Hash)
83
- self.class.relations.each do |klass|
84
- if params[klass]
85
- self.send "#{klass}=", klass.to_s.camelize.constantize.find(params[klass])
86
- end
94
+ self.class.relations.each do |klass|
95
+ if params[klass]
96
+ self.send "#{klass}=", klass.to_s.camelize.constantize.find(params[klass])
87
97
  end
88
- else
89
- self.wrapped= self.wrapped.class.find(params)
90
98
  end
91
99
  end
92
100
 
@@ -106,10 +114,6 @@ class Syrup::FormObject
106
114
  def after_save; end
107
115
  def after_commit; end
108
116
 
109
- def persisted?
110
- respond_to?(:wrapped) && wrapped.persisted?
111
- end
112
-
113
117
  def transaction(&block)
114
118
  first_related_object.transaction(&block)
115
119
  end
@@ -118,34 +122,44 @@ class Syrup::FormObject
118
122
  respond_to?(:wrapped) ? wrapped : self.send(self.class.relations.first)
119
123
  end
120
124
 
121
- def save
122
- if self.class.relations.empty? && !respond_to?(:wrapped)
123
- after_save
124
- true
125
- else
126
- new_object= !persisted?
127
- saved = false
128
- transaction do
129
- before_save
130
- if new_object
131
- before_create
132
- end
133
- saved = self.class.relations.all? do |klass|
134
- self.send(klass).save
135
- end
136
- if !saved
137
- raise ActiveRecord::Rollback
138
- end
139
- if new_object
140
- after_create
141
- end
142
- after_save
143
- end
144
- if saved
145
- after_commit
125
+ def related_objects
126
+ related= {}
127
+ self.class.relations.collect do |klass|
128
+ related[klass] = self.send(klass)
129
+ end
130
+ related
131
+ end
132
+
133
+
134
+ def add_to_transaction; end
135
+
136
+ def run_validations!(*)
137
+ super
138
+ self.related_objects.each do |klass, related|
139
+ unless related.valid?
140
+ self.errors.add(klass, related.errors)
146
141
  end
147
- saved
148
142
  end
149
143
  end
150
144
 
145
+ def create_record
146
+ run_callbacks(:create) {save_form}
147
+ end
148
+
149
+ def update_record
150
+ run_callbacks(:update) {save_form}
151
+ end
152
+
153
+ def create
154
+ run_callbacks(:create) { save_form }
155
+ end
156
+
157
+ def update
158
+ run_callbacks(:update) { save_form }
159
+ end
160
+
161
+ def save_form
162
+ self.related_objects.all?{|klass, related| related.save }
163
+ end
164
+
151
165
  end
data/lib/syrup/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Syrup
2
- VERSION = '0.0.7'
2
+ VERSION = '0.0.8'
3
3
  end
@@ -0,0 +1,32 @@
1
+ require 'spec_helper'
2
+
3
+ class FakeConnection
4
+ def transaction(params)
5
+ end
6
+ end
7
+
8
+ class TestSubclassCallbacks < Syrup::FormObject
9
+ standalone
10
+
11
+ before_validation :fail_validate
12
+
13
+ class << self
14
+ def connection
15
+ FakeConnection.new
16
+ end
17
+ end
18
+
19
+ def fail_validate
20
+ errors.add(:base, 'Invalid')
21
+ end
22
+ end
23
+
24
+ describe TestSubclassCallbacks do
25
+ it 'responds to save' do
26
+ subject.save
27
+ end
28
+
29
+ it 'calls callbacks' do
30
+ expect(subject.valid?).to be_false
31
+ end
32
+ end
@@ -4,21 +4,31 @@ class TestItem
4
4
  include Virtus.model
5
5
  attribute :test_item_value, Integer
6
6
 
7
+ def self.model_name
8
+ ActiveModel::Name.new(self, nil, "test_item")
9
+ end
10
+
11
+ def errors
12
+ []
13
+ end
14
+
7
15
  def self.find(id)
8
16
  end
9
17
 
10
18
  def save
11
19
  end
12
20
 
13
- def transaction
14
- begin
15
- yield
16
- rescue ActiveRecord::Rollback
17
- @rollback = true
18
- end
21
+ def valid?
22
+ true
19
23
  end
20
24
 
21
- attr_reader :rollback
25
+ def readonly?
26
+ false
27
+ end
28
+
29
+ def new_record?
30
+ true
31
+ end
22
32
 
23
33
  def persisted?
24
34
  false
@@ -26,49 +36,85 @@ class TestItem
26
36
  end
27
37
 
28
38
  class TestSubclass < Syrup::FormObject
39
+ def self.transaction
40
+ begin
41
+ yield
42
+ rescue ActiveRecord::Rollback
43
+ false
44
+ end
45
+ end
46
+
29
47
  def build(params)
30
- @built = true
48
+ @built||=0
49
+ @built += 1
31
50
  end
32
51
 
33
52
  def has_called_build?
34
- @built
53
+ @built == 1
35
54
  end
36
55
 
37
56
  def after_find(params)
38
- @after_find = true
57
+ @after_find||=0
58
+ @after_find += 1
39
59
  end
40
60
 
41
61
  def has_called_after_find?
42
- @after_find
62
+ @after_find == 1
43
63
  end
44
64
 
65
+ after_save :after_save
66
+
45
67
  def after_save
46
- @after_save = true
68
+ @after_save||=0
69
+ @after_save += 1
47
70
  end
48
71
 
49
72
  def has_called_after_save?
50
- @after_save
73
+ @after_save == 1
51
74
  end
52
75
 
76
+ after_create :after_create
77
+
53
78
  def after_create
54
- @after_create = true
79
+ @after_create||=0
80
+ @after_create += 1
55
81
  end
56
82
 
57
83
  def has_called_after_create?
58
- @after_create
84
+ @after_create == 1
85
+ end
86
+
87
+ before_create :before_create
88
+
89
+ def before_create
90
+ @before_create||=0
91
+ @before_create += 1
92
+ end
93
+
94
+ def has_called_before_create?
95
+ @before_create == 1
96
+ end
97
+
98
+
99
+ after_rollback :after_rollback
100
+
101
+ def after_rollback
102
+ @after_rollback ||= 0
103
+ @after_rollback += 1
59
104
  end
60
105
 
61
106
  def has_called_rollback?
62
- @test_item.rollback
107
+ @after_rollback == 1
63
108
  end
64
109
 
65
110
 
66
111
  def after_commit
67
- @after_commit = true
112
+ @after_commit ||=0
113
+ @after_commit += 1
68
114
  end
69
115
 
70
116
  def has_called_after_commit?
71
- @after_commit
117
+ @after_commit == 1
72
118
  end
73
119
 
74
120
  end
@@ -86,7 +132,9 @@ describe Syrup::FormObject do
86
132
  context 'when using simple attributes' do
87
133
  let(:test_subclass) {
88
134
  Class.new(TestSubclass) do
135
+ standalone
89
136
  attribute :test_value, String
137
+ validates :test_value, presence: true
90
138
  end
91
139
  }
92
140
 
@@ -113,16 +161,45 @@ describe Syrup::FormObject do
113
161
  end
114
162
  end
115
163
 
116
- describe '#save' do
164
+ describe '#valid?' do
117
165
  let(:params) { {} }
166
+
118
167
  subject { test_subclass.new(params) }
119
- it 'calls after_save' do
120
- subject.save
168
+ context 'when the values are invalid' do
169
+ it 'returns false' do
170
+ expect(subject.valid?).to be_false
171
+ end
121
172
 
122
- expect(subject).to have_called_after_save
173
+ it 'adds the error message' do
174
+ subject.valid?
175
+
176
+ expect(subject.errors.full_messages).to eq ["Test value can't be blank"]
177
+ end
123
178
  end
124
179
  end
125
180
 
181
+ describe '#save' do
182
+ context 'when the values are invalid' do
183
+ let(:params) { {} }
184
+ subject { test_subclass.new(params) }
185
+ it 'calls after_save' do
186
+ subject.save
187
+
188
+ expect(subject).not_to have_called_after_save
189
+ end
190
+ end
191
+ context 'when the values are valid' do
192
+ let(:params) { {test_value:'a value'} }
193
+ subject { test_subclass.new(params) }
194
+ it 'calls after_save' do
195
+ subject.save
196
+
197
+ expect(subject).to have_called_after_save
198
+ end
199
+ end
200
+
201
+ end
202
+
126
203
  describe '#persisted?' do
127
204
  let(:params) { {} }
128
205
  subject { test_subclass.new(params) }
@@ -135,6 +212,7 @@ describe Syrup::FormObject do
135
212
  context 'when using nested attributes' do
136
213
  let(:test_subclass) {
137
214
  Class.new(TestSubclass) do
215
+ standalone
138
216
  has_one :test_item
139
217
  accepts_nested_attributes_for :test_item
140
218
  end
@@ -174,6 +252,30 @@ describe Syrup::FormObject do
174
252
  end
175
253
  end
176
254
 
255
+ describe '#valid?' do
256
+ let(:params) {{ test_item_attributes: {
257
+ test_item_value: '2'}}}
258
+
259
+ subject { test_subclass.new(params) }
260
+ context 'when the nested object is invalid' do
261
+ it 'returns false' do
262
+ subject.test_item.stub(:valid?) {false}
263
+ subject.test_item.stub(:errors) { "test item value can't be blank" }
264
+
265
+ expect(subject.valid?).to be_false
266
+ end
267
+
268
+ it 'adds the error message' do
269
+ subject.test_item.stub(:valid?) {false}
270
+ subject.test_item.stub(:errors) { "test item value can't be blank" }
271
+
272
+ subject.valid?
273
+
274
+ expect(subject.errors.full_messages).to eq ["Test item test item value can't be blank"]
275
+ end
276
+ end
277
+ end
278
+
177
279
  describe '#save' do
178
280
  let(:params) {{ test_item_attributes: {
179
281
  test_item_value: '2'}}}
@@ -205,7 +307,7 @@ describe Syrup::FormObject do
205
307
 
206
308
  expect(subject.save).to be_false
207
309
  end
208
- it 'raises a rollback exception' do
310
+ xit 'raises a rollback exception' do
209
311
  subject.test_item.stub(:save) {false}
210
312
 
211
313
  subject.save
@@ -282,6 +384,29 @@ describe Syrup::FormObject do
282
384
  end
283
385
  end
284
386
 
387
+ describe '#valid?' do
388
+ let(:params) {{ test_item_value: '2' }}
389
+
390
+ subject { test_subclass.new(params) }
391
+ context 'when the wrapped object is invalid' do
392
+ it 'returns false' do
393
+ subject.test_item.stub(:valid?) {false}
394
+ subject.test_item.stub(:errors) { "test item value can't be blank" }
395
+
396
+ expect(subject.valid?).to be_false
397
+ end
398
+
399
+ it 'adds the error message' do
400
+ subject.test_item.stub(:valid?) {false}
401
+ subject.test_item.stub(:errors) { "test item value can't be blank" }
402
+
403
+ subject.valid?
404
+
405
+ expect(subject.errors.full_messages).to eq ["Test item test item value can't be blank"]
406
+ end
407
+ end
408
+ end
409
+
285
410
  describe '#save' do
286
411
  let(:params) {{ test_item_value: '2' }}
287
412
 
@@ -300,7 +425,7 @@ describe Syrup::FormObject do
300
425
  end
301
426
  context 'when the object is new' do
302
427
  it 'calls after_create' do
303
- subject.wrapped.stub(:persisted?) { false }
428
+ subject.wrapped.stub(:new_record?) { true }
304
429
  subject.wrapped.stub(:save) { true }
305
430
 
306
431
  subject.save
@@ -310,7 +435,7 @@ describe Syrup::FormObject do
310
435
  end
311
436
  context 'when the object is not new' do
312
437
  it 'does not call after create' do
313
- subject.wrapped.stub(:persisted?) { true }
438
+ subject.wrapped.stub(:new_record?) { false }
314
439
  subject.wrapped.stub(:save) { true }
315
440
 
316
441
  subject.save
@@ -319,6 +444,14 @@ describe Syrup::FormObject do
319
444
  end
320
445
  end
321
446
 
447
+ context 'when the form is invalid' do
448
+ it 'returns false' do
449
+ subject.stub(:valid?) {false}
450
+
451
+ expect(subject.save).to be_false
452
+ end
453
+ end
454
+
322
455
  context 'when the object saves' do
323
456
  it 'returns true' do
324
457
  subject.test_item.stub(:save) { true }
@@ -332,7 +465,7 @@ describe Syrup::FormObject do
332
465
 
333
466
  expect(subject.save).to be_false
334
467
  end
335
- it 'raises a rollback exception' do
468
+ xit 'raises a rollback exception' do
336
469
  subject.test_item.stub(:save) {false}
337
470
 
338
471
  subject.save
@@ -351,9 +484,9 @@ describe Syrup::FormObject do
351
484
  let(:params) {{ test_item_value: '2' }}
352
485
  subject { test_subclass.find(params) }
353
486
  it 'forwards the message to the wrapped object' do
354
- subject.wrapped.stub(:persisted?) {:a_value}
487
+ subject.wrapped.stub(:new_record?) {true}
355
488
 
356
- expect(subject.persisted?).to be :a_value
489
+ expect(subject.new_record?).to be_true
357
490
  end
358
491
  end
359
492
  end
data/spec/spec_helper.rb CHANGED
@@ -1,26 +1,6 @@
1
1
  require 'rspec'
2
-
3
- class String
4
- def constantize
5
- Object.const_get(self)
6
- end
7
-
8
- def camelize
9
- string = sub(/^[a-z\d]*/) { $&.capitalize }
10
- string.gsub(/(?:_|(\/))([a-z\d]*)/) { "#{$1}#{$2.capitalize}" }
11
- end
12
- end
13
-
14
- module ActiveRecord
15
- class Rollback < StandardError; end
16
- end
17
-
18
- module ActiveModel
19
- module Naming; end
20
- module Conversion; end
21
- module Validations; end
22
- end
23
-
2
+ require 'active_record'
3
+ require 'active_record/errors'
24
4
  require 'syrup'
25
5
 
26
6
  RSpec.configure do |config|
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: syrup_form_object
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.7
4
+ version: 0.0.8
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-11-12 00:00:00.000000000 Z
12
+ date: 2013-11-15 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: virtus
@@ -75,9 +75,15 @@ files:
75
75
  - LICENSE
76
76
  - README.md
77
77
  - Rakefile
78
+ - gemfiles/rails3_2.gemfile
79
+ - gemfiles/rails4_0.gemfile
78
80
  - lib/syrup.rb
81
+ - lib/syrup/form.rb
82
+ - lib/syrup/form/standalone.rb
83
+ - lib/syrup/form/wrapped.rb
79
84
  - lib/syrup/form_object.rb
80
85
  - lib/syrup/version.rb
86
+ - spec/lib/syrup/callbacks_spec.rb
81
87
  - spec/lib/syrup/form_object_spec.rb
82
88
  - spec/spec_helper.rb
83
89
  - syrup_form_object.gemspec