rschema 3.1.1 → 3.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/lib/rschema.rb +13 -5
  3. data/lib/rschema/coercers.rb +2 -0
  4. data/lib/rschema/coercers/any.rb +37 -31
  5. data/lib/rschema/coercers/boolean.rb +33 -23
  6. data/lib/rschema/coercers/chain.rb +38 -32
  7. data/lib/rschema/coercers/date.rb +29 -20
  8. data/lib/rschema/coercers/fixed_hash/default_arrays_to_empty.rb +57 -56
  9. data/lib/rschema/coercers/fixed_hash/default_booleans_to_false.rb +56 -55
  10. data/lib/rschema/coercers/fixed_hash/remove_extraneous_attributes.rb +43 -39
  11. data/lib/rschema/coercers/fixed_hash/symbolize_keys.rb +55 -51
  12. data/lib/rschema/coercers/float.rb +22 -15
  13. data/lib/rschema/coercers/integer.rb +21 -15
  14. data/lib/rschema/coercers/nil_empty_strings.rb +20 -17
  15. data/lib/rschema/coercers/symbol.rb +20 -17
  16. data/lib/rschema/coercers/time.rb +29 -20
  17. data/lib/rschema/coercion_wrapper.rb +25 -26
  18. data/lib/rschema/coercion_wrapper/rack_params.rb +18 -19
  19. data/lib/rschema/dsl.rb +20 -13
  20. data/lib/rschema/error.rb +9 -4
  21. data/lib/rschema/options.rb +5 -0
  22. data/lib/rschema/rails.rb +60 -0
  23. data/lib/rschema/result.rb +9 -11
  24. data/lib/rschema/schemas.rb +2 -0
  25. data/lib/rschema/schemas/anything.rb +23 -24
  26. data/lib/rschema/schemas/boolean.rb +36 -30
  27. data/lib/rschema/schemas/coercer.rb +47 -46
  28. data/lib/rschema/schemas/convenience.rb +122 -123
  29. data/lib/rschema/schemas/enum.rb +41 -34
  30. data/lib/rschema/schemas/fixed_hash.rb +165 -162
  31. data/lib/rschema/schemas/fixed_length_array.rb +66 -58
  32. data/lib/rschema/schemas/maybe.rb +28 -28
  33. data/lib/rschema/schemas/pipeline.rb +35 -35
  34. data/lib/rschema/schemas/predicate.rb +40 -34
  35. data/lib/rschema/schemas/set.rb +57 -48
  36. data/lib/rschema/schemas/sum.rb +31 -34
  37. data/lib/rschema/schemas/type.rb +44 -38
  38. data/lib/rschema/schemas/variable_hash.rb +63 -61
  39. data/lib/rschema/schemas/variable_length_array.rb +57 -51
  40. data/lib/rschema/version.rb +3 -1
  41. metadata +54 -25
@@ -1,74 +1,75 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'set'
2
4
 
3
5
  module RSchema
4
- module Coercers
5
- module FixedHash
6
+ module Coercers
7
+ module FixedHash
8
+ # The HTTP standard says that when a form is submitted, all unchecked
9
+ # check boxes will _not_ be sent to the server. That is, they will not
10
+ # be present at all in the params hash.
11
+ #
12
+ # This class coerces these missing values into `false`.
13
+ class DefaultBooleansToFalse
14
+ attr_reader :hash_attributes
6
15
 
7
- # The HTTP standard says that when a form is submitted, all unchecked
8
- # check boxes will _not_ be sent to the server. That is, they will not
9
- # be present at all in the params hash.
10
- #
11
- # This class coerces these missing values into `false`.
12
- class DefaultBooleansToFalse
13
- attr_reader :hash_attributes
16
+ def self.build(schema)
17
+ new(schema)
18
+ end
14
19
 
15
- def self.build(schema)
16
- new(schema)
17
- end
20
+ def initialize(fixed_hash_schema)
21
+ # TODO: make fixed hash attributes frozen, and eliminate dup
22
+ @hash_attributes = fixed_hash_schema.attributes.map(&:dup)
23
+ end
18
24
 
19
- def initialize(fixed_hash_schema)
20
- #TODO: make fixed hash attributes frozen, and eliminate dup
21
- @hash_attributes = fixed_hash_schema.attributes.map(&:dup)
22
- end
25
+ def call(value)
26
+ Result.success(default_bools_to_false(value))
27
+ end
23
28
 
24
- def call(value)
25
- Result.success(default_bools_to_false(value))
26
- end
29
+ def will_affect?(value)
30
+ keys_to_default(value).any?
31
+ end
27
32
 
28
- def will_affect?(value)
29
- keys_to_default(value).any?
30
- end
33
+ private
31
34
 
32
- private
33
- def default_bools_to_false(hash)
34
- missing_keys = keys_to_default(hash)
35
+ def default_bools_to_false(hash)
36
+ missing_keys = keys_to_default(hash)
35
37
 
36
- if missing_keys.any?
37
- defaults = missing_keys.map{ |k| [k, false] }.to_h
38
- hash.merge(defaults)
39
- else
40
- hash # no coercion necessary
38
+ if missing_keys.any?
39
+ defaults = missing_keys.map { |k| [k, false] }.to_h
40
+ hash.merge(defaults)
41
+ else
42
+ hash # no coercion necessary
43
+ end
41
44
  end
42
- end
43
45
 
44
- def keys_to_default(value)
45
- if value.is_a?(Hash)
46
- keys_for_bool_defaulting - value.keys
47
- else
48
- []
46
+ def keys_to_default(value)
47
+ if value.is_a?(Hash)
48
+ keys_for_bool_defaulting - value.keys
49
+ else
50
+ []
51
+ end
49
52
  end
50
- end
51
-
52
- def keys_for_bool_defaulting
53
- @keys_for_bool_defaulting ||= Set.new(
54
- hash_attributes
55
- .reject(&:optional)
56
- .select { |attr| is_bool_schema?(attr.value_schema) }
57
- .map(&:key)
58
- )
59
- end
60
53
 
61
- def is_bool_schema?(schema)
62
- # dig through all the coercers
63
- non_coercer = schema
64
- while non_coercer.is_a?(Schemas::Coercer)
65
- non_coercer = non_coercer.subschema
54
+ def keys_for_bool_defaulting
55
+ @keys_for_bool_defaulting ||= Set.new(
56
+ hash_attributes
57
+ .reject(&:optional)
58
+ .select { |attr| bool_schema?(attr.value_schema) }
59
+ .map(&:key),
60
+ )
66
61
  end
67
62
 
68
- non_coercer.is_a?(Schemas::Boolean)
63
+ def bool_schema?(schema)
64
+ # dig through all the coercers
65
+ non_coercer = schema
66
+ while non_coercer.is_a?(Schemas::Coercer)
67
+ non_coercer = non_coercer.subschema
68
+ end
69
+
70
+ non_coercer.is_a?(Schemas::Boolean)
71
+ end
69
72
  end
73
+ end
70
74
  end
71
-
72
- end
73
- end
74
75
  end
@@ -1,54 +1,58 @@
1
- module RSchema
2
- module Coercers
3
- module FixedHash
4
-
5
- class RemoveExtraneousAttributes
6
- attr_reader :hash_attributes
1
+ # frozen_string_literal: true
7
2
 
8
- def self.build(schema)
9
- new(schema)
10
- end
3
+ module RSchema
4
+ module Coercers
5
+ module FixedHash
6
+ #
7
+ # Removes elements from `Hash` values that are not defined in the given
8
+ # `FixedHash` schema.
9
+ #
10
+ class RemoveExtraneousAttributes
11
+ attr_reader :hash_attributes
12
+
13
+ def self.build(schema)
14
+ new(schema)
15
+ end
11
16
 
12
- def initialize(fixed_hash_schema)
13
- #TODO: make fixed hash attributes frozen, and eliminate dup
14
- @hash_attributes = fixed_hash_schema.attributes.map(&:dup)
15
- end
17
+ def initialize(fixed_hash_schema)
18
+ # TODO: make fixed hash attributes frozen, and eliminate dup
19
+ @hash_attributes = fixed_hash_schema.attributes.map(&:dup)
20
+ end
16
21
 
17
- def call(value)
18
- Result.success(remove_extraneous_elements(value))
19
- end
22
+ def call(value)
23
+ Result.success(remove_extraneous_elements(value))
24
+ end
20
25
 
21
- def will_affect?(value)
22
- keys_to_remove(value).any?
23
- end
26
+ def will_affect?(value)
27
+ keys_to_remove(value).any?
28
+ end
24
29
 
25
- private
30
+ private
26
31
 
27
- def remove_extraneous_elements(hash)
28
- extra_keys = keys_to_remove(hash)
32
+ def remove_extraneous_elements(hash)
33
+ extra_keys = keys_to_remove(hash)
29
34
 
30
- if extra_keys.any?
31
- hash.dup.tap do |stripped_hash|
32
- extra_keys.each { |k| stripped_hash.delete(k) }
35
+ if extra_keys.any?
36
+ hash.dup.tap do |stripped_hash|
37
+ extra_keys.each { |k| stripped_hash.delete(k) }
38
+ end
39
+ else
40
+ hash
33
41
  end
34
- else
35
- hash
36
42
  end
37
- end
38
43
 
39
- def keys_to_remove(value)
40
- if value.is_a?(Hash)
41
- value.keys - valid_keys
42
- else
43
- []
44
+ def keys_to_remove(value)
45
+ if value.is_a?(Hash)
46
+ value.keys - valid_keys
47
+ else
48
+ []
49
+ end
44
50
  end
45
- end
46
51
 
47
- def valid_keys
48
- @valid_keys ||= hash_attributes.map(&:key)
52
+ def valid_keys
53
+ @valid_keys ||= hash_attributes.map(&:key)
54
+ end
49
55
  end
56
+ end
50
57
  end
51
-
52
- end
53
- end
54
58
  end
@@ -1,70 +1,74 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'set'
2
4
 
3
5
  module RSchema
4
- module Coercers
5
- module FixedHash
6
-
7
- class SymbolizeKeys
8
- attr_reader :hash_attributes
6
+ module Coercers
7
+ module FixedHash
8
+ #
9
+ # Coerces `String` keys into `Symbol`s according to the attributes in
10
+ # a given `FixedHash` schema.
11
+ #
12
+ class SymbolizeKeys
13
+ attr_reader :hash_attributes
9
14
 
10
- def self.build(schema)
11
- new(schema)
12
- end
15
+ def self.build(schema)
16
+ new(schema)
17
+ end
13
18
 
14
- def initialize(fixed_hash_schema)
15
- #TODO: make fixed hash attributes frozen, and eliminate dup
16
- @hash_attributes = fixed_hash_schema.attributes.map(&:dup)
17
- end
19
+ def initialize(fixed_hash_schema)
20
+ # TODO: make fixed hash attributes frozen, and eliminate dup
21
+ @hash_attributes = fixed_hash_schema.attributes.map(&:dup)
22
+ end
18
23
 
19
- def call(value)
20
- Result.success(symbolize_keys(value))
21
- end
24
+ def call(value)
25
+ Result.success(symbolize_keys(value))
26
+ end
22
27
 
23
- def will_affect?(value)
24
- keys_to_symbolize(hash).any?
25
- end
28
+ def will_affect?(_value)
29
+ keys_to_symbolize(hash).any?
30
+ end
26
31
 
27
- private
32
+ private
28
33
 
29
- def symbolize_keys(hash)
30
- keys = keys_to_symbolize(hash)
31
- if keys.any?
32
- hash.dup.tap do |new_hash|
33
- keys.each { |k| new_hash[k.to_sym] = new_hash.delete(k) }
34
+ def symbolize_keys(hash)
35
+ keys = keys_to_symbolize(hash)
36
+ if keys.any?
37
+ hash.dup.tap do |new_hash|
38
+ keys.each { |k| new_hash[k.to_sym] = new_hash.delete(k) }
39
+ end
40
+ else
41
+ hash
34
42
  end
35
- else
36
- hash
37
43
  end
38
- end
39
44
 
40
- def keys_to_symbolize(value)
41
- if value.is_a?(Hash)
42
- non_string_keys = Set.new(value.keys) - string_keys
43
- non_string_keys.intersection(symbol_keys_as_strings)
44
- else
45
- []
45
+ def keys_to_symbolize(value)
46
+ if value.is_a?(Hash)
47
+ non_string_keys = Set.new(value.keys) - string_keys
48
+ non_string_keys.intersection(symbol_keys_as_strings)
49
+ else
50
+ []
51
+ end
46
52
  end
47
- end
48
53
 
49
- def symbol_keys_as_strings
50
- @symbol_keys_as_strings ||= Set.new(
51
- all_keys
52
- .select{ |k| k.is_a?(::Symbol) }
53
- .map(&:to_s)
54
- )
55
- end
54
+ def symbol_keys_as_strings
55
+ @symbol_keys_as_strings ||= Set.new(
56
+ all_keys
57
+ .select { |k| k.is_a?(::Symbol) }
58
+ .map(&:to_s),
59
+ )
60
+ end
56
61
 
57
- def string_keys
58
- @string_keys ||= Set.new(
59
- all_keys.select { |k| k.is_a?(::String) }
60
- )
61
- end
62
+ def string_keys
63
+ @string_keys ||= Set.new(
64
+ all_keys.select { |k| k.is_a?(::String) },
65
+ )
66
+ end
62
67
 
63
- def all_keys
64
- @all_keys ||= hash_attributes.map(&:key)
68
+ def all_keys
69
+ @all_keys ||= hash_attributes.map(&:key)
70
+ end
65
71
  end
72
+ end
66
73
  end
67
-
68
- end
69
- end
70
74
  end
@@ -1,22 +1,29 @@
1
- module RSchema
2
- module Coercers
1
+ # frozen_string_literal: true
3
2
 
4
- module Float
5
- extend self
3
+ module RSchema
4
+ module Coercers
5
+ #
6
+ # Coerces values into `Float` objects using `Kernel#Float`
7
+ #
8
+ module Float
9
+ extend self
6
10
 
7
- def build(schema)
8
- self
9
- end
11
+ def build(_schema)
12
+ self
13
+ end
10
14
 
11
- def call(value)
12
- flt = Float(value) rescue nil
13
- flt ? Result.success(flt) : Result.failure
14
- end
15
+ def call(value)
16
+ flt = begin
17
+ Float(value)
18
+ rescue
19
+ nil
20
+ end
21
+ flt ? Result.success(flt) : Result.failure
22
+ end
15
23
 
16
- def will_affect?(value)
17
- not value.is_a?(Float)
24
+ def will_affect?(value)
25
+ !value.is_a?(Float)
26
+ end
18
27
  end
19
28
  end
20
-
21
- end
22
29
  end
@@ -1,22 +1,28 @@
1
- module RSchema
2
- module Coercers
1
+ # frozen_string_literal: true
3
2
 
4
- module Integer
5
- extend self
3
+ module RSchema
4
+ module Coercers
5
+ #
6
+ # Coerces values to `Integer`s using `Kernel#Integer`
7
+ module Integer
8
+ extend self
6
9
 
7
- def build(schema)
8
- self
9
- end
10
+ def build(_schema)
11
+ self
12
+ end
10
13
 
11
- def call(value)
12
- int = Integer(value) rescue nil
13
- int ? Result.success(int) : Result.failure
14
- end
14
+ def call(value)
15
+ int = begin
16
+ Integer(value)
17
+ rescue
18
+ nil
19
+ end
20
+ int ? Result.success(int) : Result.failure
21
+ end
15
22
 
16
- def will_affect?(value)
17
- not value.is_a?(Integer)
23
+ def will_affect?(value)
24
+ !value.is_a?(Integer)
25
+ end
18
26
  end
19
27
  end
20
-
21
- end
22
28
  end
@@ -1,25 +1,28 @@
1
- module RSchema
2
- module Coercers
1
+ # frozen_string_literal: true
3
2
 
4
- module NilEmptyStrings
5
- extend self
3
+ module RSchema
4
+ module Coercers
5
+ #
6
+ # Coerces empty strings to `nil`
7
+ #
8
+ module NilEmptyStrings
9
+ extend self
6
10
 
7
- def build(schema)
8
- self
9
- end
11
+ def build(_schema)
12
+ self
13
+ end
10
14
 
11
- def call(value)
12
- if "" == value
13
- Result.success(nil)
14
- else
15
- Result.success(value)
15
+ def call(value)
16
+ if value == ''
17
+ Result.success(nil)
18
+ else
19
+ Result.success(value)
20
+ end
16
21
  end
17
- end
18
22
 
19
- def will_affect?(value)
20
- "" == value
23
+ def will_affect?(value)
24
+ value == ''
25
+ end
21
26
  end
22
27
  end
23
-
24
- end
25
28
  end