roar 0.12.9 → 1.0.0.beta1
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.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.travis.yml +8 -10
- data/CHANGES.markdown +24 -2
- data/Gemfile +5 -2
- data/README.markdown +132 -28
- data/TODO.markdown +9 -7
- data/examples/example.rb +2 -0
- data/examples/example_server.rb +19 -3
- data/gemfiles/Gemfile.representable-2.0 +5 -0
- data/gemfiles/Gemfile.representable-2.1 +5 -0
- data/lib/roar.rb +1 -1
- data/lib/roar/client.rb +38 -0
- data/lib/roar/{representer/feature/coercion.rb → coercion.rb} +2 -1
- data/lib/roar/decorator.rb +3 -11
- data/lib/roar/http_verbs.rb +88 -0
- data/lib/roar/hypermedia.rb +174 -0
- data/lib/roar/json.rb +55 -0
- data/lib/roar/json/collection.rb +3 -0
- data/lib/roar/{representer/json → json}/collection_json.rb +20 -20
- data/lib/roar/{representer/json → json}/hal.rb +33 -31
- data/lib/roar/json/hash.rb +3 -0
- data/lib/roar/json/json_api.rb +208 -0
- data/lib/roar/representer.rb +3 -36
- data/lib/roar/transport/faraday.rb +49 -0
- data/lib/roar/transport/net_http.rb +57 -0
- data/lib/roar/transport/net_http/request.rb +72 -0
- data/lib/roar/version.rb +1 -1
- data/lib/roar/xml.rb +54 -0
- data/roar.gemspec +5 -4
- data/test/client_test.rb +3 -3
- data/test/coercion_feature_test.rb +6 -3
- data/test/collection_json_test.rb +8 -10
- data/test/decorator_test.rb +27 -15
- data/test/faraday_http_transport_test.rb +13 -15
- data/test/hal_json_test.rb +16 -16
- data/test/hal_links_test.rb +3 -3
- data/test/http_verbs_test.rb +17 -22
- data/test/hypermedia_feature_test.rb +23 -45
- data/test/hypermedia_test.rb +11 -23
- data/test/integration/band_representer.rb +2 -2
- data/test/integration/runner.rb +4 -3
- data/test/integration/server.rb +13 -2
- data/test/integration/ssl_server.rb +1 -1
- data/test/json_api_test.rb +336 -0
- data/test/json_representer_test.rb +16 -12
- data/test/lib/runner.rb +134 -0
- data/test/lonely_test.rb +9 -0
- data/test/net_http_transport_test.rb +4 -4
- data/test/representer_test.rb +2 -2
- data/test/{lib/roar/representer/transport/net_http/request_test.rb → ssl_client_certs_test.rb} +43 -5
- data/test/test_helper.rb +12 -5
- data/test/xml_representer_test.rb +26 -166
- metadata +49 -29
- data/gemfiles/Gemfile.representable-1.7 +0 -6
- data/gemfiles/Gemfile.representable-1.8 +0 -6
- data/lib/roar/representer/feature/client.rb +0 -39
- data/lib/roar/representer/feature/http_verbs.rb +0 -95
- data/lib/roar/representer/feature/hypermedia.rb +0 -175
- data/lib/roar/representer/json.rb +0 -67
- data/lib/roar/representer/transport/faraday.rb +0 -50
- data/lib/roar/representer/transport/net_http.rb +0 -59
- data/lib/roar/representer/transport/net_http/request.rb +0 -75
- data/lib/roar/representer/xml.rb +0 -61
@@ -1,39 +0,0 @@
|
|
1
|
-
require "roar/representer/feature/http_verbs"
|
2
|
-
|
3
|
-
module Roar
|
4
|
-
# Automatically add accessors for properties and collections. Also mixes in HttpVerbs.
|
5
|
-
module Representer
|
6
|
-
module Feature
|
7
|
-
module Client
|
8
|
-
include HttpVerbs
|
9
|
-
|
10
|
-
def self.extended(base)
|
11
|
-
base.instance_eval do
|
12
|
-
representable_attrs.each do |attr|
|
13
|
-
next unless attr.instance_of? Representable::Definition # ignore hyperlinks etc for now.
|
14
|
-
name = attr.name
|
15
|
-
|
16
|
-
# TODO: could anyone please make this better?
|
17
|
-
instance_eval %Q{
|
18
|
-
def #{name}=(v)
|
19
|
-
@#{name} = v
|
20
|
-
end
|
21
|
-
|
22
|
-
def #{name}
|
23
|
-
@#{name}
|
24
|
-
end
|
25
|
-
}
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
# DISCUSS: should we just override #serialize here? otherwise if you later include Hypermedia, it'll run before that method.
|
31
|
-
def before_serialize(options={})
|
32
|
-
options[:links] ||= false
|
33
|
-
|
34
|
-
super(options)
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
@@ -1,95 +0,0 @@
|
|
1
|
-
require 'roar/representer/transport/net_http'
|
2
|
-
|
3
|
-
module Roar
|
4
|
-
# Gives HTTP-power to representers. They can serialize, send, process and deserialize HTTP-requests.
|
5
|
-
module Representer
|
6
|
-
module Feature
|
7
|
-
module HttpVerbs
|
8
|
-
|
9
|
-
class << self
|
10
|
-
attr_accessor :transport_engine
|
11
|
-
|
12
|
-
def included(base)
|
13
|
-
base.extend ClassMethods
|
14
|
-
end
|
15
|
-
end
|
16
|
-
self.transport_engine = ::Roar::Representer::Transport::NetHTTP
|
17
|
-
|
18
|
-
|
19
|
-
module ClassMethods
|
20
|
-
# GETs +url+ with +format+ and returns deserialized represented object.
|
21
|
-
def get(*args)
|
22
|
-
new.get(*args)
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
|
27
|
-
attr_writer :transport_engine
|
28
|
-
def transport_engine
|
29
|
-
@transport_engine || HttpVerbs.transport_engine
|
30
|
-
end
|
31
|
-
|
32
|
-
# Serializes the object, POSTs it to +url+ with +format+, deserializes the returned document
|
33
|
-
# and updates properties accordingly.
|
34
|
-
def post(*args, &block)
|
35
|
-
options = handle_deprecated_args(serialize, *args)
|
36
|
-
response = http.post_uri(options, &block)
|
37
|
-
handle_response(response)
|
38
|
-
end
|
39
|
-
|
40
|
-
# GETs +url+ with +format+, deserializes the returned document and updates properties accordingly.
|
41
|
-
def get(*args, &block)
|
42
|
-
response = http.get_uri(*args, &block)
|
43
|
-
handle_response(response)
|
44
|
-
end
|
45
|
-
|
46
|
-
# Serializes the object, PUTs it to +url+ with +format+, deserializes the returned document
|
47
|
-
# and updates properties accordingly.
|
48
|
-
def put(*args, &block)
|
49
|
-
options = handle_deprecated_args(serialize, *args)
|
50
|
-
response = http.put_uri(options, &block)
|
51
|
-
handle_response(response)
|
52
|
-
self
|
53
|
-
end
|
54
|
-
|
55
|
-
def patch(*args, &block)
|
56
|
-
options = handle_deprecated_args(serialize, *args)
|
57
|
-
response = http.patch_uri(options, &block)
|
58
|
-
handle_response(response)
|
59
|
-
self
|
60
|
-
end
|
61
|
-
|
62
|
-
def delete(*args, &block)
|
63
|
-
http.delete_uri(*args, &block)
|
64
|
-
self
|
65
|
-
end
|
66
|
-
|
67
|
-
private
|
68
|
-
def handle_response(response)
|
69
|
-
document = response.body
|
70
|
-
deserialize(document)
|
71
|
-
end
|
72
|
-
|
73
|
-
def http
|
74
|
-
transport_engine.new
|
75
|
-
end
|
76
|
-
|
77
|
-
def handle_deprecated_args(body, *args) # TODO: remove in 1.0.
|
78
|
-
options = args.first
|
79
|
-
|
80
|
-
if args.size > 1
|
81
|
-
warn %{DEPRECATION WARNING: #get, #post, #put, #delete and #patch no longer accept positional arguments. Please call them as follows:
|
82
|
-
get(uri: "http://localhost/songs", as: "application/json")
|
83
|
-
post(uri: "http://localhost/songs", as: "application/json")
|
84
|
-
Thank you and have a beautiful day.}
|
85
|
-
options = {:uri => args[0], :as => args[1]} if args.size == 2
|
86
|
-
options = {:uri => args[0], :as => args[2]}
|
87
|
-
end
|
88
|
-
|
89
|
-
options[:body] = body
|
90
|
-
options
|
91
|
-
end
|
92
|
-
end
|
93
|
-
end
|
94
|
-
end
|
95
|
-
end
|
@@ -1,175 +0,0 @@
|
|
1
|
-
module Roar
|
2
|
-
module Representer
|
3
|
-
module Feature
|
4
|
-
# Define hypermedia links in your representations.
|
5
|
-
#
|
6
|
-
# Example:
|
7
|
-
#
|
8
|
-
# class Order
|
9
|
-
# include Roar::Representer::JSON
|
10
|
-
#
|
11
|
-
# property :id
|
12
|
-
#
|
13
|
-
# link :self do
|
14
|
-
# "http://orders/#{id}"
|
15
|
-
# end
|
16
|
-
#
|
17
|
-
# If you want more attributes, just pass a hash to #link.
|
18
|
-
#
|
19
|
-
# link :rel => :next, :title => "Next, please!" do
|
20
|
-
# "http://orders/#{id}"
|
21
|
-
# end
|
22
|
-
#
|
23
|
-
# If you need dynamic attributes, the block can return a hash.
|
24
|
-
#
|
25
|
-
# link :preview do
|
26
|
-
# {:href => image.url, :title => image.name}
|
27
|
-
# end
|
28
|
-
#
|
29
|
-
# Sometimes you need values from outside when the representation links are rendered. Just pass them
|
30
|
-
# to the render method, they will be available as block parameters.
|
31
|
-
#
|
32
|
-
# link :self do |opts|
|
33
|
-
# "http://orders/#{opts[:id]}"
|
34
|
-
# end
|
35
|
-
#
|
36
|
-
# model.to_json(:id => 1)
|
37
|
-
module Hypermedia
|
38
|
-
def self.included(base)
|
39
|
-
base.extend ClassMethods
|
40
|
-
base.extend InheritableArray
|
41
|
-
end
|
42
|
-
|
43
|
-
def before_serialize(options={})
|
44
|
-
super(options) # Representer::Base
|
45
|
-
prepare_links!(options) unless options[:links] == false # DISCUSS: doesn't work when links are already setup (e.g. from #deserialize).
|
46
|
-
end
|
47
|
-
|
48
|
-
attr_writer :links
|
49
|
-
|
50
|
-
def links
|
51
|
-
@links ||= LinkCollection.new
|
52
|
-
end
|
53
|
-
|
54
|
-
def links_array
|
55
|
-
links.values # FIXME: move to LinkCollection#to_a.
|
56
|
-
end
|
57
|
-
|
58
|
-
def links_array=(ary)
|
59
|
-
# FIXME: move to LinkCollection
|
60
|
-
self.links= LinkCollection.new
|
61
|
-
ary.each { |lnk| links.add(lnk) }
|
62
|
-
end
|
63
|
-
|
64
|
-
module LinkConfigsMethod
|
65
|
-
def link_configs
|
66
|
-
representable_attrs.inheritable_array(:links)
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
include LinkConfigsMethod
|
71
|
-
|
72
|
-
private
|
73
|
-
def links_definition_options
|
74
|
-
# TODO: this method is never called.
|
75
|
-
[:links_array, {:as => :link, :class => Feature::Hypermedia::Hyperlink, :collection => true,
|
76
|
-
:decorator_scope => true}] # TODO: merge with JSON.
|
77
|
-
end
|
78
|
-
|
79
|
-
# Setup hypermedia links by invoking their blocks. Usually called by #serialize.
|
80
|
-
def prepare_links!(*args)
|
81
|
-
# TODO: move this method to _links or something so it doesn't need to be called in #serialize.
|
82
|
-
compile_links_for(link_configs, *args).each do |lnk|
|
83
|
-
links.add(lnk) # TODO: move to LinkCollection.new.
|
84
|
-
end
|
85
|
-
end
|
86
|
-
|
87
|
-
def compile_links_for(configs, *args)
|
88
|
-
configs.collect do |config|
|
89
|
-
options, block = config.first, config.last
|
90
|
-
href = run_link_block(block, *args) or next
|
91
|
-
|
92
|
-
prepare_link_for(href, options)
|
93
|
-
end.compact # FIXME: make this less ugly.
|
94
|
-
end
|
95
|
-
|
96
|
-
def prepare_link_for(href, options)
|
97
|
-
options = options.merge(href.is_a?(Hash) ? href : {:href => href})
|
98
|
-
Hyperlink.new(options)
|
99
|
-
end
|
100
|
-
|
101
|
-
def run_link_block(block, *args)
|
102
|
-
instance_exec(*args, &block)
|
103
|
-
end
|
104
|
-
|
105
|
-
|
106
|
-
class LinkCollection < Hash
|
107
|
-
# DISCUSS: make Link#rel return string always.
|
108
|
-
def [](rel)
|
109
|
-
self.fetch(rel.to_s, nil)
|
110
|
-
end
|
111
|
-
|
112
|
-
def add(link)
|
113
|
-
self[link.rel.to_s] = link
|
114
|
-
end
|
115
|
-
end
|
116
|
-
|
117
|
-
|
118
|
-
module ClassMethods
|
119
|
-
# Declares a hypermedia link in the document.
|
120
|
-
#
|
121
|
-
# Example:
|
122
|
-
#
|
123
|
-
# link :self do
|
124
|
-
# "http://orders/#{id}"
|
125
|
-
# end
|
126
|
-
#
|
127
|
-
# The block is executed in instance context, so you may call properties or other accessors.
|
128
|
-
# Note that you're free to put decider logic into #link blocks, too.
|
129
|
-
def link(options, &block)
|
130
|
-
options = {:rel => options} unless options.is_a?(Hash)
|
131
|
-
create_links_definition # this assures the links are rendered at the right position.
|
132
|
-
link_configs << [options, block]
|
133
|
-
end
|
134
|
-
|
135
|
-
include LinkConfigsMethod
|
136
|
-
|
137
|
-
private
|
138
|
-
def create_links_definition
|
139
|
-
return if representable_attrs.find { |d| d.is_a?(LinksDefinition) }
|
140
|
-
|
141
|
-
options = links_definition_options # TODO: remove in 1.0.
|
142
|
-
if Roar.representable_1_8?
|
143
|
-
opt = options.last
|
144
|
-
opt[:exec_context] = :decorator
|
145
|
-
opt.delete(:decorator_scope)
|
146
|
-
end
|
147
|
-
|
148
|
-
representable_attrs << LinksDefinition.new(*options)
|
149
|
-
end
|
150
|
-
end
|
151
|
-
|
152
|
-
class LinksDefinition < Representable::Definition
|
153
|
-
end
|
154
|
-
|
155
|
-
|
156
|
-
require "ostruct"
|
157
|
-
# An abstract hypermedia link with arbitrary attributes.
|
158
|
-
class Hyperlink < OpenStruct
|
159
|
-
include Enumerable
|
160
|
-
|
161
|
-
def each(*args, &block)
|
162
|
-
marshal_dump.each(*args, &block)
|
163
|
-
end
|
164
|
-
|
165
|
-
# FIXME: do we need this method any longer?
|
166
|
-
def replace(hash)
|
167
|
-
# #marshal_load requires symbol keys: http://apidock.com/ruby/v1_9_3_125/OpenStruct/marshal_load
|
168
|
-
marshal_load(hash.inject({}) { |h, (k,v)| h[k.to_sym] = v; h })
|
169
|
-
self
|
170
|
-
end
|
171
|
-
end
|
172
|
-
end
|
173
|
-
end
|
174
|
-
end
|
175
|
-
end
|
@@ -1,67 +0,0 @@
|
|
1
|
-
require 'roar/representer'
|
2
|
-
require 'roar/representer/feature/hypermedia'
|
3
|
-
require 'representable/json'
|
4
|
-
|
5
|
-
module Roar
|
6
|
-
require 'representable/version'
|
7
|
-
def self.representable_1_8? # TODO: remove me in 1.0.
|
8
|
-
Representable::VERSION =~ /^1.8/
|
9
|
-
end
|
10
|
-
|
11
|
-
module Representer
|
12
|
-
module JSON
|
13
|
-
def self.included(base)
|
14
|
-
base.class_eval do
|
15
|
-
include Representer
|
16
|
-
include Representable::JSON
|
17
|
-
|
18
|
-
extend ClassMethods
|
19
|
-
include InstanceMethods # otherwise Representable overrides our #to_json.
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
module InstanceMethods
|
24
|
-
def to_hash(*args)
|
25
|
-
before_serialize(*args)
|
26
|
-
super
|
27
|
-
end
|
28
|
-
|
29
|
-
def from_json(document, options={})
|
30
|
-
document = '{}' if document.nil? or document.empty?
|
31
|
-
|
32
|
-
super
|
33
|
-
end
|
34
|
-
|
35
|
-
# Generic entry-point for rendering.
|
36
|
-
def serialize(*args)
|
37
|
-
to_json(*args)
|
38
|
-
end
|
39
|
-
|
40
|
-
def deserialize(*args)
|
41
|
-
from_json(*args)
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
|
46
|
-
module ClassMethods
|
47
|
-
def deserialize(*args)
|
48
|
-
from_json(*args)
|
49
|
-
end
|
50
|
-
|
51
|
-
# TODO: move to instance method, or remove?
|
52
|
-
def links_definition_options
|
53
|
-
# FIXME: this doesn't belong into the generic JSON representer.
|
54
|
-
[:links_array, {:as => :links, :class => Feature::Hypermedia::Hyperlink, :extend => HyperlinkRepresenter, :collection => true,
|
55
|
-
:decorator_scope => true}]
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
|
60
|
-
require "representable/json/hash"
|
61
|
-
# Represents a hyperlink in standard roar+json hash representation.
|
62
|
-
module HyperlinkRepresenter
|
63
|
-
include Representable::JSON::Hash
|
64
|
-
end
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
@@ -1,50 +0,0 @@
|
|
1
|
-
require 'faraday'
|
2
|
-
|
3
|
-
module Roar
|
4
|
-
module Representer
|
5
|
-
module Transport
|
6
|
-
# Advanced implementation of the HTTP verbs with the Faraday HTTP library
|
7
|
-
# (which can, in turn, use adapters based on Net::HTTP or libcurl)
|
8
|
-
#
|
9
|
-
# Depending on how the Faraday middleware stack is configured, this
|
10
|
-
# Transport can support features such as HTTP error code handling,
|
11
|
-
# redirects, etc.
|
12
|
-
#
|
13
|
-
# @see http://rubydoc.info/gems/faraday/file/README.md Faraday README
|
14
|
-
class Faraday
|
15
|
-
|
16
|
-
def get_uri(uri, as, *args)
|
17
|
-
build_connection(uri, as).get
|
18
|
-
end
|
19
|
-
|
20
|
-
def post_uri(uri, body, as, *args)
|
21
|
-
build_connection(uri, as).post(nil, body)
|
22
|
-
end
|
23
|
-
|
24
|
-
def put_uri(uri, body, as, *args)
|
25
|
-
build_connection(uri, as).put(nil, body)
|
26
|
-
end
|
27
|
-
|
28
|
-
def patch_uri(uri, body, as, *args)
|
29
|
-
build_connection(uri, as).patch(nil, body)
|
30
|
-
end
|
31
|
-
|
32
|
-
def delete_uri(uri, as, *args)
|
33
|
-
build_connection(uri, as).delete
|
34
|
-
end
|
35
|
-
|
36
|
-
private
|
37
|
-
|
38
|
-
def build_connection(uri, as)
|
39
|
-
::Faraday::Connection.new(
|
40
|
-
:url => uri,
|
41
|
-
:headers => { :accept => as, :content_type => as }
|
42
|
-
) do |builder|
|
43
|
-
builder.use ::Faraday::Response::RaiseError
|
44
|
-
builder.adapter ::Faraday.default_adapter
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|