reform 1.2.0.beta2 → 1.2.1
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.
- checksums.yaml +4 -4
- data/.travis.yml +2 -1
- data/CHANGES.md +53 -7
- data/LICENSE.txt +1 -1
- data/README.md +48 -8
- data/database.sqlite3 +0 -0
- data/lib/reform/contract.rb +58 -4
- data/lib/reform/contract/setup.rb +16 -22
- data/lib/reform/contract/validate.rb +18 -21
- data/lib/reform/form/active_model.rb +6 -8
- data/lib/reform/form/json.rb +1 -1
- data/lib/reform/form/save.rb +29 -59
- data/lib/reform/form/sync.rb +52 -70
- data/lib/reform/form/validate.rb +37 -44
- data/lib/reform/representer.rb +6 -10
- data/lib/reform/version.rb +1 -1
- data/test/active_record_test.rb +68 -0
- data/test/benchmarking.rb +26 -0
- data/test/contract_test.rb +40 -0
- data/test/custom_validation_test.rb +1 -1
- data/test/empty_test.rb +31 -3
- data/test/form_composition_test.rb +1 -1
- data/test/from_test.rb +150 -0
- data/test/model_validations_test.rb +2 -2
- data/test/nested_form_test.rb +4 -4
- data/test/read_only_test.rb +0 -25
- data/test/readable_test.rb +32 -0
- data/test/reform_test.rb +0 -21
- data/test/virtual_test.rb +26 -0
- data/test/writeable_test.rb +30 -0
- metadata +14 -6
- data/test/as_test.rb +0 -75
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'reform'
|
2
|
+
require 'ostruct'
|
3
|
+
require 'benchmark'
|
4
|
+
|
5
|
+
class BandForm < Reform::Form
|
6
|
+
property :name, validates: {presence: true}
|
7
|
+
|
8
|
+
collection :songs do
|
9
|
+
property :title, validates: {presence: true}
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
songs = 50.times.collect { OpenStruct.new(title: "Be Stag") }
|
14
|
+
band = OpenStruct.new(name: "Teenage Bottlerock", songs: songs)
|
15
|
+
|
16
|
+
songs_params = 50.times.collect { {title: "Commando"} }
|
17
|
+
|
18
|
+
time = Benchmark.measure do
|
19
|
+
100.times.each do
|
20
|
+
form = BandForm.new(band)
|
21
|
+
form.validate("name" => "Ramones", "songs" => songs_params)
|
22
|
+
form.save
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
puts time
|
data/test/contract_test.rb
CHANGED
@@ -54,4 +54,44 @@ class ContractTest < BaseTest
|
|
54
54
|
|
55
55
|
it { subject.errors.messages.must_equal({}) }
|
56
56
|
end
|
57
|
+
|
58
|
+
|
59
|
+
describe "::representer" do
|
60
|
+
# without name will always iterate.
|
61
|
+
it do
|
62
|
+
names = []
|
63
|
+
AlbumContract.representer { |dfn| names << dfn.name }
|
64
|
+
names.must_equal ["hit", "songs", "band"]
|
65
|
+
|
66
|
+
# this doesn't cache.
|
67
|
+
names = []
|
68
|
+
AlbumContract.representer { |dfn| names << dfn.name }
|
69
|
+
names.must_equal ["hit", "songs", "band"]
|
70
|
+
end
|
71
|
+
|
72
|
+
# with name caches representer per class and runs once.
|
73
|
+
it do
|
74
|
+
names = []
|
75
|
+
AlbumContract.representer(:sync) { |dfn| names << dfn.name }
|
76
|
+
names.must_equal ["hit", "songs", "band"]
|
77
|
+
|
78
|
+
# this does cache.
|
79
|
+
names = []
|
80
|
+
AlbumContract.representer(:sync) { |dfn| names << dfn.name }
|
81
|
+
names.must_equal []
|
82
|
+
end
|
83
|
+
|
84
|
+
# it allows iterating all properties, not only nested.
|
85
|
+
it do
|
86
|
+
names = []
|
87
|
+
AlbumContract.representer(:save, all: true) { |dfn| names << dfn.name }
|
88
|
+
names.must_equal ["title", "hit", "songs", "band"]
|
89
|
+
|
90
|
+
names = []
|
91
|
+
AlbumContract.representer(:save, all: true) { |dfn| names << dfn.name }
|
92
|
+
names.must_equal []
|
93
|
+
end
|
94
|
+
|
95
|
+
# test :superclass?
|
96
|
+
end
|
57
97
|
end
|
data/test/empty_test.rb
CHANGED
@@ -1,11 +1,39 @@
|
|
1
1
|
require 'test_helper'
|
2
2
|
|
3
|
-
|
3
|
+
|
4
|
+
class DeprecatedVirtualTest < MiniTest::Spec # TODO: remove me in 2.0.
|
5
|
+
Location = Struct.new(:country)
|
6
|
+
|
7
|
+
class LocationForm < Reform::Form
|
8
|
+
property :country, virtual: true # this becomes readonly: true
|
9
|
+
end
|
10
|
+
|
11
|
+
let (:loc) { Location.new("Australia") }
|
12
|
+
let (:form) { LocationForm.new(loc) }
|
13
|
+
|
14
|
+
it { form.country.must_equal "Australia" }
|
15
|
+
it do
|
16
|
+
form.validate("country" => "Germany") # this usually won't change when submitting.
|
17
|
+
form.country.must_equal "Germany"
|
18
|
+
|
19
|
+
form.sync
|
20
|
+
loc.country.must_equal "Australia" # the writer wasn't called.
|
21
|
+
|
22
|
+
hash = {}
|
23
|
+
form.save do |nested|
|
24
|
+
hash = nested
|
25
|
+
end
|
26
|
+
|
27
|
+
hash.must_equal("country"=> "Germany")
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
class DeprecatedEmptyTest < MiniTest::Spec # don't read, don't write
|
4
32
|
Credentials = Struct.new(:password)
|
5
33
|
|
6
34
|
class PasswordForm < Reform::Form
|
7
35
|
property :password
|
8
|
-
property :password_confirmation, :
|
36
|
+
property :password_confirmation, empty: true
|
9
37
|
end
|
10
38
|
|
11
39
|
let (:cred) { Credentials.new }
|
@@ -15,7 +43,7 @@ class EmptyAttributesTest < MiniTest::Spec
|
|
15
43
|
form.validate("password" => "123", "password_confirmation" => "321")
|
16
44
|
|
17
45
|
form.password.must_equal "123"
|
18
|
-
form.password_confirmation.must_equal "321"
|
46
|
+
form.password_confirmation.must_equal "321" # this is still readable in the UI.
|
19
47
|
|
20
48
|
form.sync
|
21
49
|
cred.password.must_equal "123"
|
@@ -9,7 +9,7 @@ class FormCompositionTest < MiniTest::Spec
|
|
9
9
|
include Composition
|
10
10
|
|
11
11
|
property :name, :on => :requester
|
12
|
-
property :requester_id, :on => :requester, :
|
12
|
+
property :requester_id, :on => :requester, :from => :id
|
13
13
|
properties :title, :id, :on => :song
|
14
14
|
# property :channel # FIXME: what about the "main model"?
|
15
15
|
property :channel, :empty => true, :on => :song
|
data/test/from_test.rb
ADDED
@@ -0,0 +1,150 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class AsTest < BaseTest
|
4
|
+
class AlbumForm < Reform::Form
|
5
|
+
property :name, from: :title
|
6
|
+
|
7
|
+
property :single, from: :hit do
|
8
|
+
property :title
|
9
|
+
end
|
10
|
+
|
11
|
+
collection :tracks, from: :songs do
|
12
|
+
property :name, from: :title
|
13
|
+
end
|
14
|
+
|
15
|
+
property :band do
|
16
|
+
property :company, from: :label do
|
17
|
+
property :business, from: :name
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
let (:song2) { Song.new("Roxanne") }
|
23
|
+
|
24
|
+
let (:params) {
|
25
|
+
{
|
26
|
+
"name" => "Best Of The Police",
|
27
|
+
"single" => {"title" => "So Lonely"},
|
28
|
+
"tracks" => [{"name" => "Message In A Bottle"}, {"name" => "Roxanne"}]
|
29
|
+
}
|
30
|
+
}
|
31
|
+
|
32
|
+
subject { AlbumForm.new(Album.new("Best Of", hit, [Song.new("Fallout"), song2])) }
|
33
|
+
|
34
|
+
it { subject.name.must_equal "Best Of" }
|
35
|
+
it { subject.single.title.must_equal "Roxanne" }
|
36
|
+
it { subject.tracks[0].name.must_equal "Fallout" }
|
37
|
+
it { subject.tracks[1].name.must_equal "Roxanne" }
|
38
|
+
|
39
|
+
|
40
|
+
describe "#validate" do
|
41
|
+
|
42
|
+
|
43
|
+
before { subject.validate(params) }
|
44
|
+
|
45
|
+
it { subject.name.must_equal "Best Of The Police" }
|
46
|
+
it { subject.single.title.must_equal "So Lonely" }
|
47
|
+
it { subject.tracks[0].name.must_equal "Message In A Bottle" }
|
48
|
+
it { subject.tracks[1].name.must_equal "Roxanne" }
|
49
|
+
end
|
50
|
+
|
51
|
+
|
52
|
+
describe "#sync" do
|
53
|
+
before {
|
54
|
+
subject.tracks[1].name = "Livin' Ain't No Crime"
|
55
|
+
subject.sync
|
56
|
+
}
|
57
|
+
|
58
|
+
it { song2.title.must_equal "Livin' Ain't No Crime" }
|
59
|
+
end
|
60
|
+
|
61
|
+
|
62
|
+
describe "#save (nested hash)" do
|
63
|
+
before { subject.validate(params) }
|
64
|
+
|
65
|
+
it do
|
66
|
+
hash = nil
|
67
|
+
|
68
|
+
subject.save do |nested_hash|
|
69
|
+
hash = nested_hash
|
70
|
+
end
|
71
|
+
|
72
|
+
hash.must_equal({"title"=>"Best Of The Police", "hit"=>{"title"=>"So Lonely"}, "songs"=>[{"title"=>"Message In A Bottle"}, {"title"=>"Roxanne"}]})
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
|
78
|
+
class AsREMOVEMEin20Test < BaseTest # TODO: remove me in 2.0.
|
79
|
+
class AlbumForm < Reform::Form
|
80
|
+
property :name, as: :title
|
81
|
+
|
82
|
+
property :single, as: :hit do
|
83
|
+
property :title
|
84
|
+
end
|
85
|
+
|
86
|
+
collection :tracks, as: :songs do
|
87
|
+
property :name, as: :title
|
88
|
+
end
|
89
|
+
|
90
|
+
property :band do
|
91
|
+
property :company, as: :label do
|
92
|
+
property :business, as: :name
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
let (:song2) { Song.new("Roxanne") }
|
98
|
+
|
99
|
+
let (:params) {
|
100
|
+
{
|
101
|
+
"name" => "Best Of The Police",
|
102
|
+
"single" => {"title" => "So Lonely"},
|
103
|
+
"tracks" => [{"name" => "Message In A Bottle"}, {"name" => "Roxanne"}]
|
104
|
+
}
|
105
|
+
}
|
106
|
+
|
107
|
+
subject { AlbumForm.new(Album.new("Best Of", hit, [Song.new("Fallout"), song2])) }
|
108
|
+
|
109
|
+
it { subject.name.must_equal "Best Of" }
|
110
|
+
it { subject.single.title.must_equal "Roxanne" }
|
111
|
+
it { subject.tracks[0].name.must_equal "Fallout" }
|
112
|
+
it { subject.tracks[1].name.must_equal "Roxanne" }
|
113
|
+
|
114
|
+
|
115
|
+
describe "#validate" do
|
116
|
+
|
117
|
+
|
118
|
+
before { subject.validate(params) }
|
119
|
+
|
120
|
+
it { subject.name.must_equal "Best Of The Police" }
|
121
|
+
it { subject.single.title.must_equal "So Lonely" }
|
122
|
+
it { subject.tracks[0].name.must_equal "Message In A Bottle" }
|
123
|
+
it { subject.tracks[1].name.must_equal "Roxanne" }
|
124
|
+
end
|
125
|
+
|
126
|
+
|
127
|
+
describe "#sync" do
|
128
|
+
before {
|
129
|
+
subject.tracks[1].name = "Livin' Ain't No Crime"
|
130
|
+
subject.sync
|
131
|
+
}
|
132
|
+
|
133
|
+
it { song2.title.must_equal "Livin' Ain't No Crime" }
|
134
|
+
end
|
135
|
+
|
136
|
+
|
137
|
+
describe "#save (nested hash)" do
|
138
|
+
before { subject.validate(params) }
|
139
|
+
|
140
|
+
it do
|
141
|
+
hash = nil
|
142
|
+
|
143
|
+
subject.save do |nested_hash|
|
144
|
+
hash = nested_hash
|
145
|
+
end
|
146
|
+
|
147
|
+
hash.must_equal({"title"=>"Best Of The Police", "hit"=>{"title"=>"So Lonely"}, "songs"=>[{"title"=>"Message In A Bottle"}, {"title"=>"Roxanne"}]})
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
@@ -23,7 +23,7 @@ class ModelValidationsTest < MiniTest::Spec
|
|
23
23
|
extend ActiveModel::ModelValidations
|
24
24
|
|
25
25
|
property :title
|
26
|
-
property :artist_name,
|
26
|
+
property :artist_name, from: :artist
|
27
27
|
copy_validations_from Album
|
28
28
|
end
|
29
29
|
|
@@ -34,7 +34,7 @@ class ModelValidationsTest < MiniTest::Spec
|
|
34
34
|
model :album
|
35
35
|
|
36
36
|
property :title, on: :album
|
37
|
-
property :artist_name,
|
37
|
+
property :artist_name, from: :artist, on: :album
|
38
38
|
property :rating, on: :album_rating
|
39
39
|
|
40
40
|
copy_validations_from album: Album, album_rating: AlbumRating
|
data/test/nested_form_test.rb
CHANGED
@@ -94,10 +94,10 @@ class NestedFormTest < MiniTest::Spec
|
|
94
94
|
it "updates internal Fields" do
|
95
95
|
data = {}
|
96
96
|
|
97
|
-
form.save do |
|
98
|
-
data[:title] =
|
99
|
-
data[:hit_title] =
|
100
|
-
data[:first_title] =
|
97
|
+
form.save do |nested_hash|
|
98
|
+
data[:title] = form.title
|
99
|
+
data[:hit_title] = form.hit.title
|
100
|
+
data[:first_title] = form.songs.first.title
|
101
101
|
end
|
102
102
|
|
103
103
|
data.must_equal(:title=>"Second Heat", :hit_title => "Sacrifice", :first_title => "Scarified")
|
data/test/read_only_test.rb
CHANGED
@@ -1,28 +1,3 @@
|
|
1
1
|
require 'test_helper'
|
2
2
|
|
3
|
-
class ReadonlyAttributesTest < MiniTest::Spec
|
4
|
-
Location = Struct.new(:country)
|
5
3
|
|
6
|
-
class LocationForm < Reform::Form
|
7
|
-
property :country, virtual: true # read_only: true
|
8
|
-
end
|
9
|
-
|
10
|
-
let (:loc) { Location.new("Australia") }
|
11
|
-
let (:form) { LocationForm.new(loc) }
|
12
|
-
|
13
|
-
it { form.country.must_equal "Australia" }
|
14
|
-
it do
|
15
|
-
form.validate("country" => "Germany") # this usually won't change when submitting.
|
16
|
-
form.country.must_equal "Germany"
|
17
|
-
|
18
|
-
form.sync
|
19
|
-
loc.country.must_equal "Australia" # the writer wasn't called.
|
20
|
-
|
21
|
-
hash = {}
|
22
|
-
form.save do |nested|
|
23
|
-
hash = nested
|
24
|
-
end
|
25
|
-
|
26
|
-
hash.must_equal("country"=> "Germany")
|
27
|
-
end
|
28
|
-
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class ReadableTest < MiniTest::Spec
|
4
|
+
Credentials = Struct.new(:password)
|
5
|
+
|
6
|
+
class PasswordForm < Reform::Form
|
7
|
+
reform_2_0!
|
8
|
+
|
9
|
+
property :password, readable: false
|
10
|
+
end
|
11
|
+
|
12
|
+
let (:cred) { Credentials.new }
|
13
|
+
let (:form) { PasswordForm.new(cred) }
|
14
|
+
|
15
|
+
it {
|
16
|
+
form.password.must_equal nil
|
17
|
+
|
18
|
+
form.validate("password" => "123")
|
19
|
+
|
20
|
+
form.password.must_equal "123"
|
21
|
+
|
22
|
+
form.sync
|
23
|
+
cred.password.must_equal "123"
|
24
|
+
|
25
|
+
hash = {}
|
26
|
+
form.save do |nested|
|
27
|
+
hash = nested
|
28
|
+
end
|
29
|
+
|
30
|
+
hash.must_equal("password"=> "123")
|
31
|
+
}
|
32
|
+
end
|
data/test/reform_test.rb
CHANGED
@@ -143,27 +143,6 @@ class ReformTest < ReformSpec
|
|
143
143
|
end
|
144
144
|
|
145
145
|
describe "#save with block" do
|
146
|
-
it "Deprecated: provides data block argument" do # TODO: remove in 1.1.
|
147
|
-
hash = {}
|
148
|
-
|
149
|
-
form.save do |data, map|
|
150
|
-
hash[:name] = data.name
|
151
|
-
hash[:title] = data.title
|
152
|
-
end
|
153
|
-
|
154
|
-
hash.must_equal({:name=>"Diesel Boy", :title=>nil})
|
155
|
-
end
|
156
|
-
|
157
|
-
it "Deprecated: provides nested symbolized hash as second block argument" do # TODO: remove in 1.1.
|
158
|
-
hash = {}
|
159
|
-
|
160
|
-
form.save do |data, map|
|
161
|
-
hash = map
|
162
|
-
end
|
163
|
-
|
164
|
-
hash.must_equal({"name"=>"Diesel Boy"})
|
165
|
-
end
|
166
|
-
|
167
146
|
it do
|
168
147
|
hash = {}
|
169
148
|
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class VirtualTest < MiniTest::Spec
|
4
|
+
class CreditCardForm < Reform::Form
|
5
|
+
reform_2_0!
|
6
|
+
|
7
|
+
property :credit_card_number, virtual: true # no read, no write, it's virtual.
|
8
|
+
end
|
9
|
+
|
10
|
+
let (:form) { CreditCardForm.new(Object.new) }
|
11
|
+
|
12
|
+
it {
|
13
|
+
form.validate("credit_card_number" => "123")
|
14
|
+
|
15
|
+
form.credit_card_number.must_equal "123"
|
16
|
+
|
17
|
+
form.sync
|
18
|
+
|
19
|
+
hash = {}
|
20
|
+
form.save do |nested|
|
21
|
+
hash = nested
|
22
|
+
end
|
23
|
+
|
24
|
+
hash.must_equal("credit_card_number"=> "123")
|
25
|
+
}
|
26
|
+
end
|