schemacop 2.3.2 → 2.4.0

Sign up to get free protection for your applications and to get access to all the features.
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