representable 3.0.0 → 3.1.0
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 +5 -5
- data/.github/workflows/ci.yml +17 -0
- data/CHANGES.md +25 -0
- data/Gemfile +4 -12
- data/LICENSE +1 -1
- data/README.md +6 -6
- data/Rakefile +1 -6
- data/TODO +1 -3
- data/TODO-4.0.md +72 -0
- data/lib/representable.rb +19 -25
- data/lib/representable/binding.rb +32 -12
- data/lib/representable/cached.rb +1 -1
- data/lib/representable/coercion.rb +8 -6
- data/lib/representable/config.rb +13 -3
- data/lib/representable/debug.rb +23 -15
- data/lib/representable/declarative.rb +12 -7
- data/lib/representable/decorator.rb +1 -1
- data/lib/representable/definition.rb +7 -3
- data/lib/representable/deserializer.rb +5 -4
- data/lib/representable/for_collection.rb +1 -1
- data/lib/representable/hash.rb +9 -2
- data/lib/representable/hash/allow_symbols.rb +9 -11
- data/lib/representable/hash/binding.rb +1 -0
- data/lib/representable/hash/collection.rb +4 -2
- data/lib/representable/hash_methods.rb +3 -2
- data/lib/representable/insert.rb +1 -1
- data/lib/representable/json.rb +8 -7
- data/lib/representable/json/collection.rb +3 -0
- data/lib/representable/object.rb +1 -1
- data/lib/representable/object/binding.rb +5 -1
- data/lib/representable/option.rb +19 -0
- data/lib/representable/pipeline.rb +3 -2
- data/lib/representable/pipeline_factories.rb +4 -2
- data/lib/representable/populator.rb +1 -1
- data/lib/representable/represent.rb +1 -0
- data/lib/representable/serializer.rb +3 -2
- data/lib/representable/version.rb +1 -1
- data/lib/representable/virtus_coercion.rb +38 -0
- data/lib/representable/xml.rb +12 -10
- data/lib/representable/xml/binding.rb +19 -13
- data/lib/representable/xml/namespace.rb +122 -0
- data/lib/representable/yaml.rb +6 -2
- data/lib/representable/yaml/binding.rb +1 -0
- data/representable.gemspec +8 -9
- data/test/as_test.rb +7 -7
- data/test/binding_test.rb +14 -14
- data/test/cached_test.rb +59 -49
- data/test/class_test.rb +9 -9
- data/test/coercion_test.rb +33 -22
- data/test/config/inherit_test.rb +14 -14
- data/test/config_test.rb +20 -20
- data/test/decorator_scope_test.rb +4 -4
- data/test/decorator_test.rb +33 -20
- data/test/default_test.rb +8 -8
- data/test/defaults_options_test.rb +3 -3
- data/test/definition_test.rb +38 -40
- data/test/{example.rb → examples/example.rb} +0 -1
- data/test/examples/object.rb +1 -5
- data/test/exec_context_test.rb +8 -8
- data/test/features_test.rb +6 -6
- data/test/filter_test.rb +8 -8
- data/test/for_collection_test.rb +10 -10
- data/test/generic_test.rb +13 -13
- data/test/getter_setter_test.rb +5 -5
- data/test/hash_bindings_test.rb +1 -1
- data/test/hash_test.rb +45 -23
- data/test/heritage_test.rb +16 -13
- data/test/if_test.rb +9 -9
- data/test/include_exclude_test.rb +14 -14
- data/test/inherit_test.rb +18 -18
- data/test/inline_test.rb +24 -24
- data/test/instance_test.rb +31 -31
- data/test/is_representable_test.rb +10 -10
- data/test/json_test.rb +29 -7
- data/test/lonely_test.rb +31 -31
- data/test/nested_test.rb +13 -13
- data/test/object_test.rb +9 -9
- data/test/option_test.rb +36 -0
- data/test/parse_pipeline_test.rb +3 -5
- data/test/pipeline_test.rb +50 -50
- data/test/populator_test.rb +18 -18
- data/test/prepare_test.rb +4 -4
- data/test/private_options_test.rb +2 -2
- data/test/reader_writer_test.rb +2 -2
- data/test/render_nil_test.rb +2 -2
- data/test/represent_test.rb +14 -14
- data/test/representable_test.rb +34 -36
- data/test/schema_test.rb +8 -11
- data/test/serialize_deserialize_test.rb +2 -2
- data/test/skip_test.rb +14 -14
- data/test/stringify_hash_test.rb +3 -3
- data/test/test_helper.rb +26 -14
- data/test/uncategorized_test.rb +10 -10
- data/test/user_options_test.rb +4 -4
- data/test/virtus_coercion_test.rb +52 -0
- data/test/wrap_test.rb +19 -19
- data/test/xml_bindings_test.rb +0 -4
- data/test/xml_namespace_test.rb +186 -0
- data/test/xml_test.rb +103 -43
- data/test/yaml_test.rb +51 -26
- metadata +101 -39
- data/.travis.yml +0 -7
- data/lib/representable/TODO.getting_serious +0 -11
- data/lib/representable/autoload.rb +0 -10
- data/test/mongoid_test.rb +0 -31
    
        data/test/stringify_hash_test.rb
    CHANGED
    
    | @@ -17,11 +17,11 @@ describe "#from_hash" do | |
| 17 17 | 
             
               end
         | 
| 18 18 |  | 
| 19 19 | 
             
               it "parses symbols, too" do
         | 
| 20 | 
            -
                 OpenStruct.new.extend(representer).from_hash({:song => {:title => "Der Optimist"}}).song.title.must_equal "Der Optimist"
         | 
| 20 | 
            +
                 _(OpenStruct.new.extend(representer).from_hash({:song => {:title => "Der Optimist"}}).song.title).must_equal "Der Optimist"
         | 
| 21 21 | 
             
               end
         | 
| 22 22 |  | 
| 23 23 | 
             
               it "still parses strings" do
         | 
| 24 | 
            -
                 OpenStruct.new.extend(representer).from_hash({"song" => {"title" => "Der Optimist"}}).song.title.must_equal "Der Optimist"
         | 
| 24 | 
            +
                 _(OpenStruct.new.extend(representer).from_hash({"song" => {"title" => "Der Optimist"}}).song.title).must_equal "Der Optimist"
         | 
| 25 25 | 
             
               end
         | 
| 26 26 |  | 
| 27 27 | 
             
               describe "with :wrap" do
         | 
| @@ -33,7 +33,7 @@ describe "#from_hash" do | |
| 33 33 | 
             
                end
         | 
| 34 34 |  | 
| 35 35 | 
             
                 it "parses symbols, too" do
         | 
| 36 | 
            -
                   OpenStruct.new.extend(representer).from_hash({:album => {:song => {:title => "Der Optimist"}}}).song.title.must_equal "Der Optimist"
         | 
| 36 | 
            +
                   _(OpenStruct.new.extend(representer).from_hash({:album => {:song => {:title => "Der Optimist"}}}).song.title).must_equal "Der Optimist"
         | 
| 37 37 | 
             
                 end
         | 
| 38 38 | 
             
               end
         | 
| 39 39 | 
             
             end
         | 
    
        data/test/test_helper.rb
    CHANGED
    
    | @@ -1,16 +1,20 @@ | |
| 1 | 
            +
            require 'pry-byebug'
         | 
| 1 2 | 
             
            require 'representable'
         | 
| 2 3 |  | 
| 3 | 
            -
            require "json"
         | 
| 4 | 
            -
            require "psych"
         | 
| 5 | 
            -
             | 
| 6 | 
            -
            require 'representable/json'
         | 
| 7 | 
            -
            require 'representable/xml'
         | 
| 8 | 
            -
            require 'representable/yaml'
         | 
| 9 4 | 
             
            require 'minitest/autorun'
         | 
| 10 5 | 
             
            require 'test_xml/mini_test'
         | 
| 11 6 |  | 
| 12 7 | 
             
            require "representable/debug"
         | 
| 8 | 
            +
            require 'minitest/assertions'
         | 
| 13 9 |  | 
| 10 | 
            +
            module MiniTest::Assertions
         | 
| 11 | 
            +
              def assert_equal_xml(text, subject)
         | 
| 12 | 
            +
                assert_equal (text.gsub("\n", "").gsub(/(\s\s+)/, "")), subject.gsub("\n", "").gsub(/(\s\s+)/, "")
         | 
| 13 | 
            +
              end
         | 
| 14 | 
            +
            end
         | 
| 15 | 
            +
            String.infect_an_assertion :assert_equal_xml, :must_xml
         | 
| 16 | 
            +
             | 
| 17 | 
            +
            # TODO: delete all that in 4.0:
         | 
| 14 18 | 
             
            class Album
         | 
| 15 19 | 
             
              attr_accessor :songs, :best_song
         | 
| 16 20 | 
             
              def initialize(songs=nil, best_song=nil)
         | 
| @@ -45,7 +49,7 @@ module AssertJson | |
| 45 49 | 
             
              module Assertions
         | 
| 46 50 | 
             
                def assert_json(expected, actual, msg=nil)
         | 
| 47 51 | 
             
                  msg = message(msg, "") { diff expected, actual }
         | 
| 48 | 
            -
                   | 
| 52 | 
            +
                  assert_equal(expected.split("").sort, actual.split("").sort, msg)
         | 
| 49 53 | 
             
                end
         | 
| 50 54 | 
             
              end
         | 
| 51 55 | 
             
            end
         | 
| @@ -83,7 +87,7 @@ MiniTest::Spec.class_eval do | |
| 83 87 | 
             
              end
         | 
| 84 88 |  | 
| 85 89 | 
             
              def self.representer!(options={}, &block)
         | 
| 86 | 
            -
                fmt = options # we need that so the 2nd call to ::let | 
| 90 | 
            +
                fmt = options # we need that so the 2nd call to ::let(within a ::describe) remembers the right format.
         | 
| 87 91 |  | 
| 88 92 | 
             
                name   = options[:name]   || :representer
         | 
| 89 93 | 
             
                format = options[:module] || Representable::Hash
         | 
| @@ -101,6 +105,8 @@ MiniTest::Spec.class_eval do | |
| 101 105 | 
             
                  mod
         | 
| 102 106 | 
             
                end
         | 
| 103 107 |  | 
| 108 | 
            +
                undef :inject_representer if method_defined? :inject_representer
         | 
| 109 | 
            +
             | 
| 104 110 | 
             
                def inject_representer(mod, options)
         | 
| 105 111 | 
             
                  return unless options[:inject]
         | 
| 106 112 |  | 
| @@ -116,7 +122,7 @@ MiniTest::Spec.class_eval do | |
| 116 122 | 
             
                def representer_for(modules=[Representable::Hash], &block)
         | 
| 117 123 | 
             
                  Module.new do
         | 
| 118 124 | 
             
                    extend TestMethods
         | 
| 119 | 
            -
                    include | 
| 125 | 
            +
                    include(*modules)
         | 
| 120 126 | 
             
                    module_exec(&block)
         | 
| 121 127 | 
             
                  end
         | 
| 122 128 | 
             
                end
         | 
| @@ -127,9 +133,15 @@ MiniTest::Spec.class_eval do | |
| 127 133 | 
             
            end
         | 
| 128 134 |  | 
| 129 135 | 
             
            class BaseTest < MiniTest::Spec
         | 
| 130 | 
            -
              let | 
| 131 | 
            -
              let | 
| 132 | 
            -
              let | 
| 133 | 
            -
              let | 
| 136 | 
            +
              let(:new_album)  { OpenStruct.new.extend(representer) }
         | 
| 137 | 
            +
              let(:album)      { OpenStruct.new(:songs => ["Fuck Armageddon"]).extend(representer) }
         | 
| 138 | 
            +
              let(:song) { OpenStruct.new(:title => "Resist Stance") }
         | 
| 139 | 
            +
              let(:song_representer) { Module.new do include Representable::Hash; property :title end  }
         | 
| 134 140 |  | 
| 135 | 
            -
            end
         | 
| 141 | 
            +
            end
         | 
| 142 | 
            +
             | 
| 143 | 
            +
            Band = Struct.new(:id, :name) do
         | 
| 144 | 
            +
              def [](*attrs)
         | 
| 145 | 
            +
                attrs.collect { |attr| send(attr) }
         | 
| 146 | 
            +
              end
         | 
| 147 | 
            +
            end
         | 
    
        data/test/uncategorized_test.rb
    CHANGED
    
    | @@ -15,12 +15,12 @@ class StopWhenIncomingObjectFragmentIsNilTest < MiniTest::Spec | |
| 15 15 |  | 
| 16 16 | 
             
              it do
         | 
| 17 17 | 
             
                album = Album.new
         | 
| 18 | 
            -
                representer.new(album).from_hash({"id"=>1, "songs"=>[{"title"=>"Walkie Talkie"}]}).songs.must_equal [Song.new("Walkie Talkie")]
         | 
| 18 | 
            +
                _(representer.new(album).from_hash({"id"=>1, "songs"=>[{"title"=>"Walkie Talkie"}]}).songs).must_equal [Song.new("Walkie Talkie")]
         | 
| 19 19 | 
             
              end
         | 
| 20 20 |  | 
| 21 21 | 
             
              it do
         | 
| 22 22 | 
             
                album = Album.new(2, ["original"])
         | 
| 23 | 
            -
                representer.new(album).from_hash({"id"=>1, "songs"=>nil}).songs.must_equal ["original"]
         | 
| 23 | 
            +
                _(representer.new(album).from_hash({"id"=>1, "songs"=>nil}).songs).must_equal ["original"]
         | 
| 24 24 | 
             
              end
         | 
| 25 25 |  | 
| 26 26 | 
             
            end
         | 
| @@ -35,13 +35,13 @@ class RenderPipelineOptionTest < MiniTest::Spec | |
| 35 35 | 
             
                end
         | 
| 36 36 | 
             
              end
         | 
| 37 37 |  | 
| 38 | 
            -
              it { representer.new(Album.new).to_hash(user_options: {function: NilToNA}).must_equal({"id"=>"n/a"}) }
         | 
| 39 | 
            -
              it { representer.new(Album.new(1)).to_hash(user_options: {function: NilToNA}).must_equal({"id"=>1}) }
         | 
| 38 | 
            +
              it { _(representer.new(Album.new).to_hash(user_options: {function: NilToNA})).must_equal({"id"=>"n/a"}) }
         | 
| 39 | 
            +
              it { _(representer.new(Album.new(1)).to_hash(user_options: {function: NilToNA})).must_equal({"id"=>1}) }
         | 
| 40 40 |  | 
| 41 41 | 
             
              it "is cached" do
         | 
| 42 42 | 
             
                decorator = representer.new(Album.new)
         | 
| 43 | 
            -
                decorator.to_hash(user_options: {function: NilToNA}).must_equal({"id"=>"n/a"})
         | 
| 44 | 
            -
                decorator.to_hash(user_options: {function: nil}).must_equal({"id"=>"n/a"}) # non-sense function is not applied.
         | 
| 43 | 
            +
                _(decorator.to_hash(user_options: {function: NilToNA})).must_equal({"id"=>"n/a"})
         | 
| 44 | 
            +
                _(decorator.to_hash(user_options: {function: nil})).must_equal({"id"=>"n/a"}) # non-sense function is not applied.
         | 
| 45 45 | 
             
              end
         | 
| 46 46 |  | 
| 47 47 | 
             
            end
         | 
| @@ -56,12 +56,12 @@ class ParsePipelineOptionTest < MiniTest::Spec | |
| 56 56 | 
             
                end
         | 
| 57 57 | 
             
              end
         | 
| 58 58 |  | 
| 59 | 
            -
              it { representer.new(Album.new).from_hash({"id"=>nil}, user_options: {function: NilToNA}).id.must_equal "n/a" }
         | 
| 60 | 
            -
              it { representer.new(Album.new(1)).to_hash(user_options: {function: NilToNA}).must_equal({"id"=>1}) }
         | 
| 59 | 
            +
              it { _(representer.new(Album.new).from_hash({"id"=>nil}, user_options: {function: NilToNA}).id).must_equal "n/a" }
         | 
| 60 | 
            +
              it { _(representer.new(Album.new(1)).to_hash(user_options: {function: NilToNA})).must_equal({"id"=>1}) }
         | 
| 61 61 |  | 
| 62 62 | 
             
              it "is cached" do
         | 
| 63 63 | 
             
                decorator = representer.new(Album.new)
         | 
| 64 | 
            -
                decorator.from_hash({"id"=>nil}, user_options: {function: NilToNA}).id.must_equal "n/a"
         | 
| 65 | 
            -
                decorator.from_hash({"id"=>nil}, user_options: {function: "nonsense"}).id.must_equal "n/a" # non-sense function is not applied.
         | 
| 64 | 
            +
                _(decorator.from_hash({"id"=>nil}, user_options: {function: NilToNA}).id).must_equal "n/a"
         | 
| 65 | 
            +
                _(decorator.from_hash({"id"=>nil}, user_options: {function: "nonsense"}).id).must_equal "n/a" # non-sense function is not applied.
         | 
| 66 66 | 
             
              end
         | 
| 67 67 | 
             
            end
         | 
    
        data/test/user_options_test.rb
    CHANGED
    
    | @@ -7,9 +7,9 @@ class UserOptionsTest < Minitest::Spec | |
| 7 7 | 
             
                property :title, if: ->(options) { options[:user_options][:visible] }
         | 
| 8 8 | 
             
              end
         | 
| 9 9 |  | 
| 10 | 
            -
              it { Song.new("Run With It").extend(representer).to_hash.must_equal({}) }
         | 
| 11 | 
            -
              it { Song.new("Run With It").extend(representer).to_hash(user_options: {visible: true}).must_equal({"title"=>"Run With It"}) }
         | 
| 12 | 
            -
              it { Song.new("Run With It").extend(representer).from_hash("title"=>"Business Conduct").title.must_equal "Run With It" }
         | 
| 13 | 
            -
              it { Song.new("Run With It").extend(representer).from_hash({"title"=>"Business Conduct"}, user_options: {visible: true}).title.must_equal "Business Conduct" }
         | 
| 10 | 
            +
              it { _(Song.new("Run With It").extend(representer).to_hash).must_equal({}) }
         | 
| 11 | 
            +
              it { _(Song.new("Run With It").extend(representer).to_hash(user_options: {visible: true})).must_equal({"title"=>"Run With It"}) }
         | 
| 12 | 
            +
              it { _(Song.new("Run With It").extend(representer).from_hash("title"=>"Business Conduct").title).must_equal "Run With It" }
         | 
| 13 | 
            +
              it { _(Song.new("Run With It").extend(representer).from_hash({"title"=>"Business Conduct"}, user_options: {visible: true}).title).must_equal "Business Conduct" }
         | 
| 14 14 | 
             
            end
         | 
| 15 15 | 
             
            # Representable.deprecations=false
         | 
| @@ -0,0 +1,52 @@ | |
| 1 | 
            +
            require 'test_helper'
         | 
| 2 | 
            +
            require 'representable/virtus_coercion'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            class VirtusCoercionTest < MiniTest::Spec
         | 
| 5 | 
            +
              representer! do
         | 
| 6 | 
            +
                include Representable::VirtusCoercion
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                property :title # no coercion.
         | 
| 9 | 
            +
                property :length, :type => Float
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                property :band, :class => OpenStruct do
         | 
| 12 | 
            +
                  property :founded, :type => Integer
         | 
| 13 | 
            +
                end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                collection :songs, :class => OpenStruct do
         | 
| 16 | 
            +
                  property :ok, :type => Virtus::Attribute::Boolean
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
              end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
              let(:album) { OpenStruct.new(:title => "Dire Straits", :length => 41.34,
         | 
| 21 | 
            +
                :band  => OpenStruct.new(:founded => "1977"),
         | 
| 22 | 
            +
                :songs => [OpenStruct.new(:ok => 1), OpenStruct.new(:ok => 0)]) }
         | 
| 23 | 
            +
             | 
| 24 | 
            +
              it { _(album.extend(representer).to_hash).must_equal({"title"=>"Dire Straits", "length"=>41.34, "band"=>{"founded"=>1977}, "songs"=>[{"ok"=>true}, {"ok"=>false}]}) }
         | 
| 25 | 
            +
             | 
| 26 | 
            +
              it {
         | 
| 27 | 
            +
                album = OpenStruct.new
         | 
| 28 | 
            +
                album.extend(representer)
         | 
| 29 | 
            +
                album.from_hash({"title"=>"Dire Straits", "length"=>"41.34", "band"=>{"founded"=>"1977"}, "songs"=>[{"ok"=>1}, {"ok"=>0}]})
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                # it
         | 
| 32 | 
            +
                _(album.length).must_equal 41.34
         | 
| 33 | 
            +
                _(album.band.founded).must_equal 1977
         | 
| 34 | 
            +
                _(album.songs[0].ok).must_equal true
         | 
| 35 | 
            +
              }
         | 
| 36 | 
            +
             | 
| 37 | 
            +
             | 
| 38 | 
            +
              describe "with user :parse_filter and :render_filter" do
         | 
| 39 | 
            +
                representer! do
         | 
| 40 | 
            +
                  include Representable::VirtusCoercion
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                  property :length, :type => Float,
         | 
| 43 | 
            +
                  :parse_filter  => lambda { |input, options| "#{input}.1" }, # happens BEFORE coercer.
         | 
| 44 | 
            +
                  :render_filter => lambda { |fragment,*| "#{fragment}.1" }
         | 
| 45 | 
            +
                end
         | 
| 46 | 
            +
             | 
| 47 | 
            +
                # user's :parse_filter(s) are run before coercion.
         | 
| 48 | 
            +
                it { _(OpenStruct.new.extend(representer).from_hash("length"=>"1").length).must_equal 1.1 }
         | 
| 49 | 
            +
                # user's :render_filter(s) are run before coercion.
         | 
| 50 | 
            +
                it { _(OpenStruct.new(:length=>1).extend(representer).to_hash).must_equal({"length" => 1.1}) }
         | 
| 51 | 
            +
              end
         | 
| 52 | 
            +
            end
         | 
    
        data/test/wrap_test.rb
    CHANGED
    
    | @@ -8,10 +8,10 @@ class WrapTest < MiniTest::Spec | |
| 8 8 | 
             
              class SoftcoreBand < HardcoreBand
         | 
| 9 9 | 
             
              end
         | 
| 10 10 |  | 
| 11 | 
            -
              let | 
| 11 | 
            +
              let(:band) { HardcoreBand.new }
         | 
| 12 12 |  | 
| 13 13 | 
             
              it "returns false per default" do
         | 
| 14 | 
            -
                 | 
| 14 | 
            +
                assert_nil SoftcoreBand.new.send(:representation_wrap)
         | 
| 15 15 | 
             
              end
         | 
| 16 16 |  | 
| 17 17 | 
             
              it "infers a printable class name if set to true" do
         | 
| @@ -32,17 +32,17 @@ class WrapTest < MiniTest::Spec | |
| 32 32 | 
             
              ) do |format, mod, output, input|
         | 
| 33 33 |  | 
| 34 34 | 
             
                describe "[#{format}] dynamic wrap" do
         | 
| 35 | 
            -
                  let | 
| 36 | 
            -
                  let | 
| 35 | 
            +
                  let(:band) { representer.prepare(Struct.new(:name, :genre).new("Blink", "Pop")) }
         | 
| 36 | 
            +
                  let(:format) { format }
         | 
| 37 37 |  | 
| 38 38 | 
             
                  representer!(:module => mod) do
         | 
| 39 | 
            -
                    self.representation_wrap = lambda { | | 
| 39 | 
            +
                    self.representation_wrap = lambda { |number:, **| "#{name}#{number}" }
         | 
| 40 40 | 
             
                    property :genre
         | 
| 41 41 | 
             
                  end
         | 
| 42 42 |  | 
| 43 43 | 
             
                  it { render(band, {:number => 182}).must_equal_document(output) }
         | 
| 44 44 |  | 
| 45 | 
            -
                  it { parse(band, input, {:number => 182}).genre.must_equal "Poppunk" } # TODO: better test. also, xml parses _any_ wrap.
         | 
| 45 | 
            +
                  it { _(parse(band, input, {:number => 182}).genre).must_equal "Poppunk" } # TODO: better test. also, xml parses _any_ wrap.
         | 
| 46 46 | 
             
                end
         | 
| 47 47 | 
             
              end
         | 
| 48 48 | 
             
            end
         | 
| @@ -65,19 +65,19 @@ class HashDisableWrapTest < MiniTest::Spec | |
| 65 65 | 
             
                end
         | 
| 66 66 | 
             
              end
         | 
| 67 67 |  | 
| 68 | 
            -
              let | 
| 68 | 
            +
              let(:band) { BandDecorator.prepare(Band.new("Social Distortion")) }
         | 
| 69 69 |  | 
| 70 70 | 
             
              # direct, local api.
         | 
| 71 71 | 
             
              it do
         | 
| 72 | 
            -
                band.to_hash.must_equal({"bands" => {"name"=>"Social Distortion"}})
         | 
| 73 | 
            -
                band.to_hash(wrap: false).must_equal({"name"=>"Social Distortion"})
         | 
| 74 | 
            -
                band.to_hash(wrap: :band).must_equal(:band=>{"name"=>"Social Distortion"})
         | 
| 72 | 
            +
                _(band.to_hash).must_equal({"bands" => {"name"=>"Social Distortion"}})
         | 
| 73 | 
            +
                _(band.to_hash(wrap: false)).must_equal({"name"=>"Social Distortion"})
         | 
| 74 | 
            +
                _(band.to_hash(wrap: :band)).must_equal(:band=>{"name"=>"Social Distortion"})
         | 
| 75 75 | 
             
              end
         | 
| 76 76 |  | 
| 77 77 | 
             
              it do
         | 
| 78 | 
            -
                band.from_hash({"bands" => {"name"=>"Social Distortion"}}).name.must_equal "Social Distortion"
         | 
| 79 | 
            -
                band.from_hash({"name"=>"Social Distortion"}, wrap: false).name.must_equal "Social Distortion"
         | 
| 80 | 
            -
                band.from_hash({band: {"name"=>"Social Distortion"}}, wrap: :band).name.must_equal "Social Distortion"
         | 
| 78 | 
            +
                _(band.from_hash({"bands" => {"name"=>"Social Distortion"}}).name).must_equal "Social Distortion"
         | 
| 79 | 
            +
                _(band.from_hash({"name"=>"Social Distortion"}, wrap: false).name).must_equal "Social Distortion"
         | 
| 80 | 
            +
                _(band.from_hash({band: {"name"=>"Social Distortion"}}, wrap: :band).name).must_equal "Social Distortion"
         | 
| 81 81 | 
             
              end
         | 
| 82 82 |  | 
| 83 83 |  | 
| @@ -90,15 +90,15 @@ class HashDisableWrapTest < MiniTest::Spec | |
| 90 90 | 
             
              end
         | 
| 91 91 |  | 
| 92 92 |  | 
| 93 | 
            -
              let | 
| 93 | 
            +
              let(:album) { AlbumDecorator.prepare(Album.new(Band.new("Social Distortion", Label.new("Epitaph")))) }
         | 
| 94 94 |  | 
| 95 95 | 
             
              # band has wrap turned off per property definition, however, label still has wrap.
         | 
| 96 96 | 
             
              it "renders" do
         | 
| 97 | 
            -
                album.to_hash.must_equal({"albums" => {"band" => {"name"=>"Social Distortion", "label"=>{"important"=>{"name"=>"Epitaph"}}}}})
         | 
| 97 | 
            +
                _(album.to_hash).must_equal({"albums" => {"band" => {"name"=>"Social Distortion", "label"=>{"important"=>{"name"=>"Epitaph"}}}}})
         | 
| 98 98 | 
             
              end
         | 
| 99 99 |  | 
| 100 100 | 
             
              it "parses" do
         | 
| 101 | 
            -
                album.from_hash({"albums" => {"band" => {"name"=>"Rvivr"}}}).band.name.must_equal "Rvivr"
         | 
| 101 | 
            +
                _(album.from_hash({"albums" => {"band" => {"name"=>"Rvivr"}}}).band.name).must_equal "Rvivr"
         | 
| 102 102 | 
             
              end
         | 
| 103 103 | 
             
            end
         | 
| 104 104 |  | 
| @@ -120,7 +120,7 @@ class XMLDisableWrapTest < MiniTest::Spec | |
| 120 120 | 
             
                # end
         | 
| 121 121 | 
             
              end
         | 
| 122 122 |  | 
| 123 | 
            -
              let | 
| 123 | 
            +
              let(:band) { BandDecorator.prepare(Band.new("Social Distortion")) }
         | 
| 124 124 |  | 
| 125 125 | 
             
              it do
         | 
| 126 126 | 
             
                band.to_xml.must_equal_xml "<bands><name>Social Distortion</name></bands>"
         | 
| @@ -137,12 +137,12 @@ class XMLDisableWrapTest < MiniTest::Spec | |
| 137 137 | 
             
              end
         | 
| 138 138 |  | 
| 139 139 |  | 
| 140 | 
            -
              let | 
| 140 | 
            +
              let(:album) { AlbumDecorator.prepare(Album.new(Band.new("Social Distortion", Label.new("Epitaph")))) }
         | 
| 141 141 |  | 
| 142 142 | 
             
              # band has wrap turned of per property definition, however, label still has wrap.
         | 
| 143 143 | 
             
              it "rendersxx" do
         | 
| 144 144 | 
             
                skip
         | 
| 145 | 
            -
                album.to_xml.must_equal({"albums" => {"band" => {"name"=>"Social Distortion", "label"=>{"important"=>{"name"=>"Epitaph"}}}}})
         | 
| 145 | 
            +
                _(album.to_xml).must_equal({"albums" => {"band" => {"name"=>"Social Distortion", "label"=>{"important"=>{"name"=>"Epitaph"}}}}})
         | 
| 146 146 | 
             
              end
         | 
| 147 147 |  | 
| 148 148 | 
             
              # it "parses" do
         | 
    
        data/test/xml_bindings_test.rb
    CHANGED
    
    | @@ -1,10 +1,6 @@ | |
| 1 1 | 
             
            require 'test_helper'
         | 
| 2 | 
            -
            require 'representable/json'  # FIXME.
         | 
| 3 | 
            -
            require 'representable/xml/collection'
         | 
| 4 2 | 
             
            require 'representable/xml/hash'
         | 
| 5 3 |  | 
| 6 | 
            -
            require 'representable/xml'
         | 
| 7 | 
            -
             | 
| 8 4 | 
             
            class XMLBindingTest < MiniTest::Spec
         | 
| 9 5 | 
             
              module SongRepresenter
         | 
| 10 6 | 
             
                include Representable::XML
         | 
| @@ -0,0 +1,186 @@ | |
| 1 | 
            +
            require "test_helper"
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            # <lib:library
         | 
| 4 | 
            +
            #    xmlns:lib="http://eric.van-der-vlist.com/ns/library"
         | 
| 5 | 
            +
            #    xmlns:hr="http://eric.van-der-vlist.com/ns/person">
         | 
| 6 | 
            +
            #   <lib:book id="b0836217462" available="true">
         | 
| 7 | 
            +
            #    <lib:isbn>0836217462</lib:isbn>
         | 
| 8 | 
            +
            #    <lib:title xml:lang="en">Being a Dog Is a Full-Time Job</lib:title>
         | 
| 9 | 
            +
            #    <hr:author id="CMS">
         | 
| 10 | 
            +
            #     <hr:name>Charles M Schulz</hr:name>
         | 
| 11 | 
            +
            #     <hr:born>1922-11-26</hr:born>
         | 
| 12 | 
            +
            #     <hr:dead>2000-02-12</hr:dead>
         | 
| 13 | 
            +
            #    </hr:author>
         | 
| 14 | 
            +
            #    <lib:character id="PP">
         | 
| 15 | 
            +
            #     <hr:name>Peppermint Patty</hr:name>
         | 
| 16 | 
            +
            #     <hr:born>1966-08-22</hr:born>
         | 
| 17 | 
            +
            #     <lib:qualification>bold, brash and tomboyish</lib:qualification>
         | 
| 18 | 
            +
            #     </lib:character>
         | 
| 19 | 
            +
            #    <lib:character id="Snoopy">
         | 
| 20 | 
            +
            #     <hr:name>Snoopy</hr:name>
         | 
| 21 | 
            +
            #     <hr:born>1950-10-04</hr:born>
         | 
| 22 | 
            +
            #     <lib:qualification>extroverted beagle</lib:qualification>
         | 
| 23 | 
            +
            #    </lib:character>
         | 
| 24 | 
            +
            #    <lib:character id="Schroeder">
         | 
| 25 | 
            +
            #     <hr:name>Schroeder</hr:name>
         | 
| 26 | 
            +
            #     <hr:born>1951-05-30</hr:born>
         | 
| 27 | 
            +
            #     <lib:qualification>brought classical music to the Peanuts strip
         | 
| 28 | 
            +
            #                   </lib:qualification>
         | 
| 29 | 
            +
            #    </lib:character>
         | 
| 30 | 
            +
            #    <lib:character id="Lucy">
         | 
| 31 | 
            +
            #     <hr:name>Lucy</hr:name>
         | 
| 32 | 
            +
            #     <hr:born>1952-03-03</hr:born>
         | 
| 33 | 
            +
            #     <lib:qualification>bossy, crabby and selfish</lib:qualification>
         | 
| 34 | 
            +
            #    </lib:character>
         | 
| 35 | 
            +
            #   </lib:book>
         | 
| 36 | 
            +
            #  </lib:library>
         | 
| 37 | 
            +
             | 
| 38 | 
            +
              # Theoretically, every property (scalar) needs/should have a namespace.
         | 
| 39 | 
            +
              # property :name, namespace: "http://eric.van-der-vlist.com/ns/person"
         | 
| 40 | 
            +
              # # This is implicit if contained:
         | 
| 41 | 
            +
              # class Person < Decorator
         | 
| 42 | 
            +
              #   namespace: "http://eric.van-der-vlist.com/ns/person"
         | 
| 43 | 
            +
              #   property :name #, namespace: "http://eric.van-der-vlist.com/ns/person"
         | 
| 44 | 
            +
              # end
         | 
| 45 | 
            +
              # class Library
         | 
| 46 | 
            +
              #   namespace "http://eric.van-der-vlist.com/ns/library"
         | 
| 47 | 
            +
             | 
| 48 | 
            +
              #   namespace_def lib:    "http://eric.van-der-vlist.com/ns/library"
         | 
| 49 | 
            +
              #   namespace_def person: "http://eric.van-der-vlist.com/ns/person"
         | 
| 50 | 
            +
              #   # namespace_def person: Person
         | 
| 51 | 
            +
             | 
| 52 | 
            +
              #   property :person, decorator: Person
         | 
| 53 | 
            +
              # end
         | 
| 54 | 
            +
            class NamespaceXMLTest < Minitest::Spec
         | 
| 55 | 
            +
              module Model
         | 
| 56 | 
            +
                Library = Struct.new(:book)
         | 
| 57 | 
            +
                Book = Struct.new(:id, :isbn)
         | 
| 58 | 
            +
              end
         | 
| 59 | 
            +
             | 
| 60 | 
            +
              let (:book) { Model::Book.new(1, 666) }
         | 
| 61 | 
            +
             | 
| 62 | 
            +
              #:simple-class
         | 
| 63 | 
            +
              class Library < Representable::Decorator
         | 
| 64 | 
            +
                feature Representable::XML
         | 
| 65 | 
            +
                feature Representable::XML::Namespace
         | 
| 66 | 
            +
             | 
| 67 | 
            +
                namespace "http://eric.van-der-vlist.com/ns/library"
         | 
| 68 | 
            +
             | 
| 69 | 
            +
                property :book do
         | 
| 70 | 
            +
                  namespace "http://eric.van-der-vlist.com/ns/library"
         | 
| 71 | 
            +
             | 
| 72 | 
            +
                  property :id,  attribute: true
         | 
| 73 | 
            +
                  property :isbn
         | 
| 74 | 
            +
                end
         | 
| 75 | 
            +
              end
         | 
| 76 | 
            +
              #:simple-class end
         | 
| 77 | 
            +
             | 
| 78 | 
            +
             | 
| 79 | 
            +
              # default namespace for library
         | 
| 80 | 
            +
              it "what" do
         | 
| 81 | 
            +
                Library.new(Model::Library.new(book)).to_xml.must_xml(
         | 
| 82 | 
            +
             | 
| 83 | 
            +
                #:simple-xml
         | 
| 84 | 
            +
                %{<library xmlns="http://eric.van-der-vlist.com/ns/library">
         | 
| 85 | 
            +
                  <book id="1">
         | 
| 86 | 
            +
                    <isbn>666</isbn>
         | 
| 87 | 
            +
                  </book>
         | 
| 88 | 
            +
                </library>}
         | 
| 89 | 
            +
                #:simple-xml end
         | 
| 90 | 
            +
                )
         | 
| 91 | 
            +
              end
         | 
| 92 | 
            +
            end
         | 
| 93 | 
            +
             | 
| 94 | 
            +
            class Namespace2XMLTest < Minitest::Spec
         | 
| 95 | 
            +
              module Model
         | 
| 96 | 
            +
                Library   = Struct.new(:book)
         | 
| 97 | 
            +
                Book      = Struct.new(:id, :isbn, :author, :character)
         | 
| 98 | 
            +
                Character = Struct.new(:name, :born, :qualification)
         | 
| 99 | 
            +
              end
         | 
| 100 | 
            +
             | 
| 101 | 
            +
              let (:book) { Model::Book.new(1, 666, Model::Character.new("Fowler"), [Model::Character.new("Frau Java", 1991, "typed")]) }
         | 
| 102 | 
            +
             | 
| 103 | 
            +
              #:map-class
         | 
| 104 | 
            +
              class Library < Representable::Decorator
         | 
| 105 | 
            +
                feature Representable::XML
         | 
| 106 | 
            +
                feature Representable::XML::Namespace
         | 
| 107 | 
            +
             | 
| 108 | 
            +
                namespace "http://eric.van-der-vlist.com/ns/library"
         | 
| 109 | 
            +
                namespace_def lib: "http://eric.van-der-vlist.com/ns/library"
         | 
| 110 | 
            +
                namespace_def hr: "http://eric.van-der-vlist.com/ns/person"
         | 
| 111 | 
            +
             | 
| 112 | 
            +
                property :book, class: Model::Book do
         | 
| 113 | 
            +
                  namespace "http://eric.van-der-vlist.com/ns/library"
         | 
| 114 | 
            +
             | 
| 115 | 
            +
                  property :id,  attribute: true
         | 
| 116 | 
            +
                  property :isbn
         | 
| 117 | 
            +
             | 
| 118 | 
            +
                  property :author, class: Model::Character do
         | 
| 119 | 
            +
                    namespace "http://eric.van-der-vlist.com/ns/person"
         | 
| 120 | 
            +
             | 
| 121 | 
            +
                    property :name
         | 
| 122 | 
            +
                    property :born
         | 
| 123 | 
            +
                  end
         | 
| 124 | 
            +
             | 
| 125 | 
            +
                  collection :character, class: Model::Character do
         | 
| 126 | 
            +
                    namespace "http://eric.van-der-vlist.com/ns/library"
         | 
| 127 | 
            +
             | 
| 128 | 
            +
                    property :qualification
         | 
| 129 | 
            +
             | 
| 130 | 
            +
                    property :name, namespace: "http://eric.van-der-vlist.com/ns/person"
         | 
| 131 | 
            +
                    property :born, namespace: "http://eric.van-der-vlist.com/ns/person"
         | 
| 132 | 
            +
                  end
         | 
| 133 | 
            +
                end
         | 
| 134 | 
            +
              end
         | 
| 135 | 
            +
              #:map-class end
         | 
| 136 | 
            +
             | 
| 137 | 
            +
              it "renders" do
         | 
| 138 | 
            +
                Library.new(Model::Library.new(book)).to_xml.must_xml(
         | 
| 139 | 
            +
            #:map-xml
         | 
| 140 | 
            +
            %{<lib:library xmlns:lib=\"http://eric.van-der-vlist.com/ns/library\" xmlns:hr=\"http://eric.van-der-vlist.com/ns/person\">
         | 
| 141 | 
            +
              <lib:book id=\"1\">
         | 
| 142 | 
            +
                <lib:isbn>666</lib:isbn>
         | 
| 143 | 
            +
                <hr:author>
         | 
| 144 | 
            +
                  <hr:name>Fowler</hr:name>
         | 
| 145 | 
            +
                </hr:author>
         | 
| 146 | 
            +
                <lib:character>
         | 
| 147 | 
            +
                  <lib:qualification>typed</lib:qualification>
         | 
| 148 | 
            +
                  <hr:name>Frau Java</hr:name>
         | 
| 149 | 
            +
                  <hr:born>1991</hr:born>
         | 
| 150 | 
            +
                </lib:character>
         | 
| 151 | 
            +
              </lib:book>
         | 
| 152 | 
            +
            </lib:library>}
         | 
| 153 | 
            +
            #:map-xml end
         | 
| 154 | 
            +
                )
         | 
| 155 | 
            +
              end
         | 
| 156 | 
            +
             | 
| 157 | 
            +
              it "parses" do
         | 
| 158 | 
            +
                lib  = Model::Library.new
         | 
| 159 | 
            +
                #:parse-call
         | 
| 160 | 
            +
                Library.new(lib).from_xml(%{<lib:library
         | 
| 161 | 
            +
              xmlns:lib="http://eric.van-der-vlist.com/ns/library"
         | 
| 162 | 
            +
              xmlns:hr="http://eric.van-der-vlist.com/ns/person">
         | 
| 163 | 
            +
              <lib:book id="1">
         | 
| 164 | 
            +
                <lib:isbn>666</lib:isbn>
         | 
| 165 | 
            +
                <hr:author>
         | 
| 166 | 
            +
                  <hr:name>Fowler</hr:name>
         | 
| 167 | 
            +
                </hr:author>
         | 
| 168 | 
            +
                <lib:character>
         | 
| 169 | 
            +
                  <lib:qualification>typed</lib:qualification>
         | 
| 170 | 
            +
                  <hr:name>Frau Java</hr:name>
         | 
| 171 | 
            +
                  <bogus:name>Mr. Ruby</hr:name>
         | 
| 172 | 
            +
                  <name>Dr. Elixir</hr:name>
         | 
| 173 | 
            +
                  <hr:born>1991</hr:born>
         | 
| 174 | 
            +
                </lib:character>
         | 
| 175 | 
            +
              </lib:book>
         | 
| 176 | 
            +
            </lib:library>}
         | 
| 177 | 
            +
                #:parse-call end
         | 
| 178 | 
            +
                )
         | 
| 179 | 
            +
             | 
| 180 | 
            +
                _(lib.book.inspect).must_equal %{#<struct Namespace2XMLTest::Model::Book id=\"1\", isbn=\"666\", author=#<struct Namespace2XMLTest::Model::Character name=\"Fowler\", born=nil, qualification=nil>, character=[#<struct Namespace2XMLTest::Model::Character name=\"Frau Java\", born=\"1991\", qualification=\"typed\">]>}
         | 
| 181 | 
            +
             | 
| 182 | 
            +
                #:parse-res
         | 
| 183 | 
            +
                lib.book.character[0].name #=> "Frau Java"
         | 
| 184 | 
            +
                #:parse-res end
         | 
| 185 | 
            +
              end
         | 
| 186 | 
            +
            end
         |