openapi3_parser 0.8.2 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (34) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/ci.yml +23 -0
  3. data/.rubocop.yml +18 -1
  4. data/.ruby-version +1 -1
  5. data/CHANGELOG.md +6 -0
  6. data/README.md +3 -3
  7. data/lib/openapi3_parser/array_sentence.rb +1 -1
  8. data/lib/openapi3_parser/error.rb +11 -1
  9. data/lib/openapi3_parser/node/context.rb +1 -3
  10. data/lib/openapi3_parser/node/placeholder.rb +8 -7
  11. data/lib/openapi3_parser/node_factory/map.rb +6 -6
  12. data/lib/openapi3_parser/node_factory/object_factory/dsl.rb +6 -4
  13. data/lib/openapi3_parser/node_factory/object_factory/field_config.rb +8 -7
  14. data/lib/openapi3_parser/node_factory/object_factory/node_builder.rb +11 -13
  15. data/lib/openapi3_parser/node_factory/object_factory/validator.rb +19 -17
  16. data/lib/openapi3_parser/node_factory/operation.rb +1 -3
  17. data/lib/openapi3_parser/node_factory/parameter_like.rb +1 -1
  18. data/lib/openapi3_parser/node_factory/reference.rb +1 -1
  19. data/lib/openapi3_parser/node_factory/request_body.rb +2 -4
  20. data/lib/openapi3_parser/source/pointer.rb +4 -4
  21. data/lib/openapi3_parser/source_input.rb +8 -10
  22. data/lib/openapi3_parser/source_input/file.rb +1 -1
  23. data/lib/openapi3_parser/source_input/raw.rb +1 -1
  24. data/lib/openapi3_parser/source_input/url.rb +1 -1
  25. data/lib/openapi3_parser/validation/error_collection.rb +1 -1
  26. data/lib/openapi3_parser/validation/input_validator.rb +1 -1
  27. data/lib/openapi3_parser/validators/component_keys.rb +1 -1
  28. data/lib/openapi3_parser/validators/email.rb +2 -2
  29. data/lib/openapi3_parser/validators/mutually_exclusive_fields.rb +6 -6
  30. data/lib/openapi3_parser/validators/url.rb +2 -7
  31. data/lib/openapi3_parser/version.rb +1 -1
  32. data/openapi3_parser.gemspec +6 -4
  33. metadata +45 -17
  34. data/.travis.yml +0 -22
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 370efdcfee85cad9520504280a4d34bddb5580df
4
- data.tar.gz: b28c58e9f45cf1c710f04d4b107d9e57c1502efa
2
+ SHA256:
3
+ metadata.gz: 81001258de6af8c21c8a7db87520d9433e3acb878483a56a616fdcd804e92848
4
+ data.tar.gz: 496f3a02ebcb386e949eab7ec6607f360a0b2e755be6bb4f1df3cd6b260a6e0d
5
5
  SHA512:
6
- metadata.gz: 41442d7730efd30d1e0d24dc78727f344c4ed46d37830cb205c9507d23190d39e1b88e6bd2691500e72d2647407c11242f321f6115bb40d46c5cfc1b6431fe9d
7
- data.tar.gz: c70c7b03895bfa441b1433acece362f0792c8436785361ac6b568bbe16866fba863d559f3c376149a958c1d3e2cde4f66cd50c53125203578e9397c798d23932
6
+ metadata.gz: d789d4ffe423f8854f961e902ffa6ef56b86d7dbcf506292106afa8548b72f2fbe968d98358ea7c80771a3c2e974c302096d43968c0663bdad40dc5f60a676e2
7
+ data.tar.gz: aea92fa77fbb4808872093b9149f8eb933f70a38336a0e415fa1fc9d4c15e691b8307abb0d70c0e51eee8eca89887cbc1a16b21e70f2d1812ae0fd77b75fe2a3
@@ -0,0 +1,23 @@
1
+ on: [push, pull_request]
2
+ jobs:
3
+ test:
4
+ strategy:
5
+ matrix:
6
+ ruby: [2.5, 2.6, 2.7, 3.0]
7
+ runs-on: ubuntu-latest
8
+ steps:
9
+ - uses: actions/checkout@v2
10
+ - uses: ruby/setup-ruby@v1
11
+ with:
12
+ bundler-cache: true
13
+ ruby-version: ${{ matrix.ruby }}
14
+ - name: Test Ruby ${{ matrix.ruby }}
15
+ run: bundle exec rake
16
+ if: matrix.ruby != '2.5'
17
+ - name: Test and publish coverage for Ruby ${{ matrix.ruby }}
18
+ uses: paambaati/codeclimate-action@v2.7.5
19
+ env:
20
+ CC_TEST_REPORTER_ID: 8bc2d8e54331569aeb442094c21cb64a58d6efa0670f65ff00d9ae887f63c0b4
21
+ with:
22
+ coverageCommand: bundle exec rake
23
+ if: matrix.ruby == '2.5'
data/.rubocop.yml CHANGED
@@ -1,13 +1,30 @@
1
+ require:
2
+ - rubocop-rake
3
+ - rubocop-rspec
4
+ AllCops:
5
+ NewCops: enable
1
6
  Style/StringLiterals:
2
7
  EnforcedStyle: double_quotes
3
8
  Metrics/MethodLength:
4
9
  Max: 30
5
10
  Metrics/AbcSize:
6
11
  Max: 30
12
+ RSpec/ExampleLength:
13
+ Max: 30
7
14
  Style/Documentation:
8
15
  Enabled: false
9
16
  Metrics/BlockLength:
10
17
  Exclude:
11
18
  - 'spec/**/*.rb'
12
- Style/BracesAroundHashParameters:
19
+ - '*.gemspec'
20
+ RSpec/DescribeClass:
21
+ Exclude:
22
+ - 'spec/integration/**/*.rb'
23
+ # I'd rather have multiple expectations than lots of duplicate tests
24
+ RSpec/MultipleExpectations:
25
+ Enabled: false
26
+ # The default arbitrary number (5) is a little painful
27
+ RSpec/MultipleMemoizedHelpers:
28
+ Enabled: false
29
+ RSpec/MessageSpies:
13
30
  Enabled: false
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- 2.4.6
1
+ 2.5.8
data/CHANGELOG.md CHANGED
@@ -1,3 +1,9 @@
1
+ # 0.9.0
2
+
3
+ - Fix unexpected fields error when using Example nodes inside a Parameter -
4
+ https://github.com/kevindew/openapi3_parser/pull/19
5
+ - Drop support for Ruby 2.4
6
+
1
7
  # 0.8.2
2
8
 
3
9
  - Fix bug falling into recursive loop on Array/Map nodes -
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # OpenAPI 3 Parser
2
2
 
3
- [![Build Status](https://travis-ci.org/kevindew/openapi3_parser.svg?branch=master)](https://travis-ci.org/kevindew/openapi3_parser)
3
+ [![Build Status](https://travis-ci.org/kevindew/openapi3_parser.svg?branch=main)](https://travis-ci.org/kevindew/openapi3_parser)
4
4
 
5
5
  This a Ruby based parser/validator for [OpenAPI 3][openapi-3]. It is used to
6
6
  convert an OpenAPI file (can be a local file, a URL, a string or even a Ruby
@@ -47,7 +47,7 @@ parser in [How to write an OpenAPI 3 parser][blog].
47
47
 
48
48
  ```ruby
49
49
  # by URL
50
- Openapi3Parser.load_url("https://raw.githubusercontent.com/kevindew/openapi3_parser/master/spec/support/examples/petstore-expanded.yaml")
50
+ Openapi3Parser.load_url("https://raw.githubusercontent.com/kevindew/openapi3_parser/main/spec/support/examples/petstore-expanded.yaml")
51
51
 
52
52
  # by path to file
53
53
  Openapi3Parser.load_file("spec/support/examples/uber.yaml")
@@ -76,7 +76,7 @@ document.errors
76
76
  ### Traversing
77
77
 
78
78
  ```ruby
79
- document = Openapi3Parser.load_url("https://raw.githubusercontent.com/kevindew/openapi3_parser/master/spec/support/examples/petstore-expanded.yaml")
79
+ document = Openapi3Parser.load_url("https://raw.githubusercontent.com/kevindew/openapi3_parser/main/spec/support/examples/petstore-expanded.yaml")
80
80
 
81
81
  # by objects
82
82
 
@@ -6,7 +6,7 @@ module Openapi3Parser
6
6
  def sentence_join
7
7
  return join if count < 2
8
8
 
9
- self[0..-2].join(", ") + " and " + self[-1]
9
+ "#{self[0..-2].join(', ')} and #{self[-1]}"
10
10
  end
11
11
  end
12
12
  end
@@ -7,32 +7,42 @@ module Openapi3Parser
7
7
  # at runtime when we have tried to access that resource it is not available
8
8
  # for whatever reason.
9
9
  class InaccessibleInput < Error; end
10
+
10
11
  # Raised in cases where we provided data that we expected to be parsable
11
12
  # (such as a string of JSON data) but when we tried to parse it an error
12
13
  # is raised
13
14
  class UnparsableInput < Error; end
15
+
14
16
  # Raised in cases where an object that is in an immutable state is modified
15
17
  #
16
18
  # Typically this would occur when a component that is frozen is modififed.
17
19
  # Some components are mutable during the construction of a document and
18
20
  # then frozen afterwards.
19
21
  class ImmutableObject < Error; end
20
- # Raised when a type that is not a whitelist of valid types is used
22
+
23
+ # Raised when a node is provided data as a type that is outside the allowed
24
+ # list
21
25
  class InvalidType < Error; end
26
+
22
27
  # Raised when we have to abort creating an object due to invalid data
23
28
  class InvalidData < Error; end
29
+
24
30
  # Used when there are fields that are missing from an object which prevents
25
31
  # us from creating a node
26
32
  class MissingFields < Error; end
33
+
27
34
  # Used when there are extra fields that are not expected in the data for
28
35
  # a node
29
36
  class UnexpectedFields < Error; end
37
+
30
38
  # Used when a method we expect to be able to call (through symbol or proc)
31
39
  # is not callable
32
40
  class NotCallable < Error; end
41
+
33
42
  # Raised when we in a recursive data structure and can't perform an
34
43
  # operation
35
44
  class InRecursiveStructure < Error; end
45
+
36
46
  # Used when we're trying to validate that a type is something that is not
37
47
  # validatable, most likely a sign that we're in a bug
38
48
  class UnvalidatableType < Error; end
@@ -107,9 +107,7 @@ module Openapi3Parser
107
107
  def location_summary
108
108
  summary = document_location.to_s
109
109
 
110
- if document_location != source_location
111
- summary += " (#{source_location})"
112
- end
110
+ summary += " (#{source_location})" if document_location != source_location
113
111
 
114
112
  summary
115
113
  end
@@ -21,8 +21,8 @@ module Openapi3Parser
21
21
  def self.each(node_data, &block)
22
22
  resolved =
23
23
  if node_data.respond_to?(:keys)
24
- node_data.each_with_object({}) do |(key, value), memo|
25
- memo[key] = resolve(value)
24
+ node_data.transform_values do |value|
25
+ resolve(value)
26
26
  end
27
27
  else
28
28
  node_data.map { |item| resolve(item) }
@@ -32,6 +32,7 @@ module Openapi3Parser
32
32
  end
33
33
 
34
34
  attr_reader :node_factory, :field, :parent_context
35
+
35
36
  def_delegators :node_factory, :nil_input?
36
37
 
37
38
  def initialize(node_factory, field, parent_context)
@@ -42,11 +43,11 @@ module Openapi3Parser
42
43
 
43
44
  def node
44
45
  @node ||= begin
45
- node_context = Context.next_field(parent_context,
46
- field,
47
- node_factory.context)
48
- node_factory.node(node_context)
49
- end
46
+ node_context = Context.next_field(parent_context,
47
+ field,
48
+ node_factory.context)
49
+ node_factory.node(node_context)
50
+ end
50
51
  end
51
52
  end
52
53
  end
@@ -90,12 +90,12 @@ module Openapi3Parser
90
90
  def build_resolved_input
91
91
  return unless data
92
92
 
93
- data.each_with_object({}) do |(key, value), memo|
94
- memo[key] = if value.respond_to?(:resolved_input)
95
- value.resolved_input
96
- else
97
- value
98
- end
93
+ data.transform_values do |value|
94
+ if value.respond_to?(:resolved_input)
95
+ value.resolved_input
96
+ else
97
+ value
98
+ end
99
99
  end
100
100
  end
101
101
 
@@ -1,12 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "ostruct"
4
3
  require "openapi3_parser/node_factory/object_factory/field_config"
5
4
 
6
5
  module Openapi3Parser
7
6
  module NodeFactory
8
7
  module ObjectFactory
9
8
  module Dsl
9
+ MutuallyExclusiveField = Struct.new(:fields, :required, keyword_init: true)
10
+
10
11
  def field(name, **options)
11
12
  @field_configs ||= {}
12
13
  @field_configs[name] = FieldConfig.new(**options)
@@ -30,8 +31,9 @@ module Openapi3Parser
30
31
 
31
32
  def mutually_exclusive(*fields, required: false)
32
33
  @mutually_exclusive_fields ||= []
33
- @mutually_exclusive_fields << OpenStruct.new(
34
- fields: fields, required: required
34
+ @mutually_exclusive_fields << MutuallyExclusiveField.new(
35
+ fields: fields,
36
+ required: required
35
37
  )
36
38
  end
37
39
 
@@ -41,7 +43,7 @@ module Openapi3Parser
41
43
 
42
44
  def validate(*items, &block)
43
45
  @validations ||= []
44
- @validations = @validations.concat(items)
46
+ @validations.concat(items)
45
47
  @validations << block if block
46
48
  end
47
49
 
@@ -22,10 +22,11 @@ module Openapi3Parser
22
22
  !given_factory.nil?
23
23
  end
24
24
 
25
- def initialize_factory(context, parent_factory)
26
- if given_factory.is_a?(Class)
25
+ def initialize_factory(context, parent_factory = nil)
26
+ case given_factory
27
+ when Class
27
28
  given_factory.new(context)
28
- elsif given_factory.is_a?(Symbol)
29
+ when Symbol
29
30
  parent_factory.send(given_factory, context)
30
31
  else
31
32
  given_factory.call(context)
@@ -36,7 +37,7 @@ module Openapi3Parser
36
37
  given_required
37
38
  end
38
39
 
39
- def check_input_type(validatable, building_node)
40
+ def check_input_type(validatable, building_node: false)
40
41
  return true if !given_input_type || validatable.input.nil?
41
42
 
42
43
  if building_node
@@ -47,7 +48,7 @@ module Openapi3Parser
47
48
  end
48
49
  end
49
50
 
50
- def validate_field(validatable, building_node)
51
+ def validate_field(validatable, building_node: false)
51
52
  return true if !given_validate || validatable.input.nil?
52
53
 
53
54
  run_validation(validatable)
@@ -61,9 +62,9 @@ module Openapi3Parser
61
62
  "Invalid data for #{location_summary}: #{error.message}"
62
63
  end
63
64
 
64
- def default(factory)
65
+ def default(factory = nil)
65
66
  return given_default.call if given_default.is_a?(Proc)
66
- return factory.send(given_default) if given_default.is_a?(Symbol)
67
+ return factory&.send(given_default) if given_default.is_a?(Symbol)
67
68
 
68
69
  given_default
69
70
  end
@@ -8,8 +8,8 @@ module Openapi3Parser
8
8
  new(factory).errors
9
9
  end
10
10
 
11
- def self.node_data(factory, parent_context)
12
- new(factory).node_data(parent_context)
11
+ def self.node_data(factory, node_context)
12
+ new(factory).node_data(node_context)
13
13
  end
14
14
 
15
15
  def initialize(factory)
@@ -22,19 +22,17 @@ module Openapi3Parser
22
22
 
23
23
  TypeChecker.validate_type(validatable, type: ::Hash)
24
24
 
25
- if validatable.errors.empty?
26
- validatable.add_errors(validate(raise_on_invalid: false))
27
- end
25
+ validatable.add_errors(validate(raise_on_invalid: false)) if validatable.errors.empty?
28
26
 
29
27
  validatable.collection
30
28
  end
31
29
 
32
- def node_data(parent_context)
33
- return build_node_data(parent_context) if empty_and_allowed_to_be?
30
+ def node_data(node_context)
31
+ return build_node_data(node_context) if empty_and_allowed_to_be?
34
32
 
35
33
  TypeChecker.raise_on_invalid_type(factory.context, type: ::Hash)
36
34
  validate(raise_on_invalid: true)
37
- build_node_data(parent_context)
35
+ build_node_data(node_context)
38
36
  end
39
37
 
40
38
  private_class_method :new
@@ -48,22 +46,22 @@ module Openapi3Parser
48
46
  end
49
47
 
50
48
  def validate(raise_on_invalid:)
51
- Validator.call(factory, raise_on_invalid)
49
+ Validator.call(factory, raise_on_invalid: raise_on_invalid)
52
50
  end
53
51
 
54
- def build_node_data(parent_context)
52
+ def build_node_data(node_context)
55
53
  return if factory.nil_input? && factory.data.nil?
56
54
 
57
55
  factory.data.each_with_object({}) do |(key, value), memo|
58
- memo[key] = resolve_value(key, value, parent_context)
56
+ memo[key] = resolve_value(key, value, node_context)
59
57
  end
60
58
  end
61
59
 
62
- def resolve_value(key, value, parent_context)
60
+ def resolve_value(key, value, node_context)
63
61
  resolved = determine_value_or_default(key, value)
64
62
 
65
63
  if resolved.respond_to?(:node)
66
- Node::Placeholder.new(value, key, parent_context)
64
+ Node::Placeholder.new(value, key, node_context)
67
65
  else
68
66
  resolved
69
67
  end
@@ -7,15 +7,15 @@ module Openapi3Parser
7
7
  module ObjectFactory
8
8
  class Validator
9
9
  private_class_method :new
10
- attr_reader :factory, :validatable, :building_node
10
+ attr_reader :factory, :validatable, :raise_on_invalid
11
11
 
12
- def self.call(*args)
13
- new(*args).call
12
+ def self.call(*args, **kwargs)
13
+ new(*args, **kwargs).call
14
14
  end
15
15
 
16
- def initialize(factory, building_node)
16
+ def initialize(factory, raise_on_invalid: false)
17
17
  @factory = factory
18
- @building_node = building_node
18
+ @raise_on_invalid = raise_on_invalid
19
19
  @validatable = Validation::Validatable.new(factory)
20
20
  end
21
21
 
@@ -34,7 +34,7 @@ module Openapi3Parser
34
34
  Validators::RequiredFields.call(
35
35
  validatable,
36
36
  required_fields: factory.required_fields,
37
- raise_on_invalid: building_node
37
+ raise_on_invalid: raise_on_invalid
38
38
  )
39
39
  end
40
40
 
@@ -43,7 +43,7 @@ module Openapi3Parser
43
43
  validatable,
44
44
  allow_extensions: factory.allowed_extensions?,
45
45
  allowed_fields: factory.allowed_fields,
46
- raise_on_invalid: building_node
46
+ raise_on_invalid: raise_on_invalid
47
47
  )
48
48
  end
49
49
 
@@ -51,7 +51,7 @@ module Openapi3Parser
51
51
  Validators::MutuallyExclusiveFields.call(
52
52
  validatable,
53
53
  mutually_exclusive_fields: factory.mutually_exclusive_fields,
54
- raise_on_invalid: building_node
54
+ raise_on_invalid: raise_on_invalid
55
55
  )
56
56
  end
57
57
 
@@ -66,7 +66,8 @@ module Openapi3Parser
66
66
  class CheckInvalidFields
67
67
  extend Forwardable
68
68
  attr_reader :validator
69
- def_delegators :validator, :factory, :building_node, :validatable
69
+
70
+ def_delegators :validator, :factory, :raise_on_invalid, :validatable
70
71
  private_class_method :new
71
72
 
72
73
  def self.call(validator)
@@ -88,16 +89,14 @@ module Openapi3Parser
88
89
 
89
90
  # We don't add errors when we're building a node as they will
90
91
  # be raised when that child node is built
91
- validatable.add_errors(field.errors) unless building_node
92
+ validatable.add_errors(field.errors) unless raise_on_invalid
92
93
  end
93
94
  end
94
95
 
95
96
  private
96
97
 
97
98
  def handle_factory_checks(name)
98
- field_errors = if factory.field_configs[name]
99
- check_field(name, factory.field_configs[name])
100
- end
99
+ field_errors = (check_field(name, factory.field_configs[name]) if factory.field_configs[name])
101
100
 
102
101
  (field_errors || []).any?
103
102
  end
@@ -115,11 +114,14 @@ module Openapi3Parser
115
114
  field_validatable = Validation::Validatable.new(factory,
116
115
  context: context)
117
116
 
118
- valid_input_type = field_config.check_input_type(field_validatable,
119
- building_node)
117
+ valid_input_type = field_config.check_input_type(
118
+ field_validatable,
119
+ building_node: raise_on_invalid
120
+ )
120
121
 
121
122
  if valid_input_type
122
- field_config.validate_field(field_validatable, building_node)
123
+ field_config.validate_field(field_validatable,
124
+ building_node: raise_on_invalid)
123
125
  end
124
126
 
125
127
  validatable.add_errors(field_validatable.errors)
@@ -139,7 +141,7 @@ module Openapi3Parser
139
141
 
140
142
  errors = validator.validatable.errors
141
143
 
142
- return if errors.empty? || !validator.building_node
144
+ return if errors.empty? || !validator.raise_on_invalid
143
145
 
144
146
  location_summary = errors.first.context.location_summary
145
147
  raise Error::InvalidData,
@@ -25,9 +25,7 @@ module Openapi3Parser
25
25
  private
26
26
 
27
27
  def build_object(data, context)
28
- if data["servers"].node.empty?
29
- data["servers"] = path_item_server_data(context)
30
- end
28
+ data["servers"] = path_item_server_data(context) if data["servers"].node.empty?
31
29
 
32
30
  Node::Operation.new(data, context)
33
31
  end
@@ -13,7 +13,7 @@ module Openapi3Parser
13
13
  end
14
14
 
15
15
  def examples_factory(context)
16
- factory = NodeFactory::OptionalReference.new(NodeFactory::Schema)
16
+ factory = NodeFactory::OptionalReference.new(NodeFactory::Example)
17
17
  NodeFactory::Map.new(context,
18
18
  default: nil,
19
19
  value_factory: factory)
@@ -44,7 +44,7 @@ module Openapi3Parser
44
44
 
45
45
  def build_node(node_context)
46
46
  TypeChecker.raise_on_invalid_type(context, type: ::Hash)
47
- ObjectFactory::Validator.call(self, true)
47
+ ObjectFactory::Validator.call(self, raise_on_invalid: true)
48
48
  data["$ref"].node(node_context)
49
49
  end
50
50
 
@@ -32,11 +32,9 @@ module Openapi3Parser
32
32
  def call(validatable)
33
33
  # This validation isn't actually mentioned in the spec, but it
34
34
  # doesn't seem to make sense if this is an empty hash.
35
- if validatable.input.size.zero?
36
- return validatable.add_error("Expected to have at least 1 item")
37
- end
35
+ return validatable.add_error("Expected to have at least 1 item") if validatable.input.size.zero?
38
36
 
39
- validatable.input.keys.each do |key|
37
+ validatable.input.each_key do |key|
40
38
  message = Validators::MediaType.call(key)
41
39
  next unless message
42
40
 
@@ -16,7 +16,7 @@ module Openapi3Parser
16
16
  unescaped = CGI.unescape(part.gsub("%20", "+"))
17
17
  unescaped.match?(/\A\d+\z/) ? unescaped.to_i : unescaped
18
18
  end
19
- new(segments.compact, absolute)
19
+ new(segments.compact, absolute: absolute)
20
20
  end
21
21
 
22
22
  def self.merge_pointers(base_pointer, new_pointer)
@@ -27,7 +27,7 @@ module Openapi3Parser
27
27
 
28
28
  # @param [::Array] segments
29
29
  # @param [Boolean] absolute
30
- def initialize(segments, absolute = true)
30
+ def initialize(segments, absolute: true)
31
31
  @segments = segments.freeze
32
32
  @absolute = absolute
33
33
  end
@@ -39,7 +39,7 @@ module Openapi3Parser
39
39
  def fragment
40
40
  fragment = segments.map { |s| CGI.escape(s.to_s).gsub("+", "%20") }
41
41
  .join("/")
42
- "#" + (absolute ? fragment.prepend("/") : fragment)
42
+ "##{absolute ? fragment.prepend('/') : fragment}"
43
43
  end
44
44
 
45
45
  def to_s
@@ -80,7 +80,7 @@ module Openapi3Parser
80
80
  def create_pointer(pointer_like)
81
81
  case pointer_like
82
82
  when Pointer then pointer_like
83
- when ::Array then Pointer.new(pointer_like, false)
83
+ when ::Array then Pointer.new(pointer_like, absolute: false)
84
84
  when ::String then Pointer.from_fragment(pointer_like)
85
85
  when nil then nil
86
86
  else raise Openapi3Parser::Error, "Unexpected type for pointer"
@@ -20,6 +20,14 @@ module Openapi3Parser
20
20
  class SourceInput
21
21
  attr_reader :access_error, :parse_error
22
22
 
23
+ def initialize
24
+ return if access_error
25
+
26
+ @contents = parse_contents
27
+ rescue ::StandardError => e
28
+ @parse_error = Error::UnparsableInput.new(e.message)
29
+ end
30
+
23
31
  # Indicates that the data within this input is suitable (i.e. can parse
24
32
  # underlying JSON or YAML) for trying to use as part of a Document
25
33
  def available?
@@ -57,15 +65,5 @@ module Openapi3Parser
57
65
  def relative_to(_source_input)
58
66
  ""
59
67
  end
60
-
61
- private
62
-
63
- def initialize_contents
64
- return if access_error
65
-
66
- @contents = parse_contents
67
- rescue ::StandardError => e
68
- @parse_error = Error::UnparsableInput.new(e.message)
69
- end
70
68
  end
71
69
  end
@@ -24,7 +24,7 @@ module Openapi3Parser
24
24
  @path = ::File.absolute_path(path)
25
25
  working_directory ||= resolve_working_directory
26
26
  @working_directory = ::File.absolute_path(working_directory)
27
- initialize_contents
27
+ super()
28
28
  end
29
29
 
30
30
  # @see SourceInput#resolve_next
@@ -26,7 +26,7 @@ module Openapi3Parser
26
26
  @base_url = base_url
27
27
  working_directory ||= resolve_working_directory
28
28
  @working_directory = ::File.absolute_path(working_directory)
29
- initialize_contents
29
+ super()
30
30
  end
31
31
 
32
32
  # @see SourceInput#resolve_next
@@ -17,7 +17,7 @@ module Openapi3Parser
17
17
  # @param [String, URI] request_url
18
18
  def initialize(request_url)
19
19
  @request_url = request_url.to_s
20
- initialize_contents
20
+ super()
21
21
  end
22
22
 
23
23
  # @see SourceInput#resolve_next
@@ -56,7 +56,7 @@ module Openapi3Parser
56
56
  grouped.each_with_object({}) do |(_, items), memo|
57
57
  items.each do |item|
58
58
  key = item.location_summary(with_type: items.count > 1)
59
- memo[key] = (memo[key] || []) + item.errors.map(&:to_s)
59
+ memo[key] = memo.fetch(key, []) + item.errors.map(&:to_s)
60
60
  end
61
61
  end
62
62
  end
@@ -10,7 +10,7 @@ module Openapi3Parser
10
10
  end
11
11
 
12
12
  def call(validatable)
13
- error = @callable.call(validatable.input)
13
+ error = callable.call(validatable.input)
14
14
  validatable.add_error(error) if error
15
15
  end
16
16
  end
@@ -6,7 +6,7 @@ module Openapi3Parser
6
6
  # defined for a Components node.
7
7
  # As defined: https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#components-object
8
8
  class ComponentKeys
9
- REGEX = /\A[a-zA-Z0-9\.\-_]+\Z/.freeze
9
+ REGEX = /\A[a-zA-Z0-9.\-_]+\Z/.freeze
10
10
 
11
11
  def self.call(input)
12
12
  invalid = input.keys.reject { |key| REGEX.match(key) }
@@ -7,10 +7,10 @@ module Openapi3Parser
7
7
  # https://html.spec.whatwg.org/#e-mail-state-(type=email)
8
8
  REGEX = %r{
9
9
  \A
10
- [a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+
10
+ [a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+
11
11
  @
12
12
  [a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?
13
- (?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*
13
+ (?:.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*
14
14
  \Z
15
15
  }x.freeze
16
16
 
@@ -78,12 +78,12 @@ module Openapi3Parser
78
78
 
79
79
  def errors
80
80
  @errors ||= begin
81
- default = { required: [], exclusive: [] }
82
- mutually_exclusive_fields
83
- .each_with_object(default) do |exclusive, errors|
84
- add_error(errors, exclusive)
85
- end
86
- end
81
+ default = { required: [], exclusive: [] }
82
+ mutually_exclusive_fields
83
+ .each_with_object(default) do |exclusive, errors|
84
+ add_error(errors, exclusive)
85
+ end
86
+ end
87
87
  end
88
88
 
89
89
  private
@@ -4,14 +4,9 @@ module Openapi3Parser
4
4
  module Validators
5
5
  class Url
6
6
  def self.call(input)
7
- message = %("#{input}" is not a valid URL)
8
- uri = URI.parse(input)
9
-
10
- message if !uri.relative? &&
11
- !uri.is_a?(URI::HTTP) &&
12
- !uri.is_a?(URI::HTTPS)
7
+ URI.parse(input) && nil
13
8
  rescue URI::InvalidURIError
14
- message
9
+ %("#{input}" is not a valid URL)
15
10
  end
16
11
  end
17
12
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Openapi3Parser
4
- VERSION = "0.8.2"
4
+ VERSION = "0.9.0"
5
5
  end
@@ -24,16 +24,18 @@ Gem::Specification.new do |spec|
24
24
  f.match(%r{^spec/})
25
25
  end
26
26
 
27
- spec.required_ruby_version = ">= 2.4.0"
27
+ spec.required_ruby_version = ">= 2.5.0"
28
28
 
29
29
  spec.add_dependency "commonmarker", "~> 0.17"
30
30
  spec.add_dependency "psych", "~> 3.1"
31
31
 
32
32
  spec.add_development_dependency "bundler"
33
33
  spec.add_development_dependency "byebug", "~> 11.0"
34
- spec.add_development_dependency "rake", "~> 13.0"
34
+ spec.add_development_dependency "rake"
35
35
  spec.add_development_dependency "rspec", "~> 3.9"
36
- spec.add_development_dependency "rubocop", "~> 0.79.0"
37
- spec.add_development_dependency "simplecov", "~> 0.17"
36
+ spec.add_development_dependency "rubocop", "~> 1"
37
+ spec.add_development_dependency "rubocop-rake", "~> 0.5"
38
+ spec.add_development_dependency "rubocop-rspec", "~> 2"
39
+ spec.add_development_dependency "simplecov", "~> 0.19"
38
40
  spec.add_development_dependency "webmock", "~> 3.8"
39
41
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: openapi3_parser
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.2
4
+ version: 0.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kevin Dew
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-06-13 00:00:00.000000000 Z
11
+ date: 2021-02-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: commonmarker
@@ -70,16 +70,16 @@ dependencies:
70
70
  name: rake
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - "~>"
73
+ - - ">="
74
74
  - !ruby/object:Gem::Version
75
- version: '13.0'
75
+ version: '0'
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
- - - "~>"
80
+ - - ">="
81
81
  - !ruby/object:Gem::Version
82
- version: '13.0'
82
+ version: '0'
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: rspec
85
85
  requirement: !ruby/object:Gem::Requirement
@@ -100,28 +100,56 @@ dependencies:
100
100
  requirements:
101
101
  - - "~>"
102
102
  - !ruby/object:Gem::Version
103
- version: 0.79.0
103
+ version: '1'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '1'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rubocop-rake
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '0.5'
104
118
  type: :development
105
119
  prerelease: false
106
120
  version_requirements: !ruby/object:Gem::Requirement
107
121
  requirements:
108
122
  - - "~>"
109
123
  - !ruby/object:Gem::Version
110
- version: 0.79.0
124
+ version: '0.5'
125
+ - !ruby/object:Gem::Dependency
126
+ name: rubocop-rspec
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: '2'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: '2'
111
139
  - !ruby/object:Gem::Dependency
112
140
  name: simplecov
113
141
  requirement: !ruby/object:Gem::Requirement
114
142
  requirements:
115
143
  - - "~>"
116
144
  - !ruby/object:Gem::Version
117
- version: '0.17'
145
+ version: '0.19'
118
146
  type: :development
119
147
  prerelease: false
120
148
  version_requirements: !ruby/object:Gem::Requirement
121
149
  requirements:
122
150
  - - "~>"
123
151
  - !ruby/object:Gem::Version
124
- version: '0.17'
152
+ version: '0.19'
125
153
  - !ruby/object:Gem::Dependency
126
154
  name: webmock
127
155
  requirement: !ruby/object:Gem::Requirement
@@ -145,11 +173,11 @@ executables: []
145
173
  extensions: []
146
174
  extra_rdoc_files: []
147
175
  files:
176
+ - ".github/workflows/ci.yml"
148
177
  - ".gitignore"
149
178
  - ".rspec"
150
179
  - ".rubocop.yml"
151
180
  - ".ruby-version"
152
- - ".travis.yml"
153
181
  - CHANGELOG.md
154
182
  - Gemfile
155
183
  - LICENCE
@@ -273,7 +301,7 @@ homepage: https://github.com/kevindew/openapi_parser
273
301
  licenses:
274
302
  - MIT
275
303
  metadata: {}
276
- post_install_message:
304
+ post_install_message:
277
305
  rdoc_options: []
278
306
  require_paths:
279
307
  - lib
@@ -281,16 +309,16 @@ required_ruby_version: !ruby/object:Gem::Requirement
281
309
  requirements:
282
310
  - - ">="
283
311
  - !ruby/object:Gem::Version
284
- version: 2.4.0
312
+ version: 2.5.0
285
313
  required_rubygems_version: !ruby/object:Gem::Requirement
286
314
  requirements:
287
315
  - - ">="
288
316
  - !ruby/object:Gem::Version
289
317
  version: '0'
290
318
  requirements: []
291
- rubyforge_project:
292
- rubygems_version: 2.6.14.4
293
- signing_key:
319
+ rubyforge_project:
320
+ rubygems_version: 2.7.6.2
321
+ signing_key:
294
322
  specification_version: 4
295
323
  summary: An OpenAPI V3 parser for Ruby
296
324
  test_files: []
data/.travis.yml DELETED
@@ -1,22 +0,0 @@
1
- language: ruby
2
- sudo: false
3
- env:
4
- global:
5
- CC_TEST_REPORTER_ID=8bc2d8e54331569aeb442094c21cb64a58d6efa0670f65ff00d9ae887f63c0b4
6
- CC_RUBY_VERSION=ruby-2.4.6
7
- rvm:
8
- - 2.4.6
9
- - 2.5.5
10
- - 2.6.4
11
- - 2.7.0
12
- - ruby-head
13
- matrix:
14
- allow_failures:
15
- - rvm: ruby-head
16
- fast_finish: true
17
- before_script:
18
- - curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
19
- - chmod +x ./cc-test-reporter
20
- - if [ $(rvm current) = $CC_RUBY_VERSION ]; then ./cc-test-reporter before-build; fi
21
- after_script:
22
- - if [ $(rvm current) = $CC_RUBY_VERSION ]; then ./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT; fi