rom-rails 0.9.0 → 1.0.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/.rspec +2 -0
  3. data/.travis.yml +1 -0
  4. data/CHANGELOG.md +14 -0
  5. data/Gemfile +8 -5
  6. data/lib/generators/rom/commands/templates/create.rb.erb +5 -7
  7. data/lib/generators/rom/commands/templates/update.rb.erb +5 -7
  8. data/lib/generators/rom/relation/templates/relation.rb.erb +6 -4
  9. data/lib/rom-rails.rb +0 -1
  10. data/lib/rom/rails/configuration.rb +0 -2
  11. data/lib/rom/rails/version.rb +1 -1
  12. data/rom-rails.gemspec +2 -4
  13. data/spec/dummy/app/commands/create_user.rb +10 -0
  14. data/spec/dummy/app/commands/update_user.rb +9 -0
  15. data/spec/dummy/app/controllers/users_controller.rb +12 -8
  16. data/spec/dummy/app/forms/user_form.rb +29 -9
  17. data/spec/dummy/app/mappers/task_mapper.rb +1 -1
  18. data/spec/dummy/app/mappers/user_mapper.rb +1 -1
  19. data/spec/dummy/app/models/user.rb +1 -1
  20. data/spec/dummy/app/relations/dummy_relation.rb +2 -1
  21. data/spec/dummy/app/relations/tasks.rb +2 -0
  22. data/spec/dummy/app/relations/users.rb +2 -0
  23. data/spec/dummy/lib/rom/test_adapter.rb +1 -1
  24. data/spec/features/users_spec.rb +1 -3
  25. data/spec/integration/activerecord_setup.rb +1 -1
  26. data/spec/integration/initializer_spec.rb +1 -3
  27. data/spec/integration/logger_spec.rb +1 -3
  28. data/spec/integration/user_commands_spec.rb +7 -7
  29. data/spec/integration/user_model_mapping_spec.rb +2 -4
  30. data/spec/lib/active_record/configuration_spec.rb +1 -2
  31. data/spec/lib/generators/commands_generator_spec.rb +7 -17
  32. data/spec/lib/generators/mapper_generator_spec.rb +1 -3
  33. data/spec/lib/generators/relation_generator_spec.rb +4 -8
  34. data/spec/lib/generators/repository_generator_spec.rb +1 -3
  35. data/spec/spec_helper.rb +1 -1
  36. metadata +12 -61
  37. data/lib/generators/rom/form/templates/base_form.rb.erb +0 -17
  38. data/lib/generators/rom/form/templates/edit_form.rb.erb +0 -20
  39. data/lib/generators/rom/form/templates/new_form.rb.erb +0 -20
  40. data/lib/generators/rom/form_generator.rb +0 -47
  41. data/lib/rom/rails/model/form.rb +0 -173
  42. data/lib/rom/rails/model/form/class_interface.rb +0 -457
  43. data/lib/rom/rails/model/form/error_proxy.rb +0 -53
  44. data/spec/dummy/app/forms/new_user_form.rb +0 -13
  45. data/spec/dummy/app/forms/update_user_form.rb +0 -11
  46. data/spec/integration/form_with_injected_commands_spec.rb +0 -37
  47. data/spec/integration/new_user_form_spec.rb +0 -19
  48. data/spec/lib/generators/form_generator_spec.rb +0 -140
  49. data/spec/unit/form_spec.rb +0 -366
@@ -1,53 +0,0 @@
1
- module ROM
2
- module Model
3
- class Form
4
- # Proxy for form errors
5
- #
6
- # This simple proxy forwards most messages to a wrapped
7
- # ActiveModel::Errors object
8
- #
9
- # @api private
10
- class ErrorProxy < SimpleDelegator
11
- # @api private
12
- def initialize
13
- super ActiveModel::Errors.new([])
14
- end
15
-
16
- # update the current errors
17
- #
18
- # @param error [ActiveModel::Errors, ROM::Model::ValidatonError, object]
19
- #
20
- # When the argument is an AM Error object, or our wrapper around one,
21
- # replace the wrapped object. Otherwise, add an error to the current
22
- # messages
23
- #
24
- # @return [self]
25
- #
26
- # @api private
27
- def set(error)
28
- case error
29
- when ActiveModel::Errors
30
- __setobj__ error
31
- when ROM::Model::ValidationError
32
- __setobj__ error.errors
33
- when nil
34
- # do nothing
35
- else
36
- add(:base, "a database error prevented saving this form")
37
- end
38
-
39
- self
40
- end
41
-
42
- # Has the command succeeded?
43
- #
44
- # @return [Boolean]
45
- #
46
- # @api public
47
- def success?
48
- !present?
49
- end
50
- end
51
- end
52
- end
53
- end
@@ -1,13 +0,0 @@
1
- class NewUserForm < UserForm
2
- commands users: :create
3
-
4
- mappings users: :entity
5
-
6
- input do
7
- timestamps(:created_at)
8
- end
9
-
10
- def commit!
11
- users.try { users.create.call(attributes) }
12
- end
13
- end
@@ -1,11 +0,0 @@
1
- class UpdateUserForm < UserForm
2
- commands users: :update
3
-
4
- input do
5
- timestamps(:updated_at)
6
- end
7
-
8
- def commit!
9
- users.try { users.update.by_id(id).call(attributes) }
10
- end
11
- end
@@ -1,37 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe 'Form with injected commands' do
4
- subject(:form) { form_class.build(params) }
5
-
6
- let(:params) { { title: 'Task one' } }
7
-
8
- let(:form_class) do
9
- Class.new(ROM::Model::Form) do
10
- commands users: :create, tasks: :create
11
-
12
- inject_commands_for :tasks
13
-
14
- mappings tasks: :entity
15
-
16
- input do
17
- set_model_name 'Task'
18
-
19
- attribute :title
20
- end
21
-
22
- def commit!
23
- tasks.create[attributes]
24
- end
25
- end
26
- end
27
-
28
- it 'auto-maps result using injected commands' do
29
- form.save
30
-
31
- value = form.result
32
-
33
- expect(value).to be_a(Task)
34
- expect(value.id).to_not be(nil)
35
- expect(value.title).to eql('Task one')
36
- end
37
- end
@@ -1,19 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe NewUserForm do
4
- subject(:form) { NewUserForm.build(params) }
5
-
6
- let(:params) do
7
- { name: 'Jane', email: 'jane@doe.org' }
8
- end
9
-
10
- describe '#save' do
11
- it 'persists attributes and auto-map result to entity object' do
12
- form.save
13
-
14
- user = form.result.value
15
-
16
- expect(user).to eql(User.new(id: 1, name: 'Jane', email: 'jane@doe.org'))
17
- end
18
- end
19
- end
@@ -1,140 +0,0 @@
1
- require 'spec_helper'
2
-
3
- require 'generators/rom/form_generator'
4
-
5
- describe ROM::Generators::FormGenerator do
6
- destination File.expand_path('../../../../tmp', __FILE__)
7
-
8
- before(:each) do
9
- prepare_destination
10
- end
11
-
12
- shared_examples_for "generates a base user form" do
13
- it "populates a base form file" do
14
- expect(destination_root).to have_structure {
15
- directory 'app' do
16
- directory 'forms' do
17
- file 'user_form.rb' do
18
- contains <<-CONTENT.strip_heredoc
19
- class UserForm < ROM::Model::Form
20
-
21
- input do
22
- set_model_name 'User'
23
-
24
- # define always-present form input attributes
25
- # attribute :name, String
26
- end
27
-
28
- validations do
29
- relation :users
30
-
31
- # Add invariant form validations
32
- # validates :name, presence: true
33
- end
34
-
35
- end
36
- CONTENT
37
- end
38
- end
39
- end
40
- }
41
- end
42
- end
43
-
44
- shared_examples_for "generates a create user form" do
45
- it "populates a create form file" do
46
- expect(destination_root).to have_structure {
47
- directory 'app' do
48
- directory 'forms' do
49
- file 'new_user_form.rb' do
50
- contains <<-CONTENT.strip_heredoc
51
- class NewUserForm < UserForm
52
- commands users: :create
53
-
54
- input do
55
- # define form input attributes
56
- # attribute :name, String
57
-
58
- timestamps
59
- end
60
-
61
- validations do
62
- # Add form validations
63
- # validates :name, presence: true
64
- end
65
-
66
- def commit!
67
- users.try { users.create.call(attributes) }
68
- end
69
-
70
- end
71
- CONTENT
72
- end
73
- end
74
- end
75
- }
76
- end
77
- end
78
-
79
- shared_examples_for "generates an edit user form" do
80
- it "populates a edit form file" do
81
- expect(destination_root).to have_structure {
82
- directory 'app' do
83
- directory 'forms' do
84
- file 'edit_user_form.rb' do
85
- contains <<-CONTENT.strip_heredoc
86
- class EditUserForm < UserForm
87
- commands users: :update
88
-
89
- input do
90
- # define form input attributes
91
- # attribute :name, String
92
-
93
- timestamps :updated_at
94
- end
95
-
96
- validations do
97
- # Add form validations
98
- # validates :name, presence: true
99
- end
100
-
101
- def commit!
102
- users.try { users.update.by_id(id).set(attributes) }
103
- end
104
-
105
- end
106
- CONTENT
107
- end
108
- end
109
- end
110
- }
111
- end
112
- end
113
-
114
- describe "rom:form users" do
115
- before do
116
- run_generator ['users']
117
- end
118
-
119
- it_should_behave_like "generates a create user form"
120
- it_should_behave_like "generates an edit user form"
121
- end
122
-
123
- describe "rom:form users --command=create" do
124
- before do
125
- run_generator ['users', '--command=create']
126
- end
127
-
128
- it_should_behave_like "generates a base user form"
129
- it_should_behave_like "generates a create user form"
130
- end
131
-
132
- describe "rom:form users --command=update" do
133
- before do
134
- run_generator ['users', '--command=update']
135
- end
136
-
137
- it_should_behave_like "generates a base user form"
138
- it_should_behave_like "generates an edit user form"
139
- end
140
- end
@@ -1,366 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe 'Form' do
4
- subject(:form) do
5
- Class.new(ROM::Model::Form) do
6
- def self.name
7
- 'UserForm'
8
- end
9
-
10
- input do
11
- set_model_name 'User'
12
-
13
- attribute :email, String
14
- end
15
-
16
- validations do
17
- validates :email, presence: true
18
- end
19
-
20
- def commit!(*args)
21
- "it works #{args.inspect}"
22
- end
23
- end
24
- end
25
-
26
- describe '.build' do
27
- it 'rejects blank strings from params' do
28
- input = { 'name' => '' }
29
-
30
- form_object = form.build(input)
31
-
32
- expect(form_object.attributes.to_h).to eql(email: nil)
33
- end
34
-
35
- it 'exposes param values' do
36
- params = { 'email' => 'jane@doe.org' }
37
- form_object = form.build(params)
38
- expect(form_object.email).to eql('jane@doe.org')
39
-
40
- params = { email: 'jane@doe.org' }
41
- form_object = form.build(params)
42
- expect(form_object.email).to eql('jane@doe.org')
43
- end
44
- end
45
-
46
- describe '.commands' do
47
- it 'builds its own command registry' do
48
- form = Class.new(ROM::Model::Form) {
49
- inject_commands_for :tasks
50
- commands users: :create
51
- input { attribute :name }
52
- validations { validates :name, presence: true }
53
-
54
- def commit!
55
- users.try { users.create.call(attributes) }
56
- end
57
- }
58
-
59
- form_object = form.build(name: '').save
60
-
61
- expect(form_object).not_to be_success
62
- expect(form_object.errors[:name]).to include("can't be blank")
63
- expect(rom.relations.users.first).to be(nil)
64
-
65
- form_object = form.build(name: 'Jane').save
66
-
67
- expect(form_object).to be_success
68
- expect(rom.relations.users.first).to include(name: 'Jane')
69
-
70
- expect(form_object.tasks).to_not be(nil)
71
- end
72
- end
73
-
74
- describe '.key' do
75
- it 'returns default key' do
76
- expect(form.key).to eql([:id])
77
- expect(form.new({}, { id: 312 }).to_key).to eql([312])
78
- end
79
-
80
- it 'sets a custom composite key' do
81
- form = Class.new(ROM::Model::Form) do
82
- def self.name
83
- 'UserForm'
84
- end
85
-
86
- key :foo_id, :bar_id
87
-
88
- input do
89
- set_model_name 'User'
90
-
91
- attribute :email, String
92
- end
93
- end
94
-
95
- expect(form.key).to eql([:foo_id, :bar_id])
96
- expect(form.new({}, { foo_id: 312, bar_id: 132 }).to_key).to eql([312, 132])
97
- end
98
- end
99
-
100
- describe '.model_name' do
101
- it 'delegates to Attributes.model_name' do
102
- expect(form.model_name).to be(form.attributes.model_name)
103
- end
104
- end
105
-
106
- describe 'input DSL' do
107
- it 'defines params handler' do
108
- expect(form.const_defined?(:Attributes)).to be(true)
109
- expect(form.attributes.attribute_set.map(&:name)).to eql([:email])
110
- expect(form.attributes.model_name).to eql('User')
111
- end
112
-
113
- it 'defines a model' do
114
- expect(form.const_defined?(:Model)).to be(true)
115
- expect(form.model.attribute_set.map(&:name)).to match_array([:id, :email])
116
- end
117
-
118
- it 'raises error when attribute is in conflict with form interface' do
119
- expect {
120
- Class.new(ROM::Model::Form) do
121
- input do
122
- attribute :commit!
123
- end
124
- end
125
- }.to raise_error(ArgumentError, /commit! attribute is in conflict/)
126
- end
127
- end
128
-
129
- describe 'validator DSL' do
130
- it 'defines validator' do
131
- expect(form.const_defined?(:Validator)).to be(true)
132
-
133
- expect(form.validator).not_to be(nil)
134
-
135
- expect { form.validator.call(email: 'jane@doe') }.not_to raise_error
136
-
137
- expect { form.validator.call(email: '') }.to raise_error(
138
- ROM::Model::ValidationError
139
- )
140
- end
141
- end
142
-
143
- describe '#model_name' do
144
- it 'delegates to model' do
145
- form_object = form.build
146
- expect(form_object.model_name).to be(form_object.model.model_name)
147
- end
148
- end
149
-
150
- describe '#persisted?' do
151
- it 'delegates to model' do
152
- form_object = form.build
153
- expect(form_object).not_to be_persisted
154
- expect(form_object.persisted?).to be(form_object.model.persisted?)
155
-
156
- form_object = form.build({}, { id: 1 })
157
- expect(form_object).to be_persisted
158
- expect(form_object.persisted?).to be(form_object.model.persisted?)
159
- end
160
- end
161
-
162
- describe '#to_model' do
163
- context 'with a new model' do
164
- it 'returns model object without key set' do
165
- model = form.build(email: 'jane@doe').to_model
166
-
167
- expect(model.id).to be(nil)
168
- expect(model.model_name).to eql('User')
169
- expect(model.to_key).to eql([])
170
- expect(model.to_param).to be(nil)
171
- expect(model).not_to be_persisted
172
- end
173
- end
174
-
175
- context 'with a persisted model' do
176
- it 'returns model object with key set' do
177
- model = form.build({ email: 'jane@doe' }, { id: 312 }).to_model
178
-
179
- expect(model.id).to be(312)
180
- expect(model.model_name).to eql('User')
181
- expect(model.to_key).to eql([312])
182
- expect(model.to_param).to eql('312')
183
- expect(model).to be_persisted
184
- end
185
- end
186
- end
187
-
188
- describe '#save' do
189
- it 'commits the form without extra args' do
190
- result = form.build({email: 'jdoe@example.com'}).save.result
191
- expect(result).to eql('it works []')
192
- end
193
-
194
- it 'commits the form with extra args' do
195
- result = form.build({email: 'jdoe@example.com'}).save(1, 2, 3).result
196
- expect(result).to eql('it works [1, 2, 3]')
197
- end
198
- end
199
-
200
- describe "#errors" do
201
- context "with a new model" do
202
- it "exposes an activemodel compatible error" do
203
- errors = form.build({}).errors
204
-
205
- expect(errors).to respond_to(:[])
206
- expect(errors).to respond_to(:empty?)
207
- expect(errors).to respond_to(:blank?)
208
-
209
- expect(errors[:email]).to eq []
210
- end
211
- end
212
-
213
- it "recovers from database errors" do
214
- form = Class.new(ROM::Model::Form) do
215
- commands users: :create
216
-
217
- input do
218
- set_model_name 'User'
219
-
220
- attribute :email, String
221
- end
222
-
223
- def commit!(*)
224
- users.try {
225
- raise ROM::SQL::ConstraintError, RuntimeError.new("duplicate key")
226
- }
227
- end
228
- end
229
-
230
- expect {
231
- form.build(email: 'test@example.com').save
232
- }.to raise_error(ROM::SQL::ConstraintError)
233
- end
234
- end
235
-
236
- describe "#attributes" do
237
- it "returns processed attributes" do
238
- form = Class.new(ROM::Model::Form) do
239
- def self.name
240
- 'UserForm'
241
- end
242
-
243
- key :foo_id, :bar_id
244
-
245
- input do
246
- set_model_name 'User'
247
-
248
- attribute :uid, Integer
249
- end
250
- end
251
-
252
- form_object = form.build(uid: "12345")
253
- expect(form_object.attributes[:uid]).to eq 12_345
254
- end
255
- end
256
-
257
- describe "#validate!" do
258
- it "runs validations and assigns errors" do
259
- form_object = form.build({})
260
- form_object.validate!
261
-
262
- expect(form_object.errors[:email]).to include "can't be blank"
263
- end
264
-
265
- it "uses processed parameters" do
266
- form = Class.new(ROM::Model::Form) do
267
- def self.name
268
- 'UserForm'
269
- end
270
-
271
- key :foo_id, :bar_id
272
-
273
- input do
274
- set_model_name 'User'
275
-
276
- attribute :email, String
277
- attribute :country, String, default: "Unkown"
278
- end
279
-
280
- validations do
281
- validates :email, presence: true
282
- validates :country, presence: true
283
- end
284
- end
285
-
286
- form_object = form.build(uid: "12345")
287
- form_object.validate!
288
-
289
- expect(form_object.errors[:country]).to be_blank
290
- end
291
- end
292
-
293
- describe 'inheritance' do
294
- let(:child_form) do
295
- Class.new(form) do
296
- def self.name
297
- "NewUserForm"
298
- end
299
- end
300
- end
301
-
302
- it 'copies model_name' do
303
- expect(child_form.model_name.name).to eql(form.model_name.name)
304
- end
305
-
306
- it 'copies input' do
307
- expect(child_form.attributes.attribute_set[:email]).to_not be(nil)
308
- expect(child_form.attributes).to_not be(form.attributes)
309
- end
310
-
311
- it 'expands input' do
312
- child_form = Class.new(form) do
313
- def self.name
314
- "NewUserForm"
315
- end
316
-
317
- input do
318
- attribute :login, String
319
- end
320
- end
321
-
322
- expect(child_form.attributes.attribute_set[:login]).to_not be(nil)
323
- expect(child_form.attributes.attribute_set[:email]).to_not be(nil)
324
-
325
- expect(child_form.attributes).to_not be(form.attributes)
326
- end
327
-
328
- it 'copies model' do
329
- expect(child_form.model.attribute_set[:email]).to_not be(nil)
330
- expect(child_form.model).to_not be(form.model)
331
- end
332
-
333
- it 'copies validator' do
334
- expect(child_form.validator.validators.first).to be_instance_of(
335
- ActiveModel::Validations::PresenceValidator
336
- )
337
- expect(child_form.validator).to_not be(form.validator)
338
- end
339
-
340
- it "expands existing validators" do
341
- child_form = Class.new(form) do
342
- def self.name
343
- "NewUserForm"
344
- end
345
-
346
- input do
347
- attribute :login, String
348
- end
349
-
350
- validations do
351
- validates :login, length: { minimum: 4 }
352
- end
353
- end
354
-
355
- expect(child_form.validator.validators.first).to be_instance_of(
356
- ActiveModel::Validations::PresenceValidator
357
- )
358
-
359
- expect(child_form.validator.validators.last).to be_instance_of(
360
- ActiveModel::Validations::LengthValidator
361
- )
362
-
363
- expect(child_form.validator).to_not be(form.validator)
364
- end
365
- end
366
- end