simple-service 0.1.3 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -2
  3. data/.rubocop.yml +10 -2
  4. data/Gemfile +3 -1
  5. data/Makefile +7 -11
  6. data/README.md +67 -2
  7. data/TODO.txt +3 -0
  8. data/VERSION +1 -1
  9. data/doc/Simple/Service/Action/Comment/Extractor.html +347 -0
  10. data/doc/Simple/Service/Action/Comment.html +451 -0
  11. data/doc/Simple/Service/Action/MethodReflection.html +285 -0
  12. data/doc/Simple/Service/Action/Parameter.html +816 -0
  13. data/doc/Simple/Service/Action.html +923 -0
  14. data/doc/Simple/Service/ArgumentError.html +128 -0
  15. data/doc/Simple/Service/ClassMethods.html +187 -0
  16. data/doc/Simple/Service/Context.html +379 -0
  17. data/doc/Simple/Service/ContextMissingError.html +124 -0
  18. data/doc/Simple/Service/ContextReadOnlyError.html +206 -0
  19. data/doc/Simple/Service/ExtraArguments.html +428 -0
  20. data/doc/Simple/Service/GemHelper.html +190 -0
  21. data/doc/Simple/Service/MissingArguments.html +426 -0
  22. data/doc/Simple/Service/NoSuchAction.html +433 -0
  23. data/doc/Simple/Service.html +865 -0
  24. data/doc/Simple.html +117 -0
  25. data/doc/_index.html +274 -0
  26. data/doc/class_list.html +51 -0
  27. data/doc/css/common.css +1 -0
  28. data/doc/css/full_list.css +58 -0
  29. data/doc/css/style.css +496 -0
  30. data/doc/file.README.html +146 -0
  31. data/doc/file.TODO.html +70 -0
  32. data/doc/file_list.html +61 -0
  33. data/doc/frames.html +17 -0
  34. data/doc/index.html +146 -0
  35. data/doc/js/app.js +303 -0
  36. data/doc/js/full_list.js +216 -0
  37. data/doc/js/jquery.js +4 -0
  38. data/doc/method_list.html +483 -0
  39. data/doc/top-level-namespace.html +110 -0
  40. data/lib/simple/service/action/comment.rb +2 -2
  41. data/lib/simple/service/action/method_reflection.rb +1 -1
  42. data/lib/simple/service/action/parameter.rb +1 -1
  43. data/lib/simple/service/action.rb +34 -46
  44. data/lib/simple/service/errors.rb +4 -3
  45. data/lib/simple/service/version.rb +2 -2
  46. data/lib/simple/service.rb +109 -34
  47. data/lib/simple/workflow/context.rb +105 -0
  48. data/lib/simple/workflow/current_context.rb +33 -0
  49. data/lib/simple/workflow/reloader.rb +84 -0
  50. data/lib/simple/workflow/rspec_helper.rb +15 -0
  51. data/lib/simple/workflow.rb +96 -0
  52. data/lib/simple-workflow.rb +3 -0
  53. data/scripts/test +2 -0
  54. data/simple-service.gemspec +1 -0
  55. data/spec/simple/service/action_invoke3_spec.rb +258 -0
  56. data/spec/simple/service/action_invoke_spec.rb +49 -87
  57. data/spec/simple/service/service_spec.rb +40 -32
  58. data/spec/simple/workflow/context_spec.rb +90 -0
  59. data/spec/simple/workflow/current_context_spec.rb +41 -0
  60. data/spec/simple/workflow/reloader_spec/example1.rb +10 -0
  61. data/spec/simple/workflow/reloader_spec/example2.rb +7 -0
  62. data/spec/simple/workflow/reloader_spec.rb +48 -0
  63. data/spec/spec_helper.rb +2 -1
  64. data/spec/support/spec_services.rb +8 -2
  65. metadata +74 -9
  66. data/lib/simple/service/action/indie_hash.rb +0 -37
  67. data/lib/simple/service/context.rb +0 -94
  68. data/spec/simple/service/action_invoke2_spec.rb +0 -166
  69. data/spec/simple/service/context_spec.rb +0 -69
@@ -1,15 +1,11 @@
1
1
  require "spec_helper"
2
2
 
3
+ # rubocop:disable Style/WordArray
4
+
3
5
  describe "Simple::Service" do
4
6
  context "when running against a NoService module" do
5
7
  let(:service) { NoServiceModule }
6
8
 
7
- describe ".service?" do
8
- it "returns false on a NoService module" do
9
- expect(Simple::Service.service?(service)).to eq(false)
10
- end
11
- end
12
-
13
9
  describe ".actions" do
14
10
  it "raises an argument error" do
15
11
  expect { Simple::Service.actions(service) }.to raise_error(ArgumentError)
@@ -22,11 +18,9 @@ describe "Simple::Service" do
22
18
  end
23
19
  end
24
20
 
25
- describe ".invoke" do
21
+ describe ".invoke3" do
26
22
  it "raises an argument error" do
27
- ::Simple::Service.with_context do
28
- expect { Simple::Service.invoke(service, :service1, {}, {}, context: nil) }.to raise_error(::ArgumentError)
29
- end
23
+ expect { Simple::Service.invoke3(service, :service1, {}, {}, context: nil) }.to raise_error(::ArgumentError)
30
24
  end
31
25
  end
32
26
  end
@@ -34,12 +28,6 @@ describe "Simple::Service" do
34
28
  # running against a proper service module
35
29
  let(:service) { SpecService }
36
30
 
37
- describe ".service?" do
38
- it "returns true" do
39
- expect(Simple::Service.service?(service)).to eq(true)
40
- end
41
- end
42
-
43
31
  describe ".actions" do
44
32
  it "returns a Hash of actions on a Service module" do
45
33
  actions = Simple::Service.actions(service)
@@ -76,30 +64,50 @@ describe "Simple::Service" do
76
64
  end
77
65
  end
78
66
 
67
+ describe ".invoke3" do
68
+ def invoke3
69
+ Simple::Service.invoke3(service, :service1, "my_a", "my_b", d: "my_d")
70
+ end
71
+
72
+ it "calls Action#invoke with the right arguments" do
73
+ action = Simple::Service.actions(service)[:service1]
74
+ expect(action).to receive(:invoke).with(args: ["my_a", "my_b"], flags: { "d" => "my_d" })
75
+
76
+ invoke3
77
+ end
78
+ end
79
+
79
80
  describe ".invoke" do
80
- let(:positionals) { { a: "my_a", b: "my_b" } }
81
- let(:named) { { d: "my_d" } }
81
+ context "with a args array" do
82
+ def invoke
83
+ Simple::Service.invoke(service, :service1, args: ["my_a", "my_b"], flags: { "d" => "my_d" })
84
+ end
82
85
 
83
- context "when context is not set" do
84
- it "raises a ContextMissingError" do
86
+ it "calls Action#invoke with the right arguments" do
85
87
  action = Simple::Service.actions(service)[:service1]
86
- expect(action).not_to receive(:invoke)
88
+ expect(action).to receive(:invoke).with(args: ["my_a", "my_b"], flags: { "d" => "my_d" }).and_call_original
87
89
 
88
- expect do
89
- Simple::Service.invoke(service, :service1, *positionals, named_args: named)
90
- end.to raise_error(::Simple::Service::ContextMissingError)
90
+ invoke
91
91
  end
92
92
  end
93
+ end
93
94
 
94
- context "when context is not set" do
95
- it "properly delegates call to action object" do
96
- action = Simple::Service.actions(service)[:service1]
97
- expect(action).to receive(:invoke).with(*positionals, named_args: named)
95
+ describe "documentation example" do
96
+ def invoke(*args, **flags)
97
+ Simple::Service.invoke(SpecTestService, :foo, *args, **flags)
98
+ end
98
99
 
99
- ::Simple::Service.with_context do
100
- Simple::Service.invoke(service, :service1, *positionals, named_args: named)
101
- end
102
- end
100
+ def invoke3(*args, **flags)
101
+ Simple::Service.invoke3(SpecTestService, :foo, *args, **flags)
102
+ end
103
+
104
+ it "calls Action#invoke with the right arguments" do
105
+ expected = ["bar-value", "baz-value"]
106
+
107
+ expect(invoke3("bar-value", baz: "baz-value")).to eq(expected)
108
+ expect(invoke3(bar: "bar-value", baz: "baz-value")).to eq(expected)
109
+ expect(invoke(args: ["bar-value"], flags: { "baz" => "baz-value" })).to eq(expected)
110
+ expect(invoke(args: { "bar" => "bar-value", "baz" => "baz-value" })).to eq(expected)
103
111
  end
104
112
  end
105
113
  end
@@ -0,0 +1,90 @@
1
+ require "spec_helper"
2
+
3
+ describe Simple::Workflow::Context do
4
+ RSpec.shared_examples "context requesting" do
5
+ it "inherits from Simple::Immutable" do
6
+ expect(context).to be_a(Simple::Immutable)
7
+ end
8
+
9
+ describe "checking for identifier" do
10
+ it "raises an ArgumentError if the key is invalid" do
11
+ expect { context.oneTwoThree? }.to raise_error(ArgumentError)
12
+ end
13
+
14
+ it "returns nil if the key is not set" do
15
+ expect(context.two?).to be_nil
16
+ end
17
+
18
+ it "returns the value if the key is set" do
19
+ expect(context.one?).to eq 1
20
+ end
21
+ end
22
+
23
+ describe "fetching identifier" do
24
+ it "raises an ArgumentError if the identifier is invalid" do
25
+ expect { context.one! }.to raise_error(ArgumentError)
26
+ expect { context.oneTwoThree }.to raise_error(ArgumentError)
27
+ end
28
+
29
+ it "raises a NoMethodError if the key is not set" do
30
+ expect { context.two }.to raise_error(NameError)
31
+ end
32
+
33
+ it "returns the value if the key is set" do
34
+ expect(context.one).to eq 1
35
+ end
36
+ end
37
+
38
+ describe "#merge" do
39
+ context "with symbolized keys" do
40
+ it "sets a value if it does not exist yet" do
41
+ expect(context.two?).to eq(nil)
42
+ new_context = Simple::Workflow::Context.new({two: 2}, context)
43
+ expect(new_context.two).to eq(2)
44
+
45
+ # doesn't change the source context
46
+ expect(context.two?).to eq(nil)
47
+ end
48
+
49
+ it "sets a value if it does exist" do
50
+ new_context = Simple::Workflow::Context.new({one: 2}, context)
51
+ expect(new_context.one).to eq(2)
52
+
53
+ # doesn't change the source context
54
+ expect(context.one).to eq(1)
55
+ end
56
+ end
57
+
58
+ context "with stringified keys" do
59
+ it "sets a value if it does not exist yet" do
60
+ expect(context.two?).to eq(nil)
61
+ new_context = Simple::Workflow::Context.new({"two" => 2}, context)
62
+ expect(new_context.two).to eq(2)
63
+
64
+ # doesn't change the source context
65
+ expect(context.two?).to eq(nil)
66
+ end
67
+
68
+ it "sets a value if it does exist" do
69
+ new_context = Simple::Workflow::Context.new({"one" => 2}, context)
70
+ expect(new_context.one).to eq(2)
71
+
72
+ # doesn't change the source context
73
+ expect(context.one).to eq(1)
74
+ end
75
+ end
76
+ end
77
+ end
78
+
79
+ context "with a symbolized context" do
80
+ let(:context) { Simple::Workflow::Context.new(one: 1) }
81
+
82
+ it_behaves_like "context requesting"
83
+ end
84
+
85
+ context "with a stringified context" do
86
+ let(:context) { Simple::Workflow::Context.new("one" => 1) }
87
+
88
+ it_behaves_like "context requesting"
89
+ end
90
+ end
@@ -0,0 +1,41 @@
1
+ require "spec_helper"
2
+
3
+ describe Simple::Workflow::CurrentContext do
4
+ describe ".with_context" do
5
+ it "merges the current context for the duration of the block" do
6
+ block_called = false
7
+
8
+ Simple::Workflow.with_context(a: "a", foo: "bar") do
9
+ expect(Simple::Workflow.current_context.a).to eq("a")
10
+ expect(Simple::Workflow.current_context.foo).to eq("bar")
11
+
12
+ # layering
13
+ Simple::Workflow.with_context() do
14
+ expect(Simple::Workflow.current_context.foo).to eq("bar")
15
+
16
+ expect(Simple::Workflow.current_context.unknown?).to be_nil
17
+ expect {
18
+ Simple::Workflow.current_context.unknown
19
+ }.to raise_error(NameError)
20
+ end
21
+
22
+ # overwrite value
23
+ Simple::Workflow.with_context(a: "b") do
24
+ expect(Simple::Workflow.current_context.a).to eq("b")
25
+ block_called = true
26
+ end
27
+
28
+ # overwrite value w/nil
29
+ Simple::Workflow.with_context(a: nil) do
30
+ expect(Simple::Workflow.current_context.a).to be_nil
31
+ Simple::Workflow.with_context(a: "c") do
32
+ expect(Simple::Workflow.current_context.a).to eq("c")
33
+ end
34
+ end
35
+ expect(Simple::Workflow.current_context.a).to eq("a")
36
+ end
37
+
38
+ expect(block_called).to eq(true)
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,10 @@
1
+ module ReloaderSpecExample1
2
+ def foo; end
3
+ end
4
+
5
+ module ReloaderSpecExample2
6
+ end
7
+
8
+ module ReloaderSpecExample3
9
+ def foo; end
10
+ end
@@ -0,0 +1,7 @@
1
+ module ReloaderSpecExample1
2
+ def self.bar; end
3
+ end
4
+
5
+ module ReloaderSpecExample2
6
+ def self.bar; end
7
+ end
@@ -0,0 +1,48 @@
1
+ require "spec_helper"
2
+
3
+ require_relative "reloader_spec/example1"
4
+ require_relative "reloader_spec/example2"
5
+
6
+ describe "Simple::Service::Reloader" do
7
+ describe ".locate" do
8
+ def locate(mod)
9
+ Simple::Workflow::Reloader.locate(mod)
10
+ end
11
+
12
+ it "Returns all source files of a module" do
13
+ root = Dir.getwd
14
+
15
+ expected = [
16
+ "#{root}/lib/simple/workflow/reloader.rb"
17
+ ]
18
+ expect(locate(Simple::Workflow::Reloader)).to contain_exactly(*expected)
19
+
20
+ expected = [
21
+ "#{__dir__}/reloader_spec/example1.rb",
22
+ "#{__dir__}/reloader_spec/example2.rb"
23
+ ]
24
+ expect(locate(ReloaderSpecExample1)).to contain_exactly(*expected)
25
+
26
+ expected = [
27
+ "#{__dir__}/reloader_spec/example2.rb"
28
+ ]
29
+ expect(locate(ReloaderSpecExample2)).to contain_exactly(*expected)
30
+
31
+ expected = [
32
+ "#{__dir__}/reloader_spec/example1.rb"
33
+ ]
34
+ expect(locate(ReloaderSpecExample3)).to contain_exactly(*expected)
35
+ end
36
+ end
37
+
38
+ describe ".reload" do
39
+ def reload(mod)
40
+ Simple::Workflow::Reloader.reload(mod)
41
+ end
42
+
43
+ it "Reloads a module" do
44
+ # [TODO] this doesn't really check reloading...
45
+ reload Simple::Workflow::Reloader
46
+ end
47
+ end
48
+ end
data/spec/spec_helper.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  ENV["RACK_ENV"] = "test"
2
2
  ENV["RAILS_ENV"] = "test"
3
3
 
4
- require "byebug"
4
+ require "pry-byebug"
5
5
  require "rspec"
6
6
 
7
7
  require "simplecov"
@@ -18,6 +18,7 @@ SimpleCov.start do
18
18
  end
19
19
 
20
20
  require "simple/service"
21
+ require "simple/workflow"
21
22
 
22
23
  Dir.glob("./spec/support/**/*.rb").sort.each { |path| load path }
23
24
 
@@ -1,5 +1,3 @@
1
- # rubocop:disable Naming/UncommunicativeMethodParamName
2
-
3
1
  module NoServiceModule
4
2
  end
5
3
 
@@ -48,3 +46,11 @@ module InvokeTestService
48
46
  [a, b, args, e]
49
47
  end
50
48
  end
49
+
50
+ module SpecTestService
51
+ include Simple::Service
52
+
53
+ def foo(bar, baz:)
54
+ [bar, baz]
55
+ end
56
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: simple-service
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - radiospiel
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-11-29 00:00:00.000000000 Z
11
+ date: 2021-10-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: expectation
@@ -24,6 +24,26 @@ dependencies:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '1'
27
+ - !ruby/object:Gem::Dependency
28
+ name: simple-immutable
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1'
34
+ - - ">="
35
+ - !ruby/object:Gem::Version
36
+ version: '1.1'
37
+ type: :runtime
38
+ prerelease: false
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - "~>"
42
+ - !ruby/object:Gem::Version
43
+ version: '1'
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: '1.1'
27
47
  description: Pretty simple and somewhat abstract service description
28
48
  email: eno@radiospiel.org
29
49
  executables: []
@@ -37,33 +57,74 @@ files:
37
57
  - Makefile
38
58
  - README.md
39
59
  - Rakefile
60
+ - TODO.txt
40
61
  - VERSION
41
62
  - bin/bundle
42
63
  - bin/console
43
64
  - bin/rake
44
65
  - bin/rspec
66
+ - doc/Simple.html
67
+ - doc/Simple/Service.html
68
+ - doc/Simple/Service/Action.html
69
+ - doc/Simple/Service/Action/Comment.html
70
+ - doc/Simple/Service/Action/Comment/Extractor.html
71
+ - doc/Simple/Service/Action/MethodReflection.html
72
+ - doc/Simple/Service/Action/Parameter.html
73
+ - doc/Simple/Service/ArgumentError.html
74
+ - doc/Simple/Service/ClassMethods.html
75
+ - doc/Simple/Service/Context.html
76
+ - doc/Simple/Service/ContextMissingError.html
77
+ - doc/Simple/Service/ContextReadOnlyError.html
78
+ - doc/Simple/Service/ExtraArguments.html
79
+ - doc/Simple/Service/GemHelper.html
80
+ - doc/Simple/Service/MissingArguments.html
81
+ - doc/Simple/Service/NoSuchAction.html
82
+ - doc/_index.html
83
+ - doc/class_list.html
84
+ - doc/css/common.css
85
+ - doc/css/full_list.css
86
+ - doc/css/style.css
87
+ - doc/file.README.html
88
+ - doc/file.TODO.html
89
+ - doc/file_list.html
90
+ - doc/frames.html
91
+ - doc/index.html
92
+ - doc/js/app.js
93
+ - doc/js/full_list.js
94
+ - doc/js/jquery.js
95
+ - doc/method_list.html
96
+ - doc/top-level-namespace.html
45
97
  - lib/simple-service.rb
98
+ - lib/simple-workflow.rb
46
99
  - lib/simple/service.rb
47
100
  - lib/simple/service/action.rb
48
101
  - lib/simple/service/action/comment.rb
49
- - lib/simple/service/action/indie_hash.rb
50
102
  - lib/simple/service/action/method_reflection.rb
51
103
  - lib/simple/service/action/parameter.rb
52
- - lib/simple/service/context.rb
53
104
  - lib/simple/service/errors.rb
54
105
  - lib/simple/service/version.rb
106
+ - lib/simple/workflow.rb
107
+ - lib/simple/workflow/context.rb
108
+ - lib/simple/workflow/current_context.rb
109
+ - lib/simple/workflow/reloader.rb
110
+ - lib/simple/workflow/rspec_helper.rb
55
111
  - log/.gitkeep
56
112
  - scripts/release
57
113
  - scripts/release.rb
58
114
  - scripts/stats
115
+ - scripts/test
59
116
  - scripts/watch
60
117
  - simple-service.gemspec
61
- - spec/simple/service/action_invoke2_spec.rb
118
+ - spec/simple/service/action_invoke3_spec.rb
62
119
  - spec/simple/service/action_invoke_spec.rb
63
120
  - spec/simple/service/action_spec.rb
64
- - spec/simple/service/context_spec.rb
65
121
  - spec/simple/service/service_spec.rb
66
122
  - spec/simple/service/version_spec.rb
123
+ - spec/simple/workflow/context_spec.rb
124
+ - spec/simple/workflow/current_context_spec.rb
125
+ - spec/simple/workflow/reloader_spec.rb
126
+ - spec/simple/workflow/reloader_spec/example1.rb
127
+ - spec/simple/workflow/reloader_spec/example2.rb
67
128
  - spec/spec_helper.rb
68
129
  - spec/support/spec_services.rb
69
130
  homepage: http://github.com/radiospiel/simple-service
@@ -84,16 +145,20 @@ required_rubygems_version: !ruby/object:Gem::Requirement
84
145
  - !ruby/object:Gem::Version
85
146
  version: '0'
86
147
  requirements: []
87
- rubygems_version: 3.0.4
148
+ rubygems_version: 3.1.4
88
149
  signing_key:
89
150
  specification_version: 4
90
151
  summary: Pretty simple and somewhat abstract service description
91
152
  test_files:
92
- - spec/simple/service/action_invoke2_spec.rb
153
+ - spec/simple/service/action_invoke3_spec.rb
93
154
  - spec/simple/service/action_invoke_spec.rb
94
155
  - spec/simple/service/action_spec.rb
95
- - spec/simple/service/context_spec.rb
96
156
  - spec/simple/service/service_spec.rb
97
157
  - spec/simple/service/version_spec.rb
158
+ - spec/simple/workflow/context_spec.rb
159
+ - spec/simple/workflow/current_context_spec.rb
160
+ - spec/simple/workflow/reloader_spec.rb
161
+ - spec/simple/workflow/reloader_spec/example1.rb
162
+ - spec/simple/workflow/reloader_spec/example2.rb
98
163
  - spec/spec_helper.rb
99
164
  - spec/support/spec_services.rb
@@ -1,37 +0,0 @@
1
- class Simple::Service::Action
2
- # The IndieHash class defines as much of the Hash interface as necessary for simple-service
3
- # to successfully run.
4
- class IndieHash
5
- def initialize(hsh)
6
- @hsh = hsh.each_with_object({}) { |(k, v), h| h[k.to_s] = v }
7
- end
8
-
9
- def keys
10
- @hsh.keys
11
- end
12
-
13
- def fetch_values(*keys)
14
- keys = keys.map(&:to_s)
15
- @hsh.fetch_values(*keys)
16
- end
17
-
18
- def key?(sym)
19
- @hsh.key?(sym.to_s)
20
- end
21
-
22
- def [](sym)
23
- @hsh[sym.to_s]
24
- end
25
-
26
- def merge(other_hsh)
27
- @hsh = @hsh.merge(other_hsh.send(:__hsh__))
28
- self
29
- end
30
-
31
- private
32
-
33
- def __hsh__
34
- @hsh
35
- end
36
- end
37
- end
@@ -1,94 +0,0 @@
1
- module Simple::Service
2
- # Returns the current context.
3
- def self.context
4
- Thread.current[:"Simple::Service.context"]
5
- end
6
-
7
- # yields a block with a given context, and restores the previous context
8
- # object afterwards.
9
- def self.with_context(ctx = nil, &block)
10
- old_ctx = Thread.current[:"Simple::Service.context"]
11
- new_ctx = old_ctx ? old_ctx.merge(ctx) : Context.new(ctx)
12
-
13
- Thread.current[:"Simple::Service.context"] = new_ctx
14
-
15
- block.call
16
- ensure
17
- Thread.current[:"Simple::Service.context"] = old_ctx
18
- end
19
- end
20
-
21
- module Simple::Service
22
- # A context object
23
- #
24
- # Each service executes with a current context. The system manages a stack of
25
- # contexts; whenever a service execution is done the current context is reverted
26
- # to its previous value.
27
- #
28
- # A context object can store a large number of values; the only way to set or
29
- # access a value is via getters and setters. These are implemented via
30
- # +method_missing(..)+.
31
- #
32
- # Also, once a value is set in the context it is not possible to change or
33
- # unset it.
34
- class Context
35
- def initialize(hsh = {}) # :nodoc:
36
- @hsh = hsh
37
- end
38
-
39
- # returns a new Context object, which merges the values in the +overlay+
40
- # argument (which must be a Hash or nil) with the values in this context.
41
- #
42
- # The overlay is allowed to change values in the current context.
43
- #
44
- # It does not change this context.
45
- def merge(overlay)
46
- expect! overlay => [Hash, nil]
47
-
48
- overlay ||= {}
49
- new_context_hsh = @hsh.merge(overlay)
50
- ::Simple::Service::Context.new(new_context_hsh)
51
- end
52
-
53
- private
54
-
55
- IDENTIFIER_PATTERN = "[a-z][a-z0-9_]*" # :nodoc:
56
- IDENTIFIER_REGEXP = Regexp.compile("\\A#{IDENTIFIER_PATTERN}\\z") # :nodoc:
57
- ASSIGNMENT_REGEXP = Regexp.compile("\\A(#{IDENTIFIER_PATTERN})=\\z") # :nodoc:
58
-
59
- def method_missing(sym, *args, &block)
60
- raise ArgumentError, "Block given" if block
61
-
62
- if args.count == 0 && sym =~ IDENTIFIER_REGEXP
63
- self[sym]
64
- elsif args.count == 1 && sym =~ ASSIGNMENT_REGEXP
65
- self[$1.to_sym] = args.first
66
- else
67
- super
68
- end
69
- end
70
-
71
- def respond_to_missing?(sym, include_private = false)
72
- # :nocov:
73
- return true if IDENTIFIER_REGEXP.match?(sym)
74
- return true if ASSIGNMENT_REGEXP.match?(sym)
75
-
76
- super
77
- # :nocov:
78
- end
79
-
80
- def [](key)
81
- @hsh[key]
82
- end
83
-
84
- def []=(key, value)
85
- existing_value = @hsh[key]
86
-
87
- unless existing_value.nil? || existing_value == value
88
- raise ::Simple::Service::ContextReadOnlyError, key
89
- end
90
-
91
- @hsh[key] = value
92
- end
93
- end
94
- end