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 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