rschema 3.0.1.pre5 → 3.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2e570ef90c1907cc057e0b5edf7cd2bac22ace47
4
- data.tar.gz: 05039b6e5b72eea3f86b0fa1295f61055dab7a16
3
+ metadata.gz: e971b0b2b3d6a20e7d3a4d30c0426ea3f58e02f7
4
+ data.tar.gz: a1cacce7540b7a25698c48e5aa1f57847dc55a85
5
5
  SHA512:
6
- metadata.gz: 111ad7ee2f51e27bd18636566d108d5313367ea77c1ffcc11db890db571e1887712af9fab9d35d7a27e57bb6cb314f3358f662e8322d0bc849e05f3c4e61a9d9
7
- data.tar.gz: 2434658702e5ea3b87ba91cea91868d01f30bdcee10a430cf3fc3a5669f4126167cf7fc2a7f971c53136cdfdb59d749441e375ebf9d2145a4ce76e988eb54851
6
+ metadata.gz: 05194c41bc61d36b6ebacc94583ab20fa693e8ad3d3cd69858fcdcd3ac110b73e5953180f8fbc9f5f18b3fa9099f210c925136feb08a90cf27efa4c28463e17f
7
+ data.tar.gz: 2f446b9473c06e7ad75ee426a872ec6843271a86b594d87dc07a282b50b51878ac8cbd9ec512cf1a010c55a0d36faf64c517506ea83ba21c7deb17edd9893fd9
data/README.md CHANGED
@@ -22,7 +22,7 @@ First you create a schema:
22
22
 
23
23
  blog_post_schema = RSchema.define_hash {{
24
24
  title: _String,
25
- tags: Array(_Symbol),
25
+ tags: array(_Symbol),
26
26
  body: _String,
27
27
  }}
28
28
 
@@ -33,59 +33,58 @@ Then you can use the schema to validate data:
33
33
  tags: [:trick, :developers, :unbeleivable],
34
34
  body: '<p>blah blah</p>'
35
35
  }
36
- blog_post_schema.call(input).valid? #=> true
36
+ blog_post_schema.valid?(input) #=> true
37
37
 
38
38
  What Is A Schema?
39
39
  -----------------
40
40
 
41
41
  Schemas are objects that _describe and validate a value_.
42
42
 
43
- The simplest schemas are `Type` schemas, which just validate the type of a value.
43
+ The simplest schemas are `Type` schemas, which just check the type of a value.
44
44
 
45
45
  schema = RSchema.define { _Integer }
46
46
  schema.class #=> RSchema::Schemas::Type
47
47
 
48
- schema.call(1234).valid? #=> true
49
- schema.call('hi').valid? #=> false
48
+ schema.valid?(1234) #=> true
49
+ schema.valid?('hi') #=> false
50
50
 
51
51
  Then there are composite schemas, which are schemas composed of subschemas.
52
52
 
53
- Arrays are composite schemas:
53
+ Array schemas are composite schemas:
54
54
 
55
- schema = RSchema.define { Array(_Integer) }
56
- schema.call([10, 11, 12]).valid? #=> true
57
- schema.call([10, 11, :hi]).valid? #=> false
55
+ schema = RSchema.define { array(_Integer) }
56
+ schema.valid?([10, 11, 12]) #=> true
57
+ schema.valid?([10, 11, :hi]) #=> false
58
58
 
59
- And so are hashes:
59
+ And so are hash schemas:
60
60
 
61
- schema = RSchema.define do
62
- Hash(fname: _String, age: _Integer)
63
- end
61
+ schema = RSchema.define_hash {{
62
+ fname: _String,
63
+ age: _Integer,
64
+ }}
64
65
 
65
- schema.call({ fname: 'Jane', age: 27 }).valid? #=> true
66
- schema.call({ fname: 'Johnny' }).valid? #=> false
66
+ schema.valid?({ fname: 'Jane', age: 27 }) #=> true
67
+ schema.valid?({ fname: 'Johnny no age' }) #=> false
67
68
 
68
69
  Schema objects are composable – they are designed to be combined.
69
70
  This allows schemas to describe complex, nested data structures.
70
71
 
71
- schema = RSchema.define_hash do
72
- {
73
- fname: predicate { |n| n.is_a?(String) && n.size > 0 },
74
- favourite_foods: Set(_Symbol),
75
- children_by_age: VariableHash(_Integer => _String)
76
- }
77
- end
72
+ schema = RSchema.define_hash {{
73
+ fname: maybe(_String),
74
+ favourite_foods: set(_Symbol),
75
+ children_by_age: variable_hash(_Integer => _String)
76
+ }}
78
77
 
79
78
  input = {
80
- fname: 'Johnny',
81
- favourite_foods: Set.new([:bacon, :cheese, :onion]),
79
+ fname: nil,
80
+ favourite_foods: Set[:bacon, :cheese, :onion],
82
81
  children_by_age: {
83
82
  7 => 'Jenny',
84
83
  5 => 'Simon',
85
84
  },
86
85
  }
87
86
 
88
- schema.call(input).valid? #=> true
87
+ schema.valid?(input) #=> true
89
88
 
90
89
  RSchema provides many different kinds of schema classes for common tasks, but
91
90
  you can also write custom schema classes if you need to.
@@ -95,34 +94,35 @@ The DSL
95
94
  -------
96
95
 
97
96
  Schemas are usually created and composed via a DSL using `RSchema.define`.
98
- They can be created manually, although this is often too verbose.
97
+ Schemas can be created without the DSL, but the DSL is much more succinct.
99
98
 
100
99
  For example, the following two schemas are identical. `schema1` is created via the
101
100
  DSL, and `schema2` is created manually.
102
101
 
103
- schema1 = RSchema.define { Array(_Symbol) }
102
+ schema1 = RSchema.define { array(_Symbol) }
104
103
 
105
- schema2 = RSchema::Schemas::VariableArray.new(
106
- RSchema::Schemas::Type.new(Symbol)
104
+ schema2 = RSchema::Schemas::Convenience.wrap(
105
+ RSchema::Schemas::VariableLengthArray.new(
106
+ RSchema::Schemas::Type.new(Symbol)
107
+ )
107
108
  )
108
109
 
109
- You will probably never need to create schemas manually unless you are doing
110
- something advanced, like writing your own DSL.
110
+ You will probably not need to create schemas manually unless you are doing
111
+ something advanced.
111
112
 
112
- The DSL is designed to be extensible. You can add your own methods to the
113
- default DSL, or create a separate, custom DSL to suite your needs.
113
+ For a full list of DSL methods, see the API documentation for `RSchema::DSL`.
114
114
 
115
115
 
116
- When Validation Fails
117
- ---------------------
116
+ Errors (When Validation Fails)
117
+ ------------------------------
118
118
 
119
- When data fails validation, it is often important to know exactly _which
119
+ When something fails validation, it is often important to know exactly _which
120
120
  values_ were invalid, and _why_. RSchema provides details about every
121
121
  failure within a result object.
122
122
 
123
123
  schema = RSchema.define do
124
- Array(
125
- Hash(
124
+ array(
125
+ fixed_hash(
126
126
  name: _String,
127
127
  hair: enum([:red, :brown, :blonde, :black])
128
128
  )
@@ -136,13 +136,11 @@ failure within a result object.
136
136
  { name: 'Chris', hair: :red },
137
137
  ]
138
138
 
139
- result = schema.call(input)
139
+ result = schema.validate(input)
140
140
 
141
- result.class #=> RSchema::Result
141
+ result.class #=> RSchema::Result
142
142
  result.valid? #=> false
143
- result.error #=> { 2 => { :hair => #<RSchema::Error> } }
144
- result.error[2][:hair].to_s
145
- #=> "Error RSchema::Schemas::Enum/not_a_member for value: :blond"
143
+ result.error #=> { 2 => { :hair => #<RSchema::Error> } }
146
144
 
147
145
  The error above says that the value `:blond`, which exists at location
148
146
  `input[2][:hair]`, is not a valid enum member. Looking back at the schema, we
@@ -156,13 +154,11 @@ error messages for developers or users.
156
154
 
157
155
  error.value #=> :blond
158
156
  error.symbolic_name #=> :not_a_member
159
- error.schema #=> #<RSchema::Schemas::Enum>
160
- error.to_s #=> "Error RSchema::Schemas::Enum/not_a_member for value: :blond"
161
- error.to_s(:detailed) #=>
162
- # Error: not_a_member
163
- # Schema: RSchema::Schemas::Enum
164
- # Value: :blond
165
- # Vars: nil
157
+ error.schema #=> #<RSchema::Schemas::Enum ...>
158
+ error.schema.members #=> [:red, :brown, :blonde, :black]
159
+ error.to_s #=> "RSchema::Schemas::Enum/not_a_member"
160
+ error.inspect
161
+ #=> "<RSchema::Error RSchema::Schemas::Enum/not_a_member value=:blond>"
166
162
 
167
163
 
168
164
  Type Schemas
@@ -172,8 +168,8 @@ The most basic kind of schema is a `Type` schema.
172
168
  Type schemas validate the class of a value using `is_a?`.
173
169
 
174
170
  schema = RSchema.define { type(String) }
175
- schema.call('hi').valid? #=> true
176
- schema.call(1234).valid? #=> false
171
+ schema.valid?('hi') #=> true
172
+ schema.valid?(1234) #=> false
177
173
 
178
174
  Type schemas are so common that the RSchema DSL provides a shorthand way to
179
175
  create them, using an underscore prefix:
@@ -186,22 +182,21 @@ Because type schemas use `is_a?`, they handle subclasses, and can also be used
186
182
  to check for `include`d modules like `Enumerable`:
187
183
 
188
184
  schema = RSchema.define { _Enumerable }
189
- schema.call([1, 2, 3]).valid? #=> true
190
- schema.call({ a: 1, b: 2 }).valid? #=> true
185
+ schema.valid?([1, 2, 3]) #=> true
186
+ schema.valid?({ a: 12 }) #=> true
191
187
 
192
188
  Variable-length Array Schemas
193
189
  -----------------------------
194
190
 
195
191
  There are two types of array schemas.
196
- The first type are `VariableLengthArray` schemas, where every element in the
197
- array conforms to a single subschema:
192
+ The first type are `VariableLengthArray` schemas, which check that all elements
193
+ in the array conform to a single subschema:
198
194
 
199
- schema = RSchema.define { Array(_Symbol) }
200
- schema.class #=> RSchema::Schemas::VariableLengthArray
195
+ schema = RSchema.define { array(_Symbol) }
201
196
 
202
- schema.call([:a, :b, :c]).valid? #=> true
203
- schema.call([:a]).valid? #=> true
204
- schema.call([]).valid? #=> true
197
+ schema.valid?([:a, :b, :c]) #=> true
198
+ schema.valid?([:a]) #=> true
199
+ schema.valid?([]) #=> true
205
200
 
206
201
  Fixed-length Array Schemas
207
202
  --------------------------
@@ -209,37 +204,38 @@ Fixed-length Array Schemas
209
204
  There are also `FixedLengthArray` schemas, where the array must have a specific
210
205
  length, and each element of the array has a separate subschema:
211
206
 
212
- schema = RSchema.define{ Array(_Integer, _String) }
213
- schema.class #=> RSchema::Schemas::FixedLengthArray
207
+ schema = RSchema.define { array(_Integer, _String) }
214
208
 
215
- schema.call([10, 'hello']).valid? #=> true
216
- schema.call([22, 'world']).valid? #=> true
217
- schema.call(['heyoo', 33]).valid? #=> false
209
+ schema.valid?([10, 'hello']) #=> true
210
+ schema.valid?(['heyoo', 33]) #=> false
218
211
 
219
212
  Fixed Hash Schemas
220
213
  ------------------
221
214
 
222
215
  There are also two kinds of hash schemas.
223
216
 
224
- `FixedHash` schemas describes hashes where they keys are known constants:
217
+ `FixedHash` schemas describe hashes where they keys are known constants:
225
218
 
226
219
  schema = RSchema.define do
227
- Hash(name: _String, age: _Integer)
220
+ fixed_hash(
221
+ name: _String,
222
+ age: _Integer,
223
+ )
228
224
  end
229
225
 
230
- schema.call({ name: 'George', age: 2 }).valid? #=> true
226
+ schema.valid?({ name: 'George', age: 2 }) #=> true
231
227
 
232
228
  Elements can be optional:
233
229
 
234
230
  schema = RSchema.define do
235
- Hash(
231
+ fixed_hash(
236
232
  name: _String,
237
233
  optional(:age) => _Integer,
238
234
  )
239
235
  end
240
236
 
241
- schema.call({ name: 'Lucy', age: 21 }).valid? #=> true
242
- schema.call({ name: 'Tom' }).valid? #=> true
237
+ schema.valid?({ name: 'Lucy', age: 21 }) #=> true
238
+ schema.valid?({ name: 'Ageless Tommy' }) #=> true
243
239
 
244
240
  `FixedHash` schemas are common, so the `RSchema.define_hash` method exists
245
241
  to make their creation more convenient:
@@ -252,13 +248,13 @@ to make their creation more convenient:
252
248
  Variable Hash Schemas
253
249
  ---------------------
254
250
 
255
- `VariableHash` schemas are for hashes where the keys are _not_ known constants.
251
+ `VariableHash` schemas are for hashes where the keys are _not_ known ahead of time.
256
252
  They contain one subschema for keys, and another subschema for values.
257
253
 
258
- schema = RSchema.define { VariableHash(_Symbol => _Integer) }
259
- schema.call({}).valid? #=> true
260
- schema.call({ a: 1 }).valid? #=> true
261
- schema.call({ a: 1, b: 2 }).valid? #=> true
254
+ schema = RSchema.define { variable_hash(_Symbol => _Integer) }
255
+ schema.valid?({}) #=> true
256
+ schema.valid?({ a: 1 }) #=> true
257
+ schema.valid?({ a: 1, b: 2 }) #=> true
262
258
 
263
259
  Other Schema Types
264
260
  ------------------
@@ -266,40 +262,40 @@ Other Schema Types
266
262
  RSchema provides a few other schema types through its DSL:
267
263
 
268
264
  # boolean (only true or false)
269
- boolean_schema = RSchema.define { Boolean() }
270
- boolean_schema.call(true).valid? #=> true
271
- boolean_schema.call(false).valid? #=> true
272
- boolean_schema.call(nil).valid? #=> false
265
+ boolean_schema = RSchema.define { boolean }
266
+ boolean_schema.valid?(true) #=> true
267
+ boolean_schema.valid?(false) #=> true
268
+ boolean_schema.valid?(nil) #=> false
273
269
 
274
270
  # anything (literally any value)
275
271
  anything_schema = RSchema.define { anything }
276
- anything_schema.call('Hi').valid? #=> true
277
- anything_schema.call(true).valid? #=> true
278
- anything_schema.call(1234).valid? #=> true
279
- anything_schema.call(nil).valid? #=> true
272
+ anything_schema.valid?('Hi') #=> true
273
+ anything_schema.valid?(true) #=> true
274
+ anything_schema.valid?(1234) #=> true
275
+ anything_schema.valid?(nil) #=> true
280
276
 
281
277
  # either (sum types)
282
278
  either_schema = RSchema.define { either(_String, _Integer, _Float) }
283
- either_schema.call('hi').valid? #=> true
284
- either_schema.call(5555).valid? #=> true
285
- either_schema.call(77.1).valid? #=> true
279
+ either_schema.valid?('hi') #=> true
280
+ either_schema.valid?(5555) #=> true
281
+ either_schema.valid?(77.2) #=> true
286
282
 
287
283
  # maybe (allows nil)
288
284
  maybe_schema = RSchema.define { maybe(_Integer) }
289
- maybe_schema.call(5).valid? #=> true
290
- maybe_schema.call(nil).valid? #=> true
285
+ maybe_schema.valid?(5) #=> true
286
+ maybe_schema.valid?(nil) #=> true
291
287
 
292
288
  # enum (a set of valid values)
293
289
  enum_schema = RSchema.define { enum([:a, :b, :c]) }
294
- enum_schema.call(:a).valid? #=> true
295
- enum_schema.call(:z).valid? #=> false
290
+ enum_schema.valid?(:a) #=> true
291
+ enum_schema.valid?(:z) #=> false
296
292
 
297
293
  # predicate (block returns true for valid values)
298
294
  predicate_schema = RSchema.define do
299
295
  predicate { |x| x.even? }
300
296
  end
301
- predicate_schema.call(4).valid? #=> true
302
- predicate_schema.call(5).valid? #=> false
297
+ predicate_schema.valid?(4) #=> true
298
+ predicate_schema.valid?(5) #=> false
303
299
 
304
300
  # pipeline (apply multiple schemas to a single value, in order)
305
301
  pipeline_schema = RSchema.define do
@@ -308,46 +304,12 @@ RSchema provides a few other schema types through its DSL:
308
304
  predicate { |x| x.positive? },
309
305
  )
310
306
  end
311
- pipeline_schema.call(123).valid? #=> true
312
- pipeline_schema.call(5.1).valid? #=> true
313
- pipeline_schema.call(-24).valid? #=> false
314
-
315
-
316
- Coercion
317
- --------
318
-
319
- Coercers convert invalid data into valid data where possible, according to a
320
- schema.
321
-
322
- Take HTTP params as an example. Web forms often contain database IDs, which
323
- are integers, but are submitted as strings by the browser. Param hash keys
324
- are often expected to be `Symbol`s, but are also strings. The `HTTPCoercer`
325
- can automatically convert these strings into the appropriate type, based on a
326
- schema.
327
-
328
- # Input keys and values are all strings.
329
- input_params = {
330
- 'whatever_id' => '5',
331
- 'amount' => '123.45',
332
- }
333
-
334
- # The schema expects symbol keys, an integer value, and a float value.
335
- param_schema = RSchema.define_hash {{
336
- whatever_id: _Integer,
337
- amount: _Float,
338
- }}
339
-
340
- # The schema is wrapped in a HTTPCoercer.
341
- coercer = RSchema::HTTPCoercer.wrap(param_schema)
342
-
343
- # Use the coercer like a normal schema object.
344
- result = coercer.call(input_params)
345
-
346
- # The result object contains the coerced value
347
- result.valid? #=> true
348
- result.value #=> { :whatever_id => 5, :amount => 123.45 }
307
+ pipeline_schema.valid?(123) #=> true
308
+ pipeline_schema.valid?(5.1) #=> true
309
+ pipeline_schema.valid?(-24) #=> false
349
310
 
350
- TODO: explain how to create custom coercers
311
+ For a full list of built-in schema types, see the API documentation for all
312
+ classes in the `RSchema::Schemas` module.
351
313
 
352
314
  Extending The DSL
353
315
  -----------------
@@ -371,26 +333,25 @@ And your methods will be available via `RSchema.define`:
371
333
 
372
334
  schema = RSchema.define { palendrome }
373
335
 
374
- schema.call('racecar').valid? #=> true
375
- schema.call('ferrari').valid? #=> false
376
-
377
- This is the preferred way for other gems to extend RSchema with new kinds
378
- of schema classes.
336
+ schema.valid?('racecar') #=> true
337
+ schema.valid?('ferrari') #=> false
379
338
 
339
+ This is the preferred way for you, and other gems, to extend RSchema with new
340
+ DSL methods.
380
341
 
381
342
  Creating Your Own DSL
382
343
  ---------------------
383
344
 
384
- The default DSL is designed to be extended (i.e. modified) by external gems/code.
385
- If you want a DSL that isn't affected by external factors, you can create one
386
- yourself.
345
+ The default DSL is designed to be extended (i.e. modified) by you, and
346
+ third-party gems. If you want a DSL that isn't affected by external factors,
347
+ you can create one yourself.
387
348
 
388
- Create a new class, and include `RSchema::DSL` to get all the standard DSL
389
- methods that come built-in to RSchema. You can define your own custom methods
390
- on this class.
349
+ Create a new class, and include `RSchema::DSL` if you want have all the
350
+ standard DSL methods that come built-in to RSchema. You can define your own
351
+ custom methods on this class.
391
352
 
392
353
  class MyCustomDSL
393
- include RSchema::DSL
354
+ include RSchema::DSL # this is optional
394
355
 
395
356
  def palendrome
396
357
  pipeline(
@@ -400,22 +361,76 @@ on this class.
400
361
  end
401
362
  end
402
363
 
403
- Then simply use `instance_eval` to make use of your custom DSL.
364
+ Then pass an instance of your DSL class into `RSchema.define`:
404
365
 
405
- schema = MyCustomDSL.new.instance_eval { palendrome }
406
- schema.call('racecar').valid? #=> true
366
+ dsl = MyCustomDSL.new
367
+ schema = RSchema.define(dsl) { palendrome }
368
+ schema.valid?('racecar') #=> true
407
369
 
408
- See the implementation of `RSchema.define` for reference.
370
+ Coercion
371
+ --------
409
372
 
373
+ Coercers convert invalid data into valid data where possible, according to a
374
+ schema.
375
+
376
+ Take HTTP params as an example. Web forms often contain database IDs, which
377
+ are integers, but are submitted as strings by the browser. Param hash keys
378
+ are often expected to be `Symbol`s, but are also strings. RSchema can
379
+ automatically convert these strings into the appropriate type, based on a
380
+ schema.
410
381
 
411
- Custom Schema Types
412
- -------------------
382
+ # Input keys and values are all strings
383
+ input_params = {
384
+ 'whatever_id' => '5',
385
+ 'amount' => '123.45',
386
+ }
387
+
388
+ # The schema expects symbol keys, an integer value, and a float value
389
+ schema = RSchema.define_hash {{
390
+ whatever_id: _Integer,
391
+ amount: _Float,
392
+ }}
393
+
394
+ # A coercer is created by wrapping the schema
395
+ coercer = RSchema::CoercionWrapper::RACK_PARAMS.wrap(schema)
396
+
397
+ # Use the coercer like a normal schema object
398
+ result = coercer.validate(input_params)
399
+
400
+ # The result object contains the coerced value
401
+ result.valid? #=> true
402
+ result.value #=> { :whatever_id => 5, :amount => 123.45 }
403
+
404
+ Custom Coercion
405
+ ---------------
406
+
407
+ Coercion is designed to be totally extensible. You'll have to take my word
408
+ for it, because there isn't much documentation at the moment.
409
+
410
+ See `lib/rschema/coercion_wrapper/rack_params.rb` for an example of how to
411
+ make a coercion wrapper.
412
+
413
+ See all the classes in `lib/rschema/coercers/` for examples of how to make
414
+ individual coercers.
415
+
416
+ If you have any problems or questions about implementing custom coercion, feel
417
+ free to contact me (Tom Dalling).
418
+
419
+
420
+ Implementing Your Own Schema Types
421
+ ----------------------------------
413
422
 
414
423
  Schemas are objects that conform to a certain interface (i.e. a duck type).
415
424
  To create your own schema types, you just need to implement this interface.
416
425
 
426
+ The interface consists of two methods: `call` and `with_wrapped_subschemas`.
427
+ The `call` method is the interface for validating values.
428
+ The `with_wrapped_subschemas` is necessary for coercion to work.
429
+ If you have any problems or questions regarding this schema interface, feel
430
+ free to contact me (Tom Dalling).
431
+
417
432
  Below is a custom schema for pairs – arrays with two elements of the same type.
418
- This is already possible using existing schemas (e.g. `Array(_String, _String)`),
433
+ This is already possible using existing schemas (e.g. `array(_String, _String)`),
419
434
  and is only shown here for the purpose of demonstration.
420
435
 
421
436
  class PairSchema
@@ -423,19 +438,31 @@ and is only shown here for the purpose of demonstration.
423
438
  @subschema = subschema
424
439
  end
425
440
 
426
- def call(pair, options=RSchema::Options.default)
441
+ #
442
+ # This method is mandatory.
443
+ #
444
+ # `pair` is the value to validate.
445
+ # `options` is an `RSchema::Options` object.
446
+ # This method must return a `RSchema::Result` object
447
+ #
448
+ def call(pair, options)
427
449
  return not_an_array_failure(pair) unless pair.is_a?(Array)
428
450
  return not_a_pair_failure(pair) unless pair.size == 2
429
451
 
452
+ # pass both array elements to `@subschema.call`
430
453
  subresults = pair.map { |x| @subschema.call(x, options) }
431
454
 
455
+ # check if both elements are valid according to @subschema
432
456
  if subresults.all?(&:valid?)
433
- RSchema::Result.success(subresults.map(&:value).to_a)
457
+ RSchema::Result.success(subresults.map(&:value))
434
458
  else
435
459
  RSchema::Result.failure(subschema_error(subresults))
436
460
  end
437
461
  end
438
462
 
463
+ #
464
+ # This method is necessary for coercion to work
465
+ #
439
466
  def with_wrapped_subschemas(wrapper)
440
467
  PairSchema.new(wrapper.wrap(@subschema))
441
468
  end
@@ -458,25 +485,22 @@ and is only shown here for the purpose of demonstration.
458
485
  symbolic_name: :not_a_pair,
459
486
  schema: self,
460
487
  value: pair,
461
- vars: {
462
- expected_size: 2,
463
- actual_size: pair.size,
464
- }
465
488
  )
466
489
  )
467
490
  end
468
491
 
492
+ #
493
+ # Returns a hash of index => error
494
+ #
469
495
  def subschema_error(subresults)
470
496
  subresults
471
497
  .each_with_index
472
498
  .select { |(result, idx)| result.invalid? }
473
- .map(&:reverse)
499
+ .map { |(result, idx)| [idx, result.error] }
474
500
  .to_h
475
501
  end
476
502
  end
477
503
 
478
- TODO: need to explain how to implement `#call` and `#with_wrapped_subschemas`
479
-
480
504
  Add your new schema class to the default DSL:
481
505
 
482
506
  module PairSchemaDSL
@@ -490,13 +514,13 @@ Add your new schema class to the default DSL:
490
514
  Then your schema is accessible from `RSchema.define`:
491
515
 
492
516
  gps_coordinate_schema = RSchema.define { pair(_Float) }
493
- gps_coordinate_schema.call([1.2, 3.4]).valid? #=> true
517
+ gps_coordinate_schema.valid?([1.2, 3.4]) #=> true
494
518
 
495
519
  Coercion should work, as long as `#with_wrapped_subschemas` was implemented
496
520
  correctly.
497
521
 
498
- coercer = RSchema::HTTPCoercer.wrap(gps_coordinate_schema)
499
- result = coercer.call(['1', '2'])
522
+ coercer = RSchema::CoercionWrapper::RACK_PARAMS.wrap(gps_coordinate_schema)
523
+ result = coercer.validate(["1", "2"])
500
524
  result.valid? #=> true
501
525
  result.value #=> [1.0, 2.0]
502
526