roar 1.0.1 → 1.0.2
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/.travis.yml +1 -0
- data/CHANGES.markdown +10 -1
- data/Gemfile +0 -3
- data/README.markdown +32 -6
- data/gemfiles/Gemfile.representable-1.7 +6 -0
- data/gemfiles/Gemfile.representable-1.8 +6 -0
- data/gemfiles/Gemfile.representable-head +6 -0
- data/lib/roar/coercion.rb +2 -2
- data/lib/roar/hypermedia.rb +1 -1
- data/lib/roar/json/hal.rb +17 -18
- data/lib/roar/json/json_api.rb +5 -0
- data/lib/roar/version.rb +1 -1
- data/test/collection_json_test.rb +103 -101
- data/test/hal_json_test.rb +32 -1
- data/test/integration/runner.rb +13 -6
- data/test/integration/ssl_server.rb +1 -0
- data/test/json_api_test.rb +41 -0
- metadata +7 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c60a365b03b4c4196033eccc186b649c50f8f40a
|
4
|
+
data.tar.gz: 4e5dfbfe2caa91f334c2568d6a563c223776cdab
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f2ea14d0d3b644f2f0f4c0677e35419a91955e97f6357a283a2f21206c19a35fd19ef8c166f3b4540449fc09cf3c70ab54688c4266bfca1aa00c2a33bf6e3769
|
7
|
+
data.tar.gz: ee6b42fc8b33f3e21955d6ee4ba658a4903503c4208cfc766017123ddceb802a906c759a845dbe9e9a202cd3465f0ad9db5e1c835a61adeb420a2f4308a0d07b
|
data/.travis.yml
CHANGED
data/CHANGES.markdown
CHANGED
@@ -1,3 +1,12 @@
|
|
1
|
+
# 1.0.2
|
2
|
+
|
3
|
+
* Roar runs on Rubinius.
|
4
|
+
|
5
|
+
## JSON::HAL
|
6
|
+
|
7
|
+
* `"_embedded"` will always be rendered before `"_links"`.
|
8
|
+
* `render_nil: false` is now respected.
|
9
|
+
|
1
10
|
# 1.0.1
|
2
11
|
|
3
12
|
* Allow calling `::has_one`, `::links` and `::has_many` in any order in JSON-API. This requires representable >= 2.1.4.
|
@@ -14,7 +23,7 @@
|
|
14
23
|
|
15
24
|
## Added
|
16
25
|
|
17
|
-
* `Roar::JSON::
|
26
|
+
* `Roar::JSON::JSONAPI` supports JSON-API. A big thanks to @oliverbarnes for his continous help, support and research on how to implement this standard.
|
18
27
|
|
19
28
|
|
20
29
|
## Relevant
|
data/Gemfile
CHANGED
@@ -3,8 +3,5 @@ source "http://rubygems.org"
|
|
3
3
|
# Specify your gem's dependencies in roar.gemspec
|
4
4
|
gemspec
|
5
5
|
|
6
|
-
# gem "representable", "~> 2.1.0"
|
7
|
-
gem "representable", :path => "../representable"
|
8
|
-
|
9
6
|
# as long as this is not merged, i'll vendor the runner file.
|
10
7
|
# gem "sinatra-contrib", :git => "git@github.com:apotonick/sinatra-contrib.git", :branch => "runner"
|
data/README.markdown
CHANGED
@@ -2,6 +2,8 @@
|
|
2
2
|
|
3
3
|
_Resource-Oriented Architectures in Ruby._
|
4
4
|
|
5
|
+
[](https://travis-ci.org/apotonick/roar)
|
6
|
+
|
5
7
|
## Introduction
|
6
8
|
|
7
9
|
Roar is a framework for parsing and rendering REST documents. Nothing more.
|
@@ -24,6 +26,30 @@ Roar is just a thin layer on top of the [representable](https://github.com/apoto
|
|
24
26
|
|
25
27
|
If in need for a feature, make sure to check the [representable API docs](https://github.com/apotonick/representable) first.
|
26
28
|
|
29
|
+
## Installation
|
30
|
+
|
31
|
+
The roar gem runs with all Ruby versions >= 1.9.3.
|
32
|
+
|
33
|
+
```ruby
|
34
|
+
gem 'roar'
|
35
|
+
```
|
36
|
+
|
37
|
+
### Dependencies
|
38
|
+
|
39
|
+
Roar does not bundle dependencies for JSON and XML.
|
40
|
+
|
41
|
+
If you want to use JSON, add the following to your Gemfile:
|
42
|
+
|
43
|
+
```ruby
|
44
|
+
gem 'multi_json'
|
45
|
+
```
|
46
|
+
|
47
|
+
If you want to use XML, add the following to your Gemfile:
|
48
|
+
|
49
|
+
```ruby
|
50
|
+
gem 'nokogiri'
|
51
|
+
```
|
52
|
+
|
27
53
|
|
28
54
|
## Defining Representers
|
29
55
|
|
@@ -375,7 +401,7 @@ module SongRepresenter
|
|
375
401
|
end
|
376
402
|
```
|
377
403
|
|
378
|
-
Documentation for HAL can be found in the [API docs](http://rdoc.info/github/apotonick/roar/Roar/
|
404
|
+
Documentation for HAL can be found in the [API docs](http://rdoc.info/github/apotonick/roar/Roar/JSON/HAL).
|
379
405
|
|
380
406
|
Make sure you [understand the different contexts](#hypermedia) for links when using decorators.
|
381
407
|
|
@@ -418,7 +444,7 @@ album.to_json
|
|
418
444
|
|
419
445
|
HAL keys nested resources under the `_embedded` key and then by their type.
|
420
446
|
|
421
|
-
All HAL features in Roar are discussed in the [API docs](http://rdoc.info/github/apotonick/roar/Roar/
|
447
|
+
All HAL features in Roar are discussed in the [API docs](http://rdoc.info/github/apotonick/roar/Roar/JSON/HAL), including [array links](https://github.com/apotonick/roar/blob/master/lib/roar/json/hal.rb#L196).
|
422
448
|
|
423
449
|
|
424
450
|
## JSON-API
|
@@ -662,7 +688,7 @@ As `GET` is not supposed to send any data, you can use `#get` on an empty object
|
|
662
688
|
Roar supports SSL connections - they are automatically detected via the protocol.
|
663
689
|
|
664
690
|
```ruby
|
665
|
-
song.get(uri: "https://localhost:4567/songs/1")
|
691
|
+
song.get(uri: "https://localhost:4567/songs/1")
|
666
692
|
```
|
667
693
|
|
668
694
|
### Basic Authentication
|
@@ -713,8 +739,8 @@ Roar also comes with XML support.
|
|
713
739
|
|
714
740
|
```ruby
|
715
741
|
module SongRepresenter
|
716
|
-
include Roar::
|
717
|
-
include Roar::
|
742
|
+
include Roar::XML
|
743
|
+
include Roar::Hypermedia
|
718
744
|
|
719
745
|
property :title
|
720
746
|
property :id
|
@@ -725,7 +751,7 @@ module SongRepresenter
|
|
725
751
|
end
|
726
752
|
```
|
727
753
|
|
728
|
-
Include the `Roar::
|
754
|
+
Include the `Roar::XML` engine and get bi-directional XML for your objects.
|
729
755
|
|
730
756
|
```ruby
|
731
757
|
song = Song.new(title: "Roxanne", id: 42)
|
data/lib/roar/coercion.rb
CHANGED
@@ -5,8 +5,8 @@ require 'representable/coercion'
|
|
5
5
|
module Roar
|
6
6
|
# Use the +:type+ option to specify the conversion type.
|
7
7
|
# class ImmigrantSong
|
8
|
-
# include Roar::
|
9
|
-
# include Roar::
|
8
|
+
# include Roar::JSON
|
9
|
+
# include Roar::Coercion
|
10
10
|
#
|
11
11
|
# property :composed_at, :type => DateTime, :default => "May 12th, 2012"
|
12
12
|
# end
|
data/lib/roar/hypermedia.rb
CHANGED
data/lib/roar/json/hal.rb
CHANGED
@@ -16,7 +16,7 @@ module Roar
|
|
16
16
|
# Example:
|
17
17
|
#
|
18
18
|
# module OrderRepresenter
|
19
|
-
# include Roar::
|
19
|
+
# include Roar::JSON::HAL
|
20
20
|
#
|
21
21
|
# property :id
|
22
22
|
# collection :items, :class => Item, :extend => ItemRepresenter, :embedded => true
|
@@ -48,27 +48,26 @@ module Roar
|
|
48
48
|
include Links # overwrites #links_definition_options.
|
49
49
|
extend ClassMethods # overwrites #links_definition_options, again.
|
50
50
|
include Resources
|
51
|
-
|
52
|
-
def representable_mapper(*) # TODO: make this easier to override.
|
53
|
-
super.tap do |map|
|
54
|
-
map.extend Resources
|
55
|
-
end
|
56
|
-
end
|
57
51
|
end
|
58
52
|
end
|
59
53
|
|
60
54
|
module Resources
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
55
|
+
def to_hash(*)
|
56
|
+
super.tap do |hash|
|
57
|
+
embedded = {}
|
58
|
+
representable_attrs.find_all do |dfn|
|
59
|
+
next unless dfn[:embedded] and fragment = hash.delete(dfn.name)
|
60
|
+
embedded[dfn.name] = fragment
|
61
|
+
end
|
62
|
+
|
63
|
+
hash["_embedded"] = embedded if embedded.any?
|
64
|
+
hash["_links"] = hash.delete("_links") if hash["_links"] # always render _links after _embedded.
|
65
|
+
end
|
66
66
|
end
|
67
67
|
|
68
|
-
def
|
69
|
-
|
70
|
-
|
71
|
-
super(bin, doc["_embedded"] || {})
|
68
|
+
def from_hash(hash, *)
|
69
|
+
hash.fetch("_embedded", []).each { |name, fragment| hash[name] = fragment }
|
70
|
+
super
|
72
71
|
end
|
73
72
|
end
|
74
73
|
|
@@ -93,8 +92,8 @@ module Roar
|
|
93
92
|
# following the HAL specification: http://stateless.co/hal_specification.html
|
94
93
|
#
|
95
94
|
# module SongRepresenter
|
96
|
-
# include Roar::
|
97
|
-
# include Roar::
|
95
|
+
# include Roar::JSON
|
96
|
+
# include Roar::JSON::HAL::Links
|
98
97
|
#
|
99
98
|
# link :self { "http://self" }
|
100
99
|
# end
|
data/lib/roar/json/json_api.rb
CHANGED
@@ -14,6 +14,11 @@ module Roar
|
|
14
14
|
extend ForCollection
|
15
15
|
|
16
16
|
representable_attrs[:resource_representer] = Class.new(Resource::Representer)
|
17
|
+
|
18
|
+
private
|
19
|
+
def create_representation_with(doc, options, format)
|
20
|
+
super(doc, options.merge(:only_body => true), format)
|
21
|
+
end
|
17
22
|
end
|
18
23
|
end
|
19
24
|
|
data/lib/roar/version.rb
CHANGED
@@ -1,130 +1,132 @@
|
|
1
1
|
require 'test_helper'
|
2
2
|
require 'roar/json/collection_json'
|
3
3
|
|
4
|
-
|
5
|
-
|
4
|
+
if RUBY_ENGINE != "rbx"
|
5
|
+
class CollectionJsonTest < MiniTest::Spec
|
6
|
+
let(:song) { OpenStruct.new(:title => "scarifice", :length => 43) }
|
6
7
|
|
7
|
-
|
8
|
-
|
9
|
-
|
8
|
+
representer_for([Roar::JSON::CollectionJSON]) do
|
9
|
+
version "1.0"
|
10
|
+
href { "//songs/" }
|
10
11
|
|
11
|
-
|
12
|
+
link(:feed) { "//songs/feed" }
|
12
13
|
|
13
|
-
|
14
|
-
|
14
|
+
items(:class => Song) do
|
15
|
+
href { "//songs/scarifice" }
|
15
16
|
|
16
|
-
|
17
|
-
|
17
|
+
property :title, :prompt => "Song title"
|
18
|
+
property :length, :prompt => "Song length"
|
18
19
|
|
19
|
-
|
20
|
-
|
21
|
-
|
20
|
+
link(:download) { "//songs/scarifice.mp3" }
|
21
|
+
link(:stats) { "//songs/scarifice/stats" }
|
22
|
+
end
|
22
23
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
24
|
+
template do
|
25
|
+
property :title, :prompt => "Song title"
|
26
|
+
property :length, :prompt => "Song length"
|
27
|
+
end
|
27
28
|
|
28
|
-
|
29
|
-
|
30
|
-
|
29
|
+
queries do
|
30
|
+
link :search do
|
31
|
+
{:href => "//search", :data => [{:name => "q", :value => ""}]}
|
32
|
+
end
|
31
33
|
end
|
32
34
|
end
|
33
|
-
end
|
34
|
-
|
35
|
-
describe "#to_json" do
|
36
|
-
it "renders document" do
|
37
|
-
[song].extend(rpr).to_hash.must_equal(
|
38
|
-
{
|
39
|
-
"collection"=>{
|
40
|
-
"version"=>"1.0",
|
41
|
-
"href"=>"//songs/",
|
42
35
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
36
|
+
describe "#to_json" do
|
37
|
+
it "renders document" do
|
38
|
+
[song].extend(rpr).to_hash.must_equal(
|
39
|
+
{
|
40
|
+
"collection"=>{
|
41
|
+
"version"=>"1.0",
|
42
|
+
"href"=>"//songs/",
|
49
43
|
|
50
|
-
|
51
|
-
{"rel"=>"search", "href"=>"//search",
|
52
|
-
"data"=>[
|
53
|
-
{:name=>"q", :value=>""}
|
54
|
-
]
|
55
|
-
}
|
56
|
-
],
|
57
|
-
|
58
|
-
"items"=>[
|
59
|
-
{
|
60
|
-
"links"=>[
|
61
|
-
{"rel"=>"download", "href"=>"//songs/scarifice.mp3"},
|
62
|
-
{"rel"=>"stats", "href"=>"//songs/scarifice/stats"}
|
63
|
-
],
|
64
|
-
"href"=>"//songs/scarifice",
|
44
|
+
"template"=>{
|
65
45
|
:data=>[
|
66
|
-
{:name=>"title", :value=>
|
67
|
-
{:name=>"length", :value=>
|
46
|
+
{:name=>"title", :value=>nil},
|
47
|
+
{:name=>"length", :value=>nil}
|
68
48
|
]
|
69
|
-
}
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
49
|
+
},
|
50
|
+
|
51
|
+
"queries"=>[
|
52
|
+
{"rel"=>"search", "href"=>"//search",
|
53
|
+
"data"=>[
|
54
|
+
{:name=>"q", :value=>""}
|
55
|
+
]
|
56
|
+
}
|
57
|
+
],
|
58
|
+
|
59
|
+
"items"=>[
|
60
|
+
{
|
61
|
+
"links"=>[
|
62
|
+
{"rel"=>"download", "href"=>"//songs/scarifice.mp3"},
|
63
|
+
{"rel"=>"stats", "href"=>"//songs/scarifice/stats"}
|
64
|
+
],
|
65
|
+
"href"=>"//songs/scarifice",
|
66
|
+
:data=>[
|
67
|
+
{:name=>"title", :value=>"scarifice"},
|
68
|
+
{:name=>"length", :value=>43}
|
69
|
+
]
|
70
|
+
}
|
71
|
+
],
|
72
|
+
|
73
|
+
"links"=>[
|
74
|
+
{"rel"=>"feed", "href"=>"//songs/feed"}
|
75
|
+
]
|
76
|
+
}
|
77
|
+
})# %{{"collection":{"version":"1.0","href":"//songs/","items":[{"href":"//songs/scarifice","links":[{"rel":"download","href":"//songs/scarifice.mp3"},{"rel":"stats","href":"//songs/scarifice/stats"}],"data":[{"name":"title","value":"scarifice"},{"name":"length","value":43}]}],"template":{"data":[{"name":"title","value":null},{"name":"length","value":null}]},"queries":[{"rel":"search","href":"//search","data":[{"name":"q","value":""}]}],"links":[{"rel":"feed","href":"//songs/feed"}]}}}
|
78
|
+
end
|
77
79
|
end
|
78
|
-
end
|
79
80
|
|
80
|
-
|
81
|
-
|
81
|
+
describe "#from_json" do
|
82
|
+
subject { [].extend(rpr).from_json [song].extend(rpr).to_json }
|
82
83
|
|
83
|
-
|
84
|
-
|
85
|
-
|
84
|
+
it "provides #version" do
|
85
|
+
subject.version.must_equal "1.0"
|
86
|
+
end
|
86
87
|
|
87
|
-
|
88
|
-
|
89
|
-
|
88
|
+
it "provides #href" do
|
89
|
+
subject.href.must_equal link(:href => "//songs/")
|
90
|
+
end
|
90
91
|
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
92
|
+
it "provides #template" do
|
93
|
+
# DISCUSS: this might return a Template instance, soon.
|
94
|
+
subject.template.must_equal([
|
95
|
+
{"name"=>"title", "value"=>nil},
|
96
|
+
{"name"=>"length", "value"=>nil}])
|
97
|
+
end
|
97
98
|
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
99
|
+
it "provides #queries" do
|
100
|
+
# DISCUSS: this might return CollectionJSON::Hyperlink instances that support some kind of substitution operation for the :data attribute.
|
101
|
+
# FIXME: this is currently _not_ parsed!
|
102
|
+
subject.queries.must_equal([link(:rel => :search, :href=>"//search", :data=>[{:name=>"q", :value=>""}])])
|
103
|
+
end
|
103
104
|
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
105
|
+
it "provides #items" do
|
106
|
+
subject.items.must_equal([Song.new(:title => "scarifice", :length => "43")])
|
107
|
+
song = subject.items.first
|
108
|
+
song.title.must_equal "scarifice"
|
109
|
+
song.length.must_equal 43
|
110
|
+
song.links.must_equal("download" => link({:rel=>"download", :href=>"//songs/scarifice.mp3"}), "stats" => link({:rel=>"stats", :href=>"//songs/scarifice/stats"}))
|
111
|
+
song.href.must_equal link(:href => "//songs/scarifice")
|
112
|
+
end
|
112
113
|
|
113
|
-
|
114
|
-
|
114
|
+
it "provides #links" do
|
115
|
+
subject.links.must_equal({"feed" => link(:rel => "feed", :href => "//songs/feed")})
|
116
|
+
end
|
115
117
|
end
|
116
|
-
end
|
117
118
|
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
119
|
+
describe "template_representer#from_json" do
|
120
|
+
it "parses object" do
|
121
|
+
song = OpenStruct.new.extend(rpr.template_representer).from_hash(
|
122
|
+
"template"=>{
|
123
|
+
"data"=>[
|
124
|
+
{"name"=>"title", "value"=>"Black Star"},
|
125
|
+
{"name"=>"length", "value"=>"4.53"}
|
126
|
+
]
|
127
|
+
})
|
128
|
+
song.title.must_equal "Black Star"
|
129
|
+
end
|
128
130
|
end
|
129
131
|
end
|
130
132
|
end
|
data/test/hal_json_test.rb
CHANGED
@@ -126,8 +126,39 @@ class HalJsonTest < MiniTest::Spec
|
|
126
126
|
@album.links.must_equal nil
|
127
127
|
end
|
128
128
|
end
|
129
|
+
|
130
|
+
end
|
131
|
+
|
132
|
+
class JsonHalTest < MiniTest::Spec
|
133
|
+
Album = Struct.new(:artist, :songs)
|
134
|
+
Artist = Struct.new(:name)
|
135
|
+
Song = Struct.new(:title)
|
136
|
+
|
137
|
+
def self.representer!
|
138
|
+
super([Roar::JSON::HAL])
|
139
|
+
end
|
140
|
+
|
141
|
+
def representer
|
142
|
+
rpr
|
143
|
+
end
|
144
|
+
|
145
|
+
describe "render_nil: false" do
|
146
|
+
representer! do
|
147
|
+
property :artist, embedded: true, render_nil: false do
|
148
|
+
property :name
|
149
|
+
end
|
150
|
+
|
151
|
+
collection :songs, embedded: true, render_empty: false do
|
152
|
+
property :title
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
it { Album.new(Artist.new("Bare, Jr."), [Song.new("Tobacco Spit")]).extend(representer).to_hash.must_equal({"_embedded"=>{"artist"=>{"name"=>"Bare, Jr."}, "songs"=>[{"title"=>"Tobacco Spit"}]}}) }
|
157
|
+
it { Album.new.extend(representer).to_hash.must_equal({}) }
|
158
|
+
end
|
129
159
|
end
|
130
160
|
|
161
|
+
|
131
162
|
class LinkCollectionTest < MiniTest::Spec
|
132
163
|
subject { Roar::JSON::HAL::LinkCollection.new([:self, "next"]) }
|
133
164
|
describe "#is_array?" do
|
@@ -157,4 +188,4 @@ class HalCurieTest < MiniTest::Spec
|
|
157
188
|
end
|
158
189
|
|
159
190
|
it { Object.new.extend(rpr).to_hash.must_equal({"_links"=>{"doc:self"=>{"href"=>"/"}, :curies=>[{"name"=>:doc, "href"=>"//docs/{rel}", "templated"=>true}]}}) }
|
160
|
-
end
|
191
|
+
end
|
data/test/integration/runner.rb
CHANGED
@@ -30,13 +30,20 @@ class SslServerRunner < ServerRunner
|
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
33
|
-
|
34
|
-
runner.
|
33
|
+
begin
|
34
|
+
runner = ServerRunner.new
|
35
|
+
runner.run
|
35
36
|
|
36
|
-
ssl_runner = SslServerRunner.new
|
37
|
-
ssl_runner.run
|
37
|
+
ssl_runner = SslServerRunner.new
|
38
|
+
ssl_runner.run
|
38
39
|
|
39
|
-
Minitest.after_run do
|
40
|
+
Minitest.after_run do
|
41
|
+
runner.kill
|
42
|
+
ssl_runner.kill
|
43
|
+
end
|
44
|
+
rescue Exception => e
|
40
45
|
runner.kill
|
41
46
|
ssl_runner.kill
|
42
|
-
|
47
|
+
|
48
|
+
raise e
|
49
|
+
end
|
data/test/json_api_test.rb
CHANGED
@@ -349,6 +349,47 @@ if Gem::Version.new(Representable::VERSION) >= Gem::Version.new("2.1.4") # TODO:
|
|
349
349
|
end
|
350
350
|
end
|
351
351
|
|
352
|
+
class CompoundCollectionUsingExtend < self
|
353
|
+
module SongRepresenter
|
354
|
+
include Roar::JSON::JSONAPI
|
355
|
+
|
356
|
+
type :songs
|
357
|
+
property :id
|
358
|
+
property :title
|
359
|
+
end
|
360
|
+
|
361
|
+
module AlbumRepresenter
|
362
|
+
include Roar::JSON::JSONAPI
|
363
|
+
|
364
|
+
type :albums
|
365
|
+
property :id
|
366
|
+
compound do
|
367
|
+
collection :songs, extend: SongRepresenter
|
368
|
+
end
|
369
|
+
end
|
370
|
+
|
371
|
+
let(:songs) do
|
372
|
+
struct = Struct.new(:id, :title)
|
373
|
+
[struct.new(1, 'Stand Up'), struct.new(2, 'Audition Mantra')]
|
374
|
+
end
|
375
|
+
|
376
|
+
let(:album) { Struct.new(:id, :songs).new(1, songs) }
|
377
|
+
|
378
|
+
subject { album.extend(AlbumRepresenter) }
|
379
|
+
|
380
|
+
# to_hash
|
381
|
+
it do
|
382
|
+
subject.to_hash.must_equal({
|
383
|
+
'albums' => { 'id' => 1 },
|
384
|
+
'linked' => {
|
385
|
+
'songs' => [
|
386
|
+
{'id' => 1, 'title' => 'Stand Up'},
|
387
|
+
{'id' => 2, 'title' => 'Audition Mantra'}
|
388
|
+
]
|
389
|
+
}
|
390
|
+
})
|
391
|
+
end
|
392
|
+
end
|
352
393
|
|
353
394
|
class ExplicitMeta < self
|
354
395
|
module Representer
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: roar
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nick Sutterer
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-09-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: representable
|
@@ -160,8 +160,11 @@ files:
|
|
160
160
|
- TODO.markdown
|
161
161
|
- examples/example.rb
|
162
162
|
- examples/example_server.rb
|
163
|
+
- gemfiles/Gemfile.representable-1.7
|
164
|
+
- gemfiles/Gemfile.representable-1.8
|
163
165
|
- gemfiles/Gemfile.representable-2.0
|
164
166
|
- gemfiles/Gemfile.representable-2.1
|
167
|
+
- gemfiles/Gemfile.representable-head
|
165
168
|
- lib/roar.rb
|
166
169
|
- lib/roar/client.rb
|
167
170
|
- lib/roar/coercion.rb
|
@@ -227,8 +230,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
227
230
|
version: '0'
|
228
231
|
requirements: []
|
229
232
|
rubyforge_project:
|
230
|
-
rubygems_version: 2.
|
233
|
+
rubygems_version: 2.4.8
|
231
234
|
signing_key:
|
232
235
|
specification_version: 4
|
233
236
|
summary: Parse and render REST API documents using representers.
|
234
237
|
test_files: []
|
238
|
+
has_rdoc:
|