roar 0.0.1.alpha1 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- 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,29 @@
|
|
1
|
+
# This file is auto-generated from the current state of the database. Instead
|
2
|
+
# of editing this file, please use the migrations feature of Active Record to
|
3
|
+
# incrementally modify your database, and then regenerate this schema definition.
|
4
|
+
#
|
5
|
+
# Note that this schema.rb definition is the authoritative source for your
|
6
|
+
# database schema. If you need to create the application database on another
|
7
|
+
# system, you should be using db:schema:load, not running all the migrations
|
8
|
+
# from scratch. The latter is a flawed and unsustainable approach (the more migrations
|
9
|
+
# you'll amass, the slower it'll run and the greater likelihood for issues).
|
10
|
+
#
|
11
|
+
# It's strongly recommended to check this file into your version control system.
|
12
|
+
|
13
|
+
ActiveRecord::Schema.define(:version => 20110514121228) do
|
14
|
+
|
15
|
+
create_table "albums", :force => true do |t|
|
16
|
+
t.string "title"
|
17
|
+
t.string "year"
|
18
|
+
t.datetime "created_at"
|
19
|
+
t.datetime "updated_at"
|
20
|
+
end
|
21
|
+
|
22
|
+
create_table "songs", :force => true do |t|
|
23
|
+
t.string "title"
|
24
|
+
t.integer "album_id"
|
25
|
+
t.datetime "created_at"
|
26
|
+
t.datetime "updated_at"
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
File without changes
|
@@ -0,0 +1,26 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>The page you were looking for doesn't exist (404)</title>
|
5
|
+
<style type="text/css">
|
6
|
+
body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
|
7
|
+
div.dialog {
|
8
|
+
width: 25em;
|
9
|
+
padding: 0 4em;
|
10
|
+
margin: 4em auto 0 auto;
|
11
|
+
border: 1px solid #ccc;
|
12
|
+
border-right-color: #999;
|
13
|
+
border-bottom-color: #999;
|
14
|
+
}
|
15
|
+
h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
|
16
|
+
</style>
|
17
|
+
</head>
|
18
|
+
|
19
|
+
<body>
|
20
|
+
<!-- This file lives in public/404.html -->
|
21
|
+
<div class="dialog">
|
22
|
+
<h1>The page you were looking for doesn't exist.</h1>
|
23
|
+
<p>You may have mistyped the address or the page may have moved.</p>
|
24
|
+
</div>
|
25
|
+
</body>
|
26
|
+
</html>
|
@@ -0,0 +1,26 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>The change you wanted was rejected (422)</title>
|
5
|
+
<style type="text/css">
|
6
|
+
body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
|
7
|
+
div.dialog {
|
8
|
+
width: 25em;
|
9
|
+
padding: 0 4em;
|
10
|
+
margin: 4em auto 0 auto;
|
11
|
+
border: 1px solid #ccc;
|
12
|
+
border-right-color: #999;
|
13
|
+
border-bottom-color: #999;
|
14
|
+
}
|
15
|
+
h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
|
16
|
+
</style>
|
17
|
+
</head>
|
18
|
+
|
19
|
+
<body>
|
20
|
+
<!-- This file lives in public/422.html -->
|
21
|
+
<div class="dialog">
|
22
|
+
<h1>The change you wanted was rejected.</h1>
|
23
|
+
<p>Maybe you tried to change something you didn't have access to.</p>
|
24
|
+
</div>
|
25
|
+
</body>
|
26
|
+
</html>
|
@@ -0,0 +1,26 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>We're sorry, but something went wrong (500)</title>
|
5
|
+
<style type="text/css">
|
6
|
+
body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
|
7
|
+
div.dialog {
|
8
|
+
width: 25em;
|
9
|
+
padding: 0 4em;
|
10
|
+
margin: 4em auto 0 auto;
|
11
|
+
border: 1px solid #ccc;
|
12
|
+
border-right-color: #999;
|
13
|
+
border-bottom-color: #999;
|
14
|
+
}
|
15
|
+
h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
|
16
|
+
</style>
|
17
|
+
</head>
|
18
|
+
|
19
|
+
<body>
|
20
|
+
<!-- This file lives in public/500.html -->
|
21
|
+
<div class="dialog">
|
22
|
+
<h1>We're sorry, but something went wrong.</h1>
|
23
|
+
<p>We've been notified about this issue and we'll take a look at it shortly.</p>
|
24
|
+
</div>
|
25
|
+
</body>
|
26
|
+
</html>
|
File without changes
|
@@ -0,0 +1,6 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application.
|
3
|
+
|
4
|
+
APP_PATH = File.expand_path('../../config/application', __FILE__)
|
5
|
+
require File.expand_path('../../config/boot', __FILE__)
|
6
|
+
require 'rails/commands'
|
data/test/fake_server.rb
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
require "bundler/setup"
|
2
|
+
require 'sinatra/base'
|
3
|
+
require 'sinatra/reloader'
|
4
|
+
|
5
|
+
|
6
|
+
class FakeServer < Sinatra::Base
|
7
|
+
get "/method" do
|
8
|
+
"<method>get</method>"
|
9
|
+
end
|
10
|
+
|
11
|
+
post "/method" do
|
12
|
+
"<method>post</method>"
|
13
|
+
end
|
14
|
+
|
15
|
+
put "/method" do
|
16
|
+
"<method>put</method>"
|
17
|
+
end
|
18
|
+
|
19
|
+
delete "/method" do
|
20
|
+
"<method>delete</method>"
|
21
|
+
end
|
22
|
+
|
23
|
+
#patch "/method" do
|
24
|
+
# "<method>patch</method>"
|
25
|
+
#end
|
26
|
+
|
27
|
+
post "/band" do
|
28
|
+
if request.content_type =~ /xml/
|
29
|
+
%{<band><label>n/a</label><name>Strung Out</name>
|
30
|
+
<link href="http://search" rel="search" />
|
31
|
+
<link href="http://band/strungout" rel="self" />
|
32
|
+
</band>}
|
33
|
+
else
|
34
|
+
'{"band": {"label": "n/a", "name": "Strung Out", "links": [{"href":"http://search", "rel": "search"}, {"href":"http://band/strungout", "rel": "self"}]}}'
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
put "/band/strungout" do
|
39
|
+
%{<band><label>Fat Wreck</label><name>Strung Out</name></band>}
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
|
44
|
+
require Dir.pwd + '/order_representers'
|
45
|
+
JSON::Order.class_eval do
|
46
|
+
def items_url
|
47
|
+
"http://localhost:9999/orders/1/items"
|
48
|
+
end
|
49
|
+
def order_url(order)
|
50
|
+
"http://localhost:9999/orders/#{order}"
|
51
|
+
end
|
52
|
+
def represented
|
53
|
+
1
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
|
59
|
+
post "/orders" do
|
60
|
+
incoming = JSON::Order.deserialize(request.body.string)
|
61
|
+
# create new record
|
62
|
+
|
63
|
+
# render new record
|
64
|
+
|
65
|
+
JSON::Order.from_attributes(incoming.to_attributes).serialize
|
66
|
+
end
|
67
|
+
|
68
|
+
post "/orders/1/items" do
|
69
|
+
incoming = JSON::Item.deserialize(request.body.string)
|
70
|
+
|
71
|
+
JSON::Item.from_attributes(incoming.to_attributes).serialize
|
72
|
+
end
|
73
|
+
|
74
|
+
get "/orders/1" do
|
75
|
+
JSON::Order.new(:client_id => 1, :items => [JSON::Item.new(:article_id => "666-S", :amount => 1)]).serialize
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
|
80
|
+
FakeServer.run! :host => 'localhost', :port => 9999
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'roar/representer/feature/http_verbs'
|
3
|
+
|
4
|
+
class HttpVerbsTest < MiniTest::Spec
|
5
|
+
class BandRepresenter < Roar::Representer::XML
|
6
|
+
self.representation_name = :band
|
7
|
+
|
8
|
+
property :name
|
9
|
+
property :label
|
10
|
+
|
11
|
+
include Roar::Representer::Feature::HttpVerbs
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "HttpVerbs" do
|
15
|
+
before do
|
16
|
+
@r = BandRepresenter.new
|
17
|
+
end
|
18
|
+
|
19
|
+
# TODO: assert that Restfulie#post receives the correct document.
|
20
|
+
|
21
|
+
it "#post deserializes the incoming representation and returns it" do
|
22
|
+
@r.name = "Strung Out"
|
23
|
+
rep = @r.post("http://localhost:9999/band", "application/xml")
|
24
|
+
assert_equal "Strung Out", rep.name
|
25
|
+
assert_equal "n/a", rep.label
|
26
|
+
end
|
27
|
+
|
28
|
+
it "#post! deserializes the incoming representation and replaces attributes" do
|
29
|
+
@r.name = "Strung Out"
|
30
|
+
assert_equal nil, @r.label
|
31
|
+
@r.post!("http://localhost:9999/band", "application/xml")
|
32
|
+
assert_equal "Strung Out", @r.name
|
33
|
+
assert_equal "n/a", @r.label
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
|
38
|
+
it "#put deserializes the incoming representation and returns it" do
|
39
|
+
@r.name = "Strung Out"
|
40
|
+
@r.label = "Fat Wreck"
|
41
|
+
rep = @r.put("http://localhost:9999/band/strungout", "application/xml")
|
42
|
+
assert_equal "Strung Out", rep.name
|
43
|
+
assert_equal "Fat Wreck", rep.label
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'roar/representer/feature/hypermedia'
|
3
|
+
|
4
|
+
class HypermediaTest
|
5
|
+
describe "Hypermedia" do
|
6
|
+
class Bookmarks
|
7
|
+
include Roar::Representer::Feature::Hypermedia
|
8
|
+
end
|
9
|
+
|
10
|
+
before do
|
11
|
+
Hyperlink = Roar::Representer::XML::Hyperlink # TODO: move to abstract module.
|
12
|
+
@b = Bookmarks.new
|
13
|
+
@b.links = [Hyperlink.from_attributes({"rel" => "self", "href" => "http://self"}), Hyperlink.from_attributes({"rel" => "next", "href" => "http://next"})]
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "#links" do
|
17
|
+
it "returns links" do
|
18
|
+
assert_kind_of Roar::Representer::Feature::Hypermedia::LinkCollection, @b.links
|
19
|
+
assert_equal 2, @b.links.size
|
20
|
+
end
|
21
|
+
|
22
|
+
it "works with empty links set" do
|
23
|
+
assert_equal nil, Bookmarks.new.links # default empty array doesn't make sense.
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
it "responds to links #[]" do
|
29
|
+
assert_equal "http://self", @b.links["self"]
|
30
|
+
assert_equal "http://self", @b.links[:self]
|
31
|
+
assert_equal "http://next", @b.links[:next]
|
32
|
+
assert_equal nil, @b.links[:prev]
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,122 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
require 'roar/representer/xml'
|
4
|
+
require 'roar/representer/json'
|
5
|
+
|
6
|
+
require 'roar/representer/feature/http_verbs'
|
7
|
+
require 'roar/representer/feature/hypermedia'
|
8
|
+
|
9
|
+
class RepresenterIntegrationTest < MiniTest::Spec
|
10
|
+
module XML
|
11
|
+
class BandRepresenter < Roar::Representer::XML
|
12
|
+
self.representation_name = :band
|
13
|
+
|
14
|
+
property :name
|
15
|
+
property :label
|
16
|
+
|
17
|
+
include Roar::Representer::Feature::HttpVerbs
|
18
|
+
|
19
|
+
|
20
|
+
link :search do
|
21
|
+
search_url
|
22
|
+
end
|
23
|
+
|
24
|
+
link :self do
|
25
|
+
order_url(represented)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# TODO: inherit properly.
|
31
|
+
module JSON
|
32
|
+
class BandRepresenter < Roar::Representer::JSON
|
33
|
+
self.representation_name = :band
|
34
|
+
|
35
|
+
property :name
|
36
|
+
property :label
|
37
|
+
|
38
|
+
include Roar::Representer::Feature::HttpVerbs
|
39
|
+
include Roar::Representer::Feature::Hypermedia
|
40
|
+
|
41
|
+
|
42
|
+
link :search do
|
43
|
+
search_url
|
44
|
+
end
|
45
|
+
|
46
|
+
link :self do
|
47
|
+
order_url(represented)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
|
53
|
+
require 'order_representers'
|
54
|
+
describe "Representer as client" do
|
55
|
+
describe "JSON" do
|
56
|
+
it "allows a POST workflow" do
|
57
|
+
# create representation with initial values:
|
58
|
+
@r = JSON::BandRepresenter.new(:name => "Bigwig")
|
59
|
+
assert_equal "Bigwig", @r.name
|
60
|
+
|
61
|
+
@r = @r.post("http://localhost:9999/band", "application/band+json")
|
62
|
+
assert_equal "n/a", @r.label
|
63
|
+
|
64
|
+
# check HATEOAS:
|
65
|
+
#@r.extend Roar::Representer::Feature::Hypermedia
|
66
|
+
assert_equal "http://search", @r.links[:search]
|
67
|
+
assert_equal "http://band/strungout", @r.links[:self]
|
68
|
+
end
|
69
|
+
|
70
|
+
# TODO: implement me.
|
71
|
+
it "allows an ordering workflow" do
|
72
|
+
# create representation with initial values:
|
73
|
+
@o = ::JSON::Order.new(:client_id => 1)
|
74
|
+
assert_equal 1, @o.client_id
|
75
|
+
|
76
|
+
@o.post!("http://localhost:9999/orders", "application/order+json")
|
77
|
+
# check HATEOAS:
|
78
|
+
#@r.extend Roar::Representer::Feature::Hypermedia
|
79
|
+
|
80
|
+
assert_equal "http://localhost:9999/orders/1/items", @o.links[:items]
|
81
|
+
assert_equal "http://localhost:9999/orders/1", @o.links[:self]
|
82
|
+
|
83
|
+
|
84
|
+
# manually POST item:
|
85
|
+
@i = ::JSON::Item.new(:article_id => "666-S", :amount => 1)
|
86
|
+
@i.post!(@o.links[:items], "application/item+json")
|
87
|
+
@o.get!(@o.links[:self], "application/order+json")
|
88
|
+
|
89
|
+
# check if item is included in order:
|
90
|
+
assert_equal 1, @o.items.size
|
91
|
+
assert_equal @i.to_attributes, @o.items.first.to_attributes
|
92
|
+
|
93
|
+
|
94
|
+
###@@o.delete!(@o.links[:self])
|
95
|
+
|
96
|
+
# use the DSL to add items:
|
97
|
+
#@o.links[:items].post(:article_id => "666-S", :amount => 1)
|
98
|
+
|
99
|
+
#@o.items.post(:article_id => "666-S", :amount => 1)
|
100
|
+
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
describe "XML" do
|
105
|
+
it "allows a POST workflow" do
|
106
|
+
# create representation with initial values:
|
107
|
+
@r = XML::BandRepresenter.new(:name => "Bigwig")
|
108
|
+
assert_equal "Bigwig", @r.name
|
109
|
+
|
110
|
+
@r = @r.post("http://localhost:9999/band", "application/band+xml")
|
111
|
+
assert_equal "n/a", @r.label
|
112
|
+
|
113
|
+
# check HATEOAS:
|
114
|
+
#@r.extend Roar::Representer::Feature::Hypermedia
|
115
|
+
assert_equal "http://search", @r.links[:search]
|
116
|
+
assert_equal "http://band/strungout", @r.links[:self]
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
|
121
|
+
end
|
122
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
require "test_xml/mini_test"
|
4
|
+
require "roar/representer/json"
|
5
|
+
|
6
|
+
class JsonRepresenterFunctionalTest < MiniTest::Spec
|
7
|
+
class OrderRepresenter < Roar::Representer::JSON
|
8
|
+
self.representation_name= :order
|
9
|
+
representable_property :id
|
10
|
+
end
|
11
|
+
|
12
|
+
|
13
|
+
describe "JsonRepresenter" do
|
14
|
+
before do
|
15
|
+
@r = OrderRepresenter.new
|
16
|
+
end
|
17
|
+
|
18
|
+
describe "#to_json" do
|
19
|
+
it "#serialize returns the serialized model" do
|
20
|
+
@r.id = 1
|
21
|
+
assert_equal '{"order":{"id":1}}', @r.serialize
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
it ".from_xml returns the deserialized model" do
|
26
|
+
@m = OrderRepresenter.deserialize('{"order": {"id":1}}')
|
27
|
+
assert_equal 1, @m.id
|
28
|
+
end
|
29
|
+
|
30
|
+
it ".from_xml still works with nil" do
|
31
|
+
assert OrderRepresenter.deserialize(nil)
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
class JsonHyperlinkRepresenterTest
|
40
|
+
describe "API" do
|
41
|
+
before do
|
42
|
+
@l = Roar::Representer::JSON::Hyperlink.from_json({:link => {:rel => :self, :href => "http://roar.apotomo.de"}}.to_json)
|
43
|
+
end
|
44
|
+
|
45
|
+
it "responds to #representation_name" do
|
46
|
+
assert_equal :link, @l.class.representation_name
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
it "responds to #rel" do
|
51
|
+
assert_equal "self", @l.rel
|
52
|
+
end
|
53
|
+
|
54
|
+
it "responds to #href" do
|
55
|
+
assert_equal "http://roar.apotomo.de", @l.href
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
class JsonHypermediaTest
|
61
|
+
describe "Hypermedia API" do
|
62
|
+
before do
|
63
|
+
@c = Class.new(Roar::Representer::JSON) do
|
64
|
+
include Roar::Representer::Feature::Hypermedia
|
65
|
+
|
66
|
+
self.representation_name= :order
|
67
|
+
|
68
|
+
representable_property :id
|
69
|
+
|
70
|
+
link :self do "http://self" end
|
71
|
+
link :next do "http://next/#{id}" end
|
72
|
+
end
|
73
|
+
|
74
|
+
@r = @c.new
|
75
|
+
end
|
76
|
+
|
77
|
+
it "responds to #links" do
|
78
|
+
assert_equal nil, @r.links
|
79
|
+
end
|
80
|
+
|
81
|
+
it "computes links in #from_attributes" do
|
82
|
+
@r = @c.from_attributes({"id" => 1})
|
83
|
+
assert_equal 2, @r.links.size
|
84
|
+
assert_equal({"rel"=>:self, "href"=>"http://self"}, @r.links.first.to_attributes)
|
85
|
+
assert_equal({"rel"=>:next, "href"=>"http://next/1"}, @r.links.last.to_attributes)
|
86
|
+
end
|
87
|
+
|
88
|
+
it "extracts links from JSON" do
|
89
|
+
@r = @c.deserialize({:order => {:links => [{:rel => "self", :href => "http://self"}]}}.to_json)
|
90
|
+
|
91
|
+
assert_equal 1, @r.links.size
|
92
|
+
assert_equal({"rel"=>"self", "href"=>"http://self"}, @r.links.first.to_attributes)
|
93
|
+
end
|
94
|
+
|
95
|
+
it "renders link: correctly in JSON" do
|
96
|
+
assert_equal "{\"order\":{\"id\":1,\"links\":[{\"rel\":\"self\",\"href\":\"http://self\"},{\"rel\":\"next\",\"href\":\"http://next/1\"}]}}", @c.from_attributes({"id" => 1}).serialize
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|