media_types 0.4.1 → 0.5.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ccae096fd19259b025952edea85f433588fbce01
4
- data.tar.gz: 64fed267722b36d17a324eb9ebb436be04bfc412
3
+ metadata.gz: 54061285d1504ab09d4fc7299bf242ad4e0a7529
4
+ data.tar.gz: d1cff5bf120ff2f5cd570887f3e351117466e54e
5
5
  SHA512:
6
- metadata.gz: 118d4c8c2c67070cd0c5469a5330a95b954993db1773a9da633ff0e58370623732fb0236126d64eadc9869ab1ccd612ddfccef8c39dc4ddc4fa0a64c642903ba
7
- data.tar.gz: 68cf8356ab79b25ba2edf5c20cb1dcae36bb2c9ccf278529643aee6a90aec7d7a4d1599e608a689a460962a062dce586a7649d8a0240cb1994cc7de0b3e7e034
6
+ metadata.gz: 283abdbba4639fbabb39223ed943c495289a2a2f607055e1c00d1b789d6612d604d3de5b7bf4d4e5d644acd9e4d46316e2e92319354f71278059f0c42697b5eb
7
+ data.tar.gz: 2a57915b68ebab50f5820ee472499aea29d9bbeaa17f5cab416419c8ab3acba7f094c1934c50e2458b9c3728f71c5c6f845de6ec6e6e55bac666143ff48030dd
data/CHANGELOG.md CHANGED
@@ -1,3 +1,22 @@
1
+ # 0.5.0
2
+
3
+ - Change internal representation of key to symbol
4
+ - Change default type from `nil` to `Object`, removing special behaviour for nil
5
+ - Add `Rules` class to handle normalization of keys and handling `rules` (`Scheme`, `Attribute`, etc)
6
+ - Add guard classes to handle guard behaviour (`OutputEmptyGuard`, `OutputTypeGuard` and `RulesExhaustedGuard`)
7
+ - Add `optional:` keywords to most dsl (`attribute`, `collection`, `any`, `link`)
8
+ - Add `Formatter` class to handle formatting of the `Constructable#to_s`
9
+ - Add behaviour to strip leading dot (`.`) or plus (`+`) from `+%<var>` if `var` is nil, fixing weird media types
10
+ - Add behaviour to remove format variable values if format variable is not present, fixing warnings
11
+ - Add `inspect` for most public classes
12
+ - Add second argument for type or scheme to `any` dsl, mimicking `collection`
13
+ - Add tests for most dsl, common permutations
14
+ - Rename `force` to `expected_type`
15
+ - Remove `format_view` behaviour where it adds a dot (`.`) if a view is present
16
+ - Remove special iteration behaviour for `Links` (`link` dsl), allowing them to be optional, or non-exhaustive
17
+ - Raise error if `self.base_format` is not available at time of `Dsl.media_type` call
18
+ - Fix `expected_type` guard for arrays, nil, or arrays with nil.
19
+
1
20
  # 0.4.1
2
21
 
3
22
  - Use strings for `:_links`, matching the other validation keys
data/Gemfile.lock CHANGED
@@ -1,44 +1,44 @@
1
- PATH
2
- remote: .
3
- specs:
4
- media_types (0.4.1)
5
-
6
- GEM
7
- remote: https://rubygems.org/
8
- specs:
9
- ansi (1.5.0)
10
- awesome_print (1.8.0)
11
- builder (3.2.3)
12
- docile (1.3.1)
13
- json (2.1.0)
14
- minitest (5.11.3)
15
- minitest-ci (3.4.0)
16
- minitest (>= 5.0.6)
17
- minitest-reporters (1.3.4)
18
- ansi
19
- builder
20
- minitest (>= 5.0)
21
- ruby-progressbar
22
- rake (10.5.0)
23
- ruby-progressbar (1.10.0)
24
- simplecov (0.16.1)
25
- docile (~> 1.1)
26
- json (>= 1.8, < 3)
27
- simplecov-html (~> 0.10.0)
28
- simplecov-html (0.10.2)
29
-
30
- PLATFORMS
31
- x64-mingw32
32
-
33
- DEPENDENCIES
34
- awesome_print
35
- bundler (~> 1.16)
36
- media_types!
37
- minitest (~> 5.0)
38
- minitest-ci
39
- minitest-reporters
40
- rake (~> 10.0)
41
- simplecov
42
-
43
- BUNDLED WITH
44
- 1.16.4
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ media_types (0.5.0)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ ansi (1.5.0)
10
+ awesome_print (1.8.0)
11
+ builder (3.2.3)
12
+ docile (1.3.1)
13
+ json (2.1.0)
14
+ minitest (5.11.3)
15
+ minitest-ci (3.4.0)
16
+ minitest (>= 5.0.6)
17
+ minitest-reporters (1.3.4)
18
+ ansi
19
+ builder
20
+ minitest (>= 5.0)
21
+ ruby-progressbar
22
+ rake (10.5.0)
23
+ ruby-progressbar (1.10.0)
24
+ simplecov (0.16.1)
25
+ docile (~> 1.1)
26
+ json (>= 1.8, < 3)
27
+ simplecov-html (~> 0.10.0)
28
+ simplecov-html (0.10.2)
29
+
30
+ PLATFORMS
31
+ x64-mingw32
32
+
33
+ DEPENDENCIES
34
+ awesome_print
35
+ bundler (~> 1.16)
36
+ media_types!
37
+ minitest (~> 5.0)
38
+ minitest-ci
39
+ minitest-reporters
40
+ rake (~> 10.0)
41
+ simplecov
42
+
43
+ BUNDLED WITH
44
+ 1.16.4
data/README.md CHANGED
@@ -1,347 +1,379 @@
1
- # MediaTypes
2
- [![Build Status](https://travis-ci.com/SleeplessByte/media-types-ruby.svg?branch=master)](https://travis-ci.com/SleeplessByte/media-types-ruby)
3
- [![Gem Version](https://badge.fury.io/rb/media_types.svg)](https://badge.fury.io/rb/media_types)
4
- [![MIT license](http://img.shields.io/badge/license-MIT-brightgreen.svg)](http://opensource.org/licenses/MIT)
5
- [![Maintainability](https://api.codeclimate.com/v1/badges/6f2dc1fb37ecb98c4363/maintainability)](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', defaults: { suffix: :json, version: 2 }
41
-
42
- validations 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
-
53
- version 1 do
54
- attribute :name, String
55
- attribute :coords, String
56
- attribute :updated_at, String
57
-
58
- link :self
59
- end
60
-
61
- view 'create' do
62
- collection :location do
63
- attribute :latitude, Numeric
64
- attribute :longitude, Numeric
65
- attribute :altitude, AllowNil(Numeric)
66
- end
67
-
68
- version 1 do
69
- collection :location do
70
- attribute :latitude, Numeric
71
- attribute :longitude, Numeric
72
- attribute :altitude, AllowNil(Numeric)
73
- end
74
- end
75
- end
76
- end
77
-
78
- registrations :venue_json do
79
- view 'create', :create_venue
80
- view 'index', :venue_urls
81
- view 'collection', :venue_collection
82
-
83
- versions [1,2]
84
-
85
- suffix :json
86
- suffix :xml
87
- end
88
-
89
- def self.base_format
90
- 'application/vnd.mydomain.%<type>s.v%<version>s%<view>s+%<suffix>s'
91
- end
92
- end
93
- ```
94
-
95
- ## Schema Definitions
96
-
97
- If you define a scheme using `current_scheme { }`, you may use any of the following dsl:
98
-
99
- ### `attribute`
100
-
101
- Adds an attribute to the schema, if a +block+ is given, uses that to test against instead of +type+
102
-
103
- | param | type | description |
104
- |-------|------|-------------|
105
- | key | `Symbol` | the attribute name |
106
- | opts | `Hash` | options to pass to `Scheme` or `Attribute` |
107
- | type | `Class`, `===`, Scheme | The type of the value, can be anything that responds to `===`, or scheme to use if no `&block` is given. Defaults to `String` without a `&block` and to Hash with a `&block`. |
108
- | &block | `Block` | defines the scheme of the value of this attribute |
109
-
110
- #### Add an attribute named foo, expecting a string
111
- ```Ruby
112
- require 'media_types'
113
-
114
- class MyMedia
115
- include MediaTypes::Dsl
116
-
117
- validations do
118
- attribute :foo, String
119
- end
120
- end
121
-
122
- MyMedia.valid?({ foo: 'my-string' })
123
- # => true
124
- ```
125
-
126
- #### Add an attribute named foo, expecting nested scheme
127
-
128
- ```Ruby
129
- class MyMedia
130
- include MediaTypes::Dsl
131
-
132
- validations do
133
- attribute :foo do
134
- attribute :bar, String
135
- end
136
- end
137
- end
138
-
139
- MyMedia.valid?({ foo: { bar: 'my-string' }})
140
- # => true
141
- ```
142
-
143
- ### `any`
144
- Allow for any key. The `&block` defines the Schema for each value.
145
-
146
- | param | type | description |
147
- |-------|------|-------------|
148
- | scheme | `Scheme`, `NilClass` | scheme to use if no `&block` is given |
149
- | allow_empty: | `TrueClass`, `FalsClass` | if true, empty (no key/value present) is allowed |
150
- | force: | `Class`, | forces the validated value to have this type, defaults to `Hash` |
151
- | &block | `Block` | defines the scheme of the value of this attribute |
152
-
153
- #### Add a collection named foo, expecting any key with a defined value
154
- ```Ruby
155
- class MyMedia
156
- include MediaTypes::Dsl
157
-
158
- validations do
159
- collection :foo do
160
- any do
161
- attribute :bar, String
162
- end
163
- end
164
- end
165
- end
166
-
167
- MyMedia.valid?({ foo: [{ anything: { bar: 'my-string' }, other_thing: { bar: 'other-string' } }] })
168
- # => true
169
- ````
170
-
171
- ### `not_strict`
172
- Allow for extra keys in the schema/collection even when passing `strict: true` to `#validate!`
173
-
174
- #### Allow for extra keys in collection
175
-
176
- ```Ruby
177
- class MyMedia
178
- include MediaTypes::Dsl
179
-
180
- validations do
181
- collection :foo do
182
- attribute :required, String
183
- not_strict
184
- end
185
- end
186
- end
187
-
188
- MyMedia.valid?({ foo: [{ required: 'test', bar: 42 }] })
189
- # => true
190
- ```
191
-
192
- ### `collection`
193
- Expect a collection such as an array or hash. The `&block` defines the Schema for each item in that collection.
194
-
195
- | param | type | description |
196
- |-------|------|-------------|
197
- | key | `Symbol` | key of the collection (same as `#attribute`) |
198
- | scheme | `Scheme`, `NilClass`, `Class` | scheme to use if no `&block` is given or `Class` of each item in the |
199
- | allow_empty: | `TrueClass`, `FalsClass` | if true, empty (no key/value present) is allowed |
200
- | force: | `Class`, | forces the validated value to have this type, defaults to `Array` |
201
- | &block | `Block` | defines the scheme of the value of this attribute |
202
-
203
-
204
- #### Collection with an array of string
205
- ```Ruby
206
- class MyMedia
207
- include MediaTypes::Dsl
208
-
209
- validations do
210
- collection :foo, String
211
- end
212
- end
213
-
214
- MyMedia.valid?({ collection: ['foo', 'bar'] })
215
- # => true
216
- ```
217
-
218
- #### Collection with defined scheme
219
-
220
- ```Ruby
221
- class MyMedia
222
- include MediaTypes::Dsl
223
-
224
- validations do
225
- collection :foo do
226
- attribute :required, String
227
- attribute :number, Numeric
228
- end
229
- end
230
- end
231
-
232
- MyMedia.valid?({ foo: [{ required: 'test', number: 42 }, { required: 'other', number: 0 }] })
233
- # => true
234
- ```
235
-
236
- ### `link`
237
-
238
- Expect a link
239
-
240
- #### Links as defined in HAL, JSON-Links and other specs
241
- ```Ruby
242
- class MyMedia
243
- include MediaTypes::Dsl
244
-
245
- validations do
246
- link :_self
247
- link :image
248
- end
249
- end
250
-
251
- MyMedia.valid?({ _links: { self: { href: 'https://example.org/s' }, image: { href: 'https://image.org/i' }} })
252
- # => true
253
- ```
254
-
255
-
256
- #### Link with extra attributes
257
- ```Ruby
258
- class MyMedia
259
- include MediaTypes::Dsl
260
-
261
- validations do
262
- link :image do
263
- attribute :templated, TrueClass
264
- end
265
- end
266
- end
267
-
268
- MyMedia.valid?({ _links: { self: { href: 'https://example.org/s' }, image: { href: 'https://image.org/i' }} })
269
- # => true
270
- ```
271
-
272
- #### Link with extra attributes
273
- ```Ruby
274
- class MyMedia
275
- include MediaTypes::Dsl
276
-
277
- validations do
278
- link :image do
279
- attribute :templated, TrueClass
280
- end
281
- end
282
- end
283
-
284
- MyMedia.valid?({ _links: { image: { href: 'https://image.org/{md5}', templated: true }} })
285
- # => true
286
- ```
287
-
288
- ## Validation
289
- If your type has a validations, you can now use this media type for validation:
290
-
291
- ```Ruby
292
- Venue.valid?({ ... })
293
- # => true if valid, false otherwise
294
-
295
- Venue.validate!({ ... })
296
- # => raises if it's not valid
297
- ```
298
-
299
- ## Formatting for headers
300
- Any media type object can be coerced in valid string to be used with `Content-Type` or `Accept`:
301
-
302
- ```Ruby
303
- Venue.mime_type.to_s
304
- # => "application/vnd.mydomain.venue.v2+json"
305
-
306
- Venue.mime_type.version(1).to_s
307
- # => "application/vnd.mydomain.venue.v1+json"
308
-
309
- Venue.mime_type.version(1).suffix(:xml).to_s
310
- # => "application/vnd.mydomain.venue.v1+xml"
311
-
312
- Venue.mime_type.to_s(0.2)
313
- # => "application/vnd.mydomain.venue.v2+json; q=0.2"
314
-
315
- Venue.mime_type.collection.to_s
316
- # => "application/vnd.mydomain.venue.v2.collection+json"
317
-
318
- Venue.mime_type.view('active').to_s
319
- # => "application/vnd.mydomain.venue.v2.active+json"
320
- ```
321
-
322
- ## Register in Rails or Rack
323
- Define a `registrations` block on your media type, indicating the symbol for the base type (`registrations :symbol do`)
324
- and inside use the registrations dsl to define which media types to register. `versions array_of_numbers` determines which versions,
325
- `suffix name` adds a suffix, `type_alias name` adds an alias and `view name, symbol` adds a view.
326
-
327
- As long as `action_dispatch` is available, you can register the mime type with `action_dispatch/http/mime_type`:
328
- ```Ruby
329
- Venue.register
330
- # => Mime type is now available using the symbol, or lookup the actual mimetype
331
- ```
332
-
333
- You can do this in the `mime_types` initializer, or anywhere before your controllers are instantiated. Yes, the symbol
334
- (by default `<type>_v<version>_<suffix>`) can now be used in your `format` blocks, or as extension in the url.
335
-
336
- ## Development
337
-
338
- After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can
339
- also run `bin/console` for an interactive prompt that will allow you to experiment.
340
-
341
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the
342
- version number in `version.rb`, call `bundle exec rake release` to create a new git tag, push git commits and tags, and
343
- push the `.gem` file to rubygems.org.
344
-
345
- ## Contributing
346
-
347
- Bug reports and pull requests are welcome on GitHub at [SleeplessByte/media-types-ruby](https://github.com/SleeplessByte/media-types-ruby)
1
+ # MediaTypes
2
+ [![Build Status](https://travis-ci.com/SleeplessByte/media-types-ruby.svg?branch=master)](https://travis-ci.com/SleeplessByte/media-types-ruby)
3
+ [![Gem Version](https://badge.fury.io/rb/media_types.svg)](https://badge.fury.io/rb/media_types)
4
+ [![MIT license](http://img.shields.io/badge/license-MIT-brightgreen.svg)](http://opensource.org/licenses/MIT)
5
+ [![Maintainability](https://api.codeclimate.com/v1/badges/6f2dc1fb37ecb98c4363/maintainability)](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', defaults: { suffix: :json, version: 2 }
41
+
42
+ validations 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
+
53
+ version 1 do
54
+ attribute :name, String
55
+ attribute :coords, String
56
+ attribute :updated_at, String
57
+
58
+ link :self
59
+ end
60
+
61
+ view 'create' do
62
+ collection :location do
63
+ attribute :latitude, Numeric
64
+ attribute :longitude, Numeric
65
+ attribute :altitude, AllowNil(Numeric)
66
+ end
67
+
68
+ version 1 do
69
+ collection :location do
70
+ attribute :latitude, Numeric
71
+ attribute :longitude, Numeric
72
+ attribute :altitude, AllowNil(Numeric)
73
+ end
74
+ end
75
+ end
76
+ end
77
+
78
+ registrations :venue_json do
79
+ view 'create', :create_venue
80
+ view 'index', :venue_urls
81
+ view 'collection', :venue_collection
82
+
83
+ versions [1,2]
84
+
85
+ suffix :json
86
+ suffix :xml
87
+ end
88
+
89
+ def self.base_format
90
+ 'application/vnd.mydomain.%<type>s.v%<version>.s%<view>s+%<suffix>s'
91
+ end
92
+ end
93
+ ```
94
+
95
+ ## Schema Definitions
96
+
97
+ If you define a scheme using `current_scheme { }`, you may use any of the following dsl:
98
+
99
+ ### `attribute`
100
+
101
+ Adds an attribute to the schema, if a +block+ is given, uses that to test against instead of +type+
102
+
103
+ | param | type | description |
104
+ |-------|------|-------------|
105
+ | key | `Symbol` | the attribute name |
106
+ | opts | `Hash` | options to pass to `Scheme` or `Attribute` |
107
+ | type | `Class`, `===`, Scheme | The type of the value, can be anything that responds to `===`, or scheme to use if no `&block` is given. Defaults to `String` without a `&block` and to Hash with a `&block`. |
108
+ | optional: | `TrueClass`, `FalseClass` | if true, key may be absent, defaults to `false` |
109
+ | &block | `Block` | defines the scheme of the value of this attribute |
110
+
111
+ #### Add an attribute named foo, expecting a string
112
+ ```Ruby
113
+ require 'media_types'
114
+
115
+ class MyMedia
116
+ include MediaTypes::Dsl
117
+
118
+ validations do
119
+ attribute :foo, String
120
+ end
121
+ end
122
+
123
+ MyMedia.valid?({ foo: 'my-string' })
124
+ # => true
125
+ ```
126
+
127
+ #### Add an attribute named foo, expecting nested scheme
128
+
129
+ ```Ruby
130
+ class MyMedia
131
+ include MediaTypes::Dsl
132
+
133
+ validations do
134
+ attribute :foo do
135
+ attribute :bar, String
136
+ end
137
+ end
138
+ end
139
+
140
+ MyMedia.valid?({ foo: { bar: 'my-string' }})
141
+ # => true
142
+ ```
143
+
144
+ ### `any`
145
+ Allow for any key. The `&block` defines the Schema for each value.
146
+
147
+ | param | type | description |
148
+ |-------|------|-------------|
149
+ | scheme | `Scheme`, `NilClass` | scheme to use if no `&block` is given |
150
+ | allow_empty: | `TrueClass`, `FalsClass` | if true, empty (no key/value present) is allowed |
151
+ | expected_type: | `Class`, | forces the validated value to have this type, defaults to `Hash`. Use `Object` if either `Hash` or `Array` is fine |
152
+ | &block | `Block` | defines the scheme of the value of this attribute |
153
+
154
+ #### Add a collection named foo, expecting any key with a defined value
155
+ ```Ruby
156
+ class MyMedia
157
+ include MediaTypes::Dsl
158
+
159
+ validations do
160
+ collection :foo do
161
+ any do
162
+ attribute :bar, String
163
+ end
164
+ end
165
+ end
166
+ end
167
+
168
+ MyMedia.valid?({ foo: [{ anything: { bar: 'my-string' }, other_thing: { bar: 'other-string' } }] })
169
+ # => true
170
+ ````
171
+
172
+ ### `not_strict`
173
+ Allow for extra keys in the schema/collection even when passing `strict: true` to `#validate!`
174
+
175
+ #### Allow for extra keys in collection
176
+
177
+ ```Ruby
178
+ class MyMedia
179
+ include MediaTypes::Dsl
180
+
181
+ validations do
182
+ collection :foo do
183
+ attribute :required, String
184
+ not_strict
185
+ end
186
+ end
187
+ end
188
+
189
+ MyMedia.valid?({ foo: [{ required: 'test', bar: 42 }] })
190
+ # => true
191
+ ```
192
+
193
+ ### `collection`
194
+ Expect a collection such as an array or hash. The `&block` defines the Schema for each item in that collection.
195
+
196
+ | param | type | description |
197
+ |-------|------|-------------|
198
+ | key | `Symbol` | key of the collection (same as `#attribute`) |
199
+ | scheme | `Scheme`, `NilClass`, `Class` | scheme to use if no `&block` is given or `Class` of each item in the |
200
+ | allow_empty: | `TrueClass`, `FalseClass` | if true, empty (no key/value present) is allowed |
201
+ | expected_type: | `Class`, | forces the validated value to have this type, defaults to `Array`. Use `Object` if either `Array` or `Hash` is fine. |
202
+ | optional: | `TrueClass`, `FalseClass` | if true, key may be absent, defaults to `false` |
203
+ | &block | `Block` | defines the scheme of the value of this attribute |
204
+
205
+
206
+ #### Collection with an array of string
207
+ ```Ruby
208
+ class MyMedia
209
+ include MediaTypes::Dsl
210
+
211
+ validations do
212
+ collection :foo, String
213
+ end
214
+ end
215
+
216
+ MyMedia.valid?({ collection: ['foo', 'bar'] })
217
+ # => true
218
+ ```
219
+
220
+ #### Collection with defined scheme
221
+
222
+ ```Ruby
223
+ class MyMedia
224
+ include MediaTypes::Dsl
225
+
226
+ validations do
227
+ collection :foo do
228
+ attribute :required, String
229
+ attribute :number, Numeric
230
+ end
231
+ end
232
+ end
233
+
234
+ MyMedia.valid?({ foo: [{ required: 'test', number: 42 }, { required: 'other', number: 0 }] })
235
+ # => true
236
+ ```
237
+
238
+ ### `link`
239
+
240
+ Expect a link with a required `href: String` attribute
241
+
242
+ | param | type | description |
243
+ |-------|------|-------------|
244
+ | key | `Symbol` | key of the link (same as `#attribute`) |
245
+ | allow_nil: | `TrueClass`, `FalseClass` | if true, value may be nil |
246
+ | optional: | `TrueClass`, `FalseClass` | if true, key may be absent, defaults to `false` |
247
+ | &block | `Block` | defines the scheme of the value of this attribute, in addition to the `href` attribute |
248
+
249
+ #### Links as defined in HAL, JSON-Links and other specs
250
+ ```Ruby
251
+ class MyMedia
252
+ include MediaTypes::Dsl
253
+
254
+ validations do
255
+ link :_self
256
+ link :image
257
+ end
258
+ end
259
+
260
+ MyMedia.valid?({ _links: { self: { href: 'https://example.org/s' }, image: { href: 'https://image.org/i' }} })
261
+ # => true
262
+ ```
263
+
264
+
265
+ #### Link with extra attributes
266
+ ```Ruby
267
+ class MyMedia
268
+ include MediaTypes::Dsl
269
+
270
+ validations do
271
+ link :image do
272
+ attribute :templated, TrueClass
273
+ end
274
+ end
275
+ end
276
+
277
+ MyMedia.valid?({ _links: { self: { href: 'https://example.org/s' }, image: { href: 'https://image.org/i' }} })
278
+ # => true
279
+ ```
280
+
281
+ #### Link with extra attributes
282
+ ```Ruby
283
+ class MyMedia
284
+ include MediaTypes::Dsl
285
+
286
+ validations do
287
+ link :image do
288
+ attribute :templated, TrueClass
289
+ end
290
+ end
291
+ end
292
+
293
+ MyMedia.valid?({ _links: { image: { href: 'https://image.org/{md5}', templated: true }} })
294
+ # => true
295
+ ```
296
+
297
+ ## Validation
298
+ If your type has a validations, you can now use this media type for validation:
299
+
300
+ ```Ruby
301
+ Venue.valid?({
302
+ #...
303
+ })
304
+ # => true if valid, false otherwise
305
+
306
+ Venue.validate!({
307
+ # /*...*/
308
+ })
309
+ # => raises if it's not valid
310
+ ```
311
+
312
+ If an array is passed, check the scheme for each value, unless the scheme is defined as expecting a hash:
313
+ ```Ruby
314
+ expected_hash = Scheme.new(expected_type: Hash) { attribute(:foo) }
315
+ expected_object = Scheme.new { attribute(:foo) }
316
+
317
+ expected_hash.valid?({ foo: 'string' })
318
+ # => true
319
+
320
+ expected_hash.valid?([{ foo: 'string' }])
321
+ # => false
322
+
323
+
324
+ expected_object.valid?({ foo: 'string' })
325
+ # => true
326
+
327
+ expected_object.valid?([{ foo: 'string' }])
328
+ # => true
329
+ ```
330
+
331
+ ## Formatting for headers
332
+ Any media type object can be coerced in valid string to be used with `Content-Type` or `Accept`:
333
+
334
+ ```Ruby
335
+ Venue.mime_type.to_s
336
+ # => "application/vnd.mydomain.venue.v2+json"
337
+
338
+ Venue.mime_type.version(1).to_s
339
+ # => "application/vnd.mydomain.venue.v1+json"
340
+
341
+ Venue.mime_type.version(1).suffix(:xml).to_s
342
+ # => "application/vnd.mydomain.venue.v1+xml"
343
+
344
+ Venue.mime_type.to_s(0.2)
345
+ # => "application/vnd.mydomain.venue.v2+json; q=0.2"
346
+
347
+ Venue.mime_type.collection.to_s
348
+ # => "application/vnd.mydomain.venue.v2.collection+json"
349
+
350
+ Venue.mime_type.view('active').to_s
351
+ # => "application/vnd.mydomain.venue.v2.active+json"
352
+ ```
353
+
354
+ ## Register in Rails or Rack
355
+ Define a `registrations` block on your media type, indicating the symbol for the base type (`registrations :symbol do`)
356
+ and inside use the registrations dsl to define which media types to register. `versions array_of_numbers` determines which versions,
357
+ `suffix name` adds a suffix, `type_alias name` adds an alias and `view name, symbol` adds a view.
358
+
359
+ As long as `action_dispatch` is available, you can register the mime type with `action_dispatch/http/mime_type`:
360
+ ```Ruby
361
+ Venue.register
362
+ # => Mime type is now available using the symbol, or lookup the actual mimetype
363
+ ```
364
+
365
+ You can do this in the `mime_types` initializer, or anywhere before your controllers are instantiated. Yes, the symbol
366
+ (by default `<type>_v<version>_<suffix>`) can now be used in your `format` blocks, or as extension in the url.
367
+
368
+ ## Development
369
+
370
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can
371
+ also run `bin/console` for an interactive prompt that will allow you to experiment.
372
+
373
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the
374
+ version number in `version.rb`, call `bundle exec rake release` to create a new git tag, push git commits and tags, and
375
+ push the `.gem` file to rubygems.org.
376
+
377
+ ## Contributing
378
+
379
+ Bug reports and pull requests are welcome on GitHub at [SleeplessByte/media-types-ruby](https://github.com/SleeplessByte/media-types-ruby)