simple-service 0.1.1 → 0.1.6

Sign up to get free protection for your applications and to get access to all the features.
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