light-service 0.5.1 → 0.5.2

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: 4d68f9d14bf6972f0063f0e4765b582857ecdf8c
4
- data.tar.gz: ac5f09a4248a65df0781d5e93a5e7df6e95c1cfb
3
+ metadata.gz: cce43f62b668f6fa04385c772ca0d006b9e92ca0
4
+ data.tar.gz: 3d246a1c22bc6dfa9afef1c64d77c1b15b16618b
5
5
  SHA512:
6
- metadata.gz: 1ca0cb1b7e3f80e13a43560069e854c8ba410d905a2ed874a700203908465f408bc379d650cf1c820ab74ec6983ed0b30fea978e3b1c6797acb9694603b8934f
7
- data.tar.gz: 6b66eb9c58f7a7fa6414bff2df6223a2e66f8d4f17de15e107514f45aa77131b778bec94f9715c026f4216720836c37069c9c93f5684587ab6d6f1293646e4de
6
+ metadata.gz: 2c00210b56fb1be0cf27ac8c415f421421902088443ed8919d48ee600f22446e8d2b007586b5a4fae553fe39e11092589face9df3950e6e638f5e1a7fa524a81
7
+ data.tar.gz: 4171398c9f082dae55888485c98e7fe0d335cd0bd527c488b095921055b05659ab1495b33be899b1460839ac41783d902d43121c074276e94c8670481646dae9
data/README.md CHANGED
@@ -147,8 +147,8 @@ I gave a [talk at RailsConf 2013](http://www.adomokos.com/2013/06/simple-and-ele
147
147
  simple and elegant Rails code where I told the story of how LightService was extracted from the projects I had worked on.
148
148
 
149
149
  ## Expects and Promises
150
- Let me introduce to you the `expects` and `promises` macros. Think of these as a rule set of inputs/outputs for the action.
151
- `expects` describes what keys it needs to execute and `promises` makes sure the keys are in the context after the
150
+ The `expects` and `promises` macros are rules for the inputs/outputs of an action.
151
+ `expects` describes what keys it needs to execute, and `promises` makes sure the keys are in the context after the
152
152
  action is reduced. If either of them are violated, a custom exception is thrown.
153
153
 
154
154
  This is how it's used:
data/RELEASES.md CHANGED
@@ -1,5 +1,8 @@
1
1
  A brief list of new features and changes introduced with the specified version.
2
2
 
3
+ ### 0.5.2
4
+ * Guarding context keys against the reserved keys the context needs to operate.
5
+
3
6
  ### 0.5.1
4
7
  * Removing the thrown exception for invoking the "executed" macro twice
5
8
 
data/lib/light-service.rb CHANGED
@@ -6,7 +6,7 @@ require 'light-service/errors'
6
6
  require 'light-service/configuration'
7
7
  require 'light-service/localization_adapter'
8
8
  require 'light-service/context'
9
- require 'light-service/context_key_verifier'
9
+ require 'light-service/context/key_verifier'
10
10
  require 'light-service/organizer/with_reducer'
11
11
  require 'light-service/organizer/with_reducer_log_decorator'
12
12
  require 'light-service/organizer/with_reducer_factory'
@@ -25,28 +25,25 @@ module LightService
25
25
  end
26
26
 
27
27
  def executed
28
- define_singleton_method "execute" do |context = {}|
28
+ define_singleton_method :execute do |context = {}|
29
29
  action_context = create_action_context(context)
30
30
  return action_context if action_context.stop_processing?
31
31
 
32
32
  # Store the action within the context
33
33
  action_context.current_action = self
34
34
 
35
- Context::KeyVerifier.verify_expected_keys_are_in_context(action_context)
35
+ Context::KeyVerifier.verify_keys(action_context) do
36
+ action_context.define_accessor_methods_for_keys(all_keys)
36
37
 
37
- action_context.define_accessor_methods_for_keys(expected_keys)
38
- action_context.define_accessor_methods_for_keys(promised_keys)
39
-
40
- yield(action_context)
41
-
42
- Context::KeyVerifier.verify_promised_keys_are_in_context(action_context)
38
+ yield(action_context)
39
+ end
43
40
  end
44
41
  end
45
42
 
46
43
  def rolled_back
47
44
  raise "`rolled_back` macro can not be invoked again" if self.respond_to?(:rollback)
48
45
 
49
- define_singleton_method "rollback" do |context = {}|
46
+ define_singleton_method :rollback do |context = {}|
50
47
  yield(context)
51
48
 
52
49
  context
@@ -64,6 +61,10 @@ module LightService
64
61
  LightService::Context.make(context)
65
62
  end
66
63
 
64
+ def all_keys
65
+ expected_keys + promised_keys
66
+ end
67
+
67
68
  end
68
69
  end
69
70
  end
@@ -0,0 +1,114 @@
1
+ module LightService; class Context
2
+ class KeyVerifier
3
+ attr_reader :context, :action
4
+
5
+ def initialize(context)
6
+ @context = context
7
+ @action = context.current_action
8
+ end
9
+
10
+ def are_all_keys_in_context?(keys)
11
+ not_found_keys = keys_not_found(keys)
12
+ !not_found_keys.any?
13
+ end
14
+
15
+ def keys_not_found(keys)
16
+ keys ||= context.keys
17
+ keys - context.keys
18
+ end
19
+
20
+ def format_keys(keys)
21
+ keys.map { |k| ":#{k}"}.join(', ')
22
+ end
23
+
24
+ def error_message
25
+ "#{type_name} #{format_keys(keys_not_found(keys))} to be in the context during #{action}"
26
+ end
27
+
28
+ def throw_error_predicate(keys)
29
+ raise NotImplementedError, 'Sorry, you have to override length'
30
+ end
31
+
32
+ def verify
33
+ return context if context.failure?
34
+
35
+ if throw_error_predicate(keys)
36
+ Configuration.logger.error error_message
37
+ fail error_to_throw, error_message
38
+ end
39
+
40
+ context
41
+ end
42
+
43
+ def self.verify_keys(context, &block)
44
+ ReservedKeysVerifier.new(context).verify
45
+ ExpectedKeyVerifier.new(context).verify
46
+
47
+ block.call
48
+
49
+ PromisedKeyVerifier.new(context).verify
50
+ end
51
+ end
52
+
53
+ class ExpectedKeyVerifier < KeyVerifier
54
+ def type_name
55
+ "expected"
56
+ end
57
+
58
+ def keys
59
+ action.expected_keys
60
+ end
61
+
62
+ def error_to_throw
63
+ ExpectedKeysNotInContextError
64
+ end
65
+
66
+ def throw_error_predicate(keys)
67
+ !are_all_keys_in_context?(keys)
68
+ end
69
+ end
70
+
71
+ class PromisedKeyVerifier < KeyVerifier
72
+ def type_name
73
+ "promised"
74
+ end
75
+
76
+ def keys
77
+ action.promised_keys
78
+ end
79
+
80
+ def error_to_throw
81
+ PromisedKeysNotInContextError
82
+ end
83
+
84
+ def throw_error_predicate(keys)
85
+ !are_all_keys_in_context?(keys)
86
+ end
87
+ end
88
+
89
+ class ReservedKeysVerifier < KeyVerifier
90
+ def violated_keys
91
+ (action.promised_keys + action.expected_keys) & reserved_keys
92
+ end
93
+
94
+ def error_message
95
+ "promised or expected keys cannot be a reserved key: [#{format_keys(violated_keys)}]"
96
+ end
97
+
98
+ def keys
99
+ violated_keys
100
+ end
101
+
102
+ def error_to_throw
103
+ ReservedKeysInContextError
104
+ end
105
+
106
+ def throw_error_predicate(keys)
107
+ keys.any?
108
+ end
109
+
110
+ def reserved_keys
111
+ [:message, :error_code, :current_action].freeze
112
+ end
113
+ end
114
+ end; end
@@ -2,4 +2,5 @@ module LightService
2
2
  class FailWithRollbackError < StandardError; end
3
3
  class ExpectedKeysNotInContextError < StandardError; end
4
4
  class PromisedKeysNotInContextError < StandardError; end
5
+ class ReservedKeysInContextError < StandardError; end
5
6
  end
@@ -1,3 +1,3 @@
1
1
  module LightService
2
- VERSION = "0.5.1"
2
+ VERSION = "0.5.2"
3
3
  end
@@ -32,4 +32,19 @@ describe ":expects macro" do
32
32
  expect(resulting_context[:milk_tea]).to eq("black - full cream - with dark chocolate")
33
33
  end
34
34
 
35
+ context "when a reserved key is listed as an expected key" do
36
+ it "raises an error indicating a reserved key is expected" do
37
+ exception_error_text = "promised or expected keys cannot be a reserved key: [:message]"
38
+ expect {
39
+ TestDoubles::MakesTeaExpectingReservedKey.execute(:tea => "black", :message => "no no")
40
+ }.to raise_error(LightService::ReservedKeysInContextError, exception_error_text)
41
+ end
42
+
43
+ it "raises an error indicating that multiple reserved keys are expected" do
44
+ exception_error_text = "promised or expected keys cannot be a reserved key: [:message, :error_code, :current_action]"
45
+ expect {
46
+ TestDoubles::MakesTeaExpectingMultipleReservedKeys.execute(:tea => "black", :message => "no no", :error_code => 1, :current_action => "update")
47
+ }.to raise_error(LightService::ReservedKeysInContextError, exception_error_text)
48
+ end
49
+ end
35
50
  end
@@ -77,6 +77,22 @@ describe ":promises macro" do
77
77
  end
78
78
  end
79
79
 
80
+ context "when a reserved key is listed as a promised key" do
81
+ it "raises an error indicating a reserved key has been promised" do
82
+ exception_error_text = "promised or expected keys cannot be a reserved key: [:message]"
83
+ expect {
84
+ TestDoubles::MakesTeaPromisingReservedKey.execute(:tea => "black")
85
+ }.to raise_error(LightService::ReservedKeysInContextError, exception_error_text)
86
+ end
87
+
88
+ it "raises an error indicating that multiple reserved keys have been promised" do
89
+ exception_error_text = "promised or expected keys cannot be a reserved key: [:message, :error_code, :current_action]"
90
+ expect {
91
+ TestDoubles::MakesTeaPromisingMultipleReservedKeys.execute(:tea => "black")
92
+ }.to raise_error(LightService::ReservedKeysInContextError, exception_error_text)
93
+ end
94
+ end
95
+
80
96
  it "can collect promised keys when the `promised` macro is called multiple times" do
81
97
  resulting_context = TestDoubles::MultiplePromisesAction.execute(
82
98
  :coffee => "espresso",
@@ -85,5 +101,4 @@ describe ":promises macro" do
85
101
  expect(resulting_context.cappuccino).to eq("Cappucino needs espresso and a little milk")
86
102
  expect(resulting_context.latte).to eq("Latte needs espresso and a lot of milk")
87
103
  end
88
-
89
104
  end
data/spec/test_doubles.rb CHANGED
@@ -176,4 +176,41 @@ module TestDoubles
176
176
  end
177
177
  end
178
178
 
179
+ class MakesTeaExpectingReservedKey
180
+ include LightService::Action
181
+ expects :tea, :message
182
+
183
+ executed do |context|
184
+ context.product = context.number + 3
185
+ end
186
+ end
187
+
188
+ class MakesTeaExpectingMultipleReservedKeys
189
+ include LightService::Action
190
+ expects :tea, :message, :error_code, :current_action
191
+
192
+ executed do |context|
193
+ context.product = context.number + 3
194
+ end
195
+ end
196
+
197
+ class MakesTeaPromisingReservedKey
198
+ include LightService::Action
199
+ expects :tea
200
+ promises :product, :message
201
+
202
+ executed do |context|
203
+ context.product = context.number + 3
204
+ end
205
+ end
206
+
207
+ class MakesTeaPromisingMultipleReservedKeys
208
+ include LightService::Action
209
+ expects :tea
210
+ promises :product, :message, :error_code, :current_action
211
+
212
+ executed do |context|
213
+ context.product = context.number + 3
214
+ end
215
+ end
179
216
  end
metadata CHANGED
@@ -1,69 +1,69 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: light-service
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.1
4
+ version: 0.5.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Attila Domokos
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-11-12 00:00:00.000000000 Z
11
+ date: 2015-04-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ">="
17
+ - - '>='
18
18
  - !ruby/object:Gem::Version
19
19
  version: '4.0'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ">="
24
+ - - '>='
25
25
  - !ruby/object:Gem::Version
26
26
  version: '4.0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rspec
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - "~>"
31
+ - - ~>
32
32
  - !ruby/object:Gem::Version
33
33
  version: '3.0'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - "~>"
38
+ - - ~>
39
39
  - !ruby/object:Gem::Version
40
40
  version: '3.0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rspec-its
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - "~>"
45
+ - - ~>
46
46
  - !ruby/object:Gem::Version
47
47
  version: '1.0'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - "~>"
52
+ - - ~>
53
53
  - !ruby/object:Gem::Version
54
54
  version: '1.0'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: simplecov
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - "~>"
59
+ - - ~>
60
60
  - !ruby/object:Gem::Version
61
61
  version: 0.7.1
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - "~>"
66
+ - - ~>
67
67
  - !ruby/object:Gem::Version
68
68
  version: 0.7.1
69
69
  - !ruby/object:Gem::Dependency
@@ -87,9 +87,9 @@ executables: []
87
87
  extensions: []
88
88
  extra_rdoc_files: []
89
89
  files:
90
- - ".gitignore"
91
- - ".rspec"
92
- - ".travis.yml"
90
+ - .gitignore
91
+ - .rspec
92
+ - .travis.yml
93
93
  - Gemfile
94
94
  - LICENSE
95
95
  - README.md
@@ -99,7 +99,7 @@ files:
99
99
  - lib/light-service/action.rb
100
100
  - lib/light-service/configuration.rb
101
101
  - lib/light-service/context.rb
102
- - lib/light-service/context_key_verifier.rb
102
+ - lib/light-service/context/key_verifier.rb
103
103
  - lib/light-service/errors.rb
104
104
  - lib/light-service/localization_adapter.rb
105
105
  - lib/light-service/organizer.rb
@@ -142,17 +142,17 @@ require_paths:
142
142
  - lib
143
143
  required_ruby_version: !ruby/object:Gem::Requirement
144
144
  requirements:
145
- - - ">="
145
+ - - '>='
146
146
  - !ruby/object:Gem::Version
147
147
  version: '0'
148
148
  required_rubygems_version: !ruby/object:Gem::Requirement
149
149
  requirements:
150
- - - ">="
150
+ - - '>='
151
151
  - !ruby/object:Gem::Version
152
152
  version: '0'
153
153
  requirements: []
154
154
  rubyforge_project:
155
- rubygems_version: 2.2.2
155
+ rubygems_version: 2.0.14
156
156
  signing_key:
157
157
  specification_version: 4
158
158
  summary: A service skeleton with an emphasis on simplicity
@@ -1,48 +0,0 @@
1
- module LightService
2
- class Context
3
- class KeyVerifier
4
- class << self
5
- def verify_expected_keys_are_in_context(context)
6
- action = context.current_action
7
-
8
- verify_keys_are_in_context(context, action.expected_keys) do |not_found_keys|
9
- error_message = "expected #{format_keys(not_found_keys)} to be in the context during #{action}"
10
-
11
- Configuration.logger.error error_message
12
- fail ExpectedKeysNotInContextError, error_message
13
- end
14
- end
15
-
16
- def verify_promised_keys_are_in_context(context)
17
- return context if context.failure?
18
-
19
- action = context.current_action
20
-
21
- verify_keys_are_in_context(context, action.promised_keys) do |not_found_keys|
22
- error_message = "promised #{format_keys(not_found_keys)} to be in the context during #{action}"
23
-
24
- Configuration.logger.error error_message
25
- fail PromisedKeysNotInContextError, error_message
26
- end
27
- end
28
-
29
- private
30
-
31
- def verify_keys_are_in_context(context, keys)
32
- keys ||= context.keys
33
-
34
- not_found_keys = keys - context.keys
35
- unless not_found_keys.empty?
36
- yield not_found_keys
37
- end
38
-
39
- context
40
- end
41
-
42
- def format_keys(keys)
43
- keys.map { |k| ":#{k}"}.join(', ')
44
- end
45
- end
46
- end
47
- end
48
- end