media_types 1.0.0 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +10 -10
- data/CHANGELOG.md +9 -0
- data/Gemfile +6 -6
- data/Gemfile.lock +13 -62
- data/README.md +2 -53
- data/Rakefile +12 -12
- data/lib/media_types.rb +0 -1
- data/lib/media_types/constructable.rb +7 -7
- data/lib/media_types/dsl.rb +16 -26
- data/lib/media_types/scheme.rb +4 -0
- data/lib/media_types/scheme/missing_validation.rb +7 -4
- data/lib/media_types/scheme/output_empty_guard.rb +5 -4
- data/lib/media_types/scheme/rules_exhausted_guard.rb +5 -4
- data/lib/media_types/scheme/validation_options.rb +16 -5
- data/lib/media_types/validations.rb +5 -0
- data/lib/media_types/version.rb +1 -1
- data/media_types.gemspec +3 -5
- metadata +6 -40
- data/.travis.yml +0 -19
- data/lib/media_types/.dsl.rb.swp +0 -0
- data/lib/media_types/defaults.rb +0 -31
- data/lib/media_types/integrations.rb +0 -32
- data/lib/media_types/integrations/actionpack.rb +0 -21
- data/lib/media_types/integrations/http.rb +0 -47
- data/lib/media_types/minitest/assert_media_types_registered.rb +0 -166
- data/lib/media_types/registrar.rb +0 -148
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d77ce12d19694083cf37f19ccf0c68b402abe672c5e50b0d322879e9600ebda2
|
4
|
+
data.tar.gz: d2f90701ea7c0caf572e7565dcb47ff144ecc9255c81dadbe3d8264b6fcf1b30
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 273d09cee3e58708829d3d198d5178a88e86f79bd8ac414ba43587e0af756e1cf63dea66e4e9c4c98c1385b6b87363fabde907962417f24768b34168f1483c11
|
7
|
+
data.tar.gz: 0fafe409b8b89eeb979177514c8e25df1641c90a165f88c577e2f933ddc3d858b3c46f7c17672fb96ae2f3b0244bae40824ac53e66c7a46b87dcb206be8e65b4
|
data/.gitignore
CHANGED
@@ -1,10 +1,10 @@
|
|
1
|
-
/.bundle/
|
2
|
-
/.yardoc
|
3
|
-
/_yardoc/
|
4
|
-
/coverage/
|
5
|
-
/doc/
|
6
|
-
/pkg/
|
7
|
-
/spec/reports/
|
8
|
-
/tmp/
|
9
|
-
|
10
|
-
.idea/
|
1
|
+
/.bundle/
|
2
|
+
/.yardoc
|
3
|
+
/_yardoc/
|
4
|
+
/coverage/
|
5
|
+
/doc/
|
6
|
+
/pkg/
|
7
|
+
/spec/reports/
|
8
|
+
/tmp/
|
9
|
+
|
10
|
+
.idea/
|
data/CHANGELOG.md
CHANGED
@@ -1,4 +1,13 @@
|
|
1
|
+
# 2.0.0
|
2
|
+
|
3
|
+
- Removed ability to set default suffix. All suffixes now default to `+json`.
|
4
|
+
- Suffixes are now set for a given view and version instead of as a block.
|
5
|
+
- Added `suffix :yoursuffix` command to override the default `:json` suffix.
|
6
|
+
- Removed defaults block.
|
7
|
+
- Removed registrations block.
|
8
|
+
|
1
9
|
# 1.0.0
|
10
|
+
|
2
11
|
- Added the ability to do inline tests when defining validations using `assert_pass '<json>'` and `assert_fail '<json>'`.
|
3
12
|
- `media_type` has been replaced with `use_name`.
|
4
13
|
- It is no longer possible to set a default version. Please use `version <x> do` instead.
|
data/Gemfile
CHANGED
@@ -1,6 +1,6 @@
|
|
1
|
-
source "https://rubygems.org"
|
2
|
-
|
3
|
-
git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
|
4
|
-
|
5
|
-
# Specify your gem's dependencies in media_types.gemspec
|
6
|
-
gemspec
|
1
|
+
source "https://rubygems.org"
|
2
|
+
|
3
|
+
git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
|
4
|
+
|
5
|
+
# Specify your gem's dependencies in media_types.gemspec
|
6
|
+
gemspec
|
data/Gemfile.lock
CHANGED
@@ -1,63 +1,34 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
media_types (
|
4
|
+
media_types (2.0.0)
|
5
5
|
|
6
6
|
GEM
|
7
7
|
remote: https://rubygems.org/
|
8
8
|
specs:
|
9
|
-
actionpack (5.2.4)
|
10
|
-
actionview (= 5.2.4)
|
11
|
-
activesupport (= 5.2.4)
|
12
|
-
rack (~> 2.0)
|
13
|
-
rack-test (>= 0.6.3)
|
14
|
-
rails-dom-testing (~> 2.0)
|
15
|
-
rails-html-sanitizer (~> 1.0, >= 1.0.2)
|
16
|
-
actionview (5.2.4)
|
17
|
-
activesupport (= 5.2.4)
|
18
|
-
builder (~> 3.1)
|
19
|
-
erubi (~> 1.4)
|
20
|
-
rails-dom-testing (~> 2.0)
|
21
|
-
rails-html-sanitizer (~> 1.0, >= 1.0.3)
|
22
|
-
activesupport (5.2.4)
|
23
|
-
concurrent-ruby (~> 1.0, >= 1.0.2)
|
24
|
-
i18n (>= 0.7, < 2)
|
25
|
-
minitest (~> 5.1)
|
26
|
-
tzinfo (~> 1.1)
|
27
9
|
addressable (2.7.0)
|
28
10
|
public_suffix (>= 2.0.2, < 5.0)
|
29
11
|
ansi (1.5.0)
|
30
12
|
awesome_print (1.8.0)
|
31
|
-
builder (3.2.
|
32
|
-
concurrent-ruby (1.1.5)
|
33
|
-
crass (1.0.5)
|
13
|
+
builder (3.2.4)
|
34
14
|
docile (1.3.2)
|
35
15
|
domain_name (0.5.20190701)
|
36
16
|
unf (>= 0.0.5, < 1.0.0)
|
37
|
-
|
38
|
-
ffi (1.11.1)
|
39
|
-
ffi (1.11.1-x64-mingw32)
|
17
|
+
ffi (1.12.2)
|
40
18
|
ffi-compiler (1.0.1)
|
41
19
|
ffi (>= 1.0.0)
|
42
20
|
rake
|
43
|
-
http (4.
|
21
|
+
http (4.3.0)
|
44
22
|
addressable (~> 2.3)
|
45
23
|
http-cookie (~> 1.0)
|
46
|
-
http-form_data (~> 2.
|
24
|
+
http-form_data (~> 2.2)
|
47
25
|
http-parser (~> 1.2.0)
|
48
26
|
http-cookie (1.0.3)
|
49
27
|
domain_name (~> 0.5)
|
50
|
-
http-form_data (2.
|
28
|
+
http-form_data (2.2.0)
|
51
29
|
http-parser (1.2.1)
|
52
30
|
ffi-compiler (>= 1.0, < 2.0)
|
53
|
-
|
54
|
-
concurrent-ruby (~> 1.0)
|
55
|
-
json (2.2.0)
|
56
|
-
loofah (2.4.0)
|
57
|
-
crass (~> 1.0.2)
|
58
|
-
nokogiri (>= 1.5.9)
|
59
|
-
mini_portile2 (2.4.0)
|
60
|
-
minitest (5.13.0)
|
31
|
+
minitest (5.14.0)
|
61
32
|
minitest-ci (3.4.0)
|
62
33
|
minitest (>= 5.0.6)
|
63
34
|
minitest-reporters (1.4.2)
|
@@ -65,50 +36,30 @@ GEM
|
|
65
36
|
builder
|
66
37
|
minitest (>= 5.0)
|
67
38
|
ruby-progressbar
|
68
|
-
|
69
|
-
mini_portile2 (~> 2.4.0)
|
70
|
-
nokogiri (1.10.7-x64-mingw32)
|
71
|
-
mini_portile2 (~> 2.4.0)
|
72
|
-
oj (3.10.0)
|
73
|
-
public_suffix (4.0.1)
|
74
|
-
rack (2.0.7)
|
75
|
-
rack-test (1.1.0)
|
76
|
-
rack (>= 1.0, < 3)
|
77
|
-
rails-dom-testing (2.0.3)
|
78
|
-
activesupport (>= 4.2.0)
|
79
|
-
nokogiri (>= 1.6)
|
80
|
-
rails-html-sanitizer (1.3.0)
|
81
|
-
loofah (~> 2.3)
|
39
|
+
public_suffix (4.0.3)
|
82
40
|
rake (13.0.1)
|
83
41
|
ruby-progressbar (1.10.1)
|
84
|
-
simplecov (0.
|
42
|
+
simplecov (0.18.5)
|
85
43
|
docile (~> 1.1)
|
86
|
-
|
87
|
-
|
88
|
-
simplecov-html (0.10.2)
|
89
|
-
thread_safe (0.3.6)
|
90
|
-
tzinfo (1.2.5)
|
91
|
-
thread_safe (~> 0.1)
|
44
|
+
simplecov-html (~> 0.11)
|
45
|
+
simplecov-html (0.12.2)
|
92
46
|
unf (0.1.4)
|
93
47
|
unf_ext
|
94
48
|
unf_ext (0.0.7.6)
|
95
49
|
|
96
50
|
PLATFORMS
|
97
51
|
ruby
|
98
|
-
x64-mingw32
|
99
52
|
|
100
53
|
DEPENDENCIES
|
101
|
-
actionpack
|
102
54
|
awesome_print
|
103
|
-
bundler
|
55
|
+
bundler
|
104
56
|
http
|
105
57
|
media_types!
|
106
58
|
minitest (~> 5.0)
|
107
59
|
minitest-ci
|
108
60
|
minitest-reporters
|
109
|
-
oj
|
110
61
|
rake (~> 13.0)
|
111
62
|
simplecov
|
112
63
|
|
113
64
|
BUNDLED WITH
|
114
|
-
|
65
|
+
1.17.3
|
data/README.md
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
# MediaTypes
|
2
|
-
[![Build Status](https://
|
2
|
+
[![Build Status](https://github.com/SleeplessByte/media-types-ruby/workflows/Ruby/badge.svg?branch=master)](https://github.com/SleeplessByte/media-types-ruby/actions?query=workflow%3ARuby)
|
3
3
|
[![Gem Version](https://badge.fury.io/rb/media_types.svg)](https://badge.fury.io/rb/media_types)
|
4
4
|
[![MIT license](http://img.shields.io/badge/license-MIT-brightgreen.svg)](http://opensource.org/licenses/MIT)
|
5
5
|
[![Maintainability](https://api.codeclimate.com/v1/badges/6f2dc1fb37ecb98c4363/maintainability)](https://codeclimate.com/github/SleeplessByte/media-types-ruby/maintainability)
|
@@ -64,7 +64,7 @@ class Venue
|
|
64
64
|
'mydomain'
|
65
65
|
end
|
66
66
|
|
67
|
-
|
67
|
+
use_name 'venue'
|
68
68
|
|
69
69
|
validations do
|
70
70
|
version 2 do
|
@@ -103,17 +103,6 @@ class Venue
|
|
103
103
|
end
|
104
104
|
end
|
105
105
|
end
|
106
|
-
|
107
|
-
registrations :venue_json do
|
108
|
-
view 'create', :create_venue
|
109
|
-
view 'index', :venue_urls
|
110
|
-
view 'collection', :venue_collection
|
111
|
-
|
112
|
-
versions [1,2]
|
113
|
-
|
114
|
-
suffix :json
|
115
|
-
suffix :xml
|
116
|
-
end
|
117
106
|
end
|
118
107
|
```
|
119
108
|
|
@@ -346,9 +335,6 @@ Venue.mime_type.identifier
|
|
346
335
|
Venue.mime_type.version(1).identifier
|
347
336
|
# => "application/vnd.mydomain.venue.v1+json"
|
348
337
|
|
349
|
-
Venue.mime_type.version(1).suffix(:xml).identifier
|
350
|
-
# => "application/vnd.mydomain.venue.v1+xml"
|
351
|
-
|
352
338
|
Venue.mime_type.to_s(0.2)
|
353
339
|
# => "application/vnd.mydomain.venue.v2+json; q=0.2"
|
354
340
|
|
@@ -359,43 +345,6 @@ Venue.mime_type.view('active').identifier
|
|
359
345
|
# => "application/vnd.mydomain.venue.v2.active+json"
|
360
346
|
```
|
361
347
|
|
362
|
-
## Integrations
|
363
|
-
The integrations are not loaded by default, so you need to require them:
|
364
|
-
```ruby
|
365
|
-
# For Rails / ActionPack
|
366
|
-
require 'media_types/integrations/actionpack'
|
367
|
-
|
368
|
-
# For HTTP.rb
|
369
|
-
require 'media_types/integrations/http'
|
370
|
-
```
|
371
|
-
|
372
|
-
Define a `registrations` block on your media type, indicating the symbol for the base type (`registrations :symbol do`) and inside use the registrations dsl to define which media types to register. `versions array_of_numbers` determines which versions, `suffix name` adds a suffix, `type_alias name` adds an alias and `view name, symbol` adds a view.
|
373
|
-
|
374
|
-
```Ruby
|
375
|
-
Venue.register
|
376
|
-
```
|
377
|
-
|
378
|
-
### Rails
|
379
|
-
Load the `actionpack` integration and call `.register` on all the media types you want to be available in Rails. You can do this in the `mime_types` initializer, or anywhere before your controllers are instantiated. Yes, the symbol (by default `<type>_v<version>_<suffix>`) can now be used in your `format` blocks, or as extension in the url.
|
380
|
-
|
381
|
-
Rails only has a default serializer for `application/json`, and content with your `+json` media types (or different once) will not be deserialized by default. A way to overcome this is to set the JSON parameter parser for all new symbols. `.register` gives you back an array of `Registerable` objects that responds to `#to_sym` to get that symbol.
|
382
|
-
|
383
|
-
```ruby
|
384
|
-
symbols = Venue.register.map(&:to_sym)
|
385
|
-
|
386
|
-
original_parsers = ActionDispatch::Request.parameter_parsers
|
387
|
-
new_parser = original_parsers[Mime[:json].symbol]
|
388
|
-
new_parsers = original_parsers.merge(Hash[*symbols.map { |s| [s, new_parser] }])
|
389
|
-
ActionDispatch::Request.parameter_parsers = new_parsers
|
390
|
-
```
|
391
|
-
|
392
|
-
If you want to validate the content-type and not have your errors be `Rack::Error` but be handled by your controllers, leave this out and add a `before_action` to your controller that deserializes + validates for you.
|
393
|
-
|
394
|
-
### HTTP.rb
|
395
|
-
Load the `http` integration and call `.register` on all media types you want to be able to serialize and deserialize. The media type validations will run both before serialization and after deserialization.
|
396
|
-
|
397
|
-
Currently uses `oj` under the hood and this can not be changed.
|
398
|
-
|
399
348
|
## API
|
400
349
|
|
401
350
|
A defined schema has the following functions available:
|
data/Rakefile
CHANGED
@@ -1,12 +1,12 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'bundler/gem_tasks'
|
4
|
-
require 'rake/testtask'
|
5
|
-
|
6
|
-
Rake::TestTask.new(:test) do |t|
|
7
|
-
t.libs << 'test'
|
8
|
-
t.libs << 'lib'
|
9
|
-
t.test_files = FileList['test/**/*_test.rb']
|
10
|
-
end
|
11
|
-
|
12
|
-
task default: :test
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bundler/gem_tasks'
|
4
|
+
require 'rake/testtask'
|
5
|
+
|
6
|
+
Rake::TestTask.new(:test) do |t|
|
7
|
+
t.libs << 'test'
|
8
|
+
t.libs << 'lib'
|
9
|
+
t.test_files = FileList['test/**/*_test.rb']
|
10
|
+
end
|
11
|
+
|
12
|
+
task default: :test
|
data/lib/media_types.rb
CHANGED
@@ -28,11 +28,6 @@ module MediaTypes
|
|
28
28
|
with(view: view)
|
29
29
|
end
|
30
30
|
|
31
|
-
def suffix(suffix = NO_ARG)
|
32
|
-
return opts[:suffix] if suffix == NO_ARG
|
33
|
-
with(suffix: suffix)
|
34
|
-
end
|
35
|
-
|
36
31
|
def collection
|
37
32
|
view(COLLECTION_VIEW)
|
38
33
|
end
|
@@ -74,13 +69,18 @@ module MediaTypes
|
|
74
69
|
end
|
75
70
|
|
76
71
|
def as_key
|
77
|
-
[type, view, version
|
72
|
+
[type, view, version]
|
78
73
|
end
|
79
74
|
|
80
75
|
def hash
|
81
76
|
as_key.hash
|
82
77
|
end
|
83
78
|
|
79
|
+
def suffix
|
80
|
+
schema = schema_for(self)
|
81
|
+
schema.type_attributes.fetch(:suffix, 'json')
|
82
|
+
end
|
83
|
+
|
84
84
|
def to_str(qualifier = nil)
|
85
85
|
qualified(
|
86
86
|
qualifier,
|
@@ -88,7 +88,7 @@ module MediaTypes
|
|
88
88
|
type: opts[:type],
|
89
89
|
view: opts[:view],
|
90
90
|
version: opts[:version],
|
91
|
-
suffix:
|
91
|
+
suffix: suffix
|
92
92
|
)
|
93
93
|
)
|
94
94
|
end
|
data/lib/media_types/dsl.rb
CHANGED
@@ -1,8 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'media_types/constructable'
|
4
|
-
require 'media_types/defaults'
|
5
|
-
require 'media_types/registrar'
|
6
4
|
require 'media_types/validations'
|
7
5
|
|
8
6
|
module MediaTypes
|
@@ -49,7 +47,9 @@ module MediaTypes
|
|
49
47
|
def validatable?(media_type = to_constructable)
|
50
48
|
return false unless validations
|
51
49
|
|
52
|
-
validations.find(media_type, -> { nil })
|
50
|
+
resolved = validations.find(media_type, -> { nil })
|
51
|
+
|
52
|
+
!resolved.nil?
|
53
53
|
end
|
54
54
|
|
55
55
|
def register
|
@@ -65,10 +65,7 @@ module MediaTypes
|
|
65
65
|
def version(v)
|
66
66
|
to_constructable.version(v)
|
67
67
|
end
|
68
|
-
|
69
|
-
to_constructable.suffix(s)
|
70
|
-
end
|
71
|
-
|
68
|
+
|
72
69
|
def identifier_format
|
73
70
|
self.media_type_name_for = Proc.new do |type:, view:, version:, suffix:|
|
74
71
|
yield(type: type, view: view, version: version, suffix: suffix)
|
@@ -81,14 +78,18 @@ module MediaTypes
|
|
81
78
|
|
82
79
|
def available_validations
|
83
80
|
self.media_type_combinations.map do |a|
|
84
|
-
_, view, version
|
85
|
-
view(view).version(version)
|
81
|
+
_, view, version = a
|
82
|
+
view(view).version(version)
|
86
83
|
end
|
87
84
|
end
|
88
85
|
|
86
|
+
def schema_for(constructable)
|
87
|
+
validations.find(constructable)
|
88
|
+
end
|
89
|
+
|
89
90
|
private
|
90
91
|
|
91
|
-
def use_name(name
|
92
|
+
def use_name(name)
|
92
93
|
if self.media_type_name_for.nil?
|
93
94
|
self.media_type_name_for = Proc.new do |type:, view:, version:, suffix:|
|
94
95
|
resolved_org = nil
|
@@ -109,25 +110,14 @@ module MediaTypes
|
|
109
110
|
result
|
110
111
|
end
|
111
112
|
end
|
112
|
-
self.media_type_constructable = Constructable.new(self, type: name)
|
113
|
-
end
|
114
|
-
|
115
|
-
def defaults(&block)
|
116
|
-
return media_type_constructable unless block_given?
|
117
|
-
self.media_type_constructable = Defaults.new(to_constructable, &block).to_constructable
|
118
|
-
|
119
|
-
self
|
120
|
-
end
|
121
|
-
|
122
|
-
def registrations(symbol = nil, &block)
|
123
|
-
return media_type_registrar unless block_given?
|
124
|
-
self.media_type_registrar = Registrar.new(self, symbol: symbol, &block)
|
125
|
-
|
126
|
-
self
|
113
|
+
self.media_type_constructable = Constructable.new(self, type: name)
|
127
114
|
end
|
128
115
|
|
129
116
|
def validations(&block)
|
130
|
-
|
117
|
+
unless block_given?
|
118
|
+
raise 'No validations defined' if media_type_validations.nil?
|
119
|
+
return media_type_validations
|
120
|
+
end
|
131
121
|
self.media_type_validations = Validations.new(to_constructable, &block)
|
132
122
|
|
133
123
|
self
|
data/lib/media_types/scheme.rb
CHANGED
@@ -56,10 +56,13 @@ module MediaTypes
|
|
56
56
|
#
|
57
57
|
def initialize(allow_empty: false, expected_type: ::Object, &block)
|
58
58
|
self.rules = Rules.new(allow_empty: allow_empty, expected_type: expected_type)
|
59
|
+
self.type_attributes = {}
|
59
60
|
|
60
61
|
instance_exec(&block) if block_given?
|
61
62
|
end
|
62
63
|
|
64
|
+
attr_accessor :type_attributes
|
65
|
+
|
63
66
|
##
|
64
67
|
# Checks if the +output+ is valid
|
65
68
|
#
|
@@ -98,6 +101,7 @@ module MediaTypes
|
|
98
101
|
#
|
99
102
|
def validate(output, options = nil, **opts)
|
100
103
|
options ||= ValidationOptions.new(**opts)
|
104
|
+
options.context = output
|
101
105
|
|
102
106
|
catch(:end) do
|
103
107
|
validate!(output, options, context: nil)
|
@@ -9,18 +9,21 @@ module MediaTypes
|
|
9
9
|
def validate!(_output, options, context:, **_opts)
|
10
10
|
# Check that no unknown keys are present
|
11
11
|
return true unless options.strict
|
12
|
-
raise_strict!(key: context.key, strict_keys: context.rules, backtrace: options.backtrace)
|
12
|
+
raise_strict!(key: context.key, strict_keys: context.rules, backtrace: options.backtrace, found: options.scoped_output)
|
13
13
|
end
|
14
14
|
|
15
|
-
def raise_strict!(key:, backtrace:, strict_keys:)
|
15
|
+
def raise_strict!(key:, backtrace:, strict_keys:, found:)
|
16
16
|
raise StrictValidationError, format(
|
17
17
|
"Unknown key %<key>s in data.\n" \
|
18
18
|
"\tFound at: %<backtrace>s\n" \
|
19
19
|
"\tExpected:\n\n" \
|
20
|
-
|
20
|
+
"%<strict_keys>s\n\n" \
|
21
|
+
"\tBut I Found:\n\n" \
|
22
|
+
'%<found>s',
|
21
23
|
key: key.inspect,
|
22
24
|
backtrace: backtrace.join('->'),
|
23
|
-
strict_keys: strict_keys.
|
25
|
+
strict_keys: strict_keys.keys,
|
26
|
+
found: (found.is_a? Hash) ? found.keys : found.class.name
|
24
27
|
)
|
25
28
|
end
|
26
29
|
|
@@ -21,7 +21,7 @@ module MediaTypes
|
|
21
21
|
def call
|
22
22
|
return unless MediaTypes::Object.new(output).empty?
|
23
23
|
throw(:end, true) if allow_empty?
|
24
|
-
raise_empty!(backtrace: options.backtrace)
|
24
|
+
raise_empty!(backtrace: options.backtrace, found: options.scoped_output)
|
25
25
|
end
|
26
26
|
|
27
27
|
private
|
@@ -32,11 +32,12 @@ module MediaTypes
|
|
32
32
|
rules.allow_empty? || rules.required.empty?
|
33
33
|
end
|
34
34
|
|
35
|
-
def raise_empty!(backtrace:)
|
35
|
+
def raise_empty!(backtrace:, found:)
|
36
36
|
raise EmptyOutputError, format(
|
37
|
-
'Expected output, got empty at %<backtrace>s. Required are: %<required>s.',
|
37
|
+
'Expected output, got empty at %<backtrace>s. Required are: %<required>s. Found: %<found>s',
|
38
38
|
backtrace: backtrace.join('->'),
|
39
|
-
required: rules.required.keys
|
39
|
+
required: rules.required.keys,
|
40
|
+
found: (found.is_a? Hash) ? found.keys : found.class.name,
|
40
41
|
)
|
41
42
|
end
|
42
43
|
end
|
@@ -31,7 +31,7 @@ module MediaTypes
|
|
31
31
|
result = iterate(->(key) { required_rules.remove(key) })
|
32
32
|
return result if required_rules.empty?
|
33
33
|
|
34
|
-
raise_exhausted!(missing_keys: required_rules.keys, backtrace: options.backtrace)
|
34
|
+
raise_exhausted!(missing_keys: required_rules.keys, backtrace: options.backtrace, found: output)
|
35
35
|
end
|
36
36
|
|
37
37
|
def iterate(mark)
|
@@ -50,11 +50,12 @@ module MediaTypes
|
|
50
50
|
|
51
51
|
attr_accessor :rules, :options, :output
|
52
52
|
|
53
|
-
def raise_exhausted!(missing_keys:, backtrace:)
|
53
|
+
def raise_exhausted!(missing_keys:, backtrace:, found:)
|
54
54
|
raise ExhaustedOutputError, format(
|
55
|
-
'Missing keys in output: %<missing_keys>s at [%<backtrace>s]',
|
55
|
+
'Missing keys in output: %<missing_keys>s at [%<backtrace>s]. I did find: %<found>s',
|
56
56
|
missing_keys: missing_keys,
|
57
|
-
backtrace: backtrace.join('->')
|
57
|
+
backtrace: backtrace.join('->'),
|
58
|
+
found: (found.is_a? Hash) ? found.keys : found.class.name,
|
58
59
|
)
|
59
60
|
end
|
60
61
|
end
|
@@ -3,20 +3,31 @@
|
|
3
3
|
module MediaTypes
|
4
4
|
class Scheme
|
5
5
|
class ValidationOptions
|
6
|
-
attr_accessor :exhaustive, :strict, :backtrace
|
6
|
+
attr_accessor :exhaustive, :strict, :backtrace, :context
|
7
7
|
|
8
|
-
def initialize(exhaustive: true, strict: true, backtrace: [])
|
8
|
+
def initialize(context = {}, exhaustive: true, strict: true, backtrace: [])
|
9
9
|
self.exhaustive = exhaustive
|
10
10
|
self.strict = strict
|
11
11
|
self.backtrace = backtrace
|
12
|
+
self.context = context
|
12
13
|
end
|
13
14
|
|
14
15
|
def inspect
|
15
|
-
"backtrack: #{backtrace.inspect}, strict: #{strict.inspect}, exhaustive: #{exhaustive}"
|
16
|
+
"backtrack: #{backtrace.inspect}, strict: #{strict.inspect}, exhaustive: #{exhaustive}, current_obj: #{scoped_output.to_json}"
|
17
|
+
end
|
18
|
+
|
19
|
+
def scoped_output
|
20
|
+
current = context
|
21
|
+
|
22
|
+
backtrace.drop(1).first([0, backtrace.size - 2].max).each do |e|
|
23
|
+
current = current[e] unless current.nil?
|
24
|
+
end
|
25
|
+
|
26
|
+
current
|
16
27
|
end
|
17
28
|
|
18
29
|
def with_backtrace(backtrace)
|
19
|
-
ValidationOptions.new(exhaustive: exhaustive, strict: strict, backtrace: backtrace)
|
30
|
+
ValidationOptions.new(context, exhaustive: exhaustive, strict: strict, backtrace: backtrace)
|
20
31
|
end
|
21
32
|
|
22
33
|
def trace(*traces)
|
@@ -24,7 +35,7 @@ module MediaTypes
|
|
24
35
|
end
|
25
36
|
|
26
37
|
def exhaustive!
|
27
|
-
ValidationOptions.new(exhaustive: true, strict: strict, backtrace: backtrace)
|
38
|
+
ValidationOptions.new(context, exhaustive: true, strict: strict, backtrace: backtrace)
|
28
39
|
end
|
29
40
|
end
|
30
41
|
end
|
@@ -46,6 +46,7 @@ module MediaTypes
|
|
46
46
|
|
47
47
|
def method_missing(method_name, *arguments, &block)
|
48
48
|
if scheme.respond_to?(method_name)
|
49
|
+
media_type.__getobj__.media_type_combinations ||= Set.new
|
49
50
|
media_type.__getobj__.media_type_combinations.add(media_type.as_key)
|
50
51
|
|
51
52
|
return scheme.send(method_name, *arguments, &block)
|
@@ -79,5 +80,9 @@ module MediaTypes
|
|
79
80
|
def view(view, &block)
|
80
81
|
Validations.new(media_type.view(view), registry, &block)
|
81
82
|
end
|
83
|
+
|
84
|
+
def suffix(name)
|
85
|
+
scheme.type_attributes[:suffix] = name
|
86
|
+
end
|
82
87
|
end
|
83
88
|
end
|
data/lib/media_types/version.rb
CHANGED
data/media_types.gemspec
CHANGED
@@ -7,8 +7,8 @@ require 'media_types/version'
|
|
7
7
|
Gem::Specification.new do |spec|
|
8
8
|
spec.name = 'media_types'
|
9
9
|
spec.version = MediaTypes::VERSION
|
10
|
-
spec.authors = ['Derk-Jan Karrenbeld']
|
11
|
-
spec.email = ['derk-jan+github@karrenbeld.info']
|
10
|
+
spec.authors = ['Derk-Jan Karrenbeld', 'Max Maton']
|
11
|
+
spec.email = ['derk-jan+github@karrenbeld.info', 'info@maxmaton.nl']
|
12
12
|
|
13
13
|
spec.summary = 'Library to create media type definitions, schemes and validations'
|
14
14
|
spec.description = 'Media Types as mime types are not easily supported by frameworks such as rails. '
|
@@ -23,14 +23,12 @@ 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 'actionpack'
|
27
26
|
spec.add_development_dependency 'awesome_print'
|
28
|
-
spec.add_development_dependency 'bundler'
|
27
|
+
spec.add_development_dependency 'bundler'
|
29
28
|
spec.add_development_dependency 'http'
|
30
29
|
spec.add_development_dependency 'minitest', '~> 5.0'
|
31
30
|
spec.add_development_dependency 'minitest-ci'
|
32
31
|
spec.add_development_dependency 'minitest-reporters'
|
33
|
-
spec.add_development_dependency 'oj'
|
34
32
|
spec.add_development_dependency 'rake', '~> 13.0'
|
35
33
|
spec.add_development_dependency 'simplecov'
|
36
34
|
end
|
metadata
CHANGED
@@ -1,17 +1,18 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: media_types
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Derk-Jan Karrenbeld
|
8
|
+
- Max Maton
|
8
9
|
autorequire:
|
9
10
|
bindir: exe
|
10
11
|
cert_chain: []
|
11
|
-
date: 2020-
|
12
|
+
date: 2020-03-28 00:00:00.000000000 Z
|
12
13
|
dependencies:
|
13
14
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
15
|
+
name: awesome_print
|
15
16
|
requirement: !ruby/object:Gem::Requirement
|
16
17
|
requirements:
|
17
18
|
- - ">="
|
@@ -25,7 +26,7 @@ dependencies:
|
|
25
26
|
- !ruby/object:Gem::Version
|
26
27
|
version: '0'
|
27
28
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
29
|
+
name: bundler
|
29
30
|
requirement: !ruby/object:Gem::Requirement
|
30
31
|
requirements:
|
31
32
|
- - ">="
|
@@ -38,20 +39,6 @@ dependencies:
|
|
38
39
|
- - ">="
|
39
40
|
- !ruby/object:Gem::Version
|
40
41
|
version: '0'
|
41
|
-
- !ruby/object:Gem::Dependency
|
42
|
-
name: bundler
|
43
|
-
requirement: !ruby/object:Gem::Requirement
|
44
|
-
requirements:
|
45
|
-
- - "~>"
|
46
|
-
- !ruby/object:Gem::Version
|
47
|
-
version: '2'
|
48
|
-
type: :development
|
49
|
-
prerelease: false
|
50
|
-
version_requirements: !ruby/object:Gem::Requirement
|
51
|
-
requirements:
|
52
|
-
- - "~>"
|
53
|
-
- !ruby/object:Gem::Version
|
54
|
-
version: '2'
|
55
42
|
- !ruby/object:Gem::Dependency
|
56
43
|
name: http
|
57
44
|
requirement: !ruby/object:Gem::Requirement
|
@@ -108,20 +95,6 @@ dependencies:
|
|
108
95
|
- - ">="
|
109
96
|
- !ruby/object:Gem::Version
|
110
97
|
version: '0'
|
111
|
-
- !ruby/object:Gem::Dependency
|
112
|
-
name: oj
|
113
|
-
requirement: !ruby/object:Gem::Requirement
|
114
|
-
requirements:
|
115
|
-
- - ">="
|
116
|
-
- !ruby/object:Gem::Version
|
117
|
-
version: '0'
|
118
|
-
type: :development
|
119
|
-
prerelease: false
|
120
|
-
version_requirements: !ruby/object:Gem::Requirement
|
121
|
-
requirements:
|
122
|
-
- - ">="
|
123
|
-
- !ruby/object:Gem::Version
|
124
|
-
version: '0'
|
125
98
|
- !ruby/object:Gem::Dependency
|
126
99
|
name: rake
|
127
100
|
requirement: !ruby/object:Gem::Requirement
|
@@ -154,6 +127,7 @@ description: 'Media Types as mime types are not easily supported by frameworks s
|
|
154
127
|
as rails. '
|
155
128
|
email:
|
156
129
|
- derk-jan+github@karrenbeld.info
|
130
|
+
- info@maxmaton.nl
|
157
131
|
executables: []
|
158
132
|
extensions: []
|
159
133
|
extra_rdoc_files: []
|
@@ -161,7 +135,6 @@ files:
|
|
161
135
|
- ".github/workflows/ruby.yml"
|
162
136
|
- ".gitignore"
|
163
137
|
- ".rubocop.yml"
|
164
|
-
- ".travis.yml"
|
165
138
|
- CHANGELOG.md
|
166
139
|
- Gemfile
|
167
140
|
- Gemfile.lock
|
@@ -170,19 +143,12 @@ files:
|
|
170
143
|
- bin/console
|
171
144
|
- bin/setup
|
172
145
|
- lib/media_types.rb
|
173
|
-
- lib/media_types/.dsl.rb.swp
|
174
146
|
- lib/media_types/constructable.rb
|
175
|
-
- lib/media_types/defaults.rb
|
176
147
|
- lib/media_types/dsl.rb
|
177
148
|
- lib/media_types/formatter.rb
|
178
149
|
- lib/media_types/hash.rb
|
179
|
-
- lib/media_types/integrations.rb
|
180
|
-
- lib/media_types/integrations/actionpack.rb
|
181
|
-
- lib/media_types/integrations/http.rb
|
182
150
|
- lib/media_types/minitest/assert_media_type_format.rb
|
183
|
-
- lib/media_types/minitest/assert_media_types_registered.rb
|
184
151
|
- lib/media_types/object.rb
|
185
|
-
- lib/media_types/registrar.rb
|
186
152
|
- lib/media_types/scheme.rb
|
187
153
|
- lib/media_types/scheme/allow_nil.rb
|
188
154
|
- lib/media_types/scheme/any_of.rb
|
data/.travis.yml
DELETED
@@ -1,19 +0,0 @@
|
|
1
|
-
sudo: false
|
2
|
-
language: ruby
|
3
|
-
cache: bundler
|
4
|
-
rvm:
|
5
|
-
- 2.4
|
6
|
-
- 2.5
|
7
|
-
- 2.6
|
8
|
-
- rbx-3
|
9
|
-
- ruby-head
|
10
|
-
matrix:
|
11
|
-
allow_failures:
|
12
|
-
- rvm: ruby-head
|
13
|
-
- rvm: rbx-3
|
14
|
-
- rvm: 2.6
|
15
|
-
before_install:
|
16
|
-
- gem update --system
|
17
|
-
- gem --version
|
18
|
-
install:
|
19
|
-
- bundle install --with development --jobs=3 --retry=3 --path=${BUNDLE_PATH:-vendor/bundle}
|
data/lib/media_types/.dsl.rb.swp
DELETED
Binary file
|
data/lib/media_types/defaults.rb
DELETED
@@ -1,31 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module MediaTypes
|
4
|
-
class Defaults
|
5
|
-
def initialize(media_type, &block)
|
6
|
-
self.media_type = media_type
|
7
|
-
|
8
|
-
instance_exec(&block) if block_given?
|
9
|
-
end
|
10
|
-
|
11
|
-
def method_missing(method_name, *arguments, &block)
|
12
|
-
if media_type.respond_to?(method_name)
|
13
|
-
return self.media_type = media_type.send(method_name, *arguments, &block)
|
14
|
-
end
|
15
|
-
|
16
|
-
super
|
17
|
-
end
|
18
|
-
|
19
|
-
def respond_to_missing?(method_name, include_private = false)
|
20
|
-
media_type.respond_to?(method_name) || super
|
21
|
-
end
|
22
|
-
|
23
|
-
def to_constructable
|
24
|
-
media_type
|
25
|
-
end
|
26
|
-
|
27
|
-
private
|
28
|
-
|
29
|
-
attr_accessor :media_type
|
30
|
-
end
|
31
|
-
end
|
@@ -1,32 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module MediaTypes
|
4
|
-
INTEGRATION_METHODS = %i[register].freeze
|
5
|
-
|
6
|
-
module_function
|
7
|
-
|
8
|
-
def integrate(integration)
|
9
|
-
INTEGRATION_METHODS.each do |method|
|
10
|
-
next unless integration.respond_to?(method)
|
11
|
-
self.integrations = (integrations || {}).tap do |x|
|
12
|
-
x.merge!(method => (x[method] || []).concat([integration]))
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
# @!method register(registerable)
|
18
|
-
INTEGRATION_METHODS.each do |method|
|
19
|
-
define_singleton_method method do |*args, &block|
|
20
|
-
(integrations || {}).fetch(method) { [] }.each do |integration|
|
21
|
-
integration.send(method, *args, &block)
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
end
|
26
|
-
|
27
|
-
class << self
|
28
|
-
private
|
29
|
-
|
30
|
-
attr_accessor :integrations
|
31
|
-
end
|
32
|
-
end
|
@@ -1,21 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'action_dispatch/http/mime_type'
|
4
|
-
|
5
|
-
module MediaTypes
|
6
|
-
module ActionPackIntegration
|
7
|
-
|
8
|
-
module_function
|
9
|
-
|
10
|
-
def register(registerable)
|
11
|
-
mime_type = registerable.to_s
|
12
|
-
symbol = registerable.to_sym
|
13
|
-
synonyms = registerable.aliases
|
14
|
-
|
15
|
-
Mime::Type.register(mime_type, symbol, synonyms)
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
integrate ActionPackIntegration
|
20
|
-
end
|
21
|
-
|
@@ -1,47 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'http/mime_type'
|
4
|
-
require 'oj'
|
5
|
-
|
6
|
-
module MediaTypes
|
7
|
-
module HttpIntegration
|
8
|
-
|
9
|
-
module_function
|
10
|
-
|
11
|
-
def register(registerable)
|
12
|
-
mime_type = registerable.to_s
|
13
|
-
|
14
|
-
HTTP::MimeType.register_adapter mime_type, AdapterFor(registerable.media_type)
|
15
|
-
HTTP::MimeType.register_alias mime_type, registerable.to_sym
|
16
|
-
|
17
|
-
registerable.aliases.each do |alias_mime_type|
|
18
|
-
HTTP::MimeType.register_alias mime_type, alias_mime_type
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
class << self
|
23
|
-
private
|
24
|
-
|
25
|
-
# noinspection RubyInstanceMethodNamingConvention
|
26
|
-
def AdapterFor(media_type) # rubocop:disable Naming/MethodName
|
27
|
-
adapter_name = media_type.split(%r{[./_+-]}).map(&:capitalize).join('').tr('^A-z0-9', '_')
|
28
|
-
|
29
|
-
adapter = MediaTypes::HttpIntegration.const_set(adapter_name, Module.new)
|
30
|
-
adapter.define_singleton_method('encode') do |obj|
|
31
|
-
media_type.validate!(obj)
|
32
|
-
Oj.dump(obj, mode: :compat)
|
33
|
-
end
|
34
|
-
|
35
|
-
adapter.define_singleton_method('decode') do |str|
|
36
|
-
Oj.load(str, mode: :strict).tap do |result|
|
37
|
-
media_type.validate!(result)
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
adapter
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
integrate HttpIntegration
|
47
|
-
end
|
@@ -1,166 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'minitest/mock'
|
4
|
-
|
5
|
-
module MediaTypes
|
6
|
-
module Assertions
|
7
|
-
class << self
|
8
|
-
def block_exec_instance(instance, &block)
|
9
|
-
case block.arity
|
10
|
-
when 1, -1
|
11
|
-
instance.instance_exec(instance, &block)
|
12
|
-
else
|
13
|
-
instance.instance_exec(&block)
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
def assert_media_types_registered(media_type, &block)
|
19
|
-
collector = Collector.new(media_type)
|
20
|
-
Assertions.block_exec_instance(collector, &block)
|
21
|
-
assert_registered_types(media_type, collector.prepare_verify)
|
22
|
-
end
|
23
|
-
|
24
|
-
class Collector
|
25
|
-
def initialize(media_type)
|
26
|
-
self.media_type = media_type
|
27
|
-
self.registers = {}
|
28
|
-
end
|
29
|
-
|
30
|
-
def mime_type(mime_type, symbol:, synonyms: [])
|
31
|
-
registers[mime_type] = { symbol: symbol, synonyms: synonyms }
|
32
|
-
end
|
33
|
-
|
34
|
-
def formatted_mime_type(mime_type_format, &block)
|
35
|
-
collector = FormattedCollector.new(mime_type_format, {})
|
36
|
-
Assertions.block_exec_instance(collector, &block)
|
37
|
-
registers.merge!(collector.to_h)
|
38
|
-
end
|
39
|
-
|
40
|
-
def prepare_verify
|
41
|
-
expected_types_hash = registers.dup
|
42
|
-
expected_types_hash.each do |key, value|
|
43
|
-
expected_types_hash[key] = [value[:symbol], Array(value[:synonyms])]
|
44
|
-
end
|
45
|
-
|
46
|
-
expected_types_hash
|
47
|
-
end
|
48
|
-
|
49
|
-
private
|
50
|
-
|
51
|
-
attr_accessor :media_type, :registers
|
52
|
-
end
|
53
|
-
|
54
|
-
class FormattedCollector
|
55
|
-
def initialize(format, args = {})
|
56
|
-
self.mime_type_format = format
|
57
|
-
self.format_args = args
|
58
|
-
self.registers = {}
|
59
|
-
end
|
60
|
-
|
61
|
-
def version(version, **opts, &block)
|
62
|
-
new_format_args = format_args.merge(version: version)
|
63
|
-
register(new_format_args, **opts, &block)
|
64
|
-
end
|
65
|
-
|
66
|
-
def view(view, **opts, &block)
|
67
|
-
new_format_args = format_args.merge(view: view)
|
68
|
-
register(new_format_args, **opts, &block)
|
69
|
-
end
|
70
|
-
|
71
|
-
def create(**opts, &block)
|
72
|
-
view(CREATE_VIEW, **opts, &block)
|
73
|
-
end
|
74
|
-
|
75
|
-
def collection(**opts, &block)
|
76
|
-
view(COLLECTION_VIEW, **opts, &block)
|
77
|
-
end
|
78
|
-
|
79
|
-
def index(**opts, &block)
|
80
|
-
view(INDEX_VIEW, **opts, &block)
|
81
|
-
end
|
82
|
-
|
83
|
-
def to_h
|
84
|
-
Hash(registers)
|
85
|
-
end
|
86
|
-
|
87
|
-
private
|
88
|
-
|
89
|
-
attr_accessor :mime_type_format, :registers, :format_args
|
90
|
-
|
91
|
-
def register(new_format_args, symbol: nil, synonyms: [], &block)
|
92
|
-
if block_given?
|
93
|
-
collector = FormattedCollector.new(mime_type_format, new_format_args)
|
94
|
-
Assertions.block_exec_instance(collector, &block)
|
95
|
-
registers.merge!(collector.to_h)
|
96
|
-
else
|
97
|
-
formatted_mime_type_format = format(mime_type_format, **new_format_args)
|
98
|
-
registers[formatted_mime_type_format] = { symbol: symbol, synonyms: synonyms }
|
99
|
-
end
|
100
|
-
end
|
101
|
-
end
|
102
|
-
|
103
|
-
# rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
104
|
-
def assert_registered_types(media_type, expected_types_hash)
|
105
|
-
mock = Minitest::Mock.new
|
106
|
-
uncalled = expected_types_hash.dup
|
107
|
-
|
108
|
-
failed = []
|
109
|
-
|
110
|
-
uncalled.length.times do
|
111
|
-
mock.expect(:call, nil) do |registerable|
|
112
|
-
type = registerable.to_s
|
113
|
-
symbol = registerable.to_sym
|
114
|
-
synonyms = registerable.synonyms
|
115
|
-
|
116
|
-
options = uncalled.delete(type)
|
117
|
-
return true if options && options == [symbol, synonyms] && pass
|
118
|
-
|
119
|
-
failed <<
|
120
|
-
MockExpectationError.new(
|
121
|
-
format(
|
122
|
-
'Call failed to match expectations:' + "\n"\
|
123
|
-
'+++ actual [type: %<type>s, symbol: %<symbol>s, synonyms: %<synonyms>s]' + "\n"\
|
124
|
-
'--- expected [type: %<type>s, symbol: %<resolved_symbol>s, synonyms: %<resolved_synonyms>s]',
|
125
|
-
type: type,
|
126
|
-
symbol: symbol,
|
127
|
-
synonyms: synonyms,
|
128
|
-
resolved_symbol: options&.first,
|
129
|
-
resolved_synonyms: options&.last
|
130
|
-
)
|
131
|
-
)
|
132
|
-
end
|
133
|
-
|
134
|
-
false
|
135
|
-
end
|
136
|
-
|
137
|
-
MediaTypes.stub(:register, mock) do
|
138
|
-
if block_given?
|
139
|
-
yield media_type
|
140
|
-
else
|
141
|
-
media_type.register.flatten
|
142
|
-
end
|
143
|
-
end
|
144
|
-
|
145
|
-
messages = failed.map(&:message)
|
146
|
-
uncalled.each do |type, options|
|
147
|
-
messages << format(
|
148
|
-
'Call did not occur:' + "\n"\
|
149
|
-
'--- expected: [type: %<type>s, symbol: %<resolved_symbol>s, synonyms: %<resolved_synonyms>s]',
|
150
|
-
type: type,
|
151
|
-
resolved_symbol: options&.first,
|
152
|
-
resolved_synonyms: options&.last
|
153
|
-
)
|
154
|
-
end
|
155
|
-
|
156
|
-
if messages.length.positive?
|
157
|
-
flunk messages.join(",\n")
|
158
|
-
else
|
159
|
-
pass
|
160
|
-
end
|
161
|
-
|
162
|
-
assert mock
|
163
|
-
end
|
164
|
-
# rubocop:enable Metrics/AbcSize, Metrics/MethodLength
|
165
|
-
end
|
166
|
-
end
|
@@ -1,148 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module MediaTypes
|
4
|
-
class Registerable
|
5
|
-
def initialize(media_type, symbol:, aliases: [])
|
6
|
-
self.media_type = media_type
|
7
|
-
self.symbol = symbol
|
8
|
-
self.aliases = aliases
|
9
|
-
|
10
|
-
freeze
|
11
|
-
end
|
12
|
-
|
13
|
-
def to_s
|
14
|
-
String(media_type)
|
15
|
-
end
|
16
|
-
|
17
|
-
def to_sym
|
18
|
-
symbol
|
19
|
-
end
|
20
|
-
|
21
|
-
attr_accessor :media_type, :symbol, :aliases
|
22
|
-
|
23
|
-
alias synonyms aliases
|
24
|
-
alias mime_type to_s
|
25
|
-
|
26
|
-
end
|
27
|
-
|
28
|
-
##
|
29
|
-
# Holds all the configuration options in order to call {MediaTypes.register} exactly enough times to register the
|
30
|
-
# media type in its entirety.
|
31
|
-
#
|
32
|
-
# @see Registerable
|
33
|
-
#
|
34
|
-
class Registrar
|
35
|
-
|
36
|
-
##
|
37
|
-
# Creates a new registry with default values
|
38
|
-
#
|
39
|
-
# @param [Class] klazz the class that has {MediaTypes::Dsl} included
|
40
|
-
# @param [Symbol, NilClass] symbol the symbol the base view (nil view) should be registered under
|
41
|
-
#
|
42
|
-
def initialize(klazz, symbol: nil, &block)
|
43
|
-
self.base_media_type = klazz.to_constructable
|
44
|
-
|
45
|
-
self.registered_views = symbol ? { nil => { symbol: String(symbol).to_sym } } : {}
|
46
|
-
self.registered_versions = [base_media_type.version]
|
47
|
-
self.registered_aliases = []
|
48
|
-
self.registered_suffixes = [String(base_media_type.suffix).to_sym]
|
49
|
-
|
50
|
-
instance_exec(&block) if block_given?
|
51
|
-
end
|
52
|
-
|
53
|
-
##
|
54
|
-
# Resolves all the permutations and returns a list of {Registerable}
|
55
|
-
#
|
56
|
-
# @return [Array<Registerable>] the registerables based on all the permutations of +self+
|
57
|
-
#
|
58
|
-
def to_a
|
59
|
-
result = []
|
60
|
-
|
61
|
-
each_resolved do |media_type, symbol|
|
62
|
-
result << Registerable.new(media_type, symbol: symbol, aliases: aliases(media_type))
|
63
|
-
end
|
64
|
-
|
65
|
-
result
|
66
|
-
end
|
67
|
-
|
68
|
-
private
|
69
|
-
|
70
|
-
attr_accessor :registered_views, :registered_versions, :registered_aliases, :registered_suffixes,
|
71
|
-
:symbol_base, :base_media_type
|
72
|
-
|
73
|
-
##
|
74
|
-
# Registers a +view+ with a +symbol+
|
75
|
-
#
|
76
|
-
# @param [String, Symbol] view the view
|
77
|
-
# @param [String, Symbol] symbol the symbol base for this view
|
78
|
-
#
|
79
|
-
def view(view, symbol)
|
80
|
-
registered_views[String(view)] = { symbol: String(symbol).to_sym }
|
81
|
-
self
|
82
|
-
end
|
83
|
-
|
84
|
-
##
|
85
|
-
# Registers +versions+
|
86
|
-
#
|
87
|
-
# @param [*Numeric] versions the versions to register
|
88
|
-
#
|
89
|
-
def versions(*versions)
|
90
|
-
registered_versions.push(*versions)
|
91
|
-
self
|
92
|
-
end
|
93
|
-
|
94
|
-
##
|
95
|
-
# Registers a type alias. This will become a synonym when registering the media type
|
96
|
-
#
|
97
|
-
# @param [String] alias_name the name of the alias
|
98
|
-
#
|
99
|
-
def type_alias(alias_name)
|
100
|
-
registered_aliases.push(String(alias_name))
|
101
|
-
self
|
102
|
-
end
|
103
|
-
|
104
|
-
##
|
105
|
-
# Registers a suffix
|
106
|
-
#
|
107
|
-
# @param [String, Symbol] suffix the suffix to register
|
108
|
-
#
|
109
|
-
def suffix(suffix)
|
110
|
-
registered_suffixes.push(String(suffix).to_sym)
|
111
|
-
self
|
112
|
-
end
|
113
|
-
|
114
|
-
##
|
115
|
-
# Calculates the aliased media types for a media type
|
116
|
-
#
|
117
|
-
# @param [Constructable] media_type the media type constructable
|
118
|
-
# @return [Array<String>] the resolved aliases
|
119
|
-
#
|
120
|
-
def aliases(media_type)
|
121
|
-
registered_aliases.map { |a| media_type.type(a).to_s }
|
122
|
-
end
|
123
|
-
|
124
|
-
def each_combination
|
125
|
-
iterable(registered_versions).each do |version|
|
126
|
-
registered_views.each do |view, view_opts|
|
127
|
-
iterable(registered_suffixes).each do |suffix|
|
128
|
-
opts = { view: view_opts }
|
129
|
-
yield version, view, suffix, opts
|
130
|
-
end
|
131
|
-
end
|
132
|
-
end
|
133
|
-
end
|
134
|
-
|
135
|
-
def iterable(source)
|
136
|
-
source.compact.uniq
|
137
|
-
end
|
138
|
-
|
139
|
-
def each_resolved
|
140
|
-
each_combination do |version, view, suffix, opts|
|
141
|
-
media_type = base_media_type.version(version).view(view).suffix(suffix)
|
142
|
-
symbol = iterable([opts[:view][:symbol], "v#{version}", suffix]).join('_').to_sym
|
143
|
-
|
144
|
-
yield media_type, symbol
|
145
|
-
end
|
146
|
-
end
|
147
|
-
end
|
148
|
-
end
|