jei 0.1.0 → 0.2.0

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.
@@ -1,12 +1,14 @@
1
1
  module Jei
2
- # @see http://jsonapi.org/format/#document-top-level
3
- class CollectionDataNode < DataNode
4
- # @param [Hash<Symbol, Object>] context
5
- def visit(context)
6
- context[:data] = children.map do |child|
7
- data = {}
8
- child.visit(data)
9
- data
2
+ module Nodes
3
+ # @see http://jsonapi.org/format/#document-top-level
4
+ class CollectionDataNode < DataNode
5
+ # @param [Hash<Symbol, Object>] context
6
+ def visit(context)
7
+ context[:data] = children.map do |child|
8
+ data = {}
9
+ child.visit(data)
10
+ data
11
+ end
10
12
  end
11
13
  end
12
14
  end
@@ -1,16 +1,18 @@
1
1
  module Jei
2
- # @see http://jsonapi.org/format/#document-top-level
3
- class DataNode < Node
4
- # @param [Hash<Symbol, Object>] context
5
- def visit(context)
6
- context[:data] =
7
- if children.empty?
8
- nil
9
- else
10
- data = {}
11
- children.each { |child| child.visit(data) }
12
- data
13
- end
2
+ module Nodes
3
+ # @see http://jsonapi.org/format/#document-top-level
4
+ class DataNode < Node
5
+ # @param [Hash<Symbol, Object>] context
6
+ def visit(context)
7
+ context[:data] =
8
+ if children.empty?
9
+ nil
10
+ else
11
+ data = {}
12
+ children.each { |child| child.visit(data) }
13
+ data
14
+ end
15
+ end
14
16
  end
15
17
  end
16
18
  end
@@ -1,9 +1,11 @@
1
1
  module Jei
2
- # @see http://jsonapi.org/format/1.0/#document-top-level
3
- class DocumentNode < Node
4
- # @param [Hash<Symbol, Object>] context
5
- def visit(context)
6
- children.each { |child| child.visit(context) }
2
+ module Nodes
3
+ # @see http://jsonapi.org/format/1.0/#document-top-level
4
+ class DocumentNode < Node
5
+ # @param [Hash<Symbol, Object>] context
6
+ def visit(context)
7
+ children.each { |child| child.visit(context) }
8
+ end
7
9
  end
8
10
  end
9
11
  end
@@ -1,11 +1,13 @@
1
1
  module Jei
2
- # @see http://jsonapi.org/format/1.0/#document-compound-documents
3
- class IncludedNode < Node
4
- def visit(context)
5
- context[:included] = children.map do |child|
6
- data = {}
7
- child.visit(data)
8
- data
2
+ module Nodes
3
+ # @see http://jsonapi.org/format/1.0/#document-compound-documents
4
+ class IncludedNode < Node
5
+ def visit(context)
6
+ context[:included] = children.map do |child|
7
+ data = {}
8
+ child.visit(data)
9
+ data
10
+ end
9
11
  end
10
12
  end
11
13
  end
@@ -1,9 +1,11 @@
1
1
  module Jei
2
- # @see http://jsonapi.org/format/1.0/#document-jsonapi-object
3
- class JSONAPINode < Node
4
- # @param [Hash<Symbol, Object>] context
5
- def visit(context)
6
- context[:jsonapi] = { version: Document::VERSION }
2
+ module Nodes
3
+ # @see http://jsonapi.org/format/1.0/#document-jsonapi-object
4
+ class JSONAPINode < Node
5
+ # @param [Hash<Symbol, Object>] context
6
+ def visit(context)
7
+ context[:jsonapi] = { version: Document::VERSION }
8
+ end
7
9
  end
8
10
  end
9
11
  end
@@ -1,20 +1,22 @@
1
1
  module Jei
2
- # @see http://jsonapi.org/format/1.0/#document-links
3
- class LinkNode < Node
4
- # @param [Link] link
5
- def initialize(link)
6
- super()
7
- @link = link
8
- end
2
+ module Nodes
3
+ # @see http://jsonapi.org/format/1.0/#document-links
4
+ class LinkNode < Node
5
+ # @param [Link] link
6
+ def initialize(link)
7
+ super()
8
+ @link = link
9
+ end
9
10
 
10
- # @param [Hash<Symbol, Object>] context
11
- def visit(context)
12
- context[@link.name] =
13
- if @link.meta.any?
14
- { href: @link.href, meta: @link.meta }
15
- else
16
- @link.href
17
- end
11
+ # @param [Hash<Symbol, Object>] context
12
+ def visit(context)
13
+ context[@link.name] =
14
+ if @link.meta.any?
15
+ { href: @link.href, meta: @link.meta }
16
+ else
17
+ @link.href
18
+ end
19
+ end
18
20
  end
19
21
  end
20
22
  end
@@ -1,11 +1,13 @@
1
1
  module Jei
2
- # @see http://jsonapi.org/format/1.0/#document-links
3
- class LinksNode < Node
4
- # @param [Hash<Symbol, Object>] context
5
- def visit(context)
6
- data = {}
7
- children.each { |child| child.visit(data) }
8
- context[:links] = data
2
+ module Nodes
3
+ # @see http://jsonapi.org/format/1.0/#document-links
4
+ class LinksNode < Node
5
+ # @param [Hash<Symbol, Object>] context
6
+ def visit(context)
7
+ data = {}
8
+ children.each { |child| child.visit(data) }
9
+ context[:links] = data
10
+ end
9
11
  end
10
12
  end
11
13
  end
@@ -1,15 +1,17 @@
1
1
  module Jei
2
- # @see http://jsonapi.org/format/1.0/#document-meta
3
- class MetaNode < Node
4
- # param [Hash<Symbol, Object>] meta
5
- def initialize(meta)
6
- super()
7
- @meta = meta
8
- end
2
+ module Nodes
3
+ # @see http://jsonapi.org/format/1.0/#document-meta
4
+ class MetaNode < Node
5
+ # param [Hash<Symbol, Object>] meta
6
+ def initialize(meta)
7
+ super()
8
+ @meta = meta
9
+ end
9
10
 
10
- # @param [Hash<Symbol, Object>] context
11
- def visit(context)
12
- context[:meta] = @meta
11
+ # @param [Hash<Symbol, Object>] context
12
+ def visit(context)
13
+ context[:meta] = @meta
14
+ end
13
15
  end
14
16
  end
15
17
  end
@@ -1,17 +1,19 @@
1
1
  module Jei
2
- # @abstract
3
- class Node
4
- # @return [Array<Node>]
5
- attr_reader :children
2
+ module Nodes
3
+ # @abstract
4
+ class Node
5
+ # @return [Array<Node>]
6
+ attr_reader :children
6
7
 
7
- def initialize
8
- @children = []
9
- end
8
+ def initialize
9
+ @children = []
10
+ end
10
11
 
11
- # @abstract
12
- # @param [Hash<Symbol, Object>] _context
13
- def visit(_context)
14
- raise NotImplementedError
12
+ # @abstract
13
+ # @param [Hash<Symbol, Object>] _context
14
+ def visit(_context)
15
+ raise NotImplementedError
16
+ end
15
17
  end
16
18
  end
17
19
  end
@@ -1,17 +1,19 @@
1
1
  module Jei
2
- # @see http://jsonapi.org/format/1.0/#document-resource-object-relationships
3
- class RelationshipNode < Node
4
- # @param [Relationship] relationship
5
- def initialize(relationship)
6
- super()
7
- @relationship = relationship
8
- end
2
+ module Nodes
3
+ # @see http://jsonapi.org/format/1.0/#document-resource-object-relationships
4
+ class RelationshipNode < Node
5
+ # @param [Relationship] relationship
6
+ def initialize(relationship)
7
+ super()
8
+ @relationship = relationship
9
+ end
9
10
 
10
- # @param [Hash<Symbol, Object>] context
11
- def visit(context)
12
- data = {}
13
- children.each { |child| child.visit(data) }
14
- context[@relationship.name] = data
11
+ # @param [Hash<Symbol, Object>] context
12
+ def visit(context)
13
+ data = {}
14
+ children.each { |child| child.visit(data) }
15
+ context[@relationship.name] = data
16
+ end
15
17
  end
16
18
  end
17
19
  end
@@ -1,11 +1,13 @@
1
1
  module Jei
2
- # @see http://jsonapi.org/format/1.0/#document-resource-object-relationships
3
- class RelationshipsNode < Node
4
- # @param [Hash<Symbol, Object>] context
5
- def visit(context)
6
- relationships = {}
7
- children.each { |child| child.visit(relationships) }
8
- context[:relationships] = relationships
2
+ module Nodes
3
+ # @see http://jsonapi.org/format/1.0/#document-resource-object-relationships
4
+ class RelationshipsNode < Node
5
+ # @param [Hash<Symbol, Object>] context
6
+ def visit(context)
7
+ relationships = {}
8
+ children.each { |child| child.visit(relationships) }
9
+ context[:relationships] = relationships
10
+ end
9
11
  end
10
12
  end
11
13
  end
@@ -1,16 +1,18 @@
1
1
  module Jei
2
- # http://jsonapi.org/format/1.0/#document-resource-identifier-objects
3
- class ResourceIdentifierNode < Node
4
- # param [Serializer] serializer
5
- def initialize(serializer)
6
- super()
7
- @serializer = serializer
8
- end
2
+ module Nodes
3
+ # http://jsonapi.org/format/1.0/#document-resource-identifier-objects
4
+ class ResourceIdentifierNode < Node
5
+ # param [Serializer] serializer
6
+ def initialize(serializer)
7
+ super()
8
+ @serializer = serializer
9
+ end
9
10
 
10
- # @param [Hash<Symbol, Object>] context
11
- def visit(context)
12
- context[:id] = @serializer.id
13
- context[:type] = @serializer.type
11
+ # @param [Hash<Symbol, Object>] context
12
+ def visit(context)
13
+ context[:id] = @serializer.id
14
+ context[:type] = @serializer.type
15
+ end
14
16
  end
15
17
  end
16
18
  end
@@ -1,9 +1,11 @@
1
1
  module Jei
2
- # http://jsonapi.org/format/1.0/#document-resource-objects
3
- class ResourceNode < Node
4
- # @param [Hash<Symbol, Object>] context
5
- def visit(context)
6
- children.each { |child| child.visit(context) }
2
+ module Nodes
3
+ # http://jsonapi.org/format/1.0/#document-resource-objects
4
+ class ResourceNode < Node
5
+ # @param [Hash<Symbol, Object>] context
6
+ def visit(context)
7
+ children.each { |child| child.visit(context) }
8
+ end
7
9
  end
8
10
  end
9
11
  end
data/lib/jei/path.rb CHANGED
@@ -1,5 +1,7 @@
1
1
  module Jei
2
2
  class Path
3
+ class NameError < Jei::Error; end
4
+
3
5
  PATH_SEPARATOR = ','
4
6
  NAME_SEPARATOR = '.'
5
7
 
@@ -15,11 +17,11 @@ module Jei
15
17
  end
16
18
 
17
19
  # @param [Array<Path>] paths
18
- # @param [Object] resource
19
- # @param [Set<Object>] resources
20
- def self.find(paths, resource, resources)
20
+ # @param [Serializer] serializer
21
+ # @param [Set<Serializer>] serializers
22
+ def self.find(paths, serializer, serializers)
21
23
  paths.each do |path|
22
- path.walk(resource, resources)
24
+ path.walk(serializer, serializers)
23
25
  end
24
26
  end
25
27
 
@@ -28,22 +30,21 @@ module Jei
28
30
  @names = names
29
31
  end
30
32
 
31
- # @param [Object] root
32
- # @param [Set<Object>] set
33
+ # @param [Serializer] serializer
34
+ # @param [Set<Serializer>] serializers
33
35
  # @param [Integer] level
34
- def walk(root, set = Set.new, level = 0)
36
+ def walk(serializer, serializers, level = 0)
35
37
  return if level >= @names.length
36
38
 
37
- serializer = Serializer.factory(root)
38
-
39
39
  name = @names[level]
40
40
  relationship = serializer.relationships[name]
41
+ raise NameError, "invalid relationship name `#{name}'" unless relationship
41
42
  resources = [*relationship.evaluate(serializer)]
42
43
 
43
- set.merge(resources)
44
-
45
44
  resources.each do |resource|
46
- walk(resource, set, level + 1)
45
+ serializer = Serializer.factory(resource, relationship.options[:serializer])
46
+ serializers << serializer
47
+ walk(serializer, serializers, level + 1)
47
48
  end
48
49
  end
49
50
  end
@@ -1,23 +1,26 @@
1
1
  module Jei
2
- class Relationship < Attribute
2
+ class Relationship < Field
3
3
  # @return [Hash<Symbol, Object>] options
4
4
  attr_reader :options
5
5
 
6
6
  # @param [Symbol] name
7
7
  # @param [Proc, Symbol] value
8
8
  # @param [Hash<Symbol, Object>] options
9
- # @option options [Boolean] :no_data Whether to exclude data from the
10
- # relationship.
11
- # @option options [Proc] :links A Proc that evaulates to a list of links.
9
+ # @option options [Boolean] :data (true) whether to include data in the
10
+ # relationship
11
+ # @option options [Proc] :links a `Proc` that evaulates to a list of links
12
+ # @option options [Class] :serializer override the default serializer used
13
+ # for related resources
12
14
  def initialize(name, value = name, options = {})
13
15
  super(name, value)
16
+ options[:data] = options.fetch(:data, true)
14
17
  @options = options
15
18
  end
16
19
 
17
20
  # @param [Serializer] serializer
18
21
  # @return [Array<Link>]
19
22
  def links(serializer)
20
- serializer.instance_eval(&options[:links])
23
+ serializer.instance_exec(&options[:links])
21
24
  end
22
25
  end
23
26
 
@@ -4,8 +4,8 @@ module Jei
4
4
  attr_reader :resource
5
5
 
6
6
  # @return [Hash<Symbol, Attribute>]
7
- def self.serialization_map
8
- @serialization_map ||= Hash.new { |h, k| h[k] = {} }
7
+ def self.fields
8
+ @fields ||= Hash.new { |h, k| h[k] = {} }
9
9
  end
10
10
 
11
11
  # @overload attributes(name, ...)
@@ -18,27 +18,46 @@ module Jei
18
18
  # @param [Symbol] name
19
19
  def self.attribute(name, &blk)
20
20
  value = block_given? ? blk : name
21
- serialization_map[:attributes][name] = Attribute.new(name, value)
21
+ fields[:attributes][name] = Attribute.new(name, value)
22
22
  end
23
23
 
24
24
  # @param [Symbol] name
25
+ # @param [Hash<Symbol, Object>] options
26
+ # @see Relationship#initialize
25
27
  def self.belongs_to(name, options = {}, &blk)
26
28
  value = block_given? ? blk : name
27
- serialization_map[:relationships][name] =
29
+ fields[:relationships][name] =
28
30
  BelongsToRelationship.new(name, value, options)
29
31
  end
30
32
 
31
33
  # @param [Symbol] name
34
+ # @param [Hash<Symbol, Object>] options
35
+ # @see Relationship#initialize
32
36
  def self.has_many(name, options = {}, &blk)
33
37
  value = block_given? ? blk : name
34
- serialization_map[:relationships][name] =
38
+ fields[:relationships][name] =
35
39
  HasManyRelationship.new(name, value, options)
36
40
  end
37
41
 
42
+ # Instantiates a new serializer based on the type of the given resource.
43
+ #
44
+ # This assumes serializer classes are defined in the global namespace. If
45
+ # not, a serializer class can be passed to override the lookup.
46
+ #
47
+ # @example
48
+ # artist = Artist.new
49
+ #
50
+ # serializer = Serializer.factory(artist)
51
+ # # => #<ArtistSerializer>
52
+ #
53
+ # serializer = Serializer.factory(artist, SimpleArtistSerializer)
54
+ # # => #<SimpleArtistSerializer>
55
+ #
56
+ # @param [Object] resource
57
+ # @param [Class] klass the class used instead of serializer lookup
38
58
  # @return [Serializer]
39
- def self.factory(resource)
40
- name = resource.class.name
41
- klass = const_get("#{name}Serializer")
59
+ def self.factory(resource, klass = nil)
60
+ klass ||= const_get("#{resource.class.name}Serializer")
42
61
  klass.new(resource)
43
62
  end
44
63
 
@@ -57,19 +76,58 @@ module Jei
57
76
  "#{resource.class.name.downcase}s"
58
77
  end
59
78
 
79
+ # @param [Array<Symbol>] fieldset
60
80
  # @return [Hash<Symbol, Attribute>]
61
- def attributes
62
- self.class.serialization_map[:attributes]
81
+ def attributes(fieldset = nil)
82
+ fields(:attributes, fieldset)
63
83
  end
64
84
 
85
+ # @param [Array<Symbol>] fieldset
65
86
  # @return [Hash<Symbol, Relationship>]
66
- def relationships
67
- self.class.serialization_map[:relationships]
87
+ def relationships(fieldset = nil)
88
+ fields(:relationships, fieldset)
68
89
  end
69
90
 
70
91
  # @return [Array<Link>, nil]
71
92
  def links
72
93
  nil
73
94
  end
95
+
96
+ # @return [Array<String>]
97
+ def key
98
+ [type, id]
99
+ end
100
+
101
+ # @return [Boolean]
102
+ def ==(other)
103
+ key == other.key
104
+ end
105
+ alias_method :eql?, :==
106
+
107
+ # @return [Fixnum]
108
+ def hash
109
+ key.hash
110
+ end
111
+
112
+ private
113
+
114
+ # @param [Symbol] type
115
+ # @param [Array<Symbol>] fieldset
116
+ # @return [Hash<Symbol, Field>]
117
+ def fields(type, fieldset = nil)
118
+ fields = self.class.fields[type]
119
+
120
+ if fieldset
121
+ slice = {}
122
+
123
+ fieldset.each do |name|
124
+ slice[name] = fields[name] if fields.has_key?(name)
125
+ end
126
+
127
+ slice
128
+ else
129
+ fields
130
+ end
131
+ end
74
132
  end
75
133
  end