schemacop 2.3.2 → 2.4.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.
Files changed (69) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +15 -0
  3. data/README.md +190 -2
  4. data/RUBY_VERSION +1 -1
  5. data/Rakefile +6 -5
  6. data/VERSION +1 -1
  7. data/doc/Schemacop.html +30 -3
  8. data/doc/Schemacop/ArrayValidator.html +2 -2
  9. data/doc/Schemacop/BooleanValidator.html +1 -1
  10. data/doc/Schemacop/Caster.html +379 -0
  11. data/doc/Schemacop/Collector.html +178 -102
  12. data/doc/Schemacop/Exceptions.html +1 -1
  13. data/doc/Schemacop/Exceptions/InvalidSchemaError.html +1 -1
  14. data/doc/Schemacop/Exceptions/ValidationError.html +1 -1
  15. data/doc/Schemacop/FieldNode.html +17 -5
  16. data/doc/Schemacop/FloatValidator.html +1 -1
  17. data/doc/Schemacop/HashValidator.html +1 -1
  18. data/doc/Schemacop/IntegerValidator.html +1 -1
  19. data/doc/Schemacop/NilValidator.html +1 -1
  20. data/doc/Schemacop/Node.html +95 -83
  21. data/doc/Schemacop/NodeResolver.html +26 -10
  22. data/doc/Schemacop/NodeSupportingField.html +1 -1
  23. data/doc/Schemacop/NodeSupportingType.html +2 -4
  24. data/doc/Schemacop/NodeWithBlock.html +1 -1
  25. data/doc/Schemacop/NumberValidator.html +1 -1
  26. data/doc/Schemacop/ObjectValidator.html +1 -1
  27. data/doc/Schemacop/RootNode.html +1 -1
  28. data/doc/Schemacop/Schema.html +3 -3
  29. data/doc/Schemacop/StringValidator.html +1 -1
  30. data/doc/Schemacop/SymbolValidator.html +1 -1
  31. data/doc/ScopedEnv.html +1 -1
  32. data/doc/_index.html +8 -1
  33. data/doc/class_list.html +1 -1
  34. data/doc/file.README.html +184 -3
  35. data/doc/index.html +184 -3
  36. data/doc/method_list.html +93 -61
  37. data/doc/top-level-namespace.html +1 -1
  38. data/lib/schemacop.rb +14 -0
  39. data/lib/schemacop/caster.rb +38 -0
  40. data/lib/schemacop/collector.rb +34 -6
  41. data/lib/schemacop/field_node.rb +25 -3
  42. data/lib/schemacop/node.rb +10 -2
  43. data/lib/schemacop/node_resolver.rb +10 -2
  44. data/lib/schemacop/node_supporting_type.rb +21 -1
  45. data/lib/schemacop/schema.rb +2 -2
  46. data/lib/schemacop/validator/array_validator.rb +1 -1
  47. data/lib/schemacop/validator/float_validator.rb +1 -1
  48. data/lib/schemacop/validator/integer_validator.rb +1 -1
  49. data/schemacop.gemspec +14 -8
  50. data/test/casting_test.rb +90 -0
  51. data/test/custom_check_test.rb +14 -14
  52. data/test/custom_if_test.rb +12 -12
  53. data/test/defaults_test.rb +71 -0
  54. data/test/nil_dis_allow_test.rb +6 -6
  55. data/test/node_resolver_test.rb +26 -0
  56. data/test/short_forms_test.rb +73 -66
  57. data/test/test_helper.rb +7 -0
  58. data/test/types_test.rb +5 -5
  59. data/test/validator_array_test.rb +16 -16
  60. data/test/validator_boolean_test.rb +2 -2
  61. data/test/validator_float_test.rb +15 -15
  62. data/test/validator_hash_test.rb +5 -5
  63. data/test/validator_integer_test.rb +9 -9
  64. data/test/validator_nil_test.rb +1 -1
  65. data/test/validator_number_test.rb +19 -19
  66. data/test/validator_object_test.rb +18 -18
  67. data/test/validator_string_test.rb +12 -12
  68. data/test/validator_symbol_test.rb +2 -2
  69. metadata +42 -6
@@ -102,7 +102,7 @@
102
102
  </div>
103
103
 
104
104
  <div id="footer">
105
- Generated on Thu Sep 26 13:19:46 2019 by
105
+ Generated on Mon Oct 28 16:21:59 2019 by
106
106
  <a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
107
107
  0.9.20 (ruby-2.6.2).
108
108
  </div>
@@ -1,9 +1,22 @@
1
1
  module Schemacop
2
+ DEFAULT_CASTERS = {
3
+ String => {
4
+ Integer => proc { |s| Integer(s) },
5
+ Float => proc { |s| Float(s) }
6
+ },
7
+ Float => {
8
+ Integer => proc { |f| Integer(f) }
9
+ },
10
+ Integer => {
11
+ Float => proc { |f| Float(f) }
12
+ }
13
+ }
2
14
  end
3
15
 
4
16
  require 'set'
5
17
  require 'active_support/core_ext/class/attribute'
6
18
  require 'active_support/hash_with_indifferent_access'
19
+ require 'active_support/core_ext/object/deep_dup'
7
20
 
8
21
  require 'schemacop/scoped_env'
9
22
  require 'schemacop/exceptions'
@@ -16,6 +29,7 @@ require 'schemacop/node_supporting_type'
16
29
  require 'schemacop/field_node'
17
30
  require 'schemacop/root_node'
18
31
  require 'schemacop/node_supporting_field'
32
+ require 'schemacop/caster'
19
33
  require 'schemacop/validator/array_validator'
20
34
  require 'schemacop/validator/boolean_validator'
21
35
  require 'schemacop/validator/hash_validator'
@@ -0,0 +1,38 @@
1
+ module Schemacop
2
+ class Caster
3
+ def initialize(casts, data, target_type)
4
+ @casts = casts
5
+ @data = data
6
+ @target_type = target_type
7
+ @caster = nil
8
+
9
+ if casts.is_a?(Array)
10
+ from_types = casts
11
+ elsif casts.is_a?(Hash)
12
+ from_types = casts.keys
13
+ else
14
+ fail Exceptions::InvalidSchemaError, "Option `cast` must be either an array or a hash."
15
+ end
16
+
17
+ return unless from_types.include?(data.class)
18
+
19
+ if (casts.is_a?(Array) && casts.include?(data.class)) || casts[data.class] == :default
20
+ @caster = DEFAULT_CASTERS[data.class][target_type]
21
+ else
22
+ @caster = casts[data.class]
23
+ end
24
+ end
25
+
26
+ def castable?
27
+ !@caster.nil?
28
+ end
29
+
30
+ def cast
31
+ fail 'Not castable.' unless castable?
32
+ return @caster.call(@data)
33
+ rescue => e
34
+ fail Exceptions::InvalidSchemaError,
35
+ "Could not cast value #{@value.inspect} to #{@target_type}: #{e.message}."
36
+ end
37
+ end
38
+ end
@@ -1,12 +1,18 @@
1
1
  module Schemacop
2
2
  class Collector
3
- attr_reader :current_path
4
3
  attr_reader :exceptions
5
4
 
6
- def initialize
5
+ def initialize(data)
7
6
  @exceptions = []
8
7
  @current_path = []
9
8
  @ignore_next_segment = false
9
+ @current_datappoint_path = [data]
10
+ @current_index = nil
11
+ end
12
+
13
+ def data
14
+ return nil unless valid?
15
+ @current_datappoint_path.first
10
16
  end
11
17
 
12
18
  def valid?
@@ -14,20 +20,42 @@ module Schemacop
14
20
  end
15
21
 
16
22
  # Construct the current path
17
- def path(segment)
23
+ def path(segment, index, type)
18
24
  ignore_this_segment = false
25
+
26
+ previous_index = @current_index
27
+
19
28
  if @ignore_next_segment
20
29
  ignore_this_segment = true
21
30
  @ignore_next_segment = false
31
+ else
32
+ unless @current_datappoint_path.last
33
+ if type == :hash
34
+ @current_datappoint_path[-1] = {}
35
+ else
36
+ @current_datappoint_path[-1] = []
37
+ end
38
+ end
39
+ @current_path << segment unless ignore_this_segment
40
+ @current_datappoint_path << @current_datappoint_path.last[index]
41
+ @current_index = index
22
42
  end
23
43
 
24
- @current_path << segment unless ignore_this_segment
25
-
26
44
  yield
27
45
  ensure
46
+ @current_index = previous_index
47
+ @current_datappoint_path.pop unless ignore_this_segment
28
48
  @current_path.pop unless ignore_this_segment
29
49
  end
30
50
 
51
+ def override_value(value)
52
+ if @current_datappoint_path.size > 1
53
+ @current_datappoint_path[-2][@current_index] = value
54
+ else
55
+ @current_datappoint_path[0] = value
56
+ end
57
+ end
58
+
31
59
  def exception_message
32
60
  return "Schemacop validation failed:\n" + @exceptions.map do |e|
33
61
  "- #{e[:path].join('')}: #{e[:message]}"
@@ -36,7 +64,7 @@ module Schemacop
36
64
 
37
65
  def error(error_msg)
38
66
  @exceptions << {
39
- path: current_path.dup,
67
+ path: @current_path.dup,
40
68
  message: error_msg
41
69
  }
42
70
  end
@@ -16,11 +16,33 @@ module Schemacop
16
16
  def validate(data, collector)
17
17
  unless data.key?(name)
18
18
  collector.error "Missing key #{name.inspect}." if @required
19
- return
20
19
  end
21
- collector.path "/#{name}" do
22
- super(data[name], collector)
20
+
21
+ collector.path "/#{name}", name, :hash do
22
+ value, default_applied = apply_default!(data[name], collector)
23
+
24
+ unless data.key?(name) || default_applied
25
+ next
26
+ end
27
+
28
+ super(value, collector)
23
29
  end
24
30
  end
31
+
32
+ private
33
+
34
+ def apply_default!(data, collector)
35
+ return data, false unless data.nil?
36
+
37
+ @types.each do |type|
38
+ if type.option?(:default)
39
+ default = type.option(:default)
40
+ collector.override_value(default)
41
+ return default, true
42
+ end
43
+ end
44
+
45
+ return nil, false
46
+ end
25
47
  end
26
48
  end
@@ -17,6 +17,8 @@ module Schemacop
17
17
 
18
18
  option :if
19
19
  option :check
20
+ option :cast
21
+ option :default
20
22
 
21
23
  def type_label
22
24
  str = (symbols.first || 'unknown').to_s
@@ -40,8 +42,8 @@ module Schemacop
40
42
  self.klasses = [].freeze
41
43
  end
42
44
 
43
- def self.register(symbols: [], klasses: [], clear: true)
44
- NodeResolver.register(self)
45
+ def self.register(symbols: [], klasses: [], clear: true, before: nil)
46
+ NodeResolver.register(self, before: before)
45
47
  symbols = [*symbols]
46
48
  klasses = [*klasses]
47
49
  if clear
@@ -80,6 +82,12 @@ module Schemacop
80
82
  fail Exceptions::InvalidSchemaError,
81
83
  "Unrecognized option(s) #{obsolete_opts.inspect} for #{self.class.inspect}, allowed options: #{self.class.allowed_options.keys.inspect}."
82
84
  end
85
+
86
+ if option?(:cast) && self.class.klasses.size > 1
87
+ fail Exceptions::InvalidSchemaError,
88
+ "Casting is only allowed for single-value datatypes, but type #{self.class.inspect} has classes "\
89
+ "#{self.class.klasses.map(&:inspect)}."
90
+ end
83
91
  end
84
92
 
85
93
  def option(key)
@@ -3,8 +3,16 @@ module Schemacop
3
3
  class_attribute :node_classes
4
4
  self.node_classes = [].freeze
5
5
 
6
- def self.register(node_class)
7
- self.node_classes += [node_class]
6
+ def self.register(node_class, before: nil)
7
+ if before
8
+ unless (index = self.node_classes.find_index(before))
9
+ fail "Cannot insert before class #{before} which has not been registered yet."
10
+ end
11
+
12
+ self.node_classes.insert(index, node_class)
13
+ else
14
+ self.node_classes += [node_class]
15
+ end
8
16
  end
9
17
 
10
18
  def self.resolve(type)
@@ -93,13 +93,33 @@ module Schemacop
93
93
 
94
94
  def validate(data, collector)
95
95
  super
96
-
97
96
  validate_types(data, collector)
98
97
  end
99
98
 
100
99
  protected
101
100
 
101
+ def cast!(data, collector)
102
+ @types.each do |type|
103
+ if type.option?(:cast) && !type.type_matches?(data) && type.type_filter_matches?(data)
104
+ caster = Caster.new(type.option(:cast), data, type.class.klasses.first)
105
+
106
+ if caster.castable?
107
+ begin
108
+ data = caster.cast
109
+ collector.override_value(data)
110
+ return data
111
+ rescue Exceptions::InvalidSchemaError => e
112
+ collector.error e.message
113
+ end
114
+ end
115
+ end
116
+ end
117
+
118
+ return data
119
+ end
120
+
102
121
  def validate_types(data, collector)
122
+ data = cast!(data, collector)
103
123
  unless (match = @types.find { |t| t.type_matches?(data) })
104
124
  allowed_types = @types.map(&:type_label)
105
125
 
@@ -37,7 +37,7 @@ module Schemacop
37
37
  # @return [Schemacop::Collector] The object that collected errors
38
38
  # throughout the validation.
39
39
  def validate(data)
40
- collector = Collector.new
40
+ collector = Collector.new(data.deep_dup)
41
41
  @root.fields[:root].validate({ root: data }, collector.ignore_next_segment)
42
42
  return collector
43
43
  end
@@ -55,7 +55,7 @@ module Schemacop
55
55
  fail Exceptions::ValidationError, collector.exception_message
56
56
  end
57
57
 
58
- return nil
58
+ return collector.data
59
59
  end
60
60
  end
61
61
  end
@@ -21,7 +21,7 @@ module Schemacop
21
21
  collector.error "Array must have less (<=) than #{option(:max)} elements."
22
22
  end
23
23
  data.each_with_index do |entry, index|
24
- collector.path("[#{index}]") do
24
+ collector.path("[#{index}]", index, :array) do
25
25
  validate_types(entry, collector)
26
26
  end
27
27
  end
@@ -1,5 +1,5 @@
1
1
  module Schemacop
2
2
  class FloatValidator < NumberValidator
3
- register symbols: :float, klasses: Float
3
+ register symbols: :float, klasses: Float, before: NumberValidator
4
4
  end
5
5
  end
@@ -1,5 +1,5 @@
1
1
  module Schemacop
2
2
  class IntegerValidator < NumberValidator
3
- register symbols: :integer, klasses: Integer
3
+ register symbols: :integer, klasses: Integer, before: NumberValidator
4
4
  end
5
5
  end
@@ -1,54 +1,60 @@
1
1
  # -*- encoding: utf-8 -*-
2
- # stub: schemacop 2.3.2 ruby lib
2
+ # stub: schemacop 2.4.0 ruby lib
3
3
 
4
4
  Gem::Specification.new do |s|
5
5
  s.name = "schemacop".freeze
6
- s.version = "2.3.2"
6
+ s.version = "2.4.0"
7
7
 
8
8
  s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
9
9
  s.require_paths = ["lib".freeze]
10
10
  s.authors = ["Sitrox".freeze]
11
- s.date = "2019-09-26"
12
- s.files = [".gitignore".freeze, ".releaser_config".freeze, ".rubocop.yml".freeze, ".travis.yml".freeze, ".yardopts".freeze, "CHANGELOG.md".freeze, "Gemfile".freeze, "LICENSE".freeze, "README.md".freeze, "RUBY_VERSION".freeze, "Rakefile".freeze, "VERSION".freeze, "doc/Schemacop.html".freeze, "doc/Schemacop/ArrayValidator.html".freeze, "doc/Schemacop/BooleanValidator.html".freeze, "doc/Schemacop/Collector.html".freeze, "doc/Schemacop/Exceptions.html".freeze, "doc/Schemacop/Exceptions/InvalidSchemaError.html".freeze, "doc/Schemacop/Exceptions/ValidationError.html".freeze, "doc/Schemacop/FieldNode.html".freeze, "doc/Schemacop/FloatValidator.html".freeze, "doc/Schemacop/HashValidator.html".freeze, "doc/Schemacop/IntegerValidator.html".freeze, "doc/Schemacop/NilValidator.html".freeze, "doc/Schemacop/Node.html".freeze, "doc/Schemacop/NodeResolver.html".freeze, "doc/Schemacop/NodeSupportingField.html".freeze, "doc/Schemacop/NodeSupportingType.html".freeze, "doc/Schemacop/NodeWithBlock.html".freeze, "doc/Schemacop/NumberValidator.html".freeze, "doc/Schemacop/ObjectValidator.html".freeze, "doc/Schemacop/RootNode.html".freeze, "doc/Schemacop/Schema.html".freeze, "doc/Schemacop/StringValidator.html".freeze, "doc/Schemacop/SymbolValidator.html".freeze, "doc/ScopedEnv.html".freeze, "doc/_index.html".freeze, "doc/class_list.html".freeze, "doc/css/common.css".freeze, "doc/css/full_list.css".freeze, "doc/css/style.css".freeze, "doc/file.README.html".freeze, "doc/file_list.html".freeze, "doc/frames.html".freeze, "doc/index.html".freeze, "doc/inheritance.graphml".freeze, "doc/inheritance.pdf".freeze, "doc/js/app.js".freeze, "doc/js/full_list.js".freeze, "doc/js/jquery.js".freeze, "doc/method_list.html".freeze, "doc/top-level-namespace.html".freeze, "lib/schemacop.rb".freeze, "lib/schemacop/collector.rb".freeze, "lib/schemacop/exceptions.rb".freeze, "lib/schemacop/field_node.rb".freeze, "lib/schemacop/node.rb".freeze, "lib/schemacop/node_resolver.rb".freeze, "lib/schemacop/node_supporting_field.rb".freeze, "lib/schemacop/node_supporting_type.rb".freeze, "lib/schemacop/node_with_block.rb".freeze, "lib/schemacop/root_node.rb".freeze, "lib/schemacop/schema.rb".freeze, "lib/schemacop/scoped_env.rb".freeze, "lib/schemacop/validator/array_validator.rb".freeze, "lib/schemacop/validator/boolean_validator.rb".freeze, "lib/schemacop/validator/float_validator.rb".freeze, "lib/schemacop/validator/hash_validator.rb".freeze, "lib/schemacop/validator/integer_validator.rb".freeze, "lib/schemacop/validator/nil_validator.rb".freeze, "lib/schemacop/validator/number_validator.rb".freeze, "lib/schemacop/validator/object_validator.rb".freeze, "lib/schemacop/validator/string_validator.rb".freeze, "lib/schemacop/validator/symbol_validator.rb".freeze, "schemacop.gemspec".freeze, "test/collector_test.rb".freeze, "test/custom_check_test.rb".freeze, "test/custom_if_test.rb".freeze, "test/nil_dis_allow_test.rb".freeze, "test/short_forms_test.rb".freeze, "test/test_helper.rb".freeze, "test/types_test.rb".freeze, "test/validator_array_test.rb".freeze, "test/validator_boolean_test.rb".freeze, "test/validator_float_test.rb".freeze, "test/validator_hash_test.rb".freeze, "test/validator_integer_test.rb".freeze, "test/validator_nil_test.rb".freeze, "test/validator_number_test.rb".freeze, "test/validator_object_test.rb".freeze, "test/validator_string_test.rb".freeze, "test/validator_symbol_test.rb".freeze]
11
+ s.date = "2019-10-28"
12
+ s.files = [".gitignore".freeze, ".releaser_config".freeze, ".rubocop.yml".freeze, ".travis.yml".freeze, ".yardopts".freeze, "CHANGELOG.md".freeze, "Gemfile".freeze, "LICENSE".freeze, "README.md".freeze, "RUBY_VERSION".freeze, "Rakefile".freeze, "VERSION".freeze, "doc/Schemacop.html".freeze, "doc/Schemacop/ArrayValidator.html".freeze, "doc/Schemacop/BooleanValidator.html".freeze, "doc/Schemacop/Caster.html".freeze, "doc/Schemacop/Collector.html".freeze, "doc/Schemacop/Exceptions.html".freeze, "doc/Schemacop/Exceptions/InvalidSchemaError.html".freeze, "doc/Schemacop/Exceptions/ValidationError.html".freeze, "doc/Schemacop/FieldNode.html".freeze, "doc/Schemacop/FloatValidator.html".freeze, "doc/Schemacop/HashValidator.html".freeze, "doc/Schemacop/IntegerValidator.html".freeze, "doc/Schemacop/NilValidator.html".freeze, "doc/Schemacop/Node.html".freeze, "doc/Schemacop/NodeResolver.html".freeze, "doc/Schemacop/NodeSupportingField.html".freeze, "doc/Schemacop/NodeSupportingType.html".freeze, "doc/Schemacop/NodeWithBlock.html".freeze, "doc/Schemacop/NumberValidator.html".freeze, "doc/Schemacop/ObjectValidator.html".freeze, "doc/Schemacop/RootNode.html".freeze, "doc/Schemacop/Schema.html".freeze, "doc/Schemacop/StringValidator.html".freeze, "doc/Schemacop/SymbolValidator.html".freeze, "doc/ScopedEnv.html".freeze, "doc/_index.html".freeze, "doc/class_list.html".freeze, "doc/css/common.css".freeze, "doc/css/full_list.css".freeze, "doc/css/style.css".freeze, "doc/file.README.html".freeze, "doc/file_list.html".freeze, "doc/frames.html".freeze, "doc/index.html".freeze, "doc/inheritance.graphml".freeze, "doc/inheritance.pdf".freeze, "doc/js/app.js".freeze, "doc/js/full_list.js".freeze, "doc/js/jquery.js".freeze, "doc/method_list.html".freeze, "doc/top-level-namespace.html".freeze, "lib/schemacop.rb".freeze, "lib/schemacop/caster.rb".freeze, "lib/schemacop/collector.rb".freeze, "lib/schemacop/exceptions.rb".freeze, "lib/schemacop/field_node.rb".freeze, "lib/schemacop/node.rb".freeze, "lib/schemacop/node_resolver.rb".freeze, "lib/schemacop/node_supporting_field.rb".freeze, "lib/schemacop/node_supporting_type.rb".freeze, "lib/schemacop/node_with_block.rb".freeze, "lib/schemacop/root_node.rb".freeze, "lib/schemacop/schema.rb".freeze, "lib/schemacop/scoped_env.rb".freeze, "lib/schemacop/validator/array_validator.rb".freeze, "lib/schemacop/validator/boolean_validator.rb".freeze, "lib/schemacop/validator/float_validator.rb".freeze, "lib/schemacop/validator/hash_validator.rb".freeze, "lib/schemacop/validator/integer_validator.rb".freeze, "lib/schemacop/validator/nil_validator.rb".freeze, "lib/schemacop/validator/number_validator.rb".freeze, "lib/schemacop/validator/object_validator.rb".freeze, "lib/schemacop/validator/string_validator.rb".freeze, "lib/schemacop/validator/symbol_validator.rb".freeze, "schemacop.gemspec".freeze, "test/casting_test.rb".freeze, "test/collector_test.rb".freeze, "test/custom_check_test.rb".freeze, "test/custom_if_test.rb".freeze, "test/defaults_test.rb".freeze, "test/nil_dis_allow_test.rb".freeze, "test/node_resolver_test.rb".freeze, "test/short_forms_test.rb".freeze, "test/test_helper.rb".freeze, "test/types_test.rb".freeze, "test/validator_array_test.rb".freeze, "test/validator_boolean_test.rb".freeze, "test/validator_float_test.rb".freeze, "test/validator_hash_test.rb".freeze, "test/validator_integer_test.rb".freeze, "test/validator_nil_test.rb".freeze, "test/validator_number_test.rb".freeze, "test/validator_object_test.rb".freeze, "test/validator_string_test.rb".freeze, "test/validator_symbol_test.rb".freeze]
13
13
  s.homepage = "https://github.com/sitrox/schemacop".freeze
14
14
  s.licenses = ["MIT".freeze]
15
15
  s.rubygems_version = "3.0.3".freeze
16
16
  s.summary = "Schemacop validates ruby structures consisting of nested hashes and arrays against simple schema definitions.".freeze
17
- s.test_files = ["test/collector_test.rb".freeze, "test/custom_check_test.rb".freeze, "test/custom_if_test.rb".freeze, "test/nil_dis_allow_test.rb".freeze, "test/short_forms_test.rb".freeze, "test/test_helper.rb".freeze, "test/types_test.rb".freeze, "test/validator_array_test.rb".freeze, "test/validator_boolean_test.rb".freeze, "test/validator_float_test.rb".freeze, "test/validator_hash_test.rb".freeze, "test/validator_integer_test.rb".freeze, "test/validator_nil_test.rb".freeze, "test/validator_number_test.rb".freeze, "test/validator_object_test.rb".freeze, "test/validator_string_test.rb".freeze, "test/validator_symbol_test.rb".freeze]
17
+ s.test_files = ["test/casting_test.rb".freeze, "test/collector_test.rb".freeze, "test/custom_check_test.rb".freeze, "test/custom_if_test.rb".freeze, "test/defaults_test.rb".freeze, "test/nil_dis_allow_test.rb".freeze, "test/node_resolver_test.rb".freeze, "test/short_forms_test.rb".freeze, "test/test_helper.rb".freeze, "test/types_test.rb".freeze, "test/validator_array_test.rb".freeze, "test/validator_boolean_test.rb".freeze, "test/validator_float_test.rb".freeze, "test/validator_hash_test.rb".freeze, "test/validator_integer_test.rb".freeze, "test/validator_nil_test.rb".freeze, "test/validator_number_test.rb".freeze, "test/validator_object_test.rb".freeze, "test/validator_string_test.rb".freeze, "test/validator_symbol_test.rb".freeze]
18
18
 
19
19
  if s.respond_to? :specification_version then
20
20
  s.specification_version = 4
21
21
 
22
22
  if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
23
+ s.add_runtime_dependency(%q<activesupport>.freeze, [">= 4.0"])
23
24
  s.add_development_dependency(%q<bundler>.freeze, ["~> 1.3"])
24
25
  s.add_development_dependency(%q<rake>.freeze, [">= 0"])
25
26
  s.add_development_dependency(%q<ci_reporter>.freeze, ["~> 2.0"])
26
27
  s.add_development_dependency(%q<ci_reporter_minitest>.freeze, [">= 0"])
27
28
  s.add_development_dependency(%q<haml>.freeze, [">= 0"])
29
+ s.add_development_dependency(%q<colorize>.freeze, [">= 0"])
28
30
  s.add_development_dependency(%q<yard>.freeze, [">= 0"])
29
31
  s.add_development_dependency(%q<rubocop>.freeze, ["= 0.35.1"])
30
32
  s.add_development_dependency(%q<redcarpet>.freeze, [">= 0"])
31
- s.add_runtime_dependency(%q<activesupport>.freeze, [">= 4.0"])
33
+ s.add_development_dependency(%q<pry>.freeze, [">= 0"])
32
34
  else
35
+ s.add_dependency(%q<activesupport>.freeze, [">= 4.0"])
33
36
  s.add_dependency(%q<bundler>.freeze, ["~> 1.3"])
34
37
  s.add_dependency(%q<rake>.freeze, [">= 0"])
35
38
  s.add_dependency(%q<ci_reporter>.freeze, ["~> 2.0"])
36
39
  s.add_dependency(%q<ci_reporter_minitest>.freeze, [">= 0"])
37
40
  s.add_dependency(%q<haml>.freeze, [">= 0"])
41
+ s.add_dependency(%q<colorize>.freeze, [">= 0"])
38
42
  s.add_dependency(%q<yard>.freeze, [">= 0"])
39
43
  s.add_dependency(%q<rubocop>.freeze, ["= 0.35.1"])
40
44
  s.add_dependency(%q<redcarpet>.freeze, [">= 0"])
41
- s.add_dependency(%q<activesupport>.freeze, [">= 4.0"])
45
+ s.add_dependency(%q<pry>.freeze, [">= 0"])
42
46
  end
43
47
  else
48
+ s.add_dependency(%q<activesupport>.freeze, [">= 4.0"])
44
49
  s.add_dependency(%q<bundler>.freeze, ["~> 1.3"])
45
50
  s.add_dependency(%q<rake>.freeze, [">= 0"])
46
51
  s.add_dependency(%q<ci_reporter>.freeze, ["~> 2.0"])
47
52
  s.add_dependency(%q<ci_reporter_minitest>.freeze, [">= 0"])
48
53
  s.add_dependency(%q<haml>.freeze, [">= 0"])
54
+ s.add_dependency(%q<colorize>.freeze, [">= 0"])
49
55
  s.add_dependency(%q<yard>.freeze, [">= 0"])
50
56
  s.add_dependency(%q<rubocop>.freeze, ["= 0.35.1"])
51
57
  s.add_dependency(%q<redcarpet>.freeze, [">= 0"])
52
- s.add_dependency(%q<activesupport>.freeze, [">= 4.0"])
58
+ s.add_dependency(%q<pry>.freeze, [">= 0"])
53
59
  end
54
60
  end
@@ -0,0 +1,90 @@
1
+ require 'test_helper'
2
+
3
+ module Schemacop
4
+ class CastingTest < Minitest::Test
5
+ def test_basic
6
+ s = Schema.new :integer, cast: [String]
7
+
8
+ input = '42'
9
+ output = s.validate!(input)
10
+
11
+ assert_equal(42, output)
12
+ end
13
+
14
+ def test_field
15
+ s = Schema.new do
16
+ req :foo, :integer, cast: [String]
17
+ end
18
+
19
+ input = { foo: '42' }
20
+ output = s.validate!(input)
21
+
22
+ assert_equal({ foo: '42' }, input)
23
+ assert_equal({ foo: 42 }, output)
24
+ end
25
+
26
+ def test_first_type_matches
27
+ s = Schema.new do
28
+ type TrueClass
29
+ type :integer, cast: [String]
30
+ end
31
+
32
+ assert_equal(42, s.validate!('42'))
33
+ assert_equal(42, s.validate!(42))
34
+ assert_equal(true, s.validate!(true))
35
+ end
36
+
37
+ def test_with_if
38
+ s = Schema.new do
39
+ type Float, if: proc { |data| !data.is_a?(String) || data.match(/\d+\.\d+/) }, cast: [String]
40
+ type Integer, cast: [String]
41
+ end
42
+
43
+ assert_equal 42.2, s.validate!('42.2')
44
+ assert_equal 42, s.validate!('42')
45
+ end
46
+
47
+ def test_arrays
48
+ s = Schema.new do
49
+ req :foo, :array, :integer, cast: [String]
50
+ end
51
+
52
+ assert_equal(
53
+ { foo: [1, 2, 3] },
54
+ s.validate!(foo: ['1', '2', '3'])
55
+ )
56
+ end
57
+
58
+ def test_check_after_cast
59
+ s = Schema.new do
60
+ type Integer, cast: [String], check: proc { |v| v > 41 }
61
+ end
62
+
63
+ assert_equal 42, s.validate!('42')
64
+ assert_equal 43, s.validate!('43')
65
+ assert_equal 42, s.validate!(42)
66
+ assert_verr { s.validate!('41') }
67
+ assert_verr { s.validate!(42.2) }
68
+ end
69
+
70
+ def test_multilple_types
71
+ e = assert_raises Exceptions::InvalidSchemaError do
72
+ Schema.new do
73
+ type :number, cast: [String]
74
+ end
75
+ end
76
+
77
+ assert_equal 'Casting is only allowed for single-value datatypes, '\
78
+ 'but type Schemacop::NumberValidator has classes ["Integer", "Float"].',
79
+ e.message
80
+ end
81
+
82
+ def test_custom_castings
83
+ s = Schema.new do
84
+ type :integer, cast: { String => proc { |v| Integer(v) } }
85
+ end
86
+
87
+ assert_equal 42, s.validate!('42')
88
+ end
89
+ end
90
+ end