simple-service 0.1.1 → 0.1.6

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 (59) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -2
  3. data/.rubocop.yml +7 -0
  4. data/.tm_properties +1 -1
  5. data/Makefile +8 -0
  6. data/README.md +68 -1
  7. data/TODO.txt +3 -0
  8. data/VERSION +1 -1
  9. data/doc/Simple.html +117 -0
  10. data/doc/Simple/Service.html +865 -0
  11. data/doc/Simple/Service/Action.html +923 -0
  12. data/doc/Simple/Service/Action/Comment.html +451 -0
  13. data/doc/Simple/Service/Action/Comment/Extractor.html +347 -0
  14. data/doc/Simple/Service/Action/MethodReflection.html +285 -0
  15. data/doc/Simple/Service/Action/Parameter.html +816 -0
  16. data/doc/Simple/Service/ArgumentError.html +128 -0
  17. data/doc/Simple/Service/ClassMethods.html +187 -0
  18. data/doc/Simple/Service/Context.html +379 -0
  19. data/doc/Simple/Service/ContextMissingError.html +124 -0
  20. data/doc/Simple/Service/ContextReadOnlyError.html +206 -0
  21. data/doc/Simple/Service/ExtraArguments.html +428 -0
  22. data/doc/Simple/Service/GemHelper.html +190 -0
  23. data/doc/Simple/Service/MissingArguments.html +426 -0
  24. data/doc/Simple/Service/NoSuchAction.html +433 -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.rb +161 -56
  41. data/lib/simple/service/action.rb +104 -107
  42. data/lib/simple/service/action/comment.rb +3 -1
  43. data/lib/simple/service/action/method_reflection.rb +3 -3
  44. data/lib/simple/service/action/parameter.rb +3 -7
  45. data/lib/simple/service/context.rb +69 -27
  46. data/lib/simple/service/errors.rb +54 -0
  47. data/lib/simple/service/version.rb +7 -2
  48. data/scripts/stats +2 -1
  49. data/spec/simple/service/action_invoke3_spec.rb +266 -0
  50. data/spec/simple/service/action_invoke_spec.rb +237 -0
  51. data/spec/simple/service/action_spec.rb +51 -0
  52. data/spec/simple/service/context_spec.rb +39 -7
  53. data/spec/simple/service/service_spec.rb +158 -0
  54. data/spec/simple/service/version_spec.rb +7 -0
  55. data/spec/spec_helper.rb +15 -2
  56. data/spec/support/spec_services.rb +58 -0
  57. metadata +48 -6
  58. data/lib/simple.rb +0 -2
  59. data/spec/support/004_simplecov.rb +0 -13
@@ -0,0 +1,237 @@
1
+ # rubocop:disable Style/WordArray
2
+
3
+ require "spec_helper"
4
+
5
+ describe "Simple::Service.invoke" do
6
+ # the context to use in the around hook below. By default this is nil -
7
+ # which gives us an empty context.
8
+ let(:context) { nil }
9
+
10
+ around do |example|
11
+ ::Simple::Service.with_context(context) { example.run }
12
+ end
13
+
14
+ let(:service) { InvokeTestService }
15
+ let(:action) { nil }
16
+
17
+ # a shortcut
18
+ def invoke!(args: {}, flags: {})
19
+ @actual = ::Simple::Service.invoke(service, action, args: args, flags: flags)
20
+ # rescue ::StandardError => e
21
+ rescue ::Simple::Service::ArgumentError => e
22
+ @actual = e
23
+ end
24
+
25
+ attr_reader :actual
26
+
27
+ context "calling an action w/o parameters" do
28
+ # reminder: this is the definition of no_params
29
+ #
30
+ # def no_params
31
+ # "service2 return"
32
+ # end
33
+
34
+ let(:action) { :no_params }
35
+
36
+ context "calling without args" do
37
+ it "runs the action" do
38
+ invoke!
39
+ expect(actual).to eq("service2 return")
40
+ end
41
+ end
42
+
43
+ context "calling with extra named args" do
44
+ it "ignores extra args" do
45
+ invoke!(args: { "foo" => "foo", "bar" => "bar" })
46
+ expect(actual).to eq("service2 return")
47
+ end
48
+ end
49
+
50
+ context "calling with extra flags" do
51
+ it "ignores extra args" do
52
+ invoke!(flags: { "foo" => "foo", "bar" => "bar" })
53
+ expect(actual).to eq("service2 return")
54
+ end
55
+ end
56
+ end
57
+
58
+ context "calling an action w/positional parameters" do
59
+ # reminder: this is the definition of positional_params
60
+ #
61
+ # def positional_params(a, b, c = "speed-of-light", e = 2.781)
62
+ # [a, b, c, e]
63
+ # end
64
+
65
+ let(:action) { :positional_params }
66
+
67
+ context "without args" do
68
+ it "raises MissingArguments" do
69
+ invoke!
70
+ expect(actual).to be_a(::Simple::Service::MissingArguments)
71
+ expect(actual.to_s).to match(/\ba, b\b/)
72
+ end
73
+ end
74
+
75
+ context "with the required number of args" do
76
+ it "runs" do
77
+ invoke!(args: { "a" => "foo", "b" => "bar" })
78
+ expect(actual).to eq(["foo", "bar", "speed-of-light", 2.781])
79
+ end
80
+ end
81
+
82
+ context "with the required number of args and flags" do
83
+ it "merges flags and args to provide arguments" do
84
+ invoke!(args: { "a" => "foo" }, flags: { "b" => "bar" })
85
+ expect(actual).to eq(["foo", "bar", "speed-of-light", 2.781])
86
+ end
87
+ end
88
+
89
+ context "with the allowed number of args" do
90
+ it "runs" do
91
+ invoke!(args: { "a" => "foo", "b" => "bar", "c" => "baz", "e" => "number4" })
92
+ expect(actual).to eq(%w[foo bar baz number4])
93
+ end
94
+ end
95
+
96
+ context "calling with extra named args" do
97
+ it "ignores extra args" do
98
+ invoke!(args: { "a" => "foo", "b" => "bar", "c" => "baz", "e" => "number4", "extra3" => 3 })
99
+ expect(actual).to eq(%w[foo bar baz number4])
100
+ end
101
+ end
102
+ end
103
+
104
+ context "calling an action w/named parameters" do
105
+ # reminder: this is the definition of named_params
106
+ #
107
+ # def named_params(a:, b:, "c" => "speed-of-light", e: 2.781)
108
+ # [a, b, c, e]
109
+ # end
110
+
111
+ let(:action) { :named_params }
112
+
113
+ context "without args" do
114
+ it "raises MissingArguments" do
115
+ invoke!
116
+ expect(actual).to be_a(::Simple::Service::MissingArguments)
117
+ expect(actual.to_s).to match(/\ba, b\b/)
118
+ end
119
+ end
120
+
121
+ context "with the required number of args" do
122
+ it "runs" do
123
+ invoke!(args: { "a" => "foo", "b" => "bar" })
124
+ expect(actual).to eq(["foo", "bar", "speed-of-light", 2.781])
125
+ end
126
+ end
127
+
128
+ context "with the allowed number of args" do
129
+ it "runs" do
130
+ invoke!(args: { "a" => "foo", "b" => "bar", "c" => "baz", "e" => "number4" })
131
+ expect(actual).to eq(%w[foo bar baz number4])
132
+ end
133
+ end
134
+
135
+ context "with extra named args" do
136
+ it "ignores extra args" do
137
+ invoke!(args: { "a" => "foo", "b" => "bar", "c" => "baz", "extra3" => 3 })
138
+ expect(actual).to eq(["foo", "bar", "baz", 2.781])
139
+ end
140
+ end
141
+ end
142
+
143
+ context "calling an action w/mixed and optional parameters" do
144
+ # reminder: this is the definition of named_params
145
+ #
146
+ # def mixed_optional_params(a, b = "default-b", c = "speed-of-light", e: 2.781)
147
+ # [a, b, c, e]
148
+ # end
149
+
150
+ let(:action) { :mixed_optional_params }
151
+
152
+ context "without args" do
153
+ it "raises MissingArguments" do
154
+ invoke!
155
+ expect(actual).to be_a(::Simple::Service::MissingArguments)
156
+ end
157
+ end
158
+
159
+ context "with the required number of args" do
160
+ it "runs" do
161
+ invoke!(args: { "a" => "foo" })
162
+ expect(actual).to eq(["foo", "default-b", "speed-of-light", 2.781])
163
+ end
164
+ end
165
+
166
+ context "with the allowed number of args" do
167
+ it "runs" do
168
+ invoke!(args: { "a" => "foo", "b" => "bar", "c" => "baz", "e" => "number4" })
169
+ expect(actual).to eq(%w[foo bar baz number4])
170
+ end
171
+ end
172
+
173
+ context "with extra named args" do
174
+ it "ignores extra args" do
175
+ invoke!(args: { "a" => "foo", "b" => "bar", "c" => "baz", "e" => "number4", "extra3" => 3 })
176
+ expect(actual).to eq(["foo", "bar", "baz", "number4"])
177
+ end
178
+ end
179
+ end
180
+
181
+ context "calling an action w/mixed and variadic parameters" do
182
+ # reminder: this is the definition of variadic_params
183
+ #
184
+ # def variadic_params(a, b = "queen bee", *args, e: 2.781)
185
+ # [a, b, args, e]
186
+ # end
187
+
188
+ let(:action) { :variadic_params }
189
+
190
+ context "without args" do
191
+ it "raises MissingArguments" do
192
+ invoke!
193
+ expect(actual).to be_a(::Simple::Service::MissingArguments)
194
+ end
195
+ end
196
+
197
+ context "with the required number of args" do
198
+ it "runs" do
199
+ invoke!(args: { "a" => "foo" })
200
+ expect(actual).to eq(["foo", "queen bee", [], 2.781])
201
+ end
202
+ end
203
+
204
+ context "with the allowed number of args" do
205
+ it "runs" do
206
+ invoke!(args: { "a" => "foo", "b" => "bar", "args" => ["baz"] }, flags: { "e" => "number4" })
207
+ expect(actual).to eq(["foo", "bar", ["baz"], "number4"])
208
+ end
209
+ end
210
+
211
+ context "with variadic args" do
212
+ it "sends the variadic args from the args: parameter" do
213
+ invoke!(args: { "a" => "foo", "b" => "bar", "args" => ["baz", "extra"] }, flags: { "e" => "number4", "extra3" => 2 })
214
+ expect(actual).to eq(["foo", "bar", ["baz", "extra"], "number4"])
215
+ end
216
+
217
+ it "sends the variadic args from the flags: parameter" do
218
+ invoke!(args: { "a" => "foo", "b" => "bar" }, flags: { "args" => ["baz", "extra"], "e" => "number4", "extra3" => 2 })
219
+ expect(actual).to eq(["foo", "bar", ["baz", "extra"], "number4"])
220
+ end
221
+ end
222
+ end
223
+
224
+ describe "calling with symbolized Hashes" do
225
+ it "raises ArgumentError" do
226
+ hsh = { a: "foo", "b" => "KJH" }
227
+
228
+ expect do
229
+ invoke!(args: hsh)
230
+ end.to raise_error(Expectation::Matcher::Mismatch)
231
+
232
+ expect do
233
+ invoke!(flags: hsh)
234
+ end.to raise_error(Expectation::Matcher::Mismatch)
235
+ end
236
+ end
237
+ end
@@ -0,0 +1,51 @@
1
+ require "spec_helper"
2
+
3
+ describe Simple::Service::Action do
4
+ let(:service) { SpecService }
5
+
6
+ let(:service1) { ::Simple::Service.action(service, :service1) }
7
+ let(:service2) { ::Simple::Service.action(service, :service2) }
8
+ let(:service3) { ::Simple::Service.action(service, :service3) }
9
+
10
+ describe "attributes" do
11
+ describe "#service" do
12
+ it "returns the service module" do
13
+ expect(service1.service).to eq(service)
14
+ end
15
+ end
16
+
17
+ describe "#name" do
18
+ it "returns the action name" do
19
+ expect(service1.name).to eq(:service1)
20
+ end
21
+ end
22
+
23
+ describe "full_name" do
24
+ it "returns the full_name" do
25
+ expect(service1.full_name).to eq("SpecService#service1")
26
+ end
27
+ end
28
+
29
+ describe "to_s" do
30
+ it "returns the full_name" do
31
+ expect(service1.to_s).to eq("SpecService#service1")
32
+ end
33
+ end
34
+
35
+ describe "#short_description" do
36
+ it "returns the short_description as per source code" do
37
+ expect(service1.short_description).to eq("This is service1")
38
+ expect(service2.short_description).to eq("This is service2 (no full description)")
39
+ expect(service3.short_description).to eq(nil)
40
+ end
41
+ end
42
+
43
+ describe "#full_description" do
44
+ it "returns the full_description as per source code" do
45
+ expect(service1.full_description).to eq("Service 1 has a full description")
46
+ expect(service2.full_description).to eq(nil)
47
+ expect(service3.full_description).to eq(nil)
48
+ end
49
+ end
50
+ end
51
+ end
@@ -1,13 +1,47 @@
1
1
  require "spec_helper"
2
2
 
3
+ describe Simple::Service 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::Service.with_context(a: "a") do
9
+ expect(Simple::Service.context.a).to eq("a")
10
+
11
+ # overwrite value
12
+ Simple::Service.with_context(a: "b") do
13
+ expect(Simple::Service.context.a).to eq("b")
14
+ block_called = true
15
+ end
16
+
17
+ # overwrite value w/nil
18
+ Simple::Service.with_context(a: nil) do
19
+ expect(Simple::Service.context.a).to be_nil
20
+ Simple::Service.context.a = "c"
21
+ expect(Simple::Service.context.a).to eq("c")
22
+ end
23
+ expect(Simple::Service.context.a).to eq("a")
24
+ end
25
+
26
+ expect(block_called).to eq(true)
27
+ end
28
+ end
29
+ end
30
+
3
31
  describe Simple::Service::Context do
4
32
  let(:context) { Simple::Service::Context.new }
5
-
33
+
6
34
  before do
7
35
  context.one = 1
8
36
  end
9
37
 
10
- describe "reading" do
38
+ describe "invalid identifier" do
39
+ it "raises an error" do
40
+ expect { context.one! }.to raise_error(NoMethodError)
41
+ end
42
+ end
43
+
44
+ describe "context reading" do
11
45
  it "returns a value if set" do
12
46
  expect(context.one).to eq(1)
13
47
  end
@@ -17,16 +51,14 @@ describe Simple::Service::Context do
17
51
  end
18
52
  end
19
53
 
20
- describe "writing" do
54
+ describe "context writing" do
21
55
  it "sets a value if it does not exist yet" do
22
- context.two = 2
56
+ context.two = 2
23
57
  expect(context.two).to eq(2)
24
58
  end
25
59
 
26
60
  it "raises a ReadOnly error if the value exists and is not equal" do
27
- expect {
28
- context.one = 2
29
- }.to raise_error(::Simple::Service::Context::ReadOnlyError)
61
+ expect { context.one = 2 }.to raise_error(::Simple::Service::ContextReadOnlyError)
30
62
  end
31
63
 
32
64
  it "sets the value if it exists and is equal" do
@@ -0,0 +1,158 @@
1
+ require "spec_helper"
2
+
3
+ # rubocop:disable Style/WordArray
4
+
5
+ describe "Simple::Service" do
6
+ context "when running against a NoService module" do
7
+ let(:service) { NoServiceModule }
8
+
9
+ describe ".service?" do
10
+ it "returns false on a NoService module" do
11
+ expect(Simple::Service.service?(service)).to eq(false)
12
+ end
13
+ end
14
+
15
+ describe ".actions" do
16
+ it "raises an argument error" do
17
+ expect { Simple::Service.actions(service) }.to raise_error(ArgumentError)
18
+ end
19
+ end
20
+
21
+ describe ".action" do
22
+ it "raises an argument error" do
23
+ expect { Simple::Service.action(service, :service1) }.to raise_error(ArgumentError)
24
+ end
25
+ end
26
+
27
+ describe ".invoke3" do
28
+ it "raises an argument error" do
29
+ ::Simple::Service.with_context do
30
+ expect { Simple::Service.invoke3(service, :service1, {}, {}, context: nil) }.to raise_error(::ArgumentError)
31
+ end
32
+ end
33
+ end
34
+ end
35
+
36
+ # running against a proper service module
37
+ let(:service) { SpecService }
38
+
39
+ describe ".service?" do
40
+ it "returns true" do
41
+ expect(Simple::Service.service?(service)).to eq(true)
42
+ end
43
+ end
44
+
45
+ describe ".actions" do
46
+ it "returns a Hash of actions on a Service module" do
47
+ actions = Simple::Service.actions(service)
48
+ expect(actions).to be_a(Hash)
49
+ expect(actions.keys).to contain_exactly(:service1, :service2, :service3)
50
+ end
51
+ end
52
+
53
+ describe ".action" do
54
+ context "with an existing name" do
55
+ it "returns a Action object" do
56
+ action = Simple::Service.action(service, :service1)
57
+ expect(action.service).to eq(service)
58
+ expect(action.name).to eq(:service1)
59
+ end
60
+ end
61
+
62
+ describe "Simple::Service::NoSuchAction" do
63
+ it "does not inherit from Simple::Service::ArgumentError" do
64
+ expect(Simple::Service::NoSuchAction < Simple::Service::ArgumentError).to be_falsey
65
+ end
66
+
67
+ it "inherits from ArgumentError" do
68
+ expect(Simple::Service::NoSuchAction < ::ArgumentError).to eq true
69
+ end
70
+ end
71
+
72
+ context "with an unknown name" do
73
+ it "raises a NoSuchAction error" do
74
+ expect do
75
+ Simple::Service.action(service, :no_such_service)
76
+ end.to raise_error(Simple::Service::NoSuchAction, /No such action :no_such_service/)
77
+ end
78
+ end
79
+ end
80
+
81
+ describe ".invoke3" do
82
+ def invoke3
83
+ Simple::Service.invoke3(service, :service1, "my_a", "my_b", d: "my_d")
84
+ end
85
+
86
+ context "when context is not set" do
87
+ it "raises a ContextMissingError" do
88
+ action = Simple::Service.actions(service)[:service1]
89
+ expect(action).not_to receive(:invoke)
90
+
91
+ expect do
92
+ invoke3
93
+ end.to raise_error(::Simple::Service::ContextMissingError)
94
+ end
95
+ end
96
+
97
+ context "when context is set" do
98
+ it "calls Action#invoke with the right arguments" do
99
+ action = Simple::Service.actions(service)[:service1]
100
+ expect(action).to receive(:invoke).with(args: ["my_a", "my_b"], flags: { "d" => "my_d" })
101
+
102
+ ::Simple::Service.with_context do
103
+ invoke3
104
+ end
105
+ end
106
+ end
107
+ end
108
+
109
+ describe ".invoke" do
110
+ context "with a args array" do
111
+ def invoke
112
+ Simple::Service.invoke(service, :service1, args: ["my_a", "my_b"], flags: { "d" => "my_d" })
113
+ end
114
+
115
+ context "when context is not set" do
116
+ it "raises a ContextMissingError" do
117
+ action = Simple::Service.actions(service)[:service1]
118
+ expect(action).not_to receive(:invoke)
119
+
120
+ expect do
121
+ invoke
122
+ end.to raise_error(::Simple::Service::ContextMissingError)
123
+ end
124
+ end
125
+
126
+ context "when context is set" do
127
+ it "calls Action#invoke with the right arguments" do
128
+ action = Simple::Service.actions(service)[:service1]
129
+ expect(action).to receive(:invoke).with(args: ["my_a", "my_b"], flags: { "d" => "my_d" }).and_call_original
130
+
131
+ ::Simple::Service.with_context do
132
+ invoke
133
+ end
134
+ end
135
+ end
136
+ end
137
+ end
138
+
139
+ describe "documentation example" do
140
+ def invoke(*args, **flags)
141
+ Simple::Service.invoke(SpecTestService, :foo, *args, **flags)
142
+ end
143
+
144
+ def invoke3(*args, **flags)
145
+ Simple::Service.invoke3(SpecTestService, :foo, *args, **flags)
146
+ end
147
+
148
+ it "calls Action#invoke with the right arguments" do
149
+ expected = ["bar-value", "baz-value"]
150
+ ::Simple::Service.with_context do
151
+ expect(invoke3("bar-value", baz: "baz-value")).to eq(expected)
152
+ expect(invoke3(bar: "bar-value", baz: "baz-value")).to eq(expected)
153
+ expect(invoke(args: ["bar-value"], flags: { "baz" => "baz-value" })).to eq(expected)
154
+ expect(invoke(args: { "bar" => "bar-value", "baz" => "baz-value" })).to eq(expected)
155
+ end
156
+ end
157
+ end
158
+ end