light-service 0.4.0 → 0.5.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.
data/spec/action_spec.rb CHANGED
@@ -9,7 +9,7 @@ describe LightService::Action do
9
9
  it "returns immediately" do
10
10
  context.fail!("an error")
11
11
 
12
- TestDoubles::AddsTwoAction.execute(context)
12
+ TestDoubles::AddsTwoActionWithFetch.execute(context)
13
13
 
14
14
  expect(context.to_hash.keys).to be_empty
15
15
  end
@@ -17,7 +17,7 @@ describe LightService::Action do
17
17
 
18
18
  context "when the action context does not have failure" do
19
19
  it "executes the block" do
20
- TestDoubles::AddsTwoAction.execute(context)
20
+ TestDoubles::AddsTwoActionWithFetch.execute(context)
21
21
 
22
22
  expect(context.to_hash.keys).to eq [:number]
23
23
  expect(context.fetch(:number)).to eq(2)
@@ -28,32 +28,32 @@ describe LightService::Action do
28
28
  it "returns immediately" do
29
29
  context.skip_all!
30
30
 
31
- TestDoubles::AddsTwoAction.execute(context)
31
+ TestDoubles::AddsTwoActionWithFetch.execute(context)
32
32
 
33
33
  expect(context.to_hash.keys).to be_empty
34
34
  end
35
35
 
36
36
  it "does not execute skipped actions" do
37
- TestDoubles::AddsTwoAction.execute(context)
37
+ TestDoubles::AddsTwoActionWithFetch.execute(context)
38
38
  expect(context.to_hash).to eq ({:number => 2})
39
39
 
40
40
  context.skip_all!
41
41
 
42
- TestDoubles::AddsTwoAction.execute(context)
42
+ TestDoubles::AddsTwoActionWithFetch.execute(context)
43
43
  # Since the action was skipped, the number remains 2
44
44
  expect(context.to_hash).to eq ({:number => 2})
45
45
  end
46
46
  end
47
47
 
48
48
  it "returns the context" do
49
- result = TestDoubles::AddsTwoAction.execute(context)
49
+ result = TestDoubles::AddsTwoActionWithFetch.execute(context)
50
50
 
51
51
  expect(result.to_hash).to eq ({:number => 2})
52
52
  end
53
53
 
54
54
  context "when invoked with hash" do
55
55
  it "creates LightService::Context implicitly" do
56
- result = TestDoubles::AddsTwoAction.execute(:some_key => "some value")
56
+ result = TestDoubles::AddsTwoActionWithFetch.execute(:some_key => "some value")
57
57
 
58
58
  expect(result).to be_success
59
59
  expect(result.keys).to eq([:some_key, :number])
@@ -62,7 +62,7 @@ describe LightService::Action do
62
62
 
63
63
  context "when invoked without arguments" do
64
64
  it "creates LightService::Context implicitly" do
65
- result = TestDoubles::AddsTwoAction.execute
65
+ result = TestDoubles::AddsTwoActionWithFetch.execute
66
66
 
67
67
  expect(result).to be_success
68
68
  expect(result.keys).to eq([:number])
data/spec/context_spec.rb CHANGED
@@ -3,6 +3,8 @@ require 'test_doubles'
3
3
 
4
4
  describe LightService::Context do
5
5
 
6
+ let(:context) { LightService::Context.make }
7
+
6
8
  describe "can be made" do
7
9
  context "with no arguments" do
8
10
  subject { LightService::Context.make }
@@ -46,21 +48,18 @@ describe LightService::Context do
46
48
  end
47
49
 
48
50
  it "can be asked for skip_all?" do
49
- context = LightService::Context.make
50
51
  context.skip_all!
51
52
 
52
53
  expect(context.skip_all?).to be_truthy
53
54
  end
54
55
 
55
56
  it "can be pushed into a SUCCESS state" do
56
- context = LightService::Context.make
57
57
  context.succeed!("a happy end")
58
58
 
59
59
  expect(context).to be_success
60
60
  end
61
61
 
62
62
  it "can be pushed into a SUCCESS state without a message" do
63
- context = LightService::Context.make
64
63
  context.succeed!
65
64
 
66
65
  expect(context).to be_success
@@ -68,7 +67,6 @@ describe LightService::Context do
68
67
  end
69
68
 
70
69
  it "can be pushed into a FAILURE state without a message" do
71
- context = LightService::Context.make
72
70
  context.fail!
73
71
 
74
72
  expect(context).to be_failure
@@ -76,14 +74,12 @@ describe LightService::Context do
76
74
  end
77
75
 
78
76
  it "can be pushed into a FAILURE state with a message" do
79
- context = LightService::Context.make
80
77
  context.fail!("a sad end")
81
78
 
82
79
  expect(context).to be_failure
83
80
  end
84
81
 
85
82
  it "can be pushed into a FAILURE state with a message in an options hash" do
86
- context = LightService::Context.make
87
83
  context.fail!("a sad end")
88
84
 
89
85
  expect(context).to be_failure
@@ -92,7 +88,6 @@ describe LightService::Context do
92
88
  end
93
89
 
94
90
  it "can be pushed into a FAILURE state with an error code in an options hash" do
95
- context = LightService::Context.make
96
91
  context.fail!("a sad end", 10005)
97
92
 
98
93
  expect(context).to be_failure
@@ -100,16 +95,41 @@ describe LightService::Context do
100
95
  expect(context.error_code).to eq(10005)
101
96
  end
102
97
 
103
- it "can set a flag to skip all subsequent actions" do
98
+ it "uses localization adapter to translate failure message" do
99
+ action_class = TestDoubles::AnAction
100
+ expect(LightService::Configuration.localization_adapter).to receive(:failure)
101
+ .with(:failure_reason, action_class, {})
102
+ .and_return("message")
103
+
104
104
  context = LightService::Context.make
105
+ context.current_action = action_class
106
+ context.fail!(:failure_reason)
107
+
108
+ expect(context).to be_failure
109
+ expect(context.message).to eq("message")
110
+ end
111
+
112
+ it "uses localization adapter to translate success message" do
113
+ action_class = TestDoubles::AnAction
114
+ expect(LightService::Configuration.localization_adapter).to receive(:success)
115
+ .with(:action_passed, action_class, {})
116
+ .and_return("message")
117
+
118
+ context = LightService::Context.make
119
+ context.current_action = action_class
120
+ context.succeed!(:action_passed)
121
+
122
+ expect(context).to be_success
123
+ expect(context.message).to eq("message")
124
+ end
125
+
126
+ it "can set a flag to skip all subsequent actions" do
105
127
  context.skip_all!
106
128
 
107
129
  expect(context).to be_skip_all
108
130
  end
109
131
 
110
132
  context "stopping additional processing in an action" do
111
- let(:context) { LightService::Context.make }
112
-
113
133
  it "flags processing to stop on failure" do
114
134
  context.fail!("on purpose")
115
135
  expect(context.stop_processing?).to be_truthy
@@ -121,4 +141,8 @@ describe LightService::Context do
121
141
  end
122
142
  end
123
143
 
144
+ it "can fail with FailWithRollBackError" do
145
+ expect { context.fail_with_rollback!("roll me back") }.to \
146
+ raise_error(LightService::FailWithRollbackError)
147
+ end
124
148
  end
@@ -0,0 +1,79 @@
1
+ require "spec_helper"
2
+ require 'test_doubles'
3
+
4
+ describe LightService::LocalizationAdapter do
5
+ let(:action_class) { TestDoubles::AnAction }
6
+ let(:adapter) { described_class.new }
7
+
8
+ describe "#failure" do
9
+ subject { adapter.failure(message_or_key, action_class) }
10
+
11
+ context "when provided a Symbol" do
12
+ let(:message_or_key) { :not_found }
13
+
14
+ it "translates the message" do
15
+ expected_scope = "test_doubles/an_action.light_service.failures"
16
+
17
+ expect(I18n).to receive(:t)
18
+ .with(message_or_key, :scope => expected_scope)
19
+ .and_return("message")
20
+
21
+ expect(subject).to eq("message")
22
+ end
23
+
24
+ it "allows passing interpolation options to I18n layer" do
25
+ expect(I18n).to receive(:t)
26
+ .with(message_or_key, hash_including(:i18n_variable => "value"))
27
+ .and_return("message")
28
+
29
+ subject = adapter.failure(message_or_key, action_class, :i18n_variable => "value")
30
+
31
+ expect(subject).to eq("message")
32
+ end
33
+ end
34
+
35
+ context "when provided a String" do
36
+ let(:message_or_key) { "action failed" }
37
+
38
+ it "returns the message" do
39
+ expect(subject).to eq(message_or_key)
40
+ end
41
+ end
42
+ end
43
+
44
+ describe "#success" do
45
+ subject { adapter.success(message_or_key, action_class) }
46
+
47
+ context "when provided a Symbol" do
48
+ let(:message_or_key) { :not_found }
49
+
50
+ it "translates the message" do
51
+ expected_scope = "test_doubles/an_action.light_service.successes"
52
+
53
+ expect(I18n).to receive(:t)
54
+ .with(message_or_key, :scope => expected_scope)
55
+ .and_return("message")
56
+
57
+ expect(subject).to eq("message")
58
+ end
59
+
60
+ it "allows passing interpolation options to I18n layer" do
61
+ expect(I18n).to receive(:t)
62
+ .with(message_or_key, hash_including(:i18n_variable => "value"))
63
+ .and_return("message")
64
+
65
+ subject = adapter.success(message_or_key, action_class, :i18n_variable => "value")
66
+
67
+ expect(subject).to eq("message")
68
+ end
69
+ end
70
+
71
+ context "when provided a String" do
72
+ let(:message_or_key) { "action failed" }
73
+
74
+ it "returns the message" do
75
+ expect(subject).to eq(message_or_key)
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,44 @@
1
+ require 'spec_helper'
2
+ require 'test_doubles'
3
+
4
+ describe LightService::Organizer::WithReducer do
5
+ let(:context) { LightService::Context.make }
6
+ let(:action1) { double(:action1) }
7
+ let(:action2) { double(:action2) }
8
+ let(:actions) { [action1, action2] }
9
+
10
+ before { context.current_action = action2 }
11
+
12
+ it "reduces the provided actions" do
13
+ expect(action1).to receive(:execute).with(context).and_return(context)
14
+ expect(action2).to receive(:execute).with(context).and_return(context)
15
+
16
+ result = described_class.new.with(context).reduce(actions)
17
+
18
+ expect(result).to eq(context)
19
+ expect(result).to be_success
20
+ end
21
+
22
+ context "when FailWithRollbackError is caught" do
23
+ it "reduces the rollback" do
24
+ expect(action1).to receive(:execute).with(context).and_return(context)
25
+ expect(action2).to receive(:execute).with(context) { raise LightService::FailWithRollbackError }
26
+ expect(action1).to receive(:rollback).with(context).and_return(context)
27
+ expect(action2).to receive(:rollback).with(context).and_return(context)
28
+
29
+ result = described_class.new.with(context).reduce(actions)
30
+
31
+ expect(result).to eq(context)
32
+ end
33
+
34
+ it "reduces the rollback with an action without `rollback`" do
35
+ expect(action1).to receive(:execute).with(context).and_return(context)
36
+ expect(action2).to receive(:execute).with(context) { raise LightService::FailWithRollbackError }
37
+ expect(action2).to receive(:rollback).with(context).and_return(context)
38
+
39
+ result = described_class.new.with(context).reduce(actions)
40
+
41
+ expect(result).to eq(context)
42
+ end
43
+ end
44
+ end
data/spec/spec_helper.rb CHANGED
@@ -4,3 +4,6 @@ $LOAD_PATH << File.join(File.dirname(__FILE__))
4
4
  require 'light-service'
5
5
  require 'ostruct'
6
6
  require 'rspec/its'
7
+ require 'active_support/core_ext/string'
8
+
9
+ I18n.enforce_available_locales = true
data/spec/test_doubles.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  # A collection of Action and Organizer dummies used in specs
2
2
 
3
3
  module TestDoubles
4
- class AddsTwoAction
4
+ class AddsTwoActionWithFetch
5
5
  include LightService::Action
6
6
 
7
7
  executed do |context|
@@ -63,7 +63,12 @@ module TestDoubles
63
63
 
64
64
  executed do |context|
65
65
  if context.milk == :very_hot
66
- context.fail!("Can't make a latte from a milk that's too hot!")
66
+ context.fail!("Can't make a latte from a milk that's very hot!")
67
+ next context
68
+ end
69
+
70
+ if context.milk == :super_hot
71
+ context.fail_with_rollback!("Can't make a latte from a milk that's super hot!")
67
72
  next context
68
73
  end
69
74
 
@@ -103,7 +108,7 @@ module TestDoubles
103
108
 
104
109
  def self.call(milk, coffee)
105
110
  with(:milk => milk, :coffee => coffee)
106
- .reduce(TestDoubles::AddsTwoAction,
111
+ .reduce(TestDoubles::AddsTwoActionWithFetch,
107
112
  TestDoubles::MakesLatteAction)
108
113
  end
109
114
  end
@@ -111,10 +116,10 @@ module TestDoubles
111
116
  class MakesCappuccinoAddsTwoAndFails
112
117
  include LightService::Organizer
113
118
 
114
- def self.call(coffee)
115
- with(:milk => :very_hot, :coffee => coffee)
119
+ def self.call(coffee, this_hot = :very_hot)
120
+ with(:milk => this_hot, :coffee => coffee)
116
121
  .reduce(TestDoubles::MakesLatteAction,
117
- TestDoubles::AddsTwoAction)
122
+ TestDoubles::AddsTwoActionWithFetch)
118
123
 
119
124
  end
120
125
  end
@@ -125,8 +130,50 @@ module TestDoubles
125
130
  def self.call(coffee)
126
131
  with(:milk => "5%", :coffee => coffee)
127
132
  .reduce(TestDoubles::MakesLatteAction,
128
- TestDoubles::AddsTwoAction)
133
+ TestDoubles::AddsTwoActionWithFetch)
134
+
135
+ end
136
+ end
129
137
 
138
+ class AdditionOrganizer
139
+ extend LightService::Organizer
140
+
141
+ def self.add_numbers(number)
142
+ with(:number => number).reduce(
143
+ AddsOneAction,
144
+ AddsTwoAction,
145
+ AddsThreeAction
146
+ )
147
+ end
148
+ end
149
+
150
+ class AddsOneAction
151
+ include LightService::Action
152
+ expects :number
153
+ promises :number
154
+
155
+ executed do |context|
156
+ context.number += 1
130
157
  end
131
158
  end
159
+
160
+ class AddsTwoAction
161
+ include LightService::Action
162
+ expects :number
163
+
164
+ executed do |context|
165
+ context.number += 2
166
+ end
167
+ end
168
+
169
+ class AddsThreeAction
170
+ include LightService::Action
171
+ expects :number
172
+ promises :product
173
+
174
+ executed do |context|
175
+ context.product = context.number + 3
176
+ end
177
+ end
178
+
132
179
  end
metadata CHANGED
@@ -1,55 +1,69 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: light-service
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.5.0
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-08-11 00:00:00.000000000 Z
11
+ date: 2014-10-31 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '4.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '4.0'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: rspec
15
29
  requirement: !ruby/object:Gem::Requirement
16
30
  requirements:
17
- - - ~>
31
+ - - "~>"
18
32
  - !ruby/object:Gem::Version
19
33
  version: '3.0'
20
34
  type: :development
21
35
  prerelease: false
22
36
  version_requirements: !ruby/object:Gem::Requirement
23
37
  requirements:
24
- - - ~>
38
+ - - "~>"
25
39
  - !ruby/object:Gem::Version
26
40
  version: '3.0'
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: rspec-its
29
43
  requirement: !ruby/object:Gem::Requirement
30
44
  requirements:
31
- - - ~>
45
+ - - "~>"
32
46
  - !ruby/object:Gem::Version
33
47
  version: '1.0'
34
48
  type: :development
35
49
  prerelease: false
36
50
  version_requirements: !ruby/object:Gem::Requirement
37
51
  requirements:
38
- - - ~>
52
+ - - "~>"
39
53
  - !ruby/object:Gem::Version
40
54
  version: '1.0'
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: simplecov
43
57
  requirement: !ruby/object:Gem::Requirement
44
58
  requirements:
45
- - - ~>
59
+ - - "~>"
46
60
  - !ruby/object:Gem::Version
47
61
  version: 0.7.1
48
62
  type: :development
49
63
  prerelease: false
50
64
  version_requirements: !ruby/object:Gem::Requirement
51
65
  requirements:
52
- - - ~>
66
+ - - "~>"
53
67
  - !ruby/object:Gem::Version
54
68
  version: 0.7.1
55
69
  - !ruby/object:Gem::Dependency
@@ -73,9 +87,9 @@ executables: []
73
87
  extensions: []
74
88
  extra_rdoc_files: []
75
89
  files:
76
- - .gitignore
77
- - .rspec
78
- - .travis.yml
90
+ - ".gitignore"
91
+ - ".rspec"
92
+ - ".travis.yml"
79
93
  - Gemfile
80
94
  - LICENSE
81
95
  - README.md
@@ -86,6 +100,8 @@ files:
86
100
  - lib/light-service/configuration.rb
87
101
  - lib/light-service/context.rb
88
102
  - lib/light-service/context_key_verifier.rb
103
+ - lib/light-service/errors.rb
104
+ - lib/light-service/localization_adapter.rb
89
105
  - lib/light-service/organizer.rb
90
106
  - lib/light-service/organizer/with_reducer.rb
91
107
  - lib/light-service/organizer/with_reducer_factory.rb
@@ -96,11 +112,15 @@ files:
96
112
  - resources/organizer_and_actions.png
97
113
  - spec/acceptance/add_numbers_spec.rb
98
114
  - spec/acceptance/log_from_organizer_spec.rb
115
+ - spec/acceptance/message_localization_spec.rb
116
+ - spec/acceptance/rollback_spec.rb
99
117
  - spec/action_expected_keys_spec.rb
100
118
  - spec/action_expects_and_promises_spec.rb
101
119
  - spec/action_promised_keys_spec.rb
102
120
  - spec/action_spec.rb
103
121
  - spec/context_spec.rb
122
+ - spec/localization_adapter_spec.rb
123
+ - spec/organizer/with_reducer_spec.rb
104
124
  - spec/organizer_spec.rb
105
125
  - spec/sample/calculates_order_tax_action_spec.rb
106
126
  - spec/sample/calculates_tax_spec.rb
@@ -122,28 +142,32 @@ require_paths:
122
142
  - lib
123
143
  required_ruby_version: !ruby/object:Gem::Requirement
124
144
  requirements:
125
- - - '>='
145
+ - - ">="
126
146
  - !ruby/object:Gem::Version
127
147
  version: '0'
128
148
  required_rubygems_version: !ruby/object:Gem::Requirement
129
149
  requirements:
130
- - - '>='
150
+ - - ">="
131
151
  - !ruby/object:Gem::Version
132
152
  version: '0'
133
153
  requirements: []
134
154
  rubyforge_project:
135
- rubygems_version: 2.0.14
155
+ rubygems_version: 2.2.2
136
156
  signing_key:
137
157
  specification_version: 4
138
158
  summary: A service skeleton with an emphasis on simplicity
139
159
  test_files:
140
160
  - spec/acceptance/add_numbers_spec.rb
141
161
  - spec/acceptance/log_from_organizer_spec.rb
162
+ - spec/acceptance/message_localization_spec.rb
163
+ - spec/acceptance/rollback_spec.rb
142
164
  - spec/action_expected_keys_spec.rb
143
165
  - spec/action_expects_and_promises_spec.rb
144
166
  - spec/action_promised_keys_spec.rb
145
167
  - spec/action_spec.rb
146
168
  - spec/context_spec.rb
169
+ - spec/localization_adapter_spec.rb
170
+ - spec/organizer/with_reducer_spec.rb
147
171
  - spec/organizer_spec.rb
148
172
  - spec/sample/calculates_order_tax_action_spec.rb
149
173
  - spec/sample/calculates_tax_spec.rb