oat 0.1.2 → 0.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: bf0df88db08a4e8499e855c3297040d5a5624bb1
4
- data.tar.gz: 52a898fa03b0a1e043da33169334a3c40ce981e0
3
+ metadata.gz: 6b724a91b70428b2d8119bb6bdd9a30c814ac10d
4
+ data.tar.gz: 043edf3fd0dcb99075cf01660851e8a183270d1f
5
5
  SHA512:
6
- metadata.gz: 76dc4f30fabc30a43962e608895c1036cc627923e95c0a4dda092b3e5a83c4e0f1b625d14975fd81b2df382d9615e9b8b302abeb8c040a6cbeca061acc0c677c
7
- data.tar.gz: 7b9e468b4ca49e14b54d98d8342fa92254809600e0c93b22fece7ba88bf424c4bd61b36d07e9ea4c86bdb6d2cfd5f0f48fa3227b41c77c8bd1318deabe86aa78
6
+ metadata.gz: 7662b374492e8c20c8e3fbe030d1b08bbcd27665cb4230a4c696142b1e80d6d298eb4870977943ac99d12d20517792c97240d88602b28f29c2bd0974f3bf7455
7
+ data.tar.gz: a4887962d0788adfcb7992a79e21c884ddb92734c690b99f77c9541278003db4c7fbe5c5f1ffae2696c114c58a7236ce621a619ac9c44b3c8d151b4eafee6b47
data/.gitignore CHANGED
@@ -4,6 +4,7 @@
4
4
  .config
5
5
  .yardoc
6
6
  Gemfile.lock
7
+ gemfiles/Gemfile*.lock
7
8
  InstalledFiles
8
9
  _yardoc
9
10
  coverage
@@ -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 object or hash that is passed to the serializer and sub-serializers as the `context` variable. Useful if you need to pass request-specific data.
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 object to serializers
353
+ ### Pass a context hash to serializers
354
354
 
355
- You can pass a context object as second argument to serializers. This object will be passed to nested serializers too. For example, you can pass the controller instance itself.
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.
@@ -0,0 +1,5 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in oat.gemspec
4
+ gem 'activesupport', '1.4.4'
5
+ gemspec :path => "../"
@@ -0,0 +1,5 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in oat.gemspec
4
+ gem 'activesupport', '~>2.3.18'
5
+ gemspec :path => "../"
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in oat.gemspec
4
+ gem 'activesupport', '~>3.0.20'
5
+ gem 'i18n'
6
+ gemspec :path => "../"
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in oat.gemspec
4
+ gem 'activesupport', '~>3.1.12'
5
+ gem 'i18n'
6
+ gemspec :path => "../"
@@ -0,0 +1,5 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in oat.gemspec
4
+ gem 'activesupport', '~>3.2.16'
5
+ gemspec :path => "../"
@@ -0,0 +1,5 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in oat.gemspec
4
+ gem 'activesupport', '~>4.0.2'
5
+ gemspec :path => "../"
@@ -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
@@ -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
 
@@ -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
 
@@ -1,4 +1,4 @@
1
- require 'active_support/core_ext/class/attribute'
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 = nil, _adapter_class = nil, parent_serializer = nil)
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
@@ -1,3 +1,3 @@
1
1
  module Oat
2
- VERSION = "0.1.2"
2
+ VERSION = "0.2.2"
3
3
  end
@@ -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
@@ -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", ">= 4.0"
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"
@@ -5,63 +5,78 @@ describe Oat::Adapters::HAL do
5
5
 
6
6
  include Fixtures
7
7
 
8
- subject{ serializer_class.new(user, {:name => 'some_controller'}, Oat::Adapters::HAL) }
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
- subject.to_hash.tap do |h|
13
+ expect(hash).to include(
13
14
  # properties
14
- h[:id].should == user.id
15
- h[:name].should == user.name
16
- h[:age].should == user.age
17
- h[:controller_name].should == 'some_controller'
18
- # links
19
- h[:_links][:self][:href].should == "http://foo.bar.com/#{user.id}"
20
- # HAL Spec says href is REQUIRED
21
- h[:_links].should_not include(:empty)
22
- # embedded manager
23
- h[:_embedded][:manager].tap do |m|
24
- m[:id].should == manager.id
25
- m[:name].should == manager.name
26
- m[:age].should == manager.age
27
- m[:_links][:self][:href].should == "http://foo.bar.com/#{manager.id}"
28
- end
29
- # embedded friends
30
- h[:_embedded][:friends].size.should == 1
31
- h[:_embedded][:friends][0].tap do |f|
32
- f[:id].should == friend.id
33
- f[:name].should == friend.name
34
- f[:age].should == friend.age
35
- f[:controller_name].should == 'some_controller'
36
- f[:_links][:self][:href].should == "http://foo.bar.com/#{friend.id}"
37
- end
38
- end
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
- subject.to_hash.tap do |h|
46
- # properties
47
- h[:id].should == user.id
48
- h[:name].should == user.name
49
- h[:age].should == user.age
50
- h[:controller_name].should == 'some_controller'
51
- # links
52
- h[:_links][:self][:href].should == "http://foo.bar.com/#{user.id}"
53
- # embedded manager
54
- h[:_embedded].fetch(:manager).should be_nil
55
- # embedded friends
56
- h[:_embedded][:friends].size.should == 1
57
- h[:_embedded][:friends][0].tap do |f|
58
- f[:id].should == friend.id
59
- f[:name].should == friend.name
60
- f[:age].should == friend.age
61
- f[:controller_name].should == 'some_controller'
62
- f[:_links][:self][:href].should == "http://foo.bar.com/#{friend.id}"
63
- end
64
- end
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
- subject{ serializer_class.new(user, {:name => 'some_controller'}, Oat::Adapters::JsonAPI) }
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
- payload = subject.to_hash
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
- payload[:linked][:friends][0].tap do |f|
15
- f[:id].should == friend.id
16
- f[:name].should == friend.name
17
- f[:age].should == friend.age
18
- f[:controller_name].should == 'some_controller'
19
- f[:links][:self].should == "http://foo.bar.com/#{friend.id}"
20
- end
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
- # embedded manager
23
- payload[:linked][:managers][0].tap do |m|
24
- m[:id].should == manager.id
25
- m[:name].should == manager.name
26
- m[:age].should == manager.age
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
- payload[:users][0].tap do |h|
31
- h[:id].should == user.id
32
- h[:name].should == user.name
33
- h[:age].should == user.age
34
- h[:controller_name].should == 'some_controller'
35
- # links
36
- h[:links][:self].should == "http://foo.bar.com/#{user.id}"
37
- # these links are added by embedding entities
38
- h[:links][:manager].should == manager.id
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
- payload = subject.to_hash
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
- payload[:linked][:friends][0].tap do |f|
50
- f[:id].should == friend.id
51
- f[:name].should == friend.name
52
- f[:age].should == friend.age
53
- f[:controller_name].should == 'some_controller'
54
- f[:links][:self].should == "http://foo.bar.com/#{friend.id}"
55
- end
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
- # embedded manager
58
- payload[:linked].fetch(:managers).should be_empty
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
- payload[:users][0].tap do |h|
61
- h[:id].should == user.id
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
@@ -5,82 +5,110 @@ describe Oat::Adapters::Siren do
5
5
 
6
6
  include Fixtures
7
7
 
8
- subject{ serializer_class.new(user, {:name => 'some_controller'}, Oat::Adapters::Siren) }
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
- subject.to_hash.tap do |h|
13
- #siren class
14
- h[:class].should == ['user']
15
- # properties
16
- h[:properties][:id].should == user.id
17
- h[:properties][:name].should == user.name
18
- h[:properties][:age].should == user.age
19
- h[:properties][:controller_name].should == 'some_controller'
20
- # links
21
- h[:links][0][:rel].should == [:self]
22
- h[:links][0][:href].should == "http://foo.bar.com/#{user.id}"
23
- # embedded manager
24
- h[:entities][1].tap do |m|
25
- m[:class].should == ['manager']
26
- m[:properties][:id].should == manager.id
27
- m[:properties][:name].should == manager.name
28
- m[:properties][:age].should == manager.age
29
- m[:links][0][:rel].should == [:self]
30
- m[:links][0][:href].should == "http://foo.bar.com/#{manager.id}"
31
- end
32
- # embedded friends
33
- h[:entities][0].tap do |f|
34
- f[:class].should == ['user']
35
- f[:properties][:id].should == friend.id
36
- f[:properties][:name].should == friend.name
37
- f[:properties][:age].should == friend.age
38
- f[:properties][:controller_name].should == 'some_controller'
39
- f[:links][0][:rel].should == [:self]
40
- f[:links][0][:href].should == "http://foo.bar.com/#{friend.id}"
41
- end
42
- # action close_account
43
- h[:actions][0].tap do |a|
44
- a[:name].should == :close_account
45
- a[:href].should == "http://foo.bar.com/#{user.id}/close_account"
46
- a[:class].should == ['danger', 'irreversible']
47
- a[:method].should == 'DELETE'
48
- a[:fields][0].tap do |f|
49
- f[:name].should == :current_password
50
- f[:type].should == :password
51
- end
52
- end
53
- end
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
- subject.to_hash.tap do |h|
61
- #siren class
62
- h[:class].should == ['user']
63
- # properties
64
- h[:properties][:id].should == user.id
65
- h[:properties][:name].should == user.name
66
- h[:properties][:age].should == user.age
67
- h[:properties][:controller_name].should == 'some_controller'
68
- # links
69
- h[:links][0][:rel].should == [:self]
70
- h[:links][0][:href].should == "http://foo.bar.com/#{user.id}"
71
- # embedded manager
72
- h[:entities].any?{|o| o[:class].include?("manager")}.should be_false
73
- # embedded friends
74
- h[:entities][0].tap do |f|
75
- f[:class].should == ['user']
76
- f[:properties][:id].should == friend.id
77
- f[:properties][:name].should == friend.name
78
- f[:properties][:age].should == friend.age
79
- f[:properties][:controller_name].should == 'some_controller'
80
- f[:links][0][:rel].should == [:self]
81
- f[:links][0][:href].should == "http://foo.bar.com/#{friend.id}"
82
- end
83
- end
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
@@ -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'
@@ -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.tap do |h|
59
- h[:attributes][:special].should == 'Hello'
60
- h[:attributes][:id].should == user1.id
61
- h[:attributes][:name].should == user1.name
62
- h[:attributes][:age].should == user1.age
63
- h[:attributes][:controller_name].should == 'some_controller'
64
- h[:links][:self].should == "http://foo.bar.com/#{user1.id}"
65
- end
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.1.2
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-13 00:00:00.000000000 Z
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: '4.0'
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: '4.0'
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