jsonapi-serializable 0.1.1.beta1

Sign up to get free protection for your applications and to get access to all the features.
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: []