syrup_form_object 0.0.7 → 0.0.8

Sign up to get free protection for your applications and to get access to all the features.
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