reform 2.3.3 → 2.5.0

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 (68) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -1
  3. data/.travis.yml +0 -3
  4. data/CHANGES.md +9 -0
  5. data/Gemfile +1 -1
  6. data/LICENSE.txt +1 -1
  7. data/README.md +5 -5
  8. data/Rakefile +1 -12
  9. data/lib/reform/contract/validate.rb +1 -1
  10. data/lib/reform/form/dry.rb +47 -9
  11. data/lib/reform/validation/groups.rb +0 -1
  12. data/lib/reform/version.rb +1 -1
  13. data/test/call_test.rb +23 -0
  14. data/test/changed_test.rb +6 -6
  15. data/test/coercion_test.rb +17 -17
  16. data/test/{composition_new_api.rb → composition_test.rb} +27 -28
  17. data/test/{contract_new_api.rb → contract_test.rb} +8 -8
  18. data/test/default_test.rb +2 -2
  19. data/test/deserialize_test.rb +8 -8
  20. data/test/docs/validation_test.rb +134 -0
  21. data/test/{errors_new_api.rb → errors_test.rb} +41 -41
  22. data/test/feature_test.rb +2 -2
  23. data/test/fixtures/dry_error_messages.yml +64 -54
  24. data/test/{form_option_new_api.rb → form_option_test.rb} +1 -1
  25. data/test/{form_new_api.rb → form_test.rb} +3 -3
  26. data/test/from_test.rb +10 -10
  27. data/test/{inherit_new_api.rb → inherit_test.rb} +17 -17
  28. data/test/{module_new_api.rb → module_test.rb} +10 -10
  29. data/test/parse_option_test.rb +7 -7
  30. data/test/parse_pipeline_test.rb +1 -1
  31. data/test/{populate_new_api.rb → populate_test.rb} +112 -53
  32. data/test/populator_skip_test.rb +2 -2
  33. data/test/prepopulator_test.rb +15 -15
  34. data/test/read_only_test.rb +2 -2
  35. data/test/readable_test.rb +3 -3
  36. data/test/{reform_new_api.rb → reform_test.rb} +19 -19
  37. data/test/{save_new_api.rb → save_test.rb} +4 -4
  38. data/test/setup_test.rb +9 -9
  39. data/test/{skip_if_new_api.rb → skip_if_test.rb} +12 -12
  40. data/test/skip_setter_and_getter_test.rb +6 -6
  41. data/test/test_helper.rb +5 -6
  42. data/test/{validate_new_api.rb → validate_test.rb} +65 -78
  43. data/test/validation/{dry_validation_new_api.rb → dry_validation_test.rb} +124 -123
  44. data/test/validation/result_test.rb +14 -14
  45. data/test/virtual_test.rb +7 -7
  46. data/test/writeable_test.rb +8 -8
  47. metadata +35 -68
  48. data/Appraisals +0 -8
  49. data/gemfiles/0.13.0.gemfile +0 -8
  50. data/gemfiles/1.5.0.gemfile +0 -9
  51. data/lib/reform/form/dry/new_api.rb +0 -45
  52. data/lib/reform/form/dry/old_api.rb +0 -61
  53. data/test/call_new_api.rb +0 -23
  54. data/test/call_old_api.rb +0 -23
  55. data/test/composition_old_api.rb +0 -184
  56. data/test/contract_old_api.rb +0 -77
  57. data/test/errors_old_api.rb +0 -230
  58. data/test/fixtures/dry_new_api_error_messages.yml +0 -104
  59. data/test/form_old_api.rb +0 -57
  60. data/test/form_option_old_api.rb +0 -24
  61. data/test/inherit_old_api.rb +0 -105
  62. data/test/module_old_api.rb +0 -146
  63. data/test/populate_old_api.rb +0 -304
  64. data/test/reform_old_api.rb +0 -202
  65. data/test/save_old_api.rb +0 -101
  66. data/test/skip_if_old_api.rb +0 -92
  67. data/test/validate_old_api.rb +0 -410
  68. data/test/validation/dry_validation_old_api.rb +0 -772
@@ -1,104 +0,0 @@
1
- en:
2
- dry_validation:
3
- errors:
4
- array?: "must be an array"
5
-
6
- empty?: "must be empty"
7
-
8
- excludes?: "must not include %{value}"
9
-
10
- excluded_from?:
11
- arg:
12
- default: "must not be one of: %{list}"
13
- range: "must not be one of: %{list_left} - %{list_right}"
14
-
15
- eql?: "must be equal to %{left}"
16
-
17
- not_eql?: "must not be equal to %{left}"
18
-
19
- filled?: "must be filled"
20
-
21
- format?: "is in invalid format"
22
-
23
- number?: "must be a number"
24
-
25
- odd?: "must be odd"
26
-
27
- even?: "must be even"
28
-
29
- gt?: "must be greater than %{num}"
30
-
31
- gteq?: "must be greater than or equal to %{num}"
32
-
33
- hash?: "must be a hash"
34
-
35
- included_in?:
36
- arg:
37
- default: "must be one of: %{list}"
38
- range: "must be one of: %{list_left} - %{list_right}"
39
-
40
- includes?: "must include %{value}"
41
-
42
- bool?: "must be boolean"
43
-
44
- true?: "must be true"
45
-
46
- false?: "must be false"
47
-
48
- int?: "must be an integer"
49
-
50
- float?: "must be a float"
51
-
52
- decimal?: "must be a decimal"
53
-
54
- date?: "must be a date"
55
-
56
- date_time?: "must be a date time"
57
-
58
- time?: "must be a time"
59
-
60
- key?: "is missing"
61
-
62
- attr?: "is missing"
63
-
64
- lt?: "must be less than %{num}"
65
-
66
- lteq?: "must be less than or equal to %{num}"
67
-
68
- max_size?: "size cannot be greater than %{num}"
69
-
70
- min_size?: "size cannot be less than %{num}"
71
-
72
- none?: "cannot be defined"
73
-
74
- str?: "must be a string"
75
-
76
- type?: "must be %{type}"
77
-
78
- size?:
79
- arg:
80
- default: "size must be %{size}"
81
- range: "size must be within %{size_left} - %{size_right}"
82
-
83
- value:
84
- string:
85
- arg:
86
- default: "length must be %{size}"
87
- range: "length must be within %{size_left} - %{size_right}"
88
-
89
-
90
-
91
- rules:
92
- name:
93
- good_musical_taste?: "you're a bad person"
94
- title:
95
- good_musical_taste?: "you're a bad person"
96
- songs:
97
- a_song?: "must have at least one enabled song"
98
- artist:
99
- with_last_name?: "must have last name"
100
-
101
- de:
102
- dry_validation:
103
- errors:
104
- filled?: "muss abgefüllt sein"
data/test/form_old_api.rb DELETED
@@ -1,57 +0,0 @@
1
- require "test_helper"
2
-
3
- class FormTest < MiniTest::Spec
4
- Artist = Struct.new(:name)
5
-
6
- class AlbumForm < TestForm
7
- property :title
8
-
9
- property :hit do
10
- property :title
11
- end
12
-
13
- collection :songs do
14
- property :title
15
- end
16
-
17
- property :band do # yepp, people do crazy stuff like that.
18
- property :label do
19
- property :name
20
- end
21
- end
22
- end
23
-
24
- describe "::dup" do
25
- let(:cloned) { AlbumForm.clone }
26
-
27
- # #dup is called in Op.inheritable_attr(:contract_class), it must be subclass of the original one.
28
- it { _(cloned).wont_equal AlbumForm }
29
- it { _(AlbumForm.definitions).wont_equal cloned.definitions }
30
-
31
- it do
32
- # currently, forms need a name for validation, even without AM.
33
- cloned.singleton_class.class_eval do
34
- def name
35
- "Album"
36
- end
37
- end
38
-
39
- cloned.validation do
40
- required(:title).filled
41
- end
42
-
43
- cloned.new(OpenStruct.new).validate({})
44
- end
45
- end
46
-
47
- describe "#initialize" do
48
- class ArtistForm < TestForm
49
- property :name
50
- property :current_user, virtual: true
51
- end
52
-
53
- it "allows injecting :virtual options" do
54
- _(ArtistForm.new(Artist.new, current_user: Object).current_user).must_equal Object
55
- end
56
- end
57
- end
@@ -1,24 +0,0 @@
1
- require "test_helper"
2
-
3
- class FormOptionTest < MiniTest::Spec
4
- Song = Struct.new(:title)
5
- Album = Struct.new(:song)
6
-
7
- class SongForm < TestForm
8
- property :title
9
- validation do
10
- required(:title).filled
11
- end
12
- end
13
-
14
- class AlbumForm < TestForm
15
- property :song, form: SongForm
16
- end
17
-
18
- it do
19
- form = AlbumForm.new(Album.new(Song.new("When It Comes To You")))
20
- _(form.song.title).must_equal "When It Comes To You"
21
-
22
- form.validate(song: {title: "Run For Cover"})
23
- end
24
- end
@@ -1,105 +0,0 @@
1
- require "test_helper"
2
- require "representable/json"
3
-
4
- class InheritTest < BaseTest
5
- Populator = Reform::Form::Populator
6
-
7
- class SkipParse
8
- include Uber::Callable
9
- def call(*_args)
10
- false
11
- end
12
- end
13
-
14
- class AlbumForm < TestForm
15
- property :title, deserializer: {instance: "Instance"}, skip_if: "skip_if in AlbumForm" # allow direct configuration of :deserializer.
16
-
17
- property :hit, populate_if_empty: ->(*) { Song.new } do
18
- property :title
19
- validation do
20
- required(:title).filled
21
- end
22
- end
23
-
24
- collection :songs, populate_if_empty: -> {}, skip_if: :all_blank do
25
- property :title
26
- end
27
-
28
- property :band, populate_if_empty: -> {} do
29
- def band_id
30
- 1
31
- end
32
- end
33
- end
34
-
35
- class CompilationForm < AlbumForm
36
- property :title, inherit: true, skip_if: "skip_if from CompilationForm"
37
- property :hit, inherit: true, populate_if_empty: ->(*) { Song.new }, skip_if: SkipParse.new do
38
- property :rating
39
- validation do
40
- required(:rating).filled
41
- end
42
- end
43
-
44
- # NO collection here, this is entirely inherited.
45
-
46
- property :band, inherit: true do # inherit everything, but explicitely.
47
- end
48
- end
49
-
50
- let(:album) { Album.new(nil, Song.new, [], Band.new) }
51
- subject { CompilationForm.new(album) }
52
-
53
- it do
54
- subject.validate("hit" => {"title" => "LA Drone", "rating" => 10})
55
- _(subject.hit.title).must_equal "LA Drone"
56
- _(subject.hit.rating).must_equal 10
57
- _(subject.errors.messages).must_equal({})
58
- end
59
-
60
- it do
61
- subject.validate({})
62
- assert_nil subject.model.hit.title
63
- assert_nil subject.model.hit.rating
64
- _(subject.errors.messages).must_equal("hit.title": ["must be filled"], "hit.rating": ["must be filled"])
65
- end
66
-
67
- it "xxx" do
68
- # sub hashes like :deserializer must be properly cloned when inheriting.
69
- _(AlbumForm.options_for(:title)[:deserializer].object_id).wont_equal CompilationForm.options_for(:title)[:deserializer].object_id
70
-
71
- # don't overwrite direct deserializer: {} configuration.
72
- _(AlbumForm.options_for(:title)[:internal_populator]).must_be_instance_of Reform::Form::Populator::Sync
73
- _(AlbumForm.options_for(:title)[:deserializer][:skip_parse]).must_equal "skip_if in AlbumForm"
74
-
75
- # AlbumForm.options_for(:hit)[:internal_populator].inspect.must_match /Reform::Form::Populator:.+ @user_proc="Populator"/
76
- # AlbumForm.options_for(:hit)[:deserializer][:instance].inspect.must_be_instance_with Reform::Form::Populator, user_proc: "Populator"
77
-
78
- _(AlbumForm.options_for(:songs)[:internal_populator]).must_be_instance_of Reform::Form::Populator::IfEmpty
79
- _(AlbumForm.options_for(:songs)[:deserializer][:skip_parse]).must_be_instance_of Reform::Form::Validate::Skip::AllBlank
80
-
81
- _(AlbumForm.options_for(:band)[:internal_populator]).must_be_instance_of Reform::Form::Populator::IfEmpty
82
-
83
- _(CompilationForm.options_for(:title)[:deserializer][:skip_parse]).must_equal "skip_if from CompilationForm"
84
- # pp CompilationForm.options_for(:songs)
85
- _(CompilationForm.options_for(:songs)[:internal_populator]).must_be_instance_of Reform::Form::Populator::IfEmpty
86
-
87
- _(CompilationForm.options_for(:band)[:internal_populator]).must_be_instance_of Reform::Form::Populator::IfEmpty
88
-
89
- # completely overwrite inherited.
90
- _(CompilationForm.options_for(:hit)[:deserializer][:skip_parse]).must_be_instance_of SkipParse
91
-
92
- # inherit: true with block will still inherit the original class.
93
- _(AlbumForm.new(OpenStruct.new(band: OpenStruct.new)).band.band_id).must_equal 1
94
- _(CompilationForm.new(OpenStruct.new(band: OpenStruct.new)).band.band_id).must_equal 1
95
- end
96
-
97
- class CDForm < AlbumForm
98
- # override :band's original populate_if_empty but with :inherit.
99
- property :band, inherit: true, populator: "CD Populator" do
100
-
101
- end
102
- end
103
-
104
- it { _(CDForm.options_for(:band)[:internal_populator].instance_variable_get(:@user_proc)).must_equal "CD Populator" }
105
- end
@@ -1,146 +0,0 @@
1
- require "test_helper"
2
- require "reform/form/coercion"
3
-
4
- class ModuleInclusionTest < MiniTest::Spec
5
- module BandPropertyForm
6
- include Reform::Form::Module
7
-
8
- property :artist
9
- property :band do
10
- property :title
11
-
12
- validation do
13
- required(:title).filled
14
- end
15
-
16
- def id # gets mixed into Form, too.
17
- 2
18
- end
19
- end
20
-
21
- def id # gets mixed into Form, too.
22
- 1
23
- end
24
-
25
- validation do
26
- required(:band).filled
27
- end
28
-
29
- include Dry::Types.module # allows using Types::* in module.
30
- property :cool, type: DRY_TYPES_CONSTANT::Bool # test coercion.
31
-
32
- module InstanceMethods
33
- def artist=(new_value)
34
- errors.add(:artist, "this needs to be filled") if new_value.nil?
35
- super(new_value)
36
- end
37
- end
38
- end
39
-
40
- # TODO: test if works, move stuff into inherit_schema!
41
- module AirplaysPropertyForm
42
- include Reform::Form::Module
43
-
44
- collection :airplays do
45
- property :station
46
- validation do
47
- required(:station).filled
48
- end
49
- end
50
- validation do
51
- required(:airplays).filled
52
- end
53
- end
54
-
55
- # test:
56
- # by including BandPropertyForm into multiple classes we assure that options hashes don't get messed up by AM:V.
57
- class HitForm < TestForm
58
- include BandPropertyForm
59
- end
60
-
61
- class SongForm < TestForm
62
- include Coercion
63
- property :title
64
-
65
- include BandPropertyForm
66
- end
67
-
68
- let(:song) { OpenStruct.new(band: OpenStruct.new(title: "Time Again"), artist: "Ketama") }
69
-
70
- # nested form from module is present and creates accessor.
71
- it { _(SongForm.new(song).band.title).must_equal "Time Again" }
72
- it { _(SongForm.new(song).artist).must_equal "Ketama" }
73
-
74
- # methods from module get included.
75
- it { _(SongForm.new(song).id).must_equal 1 }
76
- it { _(SongForm.new(song).band.id).must_equal 2 }
77
-
78
- # validators get inherited.
79
- it do
80
- form = SongForm.new(OpenStruct.new)
81
- form.validate(artist: nil)
82
- _(form.errors.messages).must_equal(artist: ["this needs to be filled"], band: ["must be filled"])
83
- end
84
-
85
- # coercion works
86
- it do
87
- form = SongForm.new(OpenStruct.new)
88
- form.validate({cool: "1"})
89
- _(form.cool).must_equal true
90
- end
91
-
92
- # include a module into a module into a class :)
93
- module AlbumFormModule
94
- include Reform::Form::Module
95
- include BandPropertyForm
96
-
97
- property :name
98
- validation do
99
- required(:name).filled
100
- end
101
- end
102
-
103
- class AlbumForm < TestForm
104
- include AlbumFormModule
105
-
106
- # pp heritage
107
- property :band, inherit: true do
108
- property :label
109
- validation do
110
- required(:label).filled
111
- end
112
- end
113
- end
114
-
115
- it do
116
- form = AlbumForm.new(OpenStruct.new(band: OpenStruct.new))
117
- form.validate("band" => {})
118
- _(form.errors.messages).must_equal("band.title": ["must be filled"], "band.label": ["must be filled"], name: ["must be filled"])
119
- end
120
-
121
- describe "module with custom accessors" do
122
- module SongModule
123
- include Reform::Form::Module
124
-
125
- property :id # no custom accessor for id.
126
- property :title # has custom accessor.
127
-
128
- module InstanceMethods
129
- def title
130
- super.upcase
131
- end
132
- end
133
- end
134
-
135
- class IncludingSongForm < TestForm
136
- include SongModule
137
- end
138
-
139
- let(:song) { OpenStruct.new(id: 1, title: "Instant Mash") }
140
-
141
- it do
142
- _(IncludingSongForm.new(song).id).must_equal 1
143
- _(IncludingSongForm.new(song).title).must_equal "INSTANT MASH"
144
- end
145
- end
146
- end
@@ -1,304 +0,0 @@
1
- require "test_helper"
2
-
3
- class PopulatorTest < MiniTest::Spec
4
- Song = Struct.new(:title, :album, :composer)
5
- Album = Struct.new(:name, :songs, :artist)
6
- Artist = Struct.new(:name)
7
-
8
- class AlbumForm < TestForm
9
- property :name, populator: ->(options) { self.name = options[:fragment].reverse }
10
- validation do
11
- required(:name).filled
12
- end
13
-
14
- collection :songs,
15
- populator: ->(fragment:, model:, index:, **) {
16
- (item = model[index]) ? item : model.insert(index, Song.new)
17
- } do
18
- property :title
19
- validation do
20
- required(:title).filled
21
- end
22
-
23
- property :composer, populator: ->(options) { options[:model] || self.composer = Artist.new } do
24
- property :name
25
- validation do
26
- required(:name).filled
27
- end
28
- end
29
- end
30
-
31
- # property :artist, populator: lambda { |fragment, options| (item = options.binding.get) ? item : Artist.new } do
32
- # NOTE: we have to document that model here is the twin!
33
- property :artist, populator: ->(options) { options[:model] || self.artist = Artist.new } do
34
- property :name
35
- end
36
- end
37
-
38
- let(:song) { Song.new("Broken") }
39
- let(:song_with_composer) { Song.new("Resist Stance", nil, composer) }
40
- let(:composer) { Artist.new("Greg Graffin") }
41
- let(:artist) { Artist.new("Bad Religion") }
42
- let(:album) { Album.new("The Dissent Of Man", [song, song_with_composer], artist) }
43
-
44
- let(:form) { AlbumForm.new(album) }
45
-
46
- it "runs populator on scalar" do
47
- form.validate(
48
- "name" => "override me!"
49
- )
50
-
51
- _(form.name).must_equal "!em edirrevo"
52
- end
53
-
54
- # changing existing property :artist.
55
- # TODO: check with artist==nil
56
- it do
57
- old_id = artist.object_id
58
-
59
- form.validate(
60
- "artist" => {"name" => "Marcus Miller"}
61
- )
62
-
63
- _(form.artist.model.object_id).must_equal old_id
64
- end
65
-
66
- # use populator for default value on scalars?
67
-
68
- # adding to collection via :populator.
69
- # valid.
70
- it "yyy" do
71
- _(form.validate(
72
- "songs" => [{"title" => "Fallout"}, {"title" => "Roxanne"},
73
- {"title" => "Rime Of The Ancient Mariner"}, # new song.
74
- {"title" => "Re-Education", "composer" => {"name" => "Rise Against"}}], # new song with new composer.
75
- )).must_equal true
76
-
77
- _(form.errors.messages.inspect).must_equal "{}"
78
-
79
- # form has updated.
80
- _(form.name).must_equal "The Dissent Of Man"
81
- _(form.songs[0].title).must_equal "Fallout"
82
- _(form.songs[1].title).must_equal "Roxanne"
83
- _(form.songs[1].composer.name).must_equal "Greg Graffin"
84
-
85
- _(form.songs[1].composer.model).must_be_instance_of Artist
86
-
87
- _(form.songs[1].title).must_equal "Roxanne"
88
- _(form.songs[2].title).must_equal "Rime Of The Ancient Mariner" # new song added.
89
- _(form.songs[3].title).must_equal "Re-Education"
90
- _(form.songs[3].composer.name).must_equal "Rise Against"
91
- _(form.songs.size).must_equal 4
92
- _(form.artist.name).must_equal "Bad Religion"
93
-
94
- # model has not changed, yet.
95
- _(album.name).must_equal "The Dissent Of Man"
96
- _(album.songs[0].title).must_equal "Broken"
97
- _(album.songs[1].title).must_equal "Resist Stance"
98
- _(album.songs[1].composer.name).must_equal "Greg Graffin"
99
- _(album.songs.size).must_equal 2
100
- _(album.artist.name).must_equal "Bad Religion"
101
- end
102
- end
103
-
104
- class PopulateWithMethodTest < Minitest::Spec
105
- Album = Struct.new(:title)
106
-
107
- class AlbumForm < TestForm
108
- property :title, populator: :title!
109
-
110
- def title!(options)
111
- self.title = options[:fragment].reverse
112
- end
113
- end
114
-
115
- let(:form) { AlbumForm.new(Album.new) }
116
-
117
- it "runs populator method" do
118
- form.validate("title" => "override me!")
119
-
120
- _(form.title).must_equal "!em edirrevo"
121
- end
122
- end
123
-
124
- class PopulateWithCallableTest < Minitest::Spec
125
- Album = Struct.new(:title)
126
-
127
- class TitlePopulator
128
- include Uber::Callable
129
-
130
- def call(form, options)
131
- form.title = options[:fragment].reverse
132
- end
133
- end
134
-
135
- class AlbumForm < TestForm
136
- property :title, populator: TitlePopulator.new
137
- end
138
-
139
- let(:form) { AlbumForm.new(Album.new) }
140
-
141
- it "runs populator method" do
142
- form.validate("title" => "override me!")
143
-
144
- _(form.title).must_equal "!em edirrevo"
145
- end
146
- end
147
-
148
- class PopulateWithProcTest < Minitest::Spec
149
- Album = Struct.new(:title)
150
-
151
- TitlePopulator = ->(options) do
152
- options[:represented].title = options[:fragment].reverse
153
- end
154
-
155
- class AlbumForm < TestForm
156
- property :title, populator: TitlePopulator
157
- end
158
-
159
- let(:form) { AlbumForm.new(Album.new) }
160
-
161
- it "runs populator method" do
162
- form.validate("title" => "override me!")
163
-
164
- _(form.title).must_equal "!em edirrevo"
165
- end
166
- end
167
-
168
- class PopulateIfEmptyTest < MiniTest::Spec
169
- Song = Struct.new(:title, :album, :composer)
170
- Album = Struct.new(:name, :songs, :artist)
171
- Artist = Struct.new(:name)
172
-
173
- let(:song) { Song.new("Broken") }
174
- let(:song_with_composer) { Song.new("Resist Stance", nil, composer) }
175
- let(:composer) { Artist.new("Greg Graffin") }
176
- let(:artist) { Artist.new("Bad Religion") }
177
- let(:album) { Album.new("The Dissent Of Man", [song, song_with_composer], artist) }
178
-
179
- class AlbumForm < TestForm
180
- property :name
181
-
182
- collection :songs,
183
- populate_if_empty: Song do # class name works.
184
-
185
- property :title
186
- validation do
187
- required(:title).filled
188
- end
189
-
190
- property :composer, populate_if_empty: :populate_composer! do # lambda works, too. in form context.
191
- property :name
192
- validation do
193
- required(:name).filled
194
- end
195
- end
196
-
197
- private
198
- def populate_composer!(options)
199
- Artist.new
200
- end
201
- end
202
-
203
- property :artist, populate_if_empty: ->(args) { create_artist(args[:fragment], args[:user_options]) } do # methods work, too.
204
- property :name
205
- end
206
-
207
- private
208
- class Sting < Artist
209
- attr_accessor :args
210
- end
211
- def create_artist(input, user_options)
212
- Sting.new.tap { |artist| artist.args = ([input, user_options].to_s) }
213
- end
214
- end
215
-
216
- let(:form) { AlbumForm.new(album) }
217
-
218
- it do
219
- _(form.songs.size).must_equal 2
220
-
221
- _(form.validate(
222
- "songs" => [{"title" => "Fallout"}, {"title" => "Roxanne"},
223
- {"title" => "Rime Of The Ancient Mariner"}, # new song.
224
- {"title" => "Re-Education", "composer" => {"name" => "Rise Against"}}], # new song with new composer.
225
- )).must_equal true
226
-
227
- _(form.errors.messages.inspect).must_equal "{}"
228
-
229
- # form has updated.
230
- _(form.name).must_equal "The Dissent Of Man"
231
- _(form.songs[0].title).must_equal "Fallout"
232
- _(form.songs[1].title).must_equal "Roxanne"
233
- _(form.songs[1].composer.name).must_equal "Greg Graffin"
234
- _(form.songs[1].title).must_equal "Roxanne"
235
- _(form.songs[2].title).must_equal "Rime Of The Ancient Mariner" # new song added.
236
- _(form.songs[3].title).must_equal "Re-Education"
237
- _(form.songs[3].composer.name).must_equal "Rise Against"
238
- _(form.songs.size).must_equal 4
239
- _(form.artist.name).must_equal "Bad Religion"
240
-
241
- # model has not changed, yet.
242
- _(album.name).must_equal "The Dissent Of Man"
243
- _(album.songs[0].title).must_equal "Broken"
244
- _(album.songs[1].title).must_equal "Resist Stance"
245
- _(album.songs[1].composer.name).must_equal "Greg Graffin"
246
- _(album.songs.size).must_equal 2
247
- _(album.artist.name).must_equal "Bad Religion"
248
- end
249
-
250
- # trigger artist populator. lambda calling form instance method.
251
- it "xxxx" do
252
- form = AlbumForm.new(album = Album.new)
253
- form.validate("artist" => {"name" => "From Autumn To Ashes"})
254
-
255
- _(form.artist.name).must_equal "From Autumn To Ashes"
256
- # test lambda was executed in form context.
257
- _(form.artist.model).must_be_instance_of AlbumForm::Sting
258
- # test lambda block arguments.
259
- _(form.artist.model.args.to_s).must_equal "[{\"name\"=>\"From Autumn To Ashes\"}, nil]"
260
-
261
- assert_nil album.artist
262
- end
263
- end
264
-
265
- # delete songs while deserializing.
266
- class PopulateIfEmptyWithDeletionTest < MiniTest::Spec
267
- Song = Struct.new(:title, :album, :composer)
268
- Album = Struct.new(:name, :songs, :artist)
269
-
270
- let(:song) { Song.new("Broken") }
271
- let(:song2) { Song.new("Resist Stance") }
272
- let(:album) { Album.new("The Dissent Of Man", [song, song2]) }
273
-
274
- class AlbumForm < TestForm
275
- property :name
276
-
277
- collection :songs,
278
- populate_if_empty: Song, skip_if: :delete_song! do
279
-
280
- property :title
281
- validation do
282
- required(:title).filled
283
- end
284
- end
285
-
286
- def delete_song!(options)
287
- songs.delete(songs[0]) and return true if options[:fragment]["title"] == "Broken, delete me!"
288
- false
289
- end
290
- end
291
-
292
- let(:form) { AlbumForm.new(album) }
293
-
294
- it do
295
- _(form.validate(
296
- "songs" => [{"title" => "Broken, delete me!"}, {"title" => "Roxanne"}]
297
- )).must_equal true
298
-
299
- _(form.errors.messages.inspect).must_equal "{}"
300
-
301
- _(form.songs.size).must_equal 1
302
- _(form.songs[0].title).must_equal "Roxanne"
303
- end
304
- end