media_types 0.1.3 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +27 -0
- data/Gemfile.lock +3 -1
- data/README.md +228 -31
- data/Rakefile +8 -6
- data/lib/media_types/{constructable_mime_type.rb → constructable.rb} +9 -4
- data/lib/media_types/defaults.rb +31 -0
- data/lib/media_types/dsl.rb +65 -0
- data/lib/media_types/hash.rb +21 -0
- data/lib/media_types/minitest/assert_media_types_registered.rb +4 -4
- data/lib/media_types/object.rb +35 -0
- data/lib/media_types/registrar.rb +148 -0
- data/lib/media_types/scheme/allow_nil.rb +8 -1
- data/lib/media_types/scheme/any_of.rb +25 -0
- data/lib/media_types/scheme/attribute.rb +10 -0
- data/lib/media_types/scheme/enumeration_context.rb +16 -0
- data/lib/media_types/scheme/enumeration_of_type.rb +70 -0
- data/lib/media_types/scheme/validation_options.rb +27 -0
- data/lib/media_types/scheme.rb +262 -73
- data/lib/media_types/validations.rb +79 -0
- data/lib/media_types/version.rb +1 -1
- data/lib/media_types.rb +18 -46
- data/media_types.gemspec +1 -0
- metadata +28 -5
- data/lib/media_types/base/collector.rb +0 -44
- data/lib/media_types/base.rb +0 -193
data/lib/media_types/scheme.rb
CHANGED
@@ -1,31 +1,66 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'media_types/scheme/validation_options'
|
4
|
+
require 'media_types/scheme/enumeration_context'
|
5
|
+
|
3
6
|
require 'media_types/scheme/allow_nil'
|
4
7
|
require 'media_types/scheme/attribute'
|
8
|
+
require 'media_types/scheme/enumeration_of_type'
|
5
9
|
require 'media_types/scheme/links'
|
6
10
|
require 'media_types/scheme/missing_validation'
|
7
11
|
require 'media_types/scheme/not_strict'
|
8
12
|
|
9
13
|
module MediaTypes
|
10
|
-
|
11
|
-
|
14
|
+
##
|
15
|
+
# Media Type Schemes can validate content to a media type, by itself. Used by the `validations` dsl.
|
16
|
+
#
|
17
|
+
# @see MediaTypes::Dsl
|
18
|
+
#
|
19
|
+
# @example A scheme to test against
|
20
|
+
#
|
21
|
+
# class MyMedia
|
22
|
+
# include MediaTypes::Dsl
|
23
|
+
#
|
24
|
+
# validations do
|
25
|
+
# attribute :foo do
|
26
|
+
# collection :bar, String
|
27
|
+
# end
|
28
|
+
# attribute :number, Numeric
|
29
|
+
# end
|
30
|
+
# end
|
31
|
+
#
|
32
|
+
# MyMedia.valid?({ foo: { bar: ['test'] }, number: 42 })
|
33
|
+
# #=> true
|
34
|
+
#
|
35
|
+
class Scheme
|
12
36
|
|
13
|
-
|
14
|
-
|
37
|
+
# Base class for all validations errors
|
38
|
+
class ValidationError < ArgumentError; end
|
15
39
|
|
16
|
-
|
17
|
-
|
40
|
+
# Raised when it expected more data but there wasn't any left
|
41
|
+
class ExhaustedOutputError < ValidationError; end
|
18
42
|
|
19
|
-
|
20
|
-
|
43
|
+
# Raised when it did not expect more data, but there was more left
|
44
|
+
class StrictValidationError < ValidationError; end
|
21
45
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
46
|
+
# Raised when it expected not to be empty, but it was
|
47
|
+
class EmptyOutputError < ValidationError; end
|
48
|
+
|
49
|
+
# Raised when a value did not have the expected collection type
|
50
|
+
class CollectionTypeError < ValidationError; end
|
51
|
+
|
52
|
+
##
|
53
|
+
# Creates a new scheme
|
54
|
+
#
|
55
|
+
# @param [TrueClass, FalseClass] allow_empty if true allows to be empty, if false raises EmptyOutputError if empty
|
56
|
+
# @param [NilClass, Class] force forces the type to be this type, if given
|
57
|
+
#
|
58
|
+
# @see MissingValidation
|
59
|
+
#
|
60
|
+
def initialize(allow_empty: false, force: nil)
|
27
61
|
self.validations = {}
|
28
62
|
self.allow_empty = allow_empty
|
63
|
+
self.force = force
|
29
64
|
|
30
65
|
validations.default = MissingValidation.new
|
31
66
|
end
|
@@ -33,12 +68,12 @@ module MediaTypes
|
|
33
68
|
##
|
34
69
|
# Checks if the +output+ is valid
|
35
70
|
#
|
36
|
-
# @param [#each] output
|
37
|
-
# @param [Hash] opts
|
38
|
-
# @option exhaustive [
|
39
|
-
# @option strict [
|
71
|
+
# @param [#each] output the output to test against
|
72
|
+
# @param [Hash] opts the options as defined below
|
73
|
+
# @option exhaustive [TrueClass, FalseClass] opts if true, raises when it expected more data but there wasn't any
|
74
|
+
# @option strict [TrueClass, FalseClass] opts if true, raised when it did not expect more data, but there was more
|
40
75
|
#
|
41
|
-
# @return [
|
76
|
+
# @return [TrueClass, FalseClass] true if valid, false otherwise
|
42
77
|
#
|
43
78
|
def valid?(output, **opts)
|
44
79
|
validate(output, **opts)
|
@@ -48,41 +83,22 @@ module MediaTypes
|
|
48
83
|
false
|
49
84
|
end
|
50
85
|
|
51
|
-
class ValidationOptions
|
52
|
-
attr_accessor :exhaustive, :strict, :backtrace
|
53
|
-
|
54
|
-
def initialize(exhaustive: true, strict: true, backtrace: [])
|
55
|
-
self.exhaustive = exhaustive
|
56
|
-
self.strict = strict
|
57
|
-
self.backtrace = backtrace
|
58
|
-
end
|
59
|
-
|
60
|
-
def with_backtrace(backtrace)
|
61
|
-
ValidationOptions.new(exhaustive: exhaustive, strict: strict, backtrace: backtrace)
|
62
|
-
end
|
63
|
-
|
64
|
-
def trace(*traces)
|
65
|
-
with_backtrace(backtrace.dup.concat(traces))
|
66
|
-
end
|
67
|
-
|
68
|
-
def exhaustive!
|
69
|
-
ValidationOptions.new(exhaustive: true, strict: strict, backtrace: backtrace)
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
86
|
##
|
74
87
|
# Validates the +output+ and raises on certain validation errors
|
75
88
|
#
|
76
89
|
# @param [#each] output output to validate
|
77
|
-
# @option opts [
|
78
|
-
# @option opts [
|
90
|
+
# @option opts [TrueClass, FalseClass] exhaustive if true, the entire schema needs to be consumed
|
91
|
+
# @option opts [TrueClass, FalseClass] strict if true, no extra keys may be present in +output+
|
79
92
|
# @option opts[Array<String>] backtrace the current backtrace for error messages
|
80
93
|
#
|
81
94
|
# @raise ExhaustedOutputError
|
82
95
|
# @raise StrictValidationError
|
83
96
|
# @raise EmptyOutputError
|
97
|
+
# @raise CollectionTypeError
|
84
98
|
# @raise ValidationError
|
85
99
|
#
|
100
|
+
# @see #validate!
|
101
|
+
#
|
86
102
|
# @return [TrueClass]
|
87
103
|
#
|
88
104
|
def validate(output, options = nil, **opts)
|
@@ -93,6 +109,9 @@ module MediaTypes
|
|
93
109
|
end
|
94
110
|
end
|
95
111
|
|
112
|
+
#
|
113
|
+
# @private
|
114
|
+
#
|
96
115
|
def validate!(output, call_options, **_opts)
|
97
116
|
empty_guard!(output, call_options)
|
98
117
|
|
@@ -111,39 +130,114 @@ module MediaTypes
|
|
111
130
|
|
112
131
|
##
|
113
132
|
# Adds an attribute to the schema
|
133
|
+
# If a +block+ is given, uses that to test against instead of +type+
|
114
134
|
#
|
115
135
|
# @param key [Symbol] the attribute name
|
116
|
-
# @param
|
117
|
-
# @param
|
136
|
+
# @param opts [Hash] options to pass to Scheme or Attribute
|
137
|
+
# @param type [Class, #===, Scheme] The type of the value, can be anything that responds to #===,
|
138
|
+
# or scheme to use if no +&block+ is given. Defaults to String without a +&block+ and to Hash with a +&block+.
|
139
|
+
#
|
140
|
+
# @see Scheme::Attribute
|
141
|
+
# @see Scheme
|
118
142
|
#
|
119
143
|
# @example Add an attribute named foo, expecting a string
|
120
144
|
#
|
121
|
-
# class MyMedia
|
122
|
-
#
|
145
|
+
# class MyMedia
|
146
|
+
# include MediaTypes::Dsl
|
147
|
+
#
|
148
|
+
# validations do
|
123
149
|
# attribute :foo, String
|
124
150
|
# end
|
125
151
|
# end
|
126
152
|
#
|
153
|
+
# MyMedia.valid?({ foo: 'my-string' })
|
154
|
+
# # => true
|
155
|
+
#
|
156
|
+
# @example Add an attribute named foo, expecting nested scheme
|
157
|
+
#
|
158
|
+
# class MyMedia
|
159
|
+
# include MediaTypes::Dsl
|
160
|
+
#
|
161
|
+
# validations do
|
162
|
+
# attribute :foo do
|
163
|
+
# attribute :bar, String
|
164
|
+
# end
|
165
|
+
# end
|
166
|
+
# end
|
167
|
+
#
|
168
|
+
# MyMedia.valid?({ foo: { bar: 'my-string' }})
|
169
|
+
# # => true
|
170
|
+
#
|
127
171
|
def attribute(key, type = String, **opts, &block)
|
172
|
+
if block_given?
|
173
|
+
return collection(key, force: ::Hash, **opts, &block)
|
174
|
+
end
|
175
|
+
|
176
|
+
if type.is_a?(Scheme)
|
177
|
+
return validations[key] = type
|
178
|
+
end
|
179
|
+
|
128
180
|
validations[key] = Attribute.new(type, **opts, &block)
|
129
181
|
end
|
130
182
|
|
131
183
|
##
|
132
184
|
# Allow for any key.
|
133
|
-
# The
|
185
|
+
# The +&block+ defines the Schema for each value.
|
186
|
+
#
|
187
|
+
# @param [Scheme, NilClass] scheme scheme to use if no +&block+ is given
|
188
|
+
# @param [TrueClass, FalseClass] allow_empty if true, empty (no key/value present) is allowed
|
189
|
+
# @param [Class] force forces the validated object to have this type
|
190
|
+
#
|
191
|
+
# @see Scheme
|
134
192
|
#
|
135
|
-
# @
|
193
|
+
# @example Add a collection named foo, expecting any key with a defined value
|
136
194
|
#
|
137
|
-
|
138
|
-
|
195
|
+
# class MyMedia
|
196
|
+
# include MediaTypes::Dsl
|
197
|
+
#
|
198
|
+
# validations do
|
199
|
+
# collection :foo do
|
200
|
+
# any do
|
201
|
+
# attribute :bar, String
|
202
|
+
# end
|
203
|
+
# end
|
204
|
+
# end
|
205
|
+
# end
|
206
|
+
#
|
207
|
+
# MyMedia.valid?({ foo: [{ anything: { bar: 'my-string' }, other_thing: { bar: 'other-string' } }] })
|
208
|
+
# # => true
|
209
|
+
#
|
210
|
+
def any(scheme = nil, force: ::Hash, allow_empty: false, &block)
|
211
|
+
unless block_given?
|
212
|
+
return validations.default = scheme
|
213
|
+
end
|
214
|
+
|
215
|
+
scheme = Scheme.new(allow_empty: allow_empty, force: force)
|
139
216
|
scheme.instance_exec(&block)
|
140
217
|
|
141
218
|
validations.default = scheme
|
142
219
|
end
|
143
220
|
|
144
221
|
##
|
145
|
-
# Allow for extra keys in the schema/collection
|
146
|
-
#
|
222
|
+
# Allow for extra keys in the schema/collection even when passing strict: true to #validate!
|
223
|
+
#
|
224
|
+
# @see Scheme::NotStrict
|
225
|
+
#
|
226
|
+
# @example Allow for extra keys in collection
|
227
|
+
#
|
228
|
+
# class MyMedia
|
229
|
+
# include MediaTypes::Dsl
|
230
|
+
#
|
231
|
+
# validations do
|
232
|
+
# collection :foo do
|
233
|
+
# attribute :required, String
|
234
|
+
# not_strict
|
235
|
+
# end
|
236
|
+
# end
|
237
|
+
# end
|
238
|
+
#
|
239
|
+
# MyMedia.valid?({ foo: [{ required: 'test', bar: 42 }] })
|
240
|
+
# # => true
|
147
241
|
#
|
148
242
|
def not_strict
|
149
243
|
validations.default = NotStrict.new
|
@@ -153,11 +247,56 @@ module MediaTypes
|
|
153
247
|
# Expect a collection such as an array or hash.
|
154
248
|
# The +block+ defines the Schema for each item in that collection.
|
155
249
|
#
|
156
|
-
# @param [Symbol] key
|
157
|
-
# @param [
|
250
|
+
# @param [Symbol] key key of the collection (same as #attribute)
|
251
|
+
# @param [NilClass, Scheme, Class] scheme scheme to use if no +&block+ is given, or type of each item in collection
|
252
|
+
# @param [TrueClass, FalseClass] allow_empty if true accepts 0 items in an enumerable
|
253
|
+
# @param [Class] force forces the value of this collection to be this type, defaults to Array.
|
254
|
+
#
|
255
|
+
# @see Scheme
|
256
|
+
#
|
257
|
+
# @example Collection with an array of string
|
258
|
+
#
|
259
|
+
# class MyMedia
|
260
|
+
# include MediaTypes::Dsl
|
261
|
+
#
|
262
|
+
# validations do
|
263
|
+
# collection :foo, String
|
264
|
+
# end
|
265
|
+
# end
|
266
|
+
#
|
267
|
+
# MyMedia.valid?({ collection: ['foo', 'bar'] })
|
268
|
+
# # => true
|
269
|
+
#
|
270
|
+
# @example Collection with defined scheme
|
158
271
|
#
|
159
|
-
|
160
|
-
|
272
|
+
# class MyMedia
|
273
|
+
# include MediaTypes::Dsl
|
274
|
+
#
|
275
|
+
# validations do
|
276
|
+
# collection :foo do
|
277
|
+
# attribute :required, String
|
278
|
+
# attribute :number, Numeric
|
279
|
+
# end
|
280
|
+
# end
|
281
|
+
# end
|
282
|
+
#
|
283
|
+
# MyMedia.valid?({ foo: [{ required: 'test', number: 42 }, { required: 'other', number: 0 }] })
|
284
|
+
# # => true
|
285
|
+
#
|
286
|
+
def collection(key, scheme = nil, allow_empty: false, force: Array, &block)
|
287
|
+
unless block_given?
|
288
|
+
if scheme.is_a?(Scheme)
|
289
|
+
return validations[key] = scheme
|
290
|
+
end
|
291
|
+
|
292
|
+
return validations[key] = EnumerationOfType.new(
|
293
|
+
scheme,
|
294
|
+
enumeration_type: force,
|
295
|
+
allow_empty: allow_empty
|
296
|
+
)
|
297
|
+
end
|
298
|
+
|
299
|
+
scheme = Scheme.new(allow_empty: allow_empty, force: force)
|
161
300
|
scheme.instance_exec(&block)
|
162
301
|
|
163
302
|
validations[key] = scheme
|
@@ -166,6 +305,37 @@ module MediaTypes
|
|
166
305
|
##
|
167
306
|
# Expect a link
|
168
307
|
#
|
308
|
+
# @see Scheme::Links
|
309
|
+
#
|
310
|
+
# @example Links as defined in HAL, JSON-Links and other specs
|
311
|
+
#
|
312
|
+
# class MyMedia
|
313
|
+
# include MediaTypes::Dsl
|
314
|
+
#
|
315
|
+
# validations do
|
316
|
+
# link :_self
|
317
|
+
# link :image
|
318
|
+
# end
|
319
|
+
# end
|
320
|
+
#
|
321
|
+
# MyMedia.valid?({ _links: { self: { href: 'https://example.org/s' }, image: { href: 'https://image.org/i' }} })
|
322
|
+
# # => true
|
323
|
+
#
|
324
|
+
# @example Link with extra attributes
|
325
|
+
#
|
326
|
+
# class MyMedia
|
327
|
+
# include MediaTypes::Dsl
|
328
|
+
#
|
329
|
+
# validations do
|
330
|
+
# link :image do
|
331
|
+
# attribute :templated, TrueClass
|
332
|
+
# end
|
333
|
+
# end
|
334
|
+
# end
|
335
|
+
#
|
336
|
+
# MyMedia.valid?({ _links: { image: { href: 'https://image.org/{md5}', templated: true }} })
|
337
|
+
# # => true
|
338
|
+
#
|
169
339
|
def link(*args, **opts, &block)
|
170
340
|
validations.fetch(:_links) do
|
171
341
|
Links.new.tap do |links|
|
@@ -176,41 +346,51 @@ module MediaTypes
|
|
176
346
|
|
177
347
|
private
|
178
348
|
|
179
|
-
attr_accessor :validations, :allow_empty
|
349
|
+
attr_accessor :validations, :allow_empty, :force
|
180
350
|
|
351
|
+
##
|
352
|
+
# Checks if the output is nil or empty
|
353
|
+
#
|
354
|
+
# @private
|
355
|
+
#
|
181
356
|
def empty_guard!(output, options)
|
182
|
-
return unless
|
357
|
+
return unless MediaTypes::Object.new(output).empty?
|
183
358
|
throw(:end, true) if allow_empty
|
184
359
|
raise_empty!(backtrace: options.backtrace)
|
185
360
|
end
|
186
361
|
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
end
|
191
|
-
|
192
|
-
def enumerate(val)
|
193
|
-
self.key = val
|
194
|
-
self
|
195
|
-
end
|
196
|
-
|
197
|
-
attr_accessor :validations, :key
|
198
|
-
end
|
199
|
-
|
362
|
+
##
|
363
|
+
# Mimics Enumerable#all? with mandatory +&block+
|
364
|
+
#
|
200
365
|
def all?(enumerable, options, &block)
|
201
366
|
context = EnumerationContext.new(validations: validations)
|
202
367
|
|
368
|
+
if force && !(force === enumerable) # rubocop:disable Style/CaseEquality
|
369
|
+
raise_forced_type_error!(type: enumerable.class, backtrace: options.backtrace)
|
370
|
+
end
|
371
|
+
|
203
372
|
if enumerable.is_a?(Hash) || enumerable.respond_to?(:key)
|
204
373
|
return enumerable.all? do |key, value|
|
205
374
|
yield key, value, options: options, context: context.enumerate(key)
|
206
375
|
end
|
207
376
|
end
|
208
377
|
|
209
|
-
|
210
|
-
all?
|
378
|
+
without_forcing_type do
|
379
|
+
enumerable.each_with_index.all? do |array_like_element, i|
|
380
|
+
all?(array_like_element, options.trace(i), &block)
|
381
|
+
end
|
211
382
|
end
|
212
383
|
end
|
213
384
|
|
385
|
+
def raise_forced_type_error!(type:, backtrace:)
|
386
|
+
raise CollectionTypeError, format(
|
387
|
+
'Expected a %<expected>s, got a %<actual>s at %<backtrace>s',
|
388
|
+
expected: force,
|
389
|
+
actual: type,
|
390
|
+
backtrace: backtrace.join('->')
|
391
|
+
)
|
392
|
+
end
|
393
|
+
|
214
394
|
def raise_empty!(backtrace:)
|
215
395
|
raise EmptyOutputError, format('Expected output, got empty at %<backtrace>s', backtrace: backtrace.join('->'))
|
216
396
|
end
|
@@ -229,10 +409,19 @@ module MediaTypes
|
|
229
409
|
end
|
230
410
|
|
231
411
|
exhaustive_keys = keys.dup
|
412
|
+
# noinspection RubyScope
|
232
413
|
result = yield ->(key) { exhaustive_keys.delete(key) }
|
233
414
|
return result if exhaustive_keys.empty?
|
234
415
|
|
235
416
|
raise_exhausted!(missing_keys: exhaustive_keys, backtrace: options.backtrace)
|
236
417
|
end
|
418
|
+
|
419
|
+
def without_forcing_type
|
420
|
+
before_force = force
|
421
|
+
self.force = nil
|
422
|
+
result = yield
|
423
|
+
self.force = before_force
|
424
|
+
result
|
425
|
+
end
|
237
426
|
end
|
238
427
|
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'media_types/scheme'
|
4
|
+
|
5
|
+
module MediaTypes
|
6
|
+
##
|
7
|
+
# Takes care of registering validations for a media type. It allows for nested schemes and registers each one so it
|
8
|
+
# can be looked up at a later time.
|
9
|
+
#
|
10
|
+
# @see MediaType::Dsl
|
11
|
+
# @see Scheme
|
12
|
+
#
|
13
|
+
class Validations
|
14
|
+
|
15
|
+
##
|
16
|
+
# Creates a new stack of validations
|
17
|
+
#
|
18
|
+
# @param [Constructable] media_type a Constructable media type
|
19
|
+
# @param [Hash] registry the registry reference, or nil if top level
|
20
|
+
# @param [Scheme] scheme the current scheme or nil if top level
|
21
|
+
#
|
22
|
+
# @see MediaTypes::Dsl
|
23
|
+
# @see Constructable
|
24
|
+
# @see Scheme
|
25
|
+
#
|
26
|
+
def initialize(media_type, registry = {}, scheme = Scheme.new, &block)
|
27
|
+
self.media_type = media_type
|
28
|
+
self.registry = registry.merge!(media_type.to_s => scheme)
|
29
|
+
self.scheme = scheme
|
30
|
+
|
31
|
+
instance_exec(&block) if block_given?
|
32
|
+
end
|
33
|
+
|
34
|
+
##
|
35
|
+
# Looks up the validations for Constructable
|
36
|
+
#
|
37
|
+
# @param [String, Constructable] media_type
|
38
|
+
# @param [lambda] default the lambda if nothing can be found
|
39
|
+
# @return [Scheme] the scheme for the given +media_type+
|
40
|
+
#
|
41
|
+
def find(media_type, default = -> { Scheme::NotStrict.new })
|
42
|
+
registry.fetch(String(media_type)) { default.call }
|
43
|
+
end
|
44
|
+
|
45
|
+
def method_missing(method_name, *arguments, &block)
|
46
|
+
if scheme.respond_to?(method_name)
|
47
|
+
return scheme.send(method_name, *arguments, &block)
|
48
|
+
end
|
49
|
+
|
50
|
+
super
|
51
|
+
end
|
52
|
+
|
53
|
+
def respond_to_missing?(method_name, include_private = false)
|
54
|
+
scheme.respond_to?(method_name) || super
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
attr_accessor :media_type, :registry, :scheme
|
60
|
+
|
61
|
+
##
|
62
|
+
# Switches the inner block to a specific version
|
63
|
+
#
|
64
|
+
# @param [Numeric] version the version to switch to
|
65
|
+
#
|
66
|
+
def version(version, &block)
|
67
|
+
Validations.new(media_type.version(version), registry, &block)
|
68
|
+
end
|
69
|
+
|
70
|
+
##
|
71
|
+
# Switches the inner block to a specific view
|
72
|
+
#
|
73
|
+
# @param [String, Symbol] view the view to switch to
|
74
|
+
#
|
75
|
+
def view(view, &block)
|
76
|
+
Validations.new(media_type.view(view), registry, &block)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
data/lib/media_types/version.rb
CHANGED
data/lib/media_types.rb
CHANGED
@@ -1,64 +1,36 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'delegate'
|
4
|
+
|
3
5
|
require 'media_types/version'
|
4
|
-
require 'media_types/
|
6
|
+
require 'media_types/hash'
|
7
|
+
require 'media_types/object'
|
5
8
|
require 'media_types/scheme'
|
6
|
-
|
7
|
-
require 'delegate'
|
9
|
+
require 'media_types/dsl'
|
8
10
|
|
9
11
|
module MediaTypes
|
12
|
+
# Shortcut used by #collection to #view('collection')
|
10
13
|
COLLECTION_VIEW = 'collection'
|
14
|
+
|
15
|
+
# Shortcut used by #index to #view('index')
|
11
16
|
INDEX_VIEW = 'index'
|
17
|
+
|
18
|
+
# Shortcut used by #create to #view('create')
|
12
19
|
CREATE_VIEW = 'create'
|
13
20
|
|
14
21
|
module_function
|
15
22
|
|
16
|
-
|
23
|
+
##
|
24
|
+
# Called when Registerar#register is called
|
25
|
+
# @param [Registerable] registerable
|
26
|
+
def register(registerable)
|
17
27
|
require 'action_dispatch/http/mime_type'
|
18
|
-
Mime::Type.register(mime_type, symbol, synonyms)
|
19
|
-
end
|
20
|
-
|
21
|
-
class Object < SimpleDelegator
|
22
|
-
def class
|
23
|
-
__getobj__.class
|
24
|
-
end
|
25
28
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
+
mime_type = registerable.to_s
|
30
|
+
symbol = registerable.to_sym
|
31
|
+
synonyms = registerable.aliases
|
29
32
|
|
30
|
-
|
31
|
-
if __getobj__.respond_to?(:blank?)
|
32
|
-
return __getobj__.blank?
|
33
|
-
end
|
34
|
-
|
35
|
-
# noinspection RubySimplifyBooleanInspection
|
36
|
-
__getobj__.respond_to?(:empty?) ? !!__getobj__.empty? : !__getobj__ # rubocop:disable Style/DoubleNegation
|
37
|
-
end
|
38
|
-
|
39
|
-
def present?
|
40
|
-
!blank?
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
class Hash < SimpleDelegator
|
45
|
-
def class
|
46
|
-
__getobj__.class
|
47
|
-
end
|
48
|
-
|
49
|
-
def ===(other)
|
50
|
-
__getobj__ === other # rubocop:disable Style/CaseEquality
|
51
|
-
end
|
52
|
-
|
53
|
-
def slice(*keep_keys)
|
54
|
-
if __getobj__.respond_to?(:slice)
|
55
|
-
return __getobj__.slice(*keep_keys)
|
56
|
-
end
|
57
|
-
|
58
|
-
h = {}
|
59
|
-
keep_keys.each { |key| h[key] = fetch(key) if key?(key) }
|
60
|
-
h
|
61
|
-
end
|
33
|
+
Mime::Type.register(mime_type, symbol, synonyms)
|
62
34
|
end
|
63
35
|
end
|
64
36
|
|
data/media_types.gemspec
CHANGED
@@ -23,6 +23,7 @@ Gem::Specification.new do |spec|
|
|
23
23
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
24
24
|
spec.require_paths = ['lib']
|
25
25
|
|
26
|
+
spec.add_development_dependency 'awesome_print'
|
26
27
|
spec.add_development_dependency 'bundler', '~> 1.16'
|
27
28
|
spec.add_development_dependency 'minitest', '~> 5.0'
|
28
29
|
spec.add_development_dependency 'minitest-ci'
|