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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +22 -0
- data/README.md +474 -6
- data/lib/jei.rb +15 -13
- data/lib/jei/attribute.rb +1 -19
- data/lib/jei/builders/attributes_node_builder.rb +5 -3
- data/lib/jei/builders/data_node_builder.rb +3 -1
- data/lib/jei/builders/document_builder.rb +24 -31
- data/lib/jei/builders/included_node_builder.rb +9 -6
- data/lib/jei/builders/links_node_builder.rb +3 -1
- data/lib/jei/builders/relationship_node_builder.rb +6 -4
- data/lib/jei/builders/relationships_node_builder.rb +5 -3
- data/lib/jei/builders/resource_node_builder.rb +13 -6
- data/lib/jei/document.rb +14 -10
- data/lib/jei/error.rb +4 -0
- data/lib/jei/field.rb +22 -0
- data/lib/jei/fieldset.rb +15 -0
- data/lib/jei/nodes/attribute_node.rb +14 -12
- data/lib/jei/nodes/attributes_node.rb +9 -7
- data/lib/jei/nodes/collection_data_node.rb +10 -8
- data/lib/jei/nodes/data_node.rb +14 -12
- data/lib/jei/nodes/document_node.rb +7 -5
- data/lib/jei/nodes/included_node.rb +9 -7
- data/lib/jei/nodes/json_api_node.rb +7 -5
- data/lib/jei/nodes/link_node.rb +17 -15
- data/lib/jei/nodes/links_node.rb +9 -7
- data/lib/jei/nodes/meta_node.rb +12 -10
- data/lib/jei/nodes/node.rb +13 -11
- data/lib/jei/nodes/relationship_node.rb +14 -12
- data/lib/jei/nodes/relationships_node.rb +9 -7
- data/lib/jei/nodes/resource_identifier_node.rb +13 -11
- data/lib/jei/nodes/resource_node.rb +7 -5
- data/lib/jei/path.rb +13 -12
- data/lib/jei/relationship.rb +8 -5
- data/lib/jei/serializer.rb +70 -12
- data/lib/jei/version.rb +1 -1
- metadata +6 -2
@@ -1,12 +1,14 @@
|
|
1
1
|
module Jei
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
context
|
7
|
-
data =
|
8
|
-
|
9
|
-
|
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
|
data/lib/jei/nodes/data_node.rb
CHANGED
@@ -1,16 +1,18 @@
|
|
1
1
|
module Jei
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
context
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
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
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
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
|
-
|
3
|
-
|
4
|
-
|
5
|
-
context
|
6
|
-
|
7
|
-
|
8
|
-
|
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
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
context
|
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
|
data/lib/jei/nodes/link_node.rb
CHANGED
@@ -1,20 +1,22 @@
|
|
1
1
|
module Jei
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
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
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
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
|
data/lib/jei/nodes/links_node.rb
CHANGED
@@ -1,11 +1,13 @@
|
|
1
1
|
module Jei
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
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
|
data/lib/jei/nodes/meta_node.rb
CHANGED
@@ -1,15 +1,17 @@
|
|
1
1
|
module Jei
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
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
|
-
|
11
|
-
|
12
|
-
|
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
|
data/lib/jei/nodes/node.rb
CHANGED
@@ -1,17 +1,19 @@
|
|
1
1
|
module Jei
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
2
|
+
module Nodes
|
3
|
+
# @abstract
|
4
|
+
class Node
|
5
|
+
# @return [Array<Node>]
|
6
|
+
attr_reader :children
|
6
7
|
|
7
|
-
|
8
|
-
|
9
|
-
|
8
|
+
def initialize
|
9
|
+
@children = []
|
10
|
+
end
|
10
11
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
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
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
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
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
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
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
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
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
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
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
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
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
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 [
|
19
|
-
# @param [Set<
|
20
|
-
def self.find(paths,
|
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(
|
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 [
|
32
|
-
# @param [Set<
|
33
|
+
# @param [Serializer] serializer
|
34
|
+
# @param [Set<Serializer>] serializers
|
33
35
|
# @param [Integer] level
|
34
|
-
def walk(
|
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
|
-
|
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
|
data/lib/jei/relationship.rb
CHANGED
@@ -1,23 +1,26 @@
|
|
1
1
|
module Jei
|
2
|
-
class Relationship <
|
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] :
|
10
|
-
# relationship
|
11
|
-
# @option options [Proc] :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.
|
23
|
+
serializer.instance_exec(&options[:links])
|
21
24
|
end
|
22
25
|
end
|
23
26
|
|
data/lib/jei/serializer.rb
CHANGED
@@ -4,8 +4,8 @@ module Jei
|
|
4
4
|
attr_reader :resource
|
5
5
|
|
6
6
|
# @return [Hash<Symbol, Attribute>]
|
7
|
-
def self.
|
8
|
-
@
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|