easy_json_matcher 0.0.2.pre.1 → 0.1.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: 08815b61dd12963ba183f268f8ed79ef4871e942
4
- data.tar.gz: 70c09b58d1a58df1310b78f92ac7f12f8ea6c22e
3
+ metadata.gz: 550d51e3fa5dcd2a06ade6049b34666c957e3c06
4
+ data.tar.gz: 073104ceb62af67ae2dfbf2cb4ac800cd584b809
5
5
  SHA512:
6
- metadata.gz: d2415e588006089aab89ef53870839493258f6bd5d71d9573d515c6ee10aacbb3f6dd3db1b979d5c843a07e52356d75456e72242b2ee2706093c8da78a2c1d6c
7
- data.tar.gz: 954f6c4a709230a0e8d8250e6a3a4f020fbd723071a741fb478a968bd008077c6cc587b42819d179038fce6ae48db62089227614fe2fdbc2db7f669b3fcb5a42
6
+ metadata.gz: 2a512cdd2cde619c1b9beaf88efb96167077c8d96c6fd19cf76d5c74c8e89c5e95f274b643901fe344cd96d1dc7d086721731962bad243942ea95c174b705735
7
+ data.tar.gz: 01960e66aa4bdf8ce3bb31df5ddc474622f10d19bca0b414bd1c7ab8d1b70c5ab16da3c75ea770dd0836cf1c7825dc8dfa20d18a98f16aae2896359772e36579
@@ -2,9 +2,45 @@ require 'easy_json_matcher/validator'
2
2
  module EasyJSONMatcher
3
3
  class ArrayValidator < Validator
4
4
  attr_reader :validators, :validator_results
5
+ ######################### Methods for requiring values by type #################
6
+
7
+ def should_only_contain_strings(opts: {})
8
+ should_only_contain type: :string, opts: opts
9
+ end
10
+
11
+ def should_only_contain_objects(opts: {})
12
+ should_only_contain type: :object, opts: opts
13
+ end
14
+
15
+ def should_only_contain_values(opts: {})
16
+ should_only_contain type: :value, opts: opts
17
+ end
18
+
19
+ def should_only_contain_numbers(opts: {})
20
+ should_only_contain type: :number, opts: opts
21
+ end
22
+
23
+ def should_only_contain_booleans(opts: {})
24
+ should_only_contain type: :boolean, opts: opts
25
+ end
26
+
27
+ def should_only_contain_dates(opts: {})
28
+ should_only_contain type: :date, opts: opts
29
+ end
30
+
31
+ def should_only_contain_schema(name:, opts: {})
32
+ should_only_contain type: :schema, opts: opts.merge({name: name})
33
+ end
34
+
35
+ def should_only_contain(type:,opts: {})
36
+ _clear_validators
37
+ _add_validator(_create_validator(type: type, opts: opts))
38
+ end
39
+
40
+ ######################## Private methods #######################################
5
41
 
6
42
  def _validate
7
- return false unless _content_is_array?
43
+ errors << "#{content} is not an Array" unless _content_is_array?
8
44
  _validate_content
9
45
  end
10
46
 
@@ -14,14 +50,8 @@ module EasyJSONMatcher
14
50
 
15
51
  def _validate_content
16
52
  validators.each do |val|
17
- _run_validator(val)
53
+ _accumulate_errors val
18
54
  end
19
- _validation_result
20
- end
21
-
22
- def should_only_contain(type:,opts: {})
23
- _clear_validators
24
- _add_validator(_create_validator(type: type, opts: opts))
25
55
  end
26
56
 
27
57
  def _clear_validators
@@ -36,18 +66,19 @@ module EasyJSONMatcher
36
66
  @validators ||= []
37
67
  end
38
68
 
39
- def _run_validator(v)
40
- content.each do |value|
41
- validator_results << v.valid?(value)
69
+ def _accumulate_errors(validator)
70
+ content.each do |candidate|
71
+ _run_validator(validator, candidate)
42
72
  end
73
+ errors << validator.errors unless validator._no_errors?
43
74
  end
44
75
 
45
- def _validation_result
46
- !validator_results.include? false
76
+ def _run_validator(validator, candidate)
77
+ validator.valid? candidate
47
78
  end
48
79
 
49
- def validator_results
50
- @validator_results ||= []
80
+ def _validation_result
81
+ !validator_results.include? false
51
82
  end
52
83
  end
53
84
  end
@@ -1,7 +1,12 @@
1
1
  require 'easy_json_matcher/validator'
2
2
  module EasyJSONMatcher
3
3
  class BooleanValidator < Validator
4
+
4
5
  def _validate
6
+ errors << "#{content} is not a Boolean" unless _content_is_boolean?
7
+ end
8
+
9
+ def _content_is_boolean?
5
10
  clazz = content.class
6
11
  (clazz == TrueClass) || (clazz == FalseClass)
7
12
  end
@@ -1,18 +1,16 @@
1
1
  module EasyJSONMatcher
2
- class ContentWrapper
3
-
4
- attr_reader :content
5
-
6
- def initialize(content)
7
- @content = content
8
- end
2
+ module ContentWrapper
9
3
 
10
4
  def [](key)
11
5
  content[key.to_s]
12
6
  end
13
7
 
14
- def method_missing(method, *args)
15
- content.send(method, *args)
8
+ def method_missing(method, *args, &block)
9
+ content.send(method, *args, &block)
10
+ end
11
+
12
+ def keys
13
+ content.keys.map(&:to_sym)
16
14
  end
17
15
  end
18
16
  end
@@ -12,14 +12,15 @@ module EasyJSONMatcher
12
12
  end
13
13
 
14
14
  def _validate
15
- _validate_as_string && _validate_as_date
15
+ _validate_string
16
+ _validate_date
16
17
  end
17
18
 
18
- def _validate_as_string
19
+ def _content_is_a_string?
19
20
  string_validator.valid? content
20
21
  end
21
22
 
22
- def _validate_as_date
23
+ def _content_is_a_date?
23
24
  require 'date'
24
25
  begin
25
26
  Date.strptime(content, date_format)
@@ -31,5 +32,13 @@ module EasyJSONMatcher
31
32
  def date_format
32
33
  @date_format || DEFAULT_DATE_FORMAT
33
34
  end
35
+
36
+ def _validate_string
37
+ errors << "#{content} must be provided as a String for Date validation" unless _content_is_a_string?
38
+ end
39
+
40
+ def _validate_date
41
+ errors << "#{content} is not a Date" unless _content_is_a_date?
42
+ end
34
43
  end
35
44
  end
@@ -1,4 +1,3 @@
1
- require 'easy_json_matcher'
2
1
  module EasyJSONMatcher
3
2
  # Override of Ruby error for namespacing
4
3
  class Error < RuntimeError; end
@@ -1,30 +1,51 @@
1
- require 'easy_json_matcher'
2
1
  require 'easy_json_matcher/validator_factory'
3
2
  require 'json'
4
3
  require 'easy_json_matcher/content_wrapper'
5
- require 'forwardable'
6
4
  module EasyJSONMatcher
7
5
  class Node < Validator
8
- extend Forwardable
6
+ include ContentWrapper
9
7
 
10
- attr_reader :validators
11
-
12
- def_delegators :content, :[]
8
+ attr_reader :validators, :validity, :strict
13
9
 
14
10
  def initialize(opts: {})
15
11
  super(options: opts)
16
12
  @validators = []
13
+ @validity = true
17
14
  end
18
15
 
19
16
  def add_validator(validator)
20
17
  validators << validator
21
18
  end
22
19
 
20
+ def _post_initialise(options)
21
+ @strict = options[:strict]
22
+ end
23
+
23
24
  def _validate
25
+ _validate_strict_keyset
24
26
  validators.each do |val|
25
- return false unless _use_validator val
27
+ @validity = false unless _use_validator val
28
+ end
29
+ end
30
+
31
+ def reset!
32
+ errors.clear
33
+ validators.each(&:reset!)
34
+ end
35
+
36
+ def _validate_strict_keyset
37
+ _validate_keyset if strict
38
+ end
39
+
40
+ def _validate_keyset
41
+ unexpected_keys = keys - _expected_keys
42
+ errors << "#{unexpected_keys} found in addition to expected keys" unless unexpected_keys.empty?
43
+ end
44
+
45
+ def _expected_keys
46
+ validators.each_with_object([]) do |validator, keyset|
47
+ keyset << validator.key
26
48
  end
27
- true
28
49
  end
29
50
 
30
51
  def _use_validator(validator)
@@ -32,7 +53,7 @@ module EasyJSONMatcher
32
53
  end
33
54
 
34
55
  def _get_content_for(key)
35
- content[key.to_s]
56
+ content[key]
36
57
  end
37
58
 
38
59
  def _get_validator_for(key)
@@ -40,25 +61,61 @@ module EasyJSONMatcher
40
61
  end
41
62
 
42
63
  def _set_content(candidate)
43
- candidate = _prep_candidate(candidate)
44
- @content = _is_root? ? candidate : candidate[key]
64
+ @content = _is_root? ? _prep_root_content(candidate) : candidate[key]
45
65
  end
46
66
 
47
67
  def _is_root?
48
68
  key.nil?
49
69
  end
50
70
 
51
- def _prep_candidate(json)
52
- if json.is_a? String
53
- wrap_content(JSON.parse(json))
71
+ def get_errors
72
+ child_errors = _collect_child_errors
73
+ _wrap_errors(child_errors)
74
+ end
75
+
76
+ def _collect_child_errors
77
+ validators.each_with_object({}) do |val, container|
78
+ container.merge!(val.get_errors)
79
+ end
80
+ end
81
+
82
+ def _wrap_errors(child_errors)
83
+ _add_local_errors_to child_errors
84
+ unless _is_root?
85
+ _wrap_child_errors(child_errors)
54
86
  else
55
- raise "Content for validation must be either a Hash or a String - you supplied #{json}, which is a #{json.class.name}" unless json.respond_to? :[]
56
- wrap_content(json)
87
+ _root_errors(child_errors)
88
+ end
89
+ end
90
+
91
+ def _add_local_errors_to(child_errors)
92
+ child_errors.merge!({node_errors_: errors}) unless errors.empty?
93
+ end
94
+
95
+ def _wrap_child_errors(child_errors)
96
+ errors_wrapper = {}
97
+ errors_wrapper[key] = child_errors
98
+ errors_wrapper
99
+ end
100
+
101
+ def _root_errors(child_errors)
102
+ errors.length > 0 ? {root: errors} : child_errors
103
+ end
104
+
105
+ def _prep_root_content(candidate)
106
+ candidate.is_a?(String) ? _parse_and_verify_json(candidate) : candidate
107
+ end
108
+
109
+ def _parse_and_verify_json(json)
110
+ begin
111
+ JSON.parse(json)
112
+ rescue JSON::ParserError
113
+ errors << '#{json} is not a valid JSON String'
57
114
  end
58
115
  end
59
116
 
60
- def wrap_content(json)
61
- ContentWrapper.new(json)
117
+ def _no_errors?
118
+ validity && errors.empty?
62
119
  end
63
120
  end
64
121
  end
@@ -1,8 +1,14 @@
1
1
  # Asserts that a value is a double-precision floating point number in javascript format
2
2
  require 'easy_json_matcher/validator'
3
3
  module EasyJSONMatcher
4
+
4
5
  class NumberValidator < Validator
6
+
5
7
  def _validate
8
+ errors << "#{content} is not a Number" unless _content_is_a_number?
9
+ end
10
+
11
+ def _content_is_a_number?
6
12
  begin
7
13
  Kernel::Float(content)
8
14
  true
@@ -12,6 +18,5 @@ module EasyJSONMatcher
12
18
  false
13
19
  end
14
20
  end
15
-
16
21
  end
17
22
  end
@@ -2,7 +2,11 @@ require 'easy_json_matcher/validator'
2
2
  module EasyJSONMatcher
3
3
  class ObjectValidator < Validator
4
4
  def _validate
5
- content.is_a? Hash
5
+ _content_is_object?
6
+ end
7
+
8
+ def _content_is_object?
9
+ errors << "#{content} is not an Object" unless content.is_a? Hash
6
10
  end
7
11
  end
8
12
  end
@@ -5,71 +5,100 @@ require 'easy_json_matcher/exceptions'
5
5
  module EasyJSONMatcher
6
6
  class SchemaGenerator
7
7
 
8
- attr_reader :node
9
- attr_reader :name
8
+ attr_reader :node, :name, :options, :glob_opts
10
9
 
11
- def initialize(opts: {})
12
- @name = opts[:key]
10
+ def initialize(opts: {}, global_opts: {})
11
+ @name = opts.delete(:key)
12
+ @options = opts
13
+ @glob_opts = global_opts
13
14
  yield self if block_given?
14
15
  end
15
16
 
17
+ def has_attribute(key:, opts: {})
18
+ node.add_validator(_create_validator(key, opts))
19
+ end
20
+
21
+ ################ Methods for adding specific attribute types ##############
22
+
16
23
  def contains_node(key:, opts: {})
17
24
  generator = _node_generator _validator_opts(key, opts)
18
25
  yield generator if block_given?
19
- node.add_validator generator.generate_node
26
+ node.add_validator generator.generate_schema
20
27
  end
21
28
 
22
- def has_attribute(key:, opts: {})
23
- node.add_validator(_create_validator(key, opts))
29
+ def has_boolean(key:, opts: {})
30
+ has_attribute(key: key, opts: opts.merge({type: :boolean}))
24
31
  end
25
32
 
26
- def contains_schema(schema_name:, opts: {})
27
- key = opts[:key] || schema_name
28
- schema = _create_validator(key, _prep_schema_opts(schema_name, opts))
29
- _set_validator_key(schema, opts[:key] || schema_name)
30
- node.add_validator schema
33
+ def has_number(key: , opts: {})
34
+ has_attribute(key: key, opts: opts.merge({type: :number}))
31
35
  end
32
36
 
33
- def _prep_schema_opts(schema_name, opts)
34
- opts[:type] = :schema
35
- opts[:name] = schema_name
36
- opts
37
+ def has_date(key:, opts: {})
38
+ has_attribute(key: key, opts: opts.merge({type: :date}))
37
39
  end
38
40
 
39
- def _set_validator_key(validator, key)
40
- validator.key = key
41
+ def has_object(key:, opts: {})
42
+ has_attribute(key: key, opts: opts.merge({type: :object}))
43
+ end
44
+
45
+ def has_value(key:, opts: {})
46
+ has_attribute(key: key, opts: opts.merge({type: :value}))
47
+ end
48
+
49
+ def has_string(key:, opts: {})
50
+ has_attribute(key: key, opts: opts.merge({type: :string}))
41
51
  end
42
52
 
43
53
  def contains_array(key:, opts: {})
44
- opts.merge!({type: :array})
54
+ opts = opts.merge!({type: :array})
45
55
  array_validator = _create_validator(key, opts)
46
56
  yield array_validator if block_given?
47
57
  node.add_validator array_validator
48
58
  end
49
59
 
50
- def _validator_opts(key, opts)
51
- opts[:key] = key
60
+ def has_schema(key:, opts: {})
61
+ has_attribute(key: key, opts: opts.merge({type: :schema}))
62
+ end
63
+
64
+ ################ Methods for generating the schema #########################
65
+
66
+ def generate_schema
67
+ node
68
+ end
69
+
70
+ def register(as:)
71
+ SchemaLibrary.add_schema(name: as, schema: generate_schema)
72
+ generate_schema
73
+ end
74
+
75
+ ################## Private methods #########################################
76
+
77
+ def _prep_schema_opts(schema_name, opts)
78
+ opts[:type] = :schema
79
+ opts[:name] = schema_name
52
80
  opts
53
81
  end
54
82
 
55
- def _create_validator(key, opts)
56
- ValidatorFactory.get_instance type: opts[:type], opts: _validator_opts(key, opts)
83
+ def _set_validator_key(validator, key)
84
+ validator.key = key
57
85
  end
58
86
 
59
- def _node_generator(opts = {})
60
- self.class.new opts: opts
87
+ def _validator_opts(key, opts)
88
+ opts[:key] = key
89
+ glob_opts.merge(opts)
61
90
  end
62
91
 
63
- def generate_node
64
- node
92
+ def _create_validator(key, opts)
93
+ ValidatorFactory.get_instance type: opts[:type], opts: _validator_opts(key, opts)
65
94
  end
66
95
 
67
- def register(schema_name:)
68
- SchemaLibrary.add_schema(name: schema_name, schema: generate_node)
96
+ def _node_generator(opts = {})
97
+ self.class.new opts: opts, global_opts: glob_opts
69
98
  end
70
99
 
71
100
  def node
72
- @node ||= Node.new(opts: _validator_opts(name, {}))
101
+ @node ||= Node.new(opts: _validator_opts(name, options))
73
102
  end
74
103
  end
75
104
  end