reform 2.1.0 → 2.2.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (89) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +0 -1
  3. data/.travis.yml +4 -12
  4. data/CHANGES.md +8 -0
  5. data/README.md +36 -743
  6. data/Rakefile +1 -31
  7. data/gemfiles/{Gemfile.rails-3.1 → Gemfile.disposable-0.3} +1 -2
  8. data/lib/reform.rb +0 -9
  9. data/lib/reform/contract.rb +5 -1
  10. data/lib/reform/form.rb +1 -4
  11. data/lib/reform/form/composition.rb +1 -2
  12. data/lib/reform/form/dry.rb +29 -16
  13. data/lib/reform/form/module.rb +15 -3
  14. data/lib/reform/form/validate.rb +1 -1
  15. data/lib/reform/validation.rb +3 -3
  16. data/lib/reform/version.rb +1 -1
  17. data/reform.gemspec +3 -10
  18. data/test/coercion_test.rb +7 -7
  19. data/test/composition_test.rb +5 -1
  20. data/test/contract_test.rb +10 -4
  21. data/test/deserialize_test.rb +3 -3
  22. data/test/errors_test.rb +48 -28
  23. data/test/form_option_test.rb +3 -1
  24. data/test/form_test.rb +19 -14
  25. data/test/module_test.rb +51 -11
  26. data/test/populate_test.rb +21 -7
  27. data/test/reform_test.rb +24 -20
  28. data/test/save_test.rb +10 -4
  29. data/test/skip_if_test.rb +5 -3
  30. data/test/test_helper.rb +3 -43
  31. data/test/validate_test.rb +34 -14
  32. data/test/validation/dry_test.rb +60 -0
  33. data/test/validation/dry_validation_test.rb +65 -43
  34. data/test/validation/errors.yml +4 -0
  35. metadata +16 -192
  36. data/database.sqlite3 +0 -0
  37. data/gemfiles/Gemfile.rails-3.2 +0 -7
  38. data/gemfiles/Gemfile.rails-4.0 +0 -8
  39. data/gemfiles/Gemfile.rails-4.1 +0 -8
  40. data/gemfiles/Gemfile.rails-4.2 +0 -8
  41. data/lib/reform/active_record.rb +0 -4
  42. data/lib/reform/form/active_model.rb +0 -87
  43. data/lib/reform/form/active_model/form_builder_methods.rb +0 -48
  44. data/lib/reform/form/active_model/model_reflections.rb +0 -46
  45. data/lib/reform/form/active_model/model_validations.rb +0 -110
  46. data/lib/reform/form/active_model/validations.rb +0 -107
  47. data/lib/reform/form/active_record.rb +0 -30
  48. data/lib/reform/form/lotus.rb +0 -59
  49. data/lib/reform/form/multi_parameter_attributes.rb +0 -48
  50. data/lib/reform/form/validation/unique_validator.rb +0 -54
  51. data/lib/reform/rails.rb +0 -13
  52. data/test/active_model_custom_validation_translations_test.rb +0 -75
  53. data/test/active_model_test.rb +0 -207
  54. data/test/active_model_validation_for_property_named_format_test.rb +0 -18
  55. data/test/active_record_test.rb +0 -273
  56. data/test/builder_test.rb +0 -32
  57. data/test/custom_validation_test.rb +0 -47
  58. data/test/dummy/Rakefile +0 -7
  59. data/test/dummy/app/controllers/albums_controller.rb +0 -18
  60. data/test/dummy/app/controllers/application_controller.rb +0 -4
  61. data/test/dummy/app/controllers/musician_controller.rb +0 -5
  62. data/test/dummy/app/forms/album_form.rb +0 -18
  63. data/test/dummy/app/helpers/application_helper.rb +0 -2
  64. data/test/dummy/app/models/album.rb +0 -4
  65. data/test/dummy/app/models/song.rb +0 -3
  66. data/test/dummy/app/views/albums/new.html.erb +0 -28
  67. data/test/dummy/app/views/layouts/application.html.erb +0 -14
  68. data/test/dummy/config.ru +0 -4
  69. data/test/dummy/config/application.rb +0 -20
  70. data/test/dummy/config/boot.rb +0 -10
  71. data/test/dummy/config/database.yml +0 -22
  72. data/test/dummy/config/environment.rb +0 -5
  73. data/test/dummy/config/environments/development.rb +0 -16
  74. data/test/dummy/config/environments/production.rb +0 -46
  75. data/test/dummy/config/environments/test.rb +0 -33
  76. data/test/dummy/config/locales/en.yml +0 -14
  77. data/test/dummy/config/routes.rb +0 -4
  78. data/test/dummy/db/test.sqlite3 +0 -0
  79. data/test/form_builder_test.rb +0 -138
  80. data/test/lotus/Gemfile +0 -5
  81. data/test/lotus/lotus_test.rb +0 -31
  82. data/test/lotus_test.rb +0 -150
  83. data/test/model_reflections_test.rb +0 -138
  84. data/test/model_validations_test.rb +0 -82
  85. data/test/mongoid_test.rb +0 -313
  86. data/test/multi_parameter_attributes_test.rb +0 -50
  87. data/test/rails/integration_test.rb +0 -54
  88. data/test/unique_test.rb +0 -135
  89. data/test/validation/activemodel_validation_test.rb +0 -252
@@ -1,138 +0,0 @@
1
- require 'test_helper'
2
-
3
- # Reform::ModelReflections will be the interface between the form object and form builders like simple_form.
4
- class ModelReflectionTest < MiniTest::Spec
5
- class SongForm < Reform::Form
6
- include Reform::Form::ActiveRecord
7
- include Reform::Form::ActiveModel::ModelReflections
8
-
9
- model :song
10
-
11
- property :title
12
- property :artist do
13
- property :name
14
- end
15
- end
16
-
17
- module ColumnForAttribute
18
- def column_for_attribute(*args)
19
- "#{self.class}: #{args.inspect}"
20
- end
21
- end
22
-
23
- module HasAttribute
24
- def has_attribute?(*args)
25
- "#{self.class}: has #{args.inspect}"
26
- end
27
- end
28
-
29
- module DefinedEnums
30
- def defined_enums
31
- {self.class => []}
32
- end
33
- end
34
-
35
- describe "#column_for_attribute" do
36
- let (:artist) { Artist.new }
37
- let (:song) { Song.new(artist: artist) }
38
- let (:form) { SongForm.new(song) }
39
-
40
- # delegate to model.
41
- it do
42
- song.extend(ColumnForAttribute)
43
- artist.extend(ColumnForAttribute)
44
-
45
- form.column_for_attribute(:title).must_equal "Song: [:title]"
46
- form.artist.column_for_attribute(:name).must_equal "Artist: [:name]"
47
- end
48
- end
49
-
50
- describe "#has_attribute?" do
51
- let (:artist) { Artist.new }
52
- let (:song) { Song.new(artist: artist) }
53
- let (:form) { SongForm.new(song) }
54
-
55
- # delegate to model.
56
- it do
57
- song.extend(HasAttribute)
58
- artist.extend(HasAttribute)
59
-
60
- form.has_attribute?(:title).must_equal "Song: has [:title]"
61
- form.artist.has_attribute?(:name).must_equal "Artist: has [:name]"
62
- end
63
- end
64
-
65
- describe "#defined_enums" do
66
- let (:artist) { Artist.new }
67
- let (:song) { Song.new(artist: artist) }
68
- let (:form) { SongForm.new(song) }
69
-
70
- # delegate to model.
71
- it do
72
- song.extend(DefinedEnums)
73
- artist.extend(DefinedEnums)
74
-
75
- form.defined_enums.must_include Song
76
- form.artist.defined_enums.must_include Artist
77
- end
78
- end
79
-
80
- describe ".reflect_on_association" do
81
- let (:artist) { Artist.new }
82
- let (:song) { Song.new(artist: artist) }
83
- let (:form) { SongForm.new(song) }
84
-
85
- # delegate to model class.
86
- it do
87
- reflection = form.class.reflect_on_association(:artist)
88
- reflection.must_be_kind_of ActiveRecord::Reflection::AssociationReflection
89
- end
90
- end
91
-
92
- class SongWithArtistForm < Reform::Form
93
- include Reform::Form::ActiveRecord
94
- include Reform::Form::ModelReflections
95
- include Reform::Form::Composition
96
-
97
- model :artist
98
-
99
- property :name, on: :artist
100
- property :title, on: :song
101
- end
102
-
103
- describe "#column_for_attribute with composition" do
104
- let (:artist) { Artist.new }
105
- let (:song) { Song.new }
106
- let (:form) { SongWithArtistForm.new(artist: artist, song: song) }
107
-
108
- # delegates to respective model.
109
- it do
110
- song.extend(ColumnForAttribute)
111
- artist.extend(ColumnForAttribute)
112
-
113
-
114
- form.column_for_attribute(:name).must_equal "Artist: [:name]"
115
- form.column_for_attribute(:title).must_equal "Song: [:title]"
116
- end
117
- end
118
-
119
- describe "#defined_enums with composition" do
120
- let (:artist) { Artist.new }
121
- let (:song) { Song.new }
122
- let (:form) { SongWithArtistForm.new(artist: artist, song: song) }
123
-
124
- # delegates to respective model.
125
- it do
126
- song.extend(DefinedEnums)
127
- artist.extend(DefinedEnums)
128
-
129
-
130
- form.defined_enums.must_include Song
131
- form.defined_enums.must_include Artist
132
- end
133
- end
134
-
135
- describe "::validators_on" do
136
- it { assert SongWithArtistForm.validators_on }
137
- end
138
- end
@@ -1,82 +0,0 @@
1
- require 'test_helper'
2
-
3
- class ModelValidationsTest < MiniTest::Spec
4
-
5
- class Album
6
- include ActiveModel::Validations
7
- attr_accessor :title, :artist, :other_attribute
8
-
9
- validates :title, :artist, presence: true
10
- validates :other_attribute, presence: true
11
- end
12
-
13
- class AlbumRating
14
- include ActiveModel::Validations
15
-
16
- attr_accessor :rating
17
-
18
- validates :rating, numericality: { greater_than_or_equal_to: 0 }
19
-
20
- end
21
-
22
- class AlbumForm < Reform::Form
23
- extend ActiveModel::ModelValidations
24
-
25
- property :title
26
- property :artist_name, from: :artist
27
- copy_validations_from Album
28
- end
29
-
30
- class CompositeForm < Reform::Form
31
- include Composition
32
- extend ActiveModel::ModelValidations
33
-
34
- model :album
35
-
36
- property :title, on: :album
37
- property :artist_name, from: :artist, on: :album
38
- property :rating, on: :album_rating
39
-
40
- copy_validations_from album: Album, album_rating: AlbumRating
41
- end
42
-
43
- let(:album) { Album.new }
44
-
45
- describe 'non-composite form' do
46
-
47
- let(:album_form) { AlbumForm.new(album) }
48
-
49
- it 'is not valid when title is not present' do
50
- album_form.validate(artist_name: 'test', title: nil).must_equal false
51
- end
52
-
53
- it 'is not valid when artist_name is not present' do
54
- album_form.validate(artist_name: nil, title: 'test').must_equal false
55
- end
56
-
57
- it 'is valid when title and artist_name is present' do
58
- album_form.validate(artist_name: 'test', title: 'test').must_equal true
59
- end
60
-
61
- end
62
-
63
- describe 'composite form' do
64
-
65
- let(:album_rating) { AlbumRating.new }
66
- let(:composite_form) { CompositeForm.new(album: album, album_rating: album_rating) }
67
-
68
- it 'is valid when all attributes are correct' do
69
- composite_form.validate(artist_name: 'test', title: 'test', rating: 1).must_equal true
70
- end
71
-
72
- it 'is invalid when rating is below 0' do
73
- composite_form.validate(artist_name: 'test', title: 'test', rating: -1).must_equal false
74
- end
75
-
76
- it 'is invalid when artist_name is missing' do
77
- composite_form.validate(artist_name: nil, title: 'test', rating: 1).must_equal false
78
- end
79
-
80
- end
81
-
82
- end
@@ -1,313 +0,0 @@
1
- require 'test_helper'
2
- def mongoid_present?
3
- require 'mongoid'
4
- Mongoid.configure do |config|
5
- config.connect_to("reform-mongoid-test")
6
- end
7
- true
8
- rescue
9
- false
10
- end
11
-
12
- if mongoid_present?
13
- require 'reform/mongoid'
14
-
15
- class Disc
16
- include Mongoid::Document
17
- field :title, type: String
18
- has_many :tunes
19
- has_and_belongs_to_many :musicians
20
- end
21
-
22
- class Musician
23
- include Mongoid::Document
24
- field :name, type: String
25
- end
26
-
27
- class Tune
28
- include Mongoid::Document
29
- include Mongoid::Timestamps
30
- field :title, type: String
31
- belongs_to :disc
32
- belongs_to :musician
33
- end
34
-
35
- class MongoidTest < MiniTest::Spec
36
- class TuneForm < Reform::Form
37
- include Reform::Form::Mongoid
38
- model :tune
39
-
40
- property :title
41
- property :created_at
42
-
43
- validates_uniqueness_of :title, scope: [:disc_id, :musician_id]
44
- validates :created_at, :presence => true # have another property to test if we mix up.
45
-
46
- property :musician do
47
- property :name
48
- validates_uniqueness_of :name # this currently also tests if Form::AR is included as a feature.
49
- end
50
- end
51
-
52
- let(:disc) { Disc.create(:title => "Damnation") }
53
- let(:musician) { Musician.create(:name => "Opeth") }
54
- let(:form) { TuneForm.new(Tune.new(:musician => Musician.new)) }
55
-
56
- it { form.class.i18n_scope.must_equal :mongoid }
57
-
58
- it "allows accessing the database" do
59
- end
60
-
61
- # uniqueness
62
- it "has no errors on title when title is unique for the same musician and disc" do
63
- form.validate("title" => "The Gargoyle", "musician_id" => musician.id, "disc" => disc.id, "created_at" => "November 6, 1966")
64
- assert_empty form.errors[:title]
65
- end
66
-
67
- it "has errors on title when title is taken for the same musician and disc" do
68
- skip "replace ActiveModel::Validations with our own, working and reusable gem."
69
- Tune.create(title: "Windowpane", musician_id: musician.id, disc_id: disc.id)
70
- form.validate("title" => "Windowpane", "musician_id" => musician.id, "disc" => disc)
71
- refute_empty form.errors[:title]
72
- end
73
-
74
- # nested object taken.
75
- it "is valid when musician name is unique" do
76
- form.validate("musician" => {"name" => "Paul Gilbert"}, "title" => "The Gargoyle", "created_at" => "November 6, 1966").must_equal true
77
- end
78
-
79
- it "is invalid and shows error when taken" do
80
- Tune.delete_all
81
- Musician.create(:name => "Racer X")
82
-
83
- form.validate("musician" => {"name" => "Racer X"}, "title" => "Ghost Inside My Skin").must_equal false
84
- form.errors.messages.must_equal({:"musician.name"=>["is already taken"], :created_at => ["can't be blank"]})
85
- end
86
-
87
- it "works with Composition" do
88
- form = Class.new(Reform::Form) do
89
- include Reform::Form::Mongoid
90
- include Reform::Form::Composition
91
-
92
- property :name, :on => :musician
93
- validates_uniqueness_of :name
94
- end.new(:musician => Musician.new)
95
-
96
- Musician.create(:name => "Bad Religion")
97
- form.validate("name" => "Bad Religion").must_equal false
98
- end
99
-
100
- describe "#save" do
101
- # TODO: test 1-n?
102
- it "calls model.save" do
103
- Musician.delete_all
104
- form.validate("musician" => {"name" => "Bad Religion"}, "title" => "Ghost Inside My Skin")
105
- form.save
106
- Musician.where(:name => "Bad Religion").size.must_equal 1
107
- end
108
-
109
- it "doesn't call model.save when block is given" do
110
- Musician.delete_all
111
- form.validate("name" => "Bad Religion")
112
- form.save {}
113
- Musician.where(:name => "Bad Religion").size.must_equal 0
114
- end
115
- end
116
- end
117
-
118
-
119
- class PopulateWithActiveRecordTest < MiniTest::Spec
120
- class DiscForm < Reform::Form
121
-
122
- property :title
123
-
124
- collection :tunes, :populate_if_empty => Tune do
125
- property :title
126
- end
127
- end
128
-
129
- let (:disc) { Disc.new(:tunes => []) }
130
- it do
131
- form = DiscForm.new(disc)
132
-
133
- form.validate("tunes" => [{"title" => "Straight From The Jacket"}])
134
-
135
- # form populated.
136
- form.tunes.size.must_equal 1
137
- form.tunes[0].model.must_be_kind_of Tune
138
-
139
- # model NOT populated.
140
- disc.tunes.must_equal []
141
-
142
-
143
- form.sync
144
-
145
- # form populated.
146
- form.tunes.size.must_equal 1
147
- form.tunes[0].model.must_be_kind_of Tune
148
-
149
- # model also populated.
150
- tune = disc.tunes[0]
151
- disc.tunes.must_equal [tune]
152
- tune.title.must_equal "Straight From The Jacket"
153
-
154
-
155
- # if ActiveRecord::VERSION::STRING !~ /^3.0/
156
- # # saving saves association.
157
- # form.save
158
- #
159
- # disc.reload
160
- # tune = disc.tunes[0]
161
- # disc.tunes.must_equal [tune]
162
- # tune.title.must_equal "Straight From The Jacket"
163
- # end
164
- end
165
-
166
-
167
- describe "modifying 1., adding 2." do
168
- let (:tune) { Tune.new(:title => "Part 2") }
169
- let (:disc) { Disc.create.tap { |a| a.tunes << tune } }
170
-
171
- it do
172
- form = DiscForm.new(disc)
173
-
174
- id = disc.tunes[0].id
175
- disc.tunes[0].persisted?.must_equal true
176
- assert id.to_s.size > 0
177
-
178
- form.validate("tunes" => [{"title" => "Part Two"}, {"title" => "Check For A Pulse"}])
179
-
180
- # form populated.
181
- form.tunes.size.must_equal 2
182
- form.tunes[0].model.must_be_kind_of Tune
183
- form.tunes[1].model.must_be_kind_of Tune
184
-
185
- # model NOT populated.
186
- disc.tunes.must_equal [tune]
187
-
188
-
189
- form.sync
190
-
191
- # form populated.
192
- form.tunes.size.must_equal 2
193
-
194
- # model also populated.
195
- disc.tunes.size.must_equal 2
196
-
197
- # corrected title
198
- disc.tunes[0].title.must_equal "Part Two"
199
- # ..but same tune.
200
- disc.tunes[0].id.must_equal id
201
-
202
- # and a new tune.
203
- disc.tunes[1].title.must_equal "Check For A Pulse"
204
- disc.tunes[1].persisted?.must_equal true # TODO: with << strategy, this shouldn't be saved.
205
- end
206
-
207
- describe 'using nested_models_attributes to modify nested collection' do
208
- class ActiveModelDiscForm < Reform::Form
209
- include Reform::Form::ActiveModel
210
- include Reform::Form::ActiveModel::FormBuilderMethods
211
-
212
- property :title
213
-
214
- collection :tunes, :populate_if_empty => Tune do
215
- property :title
216
- end
217
- end
218
-
219
- let (:disc) { Disc.create(:title => 'Greatest Hits') }
220
- let (:form) { ActiveModelDiscForm.new(disc) }
221
-
222
- it do
223
- form.validate('tunes_attributes' => {'0' => {'title' => 'Tango'}})
224
-
225
- # form populated.
226
- form.tunes.size.must_equal 1
227
- form.tunes[0].model.must_be_kind_of Tune
228
- form.tunes[0].title.must_equal 'Tango'
229
-
230
- # model NOT populated.
231
- disc.tunes.must_equal []
232
-
233
- form.save
234
-
235
- # nested model persisted.
236
- first_tune = disc.tunes[0]
237
- first_tune.persisted?.must_equal true
238
- assert first_tune.id.to_s.size > 0
239
-
240
- # form populated.
241
- form.tunes.size.must_equal 1
242
-
243
- # model also populated.
244
- disc.tunes.size.must_equal 1
245
- disc.tunes[0].title.must_equal 'Tango'
246
-
247
- form = ActiveModelDiscForm.new(disc)
248
- form.validate('tunes_attributes' => {'0' => {'id' => first_tune.id, 'title' => 'Tango nuevo'}, '1' => {'title' => 'Waltz'}})
249
-
250
- # form populated.
251
- form.tunes.size.must_equal 2
252
- form.tunes[0].model.must_be_kind_of Tune
253
- form.tunes[1].model.must_be_kind_of Tune
254
- form.tunes[0].title.must_equal 'Tango nuevo'
255
- form.tunes[1].title.must_equal 'Waltz'
256
-
257
- # model NOT populated.
258
- disc.tunes.size.must_equal 1
259
- disc.tunes[0].title.must_equal 'Tango'
260
-
261
- form.save
262
-
263
- # form populated.
264
- form.tunes.size.must_equal 2
265
-
266
- # model also populated.
267
- disc.tunes.size.must_equal 2
268
- disc.tunes[0].id.must_equal first_tune.id
269
- disc.tunes[0].persisted?.must_equal true
270
- disc.tunes[1].persisted?.must_equal true
271
- disc.tunes[0].title.must_equal 'Tango nuevo'
272
- disc.tunes[1].title.must_equal 'Waltz'
273
- end
274
- end
275
- end
276
-
277
- # it do
278
- # a=Disc.new
279
- # a.tunes << Tune.new(title: "Old What's His Name") # Tune does not get persisted.
280
-
281
- # a.tunes[1] = Tune.new(title: "Permanent Rust")
282
-
283
- # puts "@@@"
284
- # puts a.tunes.inspect
285
-
286
- # puts "---"
287
- # a.save
288
- # puts a.tunes.inspect
289
-
290
- # b = a.tunes.first
291
-
292
- # a.tunes = [Tune.new(title:"Biomag")]
293
- # puts "\\\\"
294
- # a.save
295
- # a.reload
296
- # puts a.tunes.inspect
297
-
298
- # b.reload
299
- # puts "#{b.inspect}, #{b.persisted?}"
300
-
301
-
302
- # a.tunes = [a.tunes.first, Tune.new(title: "Count Down")]
303
- # b = a.tunes.first
304
- # puts ":::::"
305
- # a.save
306
- # a.reload
307
- # puts a.tunes.inspect
308
-
309
- # b.reload
310
- # puts "#{b.inspect}, #{b.persisted?}"
311
- # end
312
- end
313
- end