rom-rails 0.2.1 → 0.3.0.beta1

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.
Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +26 -0
  3. data/CHANGELOG.md +17 -0
  4. data/README.md +4 -0
  5. data/lib/generators/rom/commands/templates/create.rb.erb +10 -0
  6. data/lib/generators/rom/commands/templates/delete.rb.erb +7 -0
  7. data/lib/generators/rom/commands/templates/update.rb.erb +10 -0
  8. data/lib/generators/rom/commands_generator.rb +33 -5
  9. data/lib/generators/rom/form/templates/edit_form.rb.erb +24 -0
  10. data/lib/generators/rom/form/templates/new_form.rb.erb +24 -0
  11. data/lib/generators/rom/form_generator.rb +39 -0
  12. data/lib/generators/rom/mapper/templates/mapper.rb.erb +9 -11
  13. data/lib/generators/rom/mapper_generator.rb +11 -1
  14. data/lib/generators/rom/relation/templates/relation.rb.erb +3 -2
  15. data/lib/generators/rom/relation_generator.rb +16 -1
  16. data/lib/rom-rails.rb +0 -5
  17. data/lib/rom/model.rb +7 -90
  18. data/lib/rom/rails/active_record/configuration.rb +105 -0
  19. data/lib/rom/rails/configuration.rb +4 -27
  20. data/lib/rom/rails/model/form.rb +59 -0
  21. data/lib/rom/rails/model/form/dsl.rb +173 -0
  22. data/lib/rom/rails/model/params.rb +72 -0
  23. data/lib/rom/rails/model/validator.rb +74 -0
  24. data/lib/rom/rails/model/validator/uniqueness_validator.rb +39 -0
  25. data/lib/rom/rails/railtie.rb +65 -29
  26. data/lib/rom/rails/version.rb +1 -1
  27. data/rom-rails.gemspec +3 -1
  28. data/spec/dummy/app/commands/tasks.rb +5 -0
  29. data/spec/dummy/app/commands/users.rb +4 -10
  30. data/spec/dummy/app/controllers/users_controller.rb +30 -0
  31. data/spec/dummy/app/forms/new_user_form.rb +9 -0
  32. data/spec/dummy/app/forms/update_user_form.rb +9 -0
  33. data/spec/dummy/app/forms/user_form.rb +15 -0
  34. data/spec/dummy/app/mappers/users.rb +6 -6
  35. data/spec/dummy/app/relations/tasks.rb +9 -0
  36. data/spec/dummy/app/relations/users.rb +5 -1
  37. data/spec/dummy/app/views/users/edit.html.erb +6 -0
  38. data/spec/dummy/app/views/users/new.html.erb +6 -0
  39. data/spec/dummy/config/routes.rb +5 -1
  40. data/spec/dummy/db/migrate/20141110205016_add_users.rb +2 -0
  41. data/spec/dummy/db/migrate/20150202194440_create_tasks.rb +7 -0
  42. data/spec/dummy/db/schema.rb +8 -8
  43. data/spec/dummy/spec/features/users_spec.rb +30 -0
  44. data/spec/dummy/spec/integration/logger_spec.rb +1 -1
  45. data/spec/dummy/spec/integration/user_commands_spec.rb +2 -18
  46. data/spec/dummy/spec/integration/user_model_mapping_spec.rb +2 -2
  47. data/spec/dummy/spec/integration/user_params_spec.rb +30 -15
  48. data/spec/lib/active_record/configuration_spec.rb +98 -0
  49. data/spec/lib/generators/commands_generator_spec.rb +54 -14
  50. data/spec/lib/generators/form_generator_spec.rb +89 -0
  51. data/spec/lib/generators/mapper_generator_spec.rb +10 -12
  52. data/spec/lib/generators/relation_generator_spec.rb +16 -6
  53. data/spec/spec_helper.rb +1 -1
  54. data/spec/unit/form_spec.rb +297 -0
  55. data/spec/unit/{model_spec.rb → params_spec.rb} +0 -0
  56. data/spec/unit/validator_spec.rb +75 -0
  57. metadata +72 -20
  58. data/lib/generators/rom/commands/templates/commands.rb.erb +0 -15
  59. data/spec/dummy/app/controllers/concerns/.keep +0 -0
  60. data/spec/dummy/app/params/user_params.rb +0 -7
  61. data/spec/dummy/app/validators/user_validator.rb +0 -3
@@ -14,19 +14,17 @@ describe ROM::Generators::MapperGenerator do
14
14
  expect(destination_root).to have_structure {
15
15
  directory 'app' do
16
16
  directory 'mappers' do
17
- file 'users.rb' do
17
+ file 'user_mapper.rb' do
18
18
  contains <<-CONTENT.strip_heredoc
19
- ROM.mappers do
20
-
21
- define(:users) do
22
- # specify model and attributes ie
23
- #
24
- # model User
25
- #
26
- # attribute :name
27
- # attribute :email
28
- end
29
-
19
+ class UserMapper < ROM::Mapper
20
+ # relation :users
21
+ #
22
+ # specify model and attributes ie
23
+ #
24
+ # model User
25
+ #
26
+ # attribute :name
27
+ # attribute :email
30
28
  end
31
29
  CONTENT
32
30
  end
@@ -2,27 +2,30 @@ require 'spec_helper'
2
2
 
3
3
  require 'generators/rom/relation_generator'
4
4
 
5
- describe ROM::Generators::RelationGenerator do
5
+ describe ROM::Generators::RelationGenerator, type: :generator do
6
6
  destination File.expand_path('../../../../tmp', __FILE__)
7
7
 
8
- before(:all) do
8
+ before(:each) do
9
9
  prepare_destination
10
- run_generator ['users']
11
10
  end
12
11
 
13
12
  specify do
13
+ run_generator ['users']
14
+ default_adapter = ROM.adapters.keys.first
15
+
14
16
  expect(destination_root).to have_structure {
15
17
  directory 'app' do
16
18
  directory 'relations' do
17
- file 'users.rb' do
19
+ file 'users_relation.rb' do
18
20
  contains <<-CONTENT.strip_heredoc
19
- ROM.relation(:users) do
21
+ class UsersRelation < ROM::Relation[:#{default_adapter}]
22
+ dataset :users
23
+
20
24
  # define your methods here ie:
21
25
  #
22
26
  # def all
23
27
  # select(:id, :name).order(:id)
24
28
  # end
25
- #
26
29
  end
27
30
  CONTENT
28
31
  end
@@ -30,4 +33,11 @@ describe ROM::Generators::RelationGenerator do
30
33
  end
31
34
  }
32
35
  end
36
+
37
+ specify "with given adapter" do
38
+ run_generator ['users', '--adapter=memory']
39
+
40
+ relation = File.read(File.join(destination_root, 'app', 'relations', 'users_relation.rb'))
41
+ expect(relation).to include("class UsersRelation < ROM::Relation[:memory]")
42
+ end
33
43
  end
data/spec/spec_helper.rb CHANGED
@@ -25,5 +25,5 @@ RSpec.configure do |config|
25
25
  end
26
26
 
27
27
  def rom
28
- Rails.application.config.rom.env
28
+ ROM.env
29
29
  end
@@ -0,0 +1,297 @@
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 = {
29
+ 'name' => 'Jane',
30
+ 'hash' => { 'one' => '', 'two' => 2 },
31
+ 'array' => [{ 'three' => '', 'four' => 4 }, 5]
32
+ }
33
+
34
+ form_object = form.build(input)
35
+
36
+ expect(form_object.params).to eql(
37
+ name: 'Jane', hash: { two: 2 }, array: [{ four: 4 }, 5]
38
+ )
39
+ end
40
+ end
41
+
42
+ describe '.commands' do
43
+ it 'builds its own command registry' do
44
+ form = Class.new(ROM::Model::Form) {
45
+ inject_commands_for :tasks
46
+ commands users: :create
47
+ input { attribute :name }
48
+ validations { validates :name, presence: true }
49
+
50
+ def commit!
51
+ users.try { users.create.call(params) }
52
+ end
53
+ }
54
+
55
+ form_object = form.build(name: '').save
56
+
57
+ expect(form_object).not_to be_success
58
+ expect(form_object.errors[:name]).to include("can't be blank")
59
+ expect(rom.relations.users.first).to be(nil)
60
+
61
+ form_object = form.build(name: 'Jane').save
62
+
63
+ expect(form_object).to be_success
64
+ expect(rom.relations.users.first).to include(name: 'Jane')
65
+
66
+ expect(form_object.tasks).to be(rom.command(:tasks))
67
+ end
68
+ end
69
+
70
+ describe '.key' do
71
+ it 'returns default key' do
72
+ expect(form.key).to eql([:id])
73
+ expect(form.new({}, { id: 312 }).to_key).to eql([312])
74
+ end
75
+
76
+ it 'sets a custom composite key' do
77
+ form = Class.new(ROM::Model::Form) do
78
+ def self.name
79
+ 'UserForm'
80
+ end
81
+
82
+ key :foo_id, :bar_id
83
+
84
+ input do
85
+ set_model_name 'User'
86
+
87
+ attribute :email, String
88
+ end
89
+ end
90
+
91
+ expect(form.key).to eql([:foo_id, :bar_id])
92
+ expect(form.new({}, { foo_id: 312, bar_id: 132 }).to_key).to eql([312, 132])
93
+ end
94
+ end
95
+
96
+ describe '.model_name' do
97
+ it 'delegates to Params.model_name' do
98
+ expect(form.model_name).to be(form.params.model_name)
99
+ end
100
+ end
101
+
102
+ describe 'input DSL' do
103
+ it 'defines params handler' do
104
+ expect(form.const_defined?(:Params)).to be(true)
105
+ expect(form.params.attribute_set.map(&:name)).to eql([:email])
106
+ expect(form.params.model_name).to eql('User')
107
+ end
108
+
109
+ it 'defines a model' do
110
+ expect(form.const_defined?(:Model)).to be(true)
111
+ expect(form.model.attribute_set.map(&:name)).to match_array([:id, :email])
112
+ end
113
+
114
+ it 'raises error when attribute is in conflict with form interface' do
115
+ expect {
116
+ Class.new(ROM::Model::Form) do
117
+ input do
118
+ attribute :commit!
119
+ end
120
+ end
121
+ }.to raise_error(ArgumentError, /commit! attribute is in conflict/)
122
+ end
123
+ end
124
+
125
+ describe 'validator DSL' do
126
+ it 'defines validator' do
127
+ expect(form.const_defined?(:Validator)).to be(true)
128
+
129
+ expect(form.validator).not_to be(nil)
130
+
131
+ expect { form.validator.call(email: 'jane@doe') }.not_to raise_error
132
+
133
+ expect { form.validator.call(email: '') }.to raise_error(
134
+ ROM::Model::ValidationError
135
+ )
136
+ end
137
+ end
138
+
139
+ describe '#model_name' do
140
+ it 'delegates to model' do
141
+ form_object = form.build
142
+ expect(form_object.model_name).to be(form_object.model.model_name)
143
+ end
144
+ end
145
+
146
+ describe '#persisted?' do
147
+ it 'delegates to model' do
148
+ form_object = form.build
149
+ expect(form_object).not_to be_persisted
150
+ expect(form_object.persisted?).to be(form_object.model.persisted?)
151
+
152
+ form_object = form.build({}, { id: 1 })
153
+ expect(form_object).to be_persisted
154
+ expect(form_object.persisted?).to be(form_object.model.persisted?)
155
+ end
156
+ end
157
+
158
+ describe '#to_model' do
159
+ context 'with a new model' do
160
+ it 'returns model object without key set' do
161
+ model = form.build(email: 'jane@doe').to_model
162
+
163
+ expect(model.id).to be(nil)
164
+ expect(model.model_name).to eql('User')
165
+ expect(model.to_key).to eql([])
166
+ expect(model.to_param).to be(nil)
167
+ expect(model).not_to be_persisted
168
+ end
169
+ end
170
+
171
+ context 'with a persisted model' do
172
+ it 'returns model object with key set' do
173
+ model = form.build({ email: 'jane@doe' }, { id: 312 }).to_model
174
+
175
+ expect(model.id).to be(312)
176
+ expect(model.model_name).to eql('User')
177
+ expect(model.to_key).to eql([312])
178
+ expect(model.to_param).to eql('312')
179
+ expect(model).to be_persisted
180
+ end
181
+ end
182
+ end
183
+
184
+ describe '#save' do
185
+ it 'commits the form without extra args' do
186
+ result = form.build({}).save.result
187
+ expect(result).to eql('it works []')
188
+ end
189
+
190
+ it 'commits the form with extra args' do
191
+ result = form.build({}).save(1, 2, 3).result
192
+ expect(result).to eql('it works [1, 2, 3]')
193
+ end
194
+ end
195
+
196
+ describe "#errors" do
197
+ context "with a new model" do
198
+ it "exposes an activemodel compatible error" do
199
+ errors = form.build({}).errors
200
+
201
+ expect(errors).to be_instance_of(
202
+ ActiveModel::Errors
203
+ )
204
+
205
+ expect(errors[:email]).to eq []
206
+ end
207
+ end
208
+ end
209
+
210
+ describe "#attributes" do
211
+ it "returns processed attributes" do
212
+ form = Class.new(ROM::Model::Form) do
213
+ def self.name
214
+ 'UserForm'
215
+ end
216
+
217
+ key :foo_id, :bar_id
218
+
219
+ input do
220
+ set_model_name 'User'
221
+
222
+ attribute :uid, Integer
223
+ end
224
+ end
225
+
226
+ form_object = form.build(uid: "12345")
227
+ expect(form_object.attributes[:uid]).to eq 12_345
228
+ end
229
+ end
230
+
231
+ describe "#validate!" do
232
+ it "runs validations and assigns errors" do
233
+ form_object = form.build({})
234
+ form_object.validate!
235
+
236
+ expect(form_object.errors[:email]).to include "can't be blank"
237
+ end
238
+
239
+ it "uses processed parameters" do
240
+ form = Class.new(ROM::Model::Form) do
241
+ def self.name
242
+ 'UserForm'
243
+ end
244
+
245
+ key :foo_id, :bar_id
246
+
247
+ input do
248
+ set_model_name 'User'
249
+
250
+ attribute :email, String
251
+ attribute :country, String, default: "Unkown"
252
+ end
253
+
254
+ validations do
255
+ validates :email, presence: true
256
+ validates :country, presence: true
257
+ end
258
+ end
259
+
260
+ form_object = form.build(uid: "12345")
261
+ form_object.validate!
262
+
263
+ expect(form_object.errors[:country]).to be_blank
264
+ end
265
+ end
266
+
267
+ describe 'inheritance' do
268
+ let(:child_form) do
269
+ Class.new(form) do
270
+ def self.name
271
+ "NewUserForm"
272
+ end
273
+ end
274
+ end
275
+
276
+ it 'copies model_name' do
277
+ expect(child_form.model_name.name).to eql(form.model_name.name)
278
+ end
279
+
280
+ it 'copies input' do
281
+ expect(child_form.params.attribute_set[:email]).to_not be(nil)
282
+ expect(child_form.params).to_not be(form.params)
283
+ end
284
+
285
+ it 'copies model' do
286
+ expect(child_form.model.attribute_set[:email]).to_not be(nil)
287
+ expect(child_form.model).to_not be(form.model)
288
+ end
289
+
290
+ it 'copies validator' do
291
+ expect(child_form.validator.validators.first).to be_instance_of(
292
+ ActiveModel::Validations::PresenceValidator
293
+ )
294
+ expect(child_form.validator).to_not be(form.validator)
295
+ end
296
+ end
297
+ end
File without changes
@@ -0,0 +1,75 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Validation' do
4
+ subject(:validator) { user_validator.new(params) }
5
+
6
+ let(:user_params) do
7
+ Class.new {
8
+ include ROM::Model::Params
9
+
10
+ attribute :name, String
11
+ attribute :email, String
12
+ }
13
+ end
14
+
15
+ let(:user_validator) do
16
+ Class.new {
17
+ include ROM::Model::Validator
18
+
19
+ relation :users
20
+
21
+ validates :name, presence: true, uniqueness: { message: 'TAKEN!' }
22
+ validates :email, uniqueness: true
23
+
24
+ def self.name
25
+ 'UserValidator'
26
+ end
27
+ }
28
+ end
29
+
30
+ describe '#call' do
31
+ let(:params) { {} }
32
+
33
+ it 'raises validation error when params are not valid' do
34
+ expect { validator.call }.to raise_error(ROM::Model::ValidationError)
35
+ end
36
+ end
37
+
38
+ describe "#validate" do
39
+ let(:params) { {} }
40
+
41
+ it "sets errors when params are not valid" do
42
+ validator.validate
43
+ expect(validator.errors[:name]).to eql(["can't be blank"])
44
+ end
45
+ end
46
+
47
+ describe ':presence' do
48
+ let(:params) { user_params.new(name: '') }
49
+
50
+ it 'sets error messages' do
51
+ expect(validator).to_not be_valid
52
+ expect(validator.errors[:name]).to eql(["can't be blank"])
53
+ end
54
+ end
55
+
56
+ describe ':uniqueness' do
57
+ let(:params) { user_params.new(name: 'Jane', email: 'jane@doe.org') }
58
+
59
+ before do
60
+ rom.relations.users.insert(name: 'Jane', email: 'jane@doe.org')
61
+ end
62
+
63
+ it 'sets default error messages' do
64
+ expect(validator).to_not be_valid
65
+ expect(validator.errors[:email]).to eql(['has already been taken'])
66
+ end
67
+
68
+ it 'sets custom error messages' do
69
+ rom.relations.users.insert(name: 'Jane', email: 'jane@doe.org')
70
+
71
+ expect(validator).to_not be_valid
72
+ expect(validator.errors[:name]).to eql(['TAKEN!'])
73
+ end
74
+ end
75
+ end