roar 0.8.3 → 0.9.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/CHANGES.markdown +7 -0
- data/README.textile +3 -3
- data/lib/roar/rails/representer_methods.rb +1 -1
- data/lib/roar/representer.rb +46 -0
- data/lib/roar/representer/feature/http_verbs.rb +24 -30
- data/lib/roar/representer/feature/transport.rb +31 -29
- data/lib/roar/representer/json.rb +7 -7
- data/lib/roar/representer/xml.rb +7 -11
- data/lib/roar/version.rb +1 -1
- data/roar.gemspec +1 -1
- data/test/dummy/config/routes.rb +1 -1
- data/test/fake_server.rb +9 -33
- data/test/http_verbs_feature_test.rb +41 -38
- data/test/hypermedia_feature_test.rb +1 -1
- data/test/integration_test.rb +3 -3
- data/test/json_representer_test.rb +26 -18
- data/test/model_representing_test.rb +2 -2
- data/test/order_representers.rb +1 -1
- data/test/representer_test.rb +2 -2
- data/test/test_helper.rb +1 -1
- data/test/transport_test.rb +5 -8
- data/test/xml_representer_test.rb +24 -14
- metadata +7 -8
- data/lib/roar/representer/base.rb +0 -64
data/CHANGES.markdown
CHANGED
data/README.textile
CHANGED
@@ -175,7 +175,7 @@ To create a new order, the frontend needs to POST to the REST backend. Here's ho
|
|
175
175
|
|
176
176
|
<pre>
|
177
177
|
order = Order.new(:client_id => current_user.id)
|
178
|
-
order.post
|
178
|
+
order.post("http://orders/")
|
179
179
|
</pre>
|
180
180
|
|
181
181
|
A couple of noteworthy steps happen here.
|
@@ -184,7 +184,7 @@ A couple of noteworthy steps happen here.
|
|
184
184
|
# Initial values like the client's id are passed as arguments and placed in the document.
|
185
185
|
# The filled-out document is POSTed to the given URL.
|
186
186
|
# The backend service creates an actual order record and sends back the representation.
|
187
|
-
# In the @#post
|
187
|
+
# In the @#post@ call, the returned document is parsed and attributes in the representer instance are updated accordingly,
|
188
188
|
|
189
189
|
After the HTTP roundtrip, the order instance keeps all the information we need for proceeding the ordering workflow.
|
190
190
|
|
@@ -267,7 +267,7 @@ Here's what could happen in the frontend.
|
|
267
267
|
<pre>
|
268
268
|
beer = Article.new(:title => "Lonestar Beer")
|
269
269
|
order.items << beer
|
270
|
-
order.post
|
270
|
+
order.post(order.links[:self])
|
271
271
|
</pre>
|
272
272
|
|
273
273
|
This was dead simple since representations can be composed of different documents in Roar.
|
@@ -43,7 +43,7 @@ module Roar
|
|
43
43
|
singular_name = name.to_s.singularize
|
44
44
|
|
45
45
|
super name, options.reverse_merge(
|
46
|
-
:
|
46
|
+
:class => "representer/#{namespace}/#{singular_name}".classify.constantize,
|
47
47
|
#:tag => singular_name # FIXME: how/where to decide if singular TAG or not?
|
48
48
|
)
|
49
49
|
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'representable'
|
2
|
+
|
3
|
+
module Roar
|
4
|
+
module Representer
|
5
|
+
def self.included(base)
|
6
|
+
base.class_eval do
|
7
|
+
include Representable
|
8
|
+
extend ClassMethods
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
|
13
|
+
module ClassMethods
|
14
|
+
# Creates a representer instance and fills it with +attributes+.
|
15
|
+
# DISCUSS: remove.
|
16
|
+
def from_attributes(attributes) # DISCUSS: better move to #new? how do we handle the original #new then?
|
17
|
+
new.tap do |representer|
|
18
|
+
yield representer if block_given?
|
19
|
+
attributes.each { |p,v| representer.public_send("#{p}=", v) }
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
# Convert representer's attributes to a nested attributes hash.
|
26
|
+
def to_attributes
|
27
|
+
{}.tap do |attributes|
|
28
|
+
self.class.representable_attrs.each do |definition|
|
29
|
+
value = public_send(definition.getter)
|
30
|
+
|
31
|
+
if definition.typed?
|
32
|
+
value = definition.apply(value) do |v|
|
33
|
+
v.to_attributes # applied to each typed attribute (even in collections).
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
attributes[definition.name] = value
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
def before_serialize(*)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -1,60 +1,54 @@
|
|
1
1
|
require 'roar/representer/feature/transport'
|
2
2
|
|
3
3
|
module Roar
|
4
|
-
# Gives HTTP-power to representers
|
4
|
+
# Gives HTTP-power to representers. They can serialize, send, process and deserialize HTTP-requests.
|
5
5
|
module Representer
|
6
6
|
module Feature
|
7
7
|
module HttpVerbs
|
8
8
|
def self.included(base)
|
9
9
|
base.extend ClassMethods
|
10
10
|
end
|
11
|
-
|
11
|
+
|
12
12
|
|
13
13
|
module ClassMethods
|
14
|
-
|
15
|
-
|
14
|
+
# GETs +url+ with +format+ and returns deserialized representer.
|
16
15
|
def get(url, format)
|
17
|
-
document = get_uri(url, format).body
|
16
|
+
document = http.get_uri(url, format).body
|
18
17
|
deserialize(document)
|
19
18
|
end
|
20
19
|
|
21
|
-
def
|
22
|
-
|
23
|
-
deserialize(representation)
|
24
|
-
end
|
25
|
-
|
26
|
-
|
27
|
-
def put(url, body, format)
|
28
|
-
representation = put_uri(url, body, format).body
|
29
|
-
deserialize(representation)
|
20
|
+
def http
|
21
|
+
Transport
|
30
22
|
end
|
31
23
|
end
|
32
24
|
|
25
|
+
|
26
|
+
# Serializes the object, POSTs it to +url+ with +format+, deserializes the returned document
|
27
|
+
# and updates properties accordingly.
|
33
28
|
def post(url, format)
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
rep = post(*args) # TODO: make this better.
|
38
|
-
|
39
|
-
self.class.representable_attrs.each do |definition|
|
40
|
-
|
41
|
-
send(definition.setter, rep.public_send(definition.getter))
|
42
|
-
end # TODO: this sucks. do this with #properties and #replace_properties.
|
29
|
+
# DISCUSS: what if a redirect happens here?
|
30
|
+
document = http.post_uri(url, serialize, format).body
|
31
|
+
deserialize(document)
|
43
32
|
end
|
44
33
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
send(definition.setter, rep.public_send(definition.getter))
|
50
|
-
end # TODO: this sucks. do this with #properties and #replace_properties.
|
34
|
+
# GETs +url+ with +format+, deserializes the returned document and updates properties accordingly.
|
35
|
+
def get(url, format)
|
36
|
+
document = http.get_uri(url, format).body
|
37
|
+
deserialize(document)
|
51
38
|
end
|
52
39
|
|
40
|
+
# Serializes the object, PUTs it to +url+ with +format+, deserializes the returned document
|
41
|
+
# and updates properties accordingly.
|
53
42
|
def put(url, format)
|
54
|
-
|
43
|
+
document = http.put_uri(url, serialize, format).body
|
44
|
+
deserialize(document)
|
55
45
|
end
|
56
46
|
|
57
47
|
# TODO: implement delete, patch.
|
48
|
+
private
|
49
|
+
def http
|
50
|
+
Transport # DISCUSS: might be refering to separate http object soon.
|
51
|
+
end
|
58
52
|
end
|
59
53
|
end
|
60
54
|
end
|
@@ -6,36 +6,38 @@ module Roar
|
|
6
6
|
module Feature
|
7
7
|
# Implements the HTTP verbs with Net::HTTP.
|
8
8
|
module Transport
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
9
|
+
class << self
|
10
|
+
# TODO: generically handle return codes/let Restfulie do it.
|
11
|
+
def get_uri(uri, as)
|
12
|
+
do_request(Net::HTTP::Get, uri, as)
|
13
|
+
end
|
14
|
+
|
15
|
+
def post_uri(uri, body, as)
|
16
|
+
do_request(Net::HTTP::Post, uri, as)
|
17
|
+
end
|
18
|
+
|
19
|
+
def put_uri(uri, body, as)
|
20
|
+
do_request(Net::HTTP::Put, uri, as)
|
21
|
+
end
|
22
|
+
|
23
|
+
def patch_uri(uri, body, as)
|
24
|
+
do_request(Net::HTTP::Patch, uri, as)
|
25
|
+
end
|
26
|
+
|
27
|
+
def delete_uri(uri, as)
|
28
|
+
do_request(Net::HTTP::Delete, uri, as)
|
29
|
+
end
|
25
30
|
|
26
|
-
|
27
|
-
do_request(
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
req.content_type = as
|
37
|
-
req.body = body if body
|
38
|
-
http.request(req)
|
31
|
+
private
|
32
|
+
def do_request(what, uri, as, body="")
|
33
|
+
# DISCUSS: can this be made easier?
|
34
|
+
uri = URI.parse(uri)
|
35
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
36
|
+
req = what.new(uri.request_uri)
|
37
|
+
req.content_type = as
|
38
|
+
req.body = body if body
|
39
|
+
http.request(req)
|
40
|
+
end
|
39
41
|
end
|
40
42
|
end
|
41
43
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require 'roar/representer
|
1
|
+
require 'roar/representer'
|
2
2
|
require 'representable/json'
|
3
3
|
|
4
4
|
module Roar
|
@@ -6,7 +6,7 @@ module Roar
|
|
6
6
|
module JSON
|
7
7
|
def self.included(base)
|
8
8
|
base.class_eval do
|
9
|
-
include
|
9
|
+
include Representer
|
10
10
|
include Representable::JSON
|
11
11
|
|
12
12
|
extend ClassMethods
|
@@ -23,10 +23,6 @@ module Roar
|
|
23
23
|
def from_json(document, options={})
|
24
24
|
document ||= "{}" # DISCUSS: provide this for convenience, or better not?
|
25
25
|
|
26
|
-
if block = deserialize_block_for_options(options) and
|
27
|
-
return super(document, &block)
|
28
|
-
end
|
29
|
-
|
30
26
|
super
|
31
27
|
end
|
32
28
|
|
@@ -34,6 +30,10 @@ module Roar
|
|
34
30
|
def serialize(*args)
|
35
31
|
to_json(*args)
|
36
32
|
end
|
33
|
+
|
34
|
+
def deserialize(*args)
|
35
|
+
from_json(*args)
|
36
|
+
end
|
37
37
|
end
|
38
38
|
|
39
39
|
|
@@ -44,7 +44,7 @@ module Roar
|
|
44
44
|
|
45
45
|
# TODO: move to instance method, or remove?
|
46
46
|
def links_definition_options
|
47
|
-
{:
|
47
|
+
{:class => Hyperlink , :collection => true}
|
48
48
|
end
|
49
49
|
end
|
50
50
|
|
data/lib/roar/representer/xml.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require 'roar/representer
|
1
|
+
require 'roar/representer'
|
2
2
|
require 'representable/xml'
|
3
3
|
|
4
4
|
module Roar
|
@@ -8,7 +8,7 @@ module Roar
|
|
8
8
|
module XML
|
9
9
|
def self.included(base)
|
10
10
|
base.class_eval do
|
11
|
-
include
|
11
|
+
include Representer
|
12
12
|
include Representable::XML
|
13
13
|
|
14
14
|
extend ClassMethods
|
@@ -17,14 +17,6 @@ module Roar
|
|
17
17
|
end
|
18
18
|
|
19
19
|
module InstanceMethods
|
20
|
-
def from_xml(document, options={})
|
21
|
-
if block = deserialize_block_for_options(options)
|
22
|
-
return super(document, &block)
|
23
|
-
end
|
24
|
-
|
25
|
-
super
|
26
|
-
end
|
27
|
-
|
28
20
|
def to_xml(*args)
|
29
21
|
before_serialize(*args)
|
30
22
|
super
|
@@ -34,6 +26,10 @@ module Roar
|
|
34
26
|
def serialize(*args)
|
35
27
|
to_xml(*args)
|
36
28
|
end
|
29
|
+
|
30
|
+
def deserialize(*args)
|
31
|
+
from_xml(*args)
|
32
|
+
end
|
37
33
|
end
|
38
34
|
|
39
35
|
|
@@ -41,7 +37,7 @@ module Roar
|
|
41
37
|
include Representable::XML::ClassMethods
|
42
38
|
|
43
39
|
def links_definition_options
|
44
|
-
{:from => :link, :
|
40
|
+
{:from => :link, :class => Hyperlink, :collection => true}
|
45
41
|
end
|
46
42
|
|
47
43
|
# Generic entry-point for parsing.
|
data/lib/roar/version.rb
CHANGED
data/roar.gemspec
CHANGED
@@ -19,7 +19,7 @@ Gem::Specification.new do |s|
|
|
19
19
|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
20
20
|
s.require_paths = ["lib"]
|
21
21
|
|
22
|
-
s.add_runtime_dependency "representable", "~> 0.
|
22
|
+
s.add_runtime_dependency "representable", "~> 0.12"
|
23
23
|
s.add_runtime_dependency "hooks", "~> 0.1.4"
|
24
24
|
|
25
25
|
s.add_development_dependency "test_xml"
|
data/test/dummy/config/routes.rb
CHANGED
@@ -3,5 +3,5 @@ Dummy::Application.routes.draw do
|
|
3
3
|
root :to => 'musician#index'
|
4
4
|
resources :albums
|
5
5
|
resources :songs
|
6
|
-
get "articles/starts_with/{query}", :to => "albums#search",:
|
6
|
+
get "articles/starts_with/{query}", :to => "albums#search",:class => :album_search
|
7
7
|
end
|
data/test/fake_server.rb
CHANGED
@@ -1,30 +1,9 @@
|
|
1
1
|
require "bundler/setup"
|
2
2
|
require 'sinatra/base'
|
3
3
|
require 'sinatra/reloader'
|
4
|
-
require 'roar/representer/xml'
|
5
|
-
|
6
|
-
# Usually shared in a gem between service and clients.
|
7
|
-
module BandRepresenter
|
8
|
-
include Roar::Representer::XML
|
9
|
-
property :name
|
10
|
-
property :label
|
11
|
-
end
|
12
|
-
|
13
|
-
Band = Struct.new(:name, :label)
|
14
|
-
Band.class_eval do
|
15
|
-
include Roar::Representer::XML
|
16
|
-
include BandRepresenter
|
17
|
-
end
|
18
4
|
|
19
5
|
|
20
|
-
class FakeServer < Sinatra::Base
|
21
|
-
BANDS = {"belvedere" => Band.new("Belvedere", "canadian maple")}
|
22
|
-
|
23
|
-
get "/bands/:id" do
|
24
|
-
BANDS[params[:id]].to_xml
|
25
|
-
end
|
26
|
-
|
27
|
-
|
6
|
+
class FakeServer < Sinatra::Base
|
28
7
|
get "/method" do
|
29
8
|
"<method>get</method>"
|
30
9
|
end
|
@@ -45,21 +24,18 @@ class FakeServer < Sinatra::Base
|
|
45
24
|
# "<method>patch</method>"
|
46
25
|
#end
|
47
26
|
|
48
|
-
post "/
|
49
|
-
if request.content_type =~ /xml/
|
50
|
-
|
51
|
-
<link href="http://search" rel="search" />
|
52
|
-
<link href="http://band/strungout" rel="self" />
|
53
|
-
</band>}
|
54
|
-
else
|
55
|
-
'{"band": {"label": "n/a", "name": "Strung Out", "links": [{"href":"http://search", "rel": "search"}, {"href":"http://band/strungout", "rel": "self"}]}}'
|
56
|
-
end
|
27
|
+
post "/bands" do
|
28
|
+
#if request.content_type =~ /xml/
|
29
|
+
'{"label": "n/a", "name": "Strung Out", "links": [{"href":"http://search", "rel": "search"}, {"href":"http://band/strungout", "rel": "self"}]}'
|
57
30
|
end
|
58
31
|
|
59
|
-
put "/
|
60
|
-
|
32
|
+
put "/bands/strungout" do
|
33
|
+
{:name => "Strung Out", :label => "Fat Wreck"}.to_json
|
61
34
|
end
|
62
35
|
|
36
|
+
get "/bands/slayer" do
|
37
|
+
{:name => "Slayer", :label => "Canadian Maple"}.to_json
|
38
|
+
end
|
63
39
|
|
64
40
|
|
65
41
|
require Dir.pwd + '/order_representers'
|
@@ -1,67 +1,70 @@
|
|
1
1
|
require 'test_helper'
|
2
2
|
require 'roar/representer/feature/http_verbs'
|
3
|
+
require 'roar/representer/json'
|
3
4
|
|
4
5
|
class HttpVerbsTest < MiniTest::Spec
|
5
|
-
|
6
|
-
include Roar::Representer::
|
6
|
+
module BandRepresenter
|
7
|
+
include Roar::Representer::JSON
|
7
8
|
|
8
9
|
property :name
|
9
10
|
property :label
|
10
|
-
|
11
|
-
include Roar::Representer::Feature::HttpVerbs
|
12
11
|
end
|
13
12
|
|
14
13
|
describe "HttpVerbs" do
|
15
14
|
before do
|
16
|
-
@
|
15
|
+
@band = Object.new
|
16
|
+
@band.extend(BandRepresenter)
|
17
|
+
@band.extend(Roar::Representer::Feature::HttpVerbs)
|
17
18
|
end
|
18
19
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
20
|
+
describe "HttpVerbs.get" do
|
21
|
+
it "returns instance from incoming representation" do
|
22
|
+
@Band = Class.new do
|
23
|
+
include Roar::Representer::JSON
|
24
|
+
include BandRepresenter
|
25
|
+
include Roar::Representer::Feature::HttpVerbs
|
26
|
+
end
|
27
|
+
@band = @Band.get("http://localhost:9999/bands/slayer", "application/json")
|
28
|
+
assert_equal "Slayer", @band.name
|
29
|
+
assert_equal "Canadian Maple", @band.label
|
27
30
|
end
|
28
31
|
end
|
29
32
|
|
30
|
-
describe "#
|
31
|
-
it "
|
32
|
-
@
|
33
|
-
assert_equal
|
34
|
-
|
35
|
-
assert_equal "Strung Out", @r.name
|
36
|
-
assert_equal "n/a", @r.label
|
33
|
+
describe "#get" do
|
34
|
+
it "updates instance with incoming representation" do
|
35
|
+
@band.get("http://localhost:9999/bands/slayer", "application/json")
|
36
|
+
assert_equal "Slayer", @band.name
|
37
|
+
assert_equal "Canadian Maple", @band.label
|
37
38
|
end
|
38
39
|
end
|
39
40
|
|
40
|
-
describe "#
|
41
|
-
it "
|
42
|
-
@
|
43
|
-
@
|
44
|
-
|
45
|
-
|
46
|
-
assert_equal "
|
41
|
+
describe "#post" do
|
42
|
+
it "updates instance with incoming representation" do
|
43
|
+
@band.name = "Strung Out"
|
44
|
+
assert_equal nil, @band.label
|
45
|
+
|
46
|
+
@band.post("http://localhost:9999/bands", "application/xml")
|
47
|
+
assert_equal "Strung Out", @band.name
|
48
|
+
assert_equal "n/a", @band.label
|
47
49
|
end
|
48
50
|
end
|
49
51
|
|
50
|
-
describe "
|
51
|
-
it "
|
52
|
-
band
|
53
|
-
|
54
|
-
|
52
|
+
describe "#put" do
|
53
|
+
it "updates instance with incoming representation" do
|
54
|
+
@band.name = "Strung Out"
|
55
|
+
@band.label = "Fat Wreck"
|
56
|
+
@band.put("http://localhost:9999/bands/strungout", "application/xml")
|
57
|
+
assert_equal "Strung Out", @band.name
|
58
|
+
assert_equal "Fat Wreck", @band.label
|
55
59
|
end
|
56
60
|
end
|
57
61
|
|
58
|
-
describe "#
|
59
|
-
|
60
|
-
band = @band.get!("http://localhost:9999/bands/belvedere", "application/xml")
|
61
|
-
assert_equal "Belvedere", band.name
|
62
|
-
assert_equal "canadian maple", band.label
|
63
|
-
end
|
62
|
+
describe "#delete" do
|
63
|
+
|
64
64
|
end
|
65
65
|
|
66
|
+
describe "#patch" do
|
67
|
+
|
68
|
+
end
|
66
69
|
end
|
67
70
|
end
|
@@ -59,7 +59,7 @@ class HypermediaTest
|
|
59
59
|
it "sets up links even when nested" do
|
60
60
|
class Page
|
61
61
|
include Roar::Representer::JSON
|
62
|
-
property :note, :
|
62
|
+
property :note, :class => Note
|
63
63
|
end
|
64
64
|
|
65
65
|
assert_equal "{\"note\":{\"links\":[{\"rel\":\"self\",\"href\":\"http://me\"}]}}", Page.from_attributes(note: Note.new).to_json
|
data/test/integration_test.rb
CHANGED
@@ -18,7 +18,7 @@ class IntegrationTest < MiniTest::Spec
|
|
18
18
|
include Roar::Representer::JSON
|
19
19
|
include Roar::Representer::Feature::Hypermedia
|
20
20
|
|
21
|
-
collection :items, :
|
21
|
+
collection :items, :class => Beer
|
22
22
|
end
|
23
23
|
|
24
24
|
describe "Beer service" do
|
@@ -45,7 +45,7 @@ class IntegrationTest < MiniTest::Spec
|
|
45
45
|
|
46
46
|
attr_accessor :per_page, :current_page, :all_items
|
47
47
|
|
48
|
-
collection :beers, :
|
48
|
+
collection :beers, :class => Beer
|
49
49
|
property :total
|
50
50
|
|
51
51
|
def total
|
@@ -79,7 +79,7 @@ class IntegrationTest < MiniTest::Spec
|
|
79
79
|
|
80
80
|
|
81
81
|
list.current_page = 2
|
82
|
-
assert_equal "{\"beers\":[{\"name\":\"Eisenbahn\",\"links\":[{\"rel\":\"self\",\"href\":\"http://beers/eisenbahn\"}]},{\"name\":\"Colorado\",\"links\":[{\"rel\":\"self\",\"href\":\"http://beers/colorado\"}]}],\"total\":4,\"links\":[{\"rel\":\"next\"},{\"rel\":\"prev\",\"href\":\"http://beers/all?page=1\"}]}", list.to_json
|
82
|
+
assert_equal "{\"beer_collection\":{\"beers\":[{\"name\":\"Eisenbahn\",\"links\":[{\"rel\":\"self\",\"href\":\"http://beers/eisenbahn\"}]},{\"name\":\"Colorado\",\"links\":[{\"rel\":\"self\",\"href\":\"http://beers/colorado\"}]}],\"total\":4,\"links\":[{\"rel\":\"next\"},{\"rel\":\"prev\",\"href\":\"http://beers/all?page=1\"}]}}", list.to_json
|
83
83
|
end
|
84
84
|
end
|
85
85
|
end
|
@@ -13,36 +13,44 @@ class JsonRepresenterTest < MiniTest::Spec
|
|
13
13
|
|
14
14
|
describe "JsonRepresenter" do
|
15
15
|
before do
|
16
|
-
@
|
16
|
+
@order = Order.new
|
17
17
|
end
|
18
18
|
|
19
|
+
|
19
20
|
describe "#to_json" do
|
20
|
-
|
21
|
-
@
|
22
|
-
|
21
|
+
before do
|
22
|
+
@order.id = 1
|
23
|
+
end
|
24
|
+
|
25
|
+
it "returns the serialized model" do
|
26
|
+
assert_equal '{"id":1}', @order.to_json
|
27
|
+
end
|
28
|
+
|
29
|
+
it "is aliased by #serialize" do
|
30
|
+
assert_equal '{"id":1}', @order.serialize
|
23
31
|
end
|
24
32
|
end
|
25
33
|
|
26
|
-
describe "
|
34
|
+
describe "#from_json" do
|
27
35
|
it "returns the deserialized model" do
|
28
|
-
@
|
29
|
-
assert_equal 1, @
|
36
|
+
@order.from_json('{"id":1}')
|
37
|
+
assert_equal 1, @order.id
|
30
38
|
end
|
31
39
|
|
32
|
-
it "
|
33
|
-
order
|
34
|
-
assert_equal
|
35
|
-
assert_equal 1, order.pending
|
36
|
-
end
|
37
|
-
|
38
|
-
it "accepts :include option" do
|
39
|
-
order = Order.from_json({id: 1, pending: 1}.to_json, :include => [:id])
|
40
|
-
assert_equal 1, order.id
|
41
|
-
assert_equal nil, order.pending
|
40
|
+
it "is aliased by #deserialize" do
|
41
|
+
@order.deserialize('{"id":1}')
|
42
|
+
assert_equal 1, @order.id
|
42
43
|
end
|
43
44
|
|
44
45
|
it "works with a nil document" do
|
45
|
-
assert
|
46
|
+
assert @order.from_json(nil)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe "JSON.from_json" do
|
51
|
+
it "is aliased by #deserialize" do
|
52
|
+
@order = Order.deserialize('{"id":1}')
|
53
|
+
assert_equal 1, @order.id
|
46
54
|
end
|
47
55
|
end
|
48
56
|
end
|
@@ -15,7 +15,7 @@ class ModelRepresentingTest < MiniTest::Spec
|
|
15
15
|
include Roar::Representer::Feature::ModelRepresenting
|
16
16
|
self.representation_wrap= :position
|
17
17
|
property :id
|
18
|
-
property :item, :
|
18
|
+
property :item, :class => ItemRepresenter
|
19
19
|
end
|
20
20
|
|
21
21
|
class OrderRepresenter
|
@@ -23,7 +23,7 @@ class ModelRepresentingTest < MiniTest::Spec
|
|
23
23
|
include Roar::Representer::Feature::ModelRepresenting
|
24
24
|
self.representation_wrap= :order
|
25
25
|
property :id
|
26
|
-
collection :items, :
|
26
|
+
collection :items, :class => ItemRepresenter
|
27
27
|
end
|
28
28
|
|
29
29
|
describe "#definition_class" do
|
data/test/order_representers.rb
CHANGED
data/test/representer_test.rb
CHANGED
data/test/test_helper.rb
CHANGED
data/test/transport_test.rb
CHANGED
@@ -4,26 +4,23 @@ require 'roar/representer/feature/transport'
|
|
4
4
|
class TransportTest < MiniTest::Spec
|
5
5
|
describe "Transport" do
|
6
6
|
before do
|
7
|
-
@
|
8
|
-
include Roar::Representer::Feature::Transport
|
9
|
-
end
|
10
|
-
@o = @klass.new
|
7
|
+
@transport = Roar::Representer::Feature::Transport
|
11
8
|
end
|
12
9
|
|
13
10
|
it "#get_uri returns response" do
|
14
|
-
assert_equal "<method>get</method>", @
|
11
|
+
assert_equal "<method>get</method>", @transport.get_uri("http://localhost:9999/method", "application/xml").body
|
15
12
|
end
|
16
13
|
|
17
14
|
it "#post_uri returns response" do
|
18
|
-
assert_equal "<method>post</method>", @
|
15
|
+
assert_equal "<method>post</method>", @transport.post_uri("http://localhost:9999/method", "booty", "application/xml").body
|
19
16
|
end
|
20
17
|
|
21
18
|
it "#put_uri returns response" do
|
22
|
-
assert_equal "<method>put</method>", @
|
19
|
+
assert_equal "<method>put</method>", @transport.put_uri("http://localhost:9999/method", "booty", "application/xml").body
|
23
20
|
end
|
24
21
|
|
25
22
|
it "#delete_uri returns response" do
|
26
|
-
assert_equal "<method>delete</method>", @
|
23
|
+
assert_equal "<method>delete</method>", @transport.delete_uri("http://localhost:9999/method", "application/xml").body
|
27
24
|
end
|
28
25
|
|
29
26
|
# TODO: how to get PATCH into Sinatra?
|
@@ -10,7 +10,7 @@ class PositionRepresenter
|
|
10
10
|
include Roar::Representer::XML
|
11
11
|
self.representation_wrap= :position
|
12
12
|
property :id
|
13
|
-
property :item, :
|
13
|
+
property :item, :class => ItemRepresenter
|
14
14
|
end
|
15
15
|
|
16
16
|
|
@@ -48,7 +48,7 @@ class XMLRepresenterFunctionalTest < MiniTest::Spec
|
|
48
48
|
|
49
49
|
class TestXmlRepresenter
|
50
50
|
include Roar::Representer::XML
|
51
|
-
self.representation_wrap= :order
|
51
|
+
self.representation_wrap= :order
|
52
52
|
property :id
|
53
53
|
end
|
54
54
|
|
@@ -71,19 +71,35 @@ class XMLRepresenterFunctionalTest < MiniTest::Spec
|
|
71
71
|
|
72
72
|
|
73
73
|
describe "#to_xml" do
|
74
|
-
it "serializes the
|
74
|
+
it "serializes the model" do
|
75
75
|
assert_xml_equal "<order/>", @r.to_xml
|
76
76
|
|
77
|
+
@r.id = 1
|
78
|
+
assert_xml_equal "<order><id>1</id></order>", @r.to_xml
|
79
|
+
|
77
80
|
@r.id = 2
|
78
|
-
assert_xml_equal "<rap><id>2</id></rap>", @r.to_xml(:
|
81
|
+
assert_xml_equal "<rap><id>2</id></rap>", @r.to_xml(:wrap => :rap)
|
79
82
|
end
|
80
83
|
|
81
|
-
it "is aliased
|
84
|
+
it "is aliased by #serialize" do
|
82
85
|
assert_equal @r.to_xml, @r.serialize
|
83
86
|
end
|
84
87
|
end
|
85
88
|
|
86
89
|
describe "#from_xml" do
|
90
|
+
it "deserializes object" do
|
91
|
+
@order = Order.new.from_xml("<order><id>1</id></order>")
|
92
|
+
assert_equal "1", @order.id
|
93
|
+
end
|
94
|
+
|
95
|
+
it "is aliased by #deserialize" do
|
96
|
+
@order = Order.new.deserialize("<order><id>1</id></order>")
|
97
|
+
assert_equal "1", @order.id
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
|
102
|
+
describe "XML.from_xml" do
|
87
103
|
class Order
|
88
104
|
include Roar::Representer::XML
|
89
105
|
property :id
|
@@ -109,12 +125,6 @@ class XMLRepresenterFunctionalTest < MiniTest::Spec
|
|
109
125
|
|
110
126
|
|
111
127
|
describe "without options" do
|
112
|
-
it "#to_xml returns the serialized model" do
|
113
|
-
@r.id = 1
|
114
|
-
assert_xml_equal "<order><id>1</id></order>", @r.to_xml
|
115
|
-
end
|
116
|
-
|
117
|
-
|
118
128
|
it ".from_xml returns the deserialized model" do
|
119
129
|
@m = TestXmlRepresenter.from_xml("<order><id>1</id></order>")
|
120
130
|
assert_equal "1", @m.id
|
@@ -157,7 +167,7 @@ class XMLRepresenterFunctionalTest < MiniTest::Spec
|
|
157
167
|
|
158
168
|
self.representation_wrap= :order
|
159
169
|
property :id
|
160
|
-
collection :items, :
|
170
|
+
collection :items, :class => ItemRepresenter, :from => :item
|
161
171
|
end
|
162
172
|
|
163
173
|
@r = @c.from_attributes("id" => 1)
|
@@ -192,8 +202,8 @@ class XmlHyperlinkRepresenterTest < MiniTest::Spec
|
|
192
202
|
@l = Roar::Representer::XML::Hyperlink.from_xml(%{<link rel="self" href="http://roar.apotomo.de"/>})
|
193
203
|
end
|
194
204
|
|
195
|
-
it "responds to #
|
196
|
-
|
205
|
+
it "responds to #to_xml" do
|
206
|
+
assert_xml_equal %{<link rel=\"self\" href=\"http://roar.apotomo.de\"/>}, @l.to_xml
|
197
207
|
end
|
198
208
|
|
199
209
|
|
metadata
CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
|
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
6
|
- 0
|
7
|
-
-
|
8
|
-
-
|
9
|
-
version: 0.
|
7
|
+
- 9
|
8
|
+
- 0
|
9
|
+
version: 0.9.0
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Nick Sutterer
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2011-12-
|
17
|
+
date: 2011-12-20 00:00:00 +01:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
@@ -27,9 +27,8 @@ dependencies:
|
|
27
27
|
- !ruby/object:Gem::Version
|
28
28
|
segments:
|
29
29
|
- 0
|
30
|
-
-
|
31
|
-
|
32
|
-
version: 0.10.3
|
30
|
+
- 12
|
31
|
+
version: "0.12"
|
33
32
|
type: :runtime
|
34
33
|
version_requirements: *id001
|
35
34
|
- !ruby/object:Gem::Dependency
|
@@ -111,7 +110,7 @@ files:
|
|
111
110
|
- lib/roar/rails/controller_methods.rb
|
112
111
|
- lib/roar/rails/representer_methods.rb
|
113
112
|
- lib/roar/rails/test_case.rb
|
114
|
-
- lib/roar/representer
|
113
|
+
- lib/roar/representer.rb
|
115
114
|
- lib/roar/representer/feature/http_verbs.rb
|
116
115
|
- lib/roar/representer/feature/hypermedia.rb
|
117
116
|
- lib/roar/representer/feature/model_representing.rb
|
@@ -1,64 +0,0 @@
|
|
1
|
-
require 'representable'
|
2
|
-
|
3
|
-
module Roar
|
4
|
-
module Representer
|
5
|
-
module Base
|
6
|
-
def self.included(base)
|
7
|
-
base.class_eval do
|
8
|
-
include Representable
|
9
|
-
extend ClassMethods
|
10
|
-
|
11
|
-
class << self
|
12
|
-
alias_method :property, :representable_property
|
13
|
-
alias_method :collection, :representable_collection
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
|
19
|
-
module ClassMethods
|
20
|
-
# Creates a representer instance and fills it with +attributes+.
|
21
|
-
def from_attributes(attributes) # DISCUSS: better move to #new? how do we handle the original #new then?
|
22
|
-
new.tap do |representer|
|
23
|
-
yield representer if block_given?
|
24
|
-
attributes.each { |p,v| representer.public_send("#{p}=", v) }
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
|
30
|
-
# Convert representer's attributes to a nested attributes hash.
|
31
|
-
def to_attributes
|
32
|
-
{}.tap do |attributes|
|
33
|
-
self.class.representable_attrs.each do |definition|
|
34
|
-
value = public_send(definition.getter)
|
35
|
-
|
36
|
-
if definition.typed?
|
37
|
-
value = definition.apply(value) do |v|
|
38
|
-
v.to_attributes # applied to each typed attribute (even in collections).
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
attributes[definition.name] = value
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
private
|
48
|
-
def before_serialize(*)
|
49
|
-
end
|
50
|
-
|
51
|
-
# Returns block used in #from_json and #from_xml to filter incoming arguments.
|
52
|
-
# This method is subject to change and might be removed, soon.
|
53
|
-
def deserialize_block_for_options(options)
|
54
|
-
return unless props = options[:except] || options[:include]
|
55
|
-
|
56
|
-
lambda do |name|
|
57
|
-
res = props.include?(name)
|
58
|
-
options[:include] ? res : !res
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
end
|
63
|
-
end
|
64
|
-
end
|