interpol 0.9.0 → 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile CHANGED
@@ -13,8 +13,6 @@ gem 'compass_twitter_bootstrap', :git => 'git://github.com/vwall/compass-twitter
13
13
 
14
14
  gem 'json', :platform => 'ruby_18'
15
15
 
16
- gem 'sinatra', '>= 1.3.2', '< 2.0.0'
17
-
18
16
  gem 'cane', '~> 2.0', :platform => 'ruby_19'
19
17
 
20
18
  gem 'rspec-fire', :git => 'git://github.com/xaviershay/rspec-fire.git'
@@ -1,7 +1,7 @@
1
+ require 'interpol'
1
2
  require 'interpol/endpoint'
2
3
  require 'interpol/errors'
3
4
  require 'yaml'
4
- require 'interpol/configuration_ruby_18_extensions' if RUBY_VERSION.to_f < 1.9
5
5
  require 'uri'
6
6
 
7
7
  module Interpol
@@ -33,8 +33,9 @@ module Interpol
33
33
 
34
34
  # Public: Defines interpol configuration.
35
35
  class Configuration
36
- attr_reader :endpoint_definition_files, :endpoints, :filter_example_data_blocks
37
- attr_accessor :validation_mode, :documentation_title, :endpoint_definition_merge_key_files
36
+ attr_reader :endpoint_definition_files, :endpoints, :filter_example_data_blocks,
37
+ :endpoint_definition_merge_key_files
38
+ attr_accessor :validation_mode, :documentation_title
38
39
 
39
40
  def initialize
40
41
  self.endpoint_definition_files = []
@@ -48,16 +49,25 @@ module Interpol
48
49
  end
49
50
 
50
51
  def endpoint_definition_files=(files)
51
- self.endpoints = files.map do |file|
52
- Endpoint.new(deserialized_hash_from file)
53
- end
52
+ @endpoints = nil
54
53
  @endpoint_definition_files = files
55
54
  end
56
55
 
56
+ def endpoint_definition_merge_key_files=(files)
57
+ @endpoints = nil
58
+ @endpoint_definition_merge_key_files = files
59
+ end
60
+
57
61
  def endpoints=(endpoints)
58
62
  @endpoints = endpoints.extend(DefinitionFinder)
59
63
  end
60
64
 
65
+ def endpoints
66
+ @endpoints ||= @endpoint_definition_files.map do |file|
67
+ Endpoint.new(deserialized_hash_from(file), self)
68
+ end.extend(DefinitionFinder)
69
+ end
70
+
61
71
  [:request, :response].each do |type|
62
72
  class_eval <<-EOEVAL, __FILE__, __LINE__ + 1
63
73
  def #{type}_version(version = nil, &block)
@@ -156,6 +166,15 @@ module Interpol
156
166
  selector.call(endpoint_def, env)
157
167
  end
158
168
 
169
+ def scalars_nullable_by_default=(value)
170
+ @endpoints = nil
171
+ @scalars_nullable_by_default = value
172
+ end
173
+
174
+ def scalars_nullable_by_default?
175
+ @scalars_nullable_by_default
176
+ end
177
+
159
178
  def self.default
160
179
  @default ||= Configuration.new
161
180
  end
@@ -183,24 +202,9 @@ module Interpol
183
202
  end
184
203
 
185
204
  private
186
-
187
- # 1.9 version
188
- include Module.new {
189
- BAD_ALIAS_ERROR = defined?(::Psych::BadAlias) ?
190
- ::Psych::BadAlias : TypeError
191
- def deserialized_hash_from(file)
192
- YAML.load(yaml_content_for file)
193
- rescue BAD_ALIAS_ERROR => e
194
- raise ConfigurationError.new \
195
- "Received an error while loading YAML from #{file}: \"" +
196
- "#{e.class}: #{e.message}\" If you are using YAML merge keys " +
197
- "to declare shared types, you must configure endpoint_definition_merge_key_files " +
198
- "before endpoint_definition_files.", e
199
- end
200
- }
201
-
202
- # Needed to override deserialized_hash_from for Ruby 1.8
203
- include Interpol::ConfigurationRuby18Extensions if RUBY_VERSION.to_f < 1.9
205
+ def deserialized_hash_from(file)
206
+ YAML.load(yaml_content_for file)
207
+ end
204
208
 
205
209
  def yaml_content_for(file)
206
210
  File.read(file).gsub(/\A---\n/, "---\n" + endpoint_merge_keys + "\n\n")
@@ -1,6 +1,7 @@
1
1
  require 'json-schema'
2
2
  require 'interpol/errors'
3
3
  require 'forwardable'
4
+ require 'set'
4
5
 
5
6
  module JSON
6
7
  # The JSON-schema namespace
@@ -65,13 +66,14 @@ module Interpol
65
66
  # based on the endpoint definitions in the YAML files.
66
67
  class Endpoint
67
68
  include HashFetcher
68
- attr_reader :name, :route, :method, :custom_metadata
69
+ attr_reader :name, :route, :method, :custom_metadata, :configuration
69
70
 
70
- def initialize(endpoint_hash)
71
+ def initialize(endpoint_hash, configuration = Interpol.default_configuration)
71
72
  @name = fetch_from(endpoint_hash, 'name')
72
73
  @route = fetch_from(endpoint_hash, 'route')
73
74
  @method = fetch_from(endpoint_hash, 'method').downcase.to_sym
74
75
 
76
+ @configuration = configuration
75
77
  @custom_metadata = endpoint_hash.fetch('meta') { {} }
76
78
 
77
79
  @definitions_hash, @all_definitions = extract_definitions_from(endpoint_hash)
@@ -181,7 +183,7 @@ module Interpol
181
183
  attr_reader :endpoint, :message_type, :version, :schema,
182
184
  :path_params, :query_params, :examples, :custom_metadata
183
185
  extend Forwardable
184
- def_delegators :endpoint, :route
186
+ def_delegators :endpoint, :route, :configuration
185
187
 
186
188
  DEFAULT_PARAM_HASH = { 'type' => 'object', 'properties' => {} }
187
189
 
@@ -244,12 +246,14 @@ module Interpol
244
246
  end
245
247
  end
246
248
 
247
- def make_schema_hash_strict!(raw_schema, modify_object=true)
249
+ def make_schema_hash_strict!(raw_schema, make_this_schema_strict=true)
250
+ conditionally_make_nullable(raw_schema) if make_this_schema_strict
251
+
248
252
  raw_schema.each do |key, value|
249
253
  make_schema_strict!(value, key != 'properties')
250
254
  end
251
255
 
252
- return unless modify_object
256
+ return unless make_this_schema_strict
253
257
 
254
258
  if raw_schema.has_key?('properties')
255
259
  raw_schema['additionalProperties'] ||= false
@@ -258,9 +262,33 @@ module Interpol
258
262
  raw_schema['required'] = !raw_schema.delete('optional')
259
263
  end
260
264
 
261
- def make_schema_array_strict!(raw_schema, modify_object=true)
265
+ def make_schema_array_strict!(raw_schema, make_nested_schemas_strict=true)
262
266
  raw_schema.each do |entry|
263
- make_schema_strict!(entry, modify_object)
267
+ make_schema_strict!(entry, make_nested_schemas_strict)
268
+ end
269
+ end
270
+
271
+ def conditionally_make_nullable(raw_schema)
272
+ return unless should_be_nullable?(raw_schema)
273
+
274
+ types = Array(raw_schema['type'])
275
+ return if types.none? || types.include?('null')
276
+
277
+ raw_schema['type'] = (types << "null")
278
+ end
279
+
280
+ def should_be_nullable?(raw_schema)
281
+ raw_schema.fetch('nullable') do
282
+ configuration.scalars_nullable_by_default? && scalar?(raw_schema)
283
+ end
284
+ end
285
+
286
+ NON_SCALAR_TYPES = %w[ object array ]
287
+ def scalar?(raw_schema)
288
+ types = Array(raw_schema['type']).to_set
289
+
290
+ NON_SCALAR_TYPES.none? do |non_scalar|
291
+ types.include?(non_scalar)
264
292
  end
265
293
  end
266
294
 
@@ -1,4 +1,4 @@
1
1
  module Interpol
2
- VERSION = "0.9.0"
2
+ VERSION = "0.10.0"
3
3
  end
4
4
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: interpol
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.0
4
+ version: 0.10.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-02-14 00:00:00.000000000 Z
12
+ date: 2013-04-28 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rack
@@ -66,14 +66,14 @@ dependencies:
66
66
  requirements:
67
67
  - - ~>
68
68
  - !ruby/object:Gem::Version
69
- version: '2.11'
69
+ version: '2.13'
70
70
  none: false
71
71
  type: :development
72
72
  version_requirements: !ruby/object:Gem::Requirement
73
73
  requirements:
74
74
  - - ~>
75
75
  - !ruby/object:Gem::Version
76
- version: '2.11'
76
+ version: '2.13'
77
77
  none: false
78
78
  - !ruby/object:Gem::Dependency
79
79
  name: rspec-fire
@@ -171,6 +171,22 @@ dependencies:
171
171
  - !ruby/object:Gem::Version
172
172
  version: '1.2'
173
173
  none: false
174
+ - !ruby/object:Gem::Dependency
175
+ name: sinatra
176
+ prerelease: false
177
+ requirement: !ruby/object:Gem::Requirement
178
+ requirements:
179
+ - - ~>
180
+ - !ruby/object:Gem::Version
181
+ version: '1.4'
182
+ none: false
183
+ type: :development
184
+ version_requirements: !ruby/object:Gem::Requirement
185
+ requirements:
186
+ - - ~>
187
+ - !ruby/object:Gem::Version
188
+ version: '1.4'
189
+ none: false
174
190
  description: Interpol is a toolkit for working with API endpoint definition files,
175
191
  giving you a stub app, a schema validation middleware, and browsable documentation.
176
192
  email:
@@ -186,7 +202,6 @@ files:
186
202
  - lib/interpol/configuration/built_in_param_parsers.rb
187
203
  - lib/interpol/configuration/default_callbacks.rb
188
204
  - lib/interpol/configuration.rb
189
- - lib/interpol/configuration_ruby_18_extensions.rb
190
205
  - lib/interpol/documentation.rb
191
206
  - lib/interpol/documentation_app/config.rb
192
207
  - lib/interpol/documentation_app.rb
@@ -1,27 +0,0 @@
1
- module Interpol
2
- module ConfigurationRuby18Extensions
3
- def deserialized_hash_from(file)
4
- YAML.load(yaml_content_for file).tap do |yaml|
5
- if bad_class = bad_deserialized_yaml(yaml)
6
- raise ConfigurationError.new \
7
- "Received an error while loading YAML from #{file}: \"" +
8
- "Got object of type: #{bad_class}\"\n If you are using YAML merge keys " +
9
- "to declare shared types, you must configure endpoint_definition_merge_key_files " +
10
- "before endpoint_definition_files."
11
- end
12
- end
13
- end
14
-
15
- # returns nil if the YAML has been only partially deserialized by Syck
16
- # and there are YAML::Syck objects.
17
- def bad_deserialized_yaml(yaml)
18
- if [Hash, Array].include? yaml.class
19
- yaml.map { |elem| bad_deserialized_yaml(elem) }.compact.first
20
- elsif yaml.class.name =~ /YAML::Syck::/
21
- yaml.class.name # Bad!
22
- else
23
- nil
24
- end
25
- end
26
- end
27
- end