roar 0.11.9 → 0.11.10
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 +4 -0
- data/Gemfile +1 -1
- data/TODO.markdown +2 -1
- data/lib/roar/representer/feature/hypermedia.rb +40 -32
- data/lib/roar/representer/json/collection_json.rb +3 -3
- data/lib/roar/representer/json/hal.rb +16 -14
- data/lib/roar/version.rb +1 -1
- data/test/hal_links_test.rb +1 -1
- data/test/hypermedia_feature_test.rb +0 -36
- data/test/hypermedia_test.rb +95 -29
- metadata +2 -2
data/CHANGES.markdown
CHANGED
@@ -1,3 +1,7 @@
|
|
1
|
+
## 0.11.10
|
2
|
+
* Fix a syntax error for Ruby 1.8.
|
3
|
+
* Store link definitions in `representable_attrs(:links)` now and no longer in the `LinksDefinition` instance itself. removing `#links_definition` in favor of `#link_configs`.
|
4
|
+
|
1
5
|
## 0.11.9
|
2
6
|
|
3
7
|
* When using `Feature::Client` hyperlinks are no longer rendered in POST and PUT since we pass `links: false`.
|
data/Gemfile
CHANGED
data/TODO.markdown
CHANGED
@@ -1,3 +1,4 @@
|
|
1
1
|
* Add proxies, so nested models can be lazy-loaded.
|
2
2
|
* move #prepare_links! call to #_links or something so it doesn't need to be called in #serialize.
|
3
|
-
* alias Roar::Representer to Representer
|
3
|
+
* alias Roar::Representer to Representer
|
4
|
+
* remove #before_serialize and just overwrite #serialize
|
@@ -37,6 +37,7 @@ module Roar
|
|
37
37
|
module Hypermedia
|
38
38
|
def self.included(base)
|
39
39
|
base.extend ClassMethods
|
40
|
+
base.extend InheritableArray
|
40
41
|
end
|
41
42
|
|
42
43
|
def before_serialize(options={})
|
@@ -60,15 +61,19 @@ module Roar
|
|
60
61
|
ary.each { |lnk| links.add(lnk) }
|
61
62
|
end
|
62
63
|
|
63
|
-
|
64
|
-
|
65
|
-
|
64
|
+
module LinkConfigsMethod
|
65
|
+
def link_configs
|
66
|
+
representable_attrs.inheritable_array(:links)
|
67
|
+
end
|
66
68
|
end
|
67
69
|
|
70
|
+
include LinkConfigsMethod
|
71
|
+
|
72
|
+
private
|
68
73
|
# Setup hypermedia links by invoking their blocks. Usually called by #serialize.
|
69
74
|
def prepare_links!(*args)
|
70
75
|
# TODO: move this method to _links or something so it doesn't need to be called in #serialize.
|
71
|
-
compile_links_for(
|
76
|
+
compile_links_for(link_configs, *args).each do |lnk|
|
72
77
|
links.add(lnk) # TODO: move to LinkCollection.new.
|
73
78
|
end
|
74
79
|
end
|
@@ -117,42 +122,20 @@ module Roar
|
|
117
122
|
# Note that you're free to put decider logic into #link blocks, too.
|
118
123
|
def link(options, &block)
|
119
124
|
options = {:rel => options} if options.is_a?(Symbol)
|
120
|
-
|
125
|
+
create_links_definition # this assures the links are rendered at the right position.
|
126
|
+
link_configs << [options, block]
|
121
127
|
end
|
122
128
|
|
129
|
+
include LinkConfigsMethod
|
130
|
+
|
123
131
|
private
|
124
132
|
def create_links_definition
|
125
|
-
representable_attrs
|
126
|
-
|
127
|
-
end
|
128
|
-
|
129
|
-
def links_definition
|
130
|
-
representable_attrs.find { |d| d.is_a?(LinksDefinition) } or create_links_definition
|
133
|
+
return if representable_attrs.find { |d| d.is_a?(LinksDefinition) }
|
134
|
+
representable_attrs << LinksDefinition.new(*links_definition_options)
|
131
135
|
end
|
132
136
|
end
|
133
137
|
|
134
|
-
|
135
138
|
class LinksDefinition < Representable::Definition
|
136
|
-
include Enumerable
|
137
|
-
|
138
|
-
attr_accessor :rel2block
|
139
|
-
def initialize(*)
|
140
|
-
super
|
141
|
-
@rel2block = []
|
142
|
-
end
|
143
|
-
|
144
|
-
def <<(args)
|
145
|
-
rel2block << args
|
146
|
-
end
|
147
|
-
|
148
|
-
def each(*args, &block)
|
149
|
-
rel2block.each(*args, &block)
|
150
|
-
end
|
151
|
-
|
152
|
-
# DISCUSS: where do we need this?
|
153
|
-
def clone
|
154
|
-
super.tap { |d| d.rel2block = rel2block.clone }
|
155
|
-
end
|
156
139
|
end
|
157
140
|
|
158
141
|
|
@@ -171,6 +154,31 @@ module Roar
|
|
171
154
|
marshal_load(hash.inject({}) { |h, (k,v)| h[k.to_sym] = v; h })
|
172
155
|
end
|
173
156
|
end
|
157
|
+
|
158
|
+
# TODO: move to separate module
|
159
|
+
# DISCUSS: experimental. this will soon be moved to a separate gem
|
160
|
+
module InheritableArray
|
161
|
+
def representable_attrs
|
162
|
+
super.extend(ConfigExtensions)
|
163
|
+
end
|
164
|
+
|
165
|
+
module ConfigExtensions
|
166
|
+
def inheritable_array(name)
|
167
|
+
inheritable_arrays[name] ||= []
|
168
|
+
end
|
169
|
+
def inheritable_arrays
|
170
|
+
@inheritable_arrays ||= {}
|
171
|
+
end
|
172
|
+
|
173
|
+
def inherit(parent)
|
174
|
+
super
|
175
|
+
|
176
|
+
parent.inheritable_arrays.keys.each do |k|
|
177
|
+
inheritable_array(k).push *parent.inheritable_array(k).clone
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
174
182
|
end
|
175
183
|
end
|
176
184
|
end
|
@@ -23,7 +23,7 @@ module Roar::Representer::JSON
|
|
23
23
|
|
24
24
|
collection :queries, :extend => Roar::Representer::JSON::HyperlinkRepresenter
|
25
25
|
def queries
|
26
|
-
compile_links_for(representable_attrs.collection_representers[:queries].
|
26
|
+
compile_links_for(representable_attrs.collection_representers[:queries].link_configs)
|
27
27
|
end
|
28
28
|
def queries=(v)
|
29
29
|
end
|
@@ -43,7 +43,7 @@ module Roar::Representer::JSON
|
|
43
43
|
|
44
44
|
property :__href, :as => :href
|
45
45
|
def __href
|
46
|
-
compile_links_for(representable_attrs.collection_representers[:href].
|
46
|
+
compile_links_for(representable_attrs.collection_representers[:href].link_configs).first.href
|
47
47
|
end
|
48
48
|
|
49
49
|
|
@@ -119,7 +119,7 @@ module Roar::Representer::JSON
|
|
119
119
|
# TODO: share with main module!
|
120
120
|
property :__href, :as => :href
|
121
121
|
def __href
|
122
|
-
compile_links_for(representable_attrs.collection_representers[:href].
|
122
|
+
compile_links_for(representable_attrs.collection_representers[:href].link_configs).first.href
|
123
123
|
end
|
124
124
|
def __href=(v)
|
125
125
|
@__href = Roar::Representer::Feature::Hypermedia::Hyperlink.new(:href => v)
|
@@ -81,28 +81,28 @@ module Roar::Representer
|
|
81
81
|
module Links
|
82
82
|
def self.included(base)
|
83
83
|
base.class_eval do
|
84
|
+
extend Links::ClassMethods # ::links_definition_options
|
84
85
|
include Roar::Representer::Feature::Hypermedia
|
85
|
-
include InstanceMethods
|
86
|
-
extend Links::ClassMethods
|
86
|
+
include InstanceMethods
|
87
87
|
end
|
88
88
|
end
|
89
|
-
|
89
|
+
|
90
90
|
module InstanceMethods
|
91
91
|
private
|
92
92
|
def prepare_link_for(href, options)
|
93
93
|
return super(href, options) unless options[:array] # TODO: remove :array and use special instan
|
94
|
-
|
94
|
+
|
95
95
|
list = href.collect { |opts| Feature::Hypermedia::Hyperlink.new(opts.merge!(:rel => options[:rel])) }
|
96
96
|
LinkArray.new(list)
|
97
97
|
end
|
98
|
-
|
98
|
+
|
99
99
|
# TODO: move to LinksDefinition.
|
100
100
|
def link_array_rels
|
101
|
-
|
101
|
+
link_configs.collect { |cfg| cfg.first[:array] ? cfg.first[:rel] : nil }.compact
|
102
102
|
end
|
103
103
|
end
|
104
|
-
|
105
|
-
|
104
|
+
|
105
|
+
|
106
106
|
require 'representable/json/hash'
|
107
107
|
module LinkCollectionRepresenter
|
108
108
|
include Representable::JSON::Hash
|
@@ -115,11 +115,11 @@ module Roar::Representer
|
|
115
115
|
hsh.each { |k,v| v.delete(:rel) }
|
116
116
|
end
|
117
117
|
end
|
118
|
-
|
118
|
+
|
119
119
|
|
120
120
|
def from_hash(hash, options={})
|
121
121
|
hash.each { |k,v| hash[k] = LinkArray.new(v) if is_array?(k) }
|
122
|
-
|
122
|
+
|
123
123
|
hsh = super(hash) # this is where :class and :extend do the work.
|
124
124
|
|
125
125
|
hsh.each { |k, v| v.rel = k }
|
@@ -154,16 +154,18 @@ module Roar::Representer
|
|
154
154
|
module ClassMethods
|
155
155
|
def links_definition_options
|
156
156
|
[:links,
|
157
|
-
|
158
|
-
|
159
|
-
|
157
|
+
{
|
158
|
+
:from => :links,
|
159
|
+
:extend => HAL::Links::LinkCollectionRepresenter,
|
160
|
+
:instance => lambda { |hsh| LinkCollection.new(link_array_rels) } # defined in InstanceMethods as this is executed in represented context.
|
161
|
+
}
|
160
162
|
]
|
161
163
|
end
|
162
164
|
|
163
165
|
# Use this to define link arrays. It accepts the shared rel attribute and an array of options per link object.
|
164
166
|
#
|
165
167
|
# links :self do
|
166
|
-
# [{:lang => "en", :href => "http://en.hit"},
|
168
|
+
# [{:lang => "en", :href => "http://en.hit"},
|
167
169
|
# {:lang => "de", :href => "http://de.hit"}]
|
168
170
|
# end
|
169
171
|
def links(options, &block)
|
data/lib/roar/version.rb
CHANGED
data/test/hal_links_test.rb
CHANGED
@@ -18,7 +18,7 @@ class HalLinkTest < MiniTest::Spec
|
|
18
18
|
|
19
19
|
describe "#to_json" do
|
20
20
|
it "uses 'links' key" do
|
21
|
-
|
21
|
+
subject.to_json.must_equal "{\"links\":{\"self\":{\"href\":\"//songs\"}}}"
|
22
22
|
end
|
23
23
|
end
|
24
24
|
|
@@ -134,39 +134,3 @@ class LinkCollectionTest < MiniTest::Spec
|
|
134
134
|
end
|
135
135
|
end
|
136
136
|
end
|
137
|
-
|
138
|
-
class HyperlinkInheritanceTest < MiniTest::Spec
|
139
|
-
describe "when the base representer has a link" do
|
140
|
-
before do
|
141
|
-
module BaseRepresenter
|
142
|
-
include Roar::Representer::JSON
|
143
|
-
include Roar::Representer::Feature::Hypermedia
|
144
|
-
|
145
|
-
link(:base) { "http://base" }
|
146
|
-
end
|
147
|
-
|
148
|
-
module Foo
|
149
|
-
include Roar::Representer::JSON
|
150
|
-
include Roar::Representer::Feature::Hypermedia
|
151
|
-
include BaseRepresenter
|
152
|
-
|
153
|
-
link(:foo) { "http://foo" }
|
154
|
-
end
|
155
|
-
|
156
|
-
module Bar
|
157
|
-
include Roar::Representer::JSON
|
158
|
-
include Roar::Representer::Feature::Hypermedia
|
159
|
-
include BaseRepresenter
|
160
|
-
|
161
|
-
link(:bar) { "http://bar" }
|
162
|
-
end
|
163
|
-
end
|
164
|
-
|
165
|
-
it "should inherit parent links" do
|
166
|
-
foo = Object.new.extend(Foo)
|
167
|
-
|
168
|
-
assert_equal "{\"links\":[{\"rel\":\"base\",\"href\":\"http://base\"},{\"rel\":\"foo\",\"href\":\"http://foo\"}]}", foo.to_json
|
169
|
-
end
|
170
|
-
|
171
|
-
end
|
172
|
-
end
|
data/test/hypermedia_test.rb
CHANGED
@@ -1,6 +1,44 @@
|
|
1
1
|
require 'test_helper'
|
2
2
|
|
3
3
|
class HypermediaTest < MiniTest::Spec
|
4
|
+
describe "inheritance" do
|
5
|
+
before do
|
6
|
+
module BaseRepresenter
|
7
|
+
include Roar::Representer::JSON
|
8
|
+
include Roar::Representer::Feature::Hypermedia
|
9
|
+
|
10
|
+
link(:base) { "http://base" }
|
11
|
+
end
|
12
|
+
|
13
|
+
module Bar
|
14
|
+
include Roar::Representer::JSON
|
15
|
+
include Roar::Representer::Feature::Hypermedia
|
16
|
+
|
17
|
+
link(:bar) { "http://bar" }
|
18
|
+
end
|
19
|
+
|
20
|
+
module Foo
|
21
|
+
include Roar::Representer::JSON
|
22
|
+
include Roar::Representer::Feature::Hypermedia
|
23
|
+
include BaseRepresenter
|
24
|
+
include Bar
|
25
|
+
|
26
|
+
link(:foo) { "http://foo" }
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
it "inherits parent links" do
|
31
|
+
foo = Object.new.extend(Foo)
|
32
|
+
|
33
|
+
assert_equal "{\"links\":[{\"rel\":\"base\",\"href\":\"http://base\"},{\"rel\":\"bar\",\"href\":\"http://bar\"},{\"rel\":\"foo\",\"href\":\"http://foo\"}]}", foo.to_json
|
34
|
+
end
|
35
|
+
|
36
|
+
it "inherits links from all mixed-in representers" do
|
37
|
+
skip
|
38
|
+
Object.new.extend(BaseRepresenter).extend(Bar).to_json.must_equal "{\"links\":[{\"rel\":\"base\",\"href\":\"http://base\"},{\"rel\":\"bar\",\"href\":\"http://bar\"}]}"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
4
42
|
describe "#links_array" do
|
5
43
|
subject { Object.new.extend(rpr) }
|
6
44
|
|
@@ -89,35 +127,6 @@ class HypermediaTest < MiniTest::Spec
|
|
89
127
|
end
|
90
128
|
end
|
91
129
|
|
92
|
-
class LinksDefinitionTest < MiniTest::Spec
|
93
|
-
describe "LinksDefinition" do
|
94
|
-
subject { Roar::Representer::Feature::Hypermedia::LinksDefinition.new(:links) }
|
95
|
-
|
96
|
-
it "responds to #<<" do
|
97
|
-
subject << "arbitrary bullshit"
|
98
|
-
subject.to_a.must_equal ["arbitrary bullshit"]
|
99
|
-
end
|
100
|
-
|
101
|
-
it "responds to #each" do
|
102
|
-
subject.to_a.must_equal []
|
103
|
-
end
|
104
|
-
|
105
|
-
it "accepts options in constructor" do
|
106
|
-
assert_equal [], subject.rel2block
|
107
|
-
end
|
108
|
-
|
109
|
-
it "accepts configuration" do
|
110
|
-
subject.rel2block << {:rel => :self}
|
111
|
-
assert_equal [{:rel=>:self}], subject.rel2block
|
112
|
-
end
|
113
|
-
|
114
|
-
it "responds to #clone" do
|
115
|
-
subject.rel2block << {:rel => :self}
|
116
|
-
assert subject.clone.rel2block.object_id != subject.rel2block.object_id
|
117
|
-
end
|
118
|
-
end
|
119
|
-
end
|
120
|
-
|
121
130
|
class HyperlinkTest < MiniTest::Spec
|
122
131
|
describe "Hyperlink" do
|
123
132
|
subject { link(:rel => "self", "href" => "http://self", "data-whatever" => "Hey, @myabc") }
|
@@ -144,4 +153,61 @@ class HyperlinkTest < MiniTest::Spec
|
|
144
153
|
assert_equal ["rel:self", "href:http://self", "data-whatever:Hey, @myabc"], subject.collect { |k,v| "#{k}:#{v}" }
|
145
154
|
end
|
146
155
|
end
|
156
|
+
|
157
|
+
describe "Config inheritance" do
|
158
|
+
# TODO: this section will soon be moved to uber.
|
159
|
+
describe "inheritance when including" do
|
160
|
+
# TODO: test all the below issues AND if cloning works.
|
161
|
+
module TestMethods
|
162
|
+
def representer_for(modules=[Roar::Representer::Feature::Hypermedia, Representable], &block)
|
163
|
+
Module.new do
|
164
|
+
extend TestMethods
|
165
|
+
include *modules
|
166
|
+
module_exec(&block)
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
170
|
+
include TestMethods
|
171
|
+
|
172
|
+
it "inherits to uninitialized child" do
|
173
|
+
representer_for do # child
|
174
|
+
include(representer_for do # parent
|
175
|
+
representable_attrs.inheritable_array(:links) << "bar"
|
176
|
+
end)
|
177
|
+
end.representable_attrs.inheritable_array(:links).must_equal(["bar"])
|
178
|
+
end
|
179
|
+
|
180
|
+
it "works with uninitialized parent" do
|
181
|
+
representer_for do # child
|
182
|
+
representable_attrs.inheritable_array(:links) << "bar"
|
183
|
+
|
184
|
+
include(representer_for do # parent
|
185
|
+
end)
|
186
|
+
end.representable_attrs.inheritable_array(:links).must_equal(["bar"])
|
187
|
+
end
|
188
|
+
|
189
|
+
it "inherits when both are initialized" do
|
190
|
+
representer_for do # child
|
191
|
+
representable_attrs.inheritable_array(:links) << "bar"
|
192
|
+
|
193
|
+
include(representer_for do # parent
|
194
|
+
representable_attrs.inheritable_array(:links) << "stadium"
|
195
|
+
end)
|
196
|
+
end.representable_attrs.inheritable_array(:links).must_equal(["bar", "stadium"])
|
197
|
+
end
|
198
|
+
|
199
|
+
it "clones parent inheritables" do # FIXME: actually we don't clone here!
|
200
|
+
representer_for do # child
|
201
|
+
representable_attrs.inheritable_array(:links) << "bar"
|
202
|
+
|
203
|
+
include(parent = representer_for do # parent
|
204
|
+
representable_attrs.inheritable_array(:links) << "stadium"
|
205
|
+
end)
|
206
|
+
|
207
|
+
parent.representable_attrs.inheritable_array(:links) << "park" # modify parent array.
|
208
|
+
|
209
|
+
end.representable_attrs.inheritable_array(:links).must_equal(["bar", "stadium"])
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
147
213
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: roar
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.11.
|
4
|
+
version: 0.11.10
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-02-
|
12
|
+
date: 2013-02-23 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: representable
|