json-spec 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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