roar 0.0.1.alpha1 → 0.8.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 (77) hide show
  1. data/.gitignore +1 -0
  2. data/Gemfile +8 -0
  3. data/README.textile +297 -0
  4. data/Rakefile +16 -0
  5. data/lib/roar/client/entity_proxy.rb +58 -0
  6. data/lib/roar/client/proxy.rb +14 -0
  7. data/lib/roar/client/transport.rb +29 -0
  8. data/lib/roar/model.rb +36 -0
  9. data/lib/roar/model/representable.rb +31 -0
  10. data/lib/roar/rails.rb +21 -0
  11. data/lib/roar/rails/controller_methods.rb +71 -0
  12. data/lib/roar/rails/representer_methods.rb +52 -0
  13. data/lib/roar/rails/test_case.rb +43 -0
  14. data/lib/roar/representer.rb +72 -0
  15. data/lib/roar/representer/feature/http_verbs.rb +63 -0
  16. data/lib/roar/representer/feature/hypermedia.rb +43 -0
  17. data/lib/roar/representer/feature/model_representing.rb +88 -0
  18. data/lib/roar/representer/json.rb +32 -0
  19. data/lib/roar/representer/xml.rb +43 -0
  20. data/lib/roar/version.rb +1 -1
  21. data/roar.gemspec +10 -1
  22. data/test/Gemfile +6 -0
  23. data/test/dummy/Rakefile +7 -0
  24. data/test/dummy/app/controllers/albums_controller.rb +27 -0
  25. data/test/dummy/app/controllers/application_controller.rb +4 -0
  26. data/test/dummy/app/helpers/application_helper.rb +2 -0
  27. data/test/dummy/app/models/album.rb +6 -0
  28. data/test/dummy/app/models/song.rb +2 -0
  29. data/test/dummy/app/representers/representer/xml/album.rb +19 -0
  30. data/test/dummy/app/representers/representer/xml/song.rb +9 -0
  31. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  32. data/test/dummy/app/views/musician/featured.html.erb +1 -0
  33. data/test/dummy/app/views/musician/featured_with_block.html.erb +4 -0
  34. data/test/dummy/app/views/musician/hamlet.html.haml +1 -0
  35. data/test/dummy/config.ru +4 -0
  36. data/test/dummy/config/application.rb +20 -0
  37. data/test/dummy/config/boot.rb +10 -0
  38. data/test/dummy/config/database.yml +22 -0
  39. data/test/dummy/config/environment.rb +5 -0
  40. data/test/dummy/config/environments/development.rb +16 -0
  41. data/test/dummy/config/environments/production.rb +46 -0
  42. data/test/dummy/config/environments/test.rb +32 -0
  43. data/test/dummy/config/locales/en.yml +5 -0
  44. data/test/dummy/config/routes.rb +7 -0
  45. data/test/dummy/db/development.sqlite3 +0 -0
  46. data/test/dummy/db/migrate/20110514114753_create_albums.rb +14 -0
  47. data/test/dummy/db/migrate/20110514121228_create_songs.rb +14 -0
  48. data/test/dummy/db/schema.rb +29 -0
  49. data/test/dummy/db/test.sqlite3 +0 -0
  50. data/test/dummy/module - (2011-05-14 15:26:19) +5 -0
  51. data/test/dummy/public/404.html +26 -0
  52. data/test/dummy/public/422.html +26 -0
  53. data/test/dummy/public/500.html +26 -0
  54. data/test/dummy/public/favicon.ico +0 -0
  55. data/test/dummy/script/rails +6 -0
  56. data/test/dummy/tmp/app/cells/blog/post/latest.html.erb +7 -0
  57. data/test/dummy/tmp/app/cells/blog/post_cell.rb +7 -0
  58. data/test/fake_server.rb +80 -0
  59. data/test/http_verbs_test.rb +46 -0
  60. data/test/hypermedia_test.rb +35 -0
  61. data/test/integration_test.rb +122 -0
  62. data/test/json_representer_test.rb +101 -0
  63. data/test/model_representing_test.rb +121 -0
  64. data/test/model_test.rb +50 -0
  65. data/test/order_representers.rb +34 -0
  66. data/test/proxy_test.rb +89 -0
  67. data/test/rails/controller_methods_test.rb +147 -0
  68. data/test/rails/rails_representer_methods_test.rb +32 -0
  69. data/test/representable_test.rb +49 -0
  70. data/test/representer_test.rb +25 -0
  71. data/test/ruby_representation_test.rb +144 -0
  72. data/test/test_helper.rb +45 -0
  73. data/test/test_helper_test.rb +59 -0
  74. data/test/transport_test.rb +34 -0
  75. data/test/xml_hypermedia_test.rb +47 -0
  76. data/test/xml_representer_test.rb +238 -0
  77. metadata +181 -13
@@ -0,0 +1,49 @@
1
+ require 'test_helper'
2
+ require 'roar/model/representable'
3
+
4
+ class RepresentableTest < MiniTest::Spec
5
+
6
+ class ThisAsAppXml < Roar::Representer::Base
7
+ def self.deserialize(represented_class, mime_type, data)
8
+ "#{represented_class.name}->#{mime_type}: #{data}"
9
+ end
10
+
11
+ def serialize(represented, mime_type)
12
+ "#{represented.class.name}->#{mime_type}"
13
+ end
14
+ end
15
+
16
+ describe "Representable" do
17
+ before do
18
+ @c = Class.new do
19
+ include Roar::Model::Representable
20
+
21
+ represents "application/xml", :with => ThisAsAppXml
22
+ end
23
+ end
24
+
25
+
26
+ describe ".representer_class_for" do
27
+ it "returns the class" do
28
+ assert_equal ThisAsAppXml, @c.representer_class_for("application/xml")
29
+ end
30
+
31
+ it "returns nil if unknown" do
32
+ assert_equal nil, @c.representer_class_for("text/html")
33
+ end
34
+ end
35
+
36
+
37
+ describe ".from" do
38
+ it "receives mime_type and content" do
39
+ assert_equal "->application/xml: <xml/>", @c.from("application/xml", "<xml/>")
40
+ end
41
+ end
42
+
43
+ describe "#to" do
44
+ it "receives mime_type" do
45
+ assert_equal "->application/xml", @c.new.to("application/xml")
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,25 @@
1
+ require 'test_helper'
2
+
3
+ class RepresenterTest < MiniTest::Spec
4
+ describe "Representer" do
5
+ before do
6
+ @c = Class.new(Roar::Representer::Base)
7
+ end
8
+
9
+ it "aliases #representable_property to #property" do
10
+ @c.property :title
11
+ assert_equal "title", @c.representable_attrs.first.name
12
+ end
13
+
14
+ it "aliases #representable_collection to #collection" do
15
+ @c.collection :songs
16
+ assert_equal "songs", @c.representable_attrs.first.name
17
+ end
18
+
19
+ it "accepts property hash in #new" do
20
+ @c.property :title
21
+ assert_equal "Counting Down", @c.new(:title => "Counting Down").title
22
+ end
23
+
24
+ end
25
+ end
@@ -0,0 +1,144 @@
1
+ require 'test_helper'
2
+
3
+ module Roar
4
+ module Representer
5
+ class Ruby < Base
6
+ def serialize(attributes)
7
+ serializable_attributes = attributes.dup
8
+
9
+ serialize_typed_attributes(serializable_attributes)
10
+ Marshal.dump serializable_attributes
11
+ end
12
+
13
+ def deserialize(body)
14
+ deserialized_hash = Marshal.load body
15
+ deserialize_typed_attributes(deserialized_hash)
16
+ end
17
+
18
+
19
+
20
+ module ConfigurationDsl # FIXME: move to Representer::BaseDsl or so.
21
+ def has_many(name, options={})
22
+ collections[name] = options
23
+ end
24
+ alias_method :collection, :has_many
25
+
26
+ def has_one(name, options={})
27
+ typed_entities[name] = options
28
+ end
29
+
30
+ def has_proxied(name, options={})
31
+ has_one(name, {:class => EntityProxy.class_for(options)})
32
+ end
33
+
34
+ def has_many_proxied(name, options={})
35
+ has_many(name, {:class => EntityProxy.class_for(options)})
36
+ end
37
+ end
38
+
39
+ self.extend ConfigurationDsl
40
+ # FIXME: use one variable?
41
+ extend Hooks::InheritableAttribute
42
+ inheritable_attr :collections
43
+ self.collections = {}
44
+ inheritable_attr :typed_entities
45
+ self.typed_entities = {}
46
+
47
+
48
+
49
+ def serialize_typed_attributes(attributes)
50
+ filter_attributes_for(attributes, self.class.typed_entities) do |name, options|
51
+ next unless entity = attributes[name]
52
+ attributes[name] = entity.to(mime_type)
53
+ end
54
+ end
55
+
56
+ # Attributes can be typecasted with +has_one+.
57
+ def deserialize_typed_attributes(attributes)
58
+ filter_attributes_for(attributes, self.class.typed_entities) do |name, options|
59
+ item = attributes.delete(name) # attributes[:sum]
60
+ item = options[:class].from(mime_type, item) # Sum.from_xml_attributes
61
+ attributes[name] = item
62
+ end
63
+ end
64
+
65
+ def filter_attributes_for(attributes, config)
66
+ config.each do |name, options|
67
+ name = name.to_s
68
+ yield name, options
69
+ end
70
+ attributes
71
+ end
72
+
73
+ end
74
+
75
+
76
+ end
77
+
78
+ end
79
+
80
+
81
+ class RubyRepresenterFunctionalTest < MiniTest::Spec
82
+ class Item
83
+ attr_reader :value
84
+
85
+ def initialize(value)
86
+ @value = value
87
+ end
88
+
89
+ def to(mime_type)
90
+ raise unless mime_type == "ruby/serialized"
91
+ Marshal.dump(@value)
92
+ end
93
+
94
+ def self.from(mime_type, string)
95
+ raise unless mime_type == "ruby/serialized"
96
+ new Marshal.load(string)
97
+ end
98
+
99
+ def ==(b)
100
+ value == b.value
101
+ end
102
+ end
103
+
104
+ describe "RubyRepresenter" do
105
+ before do
106
+ @r = Class.new(Roar::Representer::Ruby).new("ruby/serialized")
107
+ @m = {:id => 1}
108
+ end
109
+
110
+ describe "without options" do
111
+ it "#serialize returns the serialized model" do
112
+ assert_equal "\x04\b{\x06:\aidi\x06", @r.serialize(@m)
113
+ end
114
+
115
+ it "#deserialize returns the attributes" do
116
+ assert_equal @m, @r.deserialize("\x04\b{\x06:\aidi\x06")
117
+ end
118
+ end
119
+
120
+
121
+ describe "has_one" do
122
+ before do
123
+ @r.class.instance_eval do
124
+ has_one :item, :class => Item
125
+ end
126
+ end
127
+
128
+ it "#serialize skips empty :item" do
129
+ assert_equal "\x04\b{\x06:\aidi\x06", @r.serialize(@m)
130
+ end
131
+
132
+ it "#serialize delegates to item#to" do
133
+ @m = {:id => 1, "item" => Item.new("beer")}
134
+ assert_equal "\x04\b{\a:\aidi\x06I\"\titem\x06:\x06EF\"\x13\x04\bI\"\tbeer\x06:\x06EF", @r.serialize(@m)
135
+ end
136
+
137
+ it "#deserialize typecasts :item" do
138
+ m = @r.deserialize("\x04\b{\a:\aidi\x06I\"\titem\x06:\x06EF\"\x13\x04\bI\"\tbeer\x06:\x06EF")
139
+ assert_equal({:id => 1, "item" => Item.new("beer")}, m)
140
+ end
141
+
142
+ end
143
+ end
144
+ end
@@ -0,0 +1,45 @@
1
+ require 'bundler'
2
+ Bundler.setup
3
+
4
+ require 'test/unit'
5
+ require 'minitest/spec'
6
+
7
+ require 'active_model'
8
+ #require 'roar/client/entity_proxy'
9
+ require 'roar/representer'
10
+ require 'roar/model'
11
+ require 'roar/representer/feature/http_verbs'
12
+
13
+ require 'stringio' # FIXME. remove for 3.0.4.
14
+ require 'builder'
15
+
16
+
17
+ class Item
18
+ include Roar::Model
19
+ accessors :value
20
+
21
+ def self.model_name
22
+ "item"
23
+ end
24
+ end
25
+
26
+ class Position
27
+ include Roar::Model
28
+ accessors :id, :item
29
+
30
+ def self.model_name
31
+ :order
32
+ end
33
+ end
34
+
35
+ class Order
36
+ include Roar::Model
37
+ accessors :id, :items
38
+
39
+ def self.model_name
40
+ :order
41
+ end
42
+ end
43
+
44
+ require "test_xml/mini_test"
45
+ require "roar/representer/xml"
@@ -0,0 +1,59 @@
1
+ require 'test_helper'
2
+ require 'roar/model'
3
+
4
+ class AssertModelTest < MiniTest::Spec
5
+ class Song
6
+ include Roar::Model
7
+ accessors :title
8
+ end
9
+
10
+ class Album
11
+ include Roar::Model
12
+ accessors :songs
13
+ end
14
+
15
+ class Play
16
+ include Roar::Model
17
+ accessors :song
18
+ end
19
+
20
+
21
+ describe "#assert_model" do
22
+ before do
23
+ @jerk = Song.new(:title => "Jerk")
24
+ @sellout = Song.new(:title => "Sellout")
25
+ @saleout = Song.new(:title => "Sellout")
26
+ end
27
+
28
+ it "compares to plain models" do
29
+ assert_model @jerk, @jerk
30
+ assert_model @sellout, @saleout
31
+
32
+ assert_raises MiniTest::Assertion do
33
+ assert_model @jerk, @sellout
34
+ end
35
+ end
36
+
37
+ it "compares nested models" do
38
+ @play = Play.new(:song => @sellout)
39
+ @play_2 = Play.new(:song => @saleout)
40
+ assert_model @play, @play_2
41
+
42
+ assert_raises MiniTest::Assertion do
43
+ assert_model @play, Play.new(:song => @jerk)
44
+ end
45
+ end
46
+
47
+ it "compares nested models in collections" do
48
+ @stay_asleep = Album.new(:songs => [@jerk, @sellout])
49
+ @stay_asleep_ripped = Album.new(:songs => [@jerk, @saleout])
50
+ assert_model @stay_asleep, @stay_asleep_ripped
51
+
52
+ assert_raises MiniTest::Assertion do
53
+ assert_model assert_model @stay_asleep, Album.new(:songs => [@jerk])
54
+ end
55
+ end
56
+
57
+
58
+ end
59
+ end
@@ -0,0 +1,34 @@
1
+ require 'test_helper'
2
+ require 'roar/client/transport'
3
+
4
+ class TransportTest < MiniTest::Spec
5
+ describe "Transport" do
6
+ before do
7
+ @klass = Class.new(Object) do
8
+ include Roar::Client::Transport
9
+ end
10
+ @o = @klass.new
11
+ end
12
+
13
+ it "#get_uri returns Restfulie response" do
14
+ assert_equal "<method>get</method>", @o.get_uri("http://localhost:9999/method", "application/xml").body
15
+ end
16
+
17
+ it "#post_uri returns Restfulie response" do
18
+ assert_equal "<method>post</method>", @o.post_uri("http://localhost:9999/method", "booty", "application/xml").body
19
+ end
20
+
21
+ it "#put_uri returns Restfulie response" do
22
+ assert_equal "<method>put</method>", @o.put_uri("http://localhost:9999/method", "booty", "application/xml").body
23
+ end
24
+
25
+ it "#delete_uri returns Restfulie response" do
26
+ assert_equal "<method>delete</method>", @o.delete_uri("http://localhost:9999/method", "application/xml").body
27
+ end
28
+
29
+ # TODO: how to get PATCH into Sinatra?
30
+ #it "#patch_uri returns Restfulie response" do
31
+ # assert_equal "<method>patch</method>", @o.patch_uri("http://localhost:9999/method", "booty", "application/xml").body
32
+ #end
33
+ end
34
+ end
@@ -0,0 +1,47 @@
1
+ require 'test_helper'
2
+
3
+ class XmlHypermediaTest < MiniTest::Spec
4
+ describe "Hypermedia API" do
5
+ before do
6
+ @c = Class.new(Roar::Representer::XML) do
7
+ self.representation_name= :wuff
8
+ representable_property :id
9
+ link :self do "http://self" end
10
+ link :next do "http://next/#{id}" end
11
+ end
12
+ @r = @c.new
13
+ end
14
+
15
+ it "responds to #links" do
16
+ assert_equal nil, @r.links
17
+ end
18
+
19
+ it "computes links in #from_attributes" do
20
+ @r = @c.from_attributes({"id" => 1})
21
+ assert_equal 2, @r.links.size
22
+ assert_equal({"rel"=>:self, "href"=>"http://self"}, @r.links.first.to_attributes)
23
+ assert_equal({"rel"=>:next, "href"=>"http://next/1"}, @r.links.last.to_attributes)
24
+ end
25
+
26
+ it "extracts links from XML" do
27
+ @r = @c.deserialize(%{
28
+ <order>
29
+ <link rel="self" href="http://self">
30
+ </order>
31
+ })
32
+
33
+ assert_kind_of Roar::Representer::Feature::Hypermedia::LinkCollection, @r.links
34
+ assert_equal 1, @r.links.size
35
+ assert_equal({"rel"=>"self", "href"=>"http://self"}, @r.links.first.to_attributes)
36
+ end
37
+
38
+ it "renders <link> correctly in XML" do
39
+ assert_xml_equal %{<wuff>
40
+ <id>1</id>
41
+ <link rel="self" href="http://self"/>
42
+ <link rel="next" href="http://next/1"/>
43
+ </wuff><expected />}, @c.from_attributes({"id" => 1}).serialize
44
+ end
45
+
46
+ end
47
+ end
@@ -0,0 +1,238 @@
1
+ require 'test_helper'
2
+
3
+ class Order
4
+ include Roar::Model
5
+ accessors :id, :item
6
+
7
+ def self.model_name
8
+ :order
9
+ end
10
+ end
11
+
12
+
13
+ class ItemRepresenter < Roar::Representer::XML
14
+ self.representation_name= :item
15
+ representable_property :value
16
+ end
17
+
18
+ class PositionRepresenter < Roar::Representer::XML
19
+ self.representation_name= :position
20
+ representable_property :id
21
+ representable_property :item, :as => ItemRepresenter
22
+ end
23
+
24
+
25
+
26
+
27
+ class XMLRepresenterUnitTest < MiniTest::Spec
28
+ describe "XmlRepresenter" do
29
+ describe "#link" do
30
+ class Rapper < Roar::Representer::XML
31
+ link :self
32
+ link :next
33
+ end
34
+
35
+ it "creates a LinksDefinition" do
36
+ assert_equal 1, Rapper.representable_attrs.size
37
+ assert_equal [{:rel=>:self, :block=>nil}, {:rel=>:next, :block=>nil}], Rapper.representable_attrs.first.rel2block
38
+ end
39
+ end
40
+
41
+ describe "#from_attributes" do
42
+ it "accepts a block" do
43
+ @c = Class.new(Roar::Representer::XML) do
44
+ attr_accessor :name
45
+ end
46
+
47
+ assert_equal("Conan", @c.from_attributes({}) { |rep| rep.name = "Conan" }.name)
48
+ end
49
+ end
50
+ end
51
+ end
52
+
53
+ class LinksDefinitionTest < MiniTest::Spec
54
+ describe "LinksDefinition" do
55
+ before do
56
+ @d = Roar::Representer::LinksDefinition.new(:links)
57
+ end
58
+
59
+ it "accepts options in constructor" do
60
+ assert_equal [], @d.rel2block
61
+ end
62
+
63
+ it "accepts configuration" do
64
+ @d.rel2block << {:rel => :self}
65
+ assert_equal [{:rel=>:self}], @d.rel2block
66
+ end
67
+ end
68
+ end
69
+
70
+ class XMLDefinitionTest < MiniTest::Spec
71
+ class Rapper
72
+ attr_accessor :name
73
+ end
74
+
75
+ describe "ROXML::Definition" do
76
+ it "responds to #populate" do
77
+ @r = Rapper.new
78
+ Representable::Definition.new(:name).populate(@r, "name" => "Eugen")
79
+ assert_equal "Eugen", @r.name
80
+ end
81
+ end
82
+ end
83
+
84
+
85
+
86
+
87
+
88
+ class XMLRepresenterFunctionalTest < MiniTest::Spec
89
+ class GreedyOrder
90
+ include Roar::Model
91
+ accessors :id, :items
92
+
93
+ def self.model_name
94
+ :order
95
+ end
96
+ end
97
+
98
+ class TestXmlRepresenter < Roar::Representer::XML
99
+ self.representation_name= :order # FIXME: get from represented?
100
+ representable_property :id
101
+ end
102
+
103
+
104
+ describe "XMLRepresenter" do
105
+ before do
106
+ @m = {"id" => "1"}
107
+ @o = Order.new(@m)
108
+ @r = TestXmlRepresenter.new
109
+ @i = ItemRepresenter.new
110
+ @i.value = "Beer"
111
+ end
112
+
113
+ describe "#from_attributes" do
114
+ it "copies represented attributes, only" do
115
+ @r = PositionRepresenter.from_attributes("id" => 1, "item" => @i, "unknown" => 1)
116
+ assert_kind_of PositionRepresenter, @r
117
+ assert_equal 1, @r.id
118
+
119
+ assert_kind_of ItemRepresenter, @r.item
120
+ assert_equal @r.item.value, "Beer"
121
+ end
122
+ end
123
+
124
+
125
+ describe "#to_attributes" do
126
+ it "returns a nested attributes hash" do
127
+ @r = PositionRepresenter.from_attributes("id" => 1, "item" => @i)
128
+ assert_equal({"id" => 1, "item" => {"value" => "Beer"}}, @r.to_attributes)
129
+ end
130
+ end
131
+
132
+
133
+ describe "#to_xml" do
134
+ it "serializes the current model" do
135
+ assert_xml_equal "<order/>", @r.to_xml.serialize
136
+
137
+ @r.id = 2
138
+ assert_xml_equal "<rap><id>2</id></rap>", @r.to_xml(:name => :rap).serialize
139
+ end
140
+ end
141
+
142
+
143
+ describe "without options" do
144
+ it "#serialize returns the serialized model" do
145
+ @r.id = 1
146
+ assert_xml_equal "<order><id>1</id></order>", @r.serialize
147
+ end
148
+
149
+
150
+ it ".from_xml returns the deserialized model" do
151
+ @m = TestXmlRepresenter.deserialize("<order><id>1</id></order>")
152
+ assert_equal "1", @m.id
153
+ end
154
+
155
+ it ".from_xml still works with nil" do
156
+ assert TestXmlRepresenter.deserialize(nil)
157
+ end
158
+
159
+ end
160
+
161
+
162
+ describe "with a typed attribute" do
163
+ before do
164
+ @r = PositionRepresenter.from_attributes("id" => "1")
165
+ end
166
+
167
+ it "#serialize skips empty :item" do
168
+ assert_xml_equal "<position><id>1</id></position>", @r.serialize
169
+ end
170
+
171
+ it "#to_xml delegates to ItemRepresenter#to_xml" do
172
+ @r.item = @i
173
+ assert_xml_equal "<position><id>1</id><item><value>Beer</value></item></position>", @r.serialize
174
+ end
175
+
176
+ it ".from_xml typecasts :item" do
177
+ @m = PositionRepresenter.deserialize("<position><id>1</id><item><value>beer</value></item>\n</position>")
178
+
179
+ assert_equal "1", @m.id
180
+ assert_equal "beer", @m.item.value
181
+ end
182
+ end
183
+
184
+
185
+ describe "with a typed list" do
186
+ before do
187
+ @c = Class.new(Roar::Representer::XML) do
188
+ self.representation_name= :order
189
+ representable_property :id
190
+ representable_collection :items, :as => ItemRepresenter, :tag => :item
191
+ end
192
+
193
+ @r = @c.from_attributes("id" => 1)
194
+ end
195
+
196
+ it "#serialize_model skips empty :item" do
197
+ assert_xml_equal "<order><id>1</id></order>", @r.serialize
198
+ end
199
+
200
+ it "#serialize delegates to ItemXmlRepresenter#to_xml in list" do
201
+ @r.items = [ItemRepresenter.from_attributes("value" => "Bier")]
202
+
203
+ assert_xml_equal "<order><id>1</id><item><value>Bier</value></item></order>",
204
+ @r.serialize
205
+ end
206
+
207
+ it ".from_xml typecasts list" do
208
+ @m = @c.deserialize("<order><id>1</id><item><value>beer</value></item>\n</order>")
209
+
210
+ assert_equal "1", @m.id
211
+ assert_equal 1, @m.items.size
212
+ assert_equal "beer", @m.items.first.value
213
+ end
214
+ end
215
+
216
+ end
217
+ end
218
+
219
+ class XmlHyperlinkRepresenterTest < MiniTest::Spec
220
+ describe "API" do
221
+ before do
222
+ @l = Roar::Representer::XML::Hyperlink.from_xml(%{<link rel="self" href="http://roar.apotomo.de"/>})
223
+ end
224
+
225
+ it "responds to #representation_name" do
226
+ assert_equal :link, @l.class.representation_name
227
+ end
228
+
229
+
230
+ it "responds to #rel" do
231
+ assert_equal "self", @l.rel
232
+ end
233
+
234
+ it "responds to #href" do
235
+ assert_equal "http://roar.apotomo.de", @l.href
236
+ end
237
+ end
238
+ end