easy_json_matcher 0.4.1 → 0.5.0

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: ef40172819f1511b343e9f3dc378da1730ae0576
4
- data.tar.gz: 56913c7ee1b59003fb4949180b7bc2985803cee6
3
+ metadata.gz: b4ae72ea8cf0f22e7214a77bef9d439db03eccff
4
+ data.tar.gz: ca161753385c81aa57e6a43418664d807b1425ae
5
5
  SHA512:
6
- metadata.gz: 12e86e84712085c21d57f9db7606ea38577cfd2a590fe1c20b6b4ae67c6acb6bc09d630ec2cff2e70cc2c92c20b01a86a3a3da93302b53646a593242846f3549
7
- data.tar.gz: 5ba4fffa36e432c1b5f52ebfb350734840931d04073c89651f9ded8729cdc90bf709d4b77c52dad5076a09f37a8fdc064463999b8af0005dedb27feb4079046e
6
+ metadata.gz: 73ba46ee4cb3a9333e3b5ee56f2d18dced83580c2bd90fc95cbe77d18afb89e443aa141f5eb22d5216e1cb399f2fffbbff402ffb8c01d7f412986b7de02f953c
7
+ data.tar.gz: 7e7c1f2f0fa7abcad1c6a20a27aa87119b8c1997566e6b74f9b2eec3fedf2f59ee6523c77b4747174d919ba963a08d4a4e64a8ce9a311d2287669884e3d6076f
@@ -2,6 +2,7 @@ require "easy_json_matcher/container"
2
2
  require "easy_json_matcher/node"
3
3
  require "easy_json_matcher/schema_generator"
4
4
  require "easy_json_matcher/validator_set"
5
+ require "easy_json_matcher/printer"
5
6
 
6
7
  module EasyJSONMatcher
7
8
 
@@ -1,7 +1,7 @@
1
1
  module EasyJSONMatcher
2
2
  class ArrayContentValidator
3
3
 
4
- attr_reader :next_step, :verifier
4
+ attr_reader :verifier
5
5
 
6
6
  def initialize(verify_with:)
7
7
  @verifier = verify_with
@@ -10,13 +10,10 @@ module EasyJSONMatcher
10
10
  def call(value:)
11
11
  errors = []
12
12
  value.each do |val|
13
+ # TODO: You could remove the duplication of array content errors here
13
14
  errors += verifier.call(value: val)
14
15
  end
15
16
  errors
16
17
  end
17
-
18
- def >> (step)
19
- @next_step = step
20
- end
21
18
  end
22
19
  end
@@ -15,5 +15,6 @@ module EasyJSONMatcher
15
15
  def call(value:)
16
16
  verifier.call(value: value)
17
17
  end
18
+
18
19
  end
19
20
  end
@@ -2,7 +2,18 @@ module EasyJSONMatcher
2
2
  # Override of Ruby error for namespacing
3
3
  class Error < RuntimeError; end
4
4
 
5
- # Exception thrown by SchemaLibrary when a Schema is requested that has not
6
- # already been registered
7
- class MissingSchemaException < Error; end
5
+
6
+ class UnknownValidationStepError < Error
7
+
8
+ def error_message (type)
9
+ "No validator available for #{type},
10
+ you have either asked to validate a type that is not supported
11
+ or a schema that has not been defined. If it is the
12
+ former, consider using a custom validator"
13
+ end
14
+
15
+ def initialize(type)
16
+ super error_message(type)
17
+ end
18
+ end
8
19
  end
@@ -2,13 +2,13 @@ module EasyJSONMatcher
2
2
  class Node
3
3
  include AutoInject.kwargs[:node_content_validator, :chain_factory]
4
4
 
5
- attr_reader :node_validator, :validators
5
+ attr_reader :node_validator
6
6
 
7
7
  def initialize(opts: [], strict: false, validators:, **args)
8
8
  super(**args)
9
9
  @node_validator = chain_factory.get_chain(steps: opts + [:object])
10
- @validators = node_content_validator.new(validators: validators, strict: strict)
11
- @node_validator.concat(@validators)
10
+ validators = node_content_validator.new(validators: validators, strict: strict)
11
+ @node_validator.concat(validators)
12
12
  end
13
13
 
14
14
  def call(value:)
@@ -12,7 +12,6 @@ module EasyJSONMatcher
12
12
  @validators = {}
13
13
  @node_opts = extract_opts(local: opts, global: global_opts)
14
14
  @global_opts = global_opts
15
- yield self if block_given?
16
15
  end
17
16
 
18
17
  def generate_node
@@ -26,8 +25,8 @@ module EasyJSONMatcher
26
25
  end
27
26
 
28
27
  def contains_node(key:, opts: [], &block)
29
- if key == "alpha_2" then byebug end
30
- generator = self.class.new(opts: opts, global_opts: global_opts, &block)
28
+ generator = self.class.new(opts: opts, global_opts: global_opts)
29
+ generator.instance_eval &block if block_given?
31
30
  validators[key] = generator.generate_node
32
31
  end
33
32
 
@@ -0,0 +1,55 @@
1
+ module EasyJSONMatcher
2
+
3
+ # Class which is used to convert a node to a human-readable format for
4
+ # inspection purposes.
5
+
6
+ class Printer
7
+
8
+ attr_reader :n
9
+
10
+ def initialize(node:)
11
+ @n = node
12
+ end
13
+
14
+ def inspect
15
+ root_flag = "root: "
16
+ root_flag + pretty_print(n.validation_chain, root_flag.length)
17
+ end
18
+
19
+ def pretty_print(node, n)
20
+ depth = grow_s(n)
21
+ d = n + 1
22
+ case node
23
+ when Node
24
+ pretty_print node.node_validator, n
25
+ when Validator
26
+ pretty_print node.validation_chain, n
27
+ when ArrayValidator
28
+ pretty_print node.verifier, n
29
+ when ArrayContentValidator
30
+ pretty_print node.verifier, n
31
+ when ValidationRule
32
+ node.type.to_s
33
+ when ValidationStep
34
+ head = pretty_print node.verifier, d
35
+ tail = pretty_print node.next_step, n unless node.is_tail?
36
+ tail_string = tail ? "\n#{depth}#{tail}" : ""
37
+ "#{head} | #{tail_string}"
38
+ when ValidatorSet
39
+ parts = node.validators.each_with_object([]) do |k_v, out|
40
+ key_padding = d + k_v[0].length + 1
41
+ out << "#{k_v[0]}: #{pretty_print k_v[1], key_padding}\n"
42
+ end
43
+ parts.join(depth)
44
+ else
45
+ throw Error.new(node.class.to_s)
46
+ end
47
+ end
48
+
49
+ def grow_s(n)
50
+ buffer = ""
51
+ n.times { buffer << " " }
52
+ buffer
53
+ end
54
+ end
55
+ end
@@ -21,20 +21,14 @@ module EasyJSONMatcher
21
21
 
22
22
  # TODO: error message should read "called #{name}, not with #{name}"
23
23
  def get_schema(name:, opts: {})
24
- if schema = SCHEMAS[name]
25
- schema
26
- else
27
- lambda do |value|
28
- SCHEMAS[name]&.call(value: value) or raise MissingSchemaException.new(schema_name: name)
29
- end
30
- end
24
+ -> (value:) {
25
+ SCHEMAS[name]&.call(value: value) or raise UnknownValidationStepError.new(name)
26
+ }
31
27
  end
32
28
 
33
- # TODO: this method should use get_schema to ensure schema presence is
34
- # checked
35
- def use_schema(name:, wrap_with: Validator)
36
- wrap_with.new validate_with: get_schema(name: name)
37
- end
29
+ def use_schema(name:, wrap_with: Validator)
30
+ wrap_with.new validate_with: get_schema(name: name)
38
31
  end
39
32
  end
40
33
  end
34
+ end
@@ -1,5 +1,4 @@
1
1
  require "easy_json_matcher/validation_step"
2
- require "easy_json_matcher/unknown_validation_step_error"
3
2
  require "easy_json_matcher/exceptions"
4
3
 
5
4
  module EasyJSONMatcher
@@ -15,24 +14,24 @@ module EasyJSONMatcher
15
14
 
16
15
  def assemble_chain(head:, steps:, step_type:)
17
16
  steps.inject(head) do |last_link, step|
18
- last_link >> get_step_for(validating: step, using: step_type)
17
+ last_link >> get_step_for(validating: step, uses: step_type)
19
18
  end
20
19
  end
21
20
 
22
21
  def create_head_for(steps:, step_type:)
23
- is_required = steps.include?(:required)
24
- get_step_for validating: is_required ? :required : :not_required, using: step_type
22
+ is_required = steps.delete(:required)
23
+ get_step_for validating: is_required ? :required : :not_required, uses: step_type
25
24
  end
26
25
 
27
- def get_step_for(validating:, using: ValidationStep)
26
+ def get_step_for(validating:, uses: ValidationStep)
28
27
  if validating.respond_to? :call
29
- using.new verify_with: validating
28
+ uses.new verify_with: validating
30
29
  elsif verifier = standard_validator(with: validating)
31
- using.new verify_with: verifier
30
+ uses.new verify_with: verifier
32
31
  elsif schema = SchemaLibrary.get_schema(name: validating)
33
32
  schema
34
33
  else
35
- #TODO this needs a little finesse: How will the user know if it was a missing schema?
34
+ #This is just here as a catch-all. The prior step should always succeed.
36
35
  raise UnknownValidationStepError.new(type: validating)
37
36
  end
38
37
  end
@@ -1,58 +1,81 @@
1
1
  module EasyJSONMatcher
2
2
 
3
- VALIDATION_RULES = {
4
- object: -> (value, errors) {
5
- unless value.is_a? Hash
6
- errors << "#{value} is not an Object"
7
- return false
8
- end
9
- },
10
- string: -> (value, errors) {
11
- unless value.is_a? String
12
- errors << "#{value} is not a String"
13
- return false
14
- end
15
- },
16
- number: -> (value, errors){
17
- error_message = "#{value} is not a Number"
18
- begin
19
- Kernel::Float(value)
20
- rescue ArgumentError, TypeError
21
- errors << error_message
22
- false
23
- end
24
- },
25
- date: ->(value, errors){
26
- require "date"
27
- error_message = "#{value} is not a valid SQL date"
28
- begin
29
- Date.strptime(value,"%Y-%m-%d")
30
- rescue ArgumentError, TypeError
31
- errors << error_message
32
- end
33
- },
34
- boolean: ->(value, errors){
35
- clazz = value.class
36
- unless [ TrueClass, FalseClass].include? clazz
37
- errors << "#{value} is not a Boolean"
38
- false
3
+ class ValidationRule
4
+
5
+ attr_reader :rule, :type
6
+
7
+ def initialize(type, rule)
8
+ @type = type
9
+ @rule = rule
39
10
  end
40
- },
41
- array: ->(value, errors){
42
- unless value.is_a? Array
43
- errors << "Value was not an array"
44
- false
11
+
12
+ def call(value, errors)
13
+ rule.call(value, errors)
45
14
  end
46
- },
47
- value: ->(value, errors){
48
- # This is a bit of a toughie since value can be any value, including nil
49
- },
50
- not_required: ->(value, errors){
51
- false if value.nil?
52
- },
53
- required: ->(value, errors){
15
+ end
16
+
17
+
18
+ VALIDATION_RULES = {
19
+ object: ValidationRule.new(:object, -> (value, errors) {
20
+ unless value.is_a? Hash
21
+ errors << "#{value} is not an Object"
22
+ return false
23
+ end
24
+ }),
25
+
26
+ string: ValidationRule.new(:string, -> (value, errors) {
27
+ unless value.is_a? String
28
+ errors << "#{value} is not a String"
29
+ return false
30
+ end
31
+ }),
32
+
33
+ number: ValidationRule.new(:number, -> (value, errors){
34
+ error_message = "#{value} is not a Number"
35
+ begin
36
+ Kernel::Float(value)
37
+ rescue ArgumentError, TypeError
38
+ errors << error_message
39
+ false
40
+ end
41
+ }),
42
+
43
+ date: ValidationRule.new(:date, ->(value, errors){
44
+ require "date"
45
+ error_message = "#{value} is not a valid SQL date"
46
+ begin
47
+ Date.strptime(value,"%Y-%m-%d")
48
+ rescue ArgumentError, TypeError
49
+ errors << error_message
50
+ end
51
+ }),
52
+
53
+ boolean: ValidationRule.new(:boolean, ->(value, errors){
54
+ clazz = value.class
55
+ unless [ TrueClass, FalseClass].include? clazz
56
+ errors << "#{value} is not a Boolean"
57
+ false
58
+ end
59
+ }),
60
+
61
+ array: ValidationRule.new(:array, ->(value, errors){
62
+ unless value.is_a? Array
63
+ errors << "Value was not an array"
64
+ false
65
+ end
66
+ }),
67
+
68
+ value: ValidationRule.new(:value, ->(value, errors){
69
+ # This is a bit of a toughie since value can be any value, including nil
70
+ }),
71
+
72
+ not_required: ValidationRule.new(:not_required, ->(value, errors){
73
+ false if value.nil?
74
+ }),
75
+
76
+ required: ValidationRule.new(:required, ->(value, errors){
54
77
  errors << "no value found" and return false if value.nil?
55
- }
78
+ })
56
79
  }
57
80
  end
58
81
 
@@ -13,20 +13,29 @@ module EasyJSONMatcher
13
13
  def call(value:)
14
14
  error_hash = validators.each_with_object({}) do |k_v, errors_found|
15
15
  key = k_v[0]
16
- val = value[key]
16
+ val = value[key.to_s]
17
17
  validator = k_v[1]
18
18
  results = validator.call(value: val)
19
19
  errors_found[key] = results unless results.empty?
20
20
  end
21
21
  validate_strict_keyset(keys: validators.keys, candidates: value.keys, errors: error_hash) if strict
22
- errors = []
23
- errors << error_hash unless error_hash.empty?
24
- errors
22
+ if error_hash.empty? then [] else [error_hash] end
25
23
  end
26
24
 
27
25
  def validate_strict_keyset(keys:, errors:, candidates:)
26
+ missing_keys(keys: keys, errors: errors, candidates: candidates)
27
+ unexpected_keys(keys: keys, errors: errors, candidates: candidates)
28
+ end
29
+
30
+ def missing_keys(keys:, errors:, candidates:)
31
+ missing = keys - candidates
32
+ errors[:missing_keys] = "Missing keys: #{missing}" unless missing.empty?
33
+ end
34
+
35
+ def unexpected_keys(keys:, errors:, candidates:)
28
36
  rogue_keys = candidates - keys
29
37
  errors[:unexpected_keys] = "Unexpected keys: #{rogue_keys}" unless rogue_keys.empty?
30
38
  end
39
+
31
40
  end
32
41
  end
@@ -1,3 +1,3 @@
1
1
  module EasyJSONMatcher
2
- VERSION = "0.4.1".freeze
2
+ VERSION = "0.5.0".freeze
3
3
  end
@@ -10,6 +10,7 @@ module EasyJSONMatcher
10
10
  has_attribute(key: "name", opts: [ :string, :required ])
11
11
  }
12
12
  sc.register(as: @name)
13
+ byebug
13
14
  end
14
15
 
15
16
  test "As a user I want to be able to register a Schema so I can reuse it later" do
@@ -42,9 +43,9 @@ module EasyJSONMatcher
42
43
  assert(schema.valid?(candidate: candidate), "test_schema did not validate correctly")
43
44
  end
44
45
 
45
- test "SchemaLibrary should thrown a MissingSchemaException if an unregistered schema is requested" do
46
+ test "SchemaLibrary should thrown a UnknownValidationStepError if an unregistered schema is requested" do
46
47
  schema = SchemaLibrary.get_schema(name: "#{@name.to_s}-wibble")
47
- assert_raises(MissingSchemaException) do
48
+ assert_raises(UnknownValidationStepError) do
48
49
  schema.call(value: {}.to_json)
49
50
  end
50
51
  end
@@ -53,7 +54,7 @@ module EasyJSONMatcher
53
54
  schema = SchemaLibrary.get_schema(name: :womble)
54
55
  begin
55
56
  schema.call(value: {}.to_json)
56
- rescue MissingSchemaException => ex
57
+ rescue UnknownValidationStepError => ex
57
58
  assert ex.message =~ /womble/
58
59
  end
59
60
  end
@@ -68,8 +69,6 @@ module EasyJSONMatcher
68
69
  is_present: true,
69
70
  }
70
71
 
71
- # assert_not(test_schema.valid?(invalid_json), "#{invalid_json} should not have been valid as it does not include the saved schema")
72
-
73
72
  valid_json = invalid_json.dup
74
73
  valid_json.store(@name, {name: "Achilles Tang"})
75
74
  valid_json = valid_json.to_json
data/test/node_test.rb CHANGED
@@ -12,14 +12,14 @@ module EasyJSONMatcher
12
12
  end
13
13
 
14
14
  it "should send call to its own validator" do
15
- test_value = { a: 1, b: 2, c: 3 }
16
- validators = (:a..:c).each_with_object({}) do |n, h|
15
+ test_value = { "a" => 1, "b" => 2, "c" => 3 }
16
+ validators = ("a".."c").each_with_object({}) do |n, h|
17
17
  h[n] = ValidationChainFactory.get_chain(steps: [:string])
18
18
  end
19
19
  node = Node.new(opts: [:required], validators: validators)
20
- expected = [{a: ["1 is not a String"],
21
- b: ["2 is not a String"],
22
- c: ["3 is not a String"]
20
+ expected = [{"a" => ["1 is not a String"],
21
+ "b" => ["2 is not a String"],
22
+ "c" => ["3 is not a String"]
23
23
  }]
24
24
  node.call(value: test_value).must_be :==, expected
25
25
  end
@@ -0,0 +1,21 @@
1
+ require "test_helper"
2
+
3
+ module EasyJSONMatcher
4
+ describe Printer do
5
+
6
+ it "should properly print a Schema" do
7
+ schema = SchemaGenerator.new {
8
+ string key: "val"
9
+ contains_node key: "node" do
10
+ string key: "inner_key"
11
+ string key: "another_key"
12
+ contains_node key: "another node" do
13
+ string key: "inner_inner_key"
14
+ end
15
+ end
16
+ }.generate_schema
17
+ pr = Printer.new(node: schema)
18
+ puts pr.inspect
19
+ end
20
+ end
21
+ end
@@ -30,5 +30,13 @@ module EasyJSONMatcher
30
30
 
31
31
  subject.validate(candidate: candidate).wont_be :empty?
32
32
  end
33
+
34
+ it "should not validate candidates missing keys" do
35
+ candidate = {
36
+ a: "a"
37
+ }.to_json
38
+
39
+ subject.validate(candidate: candidate).wont_be :empty?
40
+ end
33
41
  end
34
42
  end
@@ -1,6 +1,5 @@
1
1
  require "test_helper"
2
2
  require "easy_json_matcher/validation_chain_factory"
3
- require "easy_json_matcher/unknown_validation_step_error"
4
3
 
5
4
  module EasyJSONMatcher
6
5
 
@@ -23,7 +22,8 @@ module EasyJSONMatcher
23
22
  end
24
23
 
25
24
  it "should otherwise raise an error" do
26
- skip "Leave for future release"
25
+ skip "This is currently unnecessary, but ought to be considered when
26
+ developing future versions"
27
27
  cannot_use = String.new
28
28
  -> { ValidationChainFactory.get_step_for(validating: cannot_use) }.
29
29
  must_raise UnknownValidationStepError
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: easy_json_matcher
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.1
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - WJD Hamilton
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-12-08 00:00:00.000000000 Z
11
+ date: 2017-12-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: dry-auto_inject
@@ -63,9 +63,9 @@ files:
63
63
  - lib/easy_json_matcher/json_coercer.rb
64
64
  - lib/easy_json_matcher/node.rb
65
65
  - lib/easy_json_matcher/node_generator.rb
66
+ - lib/easy_json_matcher/printer.rb
66
67
  - lib/easy_json_matcher/schema_generator.rb
67
68
  - lib/easy_json_matcher/schema_library.rb
68
- - lib/easy_json_matcher/unknown_validation_step_error.rb
69
69
  - lib/easy_json_matcher/validation_chain_factory.rb
70
70
  - lib/easy_json_matcher/validation_rules.rb
71
71
  - lib/easy_json_matcher/validation_step.rb
@@ -87,6 +87,7 @@ files:
87
87
  - test/primitives_object_test.rb
88
88
  - test/primitives_string_test.rb
89
89
  - test/primtives_value_test.rb
90
+ - test/printer_test.rb
90
91
  - test/required_validation_test.rb
91
92
  - test/schema_generator_test.rb
92
93
  - test/shortened_names_test.rb
@@ -153,6 +154,7 @@ test_files:
153
154
  - test/primitives_object_test.rb
154
155
  - test/shortened_names_test.rb
155
156
  - test/primitives_date_test.rb
157
+ - test/printer_test.rb
156
158
  - test/global_validation_options_test.rb
157
159
  - test/validation_step_array_test.rb
158
160
  - test/required_validation_test.rb
@@ -1,10 +0,0 @@
1
- require "easy_json_matcher/easy_json_matcher_error"
2
-
3
- module EasyJSONMatcher
4
- class UnknownValidationStepError < EasyJSONMatcherError
5
-
6
- def initialize(type)
7
- super "No validator available for #{type}, consider using a custom validator"
8
- end
9
- end
10
- end