rschema 2.4.0 → 3.0.1.pre1
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 +4 -4
- data/README.md +408 -197
- data/lib/rschema.rb +26 -367
- data/lib/rschema/dsl.rb +103 -0
- data/lib/rschema/error.rb +46 -0
- data/lib/rschema/http_coercer.rb +177 -0
- data/lib/rschema/options.rb +15 -0
- data/lib/rschema/result.rb +39 -0
- data/lib/rschema/schemas/anything.rb +17 -0
- data/lib/rschema/schemas/boolean.rb +27 -0
- data/lib/rschema/schemas/enum.rb +31 -0
- data/lib/rschema/schemas/fixed_hash.rb +118 -0
- data/lib/rschema/schemas/fixed_length_array.rb +60 -0
- data/lib/rschema/schemas/maybe.rb +23 -0
- data/lib/rschema/schemas/pipeline.rb +27 -0
- data/lib/rschema/schemas/predicate.rb +27 -0
- data/lib/rschema/schemas/set.rb +56 -0
- data/lib/rschema/schemas/sum.rb +36 -0
- data/lib/rschema/schemas/type.rb +27 -0
- data/lib/rschema/schemas/variable_hash.rb +67 -0
- data/lib/rschema/schemas/variable_length_array.rb +49 -0
- data/lib/rschema/version.rb +1 -1
- metadata +27 -10
- data/lib/rschema/rails_interop.rb +0 -19
@@ -0,0 +1,60 @@
|
|
1
|
+
module RSchema
|
2
|
+
module Schemas
|
3
|
+
class FixedLengthArray
|
4
|
+
attr_reader :subschemas
|
5
|
+
|
6
|
+
def initialize(subschemas)
|
7
|
+
@subschemas = subschemas
|
8
|
+
end
|
9
|
+
|
10
|
+
def call(value, options=RSchema::Options.default)
|
11
|
+
unless value.kind_of?(Array)
|
12
|
+
return Result.failure(Error.new(
|
13
|
+
symbolic_name: :not_an_array,
|
14
|
+
schema: self,
|
15
|
+
value: value,
|
16
|
+
))
|
17
|
+
end
|
18
|
+
|
19
|
+
unless value.size == @subschemas.size
|
20
|
+
return Result.failure(Error.new(
|
21
|
+
symbolic_name: :incorrect_size,
|
22
|
+
schema: self,
|
23
|
+
value: value,
|
24
|
+
))
|
25
|
+
end
|
26
|
+
|
27
|
+
validate_value, error = apply_subschemas(value, options)
|
28
|
+
if error.empty?
|
29
|
+
Result.success(validate_value)
|
30
|
+
else
|
31
|
+
Result.failure(error)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def with_wrapped_subschemas(wrapper)
|
36
|
+
wrapped_subschemas = subschemas.map{ |ss| wrapper.wrap(ss) }
|
37
|
+
self.class.new(wrapped_subschemas)
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def apply_subschemas(array_value, options)
|
43
|
+
validate_value = []
|
44
|
+
errors = {}
|
45
|
+
|
46
|
+
array_value.zip(@subschemas).each_with_index do |(subvalue, subschema), idx|
|
47
|
+
result = subschema.call(subvalue, options)
|
48
|
+
if result.valid?
|
49
|
+
validate_value << result.value
|
50
|
+
else
|
51
|
+
errors[idx] = result.error
|
52
|
+
break if options.fail_fast?
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
[validate_value, errors]
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module RSchema
|
2
|
+
module Schemas
|
3
|
+
class Maybe
|
4
|
+
attr_reader :subschema
|
5
|
+
|
6
|
+
def initialize(subschema)
|
7
|
+
@subschema = subschema
|
8
|
+
end
|
9
|
+
|
10
|
+
def call(value, options=Options.default)
|
11
|
+
if value == nil
|
12
|
+
Result.success(value)
|
13
|
+
else
|
14
|
+
@subschema.call(value, options)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def with_wrapped_subschemas(wrapper)
|
19
|
+
self.class.new(wrapper.wrap(subschema))
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module RSchema
|
2
|
+
module Schemas
|
3
|
+
class Pipeline
|
4
|
+
attr_reader :subschemas
|
5
|
+
|
6
|
+
def initialize(subschemas)
|
7
|
+
@subschemas = subschemas
|
8
|
+
end
|
9
|
+
|
10
|
+
def call(value, options=Options.default)
|
11
|
+
result = Result.success(value)
|
12
|
+
|
13
|
+
subschemas.each do |subsch|
|
14
|
+
result = subsch.call(result.value, options)
|
15
|
+
break if result.invalid?
|
16
|
+
end
|
17
|
+
|
18
|
+
result
|
19
|
+
end
|
20
|
+
|
21
|
+
def with_wrapped_subschemas(wrapper)
|
22
|
+
wrapped_subschemas = subschemas.map{ |ss| wrapper.wrap(ss) }
|
23
|
+
self.class.new(wrapped_subschemas)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module RSchema
|
2
|
+
module Schemas
|
3
|
+
class Predicate
|
4
|
+
attr_reader :block
|
5
|
+
|
6
|
+
def initialize(block)
|
7
|
+
@block = block
|
8
|
+
end
|
9
|
+
|
10
|
+
def call(value, options=Options.default)
|
11
|
+
if block.call(value)
|
12
|
+
Result.success(value)
|
13
|
+
else
|
14
|
+
Result.failure(Error.new(
|
15
|
+
schema: self,
|
16
|
+
value: value,
|
17
|
+
symbolic_name: :false,
|
18
|
+
))
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def with_wrapped_subschemas(wrapper)
|
23
|
+
self
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'set'
|
2
|
+
|
3
|
+
module RSchema
|
4
|
+
module Schemas
|
5
|
+
class Set
|
6
|
+
attr_reader :subschema
|
7
|
+
|
8
|
+
def initialize(subschema)
|
9
|
+
@subschema = subschema
|
10
|
+
end
|
11
|
+
|
12
|
+
def call(value, options=RSchema::Options.default)
|
13
|
+
return not_a_set_result(value) unless value.is_a?(::Set)
|
14
|
+
|
15
|
+
result_value = ::Set.new
|
16
|
+
result_errors = []
|
17
|
+
|
18
|
+
value.each do |subvalue|
|
19
|
+
subresult = subschema.call(subvalue, options)
|
20
|
+
if subresult.valid?
|
21
|
+
result_value << subresult.value
|
22
|
+
else
|
23
|
+
result_errors << subresult.error
|
24
|
+
end
|
25
|
+
|
26
|
+
break if options.fail_fast?
|
27
|
+
end
|
28
|
+
|
29
|
+
if result_errors.empty?
|
30
|
+
Result.success(result_value)
|
31
|
+
else
|
32
|
+
Result.failure(Error.new(
|
33
|
+
schema: self,
|
34
|
+
value: value,
|
35
|
+
symbolic_name: :contents_invalid,
|
36
|
+
vars: result_errors,
|
37
|
+
))
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def with_wrapped_subschemas(wrapper)
|
42
|
+
wrapped_subschema = wrapper.wrap(subschema)
|
43
|
+
self.class.new(wrapped_subschema)
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
def not_a_set_result(value)
|
48
|
+
Result.failure(Error.new(
|
49
|
+
schema: self,
|
50
|
+
symbolic_name: :not_a_set,
|
51
|
+
value: value,
|
52
|
+
))
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module RSchema
|
2
|
+
module Schemas
|
3
|
+
class Sum
|
4
|
+
attr_reader :subschemas
|
5
|
+
|
6
|
+
def initialize(subschemas)
|
7
|
+
@subschemas = subschemas
|
8
|
+
end
|
9
|
+
|
10
|
+
def call(value, options=Options.default)
|
11
|
+
suberrors = []
|
12
|
+
|
13
|
+
@subschemas.each do |subsch|
|
14
|
+
result = subsch.call(value, options)
|
15
|
+
if result.valid?
|
16
|
+
return result
|
17
|
+
else
|
18
|
+
suberrors << result.error
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
Result.failure(Error.new(
|
23
|
+
schema: self,
|
24
|
+
value: value,
|
25
|
+
symbolic_name: :all_invalid,
|
26
|
+
vars: suberrors,
|
27
|
+
))
|
28
|
+
end
|
29
|
+
|
30
|
+
def with_wrapped_subschemas(wrapper)
|
31
|
+
wrapped_subschemas = subschemas.map{ |ss| wrapper.wrap(ss) }
|
32
|
+
self.class.new(wrapped_subschemas)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module RSchema
|
2
|
+
module Schemas
|
3
|
+
class Type
|
4
|
+
attr_reader :type
|
5
|
+
|
6
|
+
def initialize(type)
|
7
|
+
@type = type
|
8
|
+
end
|
9
|
+
|
10
|
+
def call(value, options = RSchema::Options.default)
|
11
|
+
if value.is_a?(@type)
|
12
|
+
Result.success(value)
|
13
|
+
else
|
14
|
+
Result.failure(Error.new(
|
15
|
+
schema: self,
|
16
|
+
value: value,
|
17
|
+
symbolic_name: :wrong_type,
|
18
|
+
))
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def with_wrapped_subschemas(wrapper)
|
23
|
+
self
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module RSchema
|
2
|
+
module Schemas
|
3
|
+
class VariableHash
|
4
|
+
attr_reader :key_schema, :value_schema
|
5
|
+
|
6
|
+
def initialize(key_schema, value_schema)
|
7
|
+
@key_schema = key_schema
|
8
|
+
@value_schema = value_schema
|
9
|
+
end
|
10
|
+
|
11
|
+
def call(value, options=Options.default)
|
12
|
+
return not_a_hash_result(value) unless value.is_a?(Hash)
|
13
|
+
|
14
|
+
result, key_errors, value_errors = apply_subschemas(value, options)
|
15
|
+
|
16
|
+
if key_errors.empty? && value_errors.empty?
|
17
|
+
Result.success(result)
|
18
|
+
else
|
19
|
+
Result.failure(keys: key_errors, values: value_errors)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def with_wrapped_subschemas(wrapper)
|
24
|
+
self.class.new(
|
25
|
+
wrapper.wrap(key_schema),
|
26
|
+
wrapper.wrap(value_schema),
|
27
|
+
)
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def not_a_hash_result(value)
|
33
|
+
Result.failure(Error.new(
|
34
|
+
schema: self,
|
35
|
+
value: value,
|
36
|
+
symbolic_name: :not_a_hash,
|
37
|
+
))
|
38
|
+
end
|
39
|
+
|
40
|
+
def apply_subschemas(value, options)
|
41
|
+
result = {}
|
42
|
+
key_errors = {}
|
43
|
+
value_errors = {}
|
44
|
+
|
45
|
+
value.each do |key, subvalue|
|
46
|
+
key_result = key_schema.call(key, options)
|
47
|
+
if key_result.invalid?
|
48
|
+
key_errors[key] = key_result.error
|
49
|
+
break if options.fail_fast?
|
50
|
+
end
|
51
|
+
|
52
|
+
subvalue_result = value_schema.call(subvalue, options)
|
53
|
+
if subvalue_result.invalid?
|
54
|
+
value_errors[key] = subvalue_result.error
|
55
|
+
break if options.fail_fast?
|
56
|
+
end
|
57
|
+
|
58
|
+
if key_result.valid? && subvalue_result.valid?
|
59
|
+
result[key_result.value] = subvalue_result.value
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
return result, key_errors, value_errors
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module RSchema
|
2
|
+
module Schemas
|
3
|
+
class VariableLengthArray
|
4
|
+
attr_accessor :element_schema
|
5
|
+
|
6
|
+
def initialize(element_schema)
|
7
|
+
@element_schema = element_schema
|
8
|
+
end
|
9
|
+
|
10
|
+
def call(value, options = RSchema::Options.default)
|
11
|
+
if value.kind_of?(Array)
|
12
|
+
validated_values, errors = validate_elements(value, options)
|
13
|
+
if errors.empty?
|
14
|
+
Result.success(validated_values)
|
15
|
+
else
|
16
|
+
Result.failure(errors)
|
17
|
+
end
|
18
|
+
else
|
19
|
+
Result.failure(Error.new(
|
20
|
+
schema: self,
|
21
|
+
value: value,
|
22
|
+
symbolic_name: :not_an_array,
|
23
|
+
))
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def with_wrapped_subschemas(wrapper)
|
28
|
+
self.class.new(wrapper.wrap(element_schema))
|
29
|
+
end
|
30
|
+
|
31
|
+
def validate_elements(array, options)
|
32
|
+
errors = {}
|
33
|
+
validated_values = []
|
34
|
+
|
35
|
+
array.each_with_index do |subvalue, idx|
|
36
|
+
result = @element_schema.call(subvalue, options)
|
37
|
+
if result.valid?
|
38
|
+
validated_values[idx] = result.value
|
39
|
+
else
|
40
|
+
errors[idx] = result.error
|
41
|
+
break if options.fail_fast?
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
[validated_values, errors]
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
data/lib/rschema/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rschema
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 3.0.1.pre1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tom Dalling
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2017-02-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rspec
|
@@ -67,8 +67,8 @@ dependencies:
|
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '0'
|
69
69
|
description: |2
|
70
|
-
Schema-based validation and coercion for Ruby data structures
|
71
|
-
by
|
70
|
+
Schema-based validation and coercion for Ruby data structures, inspired
|
71
|
+
by Prismatic/schema for Clojure.
|
72
72
|
email:
|
73
73
|
- tom@tomdalling.com
|
74
74
|
executables: []
|
@@ -78,11 +78,28 @@ files:
|
|
78
78
|
- LICENSE.txt
|
79
79
|
- README.md
|
80
80
|
- lib/rschema.rb
|
81
|
-
- lib/rschema/
|
81
|
+
- lib/rschema/dsl.rb
|
82
|
+
- lib/rschema/error.rb
|
83
|
+
- lib/rschema/http_coercer.rb
|
84
|
+
- lib/rschema/options.rb
|
85
|
+
- lib/rschema/result.rb
|
86
|
+
- lib/rschema/schemas/anything.rb
|
87
|
+
- lib/rschema/schemas/boolean.rb
|
88
|
+
- lib/rschema/schemas/enum.rb
|
89
|
+
- lib/rschema/schemas/fixed_hash.rb
|
90
|
+
- lib/rschema/schemas/fixed_length_array.rb
|
91
|
+
- lib/rschema/schemas/maybe.rb
|
92
|
+
- lib/rschema/schemas/pipeline.rb
|
93
|
+
- lib/rschema/schemas/predicate.rb
|
94
|
+
- lib/rschema/schemas/set.rb
|
95
|
+
- lib/rschema/schemas/sum.rb
|
96
|
+
- lib/rschema/schemas/type.rb
|
97
|
+
- lib/rschema/schemas/variable_hash.rb
|
98
|
+
- lib/rschema/schemas/variable_length_array.rb
|
82
99
|
- lib/rschema/version.rb
|
83
|
-
homepage:
|
100
|
+
homepage: https://github.com/tomdalling/rschema
|
84
101
|
licenses:
|
85
|
-
-
|
102
|
+
- Apache-2.0
|
86
103
|
metadata: {}
|
87
104
|
post_install_message:
|
88
105
|
rdoc_options: []
|
@@ -95,12 +112,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
95
112
|
version: 2.0.0
|
96
113
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
97
114
|
requirements:
|
98
|
-
- - "
|
115
|
+
- - ">"
|
99
116
|
- !ruby/object:Gem::Version
|
100
|
-
version:
|
117
|
+
version: 1.3.1
|
101
118
|
requirements: []
|
102
119
|
rubyforge_project:
|
103
|
-
rubygems_version: 2.5
|
120
|
+
rubygems_version: 2.4.5
|
104
121
|
signing_key:
|
105
122
|
specification_version: 4
|
106
123
|
summary: Schema-based validation and coercion for Ruby data structures
|