representable 3.2.0 → 3.3.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.
Files changed (73) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +17 -10
  3. data/.github/workflows/ci_jruby.yml +21 -0
  4. data/.github/workflows/ci_truffleruby.yml +19 -0
  5. data/CHANGES.md +5 -0
  6. data/Gemfile +1 -1
  7. data/README.md +0 -1
  8. data/lib/representable/hash/binding.rb +1 -0
  9. data/lib/representable/json.rb +14 -2
  10. data/lib/representable/version.rb +1 -1
  11. data/lib/representable/xml/binding.rb +0 -7
  12. data/lib/representable/xml.rb +7 -0
  13. data/representable.gemspec +1 -3
  14. data/test/as_test.rb +8 -13
  15. data/test/benchmarking.rb +20 -25
  16. data/test/binding_test.rb +13 -5
  17. data/test/cached_test.rb +55 -35
  18. data/test/class_test.rb +46 -33
  19. data/test/coercion_test.rb +29 -19
  20. data/test/config/inherit_test.rb +12 -17
  21. data/test/config_test.rb +5 -7
  22. data/test/decorator_scope_test.rb +13 -11
  23. data/test/decorator_test.rb +11 -11
  24. data/test/default_test.rb +2 -2
  25. data/test/defaults_options_test.rb +37 -9
  26. data/test/definition_test.rb +10 -12
  27. data/test/examples/example.rb +43 -38
  28. data/test/examples/object.rb +7 -6
  29. data/test/exec_context_test.rb +18 -23
  30. data/test/features_test.rb +29 -10
  31. data/test/filter_test.rb +29 -20
  32. data/test/for_collection_test.rb +12 -15
  33. data/test/generic_test.rb +15 -22
  34. data/test/getter_setter_test.rb +11 -6
  35. data/test/hash_bindings_test.rb +21 -12
  36. data/test/hash_test.rb +53 -38
  37. data/test/heritage_test.rb +0 -1
  38. data/test/if_test.rb +25 -21
  39. data/test/include_exclude_test.rb +24 -16
  40. data/test/inherit_test.rb +114 -27
  41. data/test/inline_test.rb +42 -33
  42. data/test/instance_test.rb +151 -109
  43. data/test/is_representable_test.rb +19 -17
  44. data/test/json_test.rb +48 -46
  45. data/test/lonely_test.rb +35 -33
  46. data/test/nested_test.rb +16 -19
  47. data/test/object_test.rb +6 -6
  48. data/test/option_test.rb +10 -8
  49. data/test/parse_pipeline_test.rb +21 -15
  50. data/test/pipeline_test.rb +144 -108
  51. data/test/populator_test.rb +18 -15
  52. data/test/prepare_test.rb +15 -17
  53. data/test/private_options_test.rb +3 -2
  54. data/test/reader_writer_test.rb +4 -4
  55. data/test/realistic_benchmark.rb +21 -27
  56. data/test/render_nil_test.rb +1 -1
  57. data/test/represent_test.rb +14 -18
  58. data/test/representable_test.rb +86 -53
  59. data/test/schema_test.rb +51 -21
  60. data/test/serialize_deserialize_test.rb +14 -14
  61. data/test/skip_test.rb +39 -28
  62. data/test/stringify_hash_test.rb +29 -31
  63. data/test/test_helper.rb +31 -25
  64. data/test/test_helper_test.rb +7 -7
  65. data/test/uncategorized_test.rb +20 -15
  66. data/test/user_options_test.rb +12 -3
  67. data/test/wrap_test.rb +27 -17
  68. data/test/xml_assertions.rb +29 -0
  69. data/test/xml_bindings_test.rb +5 -8
  70. data/test/xml_namespace_test.rb +46 -39
  71. data/test/xml_test.rb +109 -88
  72. data/test/yaml_test.rb +73 -51
  73. metadata +7 -32
data/test/skip_test.rb CHANGED
@@ -1,16 +1,18 @@
1
- require 'test_helper'
1
+ require "test_helper"
2
2
 
3
- class SkipParseTest < MiniTest::Spec
3
+ class SkipParseTest < Minitest::Spec
4
4
  representer! do
5
- property :title, skip_parse: lambda { |options| options[:user_options][:skip?] and options[:fragment] == "skip me" }
5
+ property :title, skip_parse: ->(options) { options[:user_options][:skip?] and options[:fragment] == "skip me" }
6
6
  property :band,
7
- skip_parse: lambda { |options| options[:user_options][:skip?] and options[:fragment]["name"].nil? }, class: OpenStruct do
8
- property :name
7
+ skip_parse: ->(options) { options[:user_options][:skip?] and options[:fragment]["name"].nil? }, class: OpenStruct do
8
+ property :name
9
9
  end
10
10
 
11
11
  collection :airplays,
12
- skip_parse: lambda { |options| options[:user_options][:skip?] and options[:fragment]["station"].nil? }, class: OpenStruct do
13
- property :station
12
+ skip_parse: ->(options) {
13
+ options[:user_options][:skip?] and options[:fragment]["station"].nil?
14
+ }, class: OpenStruct do
15
+ property :station
14
16
  end
15
17
  end
16
18
 
@@ -18,11 +20,13 @@ class SkipParseTest < MiniTest::Spec
18
20
 
19
21
  # do parse.
20
22
  it do
21
- song.from_hash({
22
- "title" => "Victim Of Fate",
23
- "band" => {"name" => "Mute 98"},
24
- "airplays" => [{"station" => "JJJ"}]
25
- }, user_options: { skip?: true })
23
+ song.from_hash(
24
+ {
25
+ "title" => "Victim Of Fate",
26
+ "band" => {"name" => "Mute 98"},
27
+ "airplays" => [{"station" => "JJJ"}]
28
+ }, user_options: {skip?: true}
29
+ )
26
30
 
27
31
  _(song.title).must_equal "Victim Of Fate"
28
32
  _(song.band.name).must_equal "Mute 98"
@@ -33,11 +37,13 @@ class SkipParseTest < MiniTest::Spec
33
37
  let(:airplay) { OpenStruct.new(station: "JJJ") }
34
38
 
35
39
  it do
36
- song.from_hash({
37
- "title" => "skip me",
38
- "band" => {},
39
- "airplays" => [{}, {"station" => "JJJ"}, {}],
40
- }, user_options: { skip?: true })
40
+ song.from_hash(
41
+ {
42
+ "title" => "skip me",
43
+ "band" => {},
44
+ "airplays" => [{}, {"station" => "JJJ"}, {}]
45
+ }, user_options: {skip?: true}
46
+ )
41
47
 
42
48
  _(song.title).must_be_nil
43
49
  _(song.band).must_be_nil
@@ -45,17 +51,17 @@ class SkipParseTest < MiniTest::Spec
45
51
  end
46
52
  end
47
53
 
48
- class SkipRenderTest < MiniTest::Spec
54
+ class SkipRenderTest < Minitest::Spec
49
55
  representer! do
50
56
  property :title
51
57
  property :band,
52
- skip_render: lambda { |options| options[:user_options][:skip?] and options[:input].name == "Rancid" } do
53
- property :name
58
+ skip_render: ->(options) { options[:user_options][:skip?] and options[:input].name == "Rancid" } do
59
+ property :name
54
60
  end
55
61
 
56
62
  collection :airplays,
57
- skip_render: lambda { |options| options[:user_options][:skip?] and options[:input].station == "Radio Dreyeckland" } do
58
- property :station
63
+ skip_render: ->(options) { options[:user_options][:skip?] and options[:input].station == "Radio Dreyeckland" } do
64
+ property :station
59
65
  end
60
66
  end
61
67
 
@@ -63,19 +69,24 @@ class SkipRenderTest < MiniTest::Spec
63
69
  let(:skip_song) { OpenStruct.new(title: "Time Bomb", band: OpenStruct.new(name: "Rancid")).extend(representer) }
64
70
 
65
71
  # do render.
66
- it { _(song.to_hash(user_options: { skip?: true })).must_equal({"title"=>"Black Night", "band"=>{"name"=>"Time Again"}}) }
72
+ it { _(song.to_hash(user_options: {skip?: true})).must_equal({"title" => "Black Night", "band" => {"name"=>"Time Again"}}) }
67
73
  # skip.
68
- it { _(skip_song.to_hash(user_options: { skip?: true })).must_equal({"title"=>"Time Bomb"}) }
74
+ it { _(skip_song.to_hash(user_options: {skip?: true})).must_equal({"title"=>"Time Bomb"}) }
69
75
 
70
76
  # do render all collection items.
71
77
  it do
72
78
  song = OpenStruct.new(airplays: [OpenStruct.new(station: "JJJ"), OpenStruct.new(station: "ABC")]).extend(representer)
73
- _(song.to_hash(user_options: { skip?: true })).must_equal({"airplays"=>[{"station"=>"JJJ"}, {"station"=>"ABC"}]})
79
+ _(song.to_hash(user_options: {skip?: true})).must_equal({"airplays"=>[{"station"=>"JJJ"}, {"station"=>"ABC"}]})
74
80
  end
75
81
 
76
82
  # skip middle item.
77
83
  it do
78
- song = OpenStruct.new(airplays: [OpenStruct.new(station: "JJJ"), OpenStruct.new(station: "Radio Dreyeckland"), OpenStruct.new(station: "ABC")]).extend(representer)
79
- _(song.to_hash(user_options: { skip?: true })).must_equal({"airplays"=>[{"station"=>"JJJ"}, {"station"=>"ABC"}]})
84
+ song = OpenStruct.new(
85
+ airplays: [
86
+ OpenStruct.new(station: "JJJ"), OpenStruct.new(station: "Radio Dreyeckland"),
87
+ OpenStruct.new(station: "ABC")
88
+ ]
89
+ ).extend(representer)
90
+ _(song.to_hash(user_options: {skip?: true})).must_equal({"airplays"=>[{"station"=>"JJJ"}, {"station"=>"ABC"}]})
80
91
  end
81
- end
92
+ end
@@ -1,41 +1,39 @@
1
- require 'test_helper'
1
+ require "test_helper"
2
2
 
3
- class StringifyHashTest < MiniTest::Spec
4
- describe "#from_hash" do
5
- representer!(:name => :song_representer) do
6
-
7
- include Representable::Hash
8
- include Representable::Hash::AllowSymbols
9
-
10
- property :title
11
- end
12
-
13
- representer!(:inject => :song_representer) do
14
- include Representable::Hash::AllowSymbols
15
-
16
- property :song, :extend => song_representer, :class => OpenStruct
17
- end
18
-
19
- it "parses symbols, too" do
20
- _(OpenStruct.new.extend(representer).from_hash({:song => {:title => "Der Optimist"}}).song.title).must_equal "Der Optimist"
21
- end
3
+ class StringifyHashTest < Minitest::Spec
4
+ describe "#from_hash" do
5
+ representer!(:name => :song_representer) do
6
+ include Representable::Hash
7
+ include Representable::Hash::AllowSymbols
22
8
 
23
- it "still parses strings" do
24
- _(OpenStruct.new.extend(representer).from_hash({"song" => {"title" => "Der Optimist"}}).song.title).must_equal "Der Optimist"
25
- end
9
+ property :title
10
+ end
26
11
 
27
- describe "with :wrap" do
28
12
  representer!(:inject => :song_representer) do
29
13
  include Representable::Hash::AllowSymbols
30
14
 
31
- self.representation_wrap = :album
32
15
  property :song, :extend => song_representer, :class => OpenStruct
33
16
  end
34
17
 
35
- it "parses symbols, too" do
36
- _(OpenStruct.new.extend(representer).from_hash({:album => {:song => {:title => "Der Optimist"}}}).song.title).must_equal "Der Optimist"
37
- end
38
- end
39
- end
18
+ it "parses symbols, too" do
19
+ _(OpenStruct.new.extend(representer).from_hash({:song => {:title => "Der Optimist"}}).song.title).must_equal "Der Optimist"
20
+ end
21
+
22
+ it "still parses strings" do
23
+ _(OpenStruct.new.extend(representer).from_hash({"song" => {"title" => "Der Optimist"}}).song.title).must_equal "Der Optimist"
24
+ end
25
+
26
+ describe "with :wrap" do
27
+ representer!(:inject => :song_representer) do
28
+ include Representable::Hash::AllowSymbols
40
29
 
41
- end
30
+ self.representation_wrap = :album
31
+ property :song, :extend => song_representer, :class => OpenStruct
32
+ end
33
+
34
+ it "parses symbols, too" do
35
+ _(OpenStruct.new.extend(representer).from_hash({:album => {:song => {:title => "Der Optimist"}}}).song.title).must_equal "Der Optimist"
36
+ end
37
+ end
38
+ end
39
+ end
data/test/test_helper.rb CHANGED
@@ -1,23 +1,26 @@
1
- require 'pry-byebug'
2
- require 'representable'
1
+ require "ostruct"
2
+ require "representable"
3
3
 
4
- require 'minitest/autorun'
5
- require 'test_xml/mini_test'
4
+ require "minitest/autorun"
6
5
 
7
6
  require "representable/debug"
8
- require 'minitest/assertions'
7
+ require "minitest/assertions"
8
+ require "xml_assertions"
9
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+)/, "")
10
+ module Minitest::Assertions
11
+ include XmlAssertions
12
+
13
+ # Arguments read (asserted, expected), the assertion order used throughout this suite.
14
+ def assert_equal_xml(subject, text)
15
+ assert_equal text.gsub("\n", "").gsub(/(\s\s+)/, ""), subject.gsub("\n", "").gsub(/(\s\s+)/, "")
13
16
  end
14
17
  end
15
- String.infect_an_assertion :assert_equal_xml, :must_xml
16
18
 
17
19
  # TODO: delete all that in 4.0:
18
20
  class Album
19
21
  attr_accessor :songs, :best_song
20
- def initialize(songs=nil, best_song=nil)
22
+
23
+ def initialize(songs = nil, best_song = nil)
21
24
  @songs = songs
22
25
  @best_song = best_song
23
26
  end
@@ -29,7 +32,8 @@ end
29
32
 
30
33
  class Song
31
34
  attr_accessor :name, :track # never change this, track rendered with Rails#to_json.
32
- def initialize(name=nil, track=nil)
35
+
36
+ def initialize(name = nil, track = nil)
33
37
  @name = name
34
38
  @track = track
35
39
  end
@@ -47,14 +51,14 @@ end
47
51
 
48
52
  module AssertJson
49
53
  module Assertions
50
- def assert_json(expected, actual, msg=nil)
54
+ def assert_json(expected, actual, msg = nil)
51
55
  msg = message(msg, "") { diff expected, actual }
52
56
  assert_equal(expected.split("").sort, actual.split("").sort, msg)
53
57
  end
54
58
  end
55
59
  end
56
60
 
57
- MiniTest::Spec.class_eval do
61
+ Minitest::Spec.class_eval do
58
62
  include AssertJson::Assertions
59
63
  include XmlHelper
60
64
 
@@ -66,7 +70,7 @@ MiniTest::Spec.class_eval do
66
70
  end
67
71
 
68
72
  def render(object, *args)
69
- AssertableDocument.new(object.send("to_#{format}", *args), format)
73
+ AssertableDocument.new(object.send("to_#{format}", *args), format, self)
70
74
  end
71
75
 
72
76
  def parse(object, input, *args)
@@ -76,17 +80,20 @@ MiniTest::Spec.class_eval do
76
80
  class AssertableDocument
77
81
  attr_reader :document
78
82
 
79
- def initialize(document, format)
80
- @document, @format = document, format
83
+ def initialize(document, format, test)
84
+ @document = document
85
+ @format = format
86
+ @test = test
81
87
  end
82
88
 
83
- def must_equal_document(*args)
84
- return document.must_equal_xml(*args) if @format == :xml
85
- document.must_equal(*args)
89
+ def must_equal_document(expected, *rest)
90
+ return @test.assert_xml_equal(document, expected, *rest) if @format == :xml
91
+
92
+ @test.assert_equal(expected, document, *rest)
86
93
  end
87
94
  end
88
95
 
89
- def self.representer!(options={}, &block)
96
+ def self.representer!(options = {}, &block)
90
97
  fmt = options # we need that so the 2nd call to ::let(within a ::describe) remembers the right format.
91
98
 
92
99
  name = options[:name] || :representer
@@ -119,7 +126,7 @@ MiniTest::Spec.class_eval do
119
126
  end
120
127
 
121
128
  module TestMethods
122
- def representer_for(modules=[Representable::Hash], &block)
129
+ def representer_for(modules = [Representable::Hash], &block)
123
130
  Module.new do
124
131
  extend TestMethods
125
132
  include(*modules)
@@ -127,17 +134,16 @@ MiniTest::Spec.class_eval do
127
134
  end
128
135
  end
129
136
 
130
- alias_method :representer!, :representer_for
137
+ alias representer! representer_for
131
138
  end
132
139
  include TestMethods
133
140
  end
134
141
 
135
- class BaseTest < MiniTest::Spec
142
+ class BaseTest < Minitest::Spec
136
143
  let(:new_album) { OpenStruct.new.extend(representer) }
137
144
  let(:album) { OpenStruct.new(:songs => ["Fuck Armageddon"]).extend(representer) }
138
145
  let(:song) { OpenStruct.new(:title => "Resist Stance") }
139
- let(:song_representer) { Module.new do include Representable::Hash; property :title end }
140
-
146
+ let(:song_representer) { Module.new { include Representable::Hash; property :title } }
141
147
  end
142
148
 
143
149
  Band = Struct.new(:id, :name) do
@@ -1,23 +1,23 @@
1
- require 'test_helper'
1
+ require "test_helper"
2
2
 
3
- class TestHelperTest < MiniTest::Spec
3
+ class TestHelperTest < Minitest::Spec
4
4
  describe "#assert_json" do
5
5
  it "tests for equality" do
6
6
  assert_json "{\"songs\":{\"one\":\"65\",\"two\":\"Emo Boy\"}}", "{\"songs\":{\"one\":\"65\",\"two\":\"Emo Boy\"}}"
7
7
  end
8
-
8
+
9
9
  it "allows different key orders" do
10
10
  assert_json "{\"songs\":{\"one\":\"65\",\"two\":\"Emo Boy\"}}", "{\"songs\":{\"two\":\"Emo Boy\",\"one\":\"65\"}}"
11
11
  end
12
-
12
+
13
13
  it "complains when expected hash is subset" do
14
- assert_raises MiniTest::Assertion do
14
+ assert_raises Minitest::Assertion do
15
15
  assert_json "{\"songs\":{\"one\":\"65\"}}", "{\"songs\":{\"two\":\"Emo Boy\",\"one\":\"65\"}}"
16
16
  end
17
17
  end
18
-
18
+
19
19
  it "complains when source hash is subset" do
20
- assert_raises MiniTest::Assertion do
20
+ assert_raises Minitest::Assertion do
21
21
  assert_json "{\"songs\":{\"two\":\"Emo Boy\",\"one\":\"65\"}}", "{\"songs\":{\"one\":\"65\"}}"
22
22
  end
23
23
  end
@@ -1,36 +1,42 @@
1
1
  require "test_helper"
2
2
 
3
- class StopWhenIncomingObjectFragmentIsNilTest < MiniTest::Spec
3
+ class StopWhenIncomingObjectFragmentIsNilTest < Minitest::Spec
4
4
  Album = Struct.new(:id, :songs)
5
5
  Song = Struct.new(:title)
6
6
 
7
7
  representer!(decorator: true) do
8
8
  property :id
9
- collection :songs, class: Song, parse_pipeline: ->(input, options) { # TODO: test if :doc is set for parsing. test if options are ok and contain :user_options!
10
- Representable::Pipeline[*parse_functions.insert(3, Representable::StopOnNil)]
11
- } do
9
+ collection :songs, class: Song, parse_pipeline: ->(_input, _options) { # TODO: test if :doc is set for parsing. test if options are ok and contain :user_options!
10
+ Representable::Pipeline[*parse_functions.insert(3, Representable::StopOnNil)]
11
+ } do
12
12
  property :title
13
13
  end
14
14
  end
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
+ _(
19
+ representer.new(album).from_hash(
20
+ {
21
+ "id" => 1,
22
+ "songs" => [{"title"=>"Walkie Talkie"}]
23
+ }
24
+ ).songs
25
+ ).must_equal [Song.new("Walkie Talkie")]
19
26
  end
20
27
 
21
28
  it do
22
29
  album = Album.new(2, ["original"])
23
- _(representer.new(album).from_hash({"id"=>1, "songs"=>nil}).songs).must_equal ["original"]
30
+ _(representer.new(album).from_hash({"id" => 1, "songs" => nil}).songs).must_equal ["original"]
24
31
  end
25
-
26
32
  end
27
33
 
28
- class RenderPipelineOptionTest < MiniTest::Spec
34
+ class RenderPipelineOptionTest < Minitest::Spec
29
35
  Album = Struct.new(:id, :songs)
30
- NilToNA = ->(input, options) { input.nil? ? "n/a" : input }
36
+ NilToNA = ->(input, _options) { input.nil? ? "n/a" : input }
31
37
 
32
38
  representer!(decorator: true) do
33
- property :id, render_pipeline: ->(input, options) do
39
+ property :id, render_pipeline: ->(_input, options) do
34
40
  Representable::Pipeline[*render_functions.insert(2, options[:options][:user_options][:function])]
35
41
  end
36
42
  end
@@ -43,15 +49,14 @@ class RenderPipelineOptionTest < MiniTest::Spec
43
49
  _(decorator.to_hash(user_options: {function: NilToNA})).must_equal({"id"=>"n/a"})
44
50
  _(decorator.to_hash(user_options: {function: nil})).must_equal({"id"=>"n/a"}) # non-sense function is not applied.
45
51
  end
46
-
47
52
  end
48
53
 
49
- class ParsePipelineOptionTest < MiniTest::Spec
54
+ class ParsePipelineOptionTest < Minitest::Spec
50
55
  Album = Struct.new(:id, :songs)
51
- NilToNA = ->(input, options) { input.nil? ? "n/a" : input }
56
+ NilToNA = ->(input, _options) { input.nil? ? "n/a" : input }
52
57
 
53
58
  representer!(decorator: true) do
54
- property :id, parse_pipeline: ->(input, options) do
59
+ property :id, parse_pipeline: ->(_input, options) do
55
60
  Representable::Pipeline[*parse_functions.insert(3, options[:options][:user_options][:function])].extend(Representable::Pipeline::Debug)
56
61
  end
57
62
  end
@@ -64,4 +69,4 @@ class ParsePipelineOptionTest < MiniTest::Spec
64
69
  _(decorator.from_hash({"id"=>nil}, user_options: {function: NilToNA}).id).must_equal "n/a"
65
70
  _(decorator.from_hash({"id"=>nil}, user_options: {function: "nonsense"}).id).must_equal "n/a" # non-sense function is not applied.
66
71
  end
67
- end
72
+ end
@@ -8,8 +8,17 @@ class UserOptionsTest < Minitest::Spec
8
8
  end
9
9
 
10
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"}) }
11
+ it {
12
+ _(Song.new("Run With It").extend(representer).to_hash(user_options: {visible: true})).must_equal({"title"=>"Run With It"})
13
+ }
12
14
  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" }
15
+ it {
16
+ _(
17
+ Song.new("Run With It").extend(representer).from_hash(
18
+ {"title"=>"Business Conduct"},
19
+ user_options: {visible: true}
20
+ ).title
21
+ ).must_equal "Business Conduct"
22
+ }
14
23
  end
15
- # Representable.deprecations=false
24
+ # Representable.deprecations=false
data/test/wrap_test.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  require "test_helper"
2
2
 
3
- class WrapTest < MiniTest::Spec
3
+ class WrapTest < Minitest::Spec
4
4
  class HardcoreBand
5
5
  include Representable::Hash
6
6
  end
@@ -27,16 +27,15 @@ class WrapTest < MiniTest::Spec
27
27
  for_formats(
28
28
  :hash => [Representable::Hash, {"Blink182"=>{"genre"=>"Pop"}}, {"Blink182"=>{"genre"=>"Poppunk"}}],
29
29
  :json => [Representable::JSON, "{\"Blink182\":{\"genre\":\"Pop\"}}", "{\"Blink182\":{\"genre\":\"Poppunk\"}}"],
30
- :xml => [Representable::XML, "<Blink182><genre>Pop</genre></Blink182>", "<Blink182><genre>Poppunk</genre></Blink182>"],
30
+ :xml => [Representable::XML, "<Blink182><genre>Pop</genre></Blink182>", "<Blink182><genre>Poppunk</genre></Blink182>"]
31
31
  # :yaml => [Representable::YAML, "---\nBlink182:\n"], # TODO: fix YAML.
32
32
  ) do |format, mod, output, input|
33
-
34
33
  describe "[#{format}] dynamic wrap" do
35
34
  let(:band) { representer.prepare(Struct.new(:name, :genre).new("Blink", "Pop")) }
36
35
  let(:format) { format }
37
36
 
38
37
  representer!(:module => mod) do
39
- self.representation_wrap = lambda { |number:, **| "#{name}#{number}" }
38
+ self.representation_wrap = ->(number:, **) { "#{name}#{number}" }
40
39
  property :genre
41
40
  end
42
41
 
@@ -47,8 +46,7 @@ class WrapTest < MiniTest::Spec
47
46
  end
48
47
  end
49
48
 
50
-
51
- class HashDisableWrapTest < MiniTest::Spec
49
+ class HashDisableWrapTest < Minitest::Spec
52
50
  Band = Struct.new(:name, :label)
53
51
  Album = Struct.new(:band)
54
52
  Label = Struct.new(:name)
@@ -80,7 +78,6 @@ class HashDisableWrapTest < MiniTest::Spec
80
78
  _(band.from_hash({band: {"name"=>"Social Distortion"}}, wrap: :band).name).must_equal "Social Distortion"
81
79
  end
82
80
 
83
-
84
81
  class AlbumDecorator < Representable::Decorator
85
82
  include Representable::Hash
86
83
 
@@ -89,12 +86,20 @@ class HashDisableWrapTest < MiniTest::Spec
89
86
  property :band, decorator: BandDecorator, wrap: false, class: Band
90
87
  end
91
88
 
92
-
93
89
  let(:album) { AlbumDecorator.prepare(Album.new(Band.new("Social Distortion", Label.new("Epitaph")))) }
94
90
 
95
91
  # band has wrap turned off per property definition, however, label still has wrap.
96
92
  it "renders" do
97
- _(album.to_hash).must_equal({"albums" => {"band" => {"name"=>"Social Distortion", "label"=>{"important"=>{"name"=>"Epitaph"}}}}})
93
+ _(album.to_hash).must_equal(
94
+ {
95
+ "albums" => {
96
+ "band" => {
97
+ "name" => "Social Distortion",
98
+ "label" => {"important"=>{"name"=>"Epitaph"}}
99
+ }
100
+ }
101
+ }
102
+ )
98
103
  end
99
104
 
100
105
  it "parses" do
@@ -102,8 +107,7 @@ class HashDisableWrapTest < MiniTest::Spec
102
107
  end
103
108
  end
104
109
 
105
-
106
- class XMLDisableWrapTest < MiniTest::Spec
110
+ class XMLDisableWrapTest < Minitest::Spec
107
111
  Band = Struct.new(:name, :label)
108
112
  Album = Struct.new(:band)
109
113
  Label = Struct.new(:name)
@@ -123,11 +127,10 @@ class XMLDisableWrapTest < MiniTest::Spec
123
127
  let(:band) { BandDecorator.prepare(Band.new("Social Distortion")) }
124
128
 
125
129
  it do
126
- band.to_xml.must_equal_xml "<bands><name>Social Distortion</name></bands>"
127
- band.to_xml(wrap: "combo").must_equal_xml "<combo><name>Social Distortion</name></combo>"
130
+ assert_xml_equal(band.to_xml, "<bands><name>Social Distortion</name></bands>")
131
+ assert_xml_equal(band.to_xml(wrap: "combo"), "<combo><name>Social Distortion</name></combo>")
128
132
  end
129
133
 
130
-
131
134
  class AlbumDecorator < Representable::Decorator
132
135
  include Representable::XML
133
136
 
@@ -136,17 +139,24 @@ class XMLDisableWrapTest < MiniTest::Spec
136
139
  property :band, decorator: BandDecorator, wrap: "po", class: Band
137
140
  end
138
141
 
139
-
140
142
  let(:album) { AlbumDecorator.prepare(Album.new(Band.new("Social Distortion", Label.new("Epitaph")))) }
141
143
 
142
144
  # band has wrap turned of per property definition, however, label still has wrap.
143
145
  it "rendersxx" do
144
146
  skip
145
- _(album.to_xml).must_equal({"albums" => {"band" => {"name"=>"Social Distortion", "label"=>{"important"=>{"name"=>"Epitaph"}}}}})
147
+ _(album.to_xml).must_equal(
148
+ {
149
+ "albums" => {
150
+ "band" => {
151
+ "name" => "Social Distortion",
152
+ "label" => {"important"=>{"name"=>"Epitaph"}}
153
+ }
154
+ }
155
+ }
156
+ )
146
157
  end
147
158
 
148
159
  # it "parses" do
149
160
  # album.from_hash({"albums" => {"band" => {"name"=>"Rvivr"}}}).band.name.must_equal "Rvivr"
150
161
  # end
151
162
  end
152
-
@@ -0,0 +1,29 @@
1
+ require "nokogiri"
2
+
3
+ # Order-insensitive XML comparison: attributes are sorted by name and sibling
4
+ # elements by their own canonical form, then both documents are compared as
5
+ # strings.
6
+ module XmlAssertions
7
+ def self.canonicalize(xml, indent = 0)
8
+ node = xml.is_a?(String) ? Nokogiri::XML.parse(xml).root : xml
9
+ return "(unparsable xml)\n#{xml}" if node.nil?
10
+
11
+ pad = " " * indent
12
+ attrs = node.attribute_nodes.map { |a| " #{a.name}=#{a.value.inspect}" }.sort.join
13
+ children = node.elements
14
+
15
+ if children.empty?
16
+ "#{pad}<#{node.name}#{attrs}>#{node.text.strip}</#{node.name}>\n"
17
+ else
18
+ body = children.map { |child| canonicalize(child, indent + 1) }.sort.join
19
+ "#{pad}<#{node.name}#{attrs}>\n#{body}#{pad}</#{node.name}>\n"
20
+ end
21
+ end
22
+
23
+ # Arguments read (asserted, expected), the assertion order used throughout this suite.
24
+ def assert_xml_equal(actual, expected, msg = nil)
25
+ assert_equal XmlAssertions.canonicalize(expected),
26
+ XmlAssertions.canonicalize(actual),
27
+ msg
28
+ end
29
+ end
@@ -1,7 +1,7 @@
1
- require 'test_helper'
2
- require 'representable/xml/hash'
1
+ require "test_helper"
2
+ require "representable/xml/hash"
3
3
 
4
- class XMLBindingTest < MiniTest::Spec
4
+ class XMLBindingTest < Minitest::Spec
5
5
  module SongRepresenter
6
6
  include Representable::XML
7
7
  property :name
@@ -19,9 +19,6 @@ class XMLBindingTest < MiniTest::Spec
19
19
  @song = SongWithRepresenter.new("Thinning the Herd")
20
20
  end
21
21
 
22
-
23
-
24
-
25
22
  describe "AttributeBinding" do
26
23
  describe "with plain text items" do
27
24
  before do
@@ -35,7 +32,7 @@ class XMLBindingTest < MiniTest::Spec
35
32
  it "inserts with #write" do
36
33
  parent = Nokogiri::XML::Node.new("song", @doc)
37
34
  @property.write(parent, "The Gargoyle", "name")
38
- assert_xml_equal("<song name=\"The Gargoyle\" />", parent.to_s)
35
+ assert_xml_equal(parent.to_s, "<song name=\"The Gargoyle\" />")
39
36
  end
40
37
  end
41
38
  end
@@ -52,7 +49,7 @@ class XMLBindingTest < MiniTest::Spec
52
49
  it "inserts with #write" do
53
50
  parent = Nokogiri::XML::Node.new("song", @doc)
54
51
  @property.write(parent, "The Gargoyle", "song")
55
- assert_xml_equal("<song>The Gargoyle</song>", parent.to_s)
52
+ assert_xml_equal(parent.to_s, "<song>The Gargoyle</song>")
56
53
  end
57
54
  end
58
55
  end