reform 1.0.0 → 1.0.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 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: {}