roar 0.11.9 → 0.11.10
Sign up to get free protection for your applications and to get access to all the features.
- 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
|