easy_json_matcher 0.0.2.pre.1 → 0.1.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: 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