lurker 0.6.2 → 0.6.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
- checksums.yaml.gz.sig +1 -1
- data/Gemfile +1 -0
- data/features/dereferencing_through_inlining.feature +102 -0
- data/features/partials.feature +3 -1
- data/features/step_definitions/additional_cli_steps.rb +19 -0
- data/features/support/files_helper.rb +7 -0
- data/lib/lurker/endpoint.rb +85 -50
- data/lib/lurker/json/concerns/validatable.rb +47 -0
- data/lib/lurker/json/orderer.rb +19 -0
- data/lib/lurker/json/parser/expertise.rb +30 -0
- data/lib/lurker/json/parser/plain_strategy.rb +39 -0
- data/lib/lurker/json/parser/typed_strategy.rb +71 -0
- data/lib/lurker/json/parser.rb +73 -0
- data/lib/lurker/json/reader.rb +28 -0
- data/lib/lurker/json/schema/attribute.rb +115 -0
- data/lib/lurker/json/schema/extensions.rb +19 -0
- data/lib/lurker/json/schema/list.rb +51 -0
- data/lib/lurker/json/schema/object.rb +67 -0
- data/lib/lurker/json/schema/reference.rb +34 -0
- data/lib/lurker/{endpoint → json/schema}/response_codes.rb +13 -16
- data/lib/lurker/json/schema/tuple/all_of.rb +17 -0
- data/lib/lurker/json/schema/tuple/any_of.rb +17 -0
- data/lib/lurker/json/schema/tuple/one_of.rb +17 -0
- data/lib/lurker/json/schema/tuple.rb +38 -0
- data/lib/lurker/json/schema.rb +122 -0
- data/lib/lurker/json/writter.rb +58 -0
- data/lib/lurker/presenters/endpoint_presenter.rb +2 -2
- data/lib/lurker/presenters/schema_presenter.rb +4 -1
- data/lib/lurker/presenters/service_presenter.rb +8 -2
- data/lib/lurker/service.rb +4 -4
- data/lib/lurker/version.rb +1 -1
- data/lib/lurker.rb +19 -8
- data/spec/lurker/json/list_spec.rb +101 -0
- data/spec/lurker/json/schema_spec.rb +126 -0
- data/spec/spec_helper.rb +2 -0
- data/spec/support/matchers/json_attribute.rb +27 -0
- data/spec/support/matchers/json_object.rb +33 -0
- data/templates/generate_stuff.rb +19 -10
- data.tar.gz.sig +2 -4
- metadata +33 -9
- metadata.gz.sig +0 -0
- data/lib/lurker/endpoint/http_parameters.rb +0 -77
- data/lib/lurker/schema.rb +0 -89
- data/lib/lurker/schema_modifier/array.rb +0 -28
- data/lib/lurker/schema_modifier/atom.rb +0 -97
- data/lib/lurker/schema_modifier/hash.rb +0 -30
- data/lib/lurker/schema_modifier.rb +0 -48
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c59974fdb662a2fbadcb01539d0fe9a1b919da2c
|
4
|
+
data.tar.gz: 476c5cad93b78d96f397fae62ed32ae19ad30c21
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a2a7af02fa6d092a639b79f5f903c373c33b40cc3b8ad621aa69eb6ebdd056998b66cfdb57d93be644dff1c0dd2e3cf554aec85a30fd61bc65038b6060a1ace9
|
7
|
+
data.tar.gz: d2afae3c32e2adce210fb74144e0078ea8db8241b7aebeb0afeb474ec67dcf16083ad8153fc405fde8924af7d4986602575078d836be4c5b2c1e5d7a20f28fd3
|
checksums.yaml.gz.sig
CHANGED
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
�ƴs���:�vsT�\�k���Ȑj<Dk�9�s:d�������L��{o�z���W�_�W���aA�za�G��q#Mz^)8K㊥����r_~����%��Մ��H���'�0���51rÝRy�NW��ݧm�FZ��#��a� I9�g��b�:Kj��,i|�g\C�}��F��Ѥs��A�;��*���P�iM7�5aܶ��/ ����U���7A�>/K���Sh�Ņm; 5;��P�oX�3��
|
data/Gemfile
CHANGED
@@ -0,0 +1,102 @@
|
|
1
|
+
Feature: $ref defererencing through inlining
|
2
|
+
Background:
|
3
|
+
Given a checked file "lurker/api/v3/users/__id-PATCH.json.yml" with:
|
4
|
+
"""yml
|
5
|
+
---
|
6
|
+
description: user updating
|
7
|
+
prefix: users management
|
8
|
+
requestParameters:
|
9
|
+
description: ''
|
10
|
+
type: object
|
11
|
+
additionalProperties: false
|
12
|
+
required: []
|
13
|
+
properties:
|
14
|
+
user:
|
15
|
+
"$ref": "../../../definitions/user_request_parameters.json#/"
|
16
|
+
responseCodes:
|
17
|
+
- status: 200
|
18
|
+
successful: true
|
19
|
+
description: ''
|
20
|
+
responseParameters:
|
21
|
+
"$ref": "../../../definitions/user.json#/"
|
22
|
+
extensions:
|
23
|
+
method: PATCH
|
24
|
+
path_info: "/api/v3/users/1"
|
25
|
+
path_params:
|
26
|
+
id: '1'
|
27
|
+
controller: api/v3/users
|
28
|
+
action: update
|
29
|
+
|
30
|
+
"""
|
31
|
+
And a file named "lurker/definitions/user_request_parameters.json" with:
|
32
|
+
"""json
|
33
|
+
{
|
34
|
+
"properties": {
|
35
|
+
"name": {
|
36
|
+
"type": "string",
|
37
|
+
"example": "Bob"
|
38
|
+
}
|
39
|
+
}
|
40
|
+
}
|
41
|
+
"""
|
42
|
+
And a file named "lurker/definitions/user.json.yml" with:
|
43
|
+
"""yml
|
44
|
+
---
|
45
|
+
properties:
|
46
|
+
id:
|
47
|
+
type: integer
|
48
|
+
example: 1
|
49
|
+
name:
|
50
|
+
type: string
|
51
|
+
example: razum2um
|
52
|
+
surname:
|
53
|
+
type: string
|
54
|
+
example: Unknown
|
55
|
+
"""
|
56
|
+
And a file named "spec/controllers/api/v3/users_controller_spec.rb" with:
|
57
|
+
"""ruby
|
58
|
+
require "spec_helper"
|
59
|
+
|
60
|
+
describe Api::V3::UsersController, :lurker do
|
61
|
+
render_views
|
62
|
+
|
63
|
+
let(:user) do
|
64
|
+
User.where(name: 'razum2um', surname: 'Unknown').first_or_create!
|
65
|
+
end
|
66
|
+
|
67
|
+
it "updates a user surname as string" do
|
68
|
+
patch :update, id: user.id, user: { surname: 'Marley' }
|
69
|
+
expect(response).to be_success
|
70
|
+
end
|
71
|
+
end
|
72
|
+
"""
|
73
|
+
|
74
|
+
Scenario: json schema left $ref keyword as is using "users/update"
|
75
|
+
When I run `bin/rspec spec/controllers/api/v3/users_controller_spec.rb`
|
76
|
+
Then the example should pass
|
77
|
+
Then a file named "lurker/api/v3/users/__id-PATCH.json.yml" should exist
|
78
|
+
Then the checked file "lurker/api/v3/users/__id-PATCH.json.yml" should not change
|
79
|
+
Then a file named "lurker/definitions/user_request_parameters.json" should exist
|
80
|
+
Then the file "lurker/definitions/user_request_parameters.json" should contain exactly:
|
81
|
+
"""json
|
82
|
+
{
|
83
|
+
"description": "",
|
84
|
+
"type": "object",
|
85
|
+
"additionalProperties": false,
|
86
|
+
"required": [
|
87
|
+
|
88
|
+
],
|
89
|
+
"properties": {
|
90
|
+
"name": {
|
91
|
+
"description": "",
|
92
|
+
"type": "string",
|
93
|
+
"example": "Bob"
|
94
|
+
},
|
95
|
+
"surname": {
|
96
|
+
"description": "",
|
97
|
+
"type": "string",
|
98
|
+
"example": "Marley"
|
99
|
+
}
|
100
|
+
}
|
101
|
+
}
|
102
|
+
"""
|
data/features/partials.feature
CHANGED
@@ -20,6 +20,9 @@ Feature: partials
|
|
20
20
|
name:
|
21
21
|
type: string
|
22
22
|
example: razum2um
|
23
|
+
surname:
|
24
|
+
type: string
|
25
|
+
example: Unknown
|
23
26
|
"""
|
24
27
|
And a file named "lurker/definitions/repo.json.yml" with:
|
25
28
|
"""yml
|
@@ -94,4 +97,3 @@ Feature: partials
|
|
94
97
|
create index.html
|
95
98
|
create api/v1/users/__user_id/repos-POST.html
|
96
99
|
"""
|
97
|
-
|
@@ -1,3 +1,10 @@
|
|
1
|
+
Given /^a checked file "([^"]*)" with:$/ do |file_name, file_content|
|
2
|
+
write_file(file_name, file_content)
|
3
|
+
|
4
|
+
@files ||= {}
|
5
|
+
in_current_dir { @files[md5(file_name)] = checksum(file_name) }
|
6
|
+
end
|
7
|
+
|
1
8
|
Given /^an empty directory named "([^"]*)"$/ do |dir_name|
|
2
9
|
FileUtils.rm_rf File.expand_path("../../../tmp/lurker_app/#{dir_name}", __FILE__)
|
3
10
|
create_dir(dir_name)
|
@@ -83,3 +90,15 @@ Then(/^I should see JSON response with "([^"]*)"$/) do |name|
|
|
83
90
|
expect(page).to have_content name
|
84
91
|
end
|
85
92
|
end
|
93
|
+
|
94
|
+
Then /(?:a|the) checked file "([^"]*)" should not change$/ do |file_name|
|
95
|
+
in_current_dir do
|
96
|
+
expect(@files.try(:[], md5(file_name))).to eq checksum(file_name)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
Then /(?:a|the) checked file "([^"]*)" should change$/ do |file_name|
|
101
|
+
in_current_dir do
|
102
|
+
expect(@files.try(:[], md5(file_name))).not_to eq checksum(file_name)
|
103
|
+
end
|
104
|
+
end
|
data/lib/lurker/endpoint.rb
CHANGED
@@ -8,24 +8,43 @@ module Lurker
|
|
8
8
|
class Endpoint
|
9
9
|
include Lurker::Utils
|
10
10
|
|
11
|
+
PREFIX = 'prefix'.freeze
|
12
|
+
ACTION = 'action'.freeze
|
13
|
+
CONTROLLER = 'controller'.freeze
|
14
|
+
EXTENSIONS = 'extensions'.freeze
|
15
|
+
PATH_PARAMS = 'path_params'.freeze
|
16
|
+
QUERY_PARAMS = 'query_params'.freeze
|
17
|
+
DEPRECATED = 'deprecated'.freeze
|
18
|
+
DESCRIPTION = 'description'.freeze
|
19
|
+
RESPONSE_CODES = 'responseCodes'.freeze
|
20
|
+
REQUEST_PARAMETERS = 'requestParameters'.freeze
|
21
|
+
RESPONSE_PARAMETERS = 'responseParameters'.freeze
|
22
|
+
DESCRPTIONS = {
|
23
|
+
'index' => 'listing',
|
24
|
+
'show' => '',
|
25
|
+
'edit' => 'editing',
|
26
|
+
'create' => 'creation',
|
27
|
+
'update' => 'updating',
|
28
|
+
'destroy' => 'descruction'
|
29
|
+
}.freeze
|
30
|
+
|
11
31
|
attr_reader :schema, :service, :endpoint_path, :extensions
|
12
|
-
attr_reader :request_parameters, :response_parameters, :response_codes
|
13
|
-
attr_accessor :errors
|
14
32
|
|
15
33
|
def initialize(endpoint_path, extensions = {}, service = Lurker::Service.default_service)
|
16
34
|
@endpoint_path = endpoint_path
|
17
35
|
@extensions = extensions
|
18
36
|
@service = service
|
19
|
-
@errors = []
|
20
37
|
@persisted = false
|
21
38
|
@schema = File.exist?(endpoint_path) ? load_schema : build_schema
|
22
|
-
|
23
|
-
|
39
|
+
@request_errors = []
|
40
|
+
@response_errors = []
|
24
41
|
end
|
25
42
|
|
26
43
|
def persist!
|
27
|
-
|
28
|
-
|
44
|
+
finalize_schema!
|
45
|
+
|
46
|
+
Lurker::Json::Orderer.reorder(schema) unless persisted?
|
47
|
+
Lurker::Json::Writter.write(schema, endpoint_path)
|
29
48
|
|
30
49
|
@persisted = true
|
31
50
|
end
|
@@ -42,21 +61,30 @@ module Lurker
|
|
42
61
|
end
|
43
62
|
|
44
63
|
def consume_request(params, successful = true)
|
45
|
-
|
46
|
-
|
64
|
+
parameters = stringify_keys(params)
|
65
|
+
|
66
|
+
if persisted?
|
67
|
+
@request_errors = request_parameters.validate(parameters)
|
68
|
+
@request_errors.unshift('Request') unless @request_errors.empty?
|
69
|
+
end
|
70
|
+
|
71
|
+
request_parameters.merge!(parameters) if successful
|
47
72
|
end
|
48
73
|
|
49
74
|
def consume_response(params, status_code, successful = true)
|
75
|
+
parameters = stringify_keys(params)
|
76
|
+
|
50
77
|
if persisted?
|
51
78
|
response_codes.validate!(status_code, successful)
|
52
|
-
|
79
|
+
|
80
|
+
@response_errors = response_parameters.validate(parameters)
|
81
|
+
@response_errors.unshift('Response') unless @response_errors.empty?
|
53
82
|
|
54
83
|
return
|
55
84
|
end
|
56
85
|
|
57
|
-
response_parameters.
|
58
|
-
response_codes.
|
59
|
-
status_code, successful)
|
86
|
+
response_parameters.merge!(parameters) if successful
|
87
|
+
response_codes.merge!(status_code, successful)
|
60
88
|
end
|
61
89
|
|
62
90
|
def verb
|
@@ -65,44 +93,46 @@ module Lurker
|
|
65
93
|
|
66
94
|
def path
|
67
95
|
@path ||= endpoint_path.
|
68
|
-
gsub(service.service_dir,
|
96
|
+
gsub(service.service_dir, '').
|
69
97
|
match(/\/?(.*)[-\/][A-Z]+\.json(\.yml)?(\.erb)?$/)[1]
|
70
98
|
end
|
71
99
|
|
72
100
|
# properties
|
73
101
|
|
74
102
|
def deprecated?
|
75
|
-
@schema[
|
103
|
+
@schema[DEPRECATED]
|
76
104
|
end
|
77
105
|
|
78
106
|
def prefix
|
79
|
-
@schema[
|
107
|
+
@schema[PREFIX]
|
80
108
|
end
|
81
109
|
|
82
110
|
def description
|
83
|
-
@schema[
|
111
|
+
@schema[DESCRIPTION]
|
84
112
|
end
|
85
113
|
|
86
114
|
def url_params
|
87
|
-
(schema
|
115
|
+
(@schema[EXTENSIONS][PATH_PARAMS] || {}).reject { |k, _| %w(action controller format).include? k }
|
88
116
|
end
|
89
117
|
|
90
118
|
def query_params
|
91
|
-
(schema
|
119
|
+
(@schema[EXTENSIONS][QUERY_PARAMS] || {})
|
92
120
|
end
|
93
121
|
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
@response_codes = ResponseCodes.new(schema)
|
122
|
+
def request_parameters
|
123
|
+
@schema[REQUEST_PARAMETERS]
|
124
|
+
end
|
98
125
|
|
99
|
-
|
100
|
-
|
126
|
+
def response_parameters
|
127
|
+
@schema[RESPONSE_PARAMETERS]
|
128
|
+
end
|
101
129
|
|
102
|
-
|
103
|
-
|
130
|
+
def response_codes
|
131
|
+
@schema[RESPONSE_CODES]
|
104
132
|
end
|
105
133
|
|
134
|
+
protected
|
135
|
+
|
106
136
|
def persisted?
|
107
137
|
!!@persisted
|
108
138
|
end
|
@@ -110,43 +140,48 @@ module Lurker
|
|
110
140
|
def load_schema
|
111
141
|
@persisted = true
|
112
142
|
|
113
|
-
Lurker::
|
114
|
-
|
115
|
-
stringify_keys(extensions)
|
116
|
-
)
|
143
|
+
reader = Lurker::Json::Reader.new(endpoint_path)
|
144
|
+
schemify(reader.payload)
|
117
145
|
end
|
118
146
|
|
119
147
|
def build_schema
|
120
148
|
@persisted = false
|
121
149
|
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
}
|
128
|
-
|
129
|
-
)
|
130
|
-
end
|
131
|
-
|
132
|
-
def
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
YAML.load(erb)
|
137
|
-
else
|
138
|
-
YAML.load_file(fname)
|
150
|
+
payload = {
|
151
|
+
DESCRIPTION => '',
|
152
|
+
PREFIX => '',
|
153
|
+
REQUEST_PARAMETERS => {},
|
154
|
+
RESPONSE_CODES => [],
|
155
|
+
RESPONSE_PARAMETERS => {}
|
156
|
+
}
|
157
|
+
schemify(payload)
|
158
|
+
end
|
159
|
+
|
160
|
+
def schemify(payload)
|
161
|
+
Lurker::Json::Parser.plain(uri: endpoint_path).parse(payload).tap do |schm|
|
162
|
+
ext = Lurker::Json::Extensions.new(stringify_keys extensions)
|
163
|
+
schm.merge!(EXTENSIONS => ext)
|
139
164
|
end
|
140
165
|
end
|
141
166
|
|
167
|
+
def finalize_schema!
|
168
|
+
path_params = schema[EXTENSIONS][PATH_PARAMS] || {}
|
169
|
+
subject = path_params[CONTROLLER].to_s.split(/\//).last.to_s
|
170
|
+
description = DESCRPTIONS[path_params[ACTION]]
|
171
|
+
|
172
|
+
schema[DESCRIPTION] = "#{subject.singularize} #{description}".strip if schema[DESCRIPTION].blank?
|
173
|
+
schema[PREFIX] = "#{subject} management" if schema[PREFIX].blank?
|
174
|
+
end
|
175
|
+
|
142
176
|
def raise_errors!
|
143
|
-
return if
|
177
|
+
return if @response_errors.empty?
|
144
178
|
|
145
|
-
errors = (
|
179
|
+
errors = (@request_errors | @response_errors) * "\n"
|
146
180
|
exception = Lurker::ValidationError.new(word_wrap errors)
|
147
181
|
if (example = Lurker::Spy.current.block).respond_to?(:metadata) && (metadata = example.metadata).respond_to?(:location, true)
|
148
182
|
exception.set_backtrace [metadata.send(:location)]
|
149
183
|
end
|
184
|
+
|
150
185
|
raise exception
|
151
186
|
end
|
152
187
|
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module Lurker
|
2
|
+
module Json
|
3
|
+
module Concerns
|
4
|
+
module Validatable
|
5
|
+
ID = 'id'.freeze
|
6
|
+
TYPE = 'type'.freeze
|
7
|
+
OBJECT = 'object'.freeze
|
8
|
+
PROPERTIES = 'properties'.freeze
|
9
|
+
ADDITIONAL_PROPERTIES = 'additionalProperties'.freeze
|
10
|
+
|
11
|
+
def validate(data)
|
12
|
+
Lurker::Validator.new(to_validation_schema, data,
|
13
|
+
record_errors: true).validate.map { |error| "- #{error}" }
|
14
|
+
end
|
15
|
+
|
16
|
+
def to_validation_schema
|
17
|
+
set_additional_properties_false_on(to_hash).tap do |schema|
|
18
|
+
schema[ID] = "file://#{uri}"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def set_additional_properties_false_on(object)
|
25
|
+
case object
|
26
|
+
when Hash
|
27
|
+
copy = object.dup
|
28
|
+
|
29
|
+
if object[TYPE] == OBJECT || object.key?(PROPERTIES)
|
30
|
+
copy[ADDITIONAL_PROPERTIES] ||= false
|
31
|
+
end
|
32
|
+
|
33
|
+
object.each do |key, value|
|
34
|
+
next if key == ADDITIONAL_PROPERTIES
|
35
|
+
copy[key] = set_additional_properties_false_on(value)
|
36
|
+
end
|
37
|
+
|
38
|
+
copy
|
39
|
+
when Array
|
40
|
+
copy = object.map { |value| set_additional_properties_false_on(value) }
|
41
|
+
else object
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Lurker
|
2
|
+
module Json
|
3
|
+
class Orderer
|
4
|
+
EXTENSIONS = 'extensions'.freeze
|
5
|
+
|
6
|
+
class << self
|
7
|
+
def reorder(schema)
|
8
|
+
new.reorder(schema)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def reorder(schema)
|
13
|
+
extensions = schema.delete(EXTENSIONS).try(:reorder!)
|
14
|
+
schema.reorder!
|
15
|
+
schema[EXTENSIONS] = extensions
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Lurker
|
2
|
+
module Json
|
3
|
+
class Parser
|
4
|
+
module Expertise
|
5
|
+
REF = '$ref'.freeze
|
6
|
+
TYPE = 'type'.freeze
|
7
|
+
ANYOF = 'anyOf'.freeze
|
8
|
+
ALLOF = 'allOf'.freeze
|
9
|
+
ONEOF = 'oneOf'.freeze
|
10
|
+
ITEMS = 'items'.freeze
|
11
|
+
PROPERTIES = 'properties'.freeze
|
12
|
+
|
13
|
+
module_function
|
14
|
+
|
15
|
+
def type_defined?(hash)
|
16
|
+
return false unless hash.is_a?(Hash)
|
17
|
+
|
18
|
+
hash.key? TYPE
|
19
|
+
end
|
20
|
+
|
21
|
+
def type_supposed?(hash)
|
22
|
+
return false unless hash.is_a?(Hash)
|
23
|
+
|
24
|
+
hash.key?(ANYOF) || hash.key?(ALLOF) || hash.key?(ONEOF) ||
|
25
|
+
hash.key?(ITEMS) || hash.key?(PROPERTIES) || hash.key?(REF)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Lurker
|
2
|
+
module Json
|
3
|
+
class Parser
|
4
|
+
class PlainStrategy
|
5
|
+
include Lurker::Json::Parser::Expertise
|
6
|
+
|
7
|
+
attr_reader :schema_options
|
8
|
+
|
9
|
+
def initialize(options)
|
10
|
+
@schema_options = options.dup
|
11
|
+
end
|
12
|
+
|
13
|
+
def parse(payload)
|
14
|
+
case payload
|
15
|
+
when Lurker::Json::Schema
|
16
|
+
payload
|
17
|
+
when Hash
|
18
|
+
return parse_as_typed(payload) if type_defined?(payload) ||
|
19
|
+
type_supposed?(payload)
|
20
|
+
|
21
|
+
Lurker::Json::Schema.new(payload, schema_options)
|
22
|
+
when Array
|
23
|
+
payload.map do |schema|
|
24
|
+
Lurker::Json::Parser.plain(schema_options).parse(schema)
|
25
|
+
end
|
26
|
+
else
|
27
|
+
payload
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def parse_as_typed(payload)
|
34
|
+
Lurker::Json::Parser.typed(schema_options).parse(payload)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
module Lurker
|
2
|
+
module Json
|
3
|
+
class Parser
|
4
|
+
class TypedStrategy
|
5
|
+
include Lurker::Json::Parser::Expertise
|
6
|
+
|
7
|
+
ANYOF = 'anyOf'.freeze
|
8
|
+
ALLOF = 'allOf'.freeze
|
9
|
+
ONEOF = 'oneOf'.freeze
|
10
|
+
ITEMS = 'items'.freeze
|
11
|
+
TYPE = 'type'.freeze
|
12
|
+
ARRAY = 'array'.freeze
|
13
|
+
OBJECT = 'object'.freeze
|
14
|
+
PROPERTIES = 'properties'.freeze
|
15
|
+
|
16
|
+
attr_reader :schema_options
|
17
|
+
|
18
|
+
def initialize(options)
|
19
|
+
@schema_options = options.dup
|
20
|
+
end
|
21
|
+
|
22
|
+
def parse(payload)
|
23
|
+
case payload
|
24
|
+
when Lurker::Json::Schema
|
25
|
+
payload
|
26
|
+
when Hash
|
27
|
+
return create_by_type(payload) if type_defined?(payload)
|
28
|
+
return create_by_supposition(payload) if type_supposed?(payload)
|
29
|
+
|
30
|
+
Lurker::Json::Object.new(payload, schema_options)
|
31
|
+
when Array
|
32
|
+
Lurker::Json::List.new(payload, schema_options)
|
33
|
+
else
|
34
|
+
Lurker::Json::Attribute.new(payload, schema_options)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def create_by_supposition(payload)
|
41
|
+
if payload.key?(ITEMS)
|
42
|
+
Lurker::Json::List.new(payload, schema_options)
|
43
|
+
elsif payload.key?(PROPERTIES)
|
44
|
+
Lurker::Json::Object.new(payload, schema_options)
|
45
|
+
elsif payload.key?(ANYOF)
|
46
|
+
Lurker::Json::Tuple::AnyOf.new(payload, schema_options)
|
47
|
+
elsif payload.key?(ALLOF)
|
48
|
+
Lurker::Json::Tuple::AllOf.new(payload, schema_options)
|
49
|
+
elsif payload.key?(ONEOF)
|
50
|
+
Lurker::Json::Tuple::OneOf.new(payload, schema_options)
|
51
|
+
elsif payload.key?(REF)
|
52
|
+
Lurker::Json::Reference.new(payload, schema_options)
|
53
|
+
else
|
54
|
+
raise "Unknown type supposition for #{payload}"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def create_by_type(payload)
|
59
|
+
case payload[TYPE]
|
60
|
+
when OBJECT
|
61
|
+
Lurker::Json::Object.new(payload, schema_options)
|
62
|
+
when ARRAY
|
63
|
+
Lurker::Json::List.new(payload, schema_options)
|
64
|
+
else
|
65
|
+
Lurker::Json::Attribute.new(payload, schema_options)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
module Lurker
|
2
|
+
module Json
|
3
|
+
class Parser
|
4
|
+
class << self
|
5
|
+
def plain(options = {})
|
6
|
+
new(options).plain
|
7
|
+
end
|
8
|
+
|
9
|
+
def typed(options = {})
|
10
|
+
new(options).typed
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def initialize(options = {})
|
15
|
+
@root_schema = options[:root_schema]
|
16
|
+
@parent_schema = options[:parent_schema]
|
17
|
+
@parent_property = options[:parent_property]
|
18
|
+
@uri = options[:uri] || @parent_schema.try(:uri)
|
19
|
+
@strategy = nil
|
20
|
+
end
|
21
|
+
|
22
|
+
def parse(payload)
|
23
|
+
parse_once { @strategy.new(schema_options_once).parse(payload) }
|
24
|
+
end
|
25
|
+
|
26
|
+
def parse_property(property, payload)
|
27
|
+
options = schema_options_once.merge!(parent_property: property)
|
28
|
+
parse_once { @strategy.new(options).parse(payload) }
|
29
|
+
end
|
30
|
+
|
31
|
+
def plain(options = {})
|
32
|
+
@options = schema_options.merge!(options)
|
33
|
+
@strategy = strategy_klass(:plain)
|
34
|
+
self
|
35
|
+
end
|
36
|
+
|
37
|
+
def typed(options = {})
|
38
|
+
@options = schema_options.merge!(options)
|
39
|
+
@strategy = strategy_klass(:typed)
|
40
|
+
self
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def parse_once(&block)
|
46
|
+
raise 'Define parsing strategy [plain|typed] before using' unless @strategy.present?
|
47
|
+
|
48
|
+
result = block.call
|
49
|
+
@strategy = nil
|
50
|
+
|
51
|
+
result
|
52
|
+
end
|
53
|
+
|
54
|
+
def schema_options_once
|
55
|
+
options = @options.present? ? @options.dup : schema_options
|
56
|
+
@options = {}
|
57
|
+
|
58
|
+
options
|
59
|
+
end
|
60
|
+
|
61
|
+
def strategy_klass(name)
|
62
|
+
"lurker/json/parser/#{name}_strategy".camelize.constantize
|
63
|
+
end
|
64
|
+
|
65
|
+
def schema_options
|
66
|
+
{
|
67
|
+
uri: @uri, root_schema: @root_schema,
|
68
|
+
parent_schema: @parent_schema, parent_property: @parent_property
|
69
|
+
}
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|