jsonapi-serializable 0.1.1.beta1

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 366782323070f412105463eeffabe870128e49c6
4
+ data.tar.gz: d80674ddfaa130ea341f286c3f12c87ef5e75016
5
+ SHA512:
6
+ metadata.gz: 1bb696480c7e20a3dbe1b4d1525301bb0203b7fbe444268a7fd96bb8d684cdc8bddf8e9ed74161b261375f88e1962f8d1f7363647a544f7b040a9aa73aafdd2f
7
+ data.tar.gz: 9d17c652fc934460c7d1ef1249d1c32336671ce3fd26ade2acb0d430c98b24f40b56086d719ac481e77a6b6744f1225071564c5101f74b72b2e65b47d3f42160
data/README.md ADDED
@@ -0,0 +1,80 @@
1
+ # jsonapi-serializable
2
+ Ruby gem for building and rendering [JSON API](http://jsonapi.org) resources.
3
+ Built upon the [jsonapi-renderer](https://github.com/beauby/jsonapi) gem.
4
+
5
+ ## Installation
6
+ ```ruby
7
+ # In Gemfile
8
+ gem 'jsonapi-serializable'
9
+ ```
10
+ then
11
+ ```
12
+ $ bundle
13
+ ```
14
+ or manually via
15
+ ```
16
+ $ gem install jsonapi-serializable
17
+ ```
18
+
19
+ ## Usage
20
+
21
+ First, require the gem:
22
+ ```ruby
23
+ require 'jsonapi/serializable'
24
+ ```
25
+
26
+ Then, define some resource classes:
27
+ ```ruby
28
+ class PostResource < JSONAPI::Serializable::Resource
29
+ type 'posts'
30
+
31
+ id do
32
+ @post.id.to_s
33
+ end
34
+
35
+ attribute :title do
36
+ @post.title
37
+ end
38
+
39
+ attribute :date do
40
+ @post.date
41
+ end
42
+
43
+ relationship :author do
44
+ link(:self) do
45
+ href @url_helper.link_for_rel('posts', @post.id, 'author')
46
+ meta link_meta: 'some meta'
47
+ end
48
+ link(:related) { @url_helper.link_for_res('users', @post.author.id) }
49
+ data do
50
+ if @post.author.nil?
51
+ nil
52
+ else
53
+ UserResource.new(user: @post.author, url_helper: @url_helper)
54
+ end
55
+ end
56
+ meta do
57
+ { relationship_meta: 'some meta' }
58
+ end
59
+ end
60
+
61
+ meta do
62
+ { resource_meta: 'some meta' }
63
+ end
64
+
65
+ link(:self) do
66
+ @url_helper.link_for_res('posts', @post.id)
67
+ end
68
+ end
69
+ ```
70
+ Finally, build your resources from your models and render them:
71
+ ```ruby
72
+ # post = some post model
73
+ # UrlHelper is some helper class
74
+ resource = PostResource.new(post: post, url_helper: UrlHelper)
75
+ document = JSONAPI.render(resource)
76
+ ```
77
+
78
+ ## License
79
+
80
+ jsonapi-serializable is released under the [MIT License](http://www.opensource.org/licenses/MIT).
@@ -0,0 +1,82 @@
1
+ require 'jsonapi/serializable/link'
2
+ require 'jsonapi/serializable/error_dsl'
3
+
4
+ module JSONAPI
5
+ module Serializable
6
+ class ErrorSource
7
+ def self.as_jsonapi(params = {})
8
+ self.class.new(params).as_jsonapi
9
+ end
10
+
11
+ def initialize(params = {})
12
+ params.each { |k, v| instance_variable_set("@#{k}", v) }
13
+ @_data = {}
14
+ end
15
+
16
+ def as_jsonapi
17
+ @_data
18
+ end
19
+
20
+ private
21
+
22
+ def method_missing(name, arg)
23
+ @_data[name] = arg
24
+ end
25
+ end
26
+
27
+ class Error
28
+ include ErrorDSL
29
+
30
+ class << self
31
+ attr_accessor :id, :id_block, :status, :status_block, :code,
32
+ :code_block, :title, :title_block, :detail, :detail_block,
33
+ :meta, :meta_block, :source_block, :link_blocks
34
+ end
35
+
36
+ self.link_blocks = {}
37
+
38
+ def self.inherited(klass)
39
+ super
40
+ klass.link_blocks = self.class.link_blocks.dup
41
+ end
42
+
43
+ def initialize(params = {})
44
+ @_param_hash = params
45
+ params.each { |k, v| instance_variable_set("@#{k}", v) }
46
+ end
47
+
48
+ def as_jsonapi
49
+ hash = links.any? ? { links: links } : {}
50
+ [:id, :status, :code, :title, :detail, :meta, :source]
51
+ .each_with_object(hash) do |key, h|
52
+ value = send(key)
53
+ h[key] = value unless value.nil?
54
+ end
55
+ end
56
+
57
+ private
58
+
59
+ def links
60
+ @_links ||= self.class.link_blocks.each_with_object({}) do |(k, v), h|
61
+ h[k] = Link.as_jsonapi(@_param_hash, v)
62
+ end
63
+ end
64
+
65
+ def source
66
+ @_source ||= ErrorSource.as_jsonapi(@_param_hash,
67
+ self.class.source_block)
68
+ end
69
+
70
+ [:id, :status, :code, :title, :detail, :meta].each do |key|
71
+ define_method(key) do
72
+ unless instance_variable_defined?("@#{key}")
73
+ value = self.class.send(key) ||
74
+ instance_eval(self.class.send("#{key}_block"))
75
+ instance_variable_set("@#{key}", value)
76
+ end
77
+ instance_variable_get("@#{key}")
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,26 @@
1
+ module JSONAPI
2
+ module Serializable
3
+ module ErrorDSL
4
+ def self.included(base)
5
+ base.extend(ClassMethods)
6
+ end
7
+
8
+ module ClassMethods
9
+ [:id, :status, :code, :title, :detail, :meta].each do |key|
10
+ define_method(key) do |*args, &block|
11
+ send("@#{key}=", args[0])
12
+ send("@#{key}_block=", block)
13
+ end
14
+ end
15
+
16
+ def link(name, &block)
17
+ link_blocks[name] = block
18
+ end
19
+
20
+ def source(&block)
21
+ self.source_block = block
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,65 @@
1
+ module JSONAPI
2
+ module Serializable
3
+ class Link
4
+ def self.as_jsonapi(param_hash = {}, &block)
5
+ new(param_hash, &block).as_jsonapi
6
+ end
7
+
8
+ def initialize(param_hash = {}, &block)
9
+ param_hash.each { |k, v| instance_variable_set("@#{k}", v) }
10
+ static_value = instance_eval(&block)
11
+ if static_value.is_a?(Hash)
12
+ @_hash = static_value
13
+ elsif static_value.is_a?(String)
14
+ @_href = static_value
15
+ end
16
+ end
17
+
18
+ # @overload href(value)
19
+ # Declare the href for this link.
20
+ # @param [String] value The value of href.
21
+ #
22
+ # @example
23
+ # href "http://api.example.com/users/#{@user.id}"
24
+ #
25
+ # @overload href(&block)
26
+ # Declare the href for this link.
27
+ # @yieldreturn [String] The value of href.
28
+ #
29
+ # @example
30
+ # href do
31
+ # "http://api.example.com/users/#{@user.id}"
32
+ # end
33
+ def href(value = nil, &block)
34
+ @_href = block.nil? ? value : instance_eval(&block)
35
+ end
36
+
37
+ # @overload meta(value)
38
+ # Declare the meta information for this link.
39
+ # @param [Hash] value The meta information hash.
40
+ #
41
+ # @example
42
+ # meta paginated: true
43
+ #
44
+ # @overload meta(&block)
45
+ # Declare the meta information for this link.
46
+ # @yieldreturn [String] The meta information hash.
47
+ # @example
48
+ # meta do
49
+ # { paginated: true }
50
+ # end
51
+ def meta(value = nil, &block)
52
+ @_meta = block.nil? ? value : instance_eval(&block)
53
+ end
54
+
55
+ def as_jsonapi
56
+ @_hash ||=
57
+ if @_meta.nil?
58
+ @_href
59
+ else
60
+ { href: @_href, meta: @_meta }
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,42 @@
1
+ require 'jsonapi/serializable/link'
2
+ require 'jsonapi/serializable/relationship_dsl'
3
+
4
+ module JSONAPI
5
+ module Serializable
6
+ class Relationship
7
+ include RelationshipDSL
8
+
9
+ def initialize(param_hash = {}, &block)
10
+ param_hash.each { |k, v| instance_variable_set("@#{k}", v) }
11
+ @_param_hash = param_hash
12
+ @_links = {}
13
+ instance_eval(&block)
14
+ end
15
+
16
+ def as_jsonapi(included)
17
+ hash = {}
18
+ hash[:links] = @_links if @_links.any?
19
+ hash[:meta] = @_meta unless @_meta.nil?
20
+ hash[:data] = eval_linkage_data if included && (@_linkage_data_block ||
21
+ @_data_block)
22
+
23
+ hash
24
+ end
25
+
26
+ private
27
+
28
+ def eval_linkage_data
29
+ @_linkage_data ||=
30
+ if @_linkage_data_block
31
+ @_linkage_data_block.call
32
+ elsif data.respond_to?(:each)
33
+ data.map { |res| { type: res.jsonapi_type, id: res.jsonapi_id } }
34
+ elsif data.nil?
35
+ nil
36
+ else
37
+ { type: data.jsonapi_type, id: data.jsonapi_id }
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,82 @@
1
+ module JSONAPI
2
+ module Serializable
3
+ module RelationshipDSL
4
+ # Declare/access the data for this relationship.
5
+ #
6
+ # @yieldreturn [JSONAPI::Serializable::Resource,
7
+ # Array<JSONAPI::Serializable::Resource>,
8
+ # nil] The data for this relationship.
9
+ #
10
+ # @example
11
+ # data :posts do
12
+ # @user.posts.map { |p| PostResource.new(post: p) }
13
+ # end
14
+ #
15
+ # @example
16
+ # data :author do
17
+ # @user.author && UserResource.new(user: @user.author)
18
+ # end
19
+ def data(&block)
20
+ if block.nil?
21
+ @_data ||= (@_data_block && @_data_block.call)
22
+ else
23
+ @_data_block = block
24
+ end
25
+ end
26
+
27
+ # Declare the linkage data for this relationship. Useful when linkage
28
+ # can be computed in a more efficient way than the data itself.
29
+ #
30
+ # @yieldreturn [Hash] The block to compute linkage data.
31
+ #
32
+ # @example
33
+ # linkage_data do
34
+ # { id: @post.author_id.to_s, type: 'users' }
35
+ # end
36
+ def linkage_data(&block)
37
+ @_linkage_data_block = block
38
+ end
39
+
40
+ # @overload meta(value)
41
+ # Declare the meta information for this relationship.
42
+ # @param [Hash] value The meta information hash.
43
+ #
44
+ # @example
45
+ # meta paginated: true
46
+ #
47
+ # @overload meta(&block)
48
+ # Declare the meta information for this relationship.
49
+ # @yieldreturn [Hash] The meta information hash.
50
+ #
51
+ # @example
52
+ # meta do
53
+ # { paginated: true }
54
+ # end
55
+ def meta(value = nil)
56
+ @_meta = value || yield
57
+ end
58
+
59
+ # Declare a link for this relationship. The properties of the link are set
60
+ # by providing a block in which the DSL methods of
61
+ # +JSONAPI::Serializable::Link+ are called.
62
+ # @see JSONAPI::Serialiable::Link
63
+ #
64
+ # @param [Symbol] name The key of the link.
65
+ # @yieldreturn [Hash, String, nil] The block to compute the value, if any.
66
+ #
67
+ # @example
68
+ # link(:self) do
69
+ # "http://api.example.com/users/#{@user.id}/relationships/posts"
70
+ # end
71
+ #
72
+ # @example
73
+ # link(:related) do
74
+ # href "http://api.example.com/users/#{@user.id}/posts"
75
+ # meta authorization_needed: true
76
+ # end
77
+ def link(name, &block)
78
+ @_links[name] = Link.as_jsonapi(@_param_hash, &block)
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,92 @@
1
+ require 'jsonapi/serializable/link'
2
+ require 'jsonapi/serializable/relationship'
3
+ require 'jsonapi/serializable/resource_dsl'
4
+
5
+ module JSONAPI
6
+ module Serializable
7
+ class Resource
8
+ include ResourceDSL
9
+
10
+ class << self
11
+ attr_accessor :type_val, :type_block, :id_block, :attribute_blocks,
12
+ :relationship_blocks, :link_blocks, :meta_val, :meta_block
13
+ end
14
+
15
+ self.attribute_blocks = {}
16
+ self.relationship_blocks = {}
17
+ self.link_blocks = {}
18
+
19
+ def self.inherited(klass)
20
+ super
21
+ klass.attribute_blocks = attribute_blocks.dup
22
+ klass.relationship_blocks = relationship_blocks.dup
23
+ klass.link_blocks = link_blocks.dup
24
+ end
25
+
26
+ def initialize(param_hash = {})
27
+ param_hash.each { |k, v| instance_variable_set("@#{k}", v) }
28
+ @_id = instance_eval(&self.class.id_block)
29
+ @_type = self.class.type_val || instance_eval(&self.class.type_block)
30
+ @_meta = if self.class.meta_val
31
+ self.class.meta_val
32
+ elsif self.class.meta_block
33
+ instance_eval(&self.class.meta_block)
34
+ end
35
+ @_attributes = {}
36
+ @_relationships = self.class.relationship_blocks
37
+ .each_with_object({}) do |(k, v), h|
38
+ h[k] = Relationship.new(param_hash, &v)
39
+ end
40
+ @_links = self.class.link_blocks.each_with_object({}) do |(k, v), h|
41
+ h[k] = Link.as_jsonapi(param_hash, &v)
42
+ end
43
+ end
44
+
45
+ def as_jsonapi(params = {})
46
+ hash = {}
47
+ hash[:id] = @_id
48
+ hash[:type] = @_type
49
+ attr = attributes(params[:fields] || self.class.attribute_blocks.keys)
50
+ hash[:attributes] = attr if attr.any?
51
+ rels = relationships(params[:fields] || @_relationships.keys,
52
+ params[:include] || [])
53
+ hash[:relationships] = rels if rels.any?
54
+ hash[:links] = @_links if @_links.any?
55
+ hash[:meta] = @_meta unless @_meta.nil?
56
+
57
+ hash
58
+ end
59
+
60
+ def jsonapi_type
61
+ @_type
62
+ end
63
+
64
+ def jsonapi_id
65
+ @_id
66
+ end
67
+
68
+ def jsonapi_related(include)
69
+ @_relationships
70
+ .select { |k, _| include.include?(k) }
71
+ .each_with_object({}) { |(k, v), h| h[k] = Array(v.data) }
72
+ end
73
+
74
+ private
75
+
76
+ def attributes(fields)
77
+ self.class.attribute_blocks
78
+ .select { |k, _| !@_attributes.key?(k) && fields.include?(k) }
79
+ .each { |k, v| @_attributes[k] = instance_eval(&v) }
80
+ @_attributes.select { |k, _| fields.include?(k) }
81
+ end
82
+
83
+ def relationships(fields, include)
84
+ @_relationships
85
+ .select { |k, _| fields.include?(k) }
86
+ .each_with_object({}) do |(k, v), h|
87
+ h[k] = v.as_jsonapi(include.include?(k))
88
+ end
89
+ end
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,127 @@
1
+ module JSONAPI
2
+ module Serializable
3
+ module ResourceDSL
4
+ def self.included(base)
5
+ base.extend(ClassMethods)
6
+ end
7
+
8
+ module ClassMethods
9
+ # @overload type(value)
10
+ # Declare the JSON API type of this resource.
11
+ # @param [String] value The value of the type.
12
+ #
13
+ # @example
14
+ # type 'users'
15
+ #
16
+ # @overload type(value)
17
+ # Declare the JSON API type of this resource.
18
+ # @yieldreturn [String] The value of the type.
19
+ #
20
+ # @example
21
+ # type { @user.admin? ? "admin" : "users" }
22
+ def type(value = nil, &block)
23
+ self.type_val = value
24
+ self.type_block = block
25
+ end
26
+
27
+ # Declare the JSON API id of this resource.
28
+ #
29
+ # @yieldreturn [String] The id of the resource.
30
+ #
31
+ # @example
32
+ # id { @user.id.to_s }
33
+ def id(&block)
34
+ self.id_block = block
35
+ end
36
+
37
+ # @overload meta(value)
38
+ # Declare the meta information for this resource.
39
+ # @param [Hash] value The meta information hash.
40
+ #
41
+ # @example
42
+ # meta key: value
43
+ #
44
+ # @overload meta(&block)
45
+ # Declare the meta information for this resource.
46
+ # @yieldreturn [String] The meta information hash.
47
+ # @example
48
+ # meta do
49
+ # { key: value }
50
+ # end
51
+ def meta(value = nil, &block)
52
+ self.meta_val = value
53
+ self.meta_block = block
54
+ end
55
+
56
+ # Declare an attribute for this resource.
57
+ #
58
+ # @param [Symbol] name The key of the attribute.
59
+ # @yieldreturn [Hash, String, nil] The block to compute the value.
60
+ #
61
+ # @example
62
+ # attribute(:name) { @user.name }
63
+ def attribute(name, &block)
64
+ attribute_blocks[name] = block
65
+ end
66
+
67
+ # Declare a relationship for this resource. The properties of the
68
+ # relationship are set by providing a block in which the DSL methods
69
+ # of +JSONAPI::Serializable::Relationship+ are called.
70
+ # @see JSONAPI::Serializable::Relationship
71
+ #
72
+ # @param [Symbol] name The key of the relationship.
73
+ #
74
+ # @example
75
+ # relationship :posts do
76
+ # data { @user.posts.map { |p| PostResource.new(post: p) } }
77
+ # end
78
+ #
79
+ # @example
80
+ # relationship :author do
81
+ # data do
82
+ # @post.author && UserResource.new(user: @post.author)
83
+ # end
84
+ # linkage_data do
85
+ # { type: 'users', id: @post.author_id }
86
+ # end
87
+ # link(:self) do
88
+ # "http://api.example.com/posts/#{@post.id}/relationships/author"
89
+ # end
90
+ # link(:related) do
91
+ # "http://api.example.com/posts/#{@post.id}/author"
92
+ # end
93
+ # meta do
94
+ # { author_online: @post.author.online? }
95
+ # end
96
+ # end
97
+ def relationship(name, &block)
98
+ relationship_blocks[name] = block
99
+ end
100
+
101
+ # Declare a link for this resource. The properties of the link are set
102
+ # by providing a block in which the DSL methods of
103
+ # +JSONAPI::Serializable::Link+ are called, or the value of the link
104
+ # is returned directly.
105
+ # @see JSONAPI::Serialiable::Link
106
+ #
107
+ # @param [Symbol] name The key of the link.
108
+ # @yieldreturn [Hash, String, nil] The block to compute the value, if
109
+ # any.
110
+ #
111
+ # @example
112
+ # link(:self) do
113
+ # "http://api.example.com/users/#{@user.id}"
114
+ # end
115
+ #
116
+ # @example
117
+ # link(:self) do
118
+ # href "http://api.example.com/users/#{@user.id}"
119
+ # meta is_self: true
120
+ # end
121
+ def link(name, &block)
122
+ link_blocks[name] = block
123
+ end
124
+ end
125
+ end
126
+ end
127
+ end
@@ -0,0 +1,2 @@
1
+ require 'jsonapi/serializable/error'
2
+ require 'jsonapi/serializable/resource'
@@ -0,0 +1,93 @@
1
+ require 'jsonapi/serializable_link'
2
+
3
+ module JSONAPI
4
+ class SerializableErrorSource
5
+ def self.as_jsonapi(params = {})
6
+ self.class.new(params).as_jsonapi
7
+ end
8
+
9
+ def initialize(params = {})
10
+ params.each { |k, v| instance_variable_set("@#{k}", v) }
11
+ @_data = {}
12
+ end
13
+
14
+ def as_jsonapi
15
+ @_data
16
+ end
17
+
18
+ private
19
+
20
+ def method_missing(name, arg)
21
+ @_data[name] = arg
22
+ end
23
+ end
24
+
25
+ class SerializableError
26
+ class << self
27
+ attr_accessor :id, :id_block, :status, :status_block, :code, :code_block,
28
+ :title, :title_block, :detail, :detail_block, :meta,
29
+ :meta_block, :source_block, :link_blocks
30
+
31
+ [:id, :status, :code, :title, :detail, :meta].each do |key|
32
+ define_method(key) do |*args, &block|
33
+ send("@#{key}=", args[0])
34
+ send("@#{key}_block=", block)
35
+ end
36
+ end
37
+
38
+ def link(name, &block)
39
+ link_blocks[name] = block
40
+ end
41
+
42
+ def source(&block)
43
+ self.source_block = block
44
+ end
45
+ end
46
+
47
+ self.link_blocks = {}
48
+
49
+ def self.inherited(klass)
50
+ super
51
+ klass.link_blocks = self.class.link_blocks.dup
52
+ end
53
+
54
+ def initialize(params = {})
55
+ @_param_hash = params
56
+ params.each { |k, v| instance_variable_set("@#{k}", v) }
57
+ end
58
+
59
+ def as_jsonapi
60
+ hash = links.any? ? { links: links } : {}
61
+ [:id, :status, :code, :title, :detail, :meta, :source]
62
+ .each_with_object(hash) do |key, h|
63
+ value = send(key)
64
+ h[key] = value unless value.nil?
65
+ end
66
+ end
67
+
68
+ private
69
+
70
+ def links
71
+ @_links ||= self.class.link_blocks.each_with_object({}) do |(k, v), h|
72
+ h[k] = JSONAPI::SerializableLink.as_jsonapi(@_param_hash, v)
73
+ end
74
+ end
75
+
76
+ def source
77
+ @_source ||=
78
+ JSONAPI::SerializableErrorSource.as_jsonapi(@_param_hash,
79
+ self.class.source_block)
80
+ end
81
+
82
+ [:id, :status, :code, :title, :detail, :meta].each do |key|
83
+ define_method(key) do
84
+ unless instance_variable_defined?("@#{key}")
85
+ instance_variable_set("@#{key}",
86
+ self.class.send(key) ||
87
+ instance_eval(self.class.send("#{key}_block")))
88
+ end
89
+ instance_variable_get("@#{key}")
90
+ end
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,34 @@
1
+ module JSONAPI
2
+ class SerializableLink
3
+ def self.as_jsonapi(param_hash = {}, &block)
4
+ new(param_hash, &block).as_jsonapi
5
+ end
6
+
7
+ def initialize(param_hash = {}, &block)
8
+ param_hash.each do |k, v|
9
+ instance_variable_set("@#{k}", v)
10
+ end
11
+ str_value = instance_eval(&block)
12
+ @_href ||= str_value
13
+ end
14
+
15
+ def as_jsonapi
16
+ @_hash ||=
17
+ if @_meta.nil?
18
+ @_href
19
+ else
20
+ { href: @_href, meta: @_meta }
21
+ end
22
+ end
23
+
24
+ private
25
+
26
+ def href(value = nil, &block)
27
+ @_href = block.nil? ? value : instance_eval(&block)
28
+ end
29
+
30
+ def meta(value = nil, &block)
31
+ @_meta = block.nil? ? value : instance_eval(&block)
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,56 @@
1
+ require 'jsonapi/serializable_link'
2
+
3
+ module JSONAPI
4
+ class SerializableRelationship
5
+ def initialize(param_hash = {}, &block)
6
+ @_param_hash = param_hash
7
+ @_param_hash.each { |k, v| instance_variable_set("@#{k}", v) }
8
+ @_links = {}
9
+ instance_eval(&block)
10
+ end
11
+
12
+ def data(&block)
13
+ if block.nil?
14
+ @_data ||= @_data_block.call
15
+ else
16
+ @_data_block = block
17
+ end
18
+ end
19
+
20
+ def as_jsonapi(included)
21
+ hash = {}
22
+ hash[:links] = @_links if @_links.any?
23
+ hash[:meta] = @_meta unless @_meta.nil?
24
+ hash[:data] = eval_linkage_data if included
25
+
26
+ hash
27
+ end
28
+
29
+ private
30
+
31
+ def eval_linkage_data
32
+ @_linkage_data ||=
33
+ if @_linkage_data_block
34
+ @_linkage_data_block.call
35
+ elsif data.respond_to?(:each)
36
+ data.map { |res| { type: res.jsonapi_type, id: res.jsonapi_id } }
37
+ elsif data.nil?
38
+ nil
39
+ else
40
+ { type: data.jsonapi_type, id: data.jsonapi_id }
41
+ end
42
+ end
43
+
44
+ def linkage_data(&block)
45
+ @_linkage_data_block = block
46
+ end
47
+
48
+ def meta(value = nil)
49
+ @_meta = value || yield
50
+ end
51
+
52
+ def link(name, &block)
53
+ @_links[name] = JSONAPI::SerializableLink.as_jsonapi(@_param_hash, &block)
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,114 @@
1
+ require 'jsonapi/serializable_link'
2
+ require 'jsonapi/serializable_relationship'
3
+
4
+ module JSONAPI
5
+ class SerializableResource
6
+ class << self
7
+ attr_accessor :type_val, :type_block, :id_block, :attribute_blocks,
8
+ :relationship_blocks, :link_blocks, :meta_val, :meta_block
9
+
10
+ def type(value = nil, &block)
11
+ self.type_val = value
12
+ self.type_block = block
13
+ end
14
+
15
+ def id(&block)
16
+ self.id_block = block
17
+ end
18
+
19
+ def meta(value = nil, &block)
20
+ self.meta_val = value
21
+ self.meta_block = block
22
+ end
23
+
24
+ def attribute(name, &block)
25
+ attribute_blocks[name] = block
26
+ end
27
+
28
+ def relationship(name, &block)
29
+ relationship_blocks[name] = block
30
+ end
31
+
32
+ def link(name, &block)
33
+ link_blocks[name] = block
34
+ end
35
+ end
36
+
37
+ self.attribute_blocks = {}
38
+ self.relationship_blocks = {}
39
+ self.link_blocks = {}
40
+
41
+ def self.inherited(klass)
42
+ super
43
+ klass.attribute_blocks = attribute_blocks.dup
44
+ klass.relationship_blocks = relationship_blocks.dup
45
+ klass.link_blocks = link_blocks.dup
46
+ end
47
+
48
+ def initialize(param_hash = {})
49
+ param_hash.each { |k, v| instance_variable_set("@#{k}", v) }
50
+ @_id = instance_eval(&self.class.id_block)
51
+ @_type = self.class.type_val || instance_eval(&self.class.type_block)
52
+ @_meta = if self.class.meta_val
53
+ self.class.meta_val
54
+ elsif self.class.meta_block
55
+ instance_eval(&self.class.meta_block)
56
+ end
57
+ @_attributes = {}
58
+ @_relationships = self.class.relationship_blocks
59
+ .each_with_object({}) do |(k, v), h|
60
+ h[k] = JSONAPI::SerializableRelationship.new(param_hash, &v)
61
+ end
62
+ @_links = self.class.link_blocks
63
+ .each_with_object({}) do |(k, v), h|
64
+ h[k] = JSONAPI::SerializableLink.as_jsonapi(param_hash, &v)
65
+ end
66
+ end
67
+
68
+ def as_jsonapi(params = {})
69
+ hash = {}
70
+ hash[:id] = @_id
71
+ hash[:type] = @_type
72
+ attr = attributes(params[:fields] || @_attributes.keys)
73
+ hash[:attributes] = attr if attr.any?
74
+ rels = relationships(params[:field] || @_relationships.keys,
75
+ params[:include] || [])
76
+ hash[:relationships] = rels if rels.any?
77
+ hash[:links] = @_links if @_links.any?
78
+ hash[:meta] = @_meta unless @_meta.nil?
79
+
80
+ hash
81
+ end
82
+
83
+ def jsonapi_type
84
+ @_type
85
+ end
86
+
87
+ def jsonapi_id
88
+ @_id
89
+ end
90
+
91
+ def jsonapi_related(include)
92
+ @_relationships
93
+ .select { |k, _| include.include?(k) }
94
+ .each_with_object({}) { |(k, v), h| h[k] = Array(v.data) }
95
+ end
96
+
97
+ private
98
+
99
+ def attributes(fields)
100
+ self.class.attribute_blocks
101
+ .select { |k, _| !@_attributes.key?(k) && fields.include?(k) }
102
+ .each { |k, v| @_attributes[k] = instance_eval(&v) }
103
+ @_attributes.select { |k, _| fields.include?(k) }
104
+ end
105
+
106
+ def relationships(fields, include)
107
+ @_relationships
108
+ .select { |k, _| fields.include?(k) }
109
+ .each_with_object({}) do |(k, v), h|
110
+ h[k] = v.as_jsonapi(include.include?(k))
111
+ end
112
+ end
113
+ end
114
+ end
metadata ADDED
@@ -0,0 +1,70 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: jsonapi-serializable
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1.beta1
5
+ platform: ruby
6
+ authors:
7
+ - Lucas Hosseini
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-10-02 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: jsonapi-renderer
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.1'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '0.1'
27
+ description: DSL for building resource classes to be rendered by jsonapi-renderer.
28
+ email: lucas.hosseini@gmail.com
29
+ executables: []
30
+ extensions: []
31
+ extra_rdoc_files: []
32
+ files:
33
+ - README.md
34
+ - lib/jsonapi/serializable.rb
35
+ - lib/jsonapi/serializable/error.rb
36
+ - lib/jsonapi/serializable/error_dsl.rb
37
+ - lib/jsonapi/serializable/link.rb
38
+ - lib/jsonapi/serializable/relationship.rb
39
+ - lib/jsonapi/serializable/relationship_dsl.rb
40
+ - lib/jsonapi/serializable/resource.rb
41
+ - lib/jsonapi/serializable/resource_dsl.rb
42
+ - lib/jsonapi/serializable_error.rb
43
+ - lib/jsonapi/serializable_link.rb
44
+ - lib/jsonapi/serializable_relationship.rb
45
+ - lib/jsonapi/serializable_resource.rb
46
+ homepage: https://github.com/beauby/jsonapi-serializable
47
+ licenses:
48
+ - MIT
49
+ metadata: {}
50
+ post_install_message:
51
+ rdoc_options: []
52
+ require_paths:
53
+ - lib
54
+ required_ruby_version: !ruby/object:Gem::Requirement
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ version: '0'
59
+ required_rubygems_version: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ">"
62
+ - !ruby/object:Gem::Version
63
+ version: 1.3.1
64
+ requirements: []
65
+ rubyforge_project:
66
+ rubygems_version: 2.5.1
67
+ signing_key:
68
+ specification_version: 4
69
+ summary: Build and render JSON API resources.
70
+ test_files: []