jsapi 0.1.1
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/lib/jsapi/controller/base.rb +21 -0
- data/lib/jsapi/controller/error_result.rb +21 -0
- data/lib/jsapi/controller/methods.rb +144 -0
- data/lib/jsapi/controller/parameters.rb +86 -0
- data/lib/jsapi/controller/parameters_invalid.rb +25 -0
- data/lib/jsapi/controller/response.rb +84 -0
- data/lib/jsapi/controller.rb +13 -0
- data/lib/jsapi/dsl/callbacks.rb +32 -0
- data/lib/jsapi/dsl/class_methods.rb +85 -0
- data/lib/jsapi/dsl/definitions.rb +102 -0
- data/lib/jsapi/dsl/error.rb +38 -0
- data/lib/jsapi/dsl/examples.rb +30 -0
- data/lib/jsapi/dsl/node.rb +62 -0
- data/lib/jsapi/dsl/openapi/callback.rb +23 -0
- data/lib/jsapi/dsl/openapi/root.rb +12 -0
- data/lib/jsapi/dsl/openapi.rb +4 -0
- data/lib/jsapi/dsl/operation.rb +118 -0
- data/lib/jsapi/dsl/parameter.rb +10 -0
- data/lib/jsapi/dsl/request_body.rb +10 -0
- data/lib/jsapi/dsl/response.rb +33 -0
- data/lib/jsapi/dsl/schema.rb +87 -0
- data/lib/jsapi/dsl.rb +24 -0
- data/lib/jsapi/json/array.rb +35 -0
- data/lib/jsapi/json/boolean.rb +17 -0
- data/lib/jsapi/json/integer.rb +15 -0
- data/lib/jsapi/json/null.rb +27 -0
- data/lib/jsapi/json/number.rb +15 -0
- data/lib/jsapi/json/object.rb +53 -0
- data/lib/jsapi/json/string.rb +29 -0
- data/lib/jsapi/json/value.rb +47 -0
- data/lib/jsapi/json.rb +41 -0
- data/lib/jsapi/meta/attributes/class_methods.rb +112 -0
- data/lib/jsapi/meta/attributes/type_caster.rb +48 -0
- data/lib/jsapi/meta/attributes.rb +4 -0
- data/lib/jsapi/meta/base.rb +41 -0
- data/lib/jsapi/meta/base_reference.rb +33 -0
- data/lib/jsapi/meta/definitions.rb +226 -0
- data/lib/jsapi/meta/example/model.rb +44 -0
- data/lib/jsapi/meta/example/reference.rb +15 -0
- data/lib/jsapi/meta/example.rb +19 -0
- data/lib/jsapi/meta/existence.rb +69 -0
- data/lib/jsapi/meta/invalid_argument_error.rb +11 -0
- data/lib/jsapi/meta/openapi/callback/model.rb +36 -0
- data/lib/jsapi/meta/openapi/callback/reference.rb +16 -0
- data/lib/jsapi/meta/openapi/callback.rb +21 -0
- data/lib/jsapi/meta/openapi/contact.rb +34 -0
- data/lib/jsapi/meta/openapi/external_documentation.rb +28 -0
- data/lib/jsapi/meta/openapi/info.rb +52 -0
- data/lib/jsapi/meta/openapi/license.rb +28 -0
- data/lib/jsapi/meta/openapi/link/model.rb +48 -0
- data/lib/jsapi/meta/openapi/link/reference.rb +16 -0
- data/lib/jsapi/meta/openapi/link.rb +21 -0
- data/lib/jsapi/meta/openapi/oauth_flow.rb +50 -0
- data/lib/jsapi/meta/openapi/root.rb +134 -0
- data/lib/jsapi/meta/openapi/security_requirement.rb +27 -0
- data/lib/jsapi/meta/openapi/security_scheme/api_key.rb +38 -0
- data/lib/jsapi/meta/openapi/security_scheme/base.rb +16 -0
- data/lib/jsapi/meta/openapi/security_scheme/http/basic.rb +31 -0
- data/lib/jsapi/meta/openapi/security_scheme/http/bearer.rb +37 -0
- data/lib/jsapi/meta/openapi/security_scheme/http/other.rb +37 -0
- data/lib/jsapi/meta/openapi/security_scheme/http.rb +31 -0
- data/lib/jsapi/meta/openapi/security_scheme/oauth2.rb +47 -0
- data/lib/jsapi/meta/openapi/security_scheme/open_id_connect.rb +33 -0
- data/lib/jsapi/meta/openapi/security_scheme.rb +51 -0
- data/lib/jsapi/meta/openapi/server.rb +34 -0
- data/lib/jsapi/meta/openapi/server_variable.rb +34 -0
- data/lib/jsapi/meta/openapi/tag.rb +34 -0
- data/lib/jsapi/meta/openapi/version.rb +41 -0
- data/lib/jsapi/meta/openapi.rb +16 -0
- data/lib/jsapi/meta/operation.rb +186 -0
- data/lib/jsapi/meta/parameter/model.rb +170 -0
- data/lib/jsapi/meta/parameter/reference.rb +30 -0
- data/lib/jsapi/meta/parameter.rb +19 -0
- data/lib/jsapi/meta/property.rb +62 -0
- data/lib/jsapi/meta/reference_error.rb +12 -0
- data/lib/jsapi/meta/request_body/model.rb +65 -0
- data/lib/jsapi/meta/request_body/reference.rb +14 -0
- data/lib/jsapi/meta/request_body.rb +19 -0
- data/lib/jsapi/meta/rescue_handler.rb +26 -0
- data/lib/jsapi/meta/response/model.rb +72 -0
- data/lib/jsapi/meta/response/reference.rb +17 -0
- data/lib/jsapi/meta/response.rb +19 -0
- data/lib/jsapi/meta/schema/array.rb +42 -0
- data/lib/jsapi/meta/schema/base.rb +146 -0
- data/lib/jsapi/meta/schema/boolean.rb +9 -0
- data/lib/jsapi/meta/schema/boundary.rb +37 -0
- data/lib/jsapi/meta/schema/conversion.rb +28 -0
- data/lib/jsapi/meta/schema/delegator.rb +26 -0
- data/lib/jsapi/meta/schema/discriminator.rb +36 -0
- data/lib/jsapi/meta/schema/integer.rb +9 -0
- data/lib/jsapi/meta/schema/number.rb +9 -0
- data/lib/jsapi/meta/schema/numeric.rb +56 -0
- data/lib/jsapi/meta/schema/object.rb +85 -0
- data/lib/jsapi/meta/schema/reference.rb +38 -0
- data/lib/jsapi/meta/schema/string.rb +58 -0
- data/lib/jsapi/meta/schema/validation/base.rb +29 -0
- data/lib/jsapi/meta/schema/validation/enum.rb +26 -0
- data/lib/jsapi/meta/schema/validation/max_items.rb +26 -0
- data/lib/jsapi/meta/schema/validation/max_length.rb +26 -0
- data/lib/jsapi/meta/schema/validation/maximum.rb +51 -0
- data/lib/jsapi/meta/schema/validation/min_items.rb +26 -0
- data/lib/jsapi/meta/schema/validation/min_length.rb +26 -0
- data/lib/jsapi/meta/schema/validation/minimum.rb +51 -0
- data/lib/jsapi/meta/schema/validation/multiple_of.rb +24 -0
- data/lib/jsapi/meta/schema/validation/pattern.rb +30 -0
- data/lib/jsapi/meta/schema/validation.rb +12 -0
- data/lib/jsapi/meta/schema.rb +61 -0
- data/lib/jsapi/meta.rb +23 -0
- data/lib/jsapi/model/attributes.rb +22 -0
- data/lib/jsapi/model/base.rb +34 -0
- data/lib/jsapi/model/error.rb +15 -0
- data/lib/jsapi/model/errors.rb +51 -0
- data/lib/jsapi/model/naming.rb +28 -0
- data/lib/jsapi/model/nestable.rb +37 -0
- data/lib/jsapi/model/nested_error.rb +54 -0
- data/lib/jsapi/model/validations.rb +27 -0
- data/lib/jsapi/model.rb +15 -0
- data/lib/jsapi/version.rb +8 -0
- data/lib/jsapi.rb +8 -0
- metadata +162 -0
@@ -0,0 +1,62 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Jsapi
|
4
|
+
module DSL
|
5
|
+
class Node
|
6
|
+
def initialize(meta_model, &block)
|
7
|
+
@_meta_model = meta_model
|
8
|
+
instance_eval(&block) if block
|
9
|
+
end
|
10
|
+
|
11
|
+
def method_missing(*args, &block) # :nodoc:
|
12
|
+
_keyword(*args, &block)
|
13
|
+
end
|
14
|
+
|
15
|
+
def respond_to_missing?(*args) # :nodoc:
|
16
|
+
_keyword?(args.first)
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
attr_reader :_meta_model
|
22
|
+
|
23
|
+
def _define(*args, &block)
|
24
|
+
block.call
|
25
|
+
rescue Error => e
|
26
|
+
raise e.prepend_origin(args.compact.join(' '))
|
27
|
+
rescue StandardError => e
|
28
|
+
raise Error.new(e, args.compact.join(' ').presence)
|
29
|
+
end
|
30
|
+
|
31
|
+
def _eval(model, klass = Node, &block)
|
32
|
+
return unless block
|
33
|
+
|
34
|
+
if model.reference?
|
35
|
+
raise Error, 'reference cannot be specified together with a block'
|
36
|
+
end
|
37
|
+
|
38
|
+
klass.new(model, &block)
|
39
|
+
end
|
40
|
+
|
41
|
+
def _find_method(name)
|
42
|
+
["#{name}=", "add_#{name}"].find do |method|
|
43
|
+
_meta_model.respond_to?(method)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def _keyword(name, *params, &block)
|
48
|
+
method = _find_method(name)
|
49
|
+
raise "unsupported method: #{name}" unless method
|
50
|
+
|
51
|
+
_define(name) do
|
52
|
+
value = _meta_model.public_send(method, *params)
|
53
|
+
_eval(value, &block)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def _keyword?(name)
|
58
|
+
_find_method(name).present?
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Jsapi
|
4
|
+
module DSL
|
5
|
+
module OpenAPI
|
6
|
+
# Used to specify details of a callback.
|
7
|
+
class Callback < Node
|
8
|
+
|
9
|
+
# Defines a callback operation.
|
10
|
+
#
|
11
|
+
# operation '{$request.query.foo}' do
|
12
|
+
# parameter 'bar', type: 'string'
|
13
|
+
# end
|
14
|
+
def operation(expression, **keywords, &block)
|
15
|
+
_define('operation', expression.inspect) do
|
16
|
+
operation_model = _meta_model.add_operation(expression, keywords)
|
17
|
+
Operation.new(operation_model, &block) if block
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,118 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Jsapi
|
4
|
+
module DSL
|
5
|
+
# Used to specify details of an operation.
|
6
|
+
class Operation < Node
|
7
|
+
include Callbacks
|
8
|
+
|
9
|
+
# Overrides Object#method to handle +method+ as a keyword.
|
10
|
+
def method(method) # :nodoc:
|
11
|
+
_keyword(:method, method)
|
12
|
+
end
|
13
|
+
|
14
|
+
# Specifies the model class to access top-level parameters by.
|
15
|
+
#
|
16
|
+
# model Foo do
|
17
|
+
# def bar
|
18
|
+
# # ...
|
19
|
+
# end
|
20
|
+
# end
|
21
|
+
#
|
22
|
+
# +klass+ can be any subclass of Model::Base. If block is given, an
|
23
|
+
# anonymous class is created that inherits either from +klass+ or
|
24
|
+
# Model::Base.
|
25
|
+
def model(klass = nil, &block)
|
26
|
+
if block
|
27
|
+
klass = Class.new(klass || Model::Base)
|
28
|
+
klass.class_eval(&block)
|
29
|
+
end
|
30
|
+
_meta_model.model = klass
|
31
|
+
end
|
32
|
+
|
33
|
+
# Defines a parameter or refers a reusable parameter.
|
34
|
+
#
|
35
|
+
# # define a parameter
|
36
|
+
# parameter 'foo', type: 'string'
|
37
|
+
#
|
38
|
+
# # define a nested parameter
|
39
|
+
# parameter 'foo', type: 'object' do
|
40
|
+
# property 'bar', type: 'string'
|
41
|
+
# end
|
42
|
+
#
|
43
|
+
# # refer a reusable parameter
|
44
|
+
# parameter ref: 'foo'
|
45
|
+
#
|
46
|
+
# Refers the reusable parameter with the same name if neither any
|
47
|
+
# keywords nor a block is specified.
|
48
|
+
#
|
49
|
+
# parameter 'foo'
|
50
|
+
#
|
51
|
+
def parameter(name = nil, **keywords, &block)
|
52
|
+
_define('parameter', name&.inspect) do
|
53
|
+
name = keywords[:ref] if name.nil?
|
54
|
+
keywords = { ref: name } unless keywords.any? || block
|
55
|
+
|
56
|
+
parameter_model = _meta_model.add_parameter(name, keywords)
|
57
|
+
_eval(parameter_model, Parameter, &block)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# Defines the request body or refers a reusable request body.
|
62
|
+
#
|
63
|
+
# # define a request body
|
64
|
+
# request_body type: 'object' do
|
65
|
+
# property 'foo', type: 'string'
|
66
|
+
# end
|
67
|
+
#
|
68
|
+
# # refer a reusable request body
|
69
|
+
# request_body ref: 'foo'
|
70
|
+
#
|
71
|
+
# Refers the reusable request body with the same name if neither any
|
72
|
+
# keywords nor a block is specified.
|
73
|
+
#
|
74
|
+
# request_body 'foo'
|
75
|
+
#
|
76
|
+
def request_body(**keywords, &block)
|
77
|
+
_define('request body') do
|
78
|
+
_meta_model.request_body = keywords
|
79
|
+
_eval(_meta_model.request_body, RequestBody, &block)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
# Defines a response or refers a reusable response.
|
84
|
+
#
|
85
|
+
# # define a response
|
86
|
+
# response 200, type: 'object' do
|
87
|
+
# property 'foo', type: 'string'
|
88
|
+
# end
|
89
|
+
#
|
90
|
+
# # refer a reusable response
|
91
|
+
# response 200, ref: 'foo'
|
92
|
+
#
|
93
|
+
# The default status is <code>"default"</code>.
|
94
|
+
#
|
95
|
+
# Refers the reusable response with the same name if neither any keywords
|
96
|
+
# nor a block is specified.
|
97
|
+
#
|
98
|
+
# response 'foo'
|
99
|
+
#
|
100
|
+
# Raises an Error if name is specified together with keywords or a block.
|
101
|
+
def response(status_or_name = nil, name = nil, **keywords, &block)
|
102
|
+
_define('response', status_or_name&.inspect) do
|
103
|
+
raise Error, 'name cannot be specified together with keywords ' \
|
104
|
+
'or a block' if name && (keywords.any? || block)
|
105
|
+
|
106
|
+
if keywords.any? || block
|
107
|
+
status = status_or_name
|
108
|
+
else
|
109
|
+
status = status_or_name if name
|
110
|
+
keywords = { ref: name || status_or_name }
|
111
|
+
end
|
112
|
+
response_model = _meta_model.add_response(status, keywords)
|
113
|
+
_eval(response_model, Response, &block)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Jsapi
|
4
|
+
module DSL
|
5
|
+
# Used to specify details of a response.
|
6
|
+
class Response < Schema
|
7
|
+
include Examples
|
8
|
+
|
9
|
+
# Defines a link or refers a reusable link object.
|
10
|
+
#
|
11
|
+
# # define a link
|
12
|
+
# link 'foo', operation_id: 'bar'
|
13
|
+
#
|
14
|
+
# # refer a reusable link
|
15
|
+
# link ref: 'foo'
|
16
|
+
#
|
17
|
+
# Refers the reusable link object with the same name if neither any
|
18
|
+
# keywords nor a block is specified.
|
19
|
+
#
|
20
|
+
# link 'foo'
|
21
|
+
#
|
22
|
+
def link(name = nil, **keywords, &block)
|
23
|
+
_define('link', name&.inspect) do
|
24
|
+
name = keywords[:ref] if name.nil?
|
25
|
+
keywords = { ref: name } unless keywords.any? || block
|
26
|
+
|
27
|
+
link_model = _meta_model.add_link(name, keywords)
|
28
|
+
Node.new(link_model, &block) if block
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Jsapi
|
4
|
+
module DSL
|
5
|
+
# Used to specify details of a schema.
|
6
|
+
class Schema < Node
|
7
|
+
|
8
|
+
# Includes all of the properties from +schemas+. Each argument must
|
9
|
+
# be the name of a schema defined by ClassMethods#api_schema or
|
10
|
+
# Definitions#schema.
|
11
|
+
def all_of(*schemas)
|
12
|
+
schemas.each { |schema| _meta_model.add_all_of({ schema: schema }) }
|
13
|
+
end
|
14
|
+
|
15
|
+
# Specifies a sample matching the schema.
|
16
|
+
def example(example)
|
17
|
+
_meta_model.add_example(example)
|
18
|
+
end
|
19
|
+
|
20
|
+
# Overrides Kernel#format to handle +format+ as a keyword.
|
21
|
+
def format(format) # :nodoc:
|
22
|
+
_keyword(:format, format)
|
23
|
+
end
|
24
|
+
|
25
|
+
# Specifies the kind of items that can be contained in an array.
|
26
|
+
#
|
27
|
+
# items do
|
28
|
+
# property 'foo', type: 'string'
|
29
|
+
# end
|
30
|
+
#
|
31
|
+
# Raises an Error if type is other than <code>"array"</code>.
|
32
|
+
def items(**keywords, &block)
|
33
|
+
unless _meta_model.respond_to?(:items=)
|
34
|
+
raise Error, "items isn't supported for '#{_meta_model.type}'"
|
35
|
+
end
|
36
|
+
|
37
|
+
_meta_model.items = keywords
|
38
|
+
Schema.new(_meta_model.items, &block) if block
|
39
|
+
end
|
40
|
+
|
41
|
+
# Specifies the model class to access nested object parameters by.
|
42
|
+
#
|
43
|
+
# model Foo do
|
44
|
+
# def bar
|
45
|
+
# # ...
|
46
|
+
# end
|
47
|
+
# end
|
48
|
+
#
|
49
|
+
# +klass+ can be any subclass of Model::Base. If block is given, an
|
50
|
+
# anonymous class is created that inherits either from +klass+ or
|
51
|
+
# Model::Base.
|
52
|
+
#
|
53
|
+
# Raises an Error if type is other than <code>"object"</code>.
|
54
|
+
def model(klass = nil, &block)
|
55
|
+
unless _meta_model.respond_to?(:model=)
|
56
|
+
raise Error, "model isn't supported for '#{_meta_model.type}'"
|
57
|
+
end
|
58
|
+
|
59
|
+
if block
|
60
|
+
klass = Class.new(klass || Model::Base)
|
61
|
+
klass.class_eval(&block)
|
62
|
+
end
|
63
|
+
_meta_model.model = klass
|
64
|
+
end
|
65
|
+
|
66
|
+
# Defines a property.
|
67
|
+
#
|
68
|
+
# property 'foo', type: 'string'
|
69
|
+
#
|
70
|
+
# property 'foo' do
|
71
|
+
# property 'bar', type: 'string'
|
72
|
+
# end
|
73
|
+
#
|
74
|
+
# Raises an Error if type is other than <code>"object"</code>.
|
75
|
+
def property(name, **keywords, &block)
|
76
|
+
_define('property', name.inspect) do
|
77
|
+
unless _meta_model.respond_to?(:add_property)
|
78
|
+
raise Error, "property isn't supported for '#{_meta_model.type}'"
|
79
|
+
end
|
80
|
+
|
81
|
+
property_model = _meta_model.add_property(name, keywords)
|
82
|
+
Schema.new(property_model, &block) if block
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
data/lib/jsapi/dsl.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'dsl/callbacks'
|
4
|
+
require_relative 'dsl/examples'
|
5
|
+
require_relative 'dsl/error'
|
6
|
+
require_relative 'dsl/node'
|
7
|
+
require_relative 'dsl/schema'
|
8
|
+
require_relative 'dsl/parameter'
|
9
|
+
require_relative 'dsl/request_body'
|
10
|
+
require_relative 'dsl/response'
|
11
|
+
require_relative 'dsl/operation'
|
12
|
+
require_relative 'dsl/openapi'
|
13
|
+
require_relative 'dsl/definitions'
|
14
|
+
require_relative 'dsl/class_methods'
|
15
|
+
|
16
|
+
module Jsapi
|
17
|
+
# Provides class methods to define top-level API components.
|
18
|
+
# See ClassMethods for details.
|
19
|
+
module DSL
|
20
|
+
def self.included(base) # :nodoc:
|
21
|
+
base.extend(ClassMethods)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Jsapi
|
4
|
+
module JSON
|
5
|
+
# Represents a JSON array.
|
6
|
+
class Array < Value
|
7
|
+
def initialize(elements, schema, definitions)
|
8
|
+
super(schema)
|
9
|
+
@elements = Array(elements).map do |element|
|
10
|
+
JSON.wrap(element, schema.items, definitions)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
# Returns +true+ if it contains no elements, +false+ otherwise.
|
15
|
+
def empty?
|
16
|
+
@elements.empty?
|
17
|
+
end
|
18
|
+
|
19
|
+
def inspect # :nodoc:
|
20
|
+
"#<#{self.class.name} [#{@elements.map(&:inspect).join(', ')}]>"
|
21
|
+
end
|
22
|
+
|
23
|
+
# See Value#validate.
|
24
|
+
def validate(errors)
|
25
|
+
return false unless super
|
26
|
+
|
27
|
+
@elements.map { |element| element.validate(errors) }.all?
|
28
|
+
end
|
29
|
+
|
30
|
+
def value
|
31
|
+
@value ||= @elements.map(&:value)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Jsapi
|
4
|
+
module JSON
|
5
|
+
# Represents +true+ or +false+.
|
6
|
+
class Boolean < Value
|
7
|
+
TRUTHY_VALUES = [true, 'True', 'true'].freeze
|
8
|
+
|
9
|
+
attr_reader :value
|
10
|
+
|
11
|
+
def initialize(value, schema)
|
12
|
+
super(schema)
|
13
|
+
@value = value.in?(TRUTHY_VALUES)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Jsapi
|
4
|
+
module JSON
|
5
|
+
# Represents a JSON integer.
|
6
|
+
class Integer < Value
|
7
|
+
attr_reader :value
|
8
|
+
|
9
|
+
def initialize(value, schema)
|
10
|
+
super(schema)
|
11
|
+
@value = schema.convert(value.to_i)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Jsapi
|
4
|
+
module JSON
|
5
|
+
# Represents +null+.
|
6
|
+
class Null < Value
|
7
|
+
|
8
|
+
# Returns allways +true+.
|
9
|
+
def empty?
|
10
|
+
true
|
11
|
+
end
|
12
|
+
|
13
|
+
def inspect # :nodoc:
|
14
|
+
"#<#{self.class}>"
|
15
|
+
end
|
16
|
+
|
17
|
+
# Returns allways +true+.
|
18
|
+
def null?
|
19
|
+
true
|
20
|
+
end
|
21
|
+
|
22
|
+
def value
|
23
|
+
nil
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Jsapi
|
4
|
+
module JSON
|
5
|
+
# Represents a JSON number.
|
6
|
+
class Number < Value
|
7
|
+
attr_reader :value
|
8
|
+
|
9
|
+
def initialize(value, schema)
|
10
|
+
super(schema)
|
11
|
+
@value = schema.convert(value.to_f)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Jsapi
|
4
|
+
module JSON
|
5
|
+
# Represents a JSON object.
|
6
|
+
class Object < Value
|
7
|
+
include Model::Nestable
|
8
|
+
|
9
|
+
attr_reader :raw_attributes
|
10
|
+
|
11
|
+
def initialize(attributes, schema, definitions)
|
12
|
+
# Select inherriting schema on polymorphism
|
13
|
+
if (discriminator = schema.discriminator)
|
14
|
+
schema = discriminator.resolve(
|
15
|
+
attributes[discriminator.property_name],
|
16
|
+
definitions
|
17
|
+
)
|
18
|
+
end
|
19
|
+
# Wrap attribute values
|
20
|
+
@raw_attributes = schema.resolve_properties(:write, definitions)
|
21
|
+
.transform_values do |property|
|
22
|
+
JSON.wrap(attributes[property.name], property.schema, definitions)
|
23
|
+
end
|
24
|
+
|
25
|
+
super(schema)
|
26
|
+
end
|
27
|
+
|
28
|
+
# Returns +true+ if all attributes are empty, +false+ otherwise.
|
29
|
+
def empty?
|
30
|
+
@raw_attributes.values.all?(&:empty?)
|
31
|
+
end
|
32
|
+
|
33
|
+
def inspect # :nodoc:
|
34
|
+
"#<#{self.class.name} " \
|
35
|
+
"#{@raw_attributes.map { |k, v| "#{k}: #{v.inspect}" }.join(', ')}>"
|
36
|
+
end
|
37
|
+
|
38
|
+
# Returns a model to read attributes by.
|
39
|
+
def model
|
40
|
+
@model ||= (schema.model || Model::Base).new(self)
|
41
|
+
end
|
42
|
+
|
43
|
+
alias value model
|
44
|
+
|
45
|
+
# See Value#validate
|
46
|
+
def validate(errors)
|
47
|
+
return false unless super
|
48
|
+
|
49
|
+
validate_attributes(errors)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Jsapi
|
4
|
+
module JSON
|
5
|
+
# Represents a JSON string.
|
6
|
+
class String < Value
|
7
|
+
attr_reader :value
|
8
|
+
|
9
|
+
def initialize(value, schema)
|
10
|
+
super(schema)
|
11
|
+
@value = schema.convert(
|
12
|
+
case schema.format
|
13
|
+
when 'date'
|
14
|
+
value.to_date
|
15
|
+
when 'date-time'
|
16
|
+
value.to_datetime
|
17
|
+
else
|
18
|
+
value.to_s
|
19
|
+
end
|
20
|
+
)
|
21
|
+
end
|
22
|
+
|
23
|
+
# See Value#empty?.
|
24
|
+
def empty?
|
25
|
+
value.blank?
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Jsapi
|
4
|
+
module JSON
|
5
|
+
# Represents a JSON value.
|
6
|
+
#
|
7
|
+
# Subclasses of Value must provide a +value+ method returning the outside
|
8
|
+
# representation of the JSON value.
|
9
|
+
class Value
|
10
|
+
attr_reader :schema
|
11
|
+
|
12
|
+
def initialize(schema)
|
13
|
+
@schema = schema
|
14
|
+
end
|
15
|
+
|
16
|
+
# Used by #validate to test whether or not it is empty.
|
17
|
+
# Returns +false+ by default.
|
18
|
+
def empty?
|
19
|
+
false
|
20
|
+
end
|
21
|
+
|
22
|
+
def inspect # :nodoc:
|
23
|
+
"#<#{self.class} #{value.inspect}>"
|
24
|
+
end
|
25
|
+
|
26
|
+
# Used by #validate to test whether or not it is +null+.
|
27
|
+
# Returns +false+ by default.
|
28
|
+
def null?
|
29
|
+
false
|
30
|
+
end
|
31
|
+
|
32
|
+
# Validates it against #schema. Returns +true+ if it is valid, +false+
|
33
|
+
# otherwise. Detected errors are added to +errors+.
|
34
|
+
def validate(errors)
|
35
|
+
unless schema.existence.reach?(self)
|
36
|
+
errors.add(:base, :blank)
|
37
|
+
return false
|
38
|
+
end
|
39
|
+
return true if null?
|
40
|
+
|
41
|
+
schema.validations.each_value.map do |validation|
|
42
|
+
validation.validate(value, errors)
|
43
|
+
end.all?
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
data/lib/jsapi/json.rb
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'json/value'
|
4
|
+
require_relative 'json/array'
|
5
|
+
require_relative 'json/boolean'
|
6
|
+
require_relative 'json/integer'
|
7
|
+
require_relative 'json/null'
|
8
|
+
require_relative 'json/number'
|
9
|
+
require_relative 'json/object'
|
10
|
+
require_relative 'json/string'
|
11
|
+
|
12
|
+
module Jsapi
|
13
|
+
# Provides a DOM for JSON values.
|
14
|
+
module JSON
|
15
|
+
class << self
|
16
|
+
def wrap(object, schema, definitions = nil)
|
17
|
+
schema = schema.resolve(definitions) unless definitions.nil?
|
18
|
+
|
19
|
+
object = schema.default if object.nil?
|
20
|
+
return Null.new(schema) if object.nil?
|
21
|
+
|
22
|
+
case schema.type
|
23
|
+
when 'array'
|
24
|
+
Array.new(object, schema, definitions)
|
25
|
+
when 'boolean'
|
26
|
+
Boolean.new(object, schema)
|
27
|
+
when 'integer'
|
28
|
+
Integer.new(object, schema)
|
29
|
+
when 'number'
|
30
|
+
Number.new(object, schema)
|
31
|
+
when 'object'
|
32
|
+
Object.new(object, schema, definitions)
|
33
|
+
when 'string'
|
34
|
+
String.new(object, schema)
|
35
|
+
else
|
36
|
+
raise "invalid type: #{schema.type}"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|