functional-light-service 0.2.4

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 (110) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +22 -0
  3. data/.rspec +3 -0
  4. data/.rubocop.yml +72 -0
  5. data/.travis.yml +22 -0
  6. data/Appraisals +3 -0
  7. data/CHANGELOG.md +37 -0
  8. data/CODE_OF_CONDUCT.md +22 -0
  9. data/Gemfile +6 -0
  10. data/LICENSE +22 -0
  11. data/README.md +1424 -0
  12. data/Rakefile +12 -0
  13. data/VERSION +1 -0
  14. data/functional-light-service.gemspec +26 -0
  15. data/gemfiles/activesupport_5.gemfile +8 -0
  16. data/gemfiles/activesupport_5.gemfile.lock +82 -0
  17. data/lib/functional-light-service/action.rb +102 -0
  18. data/lib/functional-light-service/configuration.rb +24 -0
  19. data/lib/functional-light-service/context/key_verifier.rb +118 -0
  20. data/lib/functional-light-service/context.rb +165 -0
  21. data/lib/functional-light-service/errors.rb +6 -0
  22. data/lib/functional-light-service/functional/enum.rb +254 -0
  23. data/lib/functional-light-service/functional/maybe.rb +14 -0
  24. data/lib/functional-light-service/functional/monad.rb +66 -0
  25. data/lib/functional-light-service/functional/null.rb +74 -0
  26. data/lib/functional-light-service/functional/option.rb +99 -0
  27. data/lib/functional-light-service/functional/result.rb +122 -0
  28. data/lib/functional-light-service/localization_adapter.rb +44 -0
  29. data/lib/functional-light-service/organizer/execute.rb +14 -0
  30. data/lib/functional-light-service/organizer/iterate.rb +22 -0
  31. data/lib/functional-light-service/organizer/reduce_if.rb +17 -0
  32. data/lib/functional-light-service/organizer/reduce_until.rb +20 -0
  33. data/lib/functional-light-service/organizer/scoped_reducable.rb +13 -0
  34. data/lib/functional-light-service/organizer/verify_call_method_exists.rb +28 -0
  35. data/lib/functional-light-service/organizer/with_callback.rb +26 -0
  36. data/lib/functional-light-service/organizer/with_reducer.rb +71 -0
  37. data/lib/functional-light-service/organizer/with_reducer_factory.rb +18 -0
  38. data/lib/functional-light-service/organizer/with_reducer_log_decorator.rb +105 -0
  39. data/lib/functional-light-service/organizer.rb +105 -0
  40. data/lib/functional-light-service/testing/context_factory.rb +40 -0
  41. data/lib/functional-light-service/testing.rb +1 -0
  42. data/lib/functional-light-service/version.rb +3 -0
  43. data/lib/functional-light-service.rb +29 -0
  44. data/resources/fail_actions.png +0 -0
  45. data/resources/light-service.png +0 -0
  46. data/resources/organizer_and_actions.png +0 -0
  47. data/resources/skip_actions.png +0 -0
  48. data/spec/acceptance/add_numbers_spec.rb +11 -0
  49. data/spec/acceptance/after_actions_spec.rb +71 -0
  50. data/spec/acceptance/around_each_spec.rb +19 -0
  51. data/spec/acceptance/before_actions_spec.rb +98 -0
  52. data/spec/acceptance/custom_log_from_organizer_spec.rb +60 -0
  53. data/spec/acceptance/fail_spec.rb +24 -0
  54. data/spec/acceptance/include_warning_spec.rb +29 -0
  55. data/spec/acceptance/log_from_organizer_spec.rb +154 -0
  56. data/spec/acceptance/message_localization_spec.rb +118 -0
  57. data/spec/acceptance/not_having_call_method_warning_spec.rb +39 -0
  58. data/spec/acceptance/organizer/around_each_with_reduce_if_spec.rb +42 -0
  59. data/spec/acceptance/organizer/context_failure_and_skipping_spec.rb +65 -0
  60. data/spec/acceptance/organizer/execute_spec.rb +46 -0
  61. data/spec/acceptance/organizer/iterate_spec.rb +37 -0
  62. data/spec/acceptance/organizer/reduce_if_spec.rb +51 -0
  63. data/spec/acceptance/organizer/reduce_until_spec.rb +43 -0
  64. data/spec/acceptance/organizer/with_callback_spec.rb +110 -0
  65. data/spec/acceptance/rollback_spec.rb +132 -0
  66. data/spec/acceptance/skip_all_warning_spec.rb +20 -0
  67. data/spec/acceptance/testing/context_factory_spec.rb +54 -0
  68. data/spec/action_expected_keys_spec.rb +63 -0
  69. data/spec/action_expects_and_promises_spec.rb +93 -0
  70. data/spec/action_promised_keys_spec.rb +122 -0
  71. data/spec/action_spec.rb +89 -0
  72. data/spec/context/inspect_spec.rb +57 -0
  73. data/spec/context_spec.rb +197 -0
  74. data/spec/examples/amount_spec.rb +77 -0
  75. data/spec/examples/controller_spec.rb +63 -0
  76. data/spec/examples/validate_address_spec.rb +37 -0
  77. data/spec/lib/deterministic/class_mixin_spec.rb +24 -0
  78. data/spec/lib/deterministic/currify_spec.rb +88 -0
  79. data/spec/lib/deterministic/monad_axioms.rb +44 -0
  80. data/spec/lib/deterministic/monad_spec.rb +45 -0
  81. data/spec/lib/deterministic/null_spec.rb +58 -0
  82. data/spec/lib/deterministic/option_spec.rb +133 -0
  83. data/spec/lib/deterministic/result/failure_spec.rb +65 -0
  84. data/spec/lib/deterministic/result/result_map_spec.rb +154 -0
  85. data/spec/lib/deterministic/result/result_shared.rb +24 -0
  86. data/spec/lib/deterministic/result/success_spec.rb +41 -0
  87. data/spec/lib/deterministic/result_spec.rb +63 -0
  88. data/spec/lib/enum_spec.rb +112 -0
  89. data/spec/localization_adapter_spec.rb +83 -0
  90. data/spec/organizer/with_reducer_spec.rb +56 -0
  91. data/spec/organizer_key_aliases_spec.rb +29 -0
  92. data/spec/organizer_spec.rb +93 -0
  93. data/spec/readme_spec.rb +47 -0
  94. data/spec/sample/calculates_order_tax_action_spec.rb +16 -0
  95. data/spec/sample/calculates_tax_spec.rb +30 -0
  96. data/spec/sample/looks_up_tax_percentage_action_spec.rb +53 -0
  97. data/spec/sample/provides_free_shipping_action_spec.rb +25 -0
  98. data/spec/sample/tax/calculates_order_tax_action.rb +9 -0
  99. data/spec/sample/tax/calculates_tax.rb +11 -0
  100. data/spec/sample/tax/looks_up_tax_percentage_action.rb +27 -0
  101. data/spec/sample/tax/provides_free_shipping_action.rb +10 -0
  102. data/spec/spec_helper.rb +24 -0
  103. data/spec/support.rb +1 -0
  104. data/spec/test_doubles.rb +552 -0
  105. data/spec/testing/context_factory/iterate_spec.rb +39 -0
  106. data/spec/testing/context_factory/reduce_if_spec.rb +40 -0
  107. data/spec/testing/context_factory/reduce_until_spec.rb +40 -0
  108. data/spec/testing/context_factory/with_callback_spec.rb +38 -0
  109. data/spec/testing/context_factory_spec.rb +55 -0
  110. metadata +285 -0
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ require "rubygems"
4
+ require "bundler/setup"
5
+
6
+ require 'rspec/core/rake_task'
7
+ require 'rubocop/rake_task'
8
+ RuboCop::RakeTask.new
9
+ RSpec::Core::RakeTask.new(:spec)
10
+
11
+ task(:default).clear
12
+ task :default => %i[spec rubocop]
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.2.4
@@ -0,0 +1,26 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/functional-light-service/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["Boscolo Michele"]
6
+ gem.email = ["miboscol@gmail.com"]
7
+ gem.description = %q{A service skeleton with an emphasis on simplicity with a pinch a functional programming}
8
+ gem.summary = %q{A service skeleton with an emphasis on simplicity with a pinch a functional programming}
9
+ gem.homepage = "https://github.com/sphynx79/functional-light-service"
10
+ gem.license = "MIT"
11
+
12
+ gem.files = `git ls-files`.split($\)
13
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
14
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
15
+ gem.name = "functional-light-service"
16
+ gem.require_paths = ["lib"]
17
+ gem.version = FunctionalLightService::VERSION
18
+
19
+ # gem.add_dependency("activesupport", ">= 5.2.2")
20
+
21
+ gem.add_development_dependency("activesupport", "~> 5.2.0")
22
+ gem.add_development_dependency("rspec", "~> 3.0")
23
+ gem.add_development_dependency("simplecov", "~> 0.16.1")
24
+ gem.add_development_dependency("rubocop", "~> 0.63.1")
25
+ gem.add_development_dependency("pry", "~> 0.12.2")
26
+ end
@@ -0,0 +1,8 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "activesupport", "~> 5.0"
6
+ gem "appraisal", "~> 2.0"
7
+
8
+ gemspec :path => "../"
@@ -0,0 +1,82 @@
1
+ PATH
2
+ remote: ../
3
+ specs:
4
+ light-service (0.6.1)
5
+ activesupport (>= 3.0)
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ activesupport (5.0.0.1)
11
+ concurrent-ruby (~> 1.0, >= 1.0.2)
12
+ i18n (~> 0.7)
13
+ minitest (~> 5.1)
14
+ tzinfo (~> 1.1)
15
+ appraisal (2.1.0)
16
+ bundler
17
+ rake
18
+ thor (>= 0.14.0)
19
+ ast (2.3.0)
20
+ coderay (1.1.1)
21
+ concurrent-ruby (1.0.2)
22
+ diff-lcs (1.2.5)
23
+ docile (1.1.5)
24
+ i18n (0.7.0)
25
+ json (2.0.2)
26
+ method_source (0.8.2)
27
+ minitest (5.9.0)
28
+ parser (2.3.1.2)
29
+ ast (~> 2.2)
30
+ powerpack (0.1.1)
31
+ pry (0.10.4)
32
+ coderay (~> 1.1.0)
33
+ method_source (~> 0.8.1)
34
+ slop (~> 3.4)
35
+ rainbow (2.1.0)
36
+ rake (11.2.2)
37
+ rspec (3.5.0)
38
+ rspec-core (~> 3.5.0)
39
+ rspec-expectations (~> 3.5.0)
40
+ rspec-mocks (~> 3.5.0)
41
+ rspec-core (3.5.2)
42
+ rspec-support (~> 3.5.0)
43
+ rspec-expectations (3.5.0)
44
+ diff-lcs (>= 1.2.0, < 2.0)
45
+ rspec-support (~> 3.5.0)
46
+ rspec-mocks (3.5.0)
47
+ diff-lcs (>= 1.2.0, < 2.0)
48
+ rspec-support (~> 3.5.0)
49
+ rspec-support (3.5.0)
50
+ rubocop (0.42.0)
51
+ parser (>= 2.3.1.1, < 3.0)
52
+ powerpack (~> 0.1)
53
+ rainbow (>= 1.99.1, < 3.0)
54
+ ruby-progressbar (~> 1.7)
55
+ unicode-display_width (~> 1.0, >= 1.0.1)
56
+ ruby-progressbar (1.8.1)
57
+ simplecov (0.12.0)
58
+ docile (~> 1.1.0)
59
+ json (>= 1.8, < 3)
60
+ simplecov-html (~> 0.10.0)
61
+ simplecov-html (0.10.0)
62
+ slop (3.6.0)
63
+ thor (0.19.1)
64
+ thread_safe (0.3.5)
65
+ tzinfo (1.2.2)
66
+ thread_safe (~> 0.1)
67
+ unicode-display_width (1.1.1)
68
+
69
+ PLATFORMS
70
+ ruby
71
+
72
+ DEPENDENCIES
73
+ activesupport (~> 5.0)
74
+ appraisal (~> 2.0)
75
+ light-service!
76
+ pry (~> 0.10)
77
+ rspec (~> 3.0)
78
+ rubocop (~> 0.36)
79
+ simplecov (~> 0.11)
80
+
81
+ BUNDLED WITH
82
+ 1.12.5
@@ -0,0 +1,102 @@
1
+ require 'active_support/deprecation'
2
+
3
+ module FunctionalLightService
4
+ module Action
5
+ def self.extended(base_class)
6
+ base_class.extend Macros
7
+ base_class.extend FunctionalLightService::Prelude::Result
8
+ end
9
+
10
+ def self.included(base_class)
11
+ msg = "including FunctionalLightService::Action is deprecated. " \
12
+ "Please use `extend FunctionalLightService::Action` instead"
13
+ ActiveSupport::Deprecation.warn(msg)
14
+ base_class.extend Macros
15
+ end
16
+
17
+ module Macros
18
+ def expects(*args)
19
+ expected_keys.concat(args)
20
+ end
21
+
22
+ def promises(*args)
23
+ promised_keys.concat(args)
24
+ end
25
+
26
+ def expected_keys
27
+ @expected_keys ||= []
28
+ end
29
+
30
+ def promised_keys
31
+ @promised_keys ||= []
32
+ end
33
+
34
+ def ctx(*args)
35
+ @ctx ||= args
36
+ end
37
+
38
+ def executed
39
+ define_singleton_method :execute do |context = {}|
40
+ action_context = create_action_context(context)
41
+ return action_context if action_context.stop_processing?
42
+
43
+ @ctx = action_context
44
+
45
+ # Store the action within the context
46
+ action_context.current_action = self
47
+
48
+ Context::KeyVerifier.verify_keys(action_context, self) do
49
+ action_context.define_accessor_methods_for_keys(all_keys)
50
+
51
+ catch(:jump_when_failed) do
52
+ call_before_action(action_context)
53
+ yield(action_context)
54
+ call_after_action(action_context)
55
+ end
56
+ end
57
+ end
58
+ end
59
+
60
+ def rolled_back
61
+ msg = "`rolled_back` macro can not be invoked again"
62
+ raise msg if respond_to?(:rollback)
63
+
64
+ define_singleton_method :rollback do |context = {}|
65
+ yield(context)
66
+
67
+ context
68
+ end
69
+ end
70
+
71
+ private
72
+
73
+ def create_action_context(context)
74
+ return context if context.is_a? FunctionalLightService::Context
75
+
76
+ FunctionalLightService::Context.make(context)
77
+ end
78
+
79
+ def all_keys
80
+ expected_keys + promised_keys
81
+ end
82
+
83
+ def call_before_action(context)
84
+ invoke_callbacks(context[:_before_actions], context)
85
+ end
86
+
87
+ def call_after_action(context)
88
+ invoke_callbacks(context[:_after_actions], context)
89
+ end
90
+
91
+ def invoke_callbacks(callbacks, context)
92
+ return context unless callbacks
93
+
94
+ callbacks.each do |cb|
95
+ cb.call(context)
96
+ end
97
+
98
+ context
99
+ end
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,24 @@
1
+ module FunctionalLightService
2
+ class Configuration
3
+ class << self
4
+ attr_writer :logger, :localization_adapter
5
+
6
+ def logger
7
+ @logger = _default_logger unless instance_variable_defined?("@logger")
8
+ @logger
9
+ end
10
+
11
+ def localization_adapter
12
+ @localization_adapter ||= LocalizationAdapter.new
13
+ end
14
+
15
+ private
16
+
17
+ def _default_logger
18
+ logger = Logger.new("/dev/null")
19
+ logger.level = Logger::WARN
20
+ logger
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,118 @@
1
+ module FunctionalLightService
2
+ class Context
3
+ class KeyVerifier
4
+ attr_reader :context, :action
5
+
6
+ def initialize(context, action)
7
+ @context = context
8
+ @action = action
9
+ end
10
+
11
+ def are_all_keys_in_context?(keys)
12
+ not_found_keys = keys_not_found(keys)
13
+ not_found_keys.none?
14
+ end
15
+
16
+ def keys_not_found(keys)
17
+ keys ||= context.keys
18
+ keys - context.keys
19
+ end
20
+
21
+ def format_keys(keys)
22
+ keys.map { |k| ":#{k}" }.join(', ')
23
+ end
24
+
25
+ def error_message
26
+ "#{type_name} #{format_keys(keys_not_found(keys))} " \
27
+ "to be in the context during #{action}"
28
+ end
29
+
30
+ def throw_error_predicate(_keys)
31
+ raise NotImplementedError, 'Sorry, you have to override length'
32
+ end
33
+
34
+ def verify
35
+ return context if context.failure?
36
+
37
+ if throw_error_predicate(keys)
38
+ Configuration.logger.error error_message
39
+ raise error_to_throw, error_message
40
+ end
41
+
42
+ context
43
+ end
44
+
45
+ def self.verify_keys(context, action, &block)
46
+ ReservedKeysVerifier.new(context, action).verify
47
+ ExpectedKeyVerifier.new(context, action).verify
48
+
49
+ block.call
50
+
51
+ PromisedKeyVerifier.new(context, action).verify
52
+ end
53
+ end
54
+
55
+ class ExpectedKeyVerifier < KeyVerifier
56
+ def type_name
57
+ "expected"
58
+ end
59
+
60
+ def keys
61
+ action.expected_keys
62
+ end
63
+
64
+ def error_to_throw
65
+ ExpectedKeysNotInContextError
66
+ end
67
+
68
+ def throw_error_predicate(keys)
69
+ !are_all_keys_in_context?(keys)
70
+ end
71
+ end
72
+
73
+ class PromisedKeyVerifier < KeyVerifier
74
+ def type_name
75
+ "promised"
76
+ end
77
+
78
+ def keys
79
+ action.promised_keys
80
+ end
81
+
82
+ def error_to_throw
83
+ PromisedKeysNotInContextError
84
+ end
85
+
86
+ def throw_error_predicate(keys)
87
+ !are_all_keys_in_context?(keys)
88
+ end
89
+ end
90
+
91
+ class ReservedKeysVerifier < KeyVerifier
92
+ def violated_keys
93
+ (action.promised_keys + action.expected_keys) & reserved_keys
94
+ end
95
+
96
+ def error_message
97
+ "promised or expected keys cannot be a " \
98
+ "reserved key: [#{format_keys(violated_keys)}]"
99
+ end
100
+
101
+ def keys
102
+ violated_keys
103
+ end
104
+
105
+ def error_to_throw
106
+ ReservedKeysInContextError
107
+ end
108
+
109
+ def throw_error_predicate(keys)
110
+ keys.any?
111
+ end
112
+
113
+ def reserved_keys
114
+ %i[message error_code current_action].freeze
115
+ end
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,165 @@
1
+ require 'active_support/deprecation'
2
+
3
+ module FunctionalLightService
4
+ # rubocop:disable ClassLength
5
+ class Context < Hash
6
+ include FunctionalLightService::Prelude::Option
7
+ include FunctionalLightService::Prelude::Result
8
+ attr_accessor :outcome, :current_action
9
+
10
+ def initialize(context = {},
11
+ outcome = Success(:message => '', :error => nil))
12
+ @outcome = outcome
13
+ @skip_remaining = false
14
+ context.to_hash.each { |k, v| self[k] = v }
15
+ end
16
+
17
+ def self.make(context = {})
18
+ unless context.is_a?(Hash) || context.is_a?(FunctionalLightService::Context)
19
+ msg = 'Argument must be Hash or FunctionalLightService::Context'
20
+ raise ArgumentError, msg
21
+ end
22
+
23
+ context = new(context) unless context.is_a?(Context)
24
+
25
+ context.assign_aliases(context.delete(:_aliases)) if context[:_aliases]
26
+ context
27
+ end
28
+
29
+ def add_to_context(values)
30
+ merge! values
31
+ end
32
+
33
+ def success?
34
+ @outcome.success?
35
+ end
36
+
37
+ def failure?
38
+ success? == false
39
+ end
40
+
41
+ def skip_remaining?
42
+ @skip_remaining
43
+ end
44
+
45
+ def reset_skip_remaining!
46
+ @outcome = Success(nil)
47
+ @skip_remaining = false
48
+ end
49
+
50
+ def message
51
+ @outcome.value.dig(:message)
52
+ end
53
+
54
+ def error_code
55
+ @outcome.value.dig(:error)
56
+ end
57
+
58
+ def succeed!(message = nil, options = {})
59
+ message = Configuration.localization_adapter.success(message,
60
+ current_action,
61
+ options)
62
+ @outcome = Success(:message => message)
63
+ end
64
+
65
+ def fail!(message = nil, options_or_error_code = {})
66
+ options_or_error_code ||= {}
67
+
68
+ if options_or_error_code.is_a?(Hash)
69
+ error_code = options_or_error_code.delete(:error_code)
70
+ options = options_or_error_code
71
+ else
72
+ error_code = options_or_error_code
73
+ options = {}
74
+ end
75
+
76
+ message = Configuration.localization_adapter.failure(message,
77
+ current_action,
78
+ options)
79
+
80
+ @outcome = Failure(:message => message, :error => error_code)
81
+ end
82
+
83
+ def fail_and_return!(*args)
84
+ fail!(*args)
85
+ throw(:jump_when_failed, *args)
86
+ end
87
+
88
+ def fail_with_rollback!(message = nil, error_code = nil)
89
+ fail!(message, error_code)
90
+ raise FailWithRollbackError
91
+ end
92
+
93
+ def skip_all!(message = nil)
94
+ warning_msg = "Using skip_all! has been deprecated, " \
95
+ "please use `skip_remaining!` instead."
96
+ ActiveSupport::Deprecation.warn(warning_msg)
97
+
98
+ skip_remaining!(message)
99
+ end
100
+
101
+ def skip_remaining!(message = nil)
102
+ @outcome = Success(:message => message)
103
+ @skip_remaining = true
104
+ end
105
+
106
+ def stop_processing?
107
+ failure? || skip_remaining?
108
+ end
109
+
110
+ def define_accessor_methods_for_keys(keys)
111
+ return if keys.nil?
112
+
113
+ keys.each do |key|
114
+ next if respond_to?(key.to_sym)
115
+
116
+ define_singleton_method(key.to_s) { fetch(key) }
117
+ define_singleton_method("#{key}=") { |value| self[key] = value }
118
+ end
119
+ end
120
+
121
+ def assign_aliases(aliases)
122
+ @aliases = aliases
123
+
124
+ aliases.each_pair do |key, key_alias|
125
+ self[key_alias] = self[key]
126
+ end
127
+ end
128
+
129
+ def aliases
130
+ @aliases ||= {}
131
+ end
132
+
133
+ def [](key)
134
+ key = aliases.key(key) || key
135
+ return super(key)
136
+ end
137
+
138
+ def fetch(key, default = nil, &blk)
139
+ self[key] ||= if block_given?
140
+ super(key, &blk)
141
+ else
142
+ super
143
+ end
144
+ end
145
+
146
+ def inspect
147
+ "#{self.class}(#{self}, " \
148
+ + "success: #{success?}, " \
149
+ + "message: #{check_nil(message)}, " \
150
+ + "error_code: #{check_nil(error_code)}, " \
151
+ + "skip_remaining: #{@skip_remaining}, " \
152
+ + "aliases: #{@aliases}" \
153
+ + ")"
154
+ end
155
+
156
+ private
157
+
158
+ def check_nil(value)
159
+ return 'nil' unless value
160
+
161
+ "'#{value}'"
162
+ end
163
+ end
164
+ # rubocop:enable ClassLength
165
+ end
@@ -0,0 +1,6 @@
1
+ module FunctionalLightService
2
+ class FailWithRollbackError < StandardError; end
3
+ class ExpectedKeysNotInContextError < StandardError; end
4
+ class PromisedKeysNotInContextError < StandardError; end
5
+ class ReservedKeysInContextError < StandardError; end
6
+ end