reform 1.2.6 → 2.0.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +6 -1
  3. data/CHANGES.md +14 -0
  4. data/Gemfile +3 -2
  5. data/README.md +225 -283
  6. data/Rakefile +27 -0
  7. data/TODO.md +12 -0
  8. data/database.sqlite3 +0 -0
  9. data/gemfiles/Gemfile.rails-3.0 +1 -0
  10. data/gemfiles/Gemfile.rails-3.1 +1 -0
  11. data/gemfiles/Gemfile.rails-3.2 +1 -0
  12. data/gemfiles/Gemfile.rails-4.0 +1 -0
  13. data/lib/reform.rb +0 -1
  14. data/lib/reform/contract.rb +64 -170
  15. data/lib/reform/contract/validate.rb +10 -13
  16. data/lib/reform/form.rb +74 -19
  17. data/lib/reform/form/active_model.rb +19 -14
  18. data/lib/reform/form/coercion.rb +1 -13
  19. data/lib/reform/form/composition.rb +2 -24
  20. data/lib/reform/form/multi_parameter_attributes.rb +43 -62
  21. data/lib/reform/form/populator.rb +85 -0
  22. data/lib/reform/form/prepopulate.rb +13 -43
  23. data/lib/reform/form/validate.rb +29 -90
  24. data/lib/reform/form/validation/unique_validator.rb +13 -0
  25. data/lib/reform/version.rb +1 -1
  26. data/reform.gemspec +7 -7
  27. data/test/active_model_test.rb +43 -0
  28. data/test/changed_test.rb +23 -51
  29. data/test/coercion_test.rb +1 -7
  30. data/test/composition_test.rb +128 -34
  31. data/test/contract_test.rb +27 -86
  32. data/test/feature_test.rb +43 -6
  33. data/test/fields_test.rb +2 -12
  34. data/test/form_builder_test.rb +28 -25
  35. data/test/form_option_test.rb +19 -0
  36. data/test/from_test.rb +0 -75
  37. data/test/inherit_test.rb +178 -117
  38. data/test/model_reflections_test.rb +1 -1
  39. data/test/populate_test.rb +226 -0
  40. data/test/prepopulator_test.rb +112 -0
  41. data/test/readable_test.rb +2 -4
  42. data/test/save_test.rb +56 -112
  43. data/test/setup_test.rb +48 -0
  44. data/test/skip_if_test.rb +5 -2
  45. data/test/skip_setter_and_getter_test.rb +54 -0
  46. data/test/test_helper.rb +3 -1
  47. data/test/uniqueness_test.rb +41 -0
  48. data/test/validate_test.rb +325 -289
  49. data/test/virtual_test.rb +1 -3
  50. data/test/writeable_test.rb +3 -4
  51. metadata +35 -39
  52. data/lib/reform/composition.rb +0 -63
  53. data/lib/reform/contract/setup.rb +0 -50
  54. data/lib/reform/form/changed.rb +0 -9
  55. data/lib/reform/form/sync.rb +0 -116
  56. data/lib/reform/representer.rb +0 -84
  57. data/test/empty_test.rb +0 -58
  58. data/test/form_composition_test.rb +0 -145
  59. data/test/nested_form_test.rb +0 -197
  60. data/test/prepopulate_test.rb +0 -85
  61. data/test/sync_option_test.rb +0 -83
  62. data/test/sync_test.rb +0 -56
@@ -0,0 +1,13 @@
1
+ class Reform::Form::UniqueValidator < ActiveModel::EachValidator
2
+ def validate_each(form, attribute, value)
3
+ # search for models with attribute equals to form field value
4
+ query = form.model.class.where(attribute => value)
5
+
6
+ # if model persisted, excluded own model from query
7
+ query = query.merge(form.model.class.where("id <> ?", form.model.id)) if form.model.persisted?
8
+
9
+ # if any models found, add error on attribute
10
+ form.errors.add(attribute, "#{attribute} must be unique.") if query.any?
11
+ end
12
+ end
13
+
@@ -1,3 +1,3 @@
1
1
  module Reform
2
- VERSION = "1.2.6"
2
+ VERSION = "2.0.0.beta1"
3
3
  end
data/reform.gemspec CHANGED
@@ -1,4 +1,3 @@
1
- # coding: utf-8
2
1
  lib = File.expand_path('../lib', __FILE__)
3
2
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
3
  require 'reform/version'
@@ -8,8 +7,8 @@ Gem::Specification.new do |spec|
8
7
  spec.version = Reform::VERSION
9
8
  spec.authors = ["Nick Sutterer", "Garrett Heinlen"]
10
9
  spec.email = ["apotonick@gmail.com", "heinleng@gmail.com"]
11
- spec.description = %q{Freeing your AR models from form logic.}
12
- spec.summary = %q{Decouples your models from form by giving you form objects with validation, presentation, workflows and security.}
10
+ spec.description = %q{Form object decoupled from models.}
11
+ spec.summary = %q{Form object decoupled from models with validation, population and presentation.}
13
12
  spec.homepage = "https://github.com/apotonick/reform"
14
13
  spec.license = "MIT"
15
14
 
@@ -18,13 +17,14 @@ Gem::Specification.new do |spec|
18
17
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
18
  spec.require_paths = ["lib"]
20
19
 
21
- spec.add_dependency "representable", "~> 2.1.0"
22
- spec.add_dependency "disposable", "~> 0.0.5"
20
+ spec.add_dependency "representable", ">= 2.2.2"
21
+ spec.add_dependency "disposable", "~> 0.1.2"
23
22
  spec.add_dependency "uber", "~> 0.0.11"
24
23
  spec.add_dependency "activemodel"
25
- spec.add_development_dependency "bundler", "~> 1.3"
24
+
25
+ spec.add_development_dependency "bundler"
26
26
  spec.add_development_dependency "rake"
27
- spec.add_development_dependency "minitest", "5.4.1"
27
+ spec.add_development_dependency "minitest"
28
28
  spec.add_development_dependency "activerecord"
29
29
  spec.add_development_dependency "sqlite3"
30
30
  spec.add_development_dependency "virtus"
@@ -1,5 +1,20 @@
1
1
  require 'test_helper'
2
2
 
3
+ module IsolatedRailsEngine
4
+ def self.use_relative_model_naming?
5
+ true
6
+ end
7
+
8
+ class Lyric < ActiveRecord::Base
9
+ end
10
+ end
11
+
12
+ module NormalRailsEngine
13
+ class Lyric < ActiveRecord::Base
14
+ end
15
+ end
16
+
17
+
3
18
  class NewActiveModelTest < MiniTest::Spec # TODO: move to test/rails/
4
19
  class SongForm < Reform::Form
5
20
  include Reform::Form::ActiveModel
@@ -31,6 +46,27 @@ class NewActiveModelTest < MiniTest::Spec # TODO: move to test/rails/
31
46
  it { class_with_model.model_name.must_be_kind_of ActiveModel::Name }
32
47
  it { class_with_model.model_name.to_s.must_equal "Album" }
33
48
 
49
+ let (:class_with_isolated_model) {
50
+ Class.new(Reform::Form) do
51
+ include Reform::Form::ActiveModel
52
+
53
+ model "isolated_rails_engine/lyric", namespace: "isolated_rails_engine"
54
+ end
55
+ }
56
+
57
+ it { class_with_isolated_model.model_name.must_be_kind_of ActiveModel::Name }
58
+ it { class_with_isolated_model.model_name.to_s.must_equal "IsolatedRailsEngine::Lyric" }
59
+
60
+ let (:class_with_namespace_model) {
61
+ Class.new(Reform::Form) do
62
+ include Reform::Form::ActiveModel
63
+
64
+ model "normal_rails_engine/lyric"
65
+ end
66
+ }
67
+
68
+ it { class_with_namespace_model.model_name.must_be_kind_of ActiveModel::Name }
69
+ it { class_with_namespace_model.model_name.to_s.must_equal "NormalRailsEngine::Lyric" }
34
70
 
35
71
  let (:subclass_of_class_with_model) {
36
72
  Class.new(class_with_model)
@@ -39,6 +75,13 @@ class NewActiveModelTest < MiniTest::Spec # TODO: move to test/rails/
39
75
  it { subclass_of_class_with_model.model_name.must_be_kind_of ActiveModel::Name }
40
76
  it { subclass_of_class_with_model.model_name.to_s.must_equal 'Album' }
41
77
 
78
+ unless Reform.rails3_0?
79
+ it { form.class.model_name.route_key.must_equal "new_active_model_test_songs" }
80
+ it { class_with_model.model_name.route_key.must_equal "albums" }
81
+ it { class_with_isolated_model.model_name.route_key.must_equal "lyrics" }
82
+ it { class_with_namespace_model.model_name.route_key.must_equal "normal_rails_engine_lyrics" }
83
+ it { subclass_of_class_with_model.model_name.route_key.must_equal 'albums' }
84
+ end
42
85
 
43
86
  describe "class named Song::Form" do
44
87
  it do
data/test/changed_test.rb CHANGED
@@ -1,69 +1,41 @@
1
1
  require 'test_helper'
2
2
  require 'reform/form/coercion'
3
3
 
4
- class ChangedTest < BaseTest
5
- class AlbumForm < Reform::Form
6
- include Coercion
7
-
8
- property :title
4
+ class ChangedTest < MiniTest::Spec
5
+ Song = Struct.new(:title, :album, :composer)
6
+ Album = Struct.new(:name, :songs, :artist)
7
+ Artist = Struct.new(:name)
9
8
 
10
- property :hit do
11
- property :title
12
- property :length, type: Integer
13
- validates :title, :presence => true
14
- end
9
+ class AlbumForm < Reform::Form
10
+ property :name
15
11
 
16
12
  collection :songs do
17
13
  property :title
18
- validates :title, :presence => true
19
- end
20
14
 
21
- property :band do # yepp, people do crazy stuff like that.
22
- property :label do
15
+ property :composer do
23
16
  property :name
24
- property :location
25
- validates :name, :presence => true
26
17
  end
27
- # TODO: make band a required object.
28
18
  end
29
-
30
- validates :title, :presence => true
31
19
  end
32
20
 
33
- Label = Struct.new(:name, :location)
21
+ let (:song_with_composer) { Song.new("Resist Stance", nil, composer) }
22
+ let (:composer) { Artist.new("Greg Graffin") }
23
+ let (:album) { Album.new("The Dissent Of Man", [song_with_composer]) }
34
24
 
35
- # setup: changed? is always false
36
- let (:form) { AlbumForm.new(Album.new("Drawn Down The Moon", Song.new("The Ripper", 9), [Song.new("Black Candles"), Song.new("The Ripper")], Band.new(Label.new("Cleopatra Records")))) }
25
+ let (:form) { AlbumForm.new(album) }
37
26
 
38
- it { form.changed?(:title).must_equal false }
39
- it { form.changed?("title").must_equal false }
40
- it { form.hit.changed?(:title).must_equal false }
41
- it { form.hit.changed?.must_equal false }
42
-
43
-
44
- describe "#validate" do
45
- before { form.validate(
46
- "title" => "Five", # changed.
47
- "hit" => {"title" => "The Ripper", # same, but overridden.
48
- "length" => "9"}, # gets coerced, then compared, so not changed.
49
- "band" => {"label" => {"name" => "Shrapnel Records"}} # only label.name changes.
50
- ) }
51
-
52
- it { form.changed?(:title).must_equal true }
53
-
54
- # it { form.changed?(:hit).must_equal false }
55
-
56
- # overridden with same value is no change.
57
- it { form.hit.changed?(:title).must_equal false }
58
- # coerced value is identical to form's => not changed.
59
- it { form.hit.changed?(:length).must_equal false }
60
-
61
- # it { form.changed?(:band).must_equal true }
62
- # it { form.band.changed?(:label).must_equal true }
63
- it { form.band.label.changed?(:name).must_equal true }
27
+ # nothing changed after setup.
28
+ it do
29
+ form.changed?(:name).must_equal false
30
+ form.songs[0].changed?(:title).must_equal false
31
+ form.songs[0].composer.changed?(:name).must_equal false
32
+ end
64
33
 
65
- # not present key/value in #validate is no change.
66
- it { form.band.label.changed?(:location).must_equal false }
67
- # TODO: parent form changed when child has changed!
34
+ # after validate, things might have changed.
35
+ it do
36
+ form.validate("name" => "Out Of Bounds", "songs" => [{"composer" => {"name" => "Ingemar Jansson & Mikael Danielsson"}}])
37
+ form.changed?(:name).must_equal true
38
+ form.songs[0].changed?(:title).must_equal false
39
+ form.songs[0].composer.changed?(:name).must_equal true
68
40
  end
69
41
  end
@@ -9,20 +9,17 @@ class CoercionTest < BaseTest
9
9
  end
10
10
 
11
11
  class Form < Reform::Form
12
- include Coercion
12
+ # include Coercion
13
13
 
14
14
  property :released_at, :type => DateTime
15
15
 
16
16
  property :hit do
17
- # include Coercion
18
17
  property :length, :type => Integer
19
18
  property :good, :type => Virtus::Attribute::Boolean
20
19
  end
21
20
 
22
21
  property :band do
23
- include Coercion
24
22
  property :label do
25
- include Coercion
26
23
  property :value, :type => Irreversible
27
24
  end
28
25
  end
@@ -66,7 +63,4 @@ class CoercionTest < BaseTest
66
63
  end
67
64
 
68
65
  # save
69
-
70
-
71
-
72
66
  end
@@ -1,51 +1,145 @@
1
- class CompositionTest < ReformSpec
2
- class SongAndArtist < Reform::Composition
3
- map({:artist => [[:name]], :song => [[:title]]}) #SongAndArtistMap.representable_attrs
1
+ require 'test_helper'
2
+
3
+ class FormCompositionTest < MiniTest::Spec
4
+ Song = Struct.new(:id, :title, :band)
5
+ Requester = Struct.new(:id, :name, :requester)
6
+ Band = Struct.new(:title)
7
+
8
+ class RequestForm < Reform::Form
9
+ include Composition
10
+
11
+ property :name, :on => :requester
12
+ property :requester_id, :on => :requester, :from => :id
13
+ properties :title, :id, :on => :song
14
+ # property :channel # FIXME: what about the "main model"?
15
+ property :channel, :virtual => true, :on => :song
16
+ property :requester, :on => :requester
17
+ property :captcha, :on => :song, :virtual => true
18
+
19
+ validates :name, :title, :channel, :presence => true
20
+
21
+ property :band, :on => :song do
22
+ property :title
23
+ end
4
24
  end
5
25
 
6
- let (:comp) { SongAndArtist.new(:artist => @artist=OpenStruct.new, :song => rio) }
26
+ let (:form) { RequestForm.new(:song => song, :requester => requester) }
27
+ let (:song) { Song.new(1, "Rio", band) }
28
+ let (:requester) { Requester.new(2, "Duran Duran", "MCP") }
29
+ let (:band) { Band.new("Duran^2") }
30
+
31
+ # delegation form -> composition works
32
+ it { form.id.must_equal 1 }
33
+ it { form.title.must_equal "Rio" }
34
+ it { form.name.must_equal "Duran Duran" }
35
+ it { form.requester_id.must_equal 2 }
36
+ it { form.channel.must_equal nil }
37
+ it { form.requester.must_equal "MCP" } # same name as composed model.
38
+ it { form.captcha.must_equal nil }
39
+
40
+ # #model just returns <Composition>.
41
+ it { form.mapper.must_be_kind_of Disposable::Composition }
7
42
 
8
- it "delegates to models as defined" do
9
- comp.name.must_equal nil
10
- comp.title.must_equal "Rio"
43
+ # #model[] -> composed models
44
+ it { form.model[:requester].must_equal requester }
45
+ it { form.model[:song].must_equal song }
46
+
47
+
48
+ it "creates Composition for you" do
49
+ form.validate("title" => "Greyhound", "name" => "Frenzal Rhomb").must_equal false
11
50
  end
12
51
 
13
- it "raises when non-mapped property" do
14
- assert_raises NoMethodError do
15
- comp.raise_an_exception
52
+ describe "#save" do
53
+ # #save with {}
54
+ it do
55
+ hash = {}
56
+
57
+ form.save do |map|
58
+ hash[:name] = form.name
59
+ hash[:title] = form.title
60
+ end
61
+
62
+ hash.must_equal({:name=>"Duran Duran", :title=>"Rio"})
16
63
  end
17
- end
18
64
 
19
- describe "::from" do
20
- it "creates the same mapping" do
21
- comp =
22
- Reform::Composition.from(
23
- Class.new(Reform::Representer) do
24
- property :name, :on => :artist
25
- property :title, :on => :song
26
- end
27
- ).
28
- new(:artist => duran, :song => rio)
65
+ it "provides nested symbolized hash as second block argument" do
66
+ form.validate("title" => "Greyhound", "name" => "Frenzal Rhomb", "channel" => "JJJ", "captcha" => "wonderful")
67
+
68
+ hash = nil
29
69
 
30
- comp.name.must_equal "Duran Duran"
31
- comp.title.must_equal "Rio"
70
+ form.save do |map|
71
+ hash = map
72
+ end
73
+
74
+ hash.must_equal({
75
+ :song=>{"title"=>"Greyhound", "id"=>1, "channel" => "JJJ", "captcha"=>"wonderful", "band"=>{"title"=>"Duran^2"}},
76
+ :requester=>{"name"=>"Frenzal Rhomb", "id"=>2, "requester" => "MCP"}
77
+ }
78
+ )
32
79
  end
33
- end
34
80
 
81
+ it "xxx pushes data to models and calls #save when no block passed" do
82
+ song.extend(Saveable)
83
+ requester.extend(Saveable)
84
+ band.extend(Saveable)
35
85
 
36
- describe "#nested_hash_for" do
37
- it "returns nested hash" do
38
- comp.nested_hash_for(:name => "Jimi Hendrix", :title => "Fire").must_equal({:artist=>{:name=>"Jimi Hendrix"}, :song=>{:title=>"Fire"}})
86
+ form.validate("title" => "Greyhound", "name" => "Frenzal Rhomb", "captcha" => "1337")
87
+ form.captcha.must_equal "1337" # TODO: move to separate test.
88
+
89
+ form.save
90
+
91
+ requester.name.must_equal "Frenzal Rhomb"
92
+ requester.saved?.must_equal true
93
+ song.title.must_equal "Greyhound"
94
+ song.saved?.must_equal true
95
+ song.band.title.must_equal "Duran^2"
96
+ song.band.saved?.must_equal true
39
97
  end
40
98
 
41
- it "works with strings" do
42
- comp.nested_hash_for("name" => "Jimi Hendrix", "title" => "Fire").must_equal({:artist=>{:name=>"Jimi Hendrix"}, :song=>{:title=>"Fire"}})
99
+ it "returns true when models all save successfully" do
100
+ song.extend(Saveable)
101
+ requester.extend(Saveable)
102
+ band.extend(Saveable)
103
+
104
+ form.save.must_equal true
43
105
  end
44
106
 
45
- it "works with strings in map" do
46
- Class.new(Reform::Composition) do
47
- map(:artist => [["name"]])
48
- end.new({}).nested_hash_for(:name => "Jimi Hendrix").must_equal({:artist=>{:name=>"Jimi Hendrix"}})
107
+ it "returns false when one or more models don't save successfully" do
108
+ module Unsaveable
109
+ def save
110
+ false
111
+ end
112
+ end
113
+
114
+ song.extend(Unsaveable)
115
+ requester.extend(Saveable)
116
+ band.extend(Saveable)
117
+
118
+ form.save.must_equal false
49
119
  end
50
120
  end
51
- end
121
+ end
122
+
123
+
124
+ class FormCompositionCollectionTest < MiniTest::Spec
125
+ Book = Struct.new(:id, :name)
126
+ Library = Struct.new(:id) do
127
+ def books
128
+ [Book.new(1,"My book")]
129
+ end
130
+ end
131
+
132
+ class LibraryForm < Reform::Form
133
+ include Reform::Form::Composition
134
+
135
+ collection :books, on: :library do
136
+ property :id
137
+ property :name
138
+ end
139
+ end
140
+
141
+ let (:form) { LibraryForm.new(library: library) }
142
+ let (:library) { Library.new(2) }
143
+
144
+ it { form.save do |hash| hash.must_equal({:library=>{"books"=>[{"id"=>1, "name"=>"My book"}]}}) end }
145
+ end
@@ -1,105 +1,46 @@
1
1
  require 'test_helper'
2
2
 
3
- class ContractTest < BaseTest
4
- class AlbumContract < Reform::Contract
5
- property :title
6
- validates :title, :presence => true, :length => {:minimum => 3}
3
+ class ContractTest < MiniTest::Spec
4
+ Song = Struct.new(:title, :album, :composer)
5
+ Album = Struct.new(:name, :songs, :artist)
6
+ Artist = Struct.new(:name)
7
7
 
8
- property :hit do
9
- property :title
10
- validates :title, :presence => true
11
- end
8
+ class ArtistForm < Reform::Form
9
+ property :name
10
+ end
11
+
12
+ class AlbumForm < Reform::Contract
13
+ property :name
14
+ validates :name, presence: true
12
15
 
13
16
  collection :songs do
14
17
  property :title
15
- validates :title, :presence => true
16
- end
17
-
18
- validates :songs, :length => {:minimum => 4}
19
-
20
- property :band do # yepp, people do crazy stuff like that.
21
- validates :label, :presence => true
18
+ validates :title, presence: true
22
19
 
23
- property :label do
20
+ property :composer do
21
+ validates :name, presence: true
24
22
  property :name
25
- validates :name, :presence => true
26
23
  end
27
- # TODO: make band a required object.
28
24
  end
29
- end
30
-
31
- let (:album) { Album.new(nil, Song.new, [Song.new, Song.new], Band.new() ) }
32
- subject { AlbumContract.new(album) }
33
-
34
-
35
- describe "invalid" do
36
- before {
37
- res = subject.validate
38
- res.must_equal false
39
- }
40
-
41
- it { subject.errors.messages.must_equal({:"hit.title"=>["can't be blank"], :"songs.title"=>["can't be blank"], :"band.label"=>["can't be blank"], :songs=>["is too short (minimum is 4 characters)"], :title=>["can't be blank", "is too short (minimum is 3 characters)"]}) }
42
- end
43
25
 
44
-
45
- describe "valid" do
46
- let (:album) { Album.new(
47
- "Keeper Of The Seven Keys",
48
- nil,
49
- [Song.new("Initiation"), Song.new("I'm Alive"), Song.new("A Little Time"), Song.new("Future World"),],
50
- Band.new(Label.new("Noise"))
51
- ) }
52
-
53
- before { subject.validate.must_equal true }
54
-
55
- it { subject.errors.messages.must_equal({}) }
26
+ property :artist, form: ArtistForm
56
27
  end
57
28
 
29
+ let (:song) { Song.new("Broken") }
30
+ let (:song_with_composer) { Song.new("Resist Stance", nil, composer) }
31
+ let (:composer) { Artist.new("Greg Graffin") }
32
+ let (:artist) { Artist.new("Bad Religion") }
33
+ let (:album) { Album.new("The Dissent Of Man", [song, song_with_composer], artist) }
58
34
 
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
35
+ let (:form) { AlbumForm.new(album) }
97
36
 
98
- class SongContract < Reform::Contract
99
- property :title, readable: true, type: String
37
+ # accept `property form: SongForm`.
38
+ it do
39
+ form.artist.must_be_instance_of ArtistForm
100
40
  end
101
41
 
102
42
  describe "#options_for" do
103
- it { SongContract.new(OpenStruct.new).options_for(:title)[:coercion_type].must_equal String }
43
+ it { AlbumForm.options_for(:name).inspect.must_match "#<Representable::Definition ==>name @options" }
44
+ it { AlbumForm.new(album).options_for(:name).inspect.must_match "#<Representable::Definition ==>name @options" }
104
45
  end
105
- end
46
+ end