render 0.0.8 → 0.0.9
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.
- data/.ruby-version +1 -1
- data/lib/json/draft-04/hyper-schema.json +168 -0
- data/lib/json/draft-04/schema.json +150 -0
- data/lib/render.rb +2 -0
- data/lib/render/attributes/array_attribute.rb +20 -14
- data/lib/render/attributes/attribute.rb +23 -7
- data/lib/render/attributes/hash_attribute.rb +6 -2
- data/lib/render/definition.rb +13 -7
- data/lib/render/errors.rb +33 -6
- data/lib/render/generator.rb +67 -8
- data/lib/render/graph.rb +39 -64
- data/lib/render/json_schema.rb +12 -0
- data/lib/render/schema.rb +92 -31
- data/lib/render/type.rb +51 -9
- data/lib/render/version.rb +1 -1
- data/readme.md +66 -9
- data/render.gemspec +4 -3
- data/spec/functional/render/attribute_spec.rb +66 -8
- data/spec/functional/render/nested_schemas_spec.rb +18 -26
- data/spec/functional/render/schema_spec.rb +28 -0
- data/spec/integration/render/graph_spec.rb +3 -3
- data/spec/integration/render/nested_graph_spec.rb +12 -14
- data/spec/integration/render/schema_spec.rb +4 -4
- data/spec/support/schemas/film.json +3 -3
- data/spec/support/schemas/films.json +3 -3
- data/spec/unit/render/attributes/array_attribute_spec.rb +34 -9
- data/spec/unit/render/attributes/attribute_spec.rb +13 -0
- data/spec/unit/render/attributes/hash_attribute_spec.rb +17 -7
- data/spec/unit/render/definition_spec.rb +7 -25
- data/spec/unit/render/generator_spec.rb +102 -2
- data/spec/unit/render/graph_spec.rb +18 -19
- data/spec/unit/render/schema_spec.rb +185 -54
- data/spec/unit/render/type_spec.rb +88 -13
- metadata +66 -29
- checksums.yaml +0 -15
@@ -3,12 +3,16 @@ require "render/attributes/attribute"
|
|
3
3
|
|
4
4
|
module Render
|
5
5
|
class HashAttribute < Attribute
|
6
|
+
attr_accessor :required
|
7
|
+
|
6
8
|
def initialize(options = {})
|
7
9
|
super
|
8
10
|
|
9
11
|
self.name = options.keys.first
|
10
12
|
options = options[name]
|
11
|
-
|
13
|
+
|
14
|
+
process_options!(options)
|
15
|
+
self.required = !!options[:required]
|
12
16
|
|
13
17
|
initialize_schema!(options) if nested_schema?(options)
|
14
18
|
end
|
@@ -33,7 +37,7 @@ module Render
|
|
33
37
|
value = (explicit_value || default_value)
|
34
38
|
end
|
35
39
|
|
36
|
-
{ name.to_sym => value }
|
40
|
+
{ name.to_sym => Type.to(types, value) }
|
37
41
|
end
|
38
42
|
end
|
39
43
|
|
data/lib/render/definition.rb
CHANGED
@@ -9,21 +9,27 @@ module Render
|
|
9
9
|
Dir.glob("#{directory}/**/*.json").each do |definition_file|
|
10
10
|
Render.logger.info("Reading #{definition_file} definition")
|
11
11
|
definition_string = File.read(definition_file)
|
12
|
-
|
13
|
-
parsed_definition = Extensions::DottableHash.new(json_definition).recursively_symbolize_keys!
|
12
|
+
parsed_definition = JSON.parse(definition_string, { symbolize_names: true })
|
14
13
|
load!(parsed_definition)
|
15
14
|
end
|
16
15
|
end
|
17
16
|
|
18
17
|
def load!(definition)
|
19
|
-
|
20
|
-
self.instances[title] = definition
|
18
|
+
self.instances.merge!({ parse_id!(definition) => definition })
|
21
19
|
end
|
22
20
|
|
23
|
-
def find(
|
24
|
-
instances.fetch(
|
21
|
+
def find(id, raise_error = true)
|
22
|
+
instances.fetch(id)
|
25
23
|
rescue KeyError => error
|
26
|
-
raise Errors::
|
24
|
+
raise Errors::Definition::NotFound.new(id) if raise_error
|
25
|
+
end
|
26
|
+
|
27
|
+
def parse_id!(definition)
|
28
|
+
parse_id(definition) || (raise Errors::Definition::NoId.new(definition))
|
29
|
+
end
|
30
|
+
|
31
|
+
def parse_id(definition)
|
32
|
+
definition[:id]
|
27
33
|
end
|
28
34
|
|
29
35
|
end
|
data/lib/render/errors.rb
CHANGED
@@ -40,19 +40,46 @@ module Render
|
|
40
40
|
end
|
41
41
|
end
|
42
42
|
|
43
|
-
|
44
|
-
|
43
|
+
module Definition
|
44
|
+
class NoId < StandardError
|
45
|
+
attr_accessor :definition
|
45
46
|
|
46
|
-
|
47
|
-
|
47
|
+
def initialize(definition)
|
48
|
+
self.definition = definition
|
49
|
+
end
|
50
|
+
|
51
|
+
def to_s
|
52
|
+
"id keyword must be used to differentiate loaded schemas -- none found in: #{definition}"
|
53
|
+
end
|
48
54
|
end
|
49
55
|
|
50
|
-
|
51
|
-
|
56
|
+
class NotFound < StandardError
|
57
|
+
attr_accessor :title
|
58
|
+
|
59
|
+
def initialize(title)
|
60
|
+
self.title = title
|
61
|
+
end
|
62
|
+
|
63
|
+
def to_s
|
64
|
+
"Schema with title #{title} is not loaded"
|
65
|
+
end
|
52
66
|
end
|
53
67
|
end
|
54
68
|
|
55
69
|
class Schema
|
70
|
+
class InvalidRequire < StandardError
|
71
|
+
attr_accessor :schema_definition
|
72
|
+
|
73
|
+
def initialize(schema_definition)
|
74
|
+
self.schema_definition = schema_definition
|
75
|
+
end
|
76
|
+
|
77
|
+
def to_s
|
78
|
+
required_attributes = schema_definition.fetch(:required, [])
|
79
|
+
"Could not require the following attributes: #{required_attributes}. This should be an array of attributes for #{schema_definition}"
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
56
83
|
class RequestError < StandardError
|
57
84
|
attr_accessor :endpoint, :response
|
58
85
|
|
data/lib/render/generator.rb
CHANGED
@@ -3,11 +3,13 @@
|
|
3
3
|
|
4
4
|
require "uuid"
|
5
5
|
require "render/errors"
|
6
|
+
require "render/type"
|
6
7
|
require "date"
|
7
8
|
|
8
9
|
module Render
|
9
10
|
class Generator
|
10
11
|
@instances = []
|
12
|
+
FAUX_DATA_MAX = 1_000_000.freeze
|
11
13
|
|
12
14
|
class << self
|
13
15
|
attr_accessor :instances
|
@@ -25,12 +27,17 @@ module Render
|
|
25
27
|
|
26
28
|
def trigger(type, to_match, algorithm_argument = nil)
|
27
29
|
generator = find(type, to_match)
|
28
|
-
generator
|
30
|
+
if generator
|
31
|
+
generator.trigger(algorithm_argument)
|
32
|
+
else
|
33
|
+
Render.logger.warn("Could not find generator for type #{type} with matcher for #{to_match}, using nil")
|
34
|
+
nil
|
35
|
+
end
|
29
36
|
end
|
30
37
|
|
31
38
|
def find(type, to_match)
|
32
39
|
instances.detect do |generator|
|
33
|
-
generator.type
|
40
|
+
(type == generator.type) && to_match.to_s.match(generator.matcher)
|
34
41
|
end
|
35
42
|
end
|
36
43
|
end
|
@@ -57,14 +64,66 @@ module Render
|
|
57
64
|
end
|
58
65
|
end
|
59
66
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
67
|
+
|
68
|
+
def self.least_multiple(multiple_of, min)
|
69
|
+
lowest_multiple = multiple_of
|
70
|
+
until (lowest_multiple > min)
|
71
|
+
lowest_multiple += multiple_of
|
72
|
+
end
|
73
|
+
lowest_multiple
|
74
|
+
end
|
75
|
+
|
76
|
+
# Ensure each type can generate fake data.
|
77
|
+
# Standard JSON types
|
78
|
+
Generator.create!(String, /.*/, proc { |attribute|
|
79
|
+
min_length = attribute.min_length || -1
|
80
|
+
max_length = (attribute.max_length.to_i - 1)
|
81
|
+
"#{attribute.name} (generated)".ljust(min_length, "~")[0..max_length]
|
82
|
+
})
|
83
|
+
|
84
|
+
Generator.create!(Integer, /.*/, proc { |attribute|
|
85
|
+
min = attribute.minimum.to_i
|
86
|
+
max = attribute.maximum || FAUX_DATA_MAX
|
87
|
+
min += 1 if attribute.exclusive_minimum
|
88
|
+
max -= 1 if attribute.exclusive_maximum
|
89
|
+
|
90
|
+
if attribute.multiple_of
|
91
|
+
least_multiple(attribute.multiple_of, min)
|
92
|
+
else
|
93
|
+
rand(min..max)
|
94
|
+
end
|
95
|
+
})
|
96
|
+
|
97
|
+
# parsed from number
|
98
|
+
Generator.create!(Float, /.*/, proc { |attribute|
|
99
|
+
rounding_factor = 2
|
100
|
+
least_significant_number = 10 ** -rounding_factor
|
101
|
+
|
102
|
+
min = attribute.minimum.to_f
|
103
|
+
max = attribute.maximum || FAUX_DATA_MAX
|
104
|
+
min += least_significant_number if attribute.exclusive_minimum
|
105
|
+
max -= least_significant_number if attribute.exclusive_maximum
|
106
|
+
|
107
|
+
if attribute.multiple_of
|
108
|
+
least_multiple(attribute.multiple_of, min)
|
109
|
+
else
|
110
|
+
rand(min..max).round(rounding_factor)
|
111
|
+
end
|
112
|
+
})
|
113
|
+
|
66
114
|
Generator.create!(Type::Boolean, /.*/, proc { [true, false].sample })
|
115
|
+
Generator.create!(NilClass, /.*/, proc {}) # parsed from null
|
116
|
+
# Standard JSON formats
|
117
|
+
Generator.create!(DateTime, /.*/, proc { DateTime.now.to_s })
|
118
|
+
Generator.create!(URI, /.*/, proc { "http://localhost" })
|
119
|
+
Generator.create!(Type::Hostname, /.*/, proc { "localhost" })
|
120
|
+
Generator.create!(Type::Email, /.*/, proc { "you@localhost" })
|
121
|
+
Generator.create!(Type::IPv4, /.*/, proc { "127.0.0.1" })
|
122
|
+
Generator.create!(Type::IPv6, /.*/, proc { "::1" })
|
67
123
|
Generator.create!(Type::Enum, /.*/, proc { |attribute| attribute.enums.sample })
|
124
|
+
# Extended
|
125
|
+
Generator.create!(UUID, /.*/, proc { UUID.generate })
|
126
|
+
Generator.create!(Time, /.*/, proc { |attribute| time = Time.now; (attribute.type == String) ? time.to_s : time })
|
68
127
|
Generator.create!(Type::Date, /.*/, proc { Time.now.to_date })
|
69
128
|
end
|
70
129
|
end
|
data/lib/render/graph.rb
CHANGED
@@ -1,19 +1,18 @@
|
|
1
|
+
require "addressable/template"
|
2
|
+
|
1
3
|
require "render/schema"
|
2
4
|
require "render/errors"
|
3
5
|
require "render/extensions/dottable_hash"
|
4
6
|
|
5
7
|
module Render
|
6
8
|
class Graph
|
7
|
-
PARAM = %r{:(?<param>[\w_]+)}
|
8
|
-
PARAMS = %r{#{PARAM}[\/\;\&]?}
|
9
|
-
|
10
9
|
attr_accessor :schema,
|
11
10
|
:raw_endpoint,
|
12
11
|
:relationships,
|
13
12
|
:graphs,
|
14
|
-
:inherited_data,
|
15
13
|
:config,
|
16
|
-
:rendered_data
|
14
|
+
:rendered_data,
|
15
|
+
:relationship_info
|
17
16
|
|
18
17
|
def initialize(schema_or_definition, options = {})
|
19
18
|
self.schema = determine_schema(schema_or_definition)
|
@@ -21,60 +20,61 @@ module Render
|
|
21
20
|
self.graphs = (options.delete(:graphs) || [])
|
22
21
|
self.raw_endpoint = (options.delete(:endpoint) || schema.definition[:endpoint]).to_s
|
23
22
|
self.config = options
|
24
|
-
|
25
|
-
self.inherited_data = {}
|
23
|
+
self.relationship_info = {}
|
26
24
|
end
|
27
25
|
|
28
26
|
def title
|
29
|
-
schema.
|
27
|
+
schema.id || schema.title
|
30
28
|
end
|
31
29
|
|
32
|
-
def
|
33
|
-
|
30
|
+
def serialize!(explicit_data = nil, parental_data = nil)
|
31
|
+
process_relationship_info!(parental_data)
|
32
|
+
|
34
33
|
if (schema.type == Array)
|
35
|
-
explicit_data
|
34
|
+
schema.render!(explicit_data, endpoint)
|
36
35
|
else
|
37
|
-
explicit_data
|
38
|
-
explicit_data
|
36
|
+
explicit_data ||= {}
|
37
|
+
schema.render!(explicit_data.merge(relationship_info), endpoint)
|
39
38
|
end
|
39
|
+
end
|
40
40
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
if parent_data.is_a?(Array)
|
46
|
-
graph_data[graph.title] = parent_data.inject([]) do |nested_data, element|
|
47
|
-
nested_data << graph.render!(element)[graph.title]
|
48
|
-
end
|
49
|
-
else
|
50
|
-
nested_data = graph.render!(parent_data)
|
51
|
-
graph_data.merge!(nested_data)
|
52
|
-
end
|
41
|
+
def render!(explicit_data = nil, parental_data = nil, as_array = false)
|
42
|
+
if as_array
|
43
|
+
data = parental_data.inject([]) do |accumulator, parental_element|
|
44
|
+
accumulator << serialize!(explicit_data, parental_element)
|
53
45
|
end
|
46
|
+
else
|
47
|
+
data = serialize!(explicit_data, parental_data)
|
48
|
+
end
|
49
|
+
|
50
|
+
loop_with_configured_threading(graphs) do |graph|
|
51
|
+
graph.render!(explicit_data, data, (schema.type == Array))
|
54
52
|
end
|
55
53
|
|
56
|
-
self.rendered_data =
|
54
|
+
self.rendered_data = graphs.inject(Extensions::DottableHash.new) do |data, graph|
|
55
|
+
data[graph.title] = graph.rendered_data
|
56
|
+
end
|
57
|
+
self.rendered_data[title] = data
|
58
|
+
rendered_data
|
57
59
|
end
|
58
60
|
|
59
61
|
private
|
60
62
|
|
61
63
|
def endpoint
|
62
|
-
|
63
|
-
|
64
|
+
template = Addressable::Template.new(raw_endpoint)
|
65
|
+
variables = config.merge(relationship_info)
|
66
|
+
undefined_variables = (template.variables - variables.keys.collect(&:to_s))
|
67
|
+
raise Errors::Graph::EndpointKeyNotFound.new(undefined_variables) if (undefined_variables.size > 0)
|
68
|
+
template.expand(variables).to_s
|
69
|
+
end
|
64
70
|
|
65
|
-
|
66
|
-
|
67
|
-
param.gsub(PARAM, param_value(key).to_s)
|
68
|
-
end
|
71
|
+
def process_relationship_info!(data)
|
72
|
+
return if !data
|
69
73
|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
"#{key}=#{param_value(key)}&"
|
74
|
-
end.chop!
|
74
|
+
self.relationship_info = relationships.inject({}) do |info, (parent_key, child_key)|
|
75
|
+
value = data.is_a?(Hash) ? data.fetch(parent_key, nil) : data
|
76
|
+
info.merge!({ child_key => value })
|
75
77
|
end
|
76
|
-
|
77
|
-
uri.to_s
|
78
78
|
end
|
79
79
|
|
80
80
|
def loop_with_configured_threading(elements)
|
@@ -101,30 +101,5 @@ module Render
|
|
101
101
|
end
|
102
102
|
end
|
103
103
|
|
104
|
-
def relationship_data_from_parent
|
105
|
-
relationships.inject({}) do |data, (parent_key, child_key)|
|
106
|
-
data.merge({ child_key => value_from_inherited_data(child_key) })
|
107
|
-
end
|
108
|
-
end
|
109
|
-
|
110
|
-
def param_key(string)
|
111
|
-
string.match(PARAM)[:param].to_sym
|
112
|
-
end
|
113
|
-
|
114
|
-
def param_value(key)
|
115
|
-
value_from_inherited_data(key) || config[key] || raise(Errors::Graph::EndpointKeyNotFound.new(key))
|
116
|
-
end
|
117
|
-
|
118
|
-
def value_from_inherited_data(key)
|
119
|
-
relationships.each do |parent_key, child_key|
|
120
|
-
if !inherited_data.is_a?(Hash)
|
121
|
-
return inherited_data
|
122
|
-
elsif (child_key == key)
|
123
|
-
return inherited_data.fetch(parent_key, nil)
|
124
|
-
end
|
125
|
-
end
|
126
|
-
nil
|
127
|
-
end
|
128
|
-
|
129
104
|
end
|
130
105
|
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require "render"
|
2
|
+
|
3
|
+
module Render
|
4
|
+
module JSONSchema
|
5
|
+
Definition.load_from_directory!("lib/json/draft-04")
|
6
|
+
|
7
|
+
CORE = Schema.new("http://json-schema.org/draft-04/schema#")
|
8
|
+
HYPER = Schema.new("http://json-schema.org/draft-04/hyper-schema#")
|
9
|
+
PROPERTIES = [CORE.attributes.collect(&:name), HYPER.attributes.collect(&:name)].flatten.uniq
|
10
|
+
|
11
|
+
end
|
12
|
+
end
|
data/lib/render/schema.rb
CHANGED
@@ -8,44 +8,45 @@ require "render/extensions/dottable_hash"
|
|
8
8
|
module Render
|
9
9
|
class Schema
|
10
10
|
DEFAULT_TITLE = "untitled".freeze
|
11
|
+
CONTAINER_KEYWORDS = %w(items properties).freeze
|
12
|
+
ROOT_POINTER = "#".freeze
|
13
|
+
POINTER_SEPARATOR = %r{\/}.freeze
|
11
14
|
|
12
15
|
attr_accessor :title,
|
13
16
|
:type,
|
14
17
|
:definition,
|
15
18
|
:array_attribute,
|
16
19
|
:hash_attributes,
|
17
|
-
:
|
18
|
-
:raw_data,
|
19
|
-
:serialized_data,
|
20
|
-
:rendered_data
|
20
|
+
:id
|
21
21
|
|
22
22
|
def initialize(definition_or_title)
|
23
23
|
Render.logger.debug("Loading #{definition_or_title}")
|
24
24
|
|
25
|
-
|
26
|
-
|
27
|
-
|
25
|
+
process_definition!(definition_or_title)
|
26
|
+
interpolate_refs!(definition)
|
27
|
+
|
28
|
+
self.title = definition.fetch(:title, DEFAULT_TITLE)
|
29
|
+
self.id = Definition.parse_id(definition)
|
28
30
|
self.type = Type.parse(definition[:type]) || Object
|
29
|
-
self.universal_title = definition.fetch(:universal_title, nil)
|
30
31
|
|
31
|
-
if
|
32
|
+
if array_schema?
|
32
33
|
self.array_attribute = ArrayAttribute.new(definition)
|
33
34
|
else
|
34
35
|
self.hash_attributes = definition.fetch(:properties).collect do |name, attribute_definition|
|
35
36
|
HashAttribute.new({ name => attribute_definition })
|
36
37
|
end
|
38
|
+
require_attributes!
|
37
39
|
end
|
38
40
|
end
|
39
41
|
|
40
42
|
def serialize!(explicit_data = nil)
|
41
43
|
if (type == Array)
|
42
|
-
|
44
|
+
array_attribute.serialize(explicit_data)
|
43
45
|
else
|
44
|
-
|
45
|
-
|
46
|
+
explicit_data ||= {}
|
47
|
+
hash_attributes.inject({}) do |processed_explicit_data, attribute|
|
46
48
|
value = explicit_data.fetch(attribute.name, nil)
|
47
49
|
maintain_nil = explicit_data.has_key?(attribute.name)
|
48
|
-
|
49
50
|
serialized_attribute = attribute.serialize(value, maintain_nil)
|
50
51
|
processed_explicit_data.merge!(serialized_attribute)
|
51
52
|
end
|
@@ -53,27 +54,92 @@ module Render
|
|
53
54
|
end
|
54
55
|
|
55
56
|
def render!(explicit_data = nil, endpoint = nil)
|
56
|
-
|
57
|
-
serialize!(raw_data)
|
58
|
-
|
59
|
-
|
57
|
+
raw_data = Render.live ? request(endpoint) : explicit_data
|
58
|
+
data = serialize!(raw_data)
|
59
|
+
data.is_a?(Array) ? data : Extensions::DottableHash.new(data)
|
60
|
+
end
|
61
|
+
|
62
|
+
def attributes
|
63
|
+
array_schema? ? array_attribute : hash_attributes
|
60
64
|
end
|
61
65
|
|
62
66
|
private
|
63
67
|
|
64
|
-
def
|
65
|
-
|
66
|
-
|
68
|
+
def require_attributes!
|
69
|
+
definition.fetch(:required, []).each do |required_attribute|
|
70
|
+
attribute = attributes.detect { |attribute| attribute.name == required_attribute.to_sym }
|
71
|
+
attribute.required = true
|
72
|
+
end
|
73
|
+
rescue
|
74
|
+
raise Errors::Schema::InvalidRequire.new(definition)
|
75
|
+
end
|
76
|
+
|
77
|
+
def process_definition!(title_or_definition)
|
78
|
+
raw_definition = determine_definition(title_or_definition)
|
79
|
+
|
80
|
+
if container?(raw_definition)
|
81
|
+
self.definition = raw_definition
|
67
82
|
else
|
68
|
-
|
83
|
+
partitions = raw_definition.partition { |(key, value)| container?(value) }
|
84
|
+
subschemas, container = partitions.map { |partition| Hash[partition] }
|
85
|
+
container[:type] = Object
|
86
|
+
container[:properties] = subschemas
|
87
|
+
|
88
|
+
self.definition = container
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def interpolate_refs!(working_definition, current_scope = [])
|
93
|
+
return unless working_definition.is_a?(Hash)
|
94
|
+
|
95
|
+
working_definition.each do |(instance_name, instance_value)|
|
96
|
+
next unless instance_value.is_a?(Hash)
|
97
|
+
|
98
|
+
if instance_value.has_key?(:$ref)
|
99
|
+
ref = instance_value.fetch(:$ref)
|
100
|
+
ref_definition = Definition.find(ref, false) || find_local_schema(ref, current_scope)
|
101
|
+
instance_value.replace(ref_definition)
|
102
|
+
end
|
103
|
+
|
104
|
+
interpolate_refs!(instance_value, current_scope.dup << instance_name)
|
69
105
|
end
|
70
106
|
end
|
71
107
|
|
72
|
-
def
|
73
|
-
|
74
|
-
|
108
|
+
def find_local_schema(ref, scopes)
|
109
|
+
paths = ref.split(POINTER_SEPARATOR)
|
110
|
+
if (paths.first == ROOT_POINTER)
|
111
|
+
paths.shift
|
112
|
+
find_at_path(paths) || {}
|
75
113
|
else
|
76
|
-
|
114
|
+
find_at_closest_scope(paths, scopes) || {}
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def find_at_closest_scope(path, scopes)
|
119
|
+
return if scopes.empty?
|
120
|
+
find_at_path(scopes + path) || find_at_closest_scope(path, scopes[0...-1])
|
121
|
+
end
|
122
|
+
|
123
|
+
def find_at_path(paths)
|
124
|
+
paths.reduce(definition) do |reduction, path|
|
125
|
+
reduction[path.to_sym] || return
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def container?(definition)
|
130
|
+
return false unless definition.is_a?(Hash)
|
131
|
+
definition.any? { |(key, value)| CONTAINER_KEYWORDS.include?(key.to_s) }
|
132
|
+
end
|
133
|
+
|
134
|
+
def array_schema?
|
135
|
+
definition.keys.include?(:items)
|
136
|
+
end
|
137
|
+
|
138
|
+
def determine_definition(definition_or_title)
|
139
|
+
if (definition_or_title.is_a?(Hash) && !definition_or_title.empty?)
|
140
|
+
definition_or_title
|
141
|
+
else
|
142
|
+
Definition.find(definition_or_title)
|
77
143
|
end
|
78
144
|
end
|
79
145
|
|
@@ -84,12 +150,7 @@ module Render
|
|
84
150
|
def default_request(endpoint)
|
85
151
|
response = Net::HTTP.get_response(URI(endpoint))
|
86
152
|
if response.kind_of?(Net::HTTPSuccess)
|
87
|
-
|
88
|
-
if response.is_a?(Array)
|
89
|
-
Extensions::SymbolizableArray.new(response).recursively_symbolize_keys!
|
90
|
-
else
|
91
|
-
Extensions::DottableHash.new(response).recursively_symbolize_keys!
|
92
|
-
end
|
153
|
+
JSON.parse(response.body.to_s, { symbolize_names: true })
|
93
154
|
else
|
94
155
|
raise Errors::Schema::RequestError.new(endpoint, response)
|
95
156
|
end
|