oat 0.1.2 → 0.2.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.travis.yml +27 -0
- data/README.md +26 -6
- data/gemfiles/Gemfile.as-1.4.4 +5 -0
- data/gemfiles/Gemfile.as-2.3.x +5 -0
- data/gemfiles/Gemfile.as-3.0.x +6 -0
- data/gemfiles/Gemfile.as-3.1.x +6 -0
- data/gemfiles/Gemfile.as-3.2.x +5 -0
- data/gemfiles/Gemfile.as-4.0.x +5 -0
- data/lib/oat/adapter.rb +3 -3
- data/lib/oat/adapters/hal.rb +4 -4
- data/lib/oat/adapters/json_api.rb +13 -6
- data/lib/oat/adapters/siren.rb +4 -4
- data/lib/oat/serializer.rb +2 -2
- data/lib/oat/version.rb +1 -1
- data/lib/support/class_attribute.rb +68 -0
- data/oat.gemspec +1 -1
- data/spec/adapters/hal_spec.rb +62 -47
- data/spec/adapters/json_api_spec.rb +76 -48
- data/spec/adapters/siren_spec.rb +95 -67
- data/spec/fixtures.rb +2 -1
- data/spec/serializer_spec.rb +22 -8
- metadata +11 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6b724a91b70428b2d8119bb6bdd9a30c814ac10d
|
4
|
+
data.tar.gz: 043edf3fd0dcb99075cf01660851e8a183270d1f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7662b374492e8c20c8e3fbe030d1b08bbcd27665cb4230a4c696142b1e80d6d298eb4870977943ac99d12d20517792c97240d88602b28f29c2bd0974f3bf7455
|
7
|
+
data.tar.gz: a4887962d0788adfcb7992a79e21c884ddb92734c690b99f77c9541278003db4c7fbe5c5f1ffae2696c114c58a7236ce621a619ac9c44b3c8d151b4eafee6b47
|
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
@@ -1,3 +1,30 @@
|
|
1
1
|
language: ruby
|
2
2
|
rvm:
|
3
3
|
- 2.0.0
|
4
|
+
- 1.9.3
|
5
|
+
- 1.9.2
|
6
|
+
- 1.8.7
|
7
|
+
|
8
|
+
gemfile:
|
9
|
+
- gemfiles/Gemfile.as-2.3.x
|
10
|
+
- gemfiles/Gemfile.as-3.0.x
|
11
|
+
- gemfiles/Gemfile.as-3.1.x
|
12
|
+
- gemfiles/Gemfile.as-3.2.x
|
13
|
+
- gemfiles/Gemfile.as-4.0.x
|
14
|
+
|
15
|
+
matrix:
|
16
|
+
include:
|
17
|
+
- gemfile: gemfiles/Gemfile.as-1.4.4
|
18
|
+
rvm: 1.8.7
|
19
|
+
exclude:
|
20
|
+
- gemfile: gemfiles/Gemfile.as-2.3.x
|
21
|
+
rvm: 2.0.0
|
22
|
+
- gemfile: gemfiles/Gemfile.as-4.0.x
|
23
|
+
rvm: 1.8.7
|
24
|
+
- gemfile: gemfiles/Gemfile.as-4.0.x
|
25
|
+
rvm: 1.9.2
|
26
|
+
allow_failures:
|
27
|
+
- gemfile: gemfiles/Gemfile.as-3.0.x
|
28
|
+
rvm: 1.8.7
|
29
|
+
- gemfile: gemfiles/Gemfile.as-1.4.4
|
30
|
+
rvm: 1.8.7
|
data/README.md
CHANGED
@@ -46,7 +46,7 @@ Serializers require a single object as argument, which can be a model instance,
|
|
46
46
|
The full serializer signature is `item`, `context`, `adapter_class`.
|
47
47
|
|
48
48
|
* `item` a model or presenter instance. It is available in your serializer's schema as `item`.
|
49
|
-
* `context` (optional) a context
|
49
|
+
* `context` (optional) a context hash that is passed to the serializer and sub-serializers as the `context` variable. Useful if you need to pass request-specific data.
|
50
50
|
* `adapter_class` (optional) A serializer's adapter can be configured at class-level or passed here to the initializer. Useful if you want to switch adapters based on request data. More on this below.
|
51
51
|
|
52
52
|
### Defining Properties
|
@@ -350,32 +350,52 @@ end
|
|
350
350
|
|
351
351
|
In frameworks like Rails, you'll probably want to use the URL helpers created by the `routes.rb` file. Two options:
|
352
352
|
|
353
|
-
### Pass a context
|
353
|
+
### Pass a context hash to serializers
|
354
354
|
|
355
|
-
You can pass a context
|
355
|
+
You can pass a context hash as second argument to serializers. This object will be passed to nested serializers too. For example, you can pass the controller instance itself.
|
356
356
|
|
357
357
|
```ruby
|
358
358
|
# users_controller.rb
|
359
359
|
|
360
360
|
def show
|
361
361
|
user = User.find(params[:id])
|
362
|
-
render json: UserSerializer.new(user, self)
|
362
|
+
render json: UserSerializer.new(user, controller: self)
|
363
363
|
end
|
364
364
|
```
|
365
365
|
|
366
366
|
Then, in the `UserSerializer`:
|
367
|
+
|
367
368
|
```ruby
|
368
369
|
class ProductSerializer < Oat::Serializer
|
369
370
|
adapter Oat::Adapters::HAL
|
370
371
|
|
371
372
|
schema do
|
372
|
-
# `context` is the controller, which responds to URL helpers.
|
373
|
-
link :self, href: context.product_url(item)
|
373
|
+
# `context[:controller]` is the controller, which responds to URL helpers.
|
374
|
+
link :self, href: context[:controller].product_url(item)
|
374
375
|
...
|
375
376
|
end
|
376
377
|
end
|
377
378
|
```
|
378
379
|
|
380
|
+
The context hash is passed down to each nested serializer called by a parent. In some cases, you might want to include extra context information for one or more nested serializers. This can be done by passing options into your call to `entity` or `entities`.
|
381
|
+
|
382
|
+
```ruby
|
383
|
+
class CategorySerializer < Oat::Serializer
|
384
|
+
adapter Oat::Adapters::HAL
|
385
|
+
|
386
|
+
schema do
|
387
|
+
map_properties :id, :name
|
388
|
+
|
389
|
+
# category entities
|
390
|
+
# passing this option ensures that only direct children are embedded within
|
391
|
+
# the parent serialized category
|
392
|
+
entities :subcategories, item.subcategories, CategorySerializer, embedded: true if context[:embedded]
|
393
|
+
end
|
394
|
+
end
|
395
|
+
```
|
396
|
+
|
397
|
+
The additional options are merged into the current context before being passed down to the nested serializer.
|
398
|
+
|
379
399
|
### Mixin Rails' routing module
|
380
400
|
|
381
401
|
Alternatively, you can mix in Rails routing helpers directly into your serializers.
|
data/lib/oat/adapter.rb
CHANGED
@@ -21,17 +21,17 @@ module Oat
|
|
21
21
|
props.to_hash
|
22
22
|
end
|
23
23
|
|
24
|
-
def serializer_from_block_or_class(obj, serializer_class = nil, &block)
|
24
|
+
def serializer_from_block_or_class(obj, serializer_class = nil, context_options = {}, &block)
|
25
25
|
return nil if obj.nil?
|
26
26
|
|
27
27
|
if block_given?
|
28
28
|
serializer_class = Class.new(serializer.class)
|
29
29
|
serializer_class.adapter self.class
|
30
|
-
s = serializer_class.new(obj, serializer.context, serializer.adapter_class, serializer.top)
|
30
|
+
s = serializer_class.new(obj, serializer.context.merge(context_options), serializer.adapter_class, serializer.top)
|
31
31
|
serializer.top.instance_exec(obj, s, &block)
|
32
32
|
s.to_hash
|
33
33
|
else
|
34
|
-
serializer_class.new(obj, serializer.context, serializer.adapter_class).to_hash
|
34
|
+
serializer_class.new(obj, serializer.context.merge(context_options), serializer.adapter_class).to_hash
|
35
35
|
end
|
36
36
|
end
|
37
37
|
end
|
data/lib/oat/adapters/hal.rb
CHANGED
@@ -14,13 +14,13 @@ module Oat
|
|
14
14
|
data[key] = value
|
15
15
|
end
|
16
16
|
|
17
|
-
def entity(name, obj, serializer_class = nil, &block)
|
18
|
-
data[:_embedded][name] = serializer_from_block_or_class(obj, serializer_class, &block)
|
17
|
+
def entity(name, obj, serializer_class = nil, context_options = {}, &block)
|
18
|
+
data[:_embedded][name] = serializer_from_block_or_class(obj, serializer_class, context_options, &block)
|
19
19
|
end
|
20
20
|
|
21
|
-
def entities(name, collection, serializer_class = nil, &block)
|
21
|
+
def entities(name, collection, serializer_class = nil, context_options = {}, &block)
|
22
22
|
data[:_embedded][name] = collection.map do |obj|
|
23
|
-
serializer_from_block_or_class(obj, serializer_class, &block)
|
23
|
+
serializer_from_block_or_class(obj, serializer_class, context_options, &block)
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|
@@ -1,5 +1,12 @@
|
|
1
1
|
# http://jsonapi.org/format/#url-based-json-api
|
2
|
+
require 'active_support/inflector'
|
2
3
|
require 'active_support/core_ext/string/inflections'
|
4
|
+
unless defined?(String.new.pluralize)
|
5
|
+
class String
|
6
|
+
include ActiveSupport::CoreExtensions::String::Inflections
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
3
10
|
module Oat
|
4
11
|
module Adapters
|
5
12
|
class JsonAPI < Oat::Adapter
|
@@ -25,22 +32,22 @@ module Oat
|
|
25
32
|
data[key] = value
|
26
33
|
end
|
27
34
|
|
28
|
-
def entity(name, obj, serializer_class = nil, &block)
|
35
|
+
def entity(name, obj, serializer_class = nil, context_options = {}, &block)
|
29
36
|
@entities[name.to_s.pluralize.to_sym] ||= []
|
30
|
-
ent = entity_without_root(obj, serializer_class, &block)
|
37
|
+
ent = entity_without_root(obj, serializer_class, context_options, &block)
|
31
38
|
if ent
|
32
39
|
link name, :href => ent[:id]
|
33
40
|
@entities[name.to_s.pluralize.to_sym] << ent
|
34
41
|
end
|
35
42
|
end
|
36
43
|
|
37
|
-
def entities(name, collection, serializer_class = nil, &block)
|
44
|
+
def entities(name, collection, serializer_class = nil, context_options = {}, &block)
|
38
45
|
link_name = name.to_s.pluralize.to_sym
|
39
46
|
data[:links][link_name] = []
|
40
47
|
|
41
48
|
collection.each do |obj|
|
42
49
|
@entities[link_name] ||= []
|
43
|
-
ent = entity_without_root(obj, serializer_class, &block)
|
50
|
+
ent = entity_without_root(obj, serializer_class, context_options, &block)
|
44
51
|
if ent
|
45
52
|
data[:links][link_name] << ent[:id]
|
46
53
|
@entities[link_name] << ent
|
@@ -59,8 +66,8 @@ module Oat
|
|
59
66
|
|
60
67
|
attr_reader :root_name
|
61
68
|
|
62
|
-
def entity_without_root(obj, serializer_class = nil, &block)
|
63
|
-
ent = serializer_from_block_or_class(obj, serializer_class, &block)
|
69
|
+
def entity_without_root(obj, serializer_class = nil, context_options = {}, &block)
|
70
|
+
ent = serializer_from_block_or_class(obj, serializer_class, context_options, &block)
|
64
71
|
ent.values.first.first if ent
|
65
72
|
end
|
66
73
|
|
data/lib/oat/adapters/siren.rb
CHANGED
@@ -26,14 +26,14 @@ module Oat
|
|
26
26
|
data[:properties][key] = value
|
27
27
|
end
|
28
28
|
|
29
|
-
def entity(name, obj, serializer_class = nil, &block)
|
30
|
-
ent = serializer_from_block_or_class(obj, serializer_class, &block)
|
29
|
+
def entity(name, obj, serializer_class = nil, context_options = {}, &block)
|
30
|
+
ent = serializer_from_block_or_class(obj, serializer_class, context_options, &block)
|
31
31
|
data[:entities] << ent if ent
|
32
32
|
end
|
33
33
|
|
34
|
-
def entities(name, collection, serializer_class = nil, &block)
|
34
|
+
def entities(name, collection, serializer_class = nil, context_options = {}, &block)
|
35
35
|
collection.each do |obj|
|
36
|
-
entity name, obj, serializer_class, &block
|
36
|
+
entity name, obj, serializer_class, context_options, &block
|
37
37
|
end
|
38
38
|
end
|
39
39
|
|
data/lib/oat/serializer.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require '
|
1
|
+
require 'support/class_attribute'
|
2
2
|
module Oat
|
3
3
|
class Serializer
|
4
4
|
|
@@ -20,7 +20,7 @@ module Oat
|
|
20
20
|
|
21
21
|
attr_reader :item, :context, :adapter_class, :adapter
|
22
22
|
|
23
|
-
def initialize(item, context =
|
23
|
+
def initialize(item, context = {}, _adapter_class = nil, parent_serializer = nil)
|
24
24
|
@item, @context = item, context
|
25
25
|
@parent_serializer = parent_serializer
|
26
26
|
@adapter_class = _adapter_class || self.class.adapter
|
data/lib/oat/version.rb
CHANGED
@@ -0,0 +1,68 @@
|
|
1
|
+
begin
|
2
|
+
require 'active_support/core_ext/class/attribute'
|
3
|
+
rescue LoadError
|
4
|
+
module Kernel
|
5
|
+
# Returns the object's singleton class.
|
6
|
+
def singleton_class
|
7
|
+
class << self
|
8
|
+
self
|
9
|
+
end
|
10
|
+
end unless respond_to?(:singleton_class) # exists in 1.9.2
|
11
|
+
|
12
|
+
# class_eval on an object acts like singleton_class.class_eval.
|
13
|
+
def class_eval(*args, &block)
|
14
|
+
singleton_class.class_eval(*args, &block)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class Module
|
19
|
+
def remove_possible_method(method)
|
20
|
+
if method_defined?(method) || private_method_defined?(method)
|
21
|
+
remove_method(method)
|
22
|
+
end
|
23
|
+
rescue NameError
|
24
|
+
# If the requested method is defined on a superclass or included module,
|
25
|
+
# method_defined? returns true but remove_method throws a NameError.
|
26
|
+
# Ignore this.
|
27
|
+
end
|
28
|
+
|
29
|
+
def redefine_method(method, &block)
|
30
|
+
remove_possible_method(method)
|
31
|
+
define_method(method, &block)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
class Class
|
36
|
+
def class_attribute(*attrs)
|
37
|
+
attrs.each do |name|
|
38
|
+
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
39
|
+
def self.#{name}() nil end
|
40
|
+
def self.#{name}?() !!#{name} end
|
41
|
+
|
42
|
+
def self.#{name}=(val)
|
43
|
+
singleton_class.class_eval do
|
44
|
+
remove_possible_method(:#{name})
|
45
|
+
define_method(:#{name}) { val }
|
46
|
+
end
|
47
|
+
|
48
|
+
if singleton_class?
|
49
|
+
class_eval do
|
50
|
+
remove_possible_method(:#{name})
|
51
|
+
def #{name}
|
52
|
+
defined?(@#{name}) ? @#{name} : singleton_class.#{name}
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
val
|
57
|
+
end
|
58
|
+
RUBY
|
59
|
+
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
def singleton_class?
|
65
|
+
ancestors.first != self
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
data/oat.gemspec
CHANGED
@@ -18,7 +18,7 @@ Gem::Specification.new do |spec|
|
|
18
18
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
19
|
spec.require_paths = ["lib"]
|
20
20
|
|
21
|
-
spec.add_dependency "activesupport"
|
21
|
+
spec.add_dependency "activesupport"
|
22
22
|
spec.add_development_dependency "bundler", "~> 1.3"
|
23
23
|
spec.add_development_dependency "rake"
|
24
24
|
spec.add_development_dependency "rspec"
|
data/spec/adapters/hal_spec.rb
CHANGED
@@ -5,63 +5,78 @@ describe Oat::Adapters::HAL do
|
|
5
5
|
|
6
6
|
include Fixtures
|
7
7
|
|
8
|
-
|
8
|
+
let(:serializer) { serializer_class.new(user, {:name => 'some_controller'}, Oat::Adapters::HAL) }
|
9
|
+
let(:hash) { serializer.to_hash }
|
9
10
|
|
10
11
|
describe '#to_hash' do
|
11
12
|
it 'produces a HAL-compliant hash' do
|
12
|
-
|
13
|
+
expect(hash).to include(
|
13
14
|
# properties
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
15
|
+
:id => user.id,
|
16
|
+
:name => user.name,
|
17
|
+
:age => user.age,
|
18
|
+
:controller_name => 'some_controller',
|
19
|
+
:message_from_above => nil
|
20
|
+
)
|
21
|
+
|
22
|
+
# links
|
23
|
+
expect(hash.fetch(:_links)).to include(:self => { :href => "http://foo.bar.com/#{user.id}" })
|
24
|
+
|
25
|
+
# HAL Spec says href is REQUIRED
|
26
|
+
expect(hash.fetch(:_links)).not_to include(:empty)
|
27
|
+
expect(hash.fetch(:_embedded)).to include(:manager, :friends)
|
28
|
+
|
29
|
+
# embedded manager
|
30
|
+
expect(hash.fetch(:_embedded).fetch(:manager)).to include(
|
31
|
+
:id => manager.id,
|
32
|
+
:name => manager.name,
|
33
|
+
:age => manager.age,
|
34
|
+
:_links => { :self => { :href => "http://foo.bar.com/#{manager.id}" } }
|
35
|
+
)
|
36
|
+
|
37
|
+
# embedded friends
|
38
|
+
expect(hash.fetch(:_embedded).fetch(:friends).size).to be 1
|
39
|
+
expect(hash.fetch(:_embedded).fetch(:friends).first).to include(
|
40
|
+
:id => friend.id,
|
41
|
+
:name => friend.name,
|
42
|
+
:age => friend.age,
|
43
|
+
:controller_name => 'some_controller',
|
44
|
+
:message_from_above => "Merged into parent's context",
|
45
|
+
:_links => { :self => { :href => "http://foo.bar.com/#{friend.id}" } }
|
46
|
+
)
|
39
47
|
end
|
40
48
|
|
41
49
|
context 'with a nil entity relationship' do
|
42
50
|
let(:manager) { nil }
|
43
51
|
|
44
52
|
it 'produces a HAL-compliant hash' do
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
53
|
+
# properties
|
54
|
+
expect(hash).to include(
|
55
|
+
:id => user.id,
|
56
|
+
:name => user.name,
|
57
|
+
:age => user.age,
|
58
|
+
:controller_name => 'some_controller',
|
59
|
+
:message_from_above => nil
|
60
|
+
)
|
61
|
+
|
62
|
+
expect(hash.fetch(:_links)).to include(:self => { :href => "http://foo.bar.com/#{user.id}" })
|
63
|
+
|
64
|
+
# HAL Spec says href is REQUIRED
|
65
|
+
expect(hash.fetch(:_links)).not_to include(:empty)
|
66
|
+
expect(hash.fetch(:_embedded)).to include(:manager, :friends)
|
67
|
+
|
68
|
+
expect(hash.fetch(:_embedded).fetch(:manager)).to be_nil
|
69
|
+
|
70
|
+
# embedded friends
|
71
|
+
expect(hash.fetch(:_embedded).fetch(:friends).size).to be 1
|
72
|
+
expect(hash.fetch(:_embedded).fetch(:friends).first).to include(
|
73
|
+
:id => friend.id,
|
74
|
+
:name => friend.name,
|
75
|
+
:age => friend.age,
|
76
|
+
:controller_name => 'some_controller',
|
77
|
+
:message_from_above => "Merged into parent's context",
|
78
|
+
:_links => { :self => { :href => "http://foo.bar.com/#{friend.id}" } }
|
79
|
+
)
|
65
80
|
end
|
66
81
|
end
|
67
82
|
end
|
@@ -5,69 +5,97 @@ describe Oat::Adapters::JsonAPI do
|
|
5
5
|
|
6
6
|
include Fixtures
|
7
7
|
|
8
|
-
|
8
|
+
let(:serializer) { serializer_class.new(user, {:name => 'some_controller'}, Oat::Adapters::JsonAPI) }
|
9
|
+
let(:hash) { serializer.to_hash }
|
9
10
|
|
10
11
|
describe '#to_hash' do
|
11
12
|
it 'produces a JSON-API compliant hash' do
|
12
|
-
|
13
|
+
# the user being serialized
|
14
|
+
users = hash.fetch(:users)
|
15
|
+
expect(users.size).to be 1
|
16
|
+
expect(users.first).to include(
|
17
|
+
:id => user.id,
|
18
|
+
:name => user.name,
|
19
|
+
:age => user.age,
|
20
|
+
:controller_name => 'some_controller',
|
21
|
+
:message_from_above => nil
|
22
|
+
)
|
23
|
+
|
24
|
+
expect(users.first.fetch(:links)).to include(
|
25
|
+
:self => "http://foo.bar.com/#{user.id}",
|
26
|
+
# these links are added by embedding entities
|
27
|
+
:manager => manager.id,
|
28
|
+
:friends => [friend.id]
|
29
|
+
)
|
30
|
+
|
13
31
|
# embedded friends
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
32
|
+
linked_friends = hash.fetch(:linked).fetch(:friends)
|
33
|
+
expect(linked_friends.size).to be 1
|
34
|
+
expect(linked_friends.first).to include(
|
35
|
+
:id => friend.id,
|
36
|
+
:name => friend.name,
|
37
|
+
:age => friend.age,
|
38
|
+
:controller_name => 'some_controller',
|
39
|
+
:message_from_above => "Merged into parent's context"
|
40
|
+
)
|
21
41
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
m[:links][:self].should == "http://foo.bar.com/#{manager.id}"
|
28
|
-
end
|
42
|
+
expect(linked_friends.first.fetch(:links)).to include(
|
43
|
+
:self => "http://foo.bar.com/#{friend.id}",
|
44
|
+
:empty => nil,
|
45
|
+
:friends => []
|
46
|
+
)
|
29
47
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
h[:links][:friends].should == [friend.id]
|
40
|
-
end
|
48
|
+
# embedded manager
|
49
|
+
linked_managers = hash.fetch(:linked).fetch(:managers)
|
50
|
+
expect(linked_managers.size).to be 1
|
51
|
+
expect(linked_managers.first).to include(
|
52
|
+
:id => manager.id,
|
53
|
+
:name => manager.name,
|
54
|
+
:age => manager.age,
|
55
|
+
:links => { :self => "http://foo.bar.com/#{manager.id}" }
|
56
|
+
)
|
41
57
|
end
|
42
58
|
|
43
59
|
context 'with a nil entity relationship' do
|
44
60
|
let(:manager) { nil }
|
45
61
|
|
46
62
|
it 'produces a JSON-API compliant hash' do
|
47
|
-
|
63
|
+
# the user being serialized
|
64
|
+
users = hash.fetch(:users)
|
65
|
+
expect(users.size).to be 1
|
66
|
+
expect(users.first).to include(
|
67
|
+
:id => user.id,
|
68
|
+
:name => user.name,
|
69
|
+
:age => user.age,
|
70
|
+
:controller_name => 'some_controller',
|
71
|
+
:message_from_above => nil
|
72
|
+
)
|
73
|
+
|
74
|
+
expect(users.first.fetch(:links)).not_to include(:manager)
|
75
|
+
expect(users.first.fetch(:links)).to include(
|
76
|
+
:self => "http://foo.bar.com/#{user.id}",
|
77
|
+
# these links are added by embedding entities
|
78
|
+
:friends => [friend.id]
|
79
|
+
)
|
48
80
|
# embedded friends
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
81
|
+
linked_friends = hash.fetch(:linked).fetch(:friends)
|
82
|
+
expect(linked_friends.size).to be 1
|
83
|
+
expect(linked_friends.first).to include(
|
84
|
+
:id => friend.id,
|
85
|
+
:name => friend.name,
|
86
|
+
:age => friend.age,
|
87
|
+
:controller_name => 'some_controller',
|
88
|
+
:message_from_above => "Merged into parent's context"
|
89
|
+
)
|
56
90
|
|
57
|
-
|
58
|
-
|
91
|
+
expect(linked_friends.first.fetch(:links)).to include(
|
92
|
+
:self => "http://foo.bar.com/#{friend.id}",
|
93
|
+
:empty => nil,
|
94
|
+
:friends => []
|
95
|
+
)
|
59
96
|
|
60
|
-
|
61
|
-
|
62
|
-
h[:name].should == user.name
|
63
|
-
h[:age].should == user.age
|
64
|
-
h[:controller_name].should == 'some_controller'
|
65
|
-
# links
|
66
|
-
h[:links][:self].should == "http://foo.bar.com/#{user.id}"
|
67
|
-
# these links are added by embedding entities
|
68
|
-
h[:links].should_not include(:manager)
|
69
|
-
h[:links][:friends].should == [friend.id]
|
70
|
-
end
|
97
|
+
# embedded manager
|
98
|
+
hash.fetch(:linked).fetch(:managers).should be_empty
|
71
99
|
end
|
72
100
|
end
|
73
101
|
end
|
data/spec/adapters/siren_spec.rb
CHANGED
@@ -5,82 +5,110 @@ describe Oat::Adapters::Siren do
|
|
5
5
|
|
6
6
|
include Fixtures
|
7
7
|
|
8
|
-
|
8
|
+
let(:serializer) { serializer_class.new(user, {:name => 'some_controller'}, Oat::Adapters::Siren) }
|
9
|
+
let(:hash) { serializer.to_hash }
|
9
10
|
|
10
11
|
describe '#to_hash' do
|
11
12
|
it 'produces a Siren-compliant hash' do
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
13
|
+
expect(hash.fetch(:class)).to match_array(['user'])
|
14
|
+
|
15
|
+
expect(hash.fetch(:properties)).to include(
|
16
|
+
:id => user.id,
|
17
|
+
:name => user.name,
|
18
|
+
:age => user.age,
|
19
|
+
:controller_name => 'some_controller',
|
20
|
+
:message_from_above => nil
|
21
|
+
)
|
22
|
+
|
23
|
+
expect(hash.fetch(:links).size).to be 2
|
24
|
+
expect(hash.fetch(:links)).to include(
|
25
|
+
{ :rel => [:self], :href => "http://foo.bar.com/#{user.id}" },
|
26
|
+
{ :rel => [:empty], :href => nil }
|
27
|
+
)
|
28
|
+
|
29
|
+
expect(hash.fetch(:entities).size).to be 2
|
30
|
+
|
31
|
+
# embedded friends
|
32
|
+
embedded_friends = hash.fetch(:entities).select{ |o| o[:class].include? "user" }
|
33
|
+
expect(embedded_friends.size).to be 1
|
34
|
+
expect(embedded_friends.first.fetch(:properties)).to include(
|
35
|
+
:id => friend.id,
|
36
|
+
:name => friend.name,
|
37
|
+
:age => friend.age,
|
38
|
+
:controller_name => 'some_controller',
|
39
|
+
:message_from_above => "Merged into parent's context"
|
40
|
+
)
|
41
|
+
expect(embedded_friends.first.fetch(:links).first).to include(
|
42
|
+
:rel => [:self],
|
43
|
+
:href => "http://foo.bar.com/#{friend.id}"
|
44
|
+
)
|
45
|
+
|
46
|
+
embedded_managers = hash.fetch(:entities).select{ |o| o[:class].include? "manager" }
|
47
|
+
expect(embedded_managers.size).to be 1
|
48
|
+
expect(embedded_managers.first.fetch(:properties)).to include(
|
49
|
+
:id => manager.id,
|
50
|
+
:name => manager.name,
|
51
|
+
:age => manager.age
|
52
|
+
)
|
53
|
+
expect(embedded_managers.first.fetch(:links).first).to include(
|
54
|
+
:rel => [:self],
|
55
|
+
:href => "http://foo.bar.com/#{manager.id}"
|
56
|
+
)
|
57
|
+
|
58
|
+
# action close_account
|
59
|
+
actions = hash.fetch(:actions)
|
60
|
+
expect(actions.size).to be 1
|
61
|
+
expect(actions.first).to include(
|
62
|
+
:name => :close_account,
|
63
|
+
:href => "http://foo.bar.com/#{user.id}/close_account",
|
64
|
+
:class => ['danger', 'irreversible'],
|
65
|
+
:method => 'DELETE'
|
66
|
+
)
|
67
|
+
expect(actions.first.fetch(:fields)).to include(
|
68
|
+
:name => :current_password,
|
69
|
+
:type => :password
|
70
|
+
)
|
54
71
|
end
|
55
72
|
|
56
73
|
context 'with a nil entity relationship' do
|
57
74
|
let(:manager) { nil }
|
58
75
|
|
59
76
|
it 'produces a Siren-compliant hash' do
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
77
|
+
expect(hash.fetch(:class)).to match_array(['user'])
|
78
|
+
|
79
|
+
expect(hash.fetch(:properties)).to include(
|
80
|
+
:id => user.id,
|
81
|
+
:name => user.name,
|
82
|
+
:age => user.age,
|
83
|
+
:controller_name => 'some_controller',
|
84
|
+
:message_from_above => nil
|
85
|
+
)
|
86
|
+
|
87
|
+
expect(hash.fetch(:links).size).to be 2
|
88
|
+
expect(hash.fetch(:links)).to include(
|
89
|
+
{ :rel => [:self], :href => "http://foo.bar.com/#{user.id}" },
|
90
|
+
{ :rel => [:empty], :href => nil }
|
91
|
+
)
|
92
|
+
|
93
|
+
expect(hash.fetch(:entities).size).to be 1
|
94
|
+
|
95
|
+
# embedded friends
|
96
|
+
embedded_friends = hash.fetch(:entities).select{ |o| o[:class].include? "user" }
|
97
|
+
expect(embedded_friends.size).to be 1
|
98
|
+
expect(embedded_friends.first.fetch(:properties)).to include(
|
99
|
+
:id => friend.id,
|
100
|
+
:name => friend.name,
|
101
|
+
:age => friend.age,
|
102
|
+
:controller_name => 'some_controller',
|
103
|
+
:message_from_above => "Merged into parent's context"
|
104
|
+
)
|
105
|
+
expect(embedded_friends.first.fetch(:links).first).to include(
|
106
|
+
:rel => [:self],
|
107
|
+
:href => "http://foo.bar.com/#{friend.id}"
|
108
|
+
)
|
109
|
+
|
110
|
+
embedded_managers = hash.fetch(:entities).select{ |o| o[:class].include? "manager" }
|
111
|
+
expect(embedded_managers.size).to be 0
|
84
112
|
end
|
85
113
|
end
|
86
114
|
end
|
data/spec/fixtures.rb
CHANGED
@@ -18,9 +18,10 @@ module Fixtures
|
|
18
18
|
map_properties :name, :age
|
19
19
|
properties do |attrs|
|
20
20
|
attrs.controller_name context[:name]
|
21
|
+
attrs.message_from_above context[:message]
|
21
22
|
end
|
22
23
|
|
23
|
-
entities :friends, item.friends, klass
|
24
|
+
entities :friends, item.friends, klass, :message => "Merged into parent's context"
|
24
25
|
|
25
26
|
entity :manager, item.manager do |manager, s|
|
26
27
|
s.type 'manager'
|
data/spec/serializer_spec.rb
CHANGED
@@ -52,17 +52,31 @@ describe Oat::Serializer do
|
|
52
52
|
Oat::VERSION.should_not be_nil
|
53
53
|
end
|
54
54
|
|
55
|
+
describe "#context" do
|
56
|
+
it "is a hash by default" do
|
57
|
+
expect(@sc.new(user1).context).to be_a Hash
|
58
|
+
end
|
59
|
+
|
60
|
+
it "can be set like an options hash" do
|
61
|
+
serializer = @sc.new(user1, :controller => double(:name => "Fancy"))
|
62
|
+
expect(serializer.context.fetch(:controller).name).to eq "Fancy"
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
55
66
|
describe '#to_hash' do
|
56
67
|
it 'builds Hash from item and context with attributes as defined in adapter' do
|
57
68
|
serializer = @sc.new(user1, :name => 'some_controller')
|
58
|
-
serializer.to_hash.
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
69
|
+
expect(serializer.to_hash.fetch(:attributes)).to include(
|
70
|
+
:special => 'Hello',
|
71
|
+
:id => user1.id,
|
72
|
+
:name => user1.name,
|
73
|
+
:age => user1.age,
|
74
|
+
:controller_name => 'some_controller'
|
75
|
+
)
|
76
|
+
|
77
|
+
expect(serializer.to_hash.fetch(:links)).to include(
|
78
|
+
:self => "http://foo.bar.com/#{user1.id}"
|
79
|
+
)
|
66
80
|
end
|
67
81
|
end
|
68
82
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: oat
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ismael Celis
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-02-
|
11
|
+
date: 2014-02-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - '>='
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
19
|
+
version: '0'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - '>='
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '
|
26
|
+
version: '0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: bundler
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -83,6 +83,12 @@ files:
|
|
83
83
|
- LICENSE.txt
|
84
84
|
- README.md
|
85
85
|
- Rakefile
|
86
|
+
- gemfiles/Gemfile.as-1.4.4
|
87
|
+
- gemfiles/Gemfile.as-2.3.x
|
88
|
+
- gemfiles/Gemfile.as-3.0.x
|
89
|
+
- gemfiles/Gemfile.as-3.1.x
|
90
|
+
- gemfiles/Gemfile.as-3.2.x
|
91
|
+
- gemfiles/Gemfile.as-4.0.x
|
86
92
|
- lib/oat.rb
|
87
93
|
- lib/oat/adapter.rb
|
88
94
|
- lib/oat/adapters/hal.rb
|
@@ -91,6 +97,7 @@ files:
|
|
91
97
|
- lib/oat/props.rb
|
92
98
|
- lib/oat/serializer.rb
|
93
99
|
- lib/oat/version.rb
|
100
|
+
- lib/support/class_attribute.rb
|
94
101
|
- oat.gemspec
|
95
102
|
- spec/adapters/hal_spec.rb
|
96
103
|
- spec/adapters/json_api_spec.rb
|