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.
- data/.gitignore +1 -0
- data/Gemfile +8 -0
- data/README.textile +297 -0
- data/Rakefile +16 -0
- data/lib/roar/client/entity_proxy.rb +58 -0
- data/lib/roar/client/proxy.rb +14 -0
- data/lib/roar/client/transport.rb +29 -0
- data/lib/roar/model.rb +36 -0
- data/lib/roar/model/representable.rb +31 -0
- data/lib/roar/rails.rb +21 -0
- data/lib/roar/rails/controller_methods.rb +71 -0
- data/lib/roar/rails/representer_methods.rb +52 -0
- data/lib/roar/rails/test_case.rb +43 -0
- data/lib/roar/representer.rb +72 -0
- data/lib/roar/representer/feature/http_verbs.rb +63 -0
- data/lib/roar/representer/feature/hypermedia.rb +43 -0
- data/lib/roar/representer/feature/model_representing.rb +88 -0
- data/lib/roar/representer/json.rb +32 -0
- data/lib/roar/representer/xml.rb +43 -0
- data/lib/roar/version.rb +1 -1
- data/roar.gemspec +10 -1
- data/test/Gemfile +6 -0
- data/test/dummy/Rakefile +7 -0
- data/test/dummy/app/controllers/albums_controller.rb +27 -0
- data/test/dummy/app/controllers/application_controller.rb +4 -0
- data/test/dummy/app/helpers/application_helper.rb +2 -0
- data/test/dummy/app/models/album.rb +6 -0
- data/test/dummy/app/models/song.rb +2 -0
- data/test/dummy/app/representers/representer/xml/album.rb +19 -0
- data/test/dummy/app/representers/representer/xml/song.rb +9 -0
- data/test/dummy/app/views/layouts/application.html.erb +14 -0
- data/test/dummy/app/views/musician/featured.html.erb +1 -0
- data/test/dummy/app/views/musician/featured_with_block.html.erb +4 -0
- data/test/dummy/app/views/musician/hamlet.html.haml +1 -0
- data/test/dummy/config.ru +4 -0
- data/test/dummy/config/application.rb +20 -0
- data/test/dummy/config/boot.rb +10 -0
- data/test/dummy/config/database.yml +22 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +16 -0
- data/test/dummy/config/environments/production.rb +46 -0
- data/test/dummy/config/environments/test.rb +32 -0
- data/test/dummy/config/locales/en.yml +5 -0
- data/test/dummy/config/routes.rb +7 -0
- data/test/dummy/db/development.sqlite3 +0 -0
- data/test/dummy/db/migrate/20110514114753_create_albums.rb +14 -0
- data/test/dummy/db/migrate/20110514121228_create_songs.rb +14 -0
- data/test/dummy/db/schema.rb +29 -0
- data/test/dummy/db/test.sqlite3 +0 -0
- data/test/dummy/module - (2011-05-14 15:26:19) +5 -0
- data/test/dummy/public/404.html +26 -0
- data/test/dummy/public/422.html +26 -0
- data/test/dummy/public/500.html +26 -0
- data/test/dummy/public/favicon.ico +0 -0
- data/test/dummy/script/rails +6 -0
- data/test/dummy/tmp/app/cells/blog/post/latest.html.erb +7 -0
- data/test/dummy/tmp/app/cells/blog/post_cell.rb +7 -0
- data/test/fake_server.rb +80 -0
- data/test/http_verbs_test.rb +46 -0
- data/test/hypermedia_test.rb +35 -0
- data/test/integration_test.rb +122 -0
- data/test/json_representer_test.rb +101 -0
- data/test/model_representing_test.rb +121 -0
- data/test/model_test.rb +50 -0
- data/test/order_representers.rb +34 -0
- data/test/proxy_test.rb +89 -0
- data/test/rails/controller_methods_test.rb +147 -0
- data/test/rails/rails_representer_methods_test.rb +32 -0
- data/test/representable_test.rb +49 -0
- data/test/representer_test.rb +25 -0
- data/test/ruby_representation_test.rb +144 -0
- data/test/test_helper.rb +45 -0
- data/test/test_helper_test.rb +59 -0
- data/test/transport_test.rb +34 -0
- data/test/xml_hypermedia_test.rb +47 -0
- data/test/xml_representer_test.rb +238 -0
- 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
|
data/test/test_helper.rb
ADDED
@@ -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
|