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,16 @@
1
+ require_relative "abstract-instantiator"
2
+ require "cabeza-de-termo/json-spec/expectations/block-expectation"
3
+
4
+ module CabezaDeTermo
5
+ module JsonSpec
6
+ class BlockExpectationInstantiator < AbstractInstantiator
7
+ def initialize(block)
8
+ @block = block
9
+ end
10
+
11
+ def new(*args)
12
+ BlockExpectation.new(@block, *args)
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,45 @@
1
+ require_relative "abstract-instantiator"
2
+
3
+ module CabezaDeTermo
4
+ module JsonSpec
5
+ class CompositeInstantiator < AbstractInstantiator
6
+ def self.with_all(instantiators)
7
+ self.new.add_all_child_instantiators(instantiators)
8
+ end
9
+
10
+ def initialize()
11
+ @instantiators = []
12
+ end
13
+
14
+ def instantiators
15
+ @instantiators
16
+ end
17
+
18
+ def add_all_child_instantiators(instantiators)
19
+ instantiators.each { |child| add_child_instantiator(child) }
20
+
21
+ self
22
+ end
23
+
24
+ def add_child_instantiator(instantiator)
25
+ instantiators << instantiator
26
+
27
+ self
28
+ end
29
+
30
+ def new(*args)
31
+ composite = new_composite_expectation
32
+
33
+ instantiators.each do |instantiator|
34
+ composite.add_child( instantiator.new(*args) )
35
+ end
36
+
37
+ composite
38
+ end
39
+
40
+ def new_composite_expectation()
41
+ raise 'Subclass responsibility'
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,12 @@
1
+ require_relative "composite-instantiator"
2
+ require "cabeza-de-termo/json-spec/modifiers/modifier-composite"
3
+
4
+ module CabezaDeTermo
5
+ module JsonSpec
6
+ class ModifierCompositeInstantiator < CompositeInstantiator
7
+ def new_composite_expectation()
8
+ ModifierComposite.new
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,20 @@
1
+ require_relative "abstract-instantiator"
2
+ require "cabeza-de-termo/json-spec/expectations/negated-expectation"
3
+
4
+ module CabezaDeTermo
5
+ module JsonSpec
6
+ class NegatedExpectationInstantiator < AbstractInstantiator
7
+ def initialize(instantiator)
8
+ @instantiator = instantiator
9
+ end
10
+
11
+ def new(*args)
12
+ NegatedExpectation.new( new_expectation_to_negate(*args) )
13
+ end
14
+
15
+ def new_expectation_to_negate(*args)
16
+ @instantiator.new(*args)
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,26 @@
1
+ module CabezaDeTermo
2
+ module JsonSpec
3
+ #
4
+ # A wrapper on an AbstractInstantiator to implement a partial application function
5
+ # (https://en.wikipedia.org/wiki/Partial_application).
6
+ #
7
+ class PartialApplicationInstantiator
8
+ def initialize(underlaying_instantiator, args = [])
9
+ @underlaying_instantiator = underlaying_instantiator
10
+ @args = args
11
+ end
12
+
13
+ def underlaying_instantiator()
14
+ @underlaying_instantiator
15
+ end
16
+
17
+ def args()
18
+ @args
19
+ end
20
+
21
+ def new(*more_args)
22
+ underlaying_instantiator.new( *(args + more_args) )
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,2 @@
1
+ require_relative "version"
2
+ require_relative "expressions/json-spec"
@@ -0,0 +1,15 @@
1
+ require_relative 'message-formatter'
2
+
3
+ module CabezaDeTermo
4
+ module JsonSpec
5
+ class BlockMessageFormatter < MessageFormatter
6
+ def initialize(block)
7
+ @block = block
8
+ end
9
+
10
+ def message_on(expectation, value_holder)
11
+ @block.call(expectation, value_holder)
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,60 @@
1
+ require_relative 'message-formatter'
2
+ require 'erb'
3
+
4
+ module CabezaDeTermo
5
+ module JsonSpec
6
+ class ErbMessageFormatter
7
+ def initialize(message)
8
+ @message = message
9
+ end
10
+
11
+ def message_on(expectation, value_holder, *params)
12
+ @expectation = expectation
13
+ @value_holder = value_holder
14
+
15
+ format_message
16
+ end
17
+
18
+ # Formatting
19
+
20
+ def format_message
21
+ ERB.new(@message).result(binding)
22
+ end
23
+
24
+ # Accessing
25
+
26
+ def value_holder
27
+ @value_holder
28
+ end
29
+
30
+ def accessors_chain
31
+ value_holder.accessors_chain
32
+ end
33
+
34
+ def field
35
+ accessors_chain.to_s
36
+ end
37
+
38
+ def value
39
+ @value_holder.value
40
+ end
41
+
42
+ def expectation
43
+ @expectation
44
+ end
45
+
46
+ def format(value)
47
+ return 'null' if value == nil
48
+ return 'an object' if value.kind_of? ::Hash
49
+ return list_string(value) if value.kind_of? ::Array
50
+
51
+ value.to_s
52
+ end
53
+
54
+ def list_string(array)
55
+ values = array.collect { |each| format each }
56
+ '[' + values.join(', ') + ']'
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,9 @@
1
+ module CabezaDeTermo
2
+ module JsonSpec
3
+ class MessageFormatter
4
+ def message_on(expectation, value_holder, *params)
5
+ raise 'Subclass responsibility'
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,37 @@
1
+ module CabezaDeTermo
2
+ module JsonSpec
3
+ #
4
+ # A message to be sent to an object.
5
+ # It holds the receiver, the method name and the arguments.
6
+ # It justs waits to be evaluated with :call.
7
+ #
8
+ class MessageSend
9
+ def initialize(receiver, method_name, *args, &block)
10
+ @receiver = receiver
11
+ @method_name = method_name
12
+ @args = args
13
+ @block = block
14
+ end
15
+
16
+ def receiver()
17
+ @receiver
18
+ end
19
+
20
+ def method_name()
21
+ @method_name
22
+ end
23
+
24
+ def args()
25
+ @args
26
+ end
27
+
28
+ def block()
29
+ @block
30
+ end
31
+
32
+ def call()
33
+ receiver.send(method_name, *args, &@block)
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,37 @@
1
+ require_relative "message-send"
2
+
3
+ module CabezaDeTermo
4
+ module JsonSpec
5
+ #
6
+ # A message with arguments to be sent to an object.
7
+ #
8
+ class Message
9
+ def initialize(method_name, *args, &block)
10
+ @method_name = method_name
11
+ @args = args
12
+ @block = block
13
+ end
14
+
15
+ # Accesing
16
+
17
+ def method_name()
18
+ @method_name
19
+ end
20
+
21
+ def args()
22
+ @args
23
+ end
24
+
25
+ def block()
26
+ @block
27
+ end
28
+
29
+ # Evaluating
30
+
31
+ # Send the message with its arguments to an object.
32
+ def send_to(object)
33
+ MessageSend.new(object, method_name, *args, &block).call
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,14 @@
1
+ module CabezaDeTermo
2
+ module JsonSpec
3
+ class ObjectMethod
4
+ def initialize(object, method_name)
5
+ @object = object
6
+ @method_name = method_name
7
+ end
8
+
9
+ def call(*args, &block)
10
+ MessageSend.new(@object, @method_name, *args, &block).call
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,13 @@
1
+ require_relative "expression-modifier"
2
+ require "cabeza-de-termo/json-spec/expectations/runner/can-be-absent-expectations-runner"
3
+
4
+ module CabezaDeTermo
5
+ module JsonSpec
6
+ class CanBeAbsentModifier < ExpressionModifier
7
+ def run_on(expression)
8
+ can_be_absent_runner = CanBeAbsentExpectationsRunner.new(expression.expectations_runner)
9
+ expression.set_expectations_runner(can_be_absent_runner)
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ require_relative "expression-modifier"
2
+ require "cabeza-de-termo/json-spec/expectations/runner/can-be-null-expectations-runner"
3
+
4
+ module CabezaDeTermo
5
+ module JsonSpec
6
+ class CanBeNullModifier < ExpressionModifier
7
+ def run_on(expression)
8
+ can_be_null_runner = CanBeNullExpectationsRunner.new(expression.expectations_runner)
9
+ expression.set_expectations_runner(can_be_null_runner)
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,9 @@
1
+ module CabezaDeTermo
2
+ module JsonSpec
3
+ class ExpressionModifier
4
+ def run_on(expression)
5
+ raise 'Subclass responsibility'
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,27 @@
1
+ require_relative "expression-modifier"
2
+
3
+ module CabezaDeTermo
4
+ module JsonSpec
5
+ class ModifierComposite < ExpressionModifier
6
+ def initialize()
7
+ super()
8
+
9
+ @child_modifiers = []
10
+ end
11
+
12
+ def child_modifiers
13
+ @child_modifiers
14
+ end
15
+
16
+ def add_child(expression_modifier)
17
+ child_modifiers << expression_modifier
18
+ end
19
+
20
+ def run_on(expression)
21
+ child_modifiers.each do |child_modifier|
22
+ child_modifier.run_on(expression)
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,6 @@
1
+ module CabezaDeTermo
2
+ module JsonSpec
3
+ class Signal < StandardError
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,8 @@
1
+ require_relative 'signal'
2
+
3
+ module CabezaDeTermo
4
+ module JsonSpec
5
+ class SkipBranchSignal < Signal
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,20 @@
1
+ module CabezaDeTermo
2
+ module JsonSpec
3
+ #
4
+ # Utility class to evaluate blocks binding :self to an object, but only if the block
5
+ # does not take parameters.
6
+ # If the block takes one parameter, call the block with that parameter keeping the binding
7
+ # as it is.
8
+ #
9
+ # Example:
10
+ # Bind.evaluation(of: proc { puts self }, to: 'hello!') # binds self to 'hello!'
11
+ #
12
+ # Bind.evaluation(of: proc { |string| puts string }, to: 'hello!') # no bindings
13
+ #
14
+ class Bind
15
+ def self.evaluation(of: nil, to: nil)
16
+ of.arity == 0 ? to.instance_eval(&of) : of.call(to)
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,70 @@
1
+ module CabezaDeTermo
2
+ module JsonSpec
3
+ class Range
4
+ def self.new_from(at_min, min, max, at_max)
5
+ range = self.new(min, max)
6
+ range.be_open_at_min if at_min == '('
7
+ range.be_open_at_max if at_max == ')'
8
+ range
9
+ end
10
+
11
+ def initialize(min, max)
12
+ @min = min
13
+ @max = max
14
+ be_closed_at_min
15
+ be_closed_at_max
16
+ end
17
+
18
+ # Configuring
19
+
20
+ def be_closed_at_min()
21
+ @open_at_min = false
22
+ end
23
+
24
+ def be_closed_at_max()
25
+ @open_at_max = false
26
+ end
27
+
28
+ def be_open_at_min()
29
+ @open_at_min = true
30
+ end
31
+
32
+ def be_open_at_max()
33
+ @open_at_max = true
34
+ end
35
+
36
+ def min()
37
+ @min
38
+ end
39
+
40
+ def max()
41
+ @max
42
+ end
43
+
44
+ # Asking
45
+
46
+ def is_open_at_min?()
47
+ @open_at_min
48
+ end
49
+
50
+ def is_open_at_max?()
51
+ @open_at_max
52
+ end
53
+
54
+ def includes?(value)
55
+ return false if is_open_at_min? && value <= min
56
+ return false if !is_open_at_min? && value < min
57
+ return false if is_open_at_max? && max <= value
58
+ return false if !is_open_at_max? && max < value
59
+
60
+ true
61
+ end
62
+
63
+ # Displaying
64
+
65
+ def to_s()
66
+ (is_open_at_min? ? '(' : '[') + min.to_s + ', ' + max.to_s + (is_open_at_max? ? ')' : ']')
67
+ end
68
+ end
69
+ end
70
+ end