reform 1.0.0 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 331784eaf17a8dc17f08c7c39cdb60af3bf502ed
4
- data.tar.gz: 48cc28e685c889c3fd7ca7290215c5c4d1801ec1
3
+ metadata.gz: dbf6193ca27f1a4d6694b198771ab0bc3fec6459
4
+ data.tar.gz: 797ddc8942d2fe5c7947833b4eb52d6d5dd7fc24
5
5
  SHA512:
6
- metadata.gz: 983557534185ed0d80afaccd6b433abb2ffe97fb5e44898bb915bb8d44b92f68d11447e2e30d7839be23c8f91cd374ffefe98a704eabe8f54763f13a09ade2dd
7
- data.tar.gz: fbf1dc09a1197491e17fd4e36d137a98309fa05310f18e40804093ba6e1af3b08959f524293eef751fe5cbc0a21e73bd915d1a76fdddf4eb63091e203332342e
6
+ metadata.gz: ba03b87c0652c7daff1b3c7a5cbb3d2807f2a70f0333bda323e6da7319be22907a9d11614d3c2d6c5064f02d0c93e2957bdf194e342cb5937f1667b85093ca26
7
+ data.tar.gz: 259e07b615f263a630891ae34400cf9d2aacc966fa50c0f666b49b3047cd4cd82d11563f2ea8376e560ea70534d58973d21bcc61d90487bda3570e83d47e1c9b
data/CHANGES.md CHANGED
@@ -1,3 +1,31 @@
1
+ ## 1.0.1
2
+
3
+ * Deprecated model readers for `Composition` and `ActiveModel`. Consider the following setup.
4
+ ```ruby
5
+ class RecordingForm < Reform::Form
6
+ include Composition
7
+
8
+ property :title, on: :song
9
+ end
10
+ ```
11
+
12
+ Before, Reform would allow you to do `form.song` which returned the song model. You can still do this (but you shouldn't) with `form.model[:song]`.
13
+
14
+ This allows having composed models and properties with the same name. Until 1.1, you have to use `skip_accessors: true` to advise Reform _not_ to create the deprecated accessor.
15
+
16
+ Also deprecated is the alias accessor as found with `ActiveModel`.
17
+ ```ruby
18
+ class RecordingForm < Reform::Form
19
+ include Composition
20
+ include ActiveModel
21
+
22
+ model :hit, on: :song
23
+ end
24
+ ```
25
+ Here, an automatic reader `Form#hit` was created. This is deprecated as
26
+
27
+ This is gonna be **removed in 1.1**.
28
+
1
29
  ## 1.0.0
2
30
 
3
31
  * Removed `Form::DSL` in favour of `Form::Composition`.
data/README.md CHANGED
@@ -42,7 +42,7 @@ To add fields to the form use the `::property` method. Also, validations no long
42
42
  Forms have a ridiculously simple API with only a handful of public methods.
43
43
 
44
44
  1. `#initialize` always requires a model that the form represents.
45
- 2. `#validate(params)` will run all validations for the form with the input data. Its return value is the boolean result of the validations.
45
+ 2. `#validate(params)` updates the form's fields with the input data (only the form, _not_ the model) and then runs all validations. The return value is the boolean result of the validations.
46
46
  3. `#errors` returns validation messages in a classy ActiveModel style.
47
47
  4. `#sync` writes form data back to the model. This will only use setter methods on the model(s).
48
48
  5. `#save` (optional) will call `#save` on the model and nested models. Note that this implies a `#sync` call.
@@ -52,7 +52,7 @@ In addition to the main API, forms expose accessors to the defined properties. T
52
52
 
53
53
  ## Setup
54
54
 
55
- In your controller you'd create a form instance and pass in the models you wanna work on.
55
+ In your controller you'd create a form instance and pass in the models you want to work on.
56
56
 
57
57
  ```ruby
58
58
  class SongsController
@@ -100,12 +100,12 @@ Your `@form` is now ready to be rendered, either do it yourself or use something
100
100
  = f.input :title
101
101
  ```
102
102
 
103
- Nested forms and collections can easily rendered with `fields_for`, etc. Just use Reform as if it would be an ActiveModel instance in the view layer.
103
+ Nested forms and collections can be easily rendered with `fields_for`, etc. Just use Reform as if it would be an ActiveModel instance in the view layer.
104
104
 
105
105
 
106
106
  ## Validation
107
107
 
108
- After a form submission, you wanna validate the input.
108
+ After a form submission, you want to validate the input.
109
109
 
110
110
  ```ruby
111
111
  class SongsController
@@ -117,9 +117,9 @@ class SongsController
117
117
  if @form.validate(params[:song])
118
118
  ```
119
119
 
120
- Reform uses the validations you provided in the form - and nothing else.
120
+ The `#validate` method first updates the values of the form - the underlying model is still treated as immutuable and *remains unchanged*. It then runs all validations you provided in the form.
121
121
 
122
- Note that Reform only updates values of the internal form attributes - the underlying model is still treated as immutuable and *remains unchanged*.
122
+ It's the only entry point for updating the form. This is per design, as separating writing and validation doesn't make sense for a form.
123
123
 
124
124
  This allows rendering the form after `validate` with the data that has been submitted. However, don't get confused, the model's values are still the old, original values and are only changed after a `#save` or `#sync` operation.
125
125
 
@@ -191,7 +191,7 @@ class AlbumContract < Reform::Contract
191
191
  end
192
192
  ```
193
193
 
194
- It defines the validations and the object graph to be run.
194
+ It defines the validations and the object graph to be inspected.
195
195
 
196
196
  In future versions and with the upcoming [Trailblazer framework](https://github.com/apotonick/trailblazer), contracts can be inherited from forms, representers, and cells, and vice-versa. Actually this already works with representer inheritance - let me know if you need help.
197
197
 
@@ -412,7 +412,7 @@ class AlbumForm < Reform::Form
412
412
 
413
413
  This works for both `property` and `collection` and instantiates `Song` objects where they're missing when calling `#validate`.
414
414
 
415
- If you wanna create the objects yourself, because you're smarter than Reform, do it with a lambda.
415
+ If you want to create the objects yourself, because you're smarter than Reform, do it with a lambda.
416
416
 
417
417
  ```ruby
418
418
  class AlbumForm < Reform::Form
@@ -537,7 +537,7 @@ form.save do |f, nested|
537
537
 
538
538
  ### Read-Only Fields
539
539
 
540
- Almost identical, the `:virtual` option makes fields read-only. Say you wanna show a value, but not process it after submission, this option is your friend.
540
+ Almost identical, the `:virtual` option makes fields read-only. Say you want to show a value, but not process it after submission, this option is your friend.
541
541
 
542
542
  ```ruby
543
543
  class ProfileForm < Reform::Form
@@ -619,7 +619,7 @@ class CoverSongForm < Reform::Form
619
619
  end
620
620
  ```
621
621
 
622
- This is especially helpful when your framework tries to render `cover_song_path` although you wanna go with `song_path`.
622
+ This is especially helpful when your framework tries to render `cover_song_path` although you want to go with `song_path`.
623
623
 
624
624
 
625
625
  ## FormBuilder Support
@@ -653,10 +653,10 @@ By explicitely defining the form layout using `::property` there is no more need
653
653
 
654
654
  When nesting form, you usually use a so-called inline form doing `property :song do .. end`.
655
655
 
656
- Sometimes you wanna specify an explicit form rather than using an inline form. Use the `form:` option here.
656
+ Sometimes you want to specify an explicit form rather than using an inline form. Use the `form:` option here.
657
657
 
658
658
  ```ruby
659
- property :song, form: SongForm`
659
+ property :song, form: SongForm
660
660
  ```
661
661
 
662
662
  The nested `SongForm` is a stand-alone form class you have to provide.
data/database.sqlite3 CHANGED
Binary file
@@ -38,6 +38,6 @@ module Reform::Form::ActiveRecord
38
38
  return model unless is_a?(Reform::Form::Composition) # i am too lazy for proper inheritance. there should be a ActiveRecord::Composition that handles this.
39
39
 
40
40
  model_name = mapper.representable_attrs[name][:on]
41
- send(model_name)
41
+ model[model_name]
42
42
  end
43
43
  end
@@ -18,7 +18,7 @@ module Reform::Form::Composition
18
18
 
19
19
  def property(name, options={})
20
20
  super.tap do |definition|
21
- delegate options[:on] => :@model # form.band -> composition.band
21
+ handle_deprecated_model_accessor(options[:on]) unless options[:skip_accessors] # TODO: remove in 1.2.
22
22
  end
23
23
  end
24
24
 
@@ -32,12 +32,25 @@ module Reform::Form::Composition
32
32
 
33
33
  composition_model = options[:on] || main_model
34
34
 
35
- delegate composition_model => :model # #song => model.song
35
+ handle_deprecated_model_accessor(composition_model) unless options[:skip_accessors] # TODO: remove in 1.2.
36
36
 
37
37
  # FIXME: this should just delegate to :model as in FB, and the comp would take care of it internally.
38
- delegate [:persisted?, :to_key, :to_param] => composition_model # #to_key => song.to_key
38
+ [:persisted?, :to_key, :to_param].each do |method|
39
+ define_method method do
40
+ model[composition_model].send(method)
41
+ end
42
+ end
43
+
44
+ alias_method main_model, composition_model # #hit => model.song. # TODO: remove in 1.2.
45
+ end
39
46
 
40
- alias_method main_model, composition_model # #hit => model.song.
47
+ private
48
+ def handle_deprecated_model_accessor(name, aliased=name)
49
+ define_method name do # form.band -> composition.band
50
+ warn %{[Reform] Deprecation WARNING: When using Composition, you may not call Form##{name} anymore to access the contained model. Please use Form#model[:#{name}] and have a lovely day!}
51
+
52
+ @model[name]
53
+ end
41
54
  end
42
55
  end
43
56
 
@@ -1,3 +1,3 @@
1
1
  module Reform
2
- VERSION = "1.0.0"
2
+ VERSION = "1.0.1"
3
3
  end
data/reform.gemspec CHANGED
@@ -10,7 +10,7 @@ Gem::Specification.new do |spec|
10
10
  spec.email = ["apotonick@gmail.com", "heinleng@gmail.com"]
11
11
  spec.description = %q{Freeing your AR models from form logic.}
12
12
  spec.summary = %q{Decouples your models from form by giving you form objects with validation, presentation, workflows and security.}
13
- spec.homepage = ""
13
+ spec.homepage = "https://github.com/apotonick/reform"
14
14
  spec.license = "MIT"
15
15
 
16
16
  spec.files = `git ls-files`.split($/)
@@ -19,7 +19,7 @@ Gem::Specification.new do |spec|
19
19
  spec.require_paths = ["lib"]
20
20
 
21
21
  spec.add_dependency "representable", "~> 1.8.1"
22
- spec.add_dependency "disposable", "~> 0.0.3"
22
+ spec.add_dependency "disposable", "~> 0.0.4"
23
23
  spec.add_dependency "uber", "~> 0.0.4"
24
24
  spec.add_dependency "activemodel"
25
25
  spec.add_development_dependency "bundler", "~> 1.3"
@@ -110,9 +110,9 @@ class ActiveModelWithCompositionTest < MiniTest::Spec
110
110
  let (:duran) { OpenStruct.new }
111
111
  let (:form) { HitForm.new(:song => rio, :artist => duran) }
112
112
 
113
- describe "main form reader #hit" do
113
+ describe "main form reader #hit" do# TODO: remove in 1.2. we don't support this reader #hit anymore.
114
114
  it "delegates to :on model" do
115
- form.hit.must_equal rio
115
+ form.hit.must_equal rio # TODO: remove in 1.2.
116
116
  end
117
117
 
118
118
  it "doesn't delegate when :on missing" do
@@ -177,6 +177,6 @@ class ActiveModelWithCompositionTest < MiniTest::Spec
177
177
  end
178
178
 
179
179
 
180
- AnotherForm.new(:song => rio).song.must_equal rio
180
+ AnotherForm.new(:song => rio).model[:song].must_equal rio
181
181
  end
182
182
  end
@@ -16,12 +16,6 @@ class CompositionTest < ReformSpec
16
16
  end
17
17
  end
18
18
 
19
- it "creates readers to models" do
20
- comp.song.object_id.must_equal rio.object_id
21
- comp.artist.object_id.must_equal @artist.object_id
22
- end
23
-
24
-
25
19
  describe "::from" do
26
20
  it "creates the same mapping" do
27
21
  comp =
@@ -2,23 +2,25 @@ require 'test_helper'
2
2
 
3
3
  class FormCompositionTest < MiniTest::Spec
4
4
  Song = Struct.new(:id, :title)
5
- Requester = Struct.new(:id, :name)
5
+ Requester = Struct.new(:id, :name, :requester)
6
6
 
7
7
  class RequestForm < Reform::Form
8
8
  include Composition
9
9
 
10
- property :name, :on => :requester
11
- property :requester_id, :on => :requester, :as => :id
10
+ # TODO: remove skip_accessors in 1.1.
11
+ property :name, :on => :requester, :skip_accessors => true
12
+ property :requester_id, :on => :requester, :as => :id, :skip_accessors => true
12
13
  properties [:title, :id], :on => :song
13
14
  # property :channel # FIXME: what about the "main model"?
14
15
  property :channel, :empty => true, :on => :song
16
+ property :requester, :on => :requester, :skip_accessors => true
15
17
 
16
18
  validates :name, :title, :channel, :presence => true
17
19
  end
18
20
 
19
21
  let (:form) { RequestForm.new(:song => song, :requester => requester) }
20
22
  let (:song) { Song.new(1, "Rio") }
21
- let (:requester) { Requester.new(2, "Duran Duran") }
23
+ let (:requester) { Requester.new(2, "Duran Duran", "MCP") }
22
24
 
23
25
 
24
26
  # delegation form -> composition works
@@ -27,10 +29,19 @@ class FormCompositionTest < MiniTest::Spec
27
29
  it { form.name.must_equal "Duran Duran" }
28
30
  it { form.requester_id.must_equal 2 }
29
31
  it { form.channel.must_equal nil }
32
+ it { form.requester.must_equal "MCP" } # same name as composed model.
30
33
 
34
+ # [DEPRECATED] # TODO: remove in 1.2.
31
35
  # delegation form -> composed models (e.g. when saving this can be handy)
32
- it { form.song.must_equal song }
33
- it { form.requester.must_equal requester }
36
+ it { form.song.must_equal song }
37
+
38
+
39
+ # #model just returns <Composition>.
40
+ it { form.model.must_be_kind_of Reform::Composition }
41
+
42
+ # #model[] -> composed models
43
+ it { form.model[:requester].must_equal requester }
44
+ it { form.model[:song].must_equal song }
34
45
 
35
46
 
36
47
  it "creates Composition for you" do
@@ -58,7 +69,7 @@ class FormCompositionTest < MiniTest::Spec
58
69
  hash = map
59
70
  end
60
71
 
61
- hash.must_equal({:song=>{:title=>"Greyhound", :id=>1, :channel => "JJJ"}, :requester=>{:name=>"Frenzal Rhomb", :id=>2}})
72
+ hash.must_equal({:song=>{:title=>"Greyhound", :id=>1, :channel => "JJJ"}, :requester=>{:name=>"Frenzal Rhomb", :id=>2, :requester => "MCP"}})
62
73
  end
63
74
 
64
75
  it "pushes data to models and calls #save when no block passed" do
data/test/reform_test.rb CHANGED
@@ -249,11 +249,9 @@ class EmptyAttributesTest < MiniTest::Spec
249
249
  let (:cred) { Credentials.new }
250
250
  let (:form) { PasswordForm.new(cred) }
251
251
 
252
- it { form }
252
+ before { form.validate("password" => "123", "password_confirmation" => "321") }
253
253
 
254
254
  it {
255
-
256
- form.validate("password" => "123", "password_confirmation" => "321")
257
255
  form.password.must_equal "123"
258
256
  form.password_confirmation.must_equal "321"
259
257
 
data/test/setup_test.rb CHANGED
@@ -1,8 +1,37 @@
1
1
  require 'test_helper'
2
2
 
3
3
  class SetupTest < BaseTest
4
+ class AlbumForm < Reform::Form
5
+ property :title
6
+
7
+ property :hit do
8
+ property :title
9
+ validates :title, :presence => true
10
+ end
11
+
12
+ collection :songs do
13
+ property :title
14
+ validates :title, :presence => true
15
+
16
+ property :length do
17
+ property :minutes
18
+ end
19
+ end
20
+
21
+ property :band do # yepp, people do crazy stuff like that.
22
+ property :label do
23
+ property :name
24
+ validates :name, :presence => true
25
+ end
26
+ # TODO: make band a required object.
27
+ end
28
+
29
+ validates :title, :presence => true
30
+ end
31
+
32
+
4
33
  describe "populated" do
5
- subject { AlbumForm.new(Album.new("Best Of", hit, [Song.new("Fallout"), Song.new("Roxanne")])) }
34
+ subject { AlbumForm.new(Album.new("Best Of", hit, [Song.new("Fallout", Length.new(2,3)), Song.new("Roxanne")])) }
6
35
 
7
36
  it { subject.title.must_equal "Best Of" }
8
37
 
@@ -15,6 +44,7 @@ class SetupTest < BaseTest
15
44
 
16
45
  it { subject.songs[0].must_be_kind_of Reform::Form }
17
46
  it { subject.songs[0].title.must_equal "Fallout" }
47
+ it { subject.songs[0].length.minutes.must_equal 2 }
18
48
 
19
49
  it { subject.songs[1].must_be_kind_of Reform::Form }
20
50
  it { subject.songs[1].title.must_equal "Roxanne" }
data/test/test_helper.rb CHANGED
@@ -29,10 +29,11 @@ class BaseTest < MiniTest::Spec
29
29
  end
30
30
  end
31
31
 
32
- Song = Struct.new(:title)
33
- Album = Struct.new(:title, :hit, :songs, :band)
34
- Band = Struct.new(:label)
35
- Label = Struct.new(:name)
32
+ Song = Struct.new(:title, :length)
33
+ Album = Struct.new(:title, :hit, :songs, :band)
34
+ Band = Struct.new(:label)
35
+ Label = Struct.new(:name)
36
+ Length = Struct.new(:minutes, :seconds)
36
37
 
37
38
 
38
39
  let (:hit) { Song.new("Roxanne") }
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: reform
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nick Sutterer
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-05-05 00:00:00.000000000 Z
12
+ date: 2014-05-21 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: representable
@@ -31,14 +31,14 @@ dependencies:
31
31
  requirements:
32
32
  - - "~>"
33
33
  - !ruby/object:Gem::Version
34
- version: 0.0.3
34
+ version: 0.0.4
35
35
  type: :runtime
36
36
  prerelease: false
37
37
  version_requirements: !ruby/object:Gem::Requirement
38
38
  requirements:
39
39
  - - "~>"
40
40
  - !ruby/object:Gem::Version
41
- version: 0.0.3
41
+ version: 0.0.4
42
42
  - !ruby/object:Gem::Dependency
43
43
  name: uber
44
44
  requirement: !ruby/object:Gem::Requirement
@@ -248,7 +248,7 @@ files:
248
248
  - test/sync_test.rb
249
249
  - test/test_helper.rb
250
250
  - test/validate_test.rb
251
- homepage: ''
251
+ homepage: https://github.com/apotonick/reform
252
252
  licenses:
253
253
  - MIT
254
254
  metadata: {}