roar 1.0.2 → 1.1.1

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.
Files changed (52) hide show
  1. checksums.yaml +5 -5
  2. data/.github/ISSUE_TEMPLATE.md +20 -0
  3. data/.travis.yml +16 -11
  4. data/CHANGES.markdown +86 -57
  5. data/CONTRIBUTING.md +31 -0
  6. data/Gemfile +7 -4
  7. data/LICENSE +1 -1
  8. data/README.markdown +133 -255
  9. data/Rakefile +3 -1
  10. data/examples/example.rb +0 -0
  11. data/examples/example_server.rb +0 -0
  12. data/lib/roar/client.rb +8 -3
  13. data/lib/roar/decorator.rb +2 -2
  14. data/lib/roar/http_verbs.rb +0 -16
  15. data/lib/roar/hypermedia.rb +30 -56
  16. data/lib/roar/json/collection.rb +10 -2
  17. data/lib/roar/json/hal.rb +74 -83
  18. data/lib/roar/json.rb +5 -5
  19. data/lib/roar/version.rb +1 -1
  20. data/lib/roar/xml.rb +1 -1
  21. data/lib/roar.rb +3 -3
  22. data/roar.gemspec +7 -5
  23. data/test/client_test.rb +1 -1
  24. data/test/coercion_feature_test.rb +7 -2
  25. data/test/decorator_test.rb +17 -7
  26. data/test/hal_json_test.rb +101 -94
  27. data/test/hypermedia_feature_test.rb +13 -31
  28. data/test/hypermedia_test.rb +26 -92
  29. data/test/{decorator_client_test.rb → integration/decorator_client_test.rb} +5 -4
  30. data/test/{faraday_http_transport_test.rb → integration/faraday_http_transport_test.rb} +1 -0
  31. data/test/{http_verbs_test.rb → integration/http_verbs_test.rb} +3 -2
  32. data/test/integration/json_collection_test.rb +35 -0
  33. data/test/{net_http_transport_test.rb → integration/net_http_transport_test.rb} +1 -0
  34. data/test/integration/runner.rb +2 -3
  35. data/test/integration/server.rb +6 -0
  36. data/test/json_representer_test.rb +2 -29
  37. data/test/lonely_test.rb +1 -2
  38. data/test/ssl_client_certs_test.rb +1 -1
  39. data/test/test_helper.rb +21 -3
  40. data/test/xml_representer_test.rb +6 -5
  41. metadata +21 -37
  42. data/gemfiles/Gemfile.representable-1.7 +0 -6
  43. data/gemfiles/Gemfile.representable-1.8 +0 -6
  44. data/gemfiles/Gemfile.representable-2.0 +0 -5
  45. data/gemfiles/Gemfile.representable-2.1 +0 -5
  46. data/gemfiles/Gemfile.representable-head +0 -6
  47. data/lib/roar/json/collection_json.rb +0 -208
  48. data/lib/roar/json/json_api.rb +0 -233
  49. data/test/collection_json_test.rb +0 -132
  50. data/test/hal_links_test.rb +0 -31
  51. data/test/json_api_test.rb +0 -451
  52. data/test/lib/runner.rb +0 -134
data/README.markdown CHANGED
@@ -1,8 +1,47 @@
1
- # ROAR
1
+ # Roar
2
2
 
3
3
  _Resource-Oriented Architectures in Ruby._
4
4
 
5
- [![Build Status](https://travis-ci.org/apotonick/roar.svg?branch=master)](https://travis-ci.org/apotonick/roar)
5
+ [![Gitter Chat](https://badges.gitter.im/trailblazer/chat.svg)](https://gitter.im/trailblazer/chat)
6
+ [![TRB Newsletter](https://img.shields.io/badge/TRB-newsletter-lightgrey.svg)](http://trailblazer.to/newsletter/)
7
+ [![Build Status](https://travis-ci.org/trailblazer/roar.svg?branch=master)](https://travis-ci.org/trailblazer/roar)
8
+ [![Gem Version](https://badge.fury.io/rb/roar.svg)](http://badge.fury.io/rb/roar)
9
+
10
+ ## Table of Contents
11
+
12
+ * [Introduction](#introduction)
13
+ * [Representable](#representable)
14
+ * [Installation](#installation)
15
+ * [Dependencies](#dependencies)
16
+ * [Defining Representers](#defining-representers)
17
+ * [Rendering](#rendering)
18
+ * [Parsing](#parsing)
19
+ * [Module Representers](#module-representers)
20
+ * [Collections](#collections)
21
+ * [Nesting](#nesting)
22
+ * [Inline Representer](#inline-representer)
23
+ * [Syncing Objects](#syncing-objects)
24
+ * [Coercion](#coercion)
25
+ * [More Features](#more-features)
26
+ * [Hypermedia](#hypermedia)
27
+ * [Passing Options](#passing-options)
28
+ * [Specify Decorator](#specify-decorator)
29
+ * [Consuming Hypermedia](#consuming-hypermedia)
30
+ * [Media Formats](#media-formats)
31
+ * [HAL\-JSON](#hal-json)
32
+ * [Hypermedia](#hypermedia-1)
33
+ * [Nesting](#nesting-1)
34
+ * [JSON API](#json-api)
35
+ * [Client\-Side Support](#client-side-support)
36
+ * [HTTP Support](#http-support)
37
+ * [HTTPS](#https)
38
+ * [Basic Authentication](#basic-authentication)
39
+ * [Client SSL certificates](#client-ssl-certificates)
40
+ * [Request customization](#request-customization)
41
+ * [Error handling](#error-handling)
42
+ * [XML](#xml)
43
+ * [Support](#support)
44
+ * [License](#license)
6
45
 
7
46
  ## Introduction
8
47
 
@@ -10,21 +49,15 @@ Roar is a framework for parsing and rendering REST documents. Nothing more.
10
49
 
11
50
  Representers let you define your API document structure and semantics. They allow both rendering representations from your models _and_ parsing documents to update your Ruby objects. The bi-directional nature of representers make them interesting for both server and client usage.
12
51
 
13
- Roar comes with built-in JSON, JSON-HAL, JSON-API and XML support. Its highly modular architecture provides features like coercion, hypermedia, HTTP transport, client caching and more.
52
+ Roar comes with built-in JSON, JSON-HAL and XML support. JSON API support is available via the [JSON API](https://github.com/trailblazer/roar-jsonapi) gem. Its highly modular architecture provides features like coercion, hypermedia, HTTP transport, client caching and more.
14
53
 
15
- Roar is completely framework-agnostic and loves being used in web kits like Rails, Webmachine, Sinatra, Padrino, etc. If you use Rails, consider [roar-rails](https://github.com/apotonick/roar-rails) for an enjoyable integration.
16
-
17
- <a href="https://leanpub.com/trailblazer">
18
- ![](https://raw.githubusercontent.com/apotonick/trailblazer/master/doc/trb.jpg)
19
- </a>
20
-
21
- Roar is part of the [Trailblazer project](https://github.com/apotonick/trailblazer). Please [buy the book](https://leanpub.com/trailblazer) to support the development. Several chapters will be dedicated to Roar, its integration into operations, hypermedia formats and client-side usage.
54
+ Roar is completely framework-agnostic and loves being used in web kits like Rails, Hanami, Sinatra, Roda, etc. If you use Rails, consider [roar-rails](https://github.com/apotonick/roar-rails) for an enjoyable integration.
22
55
 
23
56
  ## Representable
24
57
 
25
- Roar is just a thin layer on top of the [representable](https://github.com/apotonick/representable) gem. While Roar gives you a DSL and behaviour for creating hypermedia APIs, representable implements all the mapping functionality.
58
+ Roar is just a thin layer on top of the [representable](https://github.com/trailblazer/representable) gem. While Roar gives you a DSL and behaviour for creating hypermedia APIs, representable implements all the mapping functionality.
26
59
 
27
- If in need for a feature, make sure to check the [representable API docs](https://github.com/apotonick/representable) first.
60
+ If in need for a feature, make sure to check the [representable API docs](https://github.com/trailblazer/representable) first.
28
61
 
29
62
  ## Installation
30
63
 
@@ -34,17 +67,23 @@ The roar gem runs with all Ruby versions >= 1.9.3.
34
67
  gem 'roar'
35
68
  ```
36
69
 
70
+ To use roar with Ruby versions < 2.2.0, add a version pin to your Gemfile:
71
+
72
+ ```ruby
73
+ gem 'sinatra', '~> 1.4'
74
+ ```
75
+
37
76
  ### Dependencies
38
77
 
39
78
  Roar does not bundle dependencies for JSON and XML.
40
79
 
41
- If you want to use JSON, add the following to your Gemfile:
80
+ If you want to use JSON, add the following to your `Gemfile`:
42
81
 
43
82
  ```ruby
44
83
  gem 'multi_json'
45
84
  ```
46
85
 
47
- If you want to use XML, add the following to your Gemfile:
86
+ If you want to use XML, add the following to your `Gemfile`:
48
87
 
49
88
  ```ruby
50
89
  gem 'nokogiri'
@@ -56,21 +95,22 @@ gem 'nokogiri'
56
95
  Let's see how representers work. They're fun to use.
57
96
 
58
97
  ```ruby
98
+ require 'roar/decorator'
59
99
  require 'roar/json'
60
100
 
61
- module SongRepresenter
101
+ class SongRepresenter < Roar::Decorator
62
102
  include Roar::JSON
63
103
 
64
104
  property :title
65
105
  end
66
106
  ```
67
107
 
68
- API documents are defined using a representer module or decorator class. You can define plain attributes using the `::property` method.
108
+ API documents are defined using a decorator class. You can define plain attributes using the `::property` method.
69
109
 
70
- Now let's assume we'd have `Song` which is an `ActiveRecord` class. Please note that Roar is not limited to ActiveRecord. In fact, it doesn't really care whether it's representing ActiveRecord, Datamapper or just an OpenStruct instance.
110
+ Now let's assume we'd have `Song` which is an `ActiveRecord` class. Please note that Roar is not limited to ActiveRecord. In fact, it doesn't really care whether it's representing ActiveRecord, `Sequel::Model` or just an OpenStruct instance.
71
111
 
72
112
  ```ruby
73
- class Song < ActiveRecord
113
+ class Song < ActiveRecord::Base
74
114
  end
75
115
  ```
76
116
 
@@ -79,66 +119,62 @@ end
79
119
  To render a document, you apply the representer to your model.
80
120
 
81
121
  ```ruby
82
- song = Song.new(title: "Fate")
83
- song.extend(SongRepresenter)
122
+ song = Song.new(title: "Medicine Balls")
84
123
 
85
- song.to_json #=> {"title":"Fate"}
124
+ SongRepresenter.new(song).to_json #=> {"title":"Medicine Balls"}
86
125
  ```
87
126
 
88
- Here, the representer is injected into the actual model and gives us a new `#to_json` method.
127
+ Here, the `song` objects gets wrapped (or "decorated") by the decorator. It is treated as immutable - Roar won't mix in any behaviour.
89
128
 
90
129
  ## Parsing
91
130
 
92
131
  The cool thing about representers is: they can be used for rendering and parsing. See how easy updating your model from a document is.
93
132
 
94
133
  ```ruby
95
- song = Song.new
96
- song.extend(SongRepresenter)
97
-
98
- song.from_json('{"title":"Linoleum"}')
134
+ song = Song.new(title: "Medicine Balls")
99
135
 
136
+ SongRepresenter.new(song).from_json('{"title":"Linoleum"}')
100
137
  song.title #=> Linoleum
101
138
  ```
102
139
 
103
- Again, `#from_json` comes from the representer and just updates the known properties.
104
-
105
140
  Unknown attributes in the parsed document are simply ignored, making half-baked solutions like `strong_parameters` redundant.
106
141
 
107
142
 
108
- ## Decorator
143
+ ## Module Representers
109
144
 
110
- Many people dislike `#extend` due to eventual performance issue or object pollution. If you're one of those, just go with a decorator representer. They almost work identical to the module approach we just discovered.
145
+ **Module Representers are deprecated in Roar 1.1 and will be removed in Roar 2.0.**
111
146
 
112
- ```ruby
113
- require 'roar/decorator'
147
+ In place of inheriting from `Roar::Decorator`, you can also extend a singleton object with a representer module. Decorators and module representers actually have identical features. You can parse, render, nest, go nuts with both of them.
114
148
 
115
- class SongRepresenter < Roar::Decorator
116
- include Roar::JSON
117
-
118
- property :title
119
- end
120
- ```
121
- In place of a module you use a class, the DSL inside is the same you already know.
122
149
 
123
150
  ```ruby
124
- song = Song.new(title: "Medicine Balls")
151
+ song = Song.new(title: "Fate")
152
+ song.extend(SongRepresenter)
125
153
 
126
- SongRepresenter.new(song).to_json #=> {"title":"Medicine Balls"}
154
+ song.to_json #=> {"title":"Fate"}
127
155
  ```
128
156
 
129
- Here, the `song` objects gets wrapped (or "decorated") by the decorator. It is treated as immutuable - Roar won't mix in any behaviour.
157
+ Here, the representer is injected into the actual model and gives us a new `#to_json` method.
130
158
 
131
- Note that decorators and representer modules have identical features. You can parse, render, nest, go nuts with both of them.
159
+ This also works both ways.
160
+
161
+ ```ruby
162
+ song = Song.new
163
+ song.extend(SongRepresenter)
164
+
165
+ song.from_json('{"title":"Fate"}')
166
+ song #=> {"title":"Fate"}
167
+ ```
132
168
 
133
- However, in this README we'll use modules to illustrate this framework.
169
+ It's worth noting though that many people dislike `#extend` due to well-known performance issues and object pollution. As such this approach is no longer recommended. In this README we'll use decorators to illustrate this library.
134
170
 
135
171
 
136
172
  ## Collections
137
173
 
138
- Roar (or rather representable) also allows to map collections in documents.
174
+ Roar (or rather representable) also allows mapping collections in documents.
139
175
 
140
176
  ```ruby
141
- module SongRepresenter
177
+ class SongRepresenter < Roar::Decorator
142
178
  include Roar::JSON
143
179
 
144
180
  property :title
@@ -150,9 +186,8 @@ Where `::property` knows how to handle plain attributes, `::collection` does lis
150
186
 
151
187
  ```ruby
152
188
  song = Song.new(title: "Roxanne", composers: ["Sting", "Stu Copeland"])
153
- song.extend(SongRepresenter)
154
189
 
155
- song.to_json #=> {"title":"Roxanne","composers":["Sting","Stu Copeland"]}
190
+ SongRepresenter.new(song).to_json #=> {"title":"Roxanne","composers":["Sting","Stu Copeland"]}
156
191
  ```
157
192
 
158
193
  And, yes, this also works for parsing: `from_json` will create and populate the array of the `composers` attribute.
@@ -163,7 +198,7 @@ And, yes, this also works for parsing: `from_json` will create and populate the
163
198
  Now what if we need to tackle with collections of `Song`s? We need to implement an `Album` class.
164
199
 
165
200
  ```ruby
166
- class Album < ActiveRecord
201
+ class Album < ActiveRecord::Base
167
202
  has_many :songs
168
203
  end
169
204
  ```
@@ -171,7 +206,7 @@ end
171
206
  Another representer to represent.
172
207
 
173
208
  ```ruby
174
- module AlbumRepresenter
209
+ class AlbumRepresenter < Roar::Decorator
175
210
  include Roar::JSON
176
211
 
177
212
  property :title
@@ -188,38 +223,35 @@ Consider the following object setup.
188
223
  ```ruby
189
224
  album = Album.new(title: "True North")
190
225
  album.songs << Song.new(title: "The Island")
191
- album.songs << Song.new(:title => "Changing Tide")
226
+ album.songs << Song.new(title: "Changing Tide")
192
227
  ```
193
228
 
194
229
  You apply the `AlbumRepresenter` and you get a nested document.
195
230
 
196
231
  ```ruby
197
- album.extend(AlbumRepresenter)
198
-
199
- album.to_json #=> {"title":"True North","songs":[{"title":"The Island"},{"title":"Changing Tide"}]}
232
+ AlbumRepresenter.new(album).to_json #=> {"title":"True North","songs":[{"title":"The Island"},{"title":"Changing Tide"}]}
200
233
  ```
201
234
 
202
235
  This works vice-versa.
203
236
 
204
237
  ```ruby
205
238
  album = Album.new
206
- album.extend(AlbumRepresenter)
207
239
 
208
- album.from_json('{"title":"Indestructible","songs":[{"title":"Tropical London"},{"title":"Roadblock"}]}')
240
+ AlbumRepresenter.new(album).from_json('{"title":"Indestructible","songs":[{"title":"Tropical London"},{"title":"Roadblock"}]}')
209
241
 
210
242
  puts album.songs[1] #=> #<Song title="Roadblock">
211
243
  ```
212
244
 
213
245
  The nesting of two representers can map composed object as you find them in many many APIs.
214
246
 
215
- In case you're after virtual nesting, where a nested block in your document still maps to the same outer object, [check out the `::nested` method](https://github.com/apotonick/representable#document-nesting).
247
+ In case you're after virtual nesting, where a nested block in your document still maps to the same outer object, [check out the `::nested` method](https://github.com/trailblazer/representable#document-nesting).
216
248
 
217
249
  ## Inline Representer
218
250
 
219
251
  Sometimes you don't wanna create two separate representers - although it makes them reusable across your app. Use inline representers if you're not intending this.
220
252
 
221
253
  ```ruby
222
- module AlbumRepresenter
254
+ class AlbumRepresenter < Roar::Decorator
223
255
  include Roar::JSON
224
256
 
225
257
  property :title
@@ -238,7 +270,7 @@ This will give you the same rendering and parsing behaviour as in the previous e
238
270
  Usually, when parsing, nested objects are created from scratch. If you want nested objects to be updated instead of being newly created, use `parse_strategy:`.
239
271
 
240
272
  ```ruby
241
- module AlbumRepresenter
273
+ class AlbumRepresenter < Roar::Decorator
242
274
  include Roar::JSON
243
275
 
244
276
  property :title
@@ -252,14 +284,14 @@ This will advise Roar to update existing `songs`.
252
284
  ```ruby
253
285
  album.songs[0].object_id #=> 81431220
254
286
 
255
- album.from_json('{"title":"True North","songs":[{"title":"Secret Society"},{"title":"Changing Tide"}]}')
287
+ AlbumRepresenter.new(album).from_json('{"title":"True North","songs":[{"title":"Secret Society"},{"title":"Changing Tide"}]}')
256
288
 
257
289
  album.songs[0].title #=> Secret Society
258
290
  album.songs[0].object_id #=> 81431220
259
291
  ```
260
292
  Roar didn't create a new `Song` instance but updated its attributes, only.
261
293
 
262
- We're currently [working on](https://github.com/apotonick/roar/issues/85) better strategies to easily implement `POST` and `PUT` semantics in your APIs without having to worry about the nitty-gritties.
294
+ We're currently [working on](https://github.com/trailblazer/roar/issues/85) better strategies to easily implement `POST` and `PUT` semantics in your APIs without having to worry about the nitty-gritties.
263
295
 
264
296
 
265
297
  ## Coercion
@@ -268,8 +300,9 @@ Roar provides coercion with the [virtus](https://github.com/solnic/virtus) gem.
268
300
 
269
301
  ```ruby
270
302
  require 'roar/coercion'
303
+ require 'roar/json'
271
304
 
272
- module SongRepresenter
305
+ class SongRepresenter < Roar::Decorator
273
306
  include Roar::JSON
274
307
  include Roar::Coercion
275
308
 
@@ -282,9 +315,8 @@ The `:type` option allows to set a virtus-compatible type.
282
315
 
283
316
  ```ruby
284
317
  song = Song.new
285
- song.extend(SongRepresenter)
286
318
 
287
- song.from_json('{"released_at":"1981/03/31"}')
319
+ SongRepresenter.new(song).from_json('{"released_at":"1981/03/31"}')
288
320
 
289
321
  song.released_at #=> 1981-03-31T00:00:00+00:00
290
322
  ```
@@ -292,7 +324,7 @@ song.released_at #=> 1981-03-31T00:00:00+00:00
292
324
 
293
325
  ## More Features
294
326
 
295
- Roar/representable gives you many more mapping features like [renaming attributes](https://github.com/apotonick/representable/#aliasing), [wrapping](https://github.com/apotonick/representable/#wrapping), [passing options](https://github.com/apotonick/representable/#passing-options), etc.
327
+ Roar/representable gives you many more mapping features like renaming attributes, wrapping, passing options, etc. See the [representable documentation](http://trailblazer.to/gems/representable/3.0/api.html) for a detailed explanation.
296
328
 
297
329
 
298
330
  ## Hypermedia
@@ -300,7 +332,7 @@ Roar/representable gives you many more mapping features like [renaming attribute
300
332
  Roar comes with built-in support for embedding and processing hypermedia in your documents.
301
333
 
302
334
  ```ruby
303
- module SongRepresenter
335
+ class SongRepresenter < Roar::Decorator
304
336
  include Roar::JSON
305
337
  include Roar::Hypermedia
306
338
 
@@ -328,8 +360,7 @@ end
328
360
  This will render links into your representation.
329
361
 
330
362
  ```ruby
331
- song.extend(SongRepresenter)
332
- song.to_json #=> {"title":"Roxanne","links":[{"rel":"self","href":"http://songs/Roxanne"}]}
363
+ SongRepresenter.new(song).to_json #=> {"title":"Roxanne","links":[{"rel":"self","href":"http://songs/Roxanne"}]}
333
364
  ```
334
365
 
335
366
  Per default, links are pushed into the hash using the `links` key. Link blocks are executed in represented context, allowing you to call any instance method of your model (here, we call `#title`).
@@ -342,7 +373,7 @@ Also, note that [roar-rails](https://github.com/apotonick/roar-rails) allows usi
342
373
  Sometimes you need more data in the link block. Data that's not available from the represented model.
343
374
 
344
375
  ```ruby
345
- module SongRepresenter
376
+ class SongRepresenter < Roar::Decorator
346
377
  include Roar::JSON
347
378
 
348
379
  property :title
@@ -356,20 +387,36 @@ end
356
387
  Pass this data to the rendering method.
357
388
 
358
389
  ```ruby
359
- song.to_json(base_url: "localhost:3001/")
390
+ representer = SongRepresenter.new(song)
391
+ representer.to_json(base_url: "localhost:3001/")
360
392
  ```
361
393
 
362
394
  Any options passed to `#to_json` will be available as block arguments in the link blocks.
363
395
 
364
396
 
397
+ ## Specify Decorator
398
+
399
+ If you have a property that is a separate class or model, you can specify a decorator for that property. Suppose there is a separate `Artist` model for an album. When the album is eagerly loaded, the artist model could be represented along with it.
400
+
401
+ ```ruby
402
+ class ArtistRepresenter < Roar::Decorator
403
+ property :name
404
+ end
405
+
406
+ class AlbumRepresenter < Roar::Decorator
407
+ # ..
408
+ property :artist, decorator: ArtistRepresenter
409
+ end
410
+ ```
411
+
365
412
  ## Consuming Hypermedia
366
413
 
367
414
  Since we defined hypermedia attributes in the representer we can also consume this hypermedia when we parse documents.
368
415
 
369
416
  ```ruby
370
- song.from_json('{"title":"Roxanne","links":[{"rel":"self","href":"http://songs/Roxanne"}]}')
417
+ representer.from_json('{"title":"Roxanne","links":[{"rel":"self","href":"http://songs/Roxanne"}]}')
371
418
 
372
- song.links[:self].href #=> "http://songs/Roxanne"
419
+ representer.links[:self].href #=> "http://songs/Roxanne"
373
420
  ```
374
421
 
375
422
  Reading link attributes works by using `#links[]` on the consuming instance.
@@ -379,7 +426,7 @@ This allows an easy way to discover hypermedia and build navigational logic on t
379
426
 
380
427
  ## Media Formats
381
428
 
382
- While Roar comes with a built-in hypermedia format, there's official media types that are widely recognized. Roar currently supports HAL and Collection+JSON. Support for Siren and JSON-API is planned when there's sponsors.
429
+ While Roar comes with a built-in hypermedia format, there's official media types that are widely recognized. Roar currently supports HAL and JSON API.
383
430
 
384
431
  Simply by including a module you make your representer understand the media type. This makes it easy to change formats during evaluation.
385
432
 
@@ -390,7 +437,7 @@ The [HAL](http://stateless.co/hal_specification.html) format is a simple media t
390
437
  ```ruby
391
438
  require 'roar/json/hal'
392
439
 
393
- module SongRepresenter
440
+ class SongRepresenter < Roar::Decorator
394
441
  include Roar::JSON::HAL
395
442
 
396
443
  property :title
@@ -401,7 +448,7 @@ module SongRepresenter
401
448
  end
402
449
  ```
403
450
 
404
- Documentation for HAL can be found in the [API docs](http://rdoc.info/github/apotonick/roar/Roar/JSON/HAL).
451
+ Documentation for HAL can be found in the [API docs](http://rdoc.info/github/trailblazer/roar/Roar/JSON/HAL).
405
452
 
406
453
  Make sure you [understand the different contexts](#hypermedia) for links when using decorators.
407
454
 
@@ -410,7 +457,7 @@ Make sure you [understand the different contexts](#hypermedia) for links when us
410
457
  Including the `Roar::JSON::HAL` module adds some more DSL methods to your module. It still allows using `::link` but treats them slightly different.
411
458
 
412
459
  ```ruby
413
- song.to_json
460
+ representer.to_json
414
461
  #=> {"title":"Roxanne","_links":{"self":{"href":"http://songs/Roxanne"}}}
415
462
  ```
416
463
 
@@ -423,7 +470,7 @@ Parsing works like-wise: Roar will use the same setters as before but it knows h
423
470
  Nested, or embedded, resources can be defined using the `:embedded` option.
424
471
 
425
472
  ```ruby
426
- module AlbumRepresenter
473
+ class AlbumRepresenter < Roar::Decorator
427
474
  include Roar::JSON::HAL
428
475
 
429
476
  property :title
@@ -437,187 +484,18 @@ end
437
484
  To embed a resource, you can use an inline representer or use `:extend` to specify the representer name.
438
485
 
439
486
  ```ruby
440
- album.to_json
487
+ AlbumRepresenter.new(album).to_json
441
488
 
442
489
  #=> {"title":"True North","_embedded":{"songs":[{"title":"The Island"},{"title":"Changing Tide"}]}}
443
490
  ```
444
491
 
445
492
  HAL keys nested resources under the `_embedded` key and then by their type.
446
493
 
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).
494
+ All HAL features in Roar are discussed in the [API docs](http://rdoc.info/github/trailblazer/roar/Roar/JSON/HAL), including [array links](https://github.com/trailblazer/roar/blob/master/lib/roar/json/hal.rb#L196).
448
495
 
496
+ ## JSON API
449
497
 
450
- ## JSON-API
451
-
452
- Roar also supports [JSON-API](http://jsonapi.org/) - yay! It can render _and_ parse singular and collection documents.
453
-
454
- Note that you need representable >= 2.1.4 in your `Gemfile`.
455
-
456
- ### Resource
457
-
458
- A minimal representation can be defined as follows.
459
-
460
- ```ruby
461
- require 'roar/json/json_api'
462
-
463
- module SongsRepresenter
464
- include Roar::JSON::JSONAPI
465
- type :songs
466
-
467
- property :id
468
- property :title
469
- end
470
- ```
471
-
472
- Properties of the represented model are defined in the root level.
473
-
474
- ### Hypermedia
475
-
476
- You can add links to `linked` models within the resource section.
477
-
478
- ```ruby
479
- module SongsRepresenter
480
- # ...
481
-
482
- has_one :composer
483
- has_many :listeners
484
- end
485
- ```
486
-
487
- Global `links` can be added using the familiar `::link` method (this is still WIP as the DSL is not final).
488
-
489
- ```ruby
490
- module SongsRepresenter
491
- # ...
492
-
493
- link "songs.album" do
494
- {
495
- type: "album",
496
- href: "http://example.com/albums/{songs.album}"
497
- }
498
- end
499
- end
500
- ```
501
-
502
- ### Compounds
503
-
504
- To add compound models into the document, use `::compound`.
505
-
506
- ```ruby
507
- module SongsRepresenter
508
- # ...
509
-
510
- compound do
511
- property :album do
512
- property :id
513
- property :title
514
- end
515
-
516
- collection :musicians do
517
- property :name
518
- end
519
- end
520
- ```
521
-
522
- ### Meta Data
523
-
524
- Meta data can be included into the rendered collection document in two ways. Please note that parsing the `meta` field is not implemented, yet, as I wasn't sure if people need it.
525
-
526
- You can define meta data on your collection object and then let Roar compile it.
527
-
528
- ```ruby
529
- module SongsRepresenter
530
- # ..
531
-
532
- meta do
533
- property :page
534
- property :total
535
- end
536
- ```
537
-
538
- Your collection object has to expose those methods.
539
-
540
- ```ruby
541
- collection.page #=> 1
542
- collection.total #=> 12
543
- ```
544
-
545
- This will render the `{"meta": {"page": 1, "total": 12}}` hash into the JSON-API document.
546
-
547
- Another way is to provide the _complete_ meta data hash when rendering. You must not define any `meta` properties in the representer when using this approach.
548
-
549
- ```ruby
550
- collection.to_json("meta" => {page: params["page"], total: collection.size})
551
- ```
552
-
553
- If you need more functionality (and parsing), please let us know.
554
-
555
- ### Usage
556
-
557
- As JSON-API per definition can represent singular models and collections you have two entry points.
558
-
559
- ```ruby
560
- SongsRepresenter.prepare(Song.find(1)).to_json
561
- SongsRepresenter.prepare(Song.new).from_json("..")
562
- ```
563
-
564
- Singular models can use the representer module directly.
565
-
566
- ```ruby
567
- SongsRepresenter.for_collection.prepare([Song.find(1), Song.find(2)]).to_json
568
- SongsRepresenter.for_collection.prepare([Song.new, Song.new]).from_json("..")
569
- ```
570
-
571
-
572
- Parsing currently works great with singular documents - for collections, we are still working out how to encode the application semantics. Feel free to help.
573
-
574
-
575
- ## Collection+JSON
576
-
577
- The [Collection+JSON media format](http://amundsen.com/media-types/collection/) defines document format and semantics for requests. It is currently experimental as we're still exploring how we optimize the support with Roar. Let us know if you're using it.
578
-
579
- ```ruby
580
- module SongRepresenter
581
- include Roar::JSON::CollectionJSON
582
- version "1.0"
583
- href { "http://localhost/songs/" }
584
-
585
- property :title
586
-
587
- items(:class => Song) do
588
- href { "//songs/#{title}" }
589
-
590
- property :title, :prompt => "Song title"
591
-
592
- link(:download) { "//songs/#{title}.mp3" }
593
- end
594
-
595
- template do
596
- property :title, :prompt => "Song title"
597
- end
598
-
599
- queries do
600
- link :search do
601
- {:href => "//search", :data => [{:name => "q", :value => ""}]}
602
- end
603
- end
604
- end
605
- ```
606
-
607
- It renders a document following the Collection+JSON specs.
608
-
609
- ```
610
- #=> {"collection":{
611
- "template":{"data":[{"name":"title","value":null}]},
612
- "queries":[{"rel":"search","href":"//search","data":[{"name":"q","value":""}]}],
613
- "version":"1.0",
614
- "href":"http://localhost/songs/",
615
- "title":"Roxanne",
616
- "items":null}}
617
- ```
618
-
619
- We have big plans with this media format, as the object model in Roar plays nicely with Collection+JSON's API semantics.
620
-
498
+ Roar also supports [JSON API](http://jsonapi.org/) via the [Roar JSON API gem](https://github.com/trailblazer/roar-jsonapi).
621
499
 
622
500
  ## Client-Side Support
623
501
 
@@ -626,7 +504,7 @@ Being a bi-directional mapper that does rendering _and_ parsing, Roar represente
626
504
  Consider the following shared representer.
627
505
 
628
506
  ```ruby
629
- module SongRepresenter
507
+ class SongRepresenter < Roar::Decorator
630
508
  include Roar::JSON
631
509
  include Roar::Hypermedia
632
510
 
@@ -643,6 +521,7 @@ In a client where you don't have access to the database it is common to use `Ope
643
521
 
644
522
  ```ruby
645
523
  require 'roar/client'
524
+ require 'roar/json'
646
525
 
647
526
  class Song < OpenStruct
648
527
  include Roar::JSON
@@ -738,7 +617,7 @@ rescue Roar::Transport::Error => exception
738
617
  Roar also comes with XML support.
739
618
 
740
619
  ```ruby
741
- module SongRepresenter
620
+ class SongRepresenter < Roar::Decorator
742
621
  include Roar::XML
743
622
  include Roar::Hypermedia
744
623
 
@@ -755,9 +634,8 @@ Include the `Roar::XML` engine and get bi-directional XML for your objects.
755
634
 
756
635
  ```ruby
757
636
  song = Song.new(title: "Roxanne", id: 42)
758
- song.extend(XML::SongRepresenter)
759
637
 
760
- song.to_xml
638
+ SongRepresenter.new(song).to_xml
761
639
  ```
762
640
 
763
641
  Note that you now use `#to_xml` and `#from_xml`.
@@ -770,7 +648,7 @@ Note that you now use `#to_xml` and `#from_xml`.
770
648
  </song>
771
649
  ```
772
650
 
773
- Please consult the [representable XML documentation](https://github.com/apotonick/representable/#more-on-xml) for all its great features.
651
+ Please consult the [representable XML documentation](https://github.com/trailblazer/representable/#more-on-xml) for all its great features.
774
652
 
775
653
 
776
654
  ## Support