representable 2.4.0.rc3 → 2.4.0.rc4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (99) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES.md +7 -2
  3. data/Rakefile +6 -0
  4. data/lib/representable.rb +21 -17
  5. data/lib/representable/binding.rb +3 -2
  6. data/lib/representable/definition.rb +1 -1
  7. data/lib/representable/deprecations.rb +31 -5
  8. data/lib/representable/deserializer.rb +24 -34
  9. data/lib/representable/hash/collection.rb +9 -2
  10. data/lib/representable/hash_methods.rb +2 -2
  11. data/lib/representable/parse_strategies.rb +6 -7
  12. data/lib/representable/pipeline.rb +12 -1
  13. data/lib/representable/pipeline_factories.rb +9 -2
  14. data/lib/representable/serializer.rb +3 -3
  15. data/lib/representable/version.rb +1 -1
  16. data/test-with-deprecations/as_test.rb +65 -0
  17. data/test-with-deprecations/benchmarking.rb +83 -0
  18. data/test-with-deprecations/binding_test.rb +46 -0
  19. data/test-with-deprecations/blaaaaaaaa_test.rb +69 -0
  20. data/test-with-deprecations/cached_test.rb +147 -0
  21. data/test-with-deprecations/class_test.rb +119 -0
  22. data/test-with-deprecations/coercion_test.rb +52 -0
  23. data/test-with-deprecations/config/inherit_test.rb +135 -0
  24. data/test-with-deprecations/config_test.rb +122 -0
  25. data/test-with-deprecations/decorator_scope_test.rb +28 -0
  26. data/test-with-deprecations/decorator_test.rb +96 -0
  27. data/test-with-deprecations/default_test.rb +34 -0
  28. data/test-with-deprecations/defaults_options_test.rb +93 -0
  29. data/test-with-deprecations/definition_test.rb +264 -0
  30. data/test-with-deprecations/example.rb +310 -0
  31. data/test-with-deprecations/examples/object.rb +31 -0
  32. data/test-with-deprecations/exec_context_test.rb +93 -0
  33. data/test-with-deprecations/features_test.rb +70 -0
  34. data/test-with-deprecations/filter_test.rb +57 -0
  35. data/test-with-deprecations/for_collection_test.rb +74 -0
  36. data/test-with-deprecations/generic_test.rb +116 -0
  37. data/test-with-deprecations/getter_setter_test.rb +21 -0
  38. data/test-with-deprecations/hash_bindings_test.rb +87 -0
  39. data/test-with-deprecations/hash_test.rb +160 -0
  40. data/test-with-deprecations/heritage_test.rb +62 -0
  41. data/test-with-deprecations/if_test.rb +79 -0
  42. data/test-with-deprecations/include_exclude_test.rb +88 -0
  43. data/test-with-deprecations/inherit_test.rb +159 -0
  44. data/test-with-deprecations/inline_test.rb +272 -0
  45. data/test-with-deprecations/instance_test.rb +266 -0
  46. data/test-with-deprecations/is_representable_test.rb +77 -0
  47. data/test-with-deprecations/json_test.rb +355 -0
  48. data/test-with-deprecations/lonely_test.rb +239 -0
  49. data/test-with-deprecations/mongoid_test.rb +31 -0
  50. data/test-with-deprecations/nested_test.rb +115 -0
  51. data/test-with-deprecations/object_test.rb +60 -0
  52. data/{test/---deserialize-pipeline_test.rb → test-with-deprecations/parse_pipeline_test.rb} +29 -2
  53. data/test-with-deprecations/parse_strategy_test.rb +279 -0
  54. data/{test → test-with-deprecations}/pass_options_test.rb +0 -0
  55. data/test-with-deprecations/pipeline_test.rb +277 -0
  56. data/test-with-deprecations/populator_test.rb +105 -0
  57. data/test-with-deprecations/prepare_test.rb +67 -0
  58. data/test-with-deprecations/private_options_test.rb +18 -0
  59. data/test-with-deprecations/reader_writer_test.rb +19 -0
  60. data/test-with-deprecations/realistic_benchmark.rb +115 -0
  61. data/test-with-deprecations/render_nil_test.rb +21 -0
  62. data/test-with-deprecations/represent_test.rb +88 -0
  63. data/test-with-deprecations/representable_test.rb +511 -0
  64. data/test-with-deprecations/schema_test.rb +148 -0
  65. data/test-with-deprecations/serialize_deserialize_test.rb +33 -0
  66. data/test-with-deprecations/skip_test.rb +81 -0
  67. data/test-with-deprecations/stringify_hash_test.rb +41 -0
  68. data/test-with-deprecations/test_helper.rb +135 -0
  69. data/test-with-deprecations/test_helper_test.rb +25 -0
  70. data/test-with-deprecations/uncategorized_test.rb +67 -0
  71. data/test-with-deprecations/user_options_test.rb +15 -0
  72. data/test-with-deprecations/wrap_test.rb +152 -0
  73. data/test-with-deprecations/xml_bindings_test.rb +62 -0
  74. data/test-with-deprecations/xml_test.rb +503 -0
  75. data/test-with-deprecations/yaml_test.rb +162 -0
  76. data/test/as_test.rb +3 -3
  77. data/test/cached_test.rb +2 -2
  78. data/test/class_test.rb +5 -5
  79. data/test/exec_context_test.rb +2 -2
  80. data/test/filter_test.rb +1 -1
  81. data/test/getter_setter_test.rb +4 -4
  82. data/test/if_test.rb +2 -2
  83. data/test/include_exclude_test.rb +88 -0
  84. data/test/instance_test.rb +15 -15
  85. data/test/lonely_test.rb +18 -2
  86. data/test/object_test.rb +4 -4
  87. data/test/parse_pipeline_test.rb +64 -0
  88. data/test/parse_strategy_test.rb +3 -3
  89. data/test/pipeline_test.rb +8 -12
  90. data/test/prepare_test.rb +2 -3
  91. data/test/reader_writer_test.rb +3 -3
  92. data/test/representable_test.rb +12 -48
  93. data/test/serialize_deserialize_test.rb +9 -9
  94. data/test/skip_test.rb +11 -11
  95. data/test/test_helper.rb +2 -0
  96. data/test/uncategorized_test.rb +10 -10
  97. data/test/user_options_test.rb +15 -0
  98. data/test/wrap_test.rb +1 -1
  99. metadata +65 -4
@@ -0,0 +1,148 @@
1
+ require 'test_helper'
2
+
3
+ # Include Inherit Module And Decorator Test
4
+ class SchemaTest < MiniTest::Spec
5
+ module Genre
6
+ include Representable
7
+ property :genre
8
+ end
9
+
10
+ module LinkFeature
11
+ def self.included(base)
12
+ base.extend(Link)
13
+ end
14
+
15
+ module Link
16
+ def link
17
+ end
18
+ end
19
+ end
20
+
21
+
22
+ module Module
23
+ include Representable::Hash
24
+ feature LinkFeature
25
+
26
+ property :title
27
+ property :label do # extend: LabelModule
28
+ property :name
29
+ link # feature
30
+
31
+ property :location do
32
+ property :city
33
+ link # feature.
34
+ end
35
+ end
36
+
37
+ property :album, :extend => lambda { raise "don't manifest me!" } # this is not an inline decorator, don't manifest it.
38
+
39
+
40
+ include Genre # Schema::Included::included is called!
41
+ end
42
+
43
+
44
+ class WithLocationStreetRepresenter < Representable::Decorator
45
+ include Representable::Hash
46
+ feature LinkFeature
47
+
48
+ property :title
49
+ property :label do # extend: LabelModule
50
+ property :name
51
+ link # feature
52
+
53
+ property :location do
54
+ property :city
55
+ link # feature.
56
+ end
57
+ end
58
+ end
59
+
60
+ describe "3-level deep with features" do
61
+ let (:label) { OpenStruct.new(:name => "Epitaph", :location => OpenStruct.new(:city => "Sanfran", :name => "DON'T SHOW ME!")) }
62
+
63
+ # Module does correctly include features in inlines.
64
+ it { band.extend(Module).to_hash.must_equal({"label"=>{"name"=>"Epitaph", "location"=>{"city"=>"Sanfran"}}, "genre"=>"Punkrock"}) }
65
+
66
+ # Decorator does correctly include features in inlines.
67
+ it { Decorator.new(band).to_hash.must_equal({"label"=>{"name"=>"Epitaph", "location"=>{"city"=>"Sanfran"}}, "genre"=>"Punkrock"}) }
68
+ end
69
+
70
+
71
+
72
+ class Decorator < Representable::Decorator
73
+ feature Representable::Hash
74
+
75
+ include Module
76
+ end
77
+
78
+ # puts Decorator.representable_attrs[:definitions].inspect
79
+
80
+ let (:label) { OpenStruct.new(:name => "Fat Wreck", :city => "San Francisco", :employees => [OpenStruct.new(:name => "Mike")], :location => OpenStruct.new(:city => "Sanfran")) }
81
+ let (:band) { OpenStruct.new(:genre => "Punkrock", :label => label) }
82
+
83
+
84
+ # it { FlatlinersDecorator.new( OpenStruct.new(label: OpenStruct.new) ).
85
+ # to_hash.must_equal({}) }
86
+ it do
87
+ Decorator.new(band).to_hash.must_equal({"genre"=>"Punkrock", "label"=>{"name"=>"Fat Wreck", "location"=>{"city"=>"Sanfran"}}})
88
+ end
89
+
90
+
91
+ class InheritDecorator < Representable::Decorator
92
+ include Representable::Hash
93
+
94
+ include Module
95
+
96
+ property :label, inherit: true do # decorator.rb:27:in `initialize': superclass must be a Class (Module given)
97
+ property :city
98
+
99
+ property :location, :inherit => true do
100
+ property :city
101
+ end
102
+ end
103
+ end
104
+
105
+ it do
106
+ InheritDecorator.new(band).to_hash.must_equal({"genre"=>"Punkrock", "label"=>{"name"=>"Fat Wreck", "city"=>"San Francisco", "location"=>{"city"=>"Sanfran"}}})
107
+ end
108
+
109
+
110
+
111
+ class InheritFromDecorator < InheritDecorator
112
+ property :label, inherit: true do
113
+ collection :employees do
114
+ property :name
115
+ end
116
+ end
117
+ end
118
+
119
+ require "pp"
120
+ pp InheritFromDecorator.representable_attrs.get(:label)[:extend].(nil).representable_attrs
121
+
122
+ it do
123
+ InheritFromDecorator.new(band).to_hash.must_equal({"genre"=>"Punkrock", "label"=>{"name"=>"Fat Wreck", "city"=>"San Francisco", "employees"=>[{"name"=>"Mike"}], "location"=>{"city"=>"Sanfran"}}})
124
+ end
125
+ end
126
+
127
+
128
+ class ApplyTest < MiniTest::Spec
129
+ class AlbumDecorator < Representable::Decorator
130
+ include Representable::Hash
131
+
132
+ property :title
133
+
134
+ property :hit do
135
+ property :title
136
+ end
137
+
138
+ collection :songs do
139
+ property :title
140
+ end
141
+
142
+ property :band do # yepp, people do crazy stuff like that.
143
+ property :label do
144
+ property :name
145
+ end
146
+ end
147
+ end
148
+ end
@@ -0,0 +1,33 @@
1
+ require 'test_helper'
2
+
3
+ class SerializeDeserializeTest < BaseTest
4
+ subject { Struct.new(:song).new.extend(representer) }
5
+
6
+ describe "deserialize" do
7
+ representer! do
8
+ property :song,
9
+ :instance => lambda { |fragment, *| fragment.to_s.upcase },
10
+ :prepare => lambda { |fragment, *| fragment },
11
+ :deserialize => lambda { |object, fragment, args|
12
+ "#{object} #{fragment} #{args.inspect}"
13
+ }
14
+ end
15
+
16
+ it { subject.from_hash({"song" => Object}, {:volume => 9}).song.must_equal "OBJECT Object {:volume=>9}" }
17
+ end
18
+
19
+ describe "serialize" do
20
+ representer! do
21
+ property :song,
22
+ :representable => true,
23
+ :prepare => lambda { |fragment, *| fragment },
24
+ :serialize => lambda { |object, args|
25
+ "#{object} #{args.inspect}"
26
+ }
27
+ end
28
+
29
+ before { subject.song = "Arrested In Shanghai" }
30
+
31
+ it { subject.to_hash({:volume => 9}).must_equal({"song"=>"Arrested In Shanghai {:volume=>9}"}) }
32
+ end
33
+ end
@@ -0,0 +1,81 @@
1
+ require 'test_helper'
2
+
3
+ class SkipParseTest < MiniTest::Spec
4
+ representer! do
5
+ property :title, skip_parse: lambda { |fragment, opts| opts[:skip?] and fragment == "skip me" }
6
+ property :band,
7
+ skip_parse: lambda { |fragment, opts| opts[:skip?] and fragment["name"].nil? }, class: OpenStruct do
8
+ property :name
9
+ end
10
+
11
+ collection :airplays,
12
+ skip_parse: lambda { |fragment, opts| opts[:skip?] and fragment["station"].nil? }, class: OpenStruct do
13
+ property :station
14
+ end
15
+ end
16
+
17
+ let (:song) { OpenStruct.new.extend(representer) }
18
+
19
+ # do parse.
20
+ it do
21
+ song.from_hash({
22
+ "title" => "Victim Of Fate",
23
+ "band" => {"name" => "Mute 98"},
24
+ "airplays" => [{"station" => "JJJ"}]
25
+ }, skip?: true)
26
+
27
+ song.title.must_equal "Victim Of Fate"
28
+ song.band.name.must_equal "Mute 98"
29
+ song.airplays[0].station.must_equal "JJJ"
30
+ end
31
+
32
+ # skip parsing.
33
+ let (:airplay) { OpenStruct.new(station: "JJJ") }
34
+
35
+ it do
36
+ song.from_hash({
37
+ "title" => "skip me",
38
+ "band" => {},
39
+ "airplays" => [{"station" => "JJJ"}, {}],
40
+ }, skip?: true)
41
+
42
+ song.title.must_equal nil
43
+ song.band.must_equal nil
44
+ song.airplays.must_equal [airplay]
45
+ end
46
+ end
47
+
48
+ class SkipRenderTest < MiniTest::Spec
49
+ representer! do
50
+ property :title
51
+ property :band,
52
+ skip_render: lambda { |object, opts| opts[:skip?] and object.name == "Rancid" } do
53
+ property :name
54
+ end
55
+
56
+ collection :airplays,
57
+ skip_render: lambda { |object, opts| puts object.inspect; opts[:skip?] and object.station == "Radio Dreyeckland" } do
58
+ property :station
59
+ end
60
+ end
61
+
62
+ let (:song) { OpenStruct.new(title: "Black Night", band: OpenStruct.new(name: "Time Again")).extend(representer) }
63
+ let (:skip_song) { OpenStruct.new(title: "Time Bomb", band: OpenStruct.new(name: "Rancid")).extend(representer) }
64
+
65
+ # do render.
66
+ it { song.to_hash(skip?: true).must_equal({"title"=>"Black Night", "band"=>{"name"=>"Time Again"}}) }
67
+ # skip.
68
+ it { skip_song.to_hash(skip?: true).must_equal({"title"=>"Time Bomb"}) }
69
+
70
+ # do render all collection items.
71
+ it do
72
+ song = OpenStruct.new(airplays: [OpenStruct.new(station: "JJJ"), OpenStruct.new(station: "ABC")]).extend(representer)
73
+ song.to_hash(skip?: true).must_equal({"airplays"=>[{"station"=>"JJJ"}, {"station"=>"ABC"}]})
74
+ end
75
+
76
+ # skip middle item.
77
+ 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(skip?: true).must_equal({"airplays"=>[{"station"=>"JJJ"}, {"station"=>"ABC"}]})
80
+ end
81
+ end
@@ -0,0 +1,41 @@
1
+ require 'test_helper'
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
22
+
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
26
+
27
+ describe "with :wrap" do
28
+ representer!(:inject => :song_representer) do
29
+ include Representable::Hash::AllowSymbols
30
+
31
+ self.representation_wrap = :album
32
+ property :song, :extend => song_representer, :class => OpenStruct
33
+ end
34
+
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
40
+
41
+ end
@@ -0,0 +1,135 @@
1
+ require 'representable'
2
+
3
+ require "json"
4
+ require "psych"
5
+
6
+ require 'representable/json'
7
+ require 'representable/xml'
8
+ require 'representable/yaml'
9
+ require 'minitest/autorun'
10
+ require 'test_xml/mini_test'
11
+
12
+ require "representable/debug"
13
+
14
+ class Album
15
+ attr_accessor :songs, :best_song
16
+ def initialize(songs=nil, best_song=nil)
17
+ @songs = songs
18
+ @best_song = best_song
19
+ end
20
+
21
+ def ==(other)
22
+ songs == other.songs and best_song == other.best_song
23
+ end
24
+ end
25
+
26
+ class Song
27
+ attr_accessor :name, :track # never change this, track rendered with Rails#to_json.
28
+ def initialize(name=nil, track=nil)
29
+ @name = name
30
+ @track = track
31
+ end
32
+
33
+ def ==(other)
34
+ name == other.name and track == other.track
35
+ end
36
+ end
37
+
38
+ module XmlHelper
39
+ def xml(document)
40
+ Nokogiri::XML(document).root
41
+ end
42
+ end
43
+
44
+ module AssertJson
45
+ module Assertions
46
+ def assert_json(expected, actual, msg=nil)
47
+ msg = message(msg, "") { diff expected, actual }
48
+ assert(expected.split("").sort == actual.split("").sort, msg)
49
+ end
50
+ end
51
+ end
52
+
53
+ MiniTest::Spec.class_eval do
54
+ include AssertJson::Assertions
55
+ include XmlHelper
56
+
57
+ def self.for_formats(formats)
58
+ formats.each do |format, cfg|
59
+ mod, output, input = cfg
60
+ yield format, mod, output, input
61
+ end
62
+ end
63
+
64
+ def render(object, *args)
65
+ AssertableDocument.new(object.send("to_#{format}", *args), format)
66
+ end
67
+
68
+ def parse(object, input, *args)
69
+ object.send("from_#{format}", input, *args)
70
+ end
71
+
72
+ class AssertableDocument
73
+ attr_reader :document
74
+
75
+ def initialize(document, format)
76
+ @document, @format = document, format
77
+ end
78
+
79
+ def must_equal_document(*args)
80
+ return document.must_equal_xml(*args) if @format == :xml
81
+ document.must_equal(*args)
82
+ end
83
+ end
84
+
85
+ def self.representer!(options={}, &block)
86
+ fmt = options # we need that so the 2nd call to ::let (within a ::describe) remembers the right format.
87
+
88
+ name = options[:name] || :representer
89
+ format = options[:module] || Representable::Hash
90
+
91
+ let(name) do
92
+ mod = options[:decorator] ? Class.new(Representable::Decorator) : Module.new
93
+
94
+ inject_representer(mod, fmt)
95
+
96
+ mod.module_eval do
97
+ include format
98
+ instance_exec(&block)
99
+ end
100
+
101
+ mod
102
+ end
103
+
104
+ def inject_representer(mod, options)
105
+ return unless options[:inject]
106
+
107
+ injected_name = options[:inject]
108
+ injected = send(injected_name) # song_representer
109
+ mod.singleton_class.instance_eval do
110
+ define_method(injected_name) { injected }
111
+ end
112
+ end
113
+ end
114
+
115
+ module TestMethods
116
+ def representer_for(modules=[Representable::Hash], &block)
117
+ Module.new do
118
+ extend TestMethods
119
+ include *modules
120
+ module_exec(&block)
121
+ end
122
+ end
123
+
124
+ alias_method :representer!, :representer_for
125
+ end
126
+ include TestMethods
127
+ end
128
+
129
+ class BaseTest < MiniTest::Spec
130
+ let (:new_album) { OpenStruct.new.extend(representer) }
131
+ let (:album) { OpenStruct.new(:songs => ["Fuck Armageddon"]).extend(representer) }
132
+ let (:song) { OpenStruct.new(:title => "Resist Stance") }
133
+ let (:song_representer) { Module.new do include Representable::Hash; property :title end }
134
+
135
+ end
@@ -0,0 +1,25 @@
1
+ require 'test_helper'
2
+
3
+ class TestHelperTest < MiniTest::Spec
4
+ describe "#assert_json" do
5
+ it "tests for equality" do
6
+ assert_json "{\"songs\":{\"one\":\"65\",\"two\":\"Emo Boy\"}}", "{\"songs\":{\"one\":\"65\",\"two\":\"Emo Boy\"}}"
7
+ end
8
+
9
+ it "allows different key orders" do
10
+ assert_json "{\"songs\":{\"one\":\"65\",\"two\":\"Emo Boy\"}}", "{\"songs\":{\"two\":\"Emo Boy\",\"one\":\"65\"}}"
11
+ end
12
+
13
+ it "complains when expected hash is subset" do
14
+ assert_raises MiniTest::Assertion do
15
+ assert_json "{\"songs\":{\"one\":\"65\"}}", "{\"songs\":{\"two\":\"Emo Boy\",\"one\":\"65\"}}"
16
+ end
17
+ end
18
+
19
+ it "complains when source hash is subset" do
20
+ assert_raises MiniTest::Assertion do
21
+ assert_json "{\"songs\":{\"two\":\"Emo Boy\",\"one\":\"65\"}}", "{\"songs\":{\"one\":\"65\"}}"
22
+ end
23
+ end
24
+ end
25
+ end