shamu 0.0.2 → 0.0.3
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/.rubocop.yml +7 -1
- data/README.md +1 -2
- data/lib/shamu/features/features_service.rb +1 -1
- data/lib/shamu/json_api/README.md +1 -0
- data/lib/shamu/json_api/base_builder.rb +67 -0
- data/lib/shamu/json_api/context.rb +69 -0
- data/lib/shamu/json_api/entity_serializer.rb +10 -0
- data/lib/shamu/json_api/error.rb +29 -0
- data/lib/shamu/json_api/error_builder.rb +78 -0
- data/lib/shamu/json_api/relationship_builder.rb +16 -0
- data/lib/shamu/json_api/resource_builder.rb +81 -0
- data/lib/shamu/json_api/response.rb +99 -0
- data/lib/shamu/json_api/serializer.rb +33 -0
- data/lib/shamu/json_api/support.rb +8 -0
- data/lib/shamu/json_api.rb +13 -0
- data/lib/shamu/locale/en.yml +6 -1
- data/lib/shamu/version.rb +1 -1
- data/lib/shamu.rb +1 -0
- data/spec/lib/shamu/json_api/base_builder_spec.rb +42 -0
- data/spec/lib/shamu/json_api/common_builder_spec.rb +0 -0
- data/spec/lib/shamu/json_api/context_spec.rb +31 -0
- data/spec/lib/shamu/json_api/error_builder_spec.rb +31 -0
- data/spec/lib/shamu/json_api/relationship_builder_spec.rb +5 -0
- data/spec/lib/shamu/json_api/resource_builder_spec.rb +52 -0
- data/spec/lib/shamu/json_api/response_spec.rb +42 -0
- metadata +28 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 027f0ea99b484c02d9986999b39f3025dee4b4a3
|
4
|
+
data.tar.gz: 0eb00f3878a9718c979e511e8930cf81d8d708e8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 75946cc4efced52d7a3cf58bb673c75cdd2d9a7aee479b91f3fff4c96d485b74319f07c22345c616075a598948ee861eecd816046aefd37f9761321981c3d11e
|
7
|
+
data.tar.gz: 63784d0e8b20db671ba1563c19146ecea4e2fa3728098fc1a79db42e8ef2ebf57a7e68716c9aa349676dff841b6c92f4c73fc81f660df3bbe3fca4d1a8b953ba
|
data/.rubocop.yml
CHANGED
@@ -79,7 +79,10 @@ Style/MultilineBlockChain:
|
|
79
79
|
Enabled: false
|
80
80
|
|
81
81
|
Style/OptionHash:
|
82
|
-
|
82
|
+
Enabled: true
|
83
|
+
|
84
|
+
Style/ParallelAssignment:
|
85
|
+
Enabled: false
|
83
86
|
|
84
87
|
Style/RegexpLiteral:
|
85
88
|
Enabled: false
|
@@ -111,6 +114,9 @@ Style/TrailingBlankLines:
|
|
111
114
|
Style/TrailingCommaInLiteral:
|
112
115
|
Enabled: false
|
113
116
|
|
117
|
+
Style/TrivialAccessors:
|
118
|
+
Enabled: false
|
119
|
+
|
114
120
|
Style/UnneededInterpolation:
|
115
121
|
Enabled: false
|
116
122
|
|
data/README.md
CHANGED
@@ -158,7 +158,7 @@ module Shamu
|
|
158
158
|
|
159
159
|
# @param [String] path of the default config file.
|
160
160
|
# @return [String]
|
161
|
-
def default_config_path=( path )
|
161
|
+
def default_config_path=( path )
|
162
162
|
@default_config_path = path
|
163
163
|
end
|
164
164
|
end
|
@@ -0,0 +1 @@
|
|
1
|
+
http://jsonapi.org
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module Shamu
|
2
|
+
module JsonApi
|
3
|
+
|
4
|
+
# Used by a {Serilaizer} to write fields and relationships
|
5
|
+
class BaseBuilder
|
6
|
+
|
7
|
+
# @param [Context] context the current serialization context.
|
8
|
+
def initialize( context )
|
9
|
+
@context = context
|
10
|
+
@output = {}
|
11
|
+
end
|
12
|
+
|
13
|
+
# @overload identifier( type, id )
|
14
|
+
# @param [String] type of the resource.
|
15
|
+
# @param [Object] id of the resource.
|
16
|
+
# @overload identifier( resource )
|
17
|
+
# @param [#json_api_type,#id] resource an object that responds to `json_api_type` and `id`
|
18
|
+
#
|
19
|
+
# Write a resource linkage info.
|
20
|
+
#
|
21
|
+
# @return [void]
|
22
|
+
def identifier( type, id = nil )
|
23
|
+
type, id = type.json_api_type, type.id if type.respond_to? :json_api_type
|
24
|
+
|
25
|
+
output[:type] = type.to_s
|
26
|
+
output[:id] = id.to_s
|
27
|
+
end
|
28
|
+
|
29
|
+
# Write a link to another resource.
|
30
|
+
#
|
31
|
+
# @param [String,Symbol] name of the link.
|
32
|
+
# @param [String] url
|
33
|
+
# @param [Hash] meta optional additional meta information.
|
34
|
+
# @return [void]
|
35
|
+
def link( name, url, meta: nil )
|
36
|
+
links = ( output[:links] ||= {} )
|
37
|
+
|
38
|
+
if meta # rubocop:disable Style/ConditionalAssignment
|
39
|
+
links[ name.to_sym ] = { href: url, meta: meta }
|
40
|
+
else
|
41
|
+
links[ name.to_sym ] = url
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# Add a meta field.
|
46
|
+
# @param [String,Symbol] name of the meta field.
|
47
|
+
# @param [Object] vlaue that can be converted to a JSON primitive type.
|
48
|
+
# @return [void]
|
49
|
+
def meta( name, value )
|
50
|
+
meta = ( output[:meta] ||= {} )
|
51
|
+
meta[ name.to_sym ] = value
|
52
|
+
end
|
53
|
+
|
54
|
+
# @return [Hash] the results output as JSON safe hash.
|
55
|
+
def compile
|
56
|
+
fail JsonApi::IncompleteResourceError unless output[:type]
|
57
|
+
output
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
attr_reader :context
|
63
|
+
attr_reader :output
|
64
|
+
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
module Shamu
|
2
|
+
module JsonApi
|
3
|
+
class Context
|
4
|
+
|
5
|
+
def initialize( fields: nil )
|
6
|
+
@included_resources = {}
|
7
|
+
@all_resources = Set.new
|
8
|
+
@fields = parse_fields( fields )
|
9
|
+
end
|
10
|
+
|
11
|
+
# Add an included resource for a compound response.
|
12
|
+
#
|
13
|
+
# @param [Object] resource to be serialized.
|
14
|
+
# @param [Serializer] the serializer to use to serialize the object. If
|
15
|
+
# not provided a default {Serializer} will be chosen.
|
16
|
+
# @return [resource]
|
17
|
+
# @yield (builder)
|
18
|
+
# @yieldparam [ResourceBuilder] builder to write embedded resource to.
|
19
|
+
def include_resource( resource, serializer = nil, &block )
|
20
|
+
return if all_resources.include?( resource )
|
21
|
+
|
22
|
+
all_resources << resource
|
23
|
+
included_resources[resource] ||= { serializer: serializer, block: block }
|
24
|
+
end
|
25
|
+
|
26
|
+
# Collects all the currently included resources and resets the queue.
|
27
|
+
def collect_included_resources
|
28
|
+
included = included_resources.dup
|
29
|
+
@included_resources = {}
|
30
|
+
included
|
31
|
+
end
|
32
|
+
|
33
|
+
# @return [Boolean] true if there are any pending included resources.
|
34
|
+
def included_resources?
|
35
|
+
included_resources.any?
|
36
|
+
end
|
37
|
+
|
38
|
+
# Check to see if the field should be included in the JSON API output.
|
39
|
+
#
|
40
|
+
# @param [Symbol] type the resource type in question.
|
41
|
+
# @param [Symbol] name of the field on the resouce in question.
|
42
|
+
# @return [Boolean] true if the
|
43
|
+
def include_field?( type, name )
|
44
|
+
return true unless type_fields = fields[ type ]
|
45
|
+
|
46
|
+
type_fields.include?( name )
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
attr_reader :all_resources
|
52
|
+
attr_reader :included_resources
|
53
|
+
attr_reader :fields
|
54
|
+
|
55
|
+
def parse_fields( raw )
|
56
|
+
return {} unless raw
|
57
|
+
|
58
|
+
raw.each_with_object( {} ) do |(type, fields), parsed|
|
59
|
+
fields = fields.split( "," ) if fields.is_a?( String )
|
60
|
+
|
61
|
+
parsed[ type.to_sym ] = fields.map do |field|
|
62
|
+
field = field.strip if field.is_a? String
|
63
|
+
field.to_sym
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require "i18n"
|
2
|
+
|
3
|
+
module Shamu
|
4
|
+
|
5
|
+
module JsonApi
|
6
|
+
# A generic error class for problems with shamu JSON API.
|
7
|
+
class Error < Shamu::Error
|
8
|
+
private
|
9
|
+
|
10
|
+
def translation_scope
|
11
|
+
super.dup.insert( 1, :json_api )
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
|
16
|
+
# Raised if an {ResourceBuilder#identifier} was not built.
|
17
|
+
class IncompleteResourceError < Error
|
18
|
+
def initialize( message = :incomplete_resource )
|
19
|
+
super
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class IdentifierRequiredError < Error
|
24
|
+
def initialize( message = :identifier_required )
|
25
|
+
super
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
module Shamu
|
2
|
+
module JsonApi
|
3
|
+
|
4
|
+
# Build an error response object.
|
5
|
+
class ErrorBuilder
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@output = { id: SecureRandom.uuid }
|
9
|
+
end
|
10
|
+
|
11
|
+
# @param [String] id unique id for this occurrence of the error.
|
12
|
+
def id( id )
|
13
|
+
output[:id] = id
|
14
|
+
end
|
15
|
+
|
16
|
+
# Summary of the error.
|
17
|
+
# @param [Integer] http_status code.
|
18
|
+
# @param [String,Symbol] code application specific code for the error.
|
19
|
+
# @param [String] human friendly title for the error.
|
20
|
+
def summary( http_status, code, title = nil )
|
21
|
+
output[:status] = http_status.to_s
|
22
|
+
output[:code] = code.to_s
|
23
|
+
output[:title] = title || code.to_s.titleize
|
24
|
+
end
|
25
|
+
|
26
|
+
# Summarize an exception as an error.
|
27
|
+
# @param [Exception] exception
|
28
|
+
# @param [Integer] http_status code. Default 400.
|
29
|
+
def exception( exception, http_status = nil )
|
30
|
+
http_status ||= 400
|
31
|
+
|
32
|
+
name = exception.class.name.demodulize.gsub( /Error$/, "" )
|
33
|
+
summary http_status, name.underscore, name.titleize
|
34
|
+
detail exception.message
|
35
|
+
end
|
36
|
+
|
37
|
+
# @return [String] message details about the error.
|
38
|
+
def detail( message )
|
39
|
+
output[:detail] = message
|
40
|
+
end
|
41
|
+
|
42
|
+
# Write a link to error information.
|
43
|
+
#
|
44
|
+
# @param [String,Symbol] name of the link.
|
45
|
+
# @param [String] url
|
46
|
+
# @param [Hash] meta optional additional meta information.
|
47
|
+
# @return [void]
|
48
|
+
def link( name, url, meta: nil )
|
49
|
+
links = ( output[:links] ||= {} )
|
50
|
+
|
51
|
+
if meta # rubocop:disable Style/ConditionalAssignment
|
52
|
+
links[ name.to_sym ] = { href: url, meta: meta }
|
53
|
+
else
|
54
|
+
links[ name.to_sym ] = url
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# Add a meta field.
|
59
|
+
# @param [String,Symbol] name of the meta field.
|
60
|
+
# @param [Object] value that can be converted to a JSON primitive type.
|
61
|
+
# @return [void]
|
62
|
+
def meta( name, value )
|
63
|
+
meta = ( output[:meta] ||= {} )
|
64
|
+
meta[ name.to_sym ] = value
|
65
|
+
end
|
66
|
+
|
67
|
+
# @return [Hash] the results output as JSON safe hash.
|
68
|
+
def compile
|
69
|
+
output
|
70
|
+
end
|
71
|
+
|
72
|
+
private
|
73
|
+
|
74
|
+
attr_reader :output
|
75
|
+
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require "shamu/json_api/base_builder"
|
2
|
+
|
3
|
+
module Shamu
|
4
|
+
module JsonApi
|
5
|
+
|
6
|
+
# Build a relationship from one resource to another.
|
7
|
+
class RelationshipBuilder < BaseBuilder
|
8
|
+
|
9
|
+
# (see Context#include_resource)
|
10
|
+
def include_resource( resource, serializer = nil, &block )
|
11
|
+
context.include_resource resource, serializer, &block
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require "shamu/json_api/base_builder"
|
2
|
+
|
3
|
+
module Shamu
|
4
|
+
module JsonApi
|
5
|
+
|
6
|
+
# Used by a {Serilaizer} to write fields and relationships
|
7
|
+
class ResourceBuilder < BaseBuilder
|
8
|
+
|
9
|
+
# @overload attribute( attributes )
|
10
|
+
# @param [Hash] attributes to write.
|
11
|
+
# @overload attribute( name, value )
|
12
|
+
# @param [String, Symbol] name of the attribute.
|
13
|
+
# @param [Object] value that can be persited to a JSON primitive value.
|
14
|
+
#
|
15
|
+
# Write one or more attributes to the output.
|
16
|
+
#
|
17
|
+
# @return [void]
|
18
|
+
def attribute( name_or_hash, value = nil )
|
19
|
+
require_identifier!
|
20
|
+
|
21
|
+
if value
|
22
|
+
add_attribute name_or_hash, value
|
23
|
+
else
|
24
|
+
name_or_hash.each do |n, v|
|
25
|
+
add_attribute n, v
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# Build a relationship reference.
|
31
|
+
#
|
32
|
+
# ```
|
33
|
+
# relationship :author do |builder|
|
34
|
+
# builder.identifier author
|
35
|
+
# builder.link :related, author_url author
|
36
|
+
# builder.link :self, book_author_url( book, author )
|
37
|
+
# end
|
38
|
+
# ```
|
39
|
+
#
|
40
|
+
# @param [String,Symbol] name of the relationship.
|
41
|
+
# @return [void]
|
42
|
+
# @yield (builder)
|
43
|
+
# @yieldparam [RelationshipBuilder] builder used to define the properties
|
44
|
+
# of the relationship.
|
45
|
+
def relationship( name, &block )
|
46
|
+
require_identifier!
|
47
|
+
|
48
|
+
return unless context.include_field?( type, name )
|
49
|
+
|
50
|
+
builder = RelationshipBuilder.new( context )
|
51
|
+
yield builder
|
52
|
+
|
53
|
+
relationships = ( output[:relationships] ||= {} )
|
54
|
+
relationships[ name.to_sym ] = builder.compile
|
55
|
+
end
|
56
|
+
|
57
|
+
# (see BaseBuilder#identifier)
|
58
|
+
def identifier( * )
|
59
|
+
super.tap do
|
60
|
+
@type = output[:type]
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
attr_reader :type
|
67
|
+
|
68
|
+
def require_identifier!
|
69
|
+
fail IdentifierRequiredError unless @type
|
70
|
+
end
|
71
|
+
|
72
|
+
def add_attribute( name, value )
|
73
|
+
return unless context.include_field?( type, name )
|
74
|
+
|
75
|
+
attributes = ( output[:attributes] ||= {} )
|
76
|
+
attributes[ name.to_sym ] = value
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
module Shamu
|
2
|
+
module JsonApi
|
3
|
+
|
4
|
+
# Build a JSON API response from one or more resources.
|
5
|
+
class Response < BaseBuilder
|
6
|
+
|
7
|
+
# Output a single resource as the response data.
|
8
|
+
# @param [Object] resource to write.
|
9
|
+
# @param [Serializer] serializer used to write the resource state.
|
10
|
+
# @yield (builder)
|
11
|
+
# @yieldparam [ResourceBuilder] builder used write the resources fields
|
12
|
+
# and meta.
|
13
|
+
#
|
14
|
+
# @return [void]
|
15
|
+
def resource( resource, serializer = nil, &block )
|
16
|
+
output[:data] = build_resource( resource, serializer, &block )
|
17
|
+
end
|
18
|
+
|
19
|
+
# Output a single resource as the response data.
|
20
|
+
#
|
21
|
+
# @param [Enumerable<Object>] resources to write.
|
22
|
+
# @param [Serializer] serializer used to write the resource state.
|
23
|
+
# @yield (builder, resource)
|
24
|
+
# @yieldparam [ResourceBuilder] builder used write the resources fields
|
25
|
+
# and meta.
|
26
|
+
# @yieldparam [Object] resource being written.
|
27
|
+
# @return [void]
|
28
|
+
def resources( collection, serializer = nil, &block )
|
29
|
+
output[:data] =
|
30
|
+
collection.map do |resource|
|
31
|
+
build_resource resource, serializer, &block
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# @overload error( exception, http_status = nil )
|
36
|
+
# @param (see ErrorBuilder#exception)
|
37
|
+
# @overload error( &block )
|
38
|
+
# @yield (builder)
|
39
|
+
# @yieldparam [ErrorBuilder] builder used to describe the error.
|
40
|
+
#
|
41
|
+
# @return [void]
|
42
|
+
def error( exception = nil, http_status = nil, &block )
|
43
|
+
builder = ErrorBuilder.new
|
44
|
+
|
45
|
+
if block_given?
|
46
|
+
yield builder
|
47
|
+
else
|
48
|
+
builder.exception( exception, http_status )
|
49
|
+
end
|
50
|
+
|
51
|
+
errors = ( output[:errors] ||= [] )
|
52
|
+
errors << builder.compile
|
53
|
+
end
|
54
|
+
|
55
|
+
# (see BaseBuilder#compile)
|
56
|
+
def compile
|
57
|
+
@compiled ||= begin
|
58
|
+
compiled = output.dup
|
59
|
+
compiled[:jsonapi] = { version: "1.0" }
|
60
|
+
|
61
|
+
while context.included_resources?
|
62
|
+
included = ( compiled[ :included ] ||= [] )
|
63
|
+
context.collect_included_resources.each do |resource, options|
|
64
|
+
included << build_resource( resource, options[:serializer], &options[:block] )
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
compiled
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def to_json
|
73
|
+
compile.to_json
|
74
|
+
end
|
75
|
+
|
76
|
+
def to_s
|
77
|
+
compile.to_s
|
78
|
+
end
|
79
|
+
|
80
|
+
private :identifier
|
81
|
+
|
82
|
+
private
|
83
|
+
|
84
|
+
def build_resource( resource, serializer, &block )
|
85
|
+
fail "A block is required if no serializer is given" if !serializer && !block_given?
|
86
|
+
|
87
|
+
builder = ResourceBuilder.new( context )
|
88
|
+
if serializer
|
89
|
+
serializer.serialize( builder )
|
90
|
+
else
|
91
|
+
yield builder
|
92
|
+
end
|
93
|
+
|
94
|
+
builder.compile
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Shamu
|
2
|
+
module JsonApi
|
3
|
+
|
4
|
+
# Serialize an object to a JSON API stream.
|
5
|
+
class Serializer
|
6
|
+
|
7
|
+
# @param [Object] resource to be serialized.
|
8
|
+
def initialize( resource )
|
9
|
+
@resource = resource
|
10
|
+
end
|
11
|
+
|
12
|
+
# Serialize the {#resource} to the builder.
|
13
|
+
# @param [ResourceBuilder] builder to write to.
|
14
|
+
# @return [void]
|
15
|
+
def serialize( builder )
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
attr_reader :resource
|
21
|
+
|
22
|
+
class << self
|
23
|
+
|
24
|
+
# Find a {Serializer} that knows how to serialize the given resource.
|
25
|
+
# @param [Object] resource to serialize.
|
26
|
+
# @return [Serializer]
|
27
|
+
def find( resource )
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Shamu
|
2
|
+
# {include:file:lib/shamu/json_api/README.md}
|
3
|
+
module JsonApi
|
4
|
+
require "shamu/json_api/context"
|
5
|
+
require "shamu/json_api/relationship_builder"
|
6
|
+
require "shamu/json_api/resource_builder"
|
7
|
+
require "shamu/json_api/response"
|
8
|
+
require "shamu/json_api/serializer"
|
9
|
+
require "shamu/json_api/support"
|
10
|
+
require "shamu/json_api/error"
|
11
|
+
require "shamu/json_api/error_builder"
|
12
|
+
end
|
13
|
+
end
|
data/lib/shamu/locale/en.yml
CHANGED
@@ -24,4 +24,9 @@ en:
|
|
24
24
|
|
25
25
|
features:
|
26
26
|
errors:
|
27
|
-
retired_toggle_checked: "The `%{name}` toggle retired at `%{retire_at}` and cannot be checked anymore."
|
27
|
+
retired_toggle_checked: "The `%{name}` toggle retired at `%{retire_at}` and cannot be checked anymore."
|
28
|
+
|
29
|
+
json_api:
|
30
|
+
errors:
|
31
|
+
incomplete_resource: "`identifier` was not called to define the type and id of the resource"
|
32
|
+
identifier_resource: "`identifier` must be called before defining any fields"
|
data/lib/shamu/version.rb
CHANGED
data/lib/shamu.rb
CHANGED
@@ -0,0 +1,42 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Shamu::JsonApi::BaseBuilder do
|
4
|
+
let( :context ) { Shamu::JsonApi::Context.new }
|
5
|
+
let( :builder ) { Shamu::JsonApi::BaseBuilder.new( context ) }
|
6
|
+
|
7
|
+
before( :each ) do
|
8
|
+
builder.identifier "example", 1
|
9
|
+
end
|
10
|
+
|
11
|
+
describe "#identifier" do
|
12
|
+
it "writes type and id" do
|
13
|
+
builder.identifier "spec", 5
|
14
|
+
|
15
|
+
expect( builder.compile ).to include type: "spec", id: "5"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe "#link" do
|
20
|
+
it "adds a link" do
|
21
|
+
builder.link :self, "http://localhost"
|
22
|
+
|
23
|
+
expect( builder.compile ).to include links: { self: "http://localhost" }
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe "#meta" do
|
28
|
+
it "adds the meta data" do
|
29
|
+
builder.meta :updated, "today"
|
30
|
+
|
31
|
+
expect( builder.compile ).to include meta: { updated: "today" }
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe "#compile" do
|
36
|
+
it "fails if identifier has not been specified" do
|
37
|
+
expect do
|
38
|
+
Shamu::JsonApi::BaseBuilder.new( context ).compile
|
39
|
+
end.to raise_error Shamu::JsonApi::IncompleteResourceError
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
File without changes
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Shamu::JsonApi::Context do
|
4
|
+
it "parses comma deliminated fields" do
|
5
|
+
context = Shamu::JsonApi::Context.new fields: { "user" => "name, email," }
|
6
|
+
|
7
|
+
expect( context.send( :fields ) ).to eq user: [:name, :email]
|
8
|
+
end
|
9
|
+
|
10
|
+
it "accepts array of fields" do
|
11
|
+
context = Shamu::JsonApi::Context.new fields: { "user" => [ "name", "email" ] }
|
12
|
+
|
13
|
+
expect( context.send( :fields ) ).to eq user: [:name, :email]
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "#include_field?" do
|
17
|
+
let( :context ) { Shamu::JsonApi::Context.new( fields: { "user": "name,email" } ) }
|
18
|
+
|
19
|
+
it "is true for unfiltered" do
|
20
|
+
expect( context.include_field?( :order, :number ) ).to be_truthy
|
21
|
+
end
|
22
|
+
|
23
|
+
it "is true for filtered with field" do
|
24
|
+
expect( context.include_field?( :user, :name ) ).to be_truthy
|
25
|
+
end
|
26
|
+
|
27
|
+
it "is false for filtered without field" do
|
28
|
+
expect( context.include_field?( :user, :birthdate ) ).not_to be_truthy
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Shamu::JsonApi::ErrorBuilder do
|
4
|
+
let( :builder ) { Shamu::JsonApi::ErrorBuilder.new }
|
5
|
+
|
6
|
+
describe "#summary" do
|
7
|
+
it "infers title" do
|
8
|
+
builder.summary 422, :not_allowed
|
9
|
+
|
10
|
+
expect( builder.compile ).to include title: "Not Allowed"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "#exception" do
|
15
|
+
before( :each ) do
|
16
|
+
builder.exception NotImplementedError.new( "Nope, we haven't done that yet" )
|
17
|
+
end
|
18
|
+
|
19
|
+
it "applies message to details" do
|
20
|
+
expect( builder.compile ).to include detail: "Nope, we haven't done that yet"
|
21
|
+
end
|
22
|
+
|
23
|
+
it "applies class name as code" do
|
24
|
+
expect( builder.compile ).to include code: "not_implemented"
|
25
|
+
end
|
26
|
+
|
27
|
+
it "applies class name as title" do
|
28
|
+
expect( builder.compile ).to include title: "Not Implemented"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Shamu::JsonApi::RelationshipBuilder do
|
4
|
+
let( :context ) { Shamu::JsonApi::Context.new }
|
5
|
+
let( :builder ) { Shamu::JsonApi::ResourceBuilder.new( context ) }
|
6
|
+
|
7
|
+
before( :each ) do
|
8
|
+
builder.identifier "example", 1
|
9
|
+
end
|
10
|
+
|
11
|
+
describe "#attribute" do
|
12
|
+
it "adds to the attributes node" do
|
13
|
+
builder.attribute name: "Jim"
|
14
|
+
|
15
|
+
expect( builder.compile ).to include attributes: { name: "Jim" }
|
16
|
+
end
|
17
|
+
|
18
|
+
it "adds a single name, value pair" do
|
19
|
+
builder.attribute :name, "Jim"
|
20
|
+
|
21
|
+
expect( builder.compile ).to include attributes: { name: "Jim" }
|
22
|
+
end
|
23
|
+
|
24
|
+
it "excludes filtered attributes" do
|
25
|
+
allow( context ).to receive( :include_field? ).and_return false
|
26
|
+
|
27
|
+
builder.attribute name: "Nope"
|
28
|
+
expect( builder.compile ).not_to include attributes: { name: "Nope" }
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe "#relationship" do
|
33
|
+
it "adds a relationship" do
|
34
|
+
builder.relationship :parent do |rel|
|
35
|
+
rel.identifier :example, 5
|
36
|
+
end
|
37
|
+
|
38
|
+
expect( builder.compile ).to include relationships: { parent: kind_of( Hash ) }
|
39
|
+
end
|
40
|
+
|
41
|
+
it "excludes filtered relationships" do
|
42
|
+
allow( context ).to receive( :include_field? ).and_return false
|
43
|
+
|
44
|
+
builder.relationship :parent do |rel|
|
45
|
+
rel.identifier :example, 5
|
46
|
+
end
|
47
|
+
|
48
|
+
expect( builder.compile ).not_to include relationships: { parent: kind_of( Hash ) }
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Shamu::JsonApi::Response do
|
4
|
+
let( :context ) { Shamu::JsonApi::Context.new }
|
5
|
+
let( :response ) { Shamu::JsonApi::Response.new context }
|
6
|
+
|
7
|
+
it "uses serializer if given" do
|
8
|
+
serializer = double Shamu::JsonApi::Serializer
|
9
|
+
expect( serializer ).to receive( :serialize ) do |builder|
|
10
|
+
builder.identifier :response, 9
|
11
|
+
end
|
12
|
+
|
13
|
+
response.resource double, serializer
|
14
|
+
end
|
15
|
+
|
16
|
+
it "expects a block if no serializer" do
|
17
|
+
expect do
|
18
|
+
response.resource double
|
19
|
+
end.to raise_error /block/
|
20
|
+
end
|
21
|
+
|
22
|
+
it "appends included resources" do
|
23
|
+
|
24
|
+
response.resource double do |builder|
|
25
|
+
builder.identifier :example, 4
|
26
|
+
builder.relationship :parent do |rel|
|
27
|
+
rel.identifier :suite, 10
|
28
|
+
rel.include_resource double do |res|
|
29
|
+
res.identifier :suite, 10
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
expect( response.compile ).to include included: [ hash_including( type: "suite" ) ]
|
35
|
+
end
|
36
|
+
|
37
|
+
it "includes errors" do
|
38
|
+
response.error NotImplementedError.new
|
39
|
+
|
40
|
+
expect( response.compile ).to include errors: [ hash_including( code: "not_implemented" ) ]
|
41
|
+
end
|
42
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: shamu
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Paul Alexander
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-04-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activemodel
|
@@ -269,6 +269,18 @@ files:
|
|
269
269
|
- lib/shamu/features/support.rb
|
270
270
|
- lib/shamu/features/toggle.rb
|
271
271
|
- lib/shamu/features/toggle_codec.rb
|
272
|
+
- lib/shamu/json_api.rb
|
273
|
+
- lib/shamu/json_api/README.md
|
274
|
+
- lib/shamu/json_api/base_builder.rb
|
275
|
+
- lib/shamu/json_api/context.rb
|
276
|
+
- lib/shamu/json_api/entity_serializer.rb
|
277
|
+
- lib/shamu/json_api/error.rb
|
278
|
+
- lib/shamu/json_api/error_builder.rb
|
279
|
+
- lib/shamu/json_api/relationship_builder.rb
|
280
|
+
- lib/shamu/json_api/resource_builder.rb
|
281
|
+
- lib/shamu/json_api/response.rb
|
282
|
+
- lib/shamu/json_api/serializer.rb
|
283
|
+
- lib/shamu/json_api/support.rb
|
272
284
|
- lib/shamu/locale/en.yml
|
273
285
|
- lib/shamu/logger.rb
|
274
286
|
- lib/shamu/rack.rb
|
@@ -363,6 +375,13 @@ files:
|
|
363
375
|
- spec/lib/shamu/features/support_spec.rb
|
364
376
|
- spec/lib/shamu/features/toggle_codec_spec.rb
|
365
377
|
- spec/lib/shamu/features/toggle_spec.rb
|
378
|
+
- spec/lib/shamu/json_api/base_builder_spec.rb
|
379
|
+
- spec/lib/shamu/json_api/common_builder_spec.rb
|
380
|
+
- spec/lib/shamu/json_api/context_spec.rb
|
381
|
+
- spec/lib/shamu/json_api/error_builder_spec.rb
|
382
|
+
- spec/lib/shamu/json_api/relationship_builder_spec.rb
|
383
|
+
- spec/lib/shamu/json_api/resource_builder_spec.rb
|
384
|
+
- spec/lib/shamu/json_api/response_spec.rb
|
366
385
|
- spec/lib/shamu/rack/cookies_middleware_spec.rb
|
367
386
|
- spec/lib/shamu/rack/cookies_spec.rb
|
368
387
|
- spec/lib/shamu/rack/query_params_middleware_spec.rb
|
@@ -466,6 +485,13 @@ test_files:
|
|
466
485
|
- spec/lib/shamu/features/support_spec.rb
|
467
486
|
- spec/lib/shamu/features/toggle_codec_spec.rb
|
468
487
|
- spec/lib/shamu/features/toggle_spec.rb
|
488
|
+
- spec/lib/shamu/json_api/base_builder_spec.rb
|
489
|
+
- spec/lib/shamu/json_api/common_builder_spec.rb
|
490
|
+
- spec/lib/shamu/json_api/context_spec.rb
|
491
|
+
- spec/lib/shamu/json_api/error_builder_spec.rb
|
492
|
+
- spec/lib/shamu/json_api/relationship_builder_spec.rb
|
493
|
+
- spec/lib/shamu/json_api/resource_builder_spec.rb
|
494
|
+
- spec/lib/shamu/json_api/response_spec.rb
|
469
495
|
- spec/lib/shamu/rack/cookies_middleware_spec.rb
|
470
496
|
- spec/lib/shamu/rack/cookies_spec.rb
|
471
497
|
- spec/lib/shamu/rack/query_params_middleware_spec.rb
|