interpol 0.9.0 → 0.10.0

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/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