roar 0.11.4 → 0.11.5
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 +5 -1
- data/Gemfile +1 -1
- data/README.textile +22 -21
- data/lib/roar/representer.rb +1 -1
- data/lib/roar/representer/feature/client.rb +3 -3
- data/lib/roar/representer/feature/coercion.rb +1 -1
- data/lib/roar/representer/feature/http_verbs.rb +8 -9
- data/lib/roar/representer/feature/hypermedia.rb +83 -63
- data/lib/roar/representer/json.rb +12 -12
- data/lib/roar/representer/json/hal.rb +98 -25
- data/lib/roar/representer/transport/faraday.rb +5 -11
- data/lib/roar/representer/transport/net_http.rb +5 -5
- data/lib/roar/representer/xml.rb +11 -11
- data/lib/roar/version.rb +1 -1
- data/roar.gemspec +2 -2
- data/test/client_test.rb +2 -2
- data/test/coercion_feature_test.rb +2 -2
- data/test/dummy/app/controllers/albums_controller.rb +6 -6
- data/test/dummy/app/models/album.rb +1 -1
- data/test/dummy/app/representers/representer/xml/album.rb +3 -3
- data/test/dummy/app/representers/representer/xml/song.rb +1 -1
- data/test/dummy/config/boot.rb +1 -1
- data/test/fake_server.rb +14 -15
- data/test/faraday_http_transport_test.rb +25 -10
- data/test/hal_json_test.rb +73 -31
- data/test/http_verbs_feature_test.rb +12 -12
- data/test/hypermedia_feature_test.rb +38 -145
- data/test/hypermedia_test.rb +100 -0
- data/test/integration_test.rb +22 -22
- data/test/json_representer_test.rb +31 -31
- data/test/net_http_transport_test.rb +24 -10
- data/test/order_representers.rb +11 -11
- data/test/rails/controller_methods_test.rb +25 -25
- data/test/rails/rails_representer_methods_test.rb +3 -3
- data/test/representer_test.rb +6 -6
- data/test/test_helper.rb +33 -4
- data/test/xml_representer_test.rb +47 -47
- metadata +3 -3
- data/lib/roar/rails.rb +0 -21
@@ -9,48 +9,48 @@ module Roar
|
|
9
9
|
base.class_eval do
|
10
10
|
include Representer
|
11
11
|
include Representable::JSON
|
12
|
-
|
12
|
+
|
13
13
|
extend ClassMethods
|
14
14
|
include InstanceMethods # otherwise Representable overrides our #to_json.
|
15
15
|
end
|
16
16
|
end
|
17
|
-
|
17
|
+
|
18
18
|
module InstanceMethods
|
19
19
|
def to_hash(*args)
|
20
20
|
before_serialize(*args)
|
21
21
|
super
|
22
22
|
end
|
23
|
-
|
23
|
+
|
24
24
|
def from_json(document, options={})
|
25
25
|
document = '{}' if document.nil? or document.empty?
|
26
|
-
|
26
|
+
|
27
27
|
super
|
28
28
|
end
|
29
|
-
|
29
|
+
|
30
30
|
# Generic entry-point for rendering.
|
31
31
|
def serialize(*args)
|
32
32
|
to_json(*args)
|
33
33
|
end
|
34
|
-
|
34
|
+
|
35
35
|
def deserialize(*args)
|
36
36
|
from_json(*args)
|
37
37
|
end
|
38
38
|
end
|
39
|
-
|
40
|
-
|
39
|
+
|
40
|
+
|
41
41
|
module ClassMethods
|
42
42
|
def deserialize(*args)
|
43
43
|
from_json(*args)
|
44
44
|
end
|
45
|
-
|
45
|
+
|
46
46
|
# TODO: move to instance method, or remove?
|
47
47
|
def links_definition_options
|
48
|
-
[:
|
48
|
+
[:links_array, {:from => :links, :class => Feature::Hypermedia::Hyperlink, :extend => HyperlinkRepresenter, :collection => true}]
|
49
49
|
end
|
50
50
|
end
|
51
|
-
|
51
|
+
|
52
52
|
require "representable/json/hash"
|
53
|
-
# Represents a hyperlink in standard roar+json hash representation.
|
53
|
+
# Represents a hyperlink in standard roar+json hash representation.
|
54
54
|
module HyperlinkRepresenter
|
55
55
|
include Representable::JSON::Hash
|
56
56
|
end
|
@@ -8,10 +8,10 @@ module Roar::Representer
|
|
8
8
|
# :embedded => true option.
|
9
9
|
#
|
10
10
|
# Example:
|
11
|
-
#
|
11
|
+
#
|
12
12
|
# module OrderRepresenter
|
13
13
|
# include Roar::Representer::JSON::HAL
|
14
|
-
#
|
14
|
+
#
|
15
15
|
# property :id
|
16
16
|
# collection :items, :class => Item, :extend => ItemRepresenter, :embedded => true
|
17
17
|
#
|
@@ -32,33 +32,48 @@ module Roar::Representer
|
|
32
32
|
include Resources
|
33
33
|
end
|
34
34
|
end
|
35
|
-
|
35
|
+
|
36
36
|
module Resources
|
37
37
|
# Write the property to the +_embedded+ hash when it's a resource.
|
38
38
|
def compile_fragment(bin, doc)
|
39
39
|
return super unless bin.options[:embedded]
|
40
40
|
super(bin, doc[:_embedded] ||= {})
|
41
41
|
end
|
42
|
-
|
42
|
+
|
43
43
|
def uncompile_fragment(bin, doc)
|
44
44
|
return super unless bin.options[:embedded]
|
45
45
|
super(bin, doc["_embedded"] || {})
|
46
46
|
end
|
47
47
|
end
|
48
|
-
|
48
|
+
|
49
49
|
module ClassMethods
|
50
50
|
def links_definition_options
|
51
|
-
super.tap { |options| options[1].merge!(
|
51
|
+
super.tap { |options| options[1].merge!(
|
52
|
+
:from => :_links,
|
53
|
+
:extend => HAL::Links::LinkCollectionRepresenter,
|
54
|
+
:instance => lambda { |hsh| LinkCollection.new(link_array_rels) }) # defined in InstanceMethods as this is executed in represented context.
|
55
|
+
}
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
class LinkCollection < Feature::Hypermedia::LinkCollection
|
60
|
+
def initialize(array_rels, *args)
|
61
|
+
super(*args)
|
62
|
+
@array_rels = array_rels.map(&:to_s)
|
63
|
+
end
|
64
|
+
|
65
|
+
def is_array?(rel)
|
66
|
+
@array_rels.include?(rel.to_s)
|
52
67
|
end
|
53
68
|
end
|
54
|
-
|
69
|
+
|
55
70
|
# Including this module in your representer will render and parse your embedded hyperlinks
|
56
71
|
# following the HAL specification: http://stateless.co/hal_specification.html
|
57
72
|
#
|
58
73
|
# module SongRepresenter
|
59
74
|
# include Roar::Representer::JSON
|
60
75
|
# include Roar::Representer::JSON::HAL::Links
|
61
|
-
#
|
76
|
+
#
|
62
77
|
# link :self { "http://self" }
|
63
78
|
# end
|
64
79
|
#
|
@@ -68,40 +83,98 @@ module Roar::Representer
|
|
68
83
|
#
|
69
84
|
# Note that the HAL::Links module alone doesn't prepend an underscore to +links+. Use the JSON::HAL module for that.
|
70
85
|
module Links
|
71
|
-
# TODO: allow more attributes besides :href in Hyperlink.
|
72
86
|
def self.included(base)
|
73
87
|
base.class_eval do
|
74
88
|
include Roar::Representer::Feature::Hypermedia
|
89
|
+
include InstanceMethods
|
75
90
|
extend Links::ClassMethods
|
76
91
|
end
|
77
92
|
end
|
78
93
|
|
94
|
+
module InstanceMethods
|
95
|
+
private
|
96
|
+
def prepare_link_for(href, options)
|
97
|
+
return super(href, options) unless options[:array] # TODO: remove :array and use special instan
|
98
|
+
|
99
|
+
list = href.collect { |opts| Feature::Hypermedia::Hyperlink.new(opts.merge!(:rel => options[:rel])) }
|
100
|
+
LinkArray.new(list)
|
101
|
+
end
|
102
|
+
|
103
|
+
# TODO: move to LinksDefinition.
|
104
|
+
def link_array_rels
|
105
|
+
links_definition.collect { |cfg| cfg.first[:array] ? cfg.first[:rel] : nil }.compact
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
79
109
|
|
110
|
+
require 'representable/json/hash'
|
80
111
|
module LinkCollectionRepresenter
|
81
|
-
include JSON
|
82
|
-
|
83
|
-
|
84
|
-
{
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
112
|
+
include Representable::JSON::Hash
|
113
|
+
|
114
|
+
values :extend => lambda { |item| item.is_a?(Array) ? LinkArrayRepresenter : Roar::Representer::JSON::HyperlinkRepresenter },
|
115
|
+
:class => lambda { |hsh| hsh.is_a?(LinkArray) ? nil : Roar::Representer::Feature::Hypermedia::Hyperlink }
|
116
|
+
|
117
|
+
def to_hash(options)
|
118
|
+
super.tap do |hsh| # TODO: cool: super(:exclude => [:rel]).
|
119
|
+
hsh.each { |k,v| v.delete(:rel) }
|
89
120
|
end
|
90
121
|
end
|
91
122
|
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
123
|
+
|
124
|
+
def from_hash(hash, options={})
|
125
|
+
hash.each { |k,v| hash[k] = LinkArray.new(v) if is_array?(k) }
|
126
|
+
|
127
|
+
hsh = super(hash) # this is where :class and :extend do the work.
|
128
|
+
|
129
|
+
hsh.each { |k, v| v.rel = k }
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
class LinkArray < Array
|
134
|
+
def rel
|
135
|
+
first.rel
|
136
|
+
end
|
137
|
+
|
138
|
+
def rel=(rel)
|
139
|
+
each { |lnk| lnk.rel = rel }
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
require 'representable/json/collection'
|
144
|
+
module LinkArrayRepresenter
|
145
|
+
include Representable::JSON::Collection
|
146
|
+
|
147
|
+
items :extend => Roar::Representer::JSON::HyperlinkRepresenter,
|
148
|
+
:class => Roar::Representer::Feature::Hypermedia::Hyperlink
|
149
|
+
|
150
|
+
def to_hash(*)
|
151
|
+
super.tap do |ary|
|
152
|
+
ary.each { |lnk| rel = lnk.delete(:rel) }
|
96
153
|
end
|
97
|
-
self
|
98
154
|
end
|
99
155
|
end
|
100
|
-
|
101
|
-
|
156
|
+
|
157
|
+
|
102
158
|
module ClassMethods
|
159
|
+
# TODO: remove Links support in non-HAL.
|
103
160
|
def links_definition_options
|
104
|
-
super.tap { |options|
|
161
|
+
super.tap { |options|
|
162
|
+
options[0] = :links
|
163
|
+
options[1] = {:class => Feature::Hypermedia::LinkCollection, :extend => LinkCollectionRepresenter, :from => :_links}
|
164
|
+
}
|
165
|
+
|
166
|
+
end
|
167
|
+
|
168
|
+
# Use this to define link arrays. It accepts the shared rel attribute and an array of options per link object.
|
169
|
+
#
|
170
|
+
# links :self do
|
171
|
+
# [{:lang => "en", :href => "http://en.hit"},
|
172
|
+
# {:lang => "de", :href => "http://de.hit"}]
|
173
|
+
# end
|
174
|
+
def links(options, &block)
|
175
|
+
options = {:rel => options} if options.is_a?(Symbol)
|
176
|
+
options[:array] = true # FIXME: we need to save this information somewhere.
|
177
|
+
link(options, &block)
|
105
178
|
end
|
106
179
|
end
|
107
180
|
end
|
@@ -1,9 +1,4 @@
|
|
1
|
-
|
2
|
-
require 'faraday'
|
3
|
-
rescue LoadError
|
4
|
-
puts 'You must add faraday as a dependency to use the FaradayTransport'
|
5
|
-
end
|
6
|
-
require 'logger'
|
1
|
+
require 'faraday'
|
7
2
|
|
8
3
|
module Roar
|
9
4
|
module Representer
|
@@ -23,15 +18,15 @@ module Roar
|
|
23
18
|
end
|
24
19
|
|
25
20
|
def post_uri(uri, body, as)
|
26
|
-
build_connection(uri, as).post
|
21
|
+
build_connection(uri, as).post(nil, body)
|
27
22
|
end
|
28
23
|
|
29
24
|
def put_uri(uri, body, as)
|
30
|
-
build_connection(uri, as).put
|
25
|
+
build_connection(uri, as).put(nil, body)
|
31
26
|
end
|
32
27
|
|
33
28
|
def patch_uri(uri, body, as)
|
34
|
-
build_connection(uri, as).patch
|
29
|
+
build_connection(uri, as).patch(nil, body)
|
35
30
|
end
|
36
31
|
|
37
32
|
def delete_uri(uri, as)
|
@@ -43,9 +38,8 @@ module Roar
|
|
43
38
|
def build_connection(uri, as)
|
44
39
|
::Faraday::Connection.new(
|
45
40
|
:url => uri,
|
46
|
-
:headers => { :accept => as }
|
41
|
+
:headers => { :accept => as, :content_type => as }
|
47
42
|
) do |builder|
|
48
|
-
# builder.use Faraday::Response::Logger, Logger.new('faraday.log')
|
49
43
|
builder.use ::Faraday::Response::RaiseError
|
50
44
|
builder.adapter ::Faraday.default_adapter
|
51
45
|
end
|
@@ -11,23 +11,23 @@ module Roar
|
|
11
11
|
def get_uri(uri, as)
|
12
12
|
do_request(Net::HTTP::Get, uri, as)
|
13
13
|
end
|
14
|
-
|
14
|
+
|
15
15
|
def post_uri(uri, body, as)
|
16
16
|
do_request(Net::HTTP::Post, uri, as, body)
|
17
17
|
end
|
18
|
-
|
18
|
+
|
19
19
|
def put_uri(uri, body, as)
|
20
20
|
do_request(Net::HTTP::Put, uri, as, body)
|
21
21
|
end
|
22
|
-
|
22
|
+
|
23
23
|
def patch_uri(uri, body, as)
|
24
24
|
do_request(Net::HTTP::Patch, uri, as, body)
|
25
25
|
end
|
26
|
-
|
26
|
+
|
27
27
|
def delete_uri(uri, as)
|
28
28
|
do_request(Net::HTTP::Delete, uri, as)
|
29
29
|
end
|
30
|
-
|
30
|
+
|
31
31
|
private
|
32
32
|
def do_request(what, uri, as, body="")
|
33
33
|
# DISCUSS: can this be made easier?
|
data/lib/roar/representer/xml.rb
CHANGED
@@ -16,42 +16,42 @@ module Roar
|
|
16
16
|
include InstanceMethods # otherwise Representable overrides our #to_xml.
|
17
17
|
end
|
18
18
|
end
|
19
|
-
|
19
|
+
|
20
20
|
module InstanceMethods
|
21
21
|
def to_xml(*args)
|
22
22
|
before_serialize(*args)
|
23
23
|
super
|
24
24
|
end
|
25
|
-
|
25
|
+
|
26
26
|
# Generic entry-point for rendering.
|
27
27
|
def serialize(*args)
|
28
28
|
to_xml(*args)
|
29
29
|
end
|
30
|
-
|
30
|
+
|
31
31
|
def deserialize(*args)
|
32
32
|
from_xml(*args)
|
33
33
|
end
|
34
34
|
end
|
35
|
-
|
36
|
-
|
35
|
+
|
36
|
+
|
37
37
|
module ClassMethods
|
38
38
|
include Representable::XML::ClassMethods
|
39
|
-
|
39
|
+
|
40
40
|
def links_definition_options
|
41
|
-
[:
|
41
|
+
[:links_array, {:from => :link, :class => Feature::Hypermedia::Hyperlink, :collection => true, :extend => XML::HyperlinkRepresenter}]
|
42
42
|
end
|
43
|
-
|
43
|
+
|
44
44
|
# Generic entry-point for parsing.
|
45
45
|
def deserialize(*args)
|
46
46
|
from_xml(*args)
|
47
47
|
end
|
48
48
|
end
|
49
|
-
|
50
|
-
|
49
|
+
|
50
|
+
|
51
51
|
require 'representable/xml/hash'
|
52
52
|
module HyperlinkRepresenter
|
53
53
|
include Representable::XML::AttributeHash
|
54
|
-
|
54
|
+
|
55
55
|
self.representation_wrap = :link
|
56
56
|
end
|
57
57
|
end
|
data/lib/roar/version.rb
CHANGED
data/roar.gemspec
CHANGED
@@ -18,9 +18,9 @@ Gem::Specification.new do |s|
|
|
18
18
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
19
19
|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
20
20
|
s.require_paths = ["lib"]
|
21
|
-
|
21
|
+
|
22
22
|
s.add_runtime_dependency "representable", ">= 1.2.8"
|
23
|
-
|
23
|
+
|
24
24
|
s.add_development_dependency "rake"
|
25
25
|
s.add_development_dependency "test_xml"
|
26
26
|
s.add_development_dependency "minitest", ">= 2.8.1"
|
data/test/client_test.rb
CHANGED
@@ -9,10 +9,10 @@ class ClientTest < MiniTest::Spec
|
|
9
9
|
property :name
|
10
10
|
property :band
|
11
11
|
end
|
12
|
-
|
12
|
+
|
13
13
|
@song = Object.new.extend(@representer)
|
14
14
|
end
|
15
|
-
|
15
|
+
|
16
16
|
it "should add accessors" do
|
17
17
|
@song.extend Roar::Representer::Feature::Client
|
18
18
|
@song.name = "Social Suicide"
|
@@ -6,10 +6,10 @@ class CoercionFeatureTest < MiniTest::Spec
|
|
6
6
|
class ImmigrantSong
|
7
7
|
include Roar::Representer::JSON
|
8
8
|
include Roar::Representer::Feature::Coercion
|
9
|
-
|
9
|
+
|
10
10
|
property :composed_at, :type => DateTime, :default => "May 12th, 2012"
|
11
11
|
end
|
12
|
-
|
12
|
+
|
13
13
|
it "coerces into the provided type" do
|
14
14
|
song = ImmigrantSong.new.from_json("{\"composed_at\":\"November 18th, 1983\"}")
|
15
15
|
assert_equal DateTime.parse("Fri, 18 Nov 1983 00:00:00 +0000"), song.composed_at
|
@@ -2,26 +2,26 @@ require 'roar/rails'
|
|
2
2
|
|
3
3
|
class AlbumsController < ActionController::Base
|
4
4
|
include Roar::Rails::ControllerMethods
|
5
|
-
|
5
|
+
|
6
6
|
respond_to :xml
|
7
7
|
represents Album
|
8
|
-
|
8
|
+
|
9
9
|
def show
|
10
10
|
@album = Album.find(params[:id])
|
11
11
|
respond_with @album
|
12
12
|
end
|
13
|
-
|
13
|
+
|
14
14
|
def create
|
15
15
|
@album = Album.create(representation)
|
16
|
-
|
16
|
+
|
17
17
|
respond_with @album
|
18
18
|
end
|
19
|
-
|
19
|
+
|
20
20
|
def update
|
21
21
|
@album = Album.find(params[:id])
|
22
22
|
@album.songs.delete_all # make PUT behave REST-compliant.
|
23
23
|
@album.update_attributes(representation)
|
24
|
-
|
24
|
+
|
25
25
|
respond_with @album
|
26
26
|
end
|
27
27
|
end
|