easy_json_matcher 0.4.1 → 0.5.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.
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