reform 2.2.4
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 +7 -0
- data/.gitignore +18 -0
- data/.travis.yml +11 -0
- data/CHANGES.md +415 -0
- data/Gemfile +19 -0
- data/LICENSE.txt +22 -0
- data/README.md +339 -0
- data/Rakefile +15 -0
- data/TODO.md +45 -0
- data/gemfiles/Gemfile.disposable-0.3 +6 -0
- data/lib/reform.rb +8 -0
- data/lib/reform/contract.rb +77 -0
- data/lib/reform/contract/errors.rb +43 -0
- data/lib/reform/contract/validate.rb +33 -0
- data/lib/reform/form.rb +94 -0
- data/lib/reform/form/call.rb +23 -0
- data/lib/reform/form/coercion.rb +3 -0
- data/lib/reform/form/composition.rb +34 -0
- data/lib/reform/form/dry.rb +67 -0
- data/lib/reform/form/module.rb +27 -0
- data/lib/reform/form/mongoid.rb +37 -0
- data/lib/reform/form/orm.rb +26 -0
- data/lib/reform/form/populator.rb +123 -0
- data/lib/reform/form/prepopulate.rb +24 -0
- data/lib/reform/form/validate.rb +60 -0
- data/lib/reform/mongoid.rb +4 -0
- data/lib/reform/validation.rb +40 -0
- data/lib/reform/validation/groups.rb +73 -0
- data/lib/reform/version.rb +3 -0
- data/reform.gemspec +29 -0
- data/test/benchmarking.rb +26 -0
- data/test/call_test.rb +23 -0
- data/test/changed_test.rb +41 -0
- data/test/coercion_test.rb +66 -0
- data/test/composition_test.rb +149 -0
- data/test/contract_test.rb +77 -0
- data/test/default_test.rb +22 -0
- data/test/deprecation_test.rb +27 -0
- data/test/deserialize_test.rb +104 -0
- data/test/errors_test.rb +165 -0
- data/test/feature_test.rb +65 -0
- data/test/fixtures/dry_error_messages.yml +44 -0
- data/test/form_option_test.rb +24 -0
- data/test/form_test.rb +57 -0
- data/test/from_test.rb +75 -0
- data/test/inherit_test.rb +119 -0
- data/test/module_test.rb +142 -0
- data/test/parse_pipeline_test.rb +15 -0
- data/test/populate_test.rb +270 -0
- data/test/populator_skip_test.rb +28 -0
- data/test/prepopulator_test.rb +112 -0
- data/test/read_only_test.rb +3 -0
- data/test/readable_test.rb +30 -0
- data/test/readonly_test.rb +14 -0
- data/test/reform_test.rb +223 -0
- data/test/save_test.rb +89 -0
- data/test/setup_test.rb +48 -0
- data/test/skip_if_test.rb +74 -0
- data/test/skip_setter_and_getter_test.rb +54 -0
- data/test/test_helper.rb +49 -0
- data/test/validate_test.rb +420 -0
- data/test/validation/dry_test.rb +60 -0
- data/test/validation/dry_validation_test.rb +352 -0
- data/test/validation/errors.yml +4 -0
- data/test/virtual_test.rb +24 -0
- data/test/writeable_test.rb +29 -0
- metadata +265 -0
    
        data/test/errors_test.rb
    ADDED
    
    | @@ -0,0 +1,165 @@ | |
| 1 | 
            +
            require "test_helper"
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            class ErrorsTest < MiniTest::Spec
         | 
| 4 | 
            +
              class AlbumForm < Reform::Form
         | 
| 5 | 
            +
                property :title
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                property :hit do
         | 
| 8 | 
            +
                  property :title
         | 
| 9 | 
            +
                  validation do
         | 
| 10 | 
            +
                    required(:title).filled
         | 
| 11 | 
            +
                  end
         | 
| 12 | 
            +
                end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                collection :songs do
         | 
| 15 | 
            +
                  property :title
         | 
| 16 | 
            +
                  validation do
         | 
| 17 | 
            +
                    required(:title).filled
         | 
| 18 | 
            +
                  end
         | 
| 19 | 
            +
                end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                property :band do # yepp, people do crazy stuff like that.
         | 
| 22 | 
            +
                  property :name
         | 
| 23 | 
            +
                  property :label do
         | 
| 24 | 
            +
                    property :name
         | 
| 25 | 
            +
                    validation do
         | 
| 26 | 
            +
                      required(:name).filled
         | 
| 27 | 
            +
                    end
         | 
| 28 | 
            +
                  end
         | 
| 29 | 
            +
                  # TODO: make band a required object.
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                  validation do
         | 
| 32 | 
            +
                    # required(:name).filled(:music_taste_ok?)
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                    configure do
         | 
| 35 | 
            +
                      config.messages_file = "test/validation/errors.yml"
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                      def music_taste_ok?(value)
         | 
| 38 | 
            +
                        value != "Nickelback"
         | 
| 39 | 
            +
                        # errors.add(:base, "You are a bad person") if name == "Nickelback"
         | 
| 40 | 
            +
                      end
         | 
| 41 | 
            +
                    end
         | 
| 42 | 
            +
                  end
         | 
| 43 | 
            +
                  # validate :music_taste_ok?
         | 
| 44 | 
            +
             | 
| 45 | 
            +
                # private
         | 
| 46 | 
            +
                #   def music_taste_ok?
         | 
| 47 | 
            +
                #     errors.add(:base, "You are a bad person") if name == "Nickelback"
         | 
| 48 | 
            +
                #   end
         | 
| 49 | 
            +
                end
         | 
| 50 | 
            +
             | 
| 51 | 
            +
                validation do
         | 
| 52 | 
            +
                  required(:title).filled
         | 
| 53 | 
            +
                end
         | 
| 54 | 
            +
              end
         | 
| 55 | 
            +
             | 
| 56 | 
            +
              let (:album) do
         | 
| 57 | 
            +
                OpenStruct.new(
         | 
| 58 | 
            +
                  :title  => "Blackhawks Over Los Angeles",
         | 
| 59 | 
            +
                  :hit    => song,
         | 
| 60 | 
            +
                  :songs  => songs, # TODO: document this requirement,
         | 
| 61 | 
            +
             | 
| 62 | 
            +
                  :band => Struct.new(:name, :label).new("Epitaph", OpenStruct.new),
         | 
| 63 | 
            +
                )
         | 
| 64 | 
            +
              end
         | 
| 65 | 
            +
              let (:song)  { OpenStruct.new(:title => "Downtown") }
         | 
| 66 | 
            +
              let (:songs) { [song=OpenStruct.new(:title => "Calling"), song] }
         | 
| 67 | 
            +
              let (:form)  { AlbumForm.new(album) }
         | 
| 68 | 
            +
             | 
| 69 | 
            +
             | 
| 70 | 
            +
              describe "incorrect #validate" do
         | 
| 71 | 
            +
                before { form.validate(
         | 
| 72 | 
            +
                  "hit"   =>{"title" => ""},
         | 
| 73 | 
            +
                  "title" => "",
         | 
| 74 | 
            +
                  "songs" => [{"title" => ""}, {"title" => ""}]) } # FIXME: what happens if item is missing?
         | 
| 75 | 
            +
             | 
| 76 | 
            +
                it do
         | 
| 77 | 
            +
                  form.errors.messages.must_equal({
         | 
| 78 | 
            +
                    :title  => ["must be filled"],
         | 
| 79 | 
            +
                    :"hit.title"=>["must be filled"],
         | 
| 80 | 
            +
                    :"songs.title"=>["must be filled"],
         | 
| 81 | 
            +
                    :"band.label.name"=>["is missing"]
         | 
| 82 | 
            +
                  })
         | 
| 83 | 
            +
                end
         | 
| 84 | 
            +
             | 
| 85 | 
            +
                it do
         | 
| 86 | 
            +
                  #form.errors.must_equal({:title  => ["must be filled"]})
         | 
| 87 | 
            +
                  # TODO: this should only contain local errors?
         | 
| 88 | 
            +
                end
         | 
| 89 | 
            +
             | 
| 90 | 
            +
                # nested forms keep their own Errors:
         | 
| 91 | 
            +
                it { form.hit.errors.messages.must_equal({:title=>["must be filled"]}) }
         | 
| 92 | 
            +
                it { form.songs[0].errors.messages.must_equal({:title=>["must be filled"]}) }
         | 
| 93 | 
            +
             | 
| 94 | 
            +
                it do
         | 
| 95 | 
            +
                  form.errors.messages.must_equal({
         | 
| 96 | 
            +
                    :title        => ["must be filled"],
         | 
| 97 | 
            +
                    :"hit.title"  => ["must be filled"],
         | 
| 98 | 
            +
                    :"songs.title"=> ["must be filled"],
         | 
| 99 | 
            +
                    :"band.label.name"=>["is missing"]
         | 
| 100 | 
            +
                  })
         | 
| 101 | 
            +
                end
         | 
| 102 | 
            +
              end
         | 
| 103 | 
            +
             | 
| 104 | 
            +
             | 
| 105 | 
            +
              describe "#validate with main form invalid" do
         | 
| 106 | 
            +
                it do
         | 
| 107 | 
            +
                  form.validate("title"=>"", "band"=>{"label"=>{:name => "Fat Wreck"}}).must_equal false
         | 
| 108 | 
            +
                  form.errors.messages.must_equal({:title=>["must be filled"]})
         | 
| 109 | 
            +
                end
         | 
| 110 | 
            +
              end
         | 
| 111 | 
            +
             | 
| 112 | 
            +
             | 
| 113 | 
            +
              describe "#validate with middle nested form invalid" do
         | 
| 114 | 
            +
                before { @result = form.validate("hit"=>{"title" => ""}, "band"=>{"label"=>{:name => "Fat Wreck"}}) }
         | 
| 115 | 
            +
             | 
| 116 | 
            +
                it { @result.must_equal false }
         | 
| 117 | 
            +
                it { form.errors.messages.must_equal({:"hit.title"=>["must be filled"]}) }
         | 
| 118 | 
            +
              end
         | 
| 119 | 
            +
             | 
| 120 | 
            +
             | 
| 121 | 
            +
              describe "#validate with collection form invalid" do
         | 
| 122 | 
            +
                before { @result = form.validate("songs"=>[{"title" => ""}], "band"=>{"label"=>{:name => "Fat Wreck"}}) }
         | 
| 123 | 
            +
             | 
| 124 | 
            +
                it { @result.must_equal false }
         | 
| 125 | 
            +
                it { form.errors.messages.must_equal({:"songs.title"=>["must be filled"]}) }
         | 
| 126 | 
            +
              end
         | 
| 127 | 
            +
             | 
| 128 | 
            +
             | 
| 129 | 
            +
              describe "#validate with collection and 2-level-nested invalid" do
         | 
| 130 | 
            +
                before { @result = form.validate("songs"=>[{"title" => ""}], "band" => {"label" => {}}) }
         | 
| 131 | 
            +
             | 
| 132 | 
            +
                it { @result.must_equal false }
         | 
| 133 | 
            +
                it { form.errors.messages.must_equal({:"songs.title"=>["must be filled"], :"band.label.name"=>["is missing"]}) }
         | 
| 134 | 
            +
              end
         | 
| 135 | 
            +
             | 
| 136 | 
            +
              describe "#validate with nested form using :base invalid" do
         | 
| 137 | 
            +
                it do
         | 
| 138 | 
            +
                  result = form.validate("songs"=>[{"title" => "Someday"}], "band" => {"name" => "Nickelback", "label" => {"name" => "Roadrunner Records"}})
         | 
| 139 | 
            +
                  result.must_equal false
         | 
| 140 | 
            +
                  form.errors.messages.must_equal({:"band.name"=>["You are a bad person"]})
         | 
| 141 | 
            +
                end
         | 
| 142 | 
            +
              end
         | 
| 143 | 
            +
             | 
| 144 | 
            +
              describe "correct #validate" do
         | 
| 145 | 
            +
                before { @result = form.validate(
         | 
| 146 | 
            +
                  "hit"   => {"title" => "Sacrifice"},
         | 
| 147 | 
            +
                  "title" => "Second Heat",
         | 
| 148 | 
            +
                  "songs" => [{"title"=>"Heart Of A Lion"}],
         | 
| 149 | 
            +
                  "band"  => {"label"=>{:name => "Fat Wreck"}}
         | 
| 150 | 
            +
                  ) }
         | 
| 151 | 
            +
             | 
| 152 | 
            +
                it { @result.must_equal true }
         | 
| 153 | 
            +
                it { form.hit.title.must_equal "Sacrifice" }
         | 
| 154 | 
            +
                it { form.title.must_equal "Second Heat" }
         | 
| 155 | 
            +
                it { form.songs.first.title.must_equal "Heart Of A Lion" }
         | 
| 156 | 
            +
              end
         | 
| 157 | 
            +
             | 
| 158 | 
            +
             | 
| 159 | 
            +
              describe "Errors#to_s" do
         | 
| 160 | 
            +
                before { form.validate("songs"=>[{"title" => ""}], "band" => {"label" => {}}) }
         | 
| 161 | 
            +
             | 
| 162 | 
            +
                # to_s is aliased to messages
         | 
| 163 | 
            +
                it { form.errors.to_s.must_equal "{:\"songs.title\"=>[\"must be filled\"], :\"band.label.name\"=>[\"is missing\"]}" }
         | 
| 164 | 
            +
              end
         | 
| 165 | 
            +
            end
         | 
| @@ -0,0 +1,65 @@ | |
| 1 | 
            +
            require 'test_helper'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            class FeatureInheritanceTest < BaseTest
         | 
| 4 | 
            +
              Song  = Struct.new(:title, :album, :composer)
         | 
| 5 | 
            +
              Album = Struct.new(:name, :songs, :artist)
         | 
| 6 | 
            +
              Artist = Struct.new(:name)
         | 
| 7 | 
            +
             | 
| 8 | 
            +
              module Date
         | 
| 9 | 
            +
                def date
         | 
| 10 | 
            +
                  "May 16"
         | 
| 11 | 
            +
                end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                def self.included(includer)
         | 
| 14 | 
            +
                  includer.send :register_feature, self
         | 
| 15 | 
            +
                end
         | 
| 16 | 
            +
              end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
              # module Name
         | 
| 19 | 
            +
              #   def name
         | 
| 20 | 
            +
              #     "Violins"
         | 
| 21 | 
            +
              #   end
         | 
| 22 | 
            +
              # end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
              class AlbumForm < Reform::Form
         | 
| 25 | 
            +
                feature Date # feature.
         | 
| 26 | 
            +
                property :name
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                collection :songs do
         | 
| 29 | 
            +
                  property :title
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                  property :composer do
         | 
| 32 | 
            +
                    property :name
         | 
| 33 | 
            +
                  end
         | 
| 34 | 
            +
                end
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                property :artist do
         | 
| 37 | 
            +
                  property :name
         | 
| 38 | 
            +
                end
         | 
| 39 | 
            +
              end
         | 
| 40 | 
            +
             | 
| 41 | 
            +
              let (:song)               { Song.new("Broken") }
         | 
| 42 | 
            +
              let (:song_with_composer) { Song.new("Resist Stance", nil, composer) }
         | 
| 43 | 
            +
              let (:composer)           { Artist.new("Greg Graffin") }
         | 
| 44 | 
            +
              let (:artist)             { Artist.new("Bad Religion") }
         | 
| 45 | 
            +
              let (:album)              { Album.new("The Dissent Of Man", [song, song_with_composer], artist) }
         | 
| 46 | 
            +
             | 
| 47 | 
            +
              let (:form) { AlbumForm.new(album) }
         | 
| 48 | 
            +
             | 
| 49 | 
            +
              it do
         | 
| 50 | 
            +
                form.date.must_equal "May 16"
         | 
| 51 | 
            +
                form.songs[0].date.must_equal "May 16"
         | 
| 52 | 
            +
              end
         | 
| 53 | 
            +
             | 
| 54 | 
            +
              # it { subject.class.include?(Reform::Form::ActiveModel) }
         | 
| 55 | 
            +
              # it { subject.class.include?(Reform::Form::Coercion) }
         | 
| 56 | 
            +
              # it { subject.is_a?(Reform::Form::MultiParameterAttributes) }
         | 
| 57 | 
            +
             | 
| 58 | 
            +
              # it { subject.band.class.include?(Reform::Form::ActiveModel) }
         | 
| 59 | 
            +
              # it { subject.band.is_a?(Reform::Form::Coercion) }
         | 
| 60 | 
            +
              # it { subject.band.is_a?(Reform::Form::MultiParameterAttributes) }
         | 
| 61 | 
            +
             | 
| 62 | 
            +
              # it { subject.band.label.is_a?(Reform::Form::ActiveModel) }
         | 
| 63 | 
            +
              # it { subject.band.label.is_a?(Reform::Form::Coercion) }
         | 
| 64 | 
            +
              # it { subject.band.label.is_a?(Reform::Form::MultiParameterAttributes) }
         | 
| 65 | 
            +
            end
         | 
| @@ -0,0 +1,44 @@ | |
| 1 | 
            +
            array?: "%{name} must be an array"
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            empty?: "%{name} cannot be empty"
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            exclusion?: "%{name} must not be one of: %{list}"
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            eql?: "%{name} must be equal to %{eql_value}"
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            filled?: "%{name} must be filled"
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            format?: "%{name} is in invalid format"
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            gt?: "%{name} must be greater than %{num} (%{value} was given)"
         | 
| 14 | 
            +
             | 
| 15 | 
            +
            gteq?: "%{name} must be greater than or equal to %{num}"
         | 
| 16 | 
            +
             | 
| 17 | 
            +
            hash?: "%{name} must be a hash"
         | 
| 18 | 
            +
             | 
| 19 | 
            +
            inclusion?: "%{name} must be one of: %{list}"
         | 
| 20 | 
            +
             | 
| 21 | 
            +
            int?: "%{name} must be an integer"
         | 
| 22 | 
            +
             | 
| 23 | 
            +
            key?: "%{name} is missing"
         | 
| 24 | 
            +
             | 
| 25 | 
            +
            lt?: "%{name} must be less than %{num} (%{value} was given)"
         | 
| 26 | 
            +
             | 
| 27 | 
            +
            lteq?: "%{name} must be less than or equal to %{num}"
         | 
| 28 | 
            +
             | 
| 29 | 
            +
            max_size?: "%{name} size cannot be greater than %{num}"
         | 
| 30 | 
            +
             | 
| 31 | 
            +
            min_size?: "%{name} size cannot be less than %{num}"
         | 
| 32 | 
            +
             | 
| 33 | 
            +
            nil?: "%{name} cannot be nil"
         | 
| 34 | 
            +
             | 
| 35 | 
            +
            size?:
         | 
| 36 | 
            +
              range: "%{name} size must be within %{left} - %{right}"
         | 
| 37 | 
            +
              default: "%{name} size must be %{num}"
         | 
| 38 | 
            +
             | 
| 39 | 
            +
            str?: "%{name} must be a string"
         | 
| 40 | 
            +
             | 
| 41 | 
            +
            good_musical_taste?: "you're a bad person"
         | 
| 42 | 
            +
             | 
| 43 | 
            +
            form_access_validation?: "this doesn't look like a Reform form dude!!"
         | 
| 44 | 
            +
             | 
| @@ -0,0 +1,24 @@ | |
| 1 | 
            +
            require 'test_helper'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            class FormOptionTest < MiniTest::Spec
         | 
| 4 | 
            +
              Song  = Struct.new(:title)
         | 
| 5 | 
            +
              Album = Struct.new(:song)
         | 
| 6 | 
            +
             | 
| 7 | 
            +
              class SongForm < Reform::Form
         | 
| 8 | 
            +
                property :title
         | 
| 9 | 
            +
                validation do
         | 
| 10 | 
            +
                  key(:title).required
         | 
| 11 | 
            +
                end
         | 
| 12 | 
            +
              end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
              class AlbumForm < Reform::Form
         | 
| 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
         | 
    
        data/test/form_test.rb
    ADDED
    
    | @@ -0,0 +1,57 @@ | |
| 1 | 
            +
            require 'test_helper'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            class FormTest < MiniTest::Spec
         | 
| 4 | 
            +
              Artist = Struct.new(:name)
         | 
| 5 | 
            +
             | 
| 6 | 
            +
              class AlbumForm < Reform::Form
         | 
| 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 | 
            +
                    key(:title).required
         | 
| 41 | 
            +
                  end
         | 
| 42 | 
            +
             | 
| 43 | 
            +
                  cloned.new(OpenStruct.new).validate({})
         | 
| 44 | 
            +
                end
         | 
| 45 | 
            +
              end
         | 
| 46 | 
            +
             | 
| 47 | 
            +
              describe "#initialize" do
         | 
| 48 | 
            +
                class ArtistForm < Reform::Form
         | 
| 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
         | 
    
        data/test/from_test.rb
    ADDED
    
    | @@ -0,0 +1,75 @@ | |
| 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
         | 
| @@ -0,0 +1,119 @@ | |
| 1 | 
            +
            require 'test_helper'
         | 
| 2 | 
            +
            require 'representable/json'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            class InheritTest < BaseTest
         | 
| 5 | 
            +
              Populator = Reform::Form::Populator
         | 
| 6 | 
            +
             | 
| 7 | 
            +
              class AlbumForm < Reform::Form
         | 
| 8 | 
            +
                property :title, deserializer: {instance: "Instance"}, skip_if: "skip_if in AlbumForm" # allow direct configuration of :deserializer.
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                property :hit, populator: "Populator" do
         | 
| 11 | 
            +
                  property :title
         | 
| 12 | 
            +
                end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                collection :songs, populate_if_empty: lambda {}, skip_if: :all_blank do
         | 
| 15 | 
            +
                  property :title
         | 
| 16 | 
            +
                end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                property :artist, populate_if_empty: lambda {} do
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                  def artist_id
         | 
| 21 | 
            +
                    1
         | 
| 22 | 
            +
                  end
         | 
| 23 | 
            +
                end
         | 
| 24 | 
            +
              end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
              puts
         | 
| 27 | 
            +
              puts "inherit"
         | 
| 28 | 
            +
             | 
| 29 | 
            +
              class CompilationForm < AlbumForm
         | 
| 30 | 
            +
                property :title, inherit: true, skip_if: "skip_if from CompilationForm"
         | 
| 31 | 
            +
                puts "[#{options_for(:title)[:deserializer].object_id}] COM@@@@@ #{options_for(:title)[:deserializer].inspect}"
         | 
| 32 | 
            +
                # property :hit, :inherit => true do
         | 
| 33 | 
            +
                #   property :rating
         | 
| 34 | 
            +
                #   validates :title, :rating, :presence => true
         | 
| 35 | 
            +
                # end
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                # puts representer_class.representable_attrs.
         | 
| 38 | 
            +
                #   get(:hit)[:extend].evaluate(nil).new(OpenStruct.new).rating
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                # NO collection here, this is entirely inherited.
         | 
| 41 | 
            +
                # collection :songs, ..
         | 
| 42 | 
            +
             | 
| 43 | 
            +
                property :artist, inherit: true do # inherit everything, but explicitely.
         | 
| 44 | 
            +
                end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                # completely override.
         | 
| 47 | 
            +
                property :hit, skip_if: "SkipParse" do
         | 
| 48 | 
            +
                end
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                # override partly.
         | 
| 51 | 
            +
              end
         | 
| 52 | 
            +
             | 
| 53 | 
            +
              let (:album) { Album.new(nil, OpenStruct.new(:hit => OpenStruct.new()) ) }
         | 
| 54 | 
            +
              subject { CompilationForm.new(album) }
         | 
| 55 | 
            +
             | 
| 56 | 
            +
             | 
| 57 | 
            +
              # valid.
         | 
| 58 | 
            +
              # it {
         | 
| 59 | 
            +
              #   subject.validate("hit" => {"title" => "LA Drone", "rating" => 10})
         | 
| 60 | 
            +
              #   subject.hit.title.must_equal "LA Drone"
         | 
| 61 | 
            +
              #   subject.hit.rating.must_equal 10
         | 
| 62 | 
            +
              #   subject.errors.messages.must_equal({})
         | 
| 63 | 
            +
              # }
         | 
| 64 | 
            +
             | 
| 65 | 
            +
              # it do
         | 
| 66 | 
            +
              #   subject.validate({})
         | 
| 67 | 
            +
              #   subject.hit.title.must_equal nil
         | 
| 68 | 
            +
              #   subject.hit.rating.must_equal nil
         | 
| 69 | 
            +
              #   subject.errors.messages.must_equal({:"hit.title"=>["can't be blank"], :"hit.rating"=>["can't be blank"]})
         | 
| 70 | 
            +
              # end
         | 
| 71 | 
            +
             | 
| 72 | 
            +
            require "pp"
         | 
| 73 | 
            +
             | 
| 74 | 
            +
              it "xxx" do
         | 
| 75 | 
            +
                # sub hashes like :deserializer must be properly cloned when inheriting.
         | 
| 76 | 
            +
                AlbumForm.options_for(:title)[:deserializer].object_id.wont_equal CompilationForm.options_for(:title)[:deserializer].object_id
         | 
| 77 | 
            +
             | 
| 78 | 
            +
                # don't overwrite direct deserializer: {} configuration.
         | 
| 79 | 
            +
                AlbumForm.options_for(:title)[:internal_populator].must_be_instance_of Reform::Form::Populator::Sync
         | 
| 80 | 
            +
                AlbumForm.options_for(:title)[:deserializer][:skip_parse].must_equal "skip_if in AlbumForm"
         | 
| 81 | 
            +
             | 
| 82 | 
            +
                AlbumForm.options_for(:hit)[:internal_populator].inspect.must_match /Reform::Form::Populator:.+ @user_proc="Populator"/
         | 
| 83 | 
            +
                # AlbumForm.options_for(:hit)[:deserializer][:instance].inspect.must_be_instance_with Reform::Form::Populator, user_proc: "Populator"
         | 
| 84 | 
            +
             | 
| 85 | 
            +
             | 
| 86 | 
            +
                AlbumForm.options_for(:songs)[:internal_populator].must_be_instance_of Reform::Form::Populator::IfEmpty
         | 
| 87 | 
            +
                AlbumForm.options_for(:songs)[:deserializer][:skip_parse].must_be_instance_of Reform::Form::Validate::Skip::AllBlank
         | 
| 88 | 
            +
             | 
| 89 | 
            +
                AlbumForm.options_for(:artist)[:internal_populator].must_be_instance_of Reform::Form::Populator::IfEmpty
         | 
| 90 | 
            +
             | 
| 91 | 
            +
             | 
| 92 | 
            +
             | 
| 93 | 
            +
                CompilationForm.options_for(:title)[:deserializer][:skip_parse].must_equal "skip_if from CompilationForm"
         | 
| 94 | 
            +
                # pp CompilationForm.options_for(:songs)
         | 
| 95 | 
            +
                CompilationForm.options_for(:songs)[:internal_populator].must_be_instance_of Reform::Form::Populator::IfEmpty
         | 
| 96 | 
            +
             | 
| 97 | 
            +
             | 
| 98 | 
            +
                CompilationForm.options_for(:artist)[:internal_populator].must_be_instance_of Reform::Form::Populator::IfEmpty
         | 
| 99 | 
            +
             | 
| 100 | 
            +
                # completely overwrite inherited.
         | 
| 101 | 
            +
                CompilationForm.options_for(:hit)[:internal_populator].must_be_instance_of Reform::Form::Populator::Sync # reset to default.
         | 
| 102 | 
            +
                CompilationForm.options_for(:hit)[:deserializer][:skip_parse].must_equal "SkipParse"
         | 
| 103 | 
            +
             | 
| 104 | 
            +
             | 
| 105 | 
            +
                # inherit: true with block will still inherit the original class.
         | 
| 106 | 
            +
                AlbumForm.new(OpenStruct.new(artist: OpenStruct.new)).artist.artist_id.must_equal 1
         | 
| 107 | 
            +
                CompilationForm.new(OpenStruct.new(artist: OpenStruct.new)).artist.artist_id.must_equal 1
         | 
| 108 | 
            +
              end
         | 
| 109 | 
            +
             | 
| 110 | 
            +
             | 
| 111 | 
            +
              class CDForm < AlbumForm
         | 
| 112 | 
            +
                # override :artist's original populate_if_empty but with :inherit.
         | 
| 113 | 
            +
                property :artist, inherit: true, populator: "CD Populator" do
         | 
| 114 | 
            +
             | 
| 115 | 
            +
                end
         | 
| 116 | 
            +
              end
         | 
| 117 | 
            +
             | 
| 118 | 
            +
              it { CDForm.options_for(:artist)[:internal_populator].instance_variable_get(:@user_proc).must_equal "CD Populator" }
         | 
| 119 | 
            +
            end
         |