apia 3.0.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 +7 -0
- data/VERSION +1 -0
- data/lib/apia.rb +21 -0
- data/lib/apia/api.rb +100 -0
- data/lib/apia/argument_set.rb +221 -0
- data/lib/apia/authenticator.rb +57 -0
- data/lib/apia/callable_with_environment.rb +43 -0
- data/lib/apia/controller.rb +32 -0
- data/lib/apia/defineable.rb +60 -0
- data/lib/apia/definition.rb +27 -0
- data/lib/apia/definitions/api.rb +51 -0
- data/lib/apia/definitions/argument.rb +77 -0
- data/lib/apia/definitions/argument_set.rb +33 -0
- data/lib/apia/definitions/authenticator.rb +46 -0
- data/lib/apia/definitions/controller.rb +41 -0
- data/lib/apia/definitions/endpoint.rb +74 -0
- data/lib/apia/definitions/enum.rb +31 -0
- data/lib/apia/definitions/error.rb +59 -0
- data/lib/apia/definitions/field.rb +117 -0
- data/lib/apia/definitions/lookup_argument_set.rb +27 -0
- data/lib/apia/definitions/object.rb +29 -0
- data/lib/apia/definitions/polymorph.rb +29 -0
- data/lib/apia/definitions/polymorph_option.rb +53 -0
- data/lib/apia/definitions/scalar.rb +23 -0
- data/lib/apia/definitions/type.rb +109 -0
- data/lib/apia/dsl.rb +23 -0
- data/lib/apia/dsls/api.rb +37 -0
- data/lib/apia/dsls/argument.rb +27 -0
- data/lib/apia/dsls/argument_set.rb +35 -0
- data/lib/apia/dsls/authenticator.rb +38 -0
- data/lib/apia/dsls/concerns/has_fields.rb +38 -0
- data/lib/apia/dsls/controller.rb +34 -0
- data/lib/apia/dsls/endpoint.rb +79 -0
- data/lib/apia/dsls/enum.rb +19 -0
- data/lib/apia/dsls/error.rb +26 -0
- data/lib/apia/dsls/field.rb +27 -0
- data/lib/apia/dsls/lookup_argument_set.rb +24 -0
- data/lib/apia/dsls/object.rb +19 -0
- data/lib/apia/dsls/polymorph.rb +19 -0
- data/lib/apia/dsls/route_group.rb +43 -0
- data/lib/apia/dsls/route_set.rb +40 -0
- data/lib/apia/dsls/scalar.rb +23 -0
- data/lib/apia/dsls/scope_descriptions.rb +17 -0
- data/lib/apia/endpoint.rb +110 -0
- data/lib/apia/enum.rb +43 -0
- data/lib/apia/environment_error_handling.rb +74 -0
- data/lib/apia/error.rb +61 -0
- data/lib/apia/error_set.rb +15 -0
- data/lib/apia/errors/error_exception_error.rb +32 -0
- data/lib/apia/errors/field_spec_parse_error.rb +23 -0
- data/lib/apia/errors/invalid_argument_error.rb +68 -0
- data/lib/apia/errors/invalid_enum_option_error.rb +21 -0
- data/lib/apia/errors/invalid_helper_error.rb +6 -0
- data/lib/apia/errors/invalid_json_error.rb +23 -0
- data/lib/apia/errors/invalid_polymorph_value_error.rb +21 -0
- data/lib/apia/errors/invalid_scalar_value_error.rb +21 -0
- data/lib/apia/errors/manifest_error.rb +43 -0
- data/lib/apia/errors/missing_argument_error.rb +40 -0
- data/lib/apia/errors/null_field_value_error.rb +37 -0
- data/lib/apia/errors/parse_error.rb +10 -0
- data/lib/apia/errors/runtime_error.rb +30 -0
- data/lib/apia/errors/scope_not_granted_error.rb +15 -0
- data/lib/apia/errors/standard_error.rb +6 -0
- data/lib/apia/field_set.rb +76 -0
- data/lib/apia/field_spec.rb +155 -0
- data/lib/apia/helpers.rb +34 -0
- data/lib/apia/hook_set.rb +30 -0
- data/lib/apia/lookup_argument_set.rb +57 -0
- data/lib/apia/lookup_environment.rb +27 -0
- data/lib/apia/manifest_errors.rb +62 -0
- data/lib/apia/mock_request.rb +18 -0
- data/lib/apia/object.rb +68 -0
- data/lib/apia/object_set.rb +21 -0
- data/lib/apia/pagination_object.rb +34 -0
- data/lib/apia/polymorph.rb +50 -0
- data/lib/apia/rack.rb +184 -0
- data/lib/apia/rack_error.rb +17 -0
- data/lib/apia/request.rb +67 -0
- data/lib/apia/request_environment.rb +84 -0
- data/lib/apia/request_headers.rb +42 -0
- data/lib/apia/response.rb +64 -0
- data/lib/apia/route.rb +61 -0
- data/lib/apia/route_group.rb +20 -0
- data/lib/apia/route_set.rb +89 -0
- data/lib/apia/scalar.rb +52 -0
- data/lib/apia/scalars.rb +25 -0
- data/lib/apia/scalars/base64.rb +31 -0
- data/lib/apia/scalars/boolean.rb +37 -0
- data/lib/apia/scalars/date.rb +45 -0
- data/lib/apia/scalars/decimal.rb +36 -0
- data/lib/apia/scalars/integer.rb +34 -0
- data/lib/apia/scalars/string.rb +24 -0
- data/lib/apia/scalars/unix_time.rb +40 -0
- data/lib/apia/schema/api_controller_schema_type.rb +17 -0
- data/lib/apia/schema/api_schema_type.rb +43 -0
- data/lib/apia/schema/argument_schema_type.rb +28 -0
- data/lib/apia/schema/argument_set_schema_type.rb +21 -0
- data/lib/apia/schema/authenticator_schema_type.rb +22 -0
- data/lib/apia/schema/controller.rb +39 -0
- data/lib/apia/schema/controller_endpoint_schema_type.rb +17 -0
- data/lib/apia/schema/controller_schema_type.rb +32 -0
- data/lib/apia/schema/endpoint_schema_type.rb +35 -0
- data/lib/apia/schema/enum_schema_type.rb +20 -0
- data/lib/apia/schema/enum_value_schema_type.rb +14 -0
- data/lib/apia/schema/error_schema_type.rb +23 -0
- data/lib/apia/schema/field_schema_type.rb +38 -0
- data/lib/apia/schema/field_spec_options_schema_type.rb +16 -0
- data/lib/apia/schema/lookup_argument_set_schema_type.rb +25 -0
- data/lib/apia/schema/object_schema_polymorph.rb +31 -0
- data/lib/apia/schema/object_schema_type.rb +21 -0
- data/lib/apia/schema/polymorph_option_schema_type.rb +16 -0
- data/lib/apia/schema/polymorph_schema_type.rb +20 -0
- data/lib/apia/schema/request_method_enum.rb +21 -0
- data/lib/apia/schema/route_group_schema_type.rb +19 -0
- data/lib/apia/schema/route_schema_type.rb +31 -0
- data/lib/apia/schema/route_set_schema_type.rb +20 -0
- data/lib/apia/schema/scalar_schema_type.rb +15 -0
- data/lib/apia/schema/scope_type.rb +14 -0
- data/lib/apia/version.rb +12 -0
- metadata +188 -0
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'apia/errors/runtime_error'
|
4
|
+
|
5
|
+
module Apia
|
6
|
+
# This is the error exception that must be raised when you wish to raise an
|
7
|
+
# error. It should be initialized with the Apia::Error class that you wish
|
8
|
+
# to raise.
|
9
|
+
class ErrorExceptionError < Apia::RuntimeError
|
10
|
+
|
11
|
+
attr_reader :error_class
|
12
|
+
attr_reader :fields
|
13
|
+
|
14
|
+
def initialize(error_class, fields = {})
|
15
|
+
@error_class = error_class
|
16
|
+
@fields = fields
|
17
|
+
end
|
18
|
+
|
19
|
+
def http_status
|
20
|
+
@error_class.definition.http_status || 500
|
21
|
+
end
|
22
|
+
|
23
|
+
def hash
|
24
|
+
{
|
25
|
+
code: @error_class.definition.code,
|
26
|
+
description: @error_class.definition.description,
|
27
|
+
detail: @error_class.definition.fields.generate_hash(@fields)
|
28
|
+
}
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'apia/errors/runtime_error'
|
4
|
+
|
5
|
+
module Apia
|
6
|
+
class FieldSpecParseError < Apia::RuntimeError
|
7
|
+
|
8
|
+
def http_status
|
9
|
+
400
|
10
|
+
end
|
11
|
+
|
12
|
+
def hash
|
13
|
+
{
|
14
|
+
code: 'invalid_field_spec',
|
15
|
+
description: 'The field spec string was invalid',
|
16
|
+
detail: {
|
17
|
+
details: message
|
18
|
+
}
|
19
|
+
}
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'apia/errors/runtime_error'
|
4
|
+
|
5
|
+
module Apia
|
6
|
+
# Raised when an argument set cannot be created based on the source object that
|
7
|
+
# has been provided. For example, if a validation rule exists or a scalar cannot
|
8
|
+
# be parsed for the underlying object.
|
9
|
+
#
|
10
|
+
# This is not raised for MISSING argument errors.
|
11
|
+
class InvalidArgumentError < Apia::RuntimeError
|
12
|
+
|
13
|
+
ISSUE_DESCRIPTIONS = {
|
14
|
+
invalid_scalar: 'The value provided was not of an appropriate type for the scalar that was requested. For example, you may have passed a string where an integer was required etc...',
|
15
|
+
parse_error: 'The value provided could not be parsed into an appropriate value by the server. For example, if a date was expected and the value could not be interpretted as such.',
|
16
|
+
validation_error: 'A validation rule that has been specified for this argument was not satisfied. See the further details in the response and in the documentation.',
|
17
|
+
invalid_enum_value: 'The value provided was not one of the options suitable for the enum.',
|
18
|
+
missing_lookup_value: 'A value for a lookup argument set has not been provided but at least one value is required.',
|
19
|
+
ambiguous_lookup_values: 'More than one value has been provided for a lookup argument set. Only one option may be provided.'
|
20
|
+
}.freeze
|
21
|
+
|
22
|
+
attr_reader :argument
|
23
|
+
attr_reader :index
|
24
|
+
attr_reader :path
|
25
|
+
attr_reader :errors
|
26
|
+
attr_reader :issue
|
27
|
+
|
28
|
+
def initialize(argument, issue: nil, index: nil, path: [], errors: [])
|
29
|
+
@argument = argument
|
30
|
+
@index = index
|
31
|
+
@path = path
|
32
|
+
@issue = issue
|
33
|
+
@errors = errors
|
34
|
+
end
|
35
|
+
|
36
|
+
def to_s
|
37
|
+
@issue.to_s
|
38
|
+
end
|
39
|
+
|
40
|
+
def http_status
|
41
|
+
400
|
42
|
+
end
|
43
|
+
|
44
|
+
def path_string
|
45
|
+
@path.map(&:name).join('.')
|
46
|
+
end
|
47
|
+
|
48
|
+
def hash
|
49
|
+
{
|
50
|
+
code: 'invalid_argument',
|
51
|
+
description: "The '#{path_string}' argument is invalid",
|
52
|
+
detail: {
|
53
|
+
path: @path.map(&:name),
|
54
|
+
index: @index,
|
55
|
+
issue: @issue&.to_s,
|
56
|
+
issue_description: ISSUE_DESCRIPTIONS[@issue.to_sym],
|
57
|
+
errors: @errors,
|
58
|
+
argument: {
|
59
|
+
id: argument.id,
|
60
|
+
name: argument.name,
|
61
|
+
description: argument.description
|
62
|
+
}
|
63
|
+
}
|
64
|
+
}
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'apia/errors/runtime_error'
|
4
|
+
|
5
|
+
module Apia
|
6
|
+
class InvalidEnumOptionError < Apia::RuntimeError
|
7
|
+
|
8
|
+
attr_reader :enum
|
9
|
+
attr_reader :given_value
|
10
|
+
|
11
|
+
def initialize(enum, given_value)
|
12
|
+
@enum = enum
|
13
|
+
@given_value = given_value
|
14
|
+
end
|
15
|
+
|
16
|
+
def to_s
|
17
|
+
"Invalid option for `#{enum.class.definition.name || 'AnonymousEnum'}` (got: #{@given_value.inspect} (#{@given_value.class}))"
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'apia/errors/runtime_error'
|
4
|
+
|
5
|
+
module Apia
|
6
|
+
class InvalidJSONError < Apia::RuntimeError
|
7
|
+
|
8
|
+
def http_status
|
9
|
+
400
|
10
|
+
end
|
11
|
+
|
12
|
+
def hash
|
13
|
+
{
|
14
|
+
code: 'invalid_json_body',
|
15
|
+
description: 'The JSON body provided with this request is invalid',
|
16
|
+
detail: {
|
17
|
+
details: message
|
18
|
+
}
|
19
|
+
}
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'apia/errors/runtime_error'
|
4
|
+
|
5
|
+
module Apia
|
6
|
+
class InvalidPolymorphValueError < Apia::RuntimeError
|
7
|
+
|
8
|
+
attr_reader :polymorph
|
9
|
+
attr_reader :given_value
|
10
|
+
|
11
|
+
def initialize(polymorph, given_value)
|
12
|
+
@polymorph = polymorph
|
13
|
+
@given_value = given_value
|
14
|
+
end
|
15
|
+
|
16
|
+
def to_s
|
17
|
+
"Invalid value for `#{polymorph.definition.id}` (got: #{@given_value.inspect})"
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'apia/errors/runtime_error'
|
4
|
+
|
5
|
+
module Apia
|
6
|
+
class InvalidScalarValueError < Apia::RuntimeError
|
7
|
+
|
8
|
+
attr_reader :scalar
|
9
|
+
attr_reader :given_value
|
10
|
+
|
11
|
+
def initialize(scalar, given_value)
|
12
|
+
@scalar = scalar
|
13
|
+
@given_value = given_value
|
14
|
+
end
|
15
|
+
|
16
|
+
def to_s
|
17
|
+
"Invalid value for `#{scalar.name}` (got: #{@given_value.inspect} (#{@given_value.class}))"
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'apia/rack'
|
4
|
+
|
5
|
+
module Apia
|
6
|
+
class ManifestError < StandardError
|
7
|
+
|
8
|
+
def initialize(errors)
|
9
|
+
@errors = errors
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_s
|
13
|
+
"#{@errors.errors.size} object(s) have issues that need attention (#{errors})"
|
14
|
+
end
|
15
|
+
|
16
|
+
def errors
|
17
|
+
@errors.errors.each_with_object([]) do |(object, errors), array|
|
18
|
+
errors.each do |error|
|
19
|
+
array << "#{object.id}: #{error[:code]} (#{error[:message]})"
|
20
|
+
end
|
21
|
+
end.join(', ')
|
22
|
+
end
|
23
|
+
|
24
|
+
def detail
|
25
|
+
@errors.errors.map do |object, errors|
|
26
|
+
{
|
27
|
+
object: object.id,
|
28
|
+
errors: errors.map do |error|
|
29
|
+
{
|
30
|
+
code: error[:code],
|
31
|
+
description: error[:message]
|
32
|
+
}
|
33
|
+
end
|
34
|
+
}
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def triplet
|
39
|
+
Rack.error_triplet('manifest_error', description: 'An issue exists with the API manifest that needs resolving by the developer.', detail: detail)
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'apia/errors/runtime_error'
|
4
|
+
|
5
|
+
module Apia
|
6
|
+
# This is raised when an argument set cannot be created because an argument
|
7
|
+
# that was required is not present on the source object.
|
8
|
+
class MissingArgumentError < Apia::RuntimeError
|
9
|
+
|
10
|
+
attr_reader :argument
|
11
|
+
|
12
|
+
def initialize(argument, path: [])
|
13
|
+
@argument = argument
|
14
|
+
@path = path
|
15
|
+
end
|
16
|
+
|
17
|
+
def http_status
|
18
|
+
400
|
19
|
+
end
|
20
|
+
|
21
|
+
def path_string
|
22
|
+
@path.map(&:name).join('.')
|
23
|
+
end
|
24
|
+
|
25
|
+
def hash
|
26
|
+
{
|
27
|
+
code: 'missing_required_argument',
|
28
|
+
description: "The '#{path_string}' argument is required but has not been provided",
|
29
|
+
detail: {
|
30
|
+
path: @path.map(&:name),
|
31
|
+
argument: {
|
32
|
+
name: argument.name,
|
33
|
+
description: argument.description
|
34
|
+
}
|
35
|
+
}
|
36
|
+
}
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'apia/errors/runtime_error'
|
4
|
+
|
5
|
+
module Apia
|
6
|
+
class NullFieldValueError < Apia::RuntimeError
|
7
|
+
|
8
|
+
attr_reader :field
|
9
|
+
|
10
|
+
def initialize(field, source)
|
11
|
+
@field = field
|
12
|
+
@source = source
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_s
|
16
|
+
"Value for `#{field.name}` is null (but cannot be)"
|
17
|
+
end
|
18
|
+
|
19
|
+
def http_status
|
20
|
+
500
|
21
|
+
end
|
22
|
+
|
23
|
+
def hash
|
24
|
+
{
|
25
|
+
code: 'null_value_for_non_null_field',
|
26
|
+
description: to_s,
|
27
|
+
detail: {
|
28
|
+
field: {
|
29
|
+
id: @field.id,
|
30
|
+
name: @field.name
|
31
|
+
}
|
32
|
+
}
|
33
|
+
}
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'apia/errors/runtime_error'
|
4
|
+
|
5
|
+
module Apia
|
6
|
+
# A parse error is raised when we are unable to parse input provided by an
|
7
|
+
# API consumer to turn it into an appropriate Scalar or Type.
|
8
|
+
class ParseError < Apia::RuntimeError
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Apia
|
4
|
+
# Runtime errors occurr during API requests because they could not
|
5
|
+
# be detected before an action is processed.
|
6
|
+
class RuntimeError < StandardError
|
7
|
+
|
8
|
+
# Return the default HTTP status code that should be returned when this
|
9
|
+
# error is encoutered over HTTP
|
10
|
+
#
|
11
|
+
# @return [Integer]
|
12
|
+
def http_status
|
13
|
+
400
|
14
|
+
end
|
15
|
+
|
16
|
+
# Return the hash that describes this error
|
17
|
+
#
|
18
|
+
# @return [Hash]
|
19
|
+
def hash
|
20
|
+
{
|
21
|
+
code: 'generic_runtime_error',
|
22
|
+
description: message,
|
23
|
+
detail: {
|
24
|
+
class: self.class.name
|
25
|
+
}
|
26
|
+
}
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'apia/error'
|
4
|
+
|
5
|
+
module Apia
|
6
|
+
class ScopeNotGrantedError < Apia::Error
|
7
|
+
|
8
|
+
code :scope_not_granted
|
9
|
+
http_status 403
|
10
|
+
description 'The scope required for this endpoint has not been granted to the authenticating identity'
|
11
|
+
|
12
|
+
field :scopes, [:string]
|
13
|
+
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'apia/helpers'
|
4
|
+
require 'apia/scalar'
|
5
|
+
require 'apia/object'
|
6
|
+
require 'apia/enum'
|
7
|
+
require 'apia/field_spec'
|
8
|
+
|
9
|
+
module Apia
|
10
|
+
class FieldSet < Hash
|
11
|
+
|
12
|
+
# Add a new field to the fieldset
|
13
|
+
#
|
14
|
+
# @param field [Apia::Field]
|
15
|
+
# @return [Apia::Field]
|
16
|
+
def add(field)
|
17
|
+
self[field.name] = field
|
18
|
+
end
|
19
|
+
|
20
|
+
# Validate this field set and add errors as appropriate
|
21
|
+
#
|
22
|
+
# @param errors [Apia::ManifestErrors]
|
23
|
+
# @param object [Object]
|
24
|
+
# @return [void]
|
25
|
+
def validate(errors, object)
|
26
|
+
each_value do |field|
|
27
|
+
unless field.type.usable_for_field?
|
28
|
+
errors.add object, 'InvalidFieldType', "Type for field #{field.name} must be a scalar, enum or object"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# Generate a hash for the fields that are defined on this object.
|
34
|
+
# It should receive the source object as well as a request
|
35
|
+
#
|
36
|
+
# @param source [Object, Hash]
|
37
|
+
# @param request [Apia::Request]
|
38
|
+
# @param only [Array]
|
39
|
+
# @return [Hash]
|
40
|
+
def generate_hash(source, request: nil, path: [])
|
41
|
+
each_with_object({}) do |(_, field), hash|
|
42
|
+
next unless field.include?(source, request)
|
43
|
+
|
44
|
+
field_path = path + [field]
|
45
|
+
next if request&.endpoint && !request&.endpoint&.include_field?(field_path)
|
46
|
+
|
47
|
+
value = field.value(source, request: request, path: field_path)
|
48
|
+
next if value == :skip
|
49
|
+
|
50
|
+
hash[field.name.to_sym] = value
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# Generate a default field spec for this field set based on the values
|
55
|
+
# provided for the include option.
|
56
|
+
#
|
57
|
+
# @return [FieldSpec]
|
58
|
+
def spec
|
59
|
+
@spec ||= begin
|
60
|
+
spec = each_with_object([]) do |(key, field), array|
|
61
|
+
next if field.include == false
|
62
|
+
|
63
|
+
if field.include.is_a?(::String)
|
64
|
+
array << "#{key}[#{field.include}]"
|
65
|
+
elsif field.type.object? || field.type.polymorph?
|
66
|
+
array << "#{key}[*]"
|
67
|
+
else
|
68
|
+
array << key
|
69
|
+
end
|
70
|
+
end.join(',')
|
71
|
+
FieldSpec.parse(spec)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
end
|