json-spec 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.
Files changed (114) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +3 -0
  3. data/.gitmodules +3 -0
  4. data/Gemfile +4 -0
  5. data/LICENSE.txt +21 -0
  6. data/README.md +960 -0
  7. data/Rakefile +10 -0
  8. data/api_documentation.md +611 -0
  9. data/cachivache/.gitignore +1 -0
  10. data/cachivache/Gemfile +4 -0
  11. data/cachivache/README.md +247 -0
  12. data/cachivache/Rakefile +19 -0
  13. data/cachivache/Vagrantfile +70 -0
  14. data/cachivache/cachivache.rb +59 -0
  15. data/cachivache/lib/let-behaviour.rb +27 -0
  16. data/cachivache/lib/rake-helper.rb +131 -0
  17. data/cachivache/lib/sh-file-context.rb +39 -0
  18. data/cachivache/lib/sh-if-context.rb +31 -0
  19. data/cachivache/stuff/.gitkeep +0 -0
  20. data/cachivache/stuff/ruby-json-spec.rb +22 -0
  21. data/examples/example-1-simple.rb +66 -0
  22. data/examples/example-2-default-expectations.rb +63 -0
  23. data/examples/example-3-each-field.rb +104 -0
  24. data/examples/example-4-to-be-as-defined-in.rb +117 -0
  25. data/examples/example-5-custom-expectations.rb +153 -0
  26. data/examples/example-6-custom-messages.rb +36 -0
  27. data/examples/example-7-full-example.rb +231 -0
  28. data/examples/fixtures.rb +77 -0
  29. data/examples/validation-printer.rb +47 -0
  30. data/json-spec.gemspec +29 -0
  31. data/lib/cabeza-de-termo/json-spec/errors/error.rb +6 -0
  32. data/lib/cabeza-de-termo/json-spec/errors/expectation-not-found-error.rb +8 -0
  33. data/lib/cabeza-de-termo/json-spec/errors/modifier-not-found-error.rb +8 -0
  34. data/lib/cabeza-de-termo/json-spec/errors/unkown-json-type-error.rb +8 -0
  35. data/lib/cabeza-de-termo/json-spec/errors/validation-error.rb +8 -0
  36. data/lib/cabeza-de-termo/json-spec/expectations-library/default-expectations/default-expectation-builder.rb +29 -0
  37. data/lib/cabeza-de-termo/json-spec/expectations-library/default-expectations/default-expectations-mapping.rb +54 -0
  38. data/lib/cabeza-de-termo/json-spec/expectations-library/definition-builders/expectation-builders/block-expectation-definition.rb +16 -0
  39. data/lib/cabeza-de-termo/json-spec/expectations-library/definition-builders/expectation-builders/class-expectation-definition.rb +15 -0
  40. data/lib/cabeza-de-termo/json-spec/expectations-library/definition-builders/expectation-builders/expectation-definition.rb +19 -0
  41. data/lib/cabeza-de-termo/json-spec/expectations-library/definition-builders/expectation-builders/expectations-definition-builder.rb +136 -0
  42. data/lib/cabeza-de-termo/json-spec/expectations-library/definition-builders/expectation-builders/expecting-all-of-expectation-definition.rb +23 -0
  43. data/lib/cabeza-de-termo/json-spec/expectations-library/definition-builders/expectation-builders/expecting-any-of-expectation-definition.rb +23 -0
  44. data/lib/cabeza-de-termo/json-spec/expectations-library/definition-builders/expectation-builders/expecting-expectation-definition.rb +17 -0
  45. data/lib/cabeza-de-termo/json-spec/expectations-library/definition-builders/expectation-builders/negating-expectation-definition.rb +16 -0
  46. data/lib/cabeza-de-termo/json-spec/expectations-library/definition-builders/expectation-library-definition-builder.rb +35 -0
  47. data/lib/cabeza-de-termo/json-spec/expectations-library/definition-builders/modifier-builders/class-modifier-definition.rb +15 -0
  48. data/lib/cabeza-de-termo/json-spec/expectations-library/definition-builders/modifier-builders/composing-modifiers-definition.rb +28 -0
  49. data/lib/cabeza-de-termo/json-spec/expectations-library/definition-builders/modifier-builders/modifier-definition.rb +13 -0
  50. data/lib/cabeza-de-termo/json-spec/expectations-library/definition-builders/modifier-builders/modifiers-definition-builder.rb +73 -0
  51. data/lib/cabeza-de-termo/json-spec/expectations-library/expectations-library.rb +150 -0
  52. data/lib/cabeza-de-termo/json-spec/expectations-library/initializers/default-library-initializer.rb +265 -0
  53. data/lib/cabeza-de-termo/json-spec/expectations-library/initializers/library-initializer.rb +9 -0
  54. data/lib/cabeza-de-termo/json-spec/expectations-library/messages/expectation-messages-mapping.rb +27 -0
  55. data/lib/cabeza-de-termo/json-spec/expectations/abstract-expectation.rb +39 -0
  56. data/lib/cabeza-de-termo/json-spec/expectations/all-expectations-composite.rb +33 -0
  57. data/lib/cabeza-de-termo/json-spec/expectations/any-expectation-composite.rb +33 -0
  58. data/lib/cabeza-de-termo/json-spec/expectations/block-expectation.rb +28 -0
  59. data/lib/cabeza-de-termo/json-spec/expectations/expectation.rb +51 -0
  60. data/lib/cabeza-de-termo/json-spec/expectations/is-email-expectation.rb +16 -0
  61. data/lib/cabeza-de-termo/json-spec/expectations/is-scalar-expectation.rb +17 -0
  62. data/lib/cabeza-de-termo/json-spec/expectations/is-url-expectation.rb +21 -0
  63. data/lib/cabeza-de-termo/json-spec/expectations/negated-expectation.rb +31 -0
  64. data/lib/cabeza-de-termo/json-spec/expectations/runner/abstract-expectations-runner.rb +27 -0
  65. data/lib/cabeza-de-termo/json-spec/expectations/runner/can-be-absent-expectations-runner.rb +50 -0
  66. data/lib/cabeza-de-termo/json-spec/expectations/runner/can-be-null-expectations-runner.rb +48 -0
  67. data/lib/cabeza-de-termo/json-spec/expectations/runner/expectations-runner.rb +43 -0
  68. data/lib/cabeza-de-termo/json-spec/expressions/json-any-of.rb +62 -0
  69. data/lib/cabeza-de-termo/json-spec/expressions/json-anything.rb +16 -0
  70. data/lib/cabeza-de-termo/json-spec/expressions/json-each-field.rb +58 -0
  71. data/lib/cabeza-de-termo/json-spec/expressions/json-each.rb +58 -0
  72. data/lib/cabeza-de-termo/json-spec/expressions/json-expression.rb +314 -0
  73. data/lib/cabeza-de-termo/json-spec/expressions/json-field-name.rb +16 -0
  74. data/lib/cabeza-de-termo/json-spec/expressions/json-field.rb +76 -0
  75. data/lib/cabeza-de-termo/json-spec/expressions/json-list.rb +40 -0
  76. data/lib/cabeza-de-termo/json-spec/expressions/json-object.rb +82 -0
  77. data/lib/cabeza-de-termo/json-spec/expressions/json-scalar.rb +20 -0
  78. data/lib/cabeza-de-termo/json-spec/expressions/json-spec.rb +174 -0
  79. data/lib/cabeza-de-termo/json-spec/instantiators/abstract-instantiator.rb +9 -0
  80. data/lib/cabeza-de-termo/json-spec/instantiators/all-expectations-composite-instantiator.rb +12 -0
  81. data/lib/cabeza-de-termo/json-spec/instantiators/any-expectation-composite-instantiator.rb +12 -0
  82. data/lib/cabeza-de-termo/json-spec/instantiators/block-expectation-instantiator.rb +16 -0
  83. data/lib/cabeza-de-termo/json-spec/instantiators/composite-instantiator.rb +45 -0
  84. data/lib/cabeza-de-termo/json-spec/instantiators/modifier-composite-instantiator.rb +12 -0
  85. data/lib/cabeza-de-termo/json-spec/instantiators/negated-expectation-instantiator.rb +20 -0
  86. data/lib/cabeza-de-termo/json-spec/instantiators/patial-application-instantiator.rb +26 -0
  87. data/lib/cabeza-de-termo/json-spec/json-spec.rb +2 -0
  88. data/lib/cabeza-de-termo/json-spec/message-formatters/block-message-formatter.rb +15 -0
  89. data/lib/cabeza-de-termo/json-spec/message-formatters/erb-message-formatter.rb +60 -0
  90. data/lib/cabeza-de-termo/json-spec/message-formatters/message-formatter.rb +9 -0
  91. data/lib/cabeza-de-termo/json-spec/metaprogramming/message-send.rb +37 -0
  92. data/lib/cabeza-de-termo/json-spec/metaprogramming/message.rb +37 -0
  93. data/lib/cabeza-de-termo/json-spec/metaprogramming/object-method.rb +14 -0
  94. data/lib/cabeza-de-termo/json-spec/modifiers/can-be-absent-modifier.rb +13 -0
  95. data/lib/cabeza-de-termo/json-spec/modifiers/can-be-null-modifier.rb +13 -0
  96. data/lib/cabeza-de-termo/json-spec/modifiers/expression-modifier.rb +9 -0
  97. data/lib/cabeza-de-termo/json-spec/modifiers/modifier-composite.rb +27 -0
  98. data/lib/cabeza-de-termo/json-spec/signals/signal.rb +6 -0
  99. data/lib/cabeza-de-termo/json-spec/signals/skip-branch-signal.rb +8 -0
  100. data/lib/cabeza-de-termo/json-spec/utilities/bind.rb +20 -0
  101. data/lib/cabeza-de-termo/json-spec/utilities/range.rb +70 -0
  102. data/lib/cabeza-de-termo/json-spec/value-holders/accessors-chain.rb +27 -0
  103. data/lib/cabeza-de-termo/json-spec/value-holders/missing-value.rb +21 -0
  104. data/lib/cabeza-de-termo/json-spec/value-holders/value-holder.rb +135 -0
  105. data/lib/cabeza-de-termo/json-spec/version.rb +5 -0
  106. data/lib/cabeza-de-termo/json-spec/walkers/expression-walker.rb +66 -0
  107. data/lib/cabeza-de-termo/json-spec/walkers/json-expectations-runner.rb +214 -0
  108. data/lib/cabeza-de-termo/json-spec/walkers/json-expression-explainer.rb +183 -0
  109. data/lib/cabeza-de-termo/json-spec/walkers/reporter/expectation-report.rb +63 -0
  110. data/lib/cabeza-de-termo/json-spec/walkers/reporter/json-expectations-reporter.rb +111 -0
  111. data/lib/cabeza-de-termo/json-spec/walkers/validator/json-validator-error.rb +29 -0
  112. data/lib/cabeza-de-termo/json-spec/walkers/validator/json-validator.rb +133 -0
  113. data/lib/cabeza-de-termo/json-spec/walkers/value-holders-stack-behaviour.rb +57 -0
  114. metadata +242 -0
@@ -0,0 +1,27 @@
1
+ module CabezaDeTermo
2
+ module JsonSpec
3
+ #
4
+ # Models the chain of accessors to get to a value in a json tree.
5
+ # For instance, something like
6
+ #
7
+ # ['users', '[3]', 'addresses', '[0]', 'street']
8
+ #
9
+ class AccessorsChain
10
+ def initialize(accessors = ['@'])
11
+ @accessors = accessors
12
+ end
13
+
14
+ def accessors()
15
+ @accessors
16
+ end
17
+
18
+ def append_accessor(accessor)
19
+ self.class.new( accessors + [accessor] )
20
+ end
21
+
22
+ def to_s()
23
+ accessors.join('.')
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,21 @@
1
+ module CabezaDeTermo
2
+ module JsonSpec
3
+ #
4
+ # This object only purpose is to model a missing value from a json field or index.
5
+ # For instance, if we have the following Json:
6
+ #
7
+ # <code>
8
+ # {
9
+ # "id": 123,
10
+ # }
11
+ # </code>
12
+ #
13
+ # and we ask for the field 'name', the answer will be a ValueHolder holding a MissingValue.
14
+ #
15
+ class MissingValue
16
+ def to_s()
17
+ 'Missing value'
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,135 @@
1
+ require_relative "missing-value"
2
+ require_relative "accessors-chain"
3
+ require "cabeza-de-termo/json-spec/errors/unkown-json-type-error"
4
+
5
+ module CabezaDeTermo
6
+ module JsonSpec
7
+ #
8
+ # The value holder is passed though the ExpressionWalker during the processing of
9
+ # a json object.
10
+ #
11
+ class ValueHolder
12
+ #
13
+ # Answer a new ValueHolder on a MissingValue.
14
+ #
15
+ def self.new_value_holder_with_missing_value(accessors_chain = nil)
16
+ self.new(MissingValue.new, accessors_chain)
17
+ end
18
+
19
+ def initialize (value, accessors_chain = nil)
20
+ @value = value
21
+ @accessors_chain = accessors_chain.nil? ? AccessorsChain.new : accessors_chain
22
+ end
23
+
24
+ # Accessing
25
+
26
+ def value()
27
+ @value
28
+ end
29
+
30
+ def accessors_chain()
31
+ @accessors_chain
32
+ end
33
+
34
+ def value_holder_on_field_named(name)
35
+ return new_value_holder(value[name], name) if can_access_field_named?(name)
36
+ new_missing_value_holder(name)
37
+ end
38
+
39
+ def value_holder_at_index(i)
40
+ name = '[' + i.to_s + ']'
41
+
42
+ return new_value_holder(value[i], name) if can_access_field_at_index?(i)
43
+ new_missing_value_holder(name)
44
+ end
45
+
46
+ def field_names()
47
+ return value.keys if is_object?
48
+ []
49
+ end
50
+
51
+ #
52
+ # Answer the length of the value.
53
+ # For {} is the number of fields.
54
+ # For [] the number of elements.
55
+ # For strings its length.
56
+ # And for any other type, it throws an UnkownJsonTypeError.
57
+ #
58
+ def length()
59
+ return value.length if is_object?
60
+ return value.length if is_list?
61
+ return value.length if is_string?
62
+ return 0 if is_missing_value?
63
+
64
+ raise UnkownJsonTypeError.new('Can not get the length of an unknown type')
65
+ end
66
+
67
+ # Asking
68
+
69
+ def is_missing_value?()
70
+ value.kind_of?(MissingValue)
71
+ end
72
+
73
+ def not_missing_value?()
74
+ !is_missing_value?
75
+ end
76
+
77
+ #
78
+ # Answer whether the value is empty or not.
79
+ # For {} to be empty means not to have any field.
80
+ # For [], not to have any element.
81
+ # For strings, to be ''.
82
+ # And for any other type, it throws an UnkownJsonTypeError.
83
+ #
84
+ def is_empty?()
85
+ length == 0
86
+ end
87
+
88
+ # Instance creation
89
+
90
+ #
91
+ # Answer a new ValueHolder on the value and with the name added to its accessors_chain.
92
+ #
93
+ def new_value_holder(value, accessor)
94
+ new_nccessors_chain = accessors_chain.append_accessor(accessor)
95
+ ValueHolder.new(value, new_nccessors_chain)
96
+ end
97
+
98
+ #
99
+ # Answer a new ValueHolder on a MissingValue and with the name added to its accessors_chain.
100
+ #
101
+ def new_missing_value_holder(accessor)
102
+ new_nccessors_chain = accessors_chain.append_accessor(accessor)
103
+ self.class.new_value_holder_with_missing_value(new_nccessors_chain)
104
+ end
105
+
106
+ protected
107
+
108
+ #
109
+ # Answer true if the value is a stdClass and has a property named name.
110
+ #
111
+ def can_access_field_named?(name)
112
+ is_object? && value.has_key?(name)
113
+ end
114
+
115
+ #
116
+ # Answer true if the value is an array and has an index i defined.
117
+ #
118
+ def can_access_field_at_index?(i)
119
+ is_list? && i.between?(0, length - 1)
120
+ end
121
+
122
+ def is_object?()
123
+ value.kind_of?(::Hash)
124
+ end
125
+
126
+ def is_list?()
127
+ value.kind_of?(::Array)
128
+ end
129
+
130
+ def is_string?()
131
+ value.kind_of?(::String)
132
+ end
133
+ end
134
+ end
135
+ end
@@ -0,0 +1,5 @@
1
+ module CabezaDeTermo
2
+ module JsonSpec
3
+ VERSION = "0.1.0"
4
+ end
5
+ end
@@ -0,0 +1,66 @@
1
+ module CabezaDeTermo
2
+ module JsonSpec
3
+ class ExpressionWalker
4
+ def walk_on(json_walkable)
5
+ json_walkable.accept_walker(self)
6
+ end
7
+
8
+ def walk_json_spec(json_spec)
9
+ raise 'Subclass responsibility'
10
+ end
11
+
12
+ def walk_json_object(json_object)
13
+ raise 'Subclass responsibility'
14
+ end
15
+
16
+ def walk_json_each_field(json_each_field)
17
+ raise 'Subclass responsibility'
18
+ end
19
+
20
+ def walk_json_field_name(json_field_name)
21
+ raise 'Subclass responsibility'
22
+ end
23
+
24
+ def walk_json_list(json_list)
25
+ raise 'Subclass responsibility'
26
+ end
27
+
28
+ def walk_json_each(json_each)
29
+ raise 'Subclass responsibility'
30
+ end
31
+
32
+ def walk_json_field(json_field)
33
+ raise 'Subclass responsibility'
34
+ end
35
+
36
+ def walk_json_scalar(json_scalar)
37
+ raise 'Subclass responsibility'
38
+ end
39
+
40
+ def walk_json_any_of(json_any_of)
41
+ raise 'Subclass responsibility'
42
+ end
43
+
44
+ def walk_json_anything(json_anything)
45
+ raise 'Subclass responsibility'
46
+ end
47
+
48
+ def walk_expectation_runner(expectation_runner)
49
+ raise 'Subclass responsibility'
50
+ end
51
+
52
+ def walk_expectation(expectation)
53
+ raise 'Subclass responsibility'
54
+ end
55
+
56
+ # Error handling
57
+ def supressing(error_class, &block)
58
+ begin
59
+ block.call
60
+ rescue error_class
61
+ end
62
+ end
63
+
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,214 @@
1
+ require_relative "expression-walker"
2
+ require_relative "value-holders-stack-behaviour"
3
+ require "cabeza-de-termo/json-spec/errors/validation-error"
4
+ require 'cabeza-de-termo/json-spec/signals/skip-branch-signal'
5
+
6
+ module CabezaDeTermo
7
+ module JsonSpec
8
+ class JsonExpectationsRunner < ExpressionWalker
9
+ include ValueHoldersStackBehaviour
10
+
11
+ # Asking
12
+
13
+ #
14
+ # Answer true if all the walked Expectations was satisfied.
15
+ #
16
+ # @return boolean
17
+ #
18
+ def no_errors?()
19
+ raise 'Subclass responsibility'
20
+ end
21
+
22
+ def has_errors?()
23
+ !no_errors?
24
+ end
25
+
26
+
27
+ # Hooks
28
+ def on_unwalked_field(field_name, value_holder)
29
+ raise 'Subclass responsibility'
30
+ end
31
+
32
+ def on_json_any_of_was_satisfied_with_runner(expectations_runner)
33
+ raise 'Subclass responsibility'
34
+ end
35
+
36
+ def on_json_any_of_failed_with_all_runners(expectations_runners)
37
+ raise 'Subclass responsibility'
38
+ end
39
+
40
+ def on_walked_expectation(expectation, value_holder, was_satisfied)
41
+ raise 'Subclass responsibility'
42
+ end
43
+
44
+ # Instance creation
45
+
46
+ def new_json_expectations_runner()
47
+ raise 'Subclass responsibility'
48
+ end
49
+
50
+ # Walking expressions
51
+
52
+ def in_isolation(&block)
53
+ supressing ValidationError, &block
54
+ end
55
+
56
+ def in_isolation_walk_on(json_walkable)
57
+ in_isolation do
58
+ walk_on(json_walkable)
59
+ end
60
+ end
61
+
62
+ def walk_on(json_walkable)
63
+ supressing SkipBranchSignal do
64
+ super(json_walkable)
65
+ end
66
+ end
67
+
68
+ def walk_json_spec(json_spec)
69
+ in_isolation_walk_on(json_spec.root_expression)
70
+ end
71
+
72
+ def walk_json_object(json_object)
73
+ walk_expectations_of(json_object)
74
+
75
+ walked_fields = walk_each_defined_field_of(json_object)
76
+
77
+ if( json_object.has_each_field? )
78
+ more_walked_fields = walk_json_each_field(json_object.each_field_expression)
79
+ walked_fields = walked_fields + more_walked_fields
80
+ end
81
+
82
+ unexpected_fields_from_current_value_holder(walked_fields).each do |field_name|
83
+ on_unwalked_field(field_name, @value_holder)
84
+ end
85
+ end
86
+
87
+ def walk_each_defined_field_of(json_object)
88
+ walked_fields = []
89
+
90
+ json_object.fields.each do |field|
91
+ with_value_holder( @value_holder.value_holder_on_field_named(field.name) ) do
92
+ in_isolation_walk_on(field)
93
+ end
94
+
95
+ walked_fields << field.name
96
+ end
97
+
98
+ walked_fields
99
+ end
100
+
101
+ def walk_each_field_name(json_each_field, field_name)
102
+ with_value_holder( @value_holder.new_value_holder(field_name, ':' + field_name) ) do
103
+ walk_on(json_each_field.name_expression)
104
+ end
105
+ end
106
+
107
+ def walk_each_field_value(json_each_field, field_name)
108
+ with_value_holder( @value_holder.value_holder_on_field_named(field_name) ) do
109
+ in_isolation_walk_on(json_each_field.value_expression)
110
+ end
111
+ end
112
+
113
+ def walk_json_each_field(json_each_field)
114
+ walked_fields = []
115
+
116
+ @value_holder.field_names.each do |field_name|
117
+ walked_fields << field_name
118
+ in_isolation_walk_each_field(json_each_field, field_name)
119
+ end
120
+
121
+ walked_fields
122
+ end
123
+
124
+ def in_isolation_walk_each_field(json_each_field, field_name)
125
+ in_isolation do
126
+ walk_each_field_name(json_each_field, field_name)
127
+ walk_each_field_value(json_each_field, field_name)
128
+ end
129
+ end
130
+
131
+ def walk_json_field_name(json_field_name)
132
+ walk_expectations_of(json_field_name)
133
+ end
134
+
135
+ def walk_json_list(json_list_expression)
136
+ walk_expectations_of(json_list_expression)
137
+
138
+ walk_on(json_list_expression.each_expression)
139
+ end
140
+
141
+ def walk_json_each(json_each)
142
+ walk_expectations_of(json_each)
143
+
144
+ return if json_each.no_each_item_expression?
145
+
146
+ (0...@value_holder.length).each do |i|
147
+ with_value_holder( @value_holder.value_holder_at_index(i) ) do
148
+ in_isolation_walk_on(json_each.each_item_expression)
149
+ end
150
+ end
151
+ end
152
+
153
+ def walk_json_field(json_field)
154
+ walk_on(json_field.value_expression)
155
+ end
156
+
157
+ def walk_json_anything(json_anything)
158
+ walk_expectations_of(json_anything)
159
+ end
160
+
161
+ def walk_json_scalar(json_scalar)
162
+ walk_expectations_of(json_scalar)
163
+ end
164
+
165
+ def walk_json_any_of(any_of)
166
+ sub_walkers = []
167
+ any_of.possible_expressions.each do |possible_expression|
168
+ sub_walkers << walk_with_new_walker(possible_expression)
169
+ end
170
+
171
+ sub_walkers.each do |each_sub_walker|
172
+ return on_json_any_of_was_satisfied_with_runner(each_sub_walker) if each_sub_walker.no_errors?
173
+ end
174
+
175
+ on_json_any_of_failed_with_all_runners(sub_walkers)
176
+ end
177
+
178
+ def walk_expectations_of(expression)
179
+ # Intentionaly dont go through :walk_on to let the SkipBranchException errors bubble up
180
+ walk_expectation_runner( expression.expectations_runner )
181
+ end
182
+
183
+ def walk_expectation_runner(expectation_runner)
184
+ expectation_runner.accept_walker_with_value_holder(self, @value_holder)
185
+ end
186
+
187
+ def walk_expectation(expectation)
188
+ was_satisfied = expectation.is_satisfied_by?(@value_holder)
189
+ on_walked_expectation(expectation, @value_holder, was_satisfied)
190
+
191
+ raise_validation_error(expectation) unless was_satisfied
192
+ end
193
+
194
+ # Helpers
195
+
196
+ def walk_with_new_walker(expression)
197
+ expectations_runner = new_json_expectations_runner
198
+ in_isolation do
199
+ expectations_runner.walk_with_value_holder(expression, @value_holder)
200
+ end
201
+
202
+ expectations_runner
203
+ end
204
+
205
+ def raise_validation_error(expectation)
206
+ raise ValidationError.new( expectation.failed_message_on(@value_holder) )
207
+ end
208
+
209
+ def unexpected_fields_from_current_value_holder(walked_fields)
210
+ @value_holder.field_names.reject { |field| walked_fields.include?(field) }
211
+ end
212
+ end
213
+ end
214
+ end