media_types 0.1.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.
- checksums.yaml +7 -0
- data/.gitignore +10 -0
- data/.rubocop.yml +29 -0
- data/.travis.yml +20 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +42 -0
- data/README.md +150 -0
- data/Rakefile +10 -0
- data/bin/console +15 -0
- data/bin/setup +8 -0
- data/lib/media_types.rb +65 -0
- data/lib/media_types/base.rb +193 -0
- data/lib/media_types/base/collector.rb +44 -0
- data/lib/media_types/constructable_mime_type.rb +126 -0
- data/lib/media_types/minitest/assert_media_type_format.rb +20 -0
- data/lib/media_types/minitest/assert_media_types_registered.rb +143 -0
- data/lib/media_types/scheme.rb +238 -0
- data/lib/media_types/scheme/allow_nil.rb +18 -0
- data/lib/media_types/scheme/attribute.rb +34 -0
- data/lib/media_types/scheme/links.rb +32 -0
- data/lib/media_types/scheme/missing_validation.rb +24 -0
- data/lib/media_types/scheme/not_strict.rb +11 -0
- data/lib/media_types/version.rb +3 -0
- data/media_types.gemspec +32 -0
- metadata +151 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 40c245e8d88896a28fc047f4c05f1991c59a95ba
|
4
|
+
data.tar.gz: 007f468d119afe894a615e4acd28a16a9175cfa4
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 38e8ac6b119157c3ac12ac84f0cf495c797c9878df4f60cc24570ac7baf890941d95a62a540281a924eedff94f21acdccfd598f07a169380490b9e4946da2aac
|
7
|
+
data.tar.gz: 7243579da6b1819058856ebcfe85262cf48f509983e06e288fba8d5ac10ded2880fd3ed997b21f823ff83e80a2f4c6cec106bc33e2417e7a6290144d8fefdedb
|
data/.gitignore
ADDED
data/.rubocop.yml
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
AllCops:
|
2
|
+
Include:
|
3
|
+
- '**/Rakefile'
|
4
|
+
- 'lib/**/*.rb'
|
5
|
+
Exclude:
|
6
|
+
- 'Gemfile'
|
7
|
+
- 'bin/**/*'
|
8
|
+
TargetRubyVersion: 2.4
|
9
|
+
|
10
|
+
Layout/EmptyLinesAroundClassBody:
|
11
|
+
Enabled: false
|
12
|
+
|
13
|
+
Layout/EndOfLine:
|
14
|
+
Enabled: false
|
15
|
+
|
16
|
+
Metrics/LineLength:
|
17
|
+
Max: 120
|
18
|
+
|
19
|
+
Metrics/MethodLength:
|
20
|
+
Max: 15
|
21
|
+
|
22
|
+
Style/Documentation:
|
23
|
+
Enabled: false
|
24
|
+
|
25
|
+
Style/EmptyMethod:
|
26
|
+
EnforcedStyle: expanded
|
27
|
+
|
28
|
+
Style/IfUnlessModifier:
|
29
|
+
Enabled: false
|
data/.travis.yml
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
sudo: false
|
2
|
+
language: ruby
|
3
|
+
cache: bundler
|
4
|
+
rvm:
|
5
|
+
- 2.3.0
|
6
|
+
- 2.4
|
7
|
+
- 2.5
|
8
|
+
- 2.6
|
9
|
+
- rbx-3
|
10
|
+
- ruby-head
|
11
|
+
matrix:
|
12
|
+
allow_failures:
|
13
|
+
- rvm: ruby-head
|
14
|
+
- rvm: rbx-3
|
15
|
+
- rvm: 2.6
|
16
|
+
before_install:
|
17
|
+
- gem update --system
|
18
|
+
- gem --version
|
19
|
+
install:
|
20
|
+
- bundle install --with development --jobs=3 --retry=3 --path=${BUNDLE_PATH:-vendor/bundle}
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
media_types (0.1.0)
|
5
|
+
|
6
|
+
GEM
|
7
|
+
remote: https://rubygems.org/
|
8
|
+
specs:
|
9
|
+
ansi (1.5.0)
|
10
|
+
builder (3.2.3)
|
11
|
+
docile (1.3.1)
|
12
|
+
json (2.1.0)
|
13
|
+
minitest (5.11.3)
|
14
|
+
minitest-ci (3.4.0)
|
15
|
+
minitest (>= 5.0.6)
|
16
|
+
minitest-reporters (1.3.4)
|
17
|
+
ansi
|
18
|
+
builder
|
19
|
+
minitest (>= 5.0)
|
20
|
+
ruby-progressbar
|
21
|
+
rake (10.5.0)
|
22
|
+
ruby-progressbar (1.10.0)
|
23
|
+
simplecov (0.16.1)
|
24
|
+
docile (~> 1.1)
|
25
|
+
json (>= 1.8, < 3)
|
26
|
+
simplecov-html (~> 0.10.0)
|
27
|
+
simplecov-html (0.10.2)
|
28
|
+
|
29
|
+
PLATFORMS
|
30
|
+
x64-mingw32
|
31
|
+
|
32
|
+
DEPENDENCIES
|
33
|
+
bundler (~> 1.16)
|
34
|
+
media_types!
|
35
|
+
minitest (~> 5.0)
|
36
|
+
minitest-ci
|
37
|
+
minitest-reporters
|
38
|
+
rake (~> 10.0)
|
39
|
+
simplecov
|
40
|
+
|
41
|
+
BUNDLED WITH
|
42
|
+
1.16.4
|
data/README.md
ADDED
@@ -0,0 +1,150 @@
|
|
1
|
+
# MediaTypes
|
2
|
+
[](https://travis-ci.com/SleeplessByte/media-types-ruby)
|
3
|
+
[](https://badge.fury.io/rb/media-types-ruby)
|
4
|
+
[](http://opensource.org/licenses/MIT)
|
5
|
+
[](https://codeclimate.com/github/SleeplessByte/media-types-ruby/maintainability)
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Add this line to your application's Gemfile:
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
gem 'media_types'
|
13
|
+
```
|
14
|
+
|
15
|
+
And then execute:
|
16
|
+
|
17
|
+
$ bundle
|
18
|
+
|
19
|
+
Or install it yourself as:
|
20
|
+
|
21
|
+
$ gem install media_types
|
22
|
+
|
23
|
+
## Usage
|
24
|
+
|
25
|
+
By default there are no media types registered or defined, except for an abstract base type.
|
26
|
+
|
27
|
+
### Definition
|
28
|
+
You can define media types by inheriting from this base type, or create your own base type with a class method
|
29
|
+
`.base_format` that is used to create the final media type string by injecting formatted parameters:
|
30
|
+
|
31
|
+
- `%<type>s`: the type `media_type` received
|
32
|
+
- `%<version>s`: the version, defaults to `:current_version`
|
33
|
+
- `%<view>s`: the view, defaults to <empty>
|
34
|
+
- `%<suffix>s`: the suffix
|
35
|
+
|
36
|
+
```Ruby
|
37
|
+
require 'media_types'
|
38
|
+
|
39
|
+
class Venue < MediaTypes::Base
|
40
|
+
media_type 'venue', suffix: :json, current_version: 2
|
41
|
+
|
42
|
+
current_scheme do
|
43
|
+
attribute :name, String
|
44
|
+
collection :location do
|
45
|
+
attribute :latitude, Numeric
|
46
|
+
attribute :longitude, Numeric
|
47
|
+
attribute :altitude, AllowNil(Numeric)
|
48
|
+
end
|
49
|
+
|
50
|
+
link :self
|
51
|
+
link :route, allow_nil: true
|
52
|
+
end
|
53
|
+
|
54
|
+
register_types :venue_json do
|
55
|
+
create :create_venue_json
|
56
|
+
index :venue_urls_json
|
57
|
+
collection :venue_collection_json
|
58
|
+
end
|
59
|
+
|
60
|
+
register_additional_versions do
|
61
|
+
version 1 do
|
62
|
+
attribute :name, String
|
63
|
+
attribute :coords, String
|
64
|
+
attribute :updated_at, String
|
65
|
+
|
66
|
+
link :self
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def self.base_format
|
71
|
+
'application/vnd.mydomain.%<type>s.v%<version>s%<view>s+%<suffix>s'
|
72
|
+
end
|
73
|
+
end
|
74
|
+
```
|
75
|
+
|
76
|
+
### Schema Definitions
|
77
|
+
|
78
|
+
If you define a scheme using `current_scheme { }`, you may use any of the following dsl:
|
79
|
+
|
80
|
+
- `attribute(string, klazz)`: Adds an attribute to the scheme, with the type `klazz`
|
81
|
+
- `any(&block)`: Allow for any key, which then is validated against the block (which is a scheme).
|
82
|
+
- `collection(string, &block)`: Expect a collection such as an array or hash. If it's an array, each item is validated
|
83
|
+
against the block (which is a scheme). If it's a hash, the hash is validated against the block. If you want to force an
|
84
|
+
array or an object, prepend the collection by `attribute(string, Hash)` or `attribute(string, Array)`.
|
85
|
+
- `no_strict`: Can be added to a `scheme` such as the root, block inside `any` or block inside `collection` to allow for
|
86
|
+
undefined keys. If `no_strict` is not added, the block will not be valid if there are extra keys.
|
87
|
+
- `link(string)`: Example of a domain type. Each link is actually added to a scheme for `_links` on the current scheme.
|
88
|
+
|
89
|
+
If you want to compose types, you can wrap a klazz in `AllowNil(klazz)` to allow for nil values. This makes a validation
|
90
|
+
expected that klass, or nil.
|
91
|
+
|
92
|
+
You an add your own DSL by inspecting the `lib/media_types/scheme/<klazz>` classes.
|
93
|
+
|
94
|
+
### Validation
|
95
|
+
If your type has a schema, you can now use this media type for validation:
|
96
|
+
|
97
|
+
```Ruby
|
98
|
+
Venue.valid?({ ... })
|
99
|
+
# => true if valid, false otherwise
|
100
|
+
|
101
|
+
Venue.validate!({ ... })
|
102
|
+
# => raises if it's not valid
|
103
|
+
```
|
104
|
+
|
105
|
+
### Formatting for headers
|
106
|
+
Any media type object can be coerced in valid string to be used with `Content-Type` or `Accept`:
|
107
|
+
|
108
|
+
```Ruby
|
109
|
+
|
110
|
+
Venue.mime_type.to_s
|
111
|
+
# => "application/vnd.mydomain.venue.v2+json"
|
112
|
+
|
113
|
+
Venue.mime_type.version(1).to_s
|
114
|
+
# => "application/vnd.mydomain.venue.v1+json"
|
115
|
+
|
116
|
+
Venue.mime_type.version(1).suffix(:xml).to_s
|
117
|
+
# => "application/vnd.mydomain.venue.v1+xml"
|
118
|
+
|
119
|
+
Venue.mime_type.to_s(0.2)
|
120
|
+
# => "application/vnd.mydomain.venue.v2+json; q=0.2"
|
121
|
+
|
122
|
+
Venue.mime_type.collection.to_s
|
123
|
+
# => "application/vnd.mydomain.venue.v2.collection+json"
|
124
|
+
|
125
|
+
Venue.mime_type.view('active').to_s
|
126
|
+
# => "application/vnd.mydomain.venue.v2.active+json"
|
127
|
+
```
|
128
|
+
|
129
|
+
### Register in Rails or Rack
|
130
|
+
As long as `action_dispatch` is available, you can register the mime type with `action_dispatch/http/mime_type`:
|
131
|
+
```Ruby
|
132
|
+
Venue.register
|
133
|
+
# => Mime type is now available using the symbol, or lookup the actual mimetype
|
134
|
+
```
|
135
|
+
|
136
|
+
You can do this in the `mime_types` initializer, or anywhere before your controllers are instantiated. Yes, the symbol
|
137
|
+
(by default `<type>_v<version>_<suffix>`) can now be used in your `format` blocks, or as extension in the url.
|
138
|
+
|
139
|
+
## Development
|
140
|
+
|
141
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can
|
142
|
+
also run `bin/console` for an interactive prompt that will allow you to experiment.
|
143
|
+
|
144
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the
|
145
|
+
version number in `version.rb`, call `bundle exec rake release` to create a new git tag, push git commits and tags, and
|
146
|
+
push the `.gem` file to rubygems.org.
|
147
|
+
|
148
|
+
## Contributing
|
149
|
+
|
150
|
+
Bug reports and pull requests are welcome on GitHub at [SleeplessByte/media_types-ruby](https://github.com/SleeplessByte/media_types-ruby)
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'bundler/setup'
|
5
|
+
require 'media_types'
|
6
|
+
|
7
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
8
|
+
# with your gem easier. You can also use a different console, if you like.
|
9
|
+
|
10
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
11
|
+
# require "pry"
|
12
|
+
# Pry.start
|
13
|
+
|
14
|
+
require 'irb'
|
15
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
data/lib/media_types.rb
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'media_types/version'
|
4
|
+
require 'media_types/base'
|
5
|
+
require 'media_types/scheme'
|
6
|
+
|
7
|
+
require 'delegate'
|
8
|
+
|
9
|
+
module MediaTypes
|
10
|
+
COLLECTION_VIEW = 'collection'
|
11
|
+
INDEX_VIEW = 'index'
|
12
|
+
CREATE_VIEW = 'create'
|
13
|
+
|
14
|
+
module_function
|
15
|
+
|
16
|
+
def register(mime_type:, symbol: nil, synonyms: [])
|
17
|
+
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
|
+
|
26
|
+
def ===(other)
|
27
|
+
__getobj__ === other # rubocop:disable Style/CaseEquality
|
28
|
+
end
|
29
|
+
|
30
|
+
def blank?
|
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
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
|
@@ -0,0 +1,193 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'media_types/base/collector'
|
4
|
+
require 'media_types/constructable_mime_type'
|
5
|
+
require 'media_types/scheme'
|
6
|
+
|
7
|
+
module MediaTypes
|
8
|
+
class Base
|
9
|
+
|
10
|
+
class << self
|
11
|
+
##
|
12
|
+
# Registers all configured mime types
|
13
|
+
#
|
14
|
+
def register(**overrides)
|
15
|
+
override_version = overrides.delete(:version)
|
16
|
+
if override_version
|
17
|
+
self.versions_ = { override_version => { scheme: (overrides.delete(:scheme) || current_scheme_) } }
|
18
|
+
end
|
19
|
+
|
20
|
+
Array(registers_).map do |registered|
|
21
|
+
resolvable = registered.merge(Hash(overrides))
|
22
|
+
mime_type = construct_mime_type(resolvable)
|
23
|
+
|
24
|
+
resolve_versions(resolvable) do |version, symbol:|
|
25
|
+
MediaTypes.register(
|
26
|
+
mime_type: mime_type.version(version).to_s,
|
27
|
+
symbol: symbol,
|
28
|
+
synonyms: versioned_synonyms(version, resolvable)
|
29
|
+
)
|
30
|
+
symbol
|
31
|
+
end
|
32
|
+
end.flatten.compact
|
33
|
+
end
|
34
|
+
|
35
|
+
##
|
36
|
+
# Get the constructable mime type for this class
|
37
|
+
#
|
38
|
+
# @return [ConstructableMimeType]
|
39
|
+
#
|
40
|
+
def mime_type(type: type_, version: current_version_, suffix: suffix_, view: nil)
|
41
|
+
ConstructableMimeType.new(self, format: base_format, version: version, suffix: suffix, type: type, view: view)
|
42
|
+
end
|
43
|
+
|
44
|
+
def current_version
|
45
|
+
current_version_
|
46
|
+
end
|
47
|
+
|
48
|
+
def valid?(output, version: current_version, **opts)
|
49
|
+
scheme = version_scheme(version: version)
|
50
|
+
!scheme || scheme.valid?(output, backtrace: ['.'], **opts)
|
51
|
+
end
|
52
|
+
|
53
|
+
def validate!(output, version: current_version, **opts)
|
54
|
+
scheme = version_scheme(version: version)
|
55
|
+
scheme.validate(output, backtrace: ['.'], **opts)
|
56
|
+
end
|
57
|
+
|
58
|
+
protected
|
59
|
+
|
60
|
+
attr_accessor :type_, :suffix_, :registers_, :versions_, :type_aliases_, :current_version_, :current_scheme_
|
61
|
+
|
62
|
+
def base_format
|
63
|
+
NotImplementedError.new('Implementors of MediaType::Base must override base_format')
|
64
|
+
end
|
65
|
+
|
66
|
+
##
|
67
|
+
# Configure the media type
|
68
|
+
#
|
69
|
+
# @param [String] media_type the +type+ part of the media type
|
70
|
+
# @param [Symbol, String, NilClass] suffix the +suffix+ part of the media type
|
71
|
+
# @param [Array<String>] aliases the aliases of +media_type+
|
72
|
+
# @param [Number, String] version the latest version
|
73
|
+
#
|
74
|
+
def media_type(media_type, suffix: nil, aliases: [], current_version: nil, version: current_version, &block)
|
75
|
+
self.type_ = media_type
|
76
|
+
self.type_aliases_ = aliases
|
77
|
+
self.suffix_ = suffix
|
78
|
+
|
79
|
+
self.current_version_ = version
|
80
|
+
self.current_scheme_ = current_scheme(&block)
|
81
|
+
end
|
82
|
+
|
83
|
+
def current_scheme(&block)
|
84
|
+
scheme = Scheme.new
|
85
|
+
scheme.instance_exec(&block) if block_given?
|
86
|
+
|
87
|
+
self.current_scheme_ = scheme
|
88
|
+
end
|
89
|
+
|
90
|
+
##
|
91
|
+
# Start registering media types
|
92
|
+
#
|
93
|
+
# @param [Symbol] opts optional symbol
|
94
|
+
# @option options [Symbol] symbol the symbol to register as if not given by +opts+
|
95
|
+
# @option options [Number] version the version to register for defaults to +current_version_+
|
96
|
+
# @option options [String, NilClass] view the view of the registered type
|
97
|
+
# @option options [String] synonyms synonyms to resolve to the same type
|
98
|
+
#
|
99
|
+
# @yieldparam [Collector] the collector to collect views for the media type
|
100
|
+
#
|
101
|
+
def register_types(*opts, **options, &block)
|
102
|
+
version = options.delete(:version)
|
103
|
+
symbol_suffix = options.delete(:symbol_suffix)
|
104
|
+
|
105
|
+
register_type(*opts, **options)
|
106
|
+
register_version(version || current_version_, symbol_suffix: symbol_suffix, scheme: current_scheme_)
|
107
|
+
|
108
|
+
return unless block_given?
|
109
|
+
block_collector(&block)
|
110
|
+
end
|
111
|
+
|
112
|
+
def register_additional_versions(&block)
|
113
|
+
block_collector(&block)
|
114
|
+
end
|
115
|
+
|
116
|
+
private
|
117
|
+
|
118
|
+
def block_collector(&block)
|
119
|
+
collector = Collector.new(self)
|
120
|
+
|
121
|
+
case block.arity
|
122
|
+
when 1, -1
|
123
|
+
collector.instance_exec(collector, &block)
|
124
|
+
else
|
125
|
+
collector.instance_exec(&block)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
# @param [Symbol] opts optional symbol
|
130
|
+
# @param [Symbol] symbol the symbol to register as if not given by +opts+
|
131
|
+
# @param [String, NilClass] view the view of the registered type
|
132
|
+
# @param [String] synonyms synonyms to resolve to the same type
|
133
|
+
# rubocop:disable Metrics/ParameterLists
|
134
|
+
def register_type(*opts, suffix: suffix_, view: nil, symbol: nil, synonyms: [], version: nil)
|
135
|
+
symbol = opts&.first || symbol
|
136
|
+
self.registers_ = Array(registers_).push(
|
137
|
+
symbol: symbol,
|
138
|
+
view: view,
|
139
|
+
synonyms: synonyms,
|
140
|
+
suffix: suffix,
|
141
|
+
pinned_version: version
|
142
|
+
)
|
143
|
+
end
|
144
|
+
# rubocop:enable Metrics/ParameterLists
|
145
|
+
|
146
|
+
def construct_mime_type(type: type_, **resolvable)
|
147
|
+
mime_type(type: type, **MediaTypes::Hash.new(resolvable).slice(:version, :view, :suffix))
|
148
|
+
end
|
149
|
+
|
150
|
+
def synonyms(resolvable)
|
151
|
+
aliases = type_aliases_.map { |type_alias| construct_mime_type(type: type_alias, **resolvable) }
|
152
|
+
|
153
|
+
Array(resolvable[:synonyms]).concat(aliases)
|
154
|
+
end
|
155
|
+
|
156
|
+
def register_version(version, symbol_suffix: :"_v#{version}", scheme: Scheme.new, &block)
|
157
|
+
scheme.instance_exec(&block) if block_given?
|
158
|
+
|
159
|
+
self.versions_ = Hash(versions_).merge(
|
160
|
+
version => {
|
161
|
+
symbol_suffix: symbol_suffix,
|
162
|
+
scheme: scheme
|
163
|
+
}
|
164
|
+
)
|
165
|
+
end
|
166
|
+
|
167
|
+
def resolve_versions(**resolvable)
|
168
|
+
pinned_version = resolvable[:pinned_version]
|
169
|
+
|
170
|
+
versions.map do |version, opts|
|
171
|
+
next if pinned_version && pinned_version != version
|
172
|
+
yield version, symbol: :"#{resolvable.fetch(:symbol)}#{opts[:symbol_suffix]}"
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
def versioned_synonyms(version, resolvable)
|
177
|
+
synonyms(resolvable).map do |synonym|
|
178
|
+
synonym.is_a?(String) ? synonym : synonym.version(version).to_s
|
179
|
+
end.uniq
|
180
|
+
end
|
181
|
+
|
182
|
+
def versions
|
183
|
+
{ current_version => { scheme: current_scheme_ } }.merge(Hash(versions_))
|
184
|
+
end
|
185
|
+
|
186
|
+
def version_scheme(version:)
|
187
|
+
version_data = versions[version]
|
188
|
+
return nil unless version_data
|
189
|
+
version_data[:scheme] || nil
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|