simple-service 0.1.4 → 0.1.5

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7921a94a0cb4244efa536f350ec568d21f9d5a5b09e141c459a7e0ad59eb4076
4
- data.tar.gz: 2c07601a1334a830bd2ff4b406563d73f816d9cbdc3ced6b788237d15cfce7ef
3
+ metadata.gz: 11f94dc8ace9fd802e2070599093e8032a83d68ae448b67cd8daddd9c3ff0d99
4
+ data.tar.gz: 71d8c154622760417f1afb7c036e1c185da50a072604e23a08b08cbb70631c2c
5
5
  SHA512:
6
- metadata.gz: 97c672710c6317d3eda455b1c1eda485ebc80aed55ce5e3ec6d1af3b08e372247cfdcfbb9e56aabab6e06456bd45f0a5b9b9945e5d980cf7e4886e59fceb735b
7
- data.tar.gz: e0733c90d2a99af1c4c88ad4053b4130f7d73fc8d4e2d80e632196ca19dfe4ec5d7480710f789595c6644089410116e392bc48eadba14261347f31e20b996024
6
+ metadata.gz: 8cce4acded3ec3adb8e58c2dab41a91f7b19b6dba24d3cae68f4954e18b55ab0eb798d7865a3689d64194baa7fc31e2fd40df8aa7e6abb2ecc35fc26dc762734
7
+ data.tar.gz: 90f763056b319c7cd45030a3f76ae18e672972ff40905408a930c84dbe1410ebdadc3cd710b04a388ad3309080db3be717b9bd3f08e6ea515301db3e77bb0d3d
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.4
1
+ 0.1.5
@@ -18,14 +18,14 @@ require_relative "service/version"
18
18
  #
19
19
  # module GodMode
20
20
  # include Simple::Service
21
- #
21
+ #
22
22
  # # Build a universe.
23
23
  # #
24
24
  # # This comment will become part of the full description of the
25
25
  # # "build_universe" service
26
26
  # def build_universe(name, c: , pi: 3.14, e: 2.781)
27
27
  # # at this point I realize that *I* am not God.
28
- #
28
+ #
29
29
  # 42 # Best try approach
30
30
  # end
31
31
  # end
@@ -36,10 +36,10 @@ require_relative "service/version"
36
36
  # Simple::Service.actions(GodMode)
37
37
  # => {:build_universe=>#<Simple::Service::Action...>, ...}
38
38
  #
39
- # 3. <em>Invoke a service:</em> run <tt>Simple::Service.invoke</tt> or <tt>Simple::Service.invoke2</tt>. You must set a context first.
39
+ # 3. <em>Invoke a service:</em> run <tt>Simple::Service.invoke3</tt> or <tt>Simple::Service.invoke</tt>. You must set a context first.
40
40
  #
41
41
  # Simple::Service.with_context do
42
- # Simple::Service.invoke(GodMode, :build_universe, "TestWorld", c: 1e9)
42
+ # Simple::Service.invoke3(GodMode, :build_universe, "TestWorld", c: 1e9)
43
43
  # end
44
44
  # => 42
45
45
  #
@@ -79,17 +79,52 @@ module Simple::Service
79
79
  end
80
80
  end
81
81
 
82
- # invokes an action with a given +name+ in a service with +arguments+ and +params+.
82
+ # invokes an action with a given +name+ in a service with +args+ and +flags+.
83
+ #
84
+ # This is a helper method which one can use to easily call an action from
85
+ # ruby source code.
86
+ #
87
+ # As the main purpose of this module is to call services with outside data,
88
+ # the +.invoke+ action is usually preferred.
89
+ #
90
+ # *Note:* You cannot call this method if the context is not set.
91
+ def self.invoke3(service, name, *args, **flags)
92
+ flags = flags.each_with_object({}) { |(k, v), hsh| hsh[k.to_s] = v }
93
+ invoke service, name, args: args, flags: flags
94
+ end
95
+
96
+ # invokes an action with a given +name+.
97
+ #
98
+ # This is the general form of invoking a service. It accepts the following
99
+ # arguments:
100
+ #
101
+ # - args: an Array of positional arguments OR a Hash of named arguments.
102
+ # - flags: a Hash of flags.
83
103
  #
84
- # When calling +invoke+ using positional arguments (i.e. non-keyword arguments)
85
- # they will be matched against positional arguments of the invoked method -
86
- # but they will not be matched against named arguments.
104
+ # Note that the keys in both the +flags+ and the +args+ Hash must be strings.
87
105
  #
88
- # In other words: if the service implements an action "def foo(bar, baz:)", one can
89
- # run it via
106
+ # The service is being called with a parameters built out of those like this:
90
107
  #
91
- # - +Service.invoke("bar-value", baz: "baz-value")+, or via
92
- # - +Service.invoke(bar: "bar-value", baz: "baz-value")+
108
+ # - The service's positional arguments are being built from the +args+ array
109
+ # parameter or from the +named_args+ hash parameter.
110
+ # - The service's keyword arguments are being built from the +named_args+
111
+ # and +flags+ arguments.
112
+ #
113
+ # In other words:
114
+ #
115
+ # 1. You cannot set both +args+ and +named_args+ at the same time.
116
+ # 2. The +flags+ arguments are only being used to determine the
117
+ # service's keyword parameters.
118
+ #
119
+ # So, if the service X implements an action "def foo(bar, baz:)", the following would
120
+ # all invoke that service:
121
+ #
122
+ # - +Service.invoke3(X, :foo, "bar-value", baz: "baz-value")+, or
123
+ # - +Service.invoke3(X, :foo, bar: "bar-value", baz: "baz-value")+, or
124
+ # - +Service.invoke(X, :foo, args: ["bar-value"], flags: { "baz" => "baz-value" })+, or
125
+ # - +Service.invoke(X, :foo, args: { "bar" => "bar-value", "baz" => "baz-value" })+.
126
+ #
127
+ # (see spec/service_spec.rb)
93
128
  #
94
129
  # When there are not enough positional arguments to match the number of required
95
130
  # positional arguments of the method we raise an ArgumentError.
@@ -98,21 +133,16 @@ module Simple::Service
98
133
  # by the method we raise an ArgumentError.
99
134
  #
100
135
  # Entries in the +named_args+ Hash that are not defined in the action itself are ignored.
101
- #
102
- # *Note:* You cannot call this method if the context is not set.
103
- def self.invoke(service, name, *args, **named_args)
104
- raise ContextMissingError, "Need to set context before calling ::Simple::Service.invoke" unless context
105
136
 
106
- action(service, name).invoke(*args, **named_args)
107
- end
137
+ # <b>Note:</b> You cannot call this method if the context is not set.
138
+ def self.invoke(service, name, args: {}, flags: {})
139
+ raise ContextMissingError, "Need to set context before calling ::Simple::Service.invoke3" unless context
108
140
 
109
- # invokes an action with a given +name+ in a service with a Hash of arguments.
110
- #
111
- # You cannot call this method if the context is not set.
112
- def self.invoke2(service, name, args: {}, flags: {})
113
- raise ContextMissingError, "Need to set context before calling ::Simple::Service.invoke" unless context
141
+ expect! args => [Hash, Array], flags: Hash
142
+ args.keys.each { |key| expect! key => String } if args.is_a?(Hash)
143
+ flags.keys.each { |key| expect! key => String }
114
144
 
115
- action(service, name).invoke2(args: args, flags: flags)
145
+ action(service, name).invoke(args: args, flags: flags)
116
146
  end
117
147
 
118
148
  module ClassMethods # @private
@@ -5,13 +5,11 @@ end
5
5
 
6
6
  require_relative "./action/comment"
7
7
  require_relative "./action/parameter"
8
- require_relative "./action/indie_hash"
9
8
 
10
9
  module Simple::Service
11
10
  # rubocop:disable Metrics/AbcSize
12
11
  # rubocop:disable Metrics/PerceivedComplexity
13
12
  # rubocop:disable Metrics/CyclomaticComplexity
14
- # rubocop:disable Style/GuardClause
15
13
  # rubocop:disable Metrics/ClassLength
16
14
 
17
15
  class Action
@@ -71,30 +69,11 @@ module Simple::Service
71
69
  @service.instance_method(name).source_location
72
70
  end
73
71
 
74
- # build a service_instance and run the action, with arguments constructed from
75
- # args_hsh and params_hsh.
76
- def invoke(*args, **named_args)
77
- # convert Array arguments into a Hash of named arguments. This is strictly
78
- # necessary to be able to apply default value-based type conversions. (On
79
- # the downside this also means we convert an array to a hash and then back
80
- # into an array. This, however, should only be an issue for CLI based action
81
- # invocations, because any other use case (that I can think of) should allow
82
- # us to provide arguments as a Hash.
83
- args = convert_argument_array_to_hash(args)
84
- named_args = named_args.merge(args)
85
-
86
- invoke2(args: named_args, flags: {})
87
- end
88
-
89
72
  # invokes an action with a given +name+ in a service with a Hash of arguments.
90
73
  #
91
74
  # You cannot call this method if the context is not set.
92
- def invoke2(args:, flags:)
93
- # args and flags are being stringified. This is necessary to not allow any
94
- # unchecked input to DOS this process by just providing always changing
95
- # key values.
96
- args = IndieHash.new(args)
97
- flags = IndieHash.new(flags)
75
+ def invoke(args:, flags:)
76
+ args = convert_argument_array_to_hash(args) if args.is_a?(Array)
98
77
 
99
78
  verify_required_args!(args, flags)
100
79
 
@@ -145,7 +124,7 @@ module Simple::Service
145
124
  end
146
125
 
147
126
  def positional_names
148
- @positional_names ||= parameters.select(&:positional?).map(&:name)
127
+ @positional_names ||= parameters.select(&:positional?).map(&:name).map(&:to_s)
149
128
  end
150
129
 
151
130
  # Enumerating all parameters it collects all positional parameters into
@@ -177,26 +156,34 @@ module Simple::Service
177
156
  def convert_argument_array_to_hash(ary)
178
157
  expect! ary => Array
179
158
 
180
- hsh = {}
181
-
182
- if variadic_parameter
183
- hsh[variadic_parameter.name] = []
184
- end
185
-
186
- if ary.length > positional_names.length
159
+ # +ary* might contain more, less, or the exact number of positional
160
+ # arguments. If the number is less, we return a hash with only whart
161
+ # exists in ary - the action might define default values after all.
162
+ #
163
+ # If it contains more the action better supports a variadic parameter;
164
+ # we otherwise raise a ExtraArguments exception.
165
+ case ary.length <=> positional_names.length
166
+ when 1 # i.e. ary.length > positional_names.length
187
167
  extra_arguments = ary[positional_names.length..-1]
168
+ ary = ary[0..positional_names.length]
188
169
 
189
- if variadic_parameter
190
- hsh[variadic_parameter.name] = extra_arguments
191
- else
170
+ if !extra_arguments.empty? && !variadic_parameter
192
171
  raise ::Simple::Service::ExtraArguments.new(self, extra_arguments)
193
172
  end
194
- end
195
173
 
196
- ary.zip(positional_names).each do |value, parameter_name|
197
- hsh[parameter_name] = value
174
+ existing_positional_names = positional_names
175
+ when 0 # i.e. ary.length == positional_names.length
176
+ existing_positional_names = positional_names
177
+ when -1 # i.e. ary.length < positional_names.length
178
+ existing_positional_names = positional_names[0, ary.length]
198
179
  end
199
180
 
181
+ # Build a hash with the existing_positional_names and the values from the array.
182
+ hsh = Hash[existing_positional_names.zip(ary)]
183
+
184
+ # Add the variadic_parameter, if any.
185
+ hsh[variadic_parameter.name] = extra_arguments if variadic_parameter
186
+
200
187
  hsh
201
188
  end
202
189
  end
@@ -36,7 +36,7 @@ class ::Simple::Service::Action::Parameter
36
36
  expect! default_value.length => [0, 1]
37
37
 
38
38
  @kind = kind
39
- @name = name
39
+ @name = name.to_s
40
40
  @default_value = default_value[0]
41
41
  end
42
42
  end
@@ -0,0 +1,266 @@
1
+ # rubocop:disable Style/WordArray
2
+
3
+ require "spec_helper"
4
+
5
+ describe "Simple::Service.invoke3" 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 invoke3!(*args, **keywords)
19
+ @actual = ::Simple::Service.invoke3(service, action, *args, **keywords)
20
+ # rescue ::StandardError => e
21
+ rescue ::Simple::Service::ArgumentError => e
22
+ @actual = e
23
+ end
24
+
25
+ attr_reader :actual
26
+
27
+ # when calling #invoke3 using positional arguments they will be matched against
28
+ # positional arguments of the invoke3d method - but they will not be matched
29
+ # against named arguments.
30
+ #
31
+ # When there are not enough positional arguments to match the number of required
32
+ # positional arguments of the method we raise an ArgumentError.
33
+ #
34
+ # When there are more positional arguments provided than the number accepted
35
+ # by the method we raise an ArgumentError.
36
+
37
+ context "calling an action w/o parameters" do
38
+ # reminder: this is the definition of no_params
39
+ #
40
+ # def no_params
41
+ # "service2 return"
42
+ # end
43
+
44
+ let(:action) { :no_params }
45
+
46
+ context "calling without args" do
47
+ it "runs the action" do
48
+ invoke3!
49
+ expect(actual).to eq("service2 return")
50
+ end
51
+ end
52
+
53
+ context "calling with extra positional args" do
54
+ it "raises ExtraArguments" do
55
+ invoke3!("foo", "bar")
56
+ expect(actual).to be_a(::Simple::Service::ExtraArguments)
57
+ expect(actual.to_s).to match(/"foo", "bar"/)
58
+ end
59
+ end
60
+
61
+ context "calling with extra named args" do
62
+ it "ignores extra args" do
63
+ invoke3!(foo: "foo", bar: "bar")
64
+ expect(actual).to eq("service2 return")
65
+ end
66
+ end
67
+
68
+ context "calling with an additional hash arg" do
69
+ xit "ignores extra args" do
70
+ args = []
71
+ args.push foo: "foo", bar: "bar"
72
+ invoke3!(*args)
73
+
74
+ expect(actual).to be_a(::Simple::Service::ExtraArguments)
75
+ end
76
+ end
77
+ end
78
+
79
+ context "calling an action w/positional parameters" do
80
+ # reminder: this is the definition of positional_params
81
+ #
82
+ # def positional_params(a, b, c = "speed-of-light", e = 2.781)
83
+ # [a, b, c, e]
84
+ # end
85
+
86
+ let(:action) { :positional_params }
87
+
88
+ context "without args" do
89
+ it "raises MissingArguments" do
90
+ invoke3!
91
+ expect(actual).to be_a(::Simple::Service::MissingArguments)
92
+ end
93
+ end
94
+
95
+ context "with the required number of args" do
96
+ it "runs" do
97
+ invoke3!("foo", "bar")
98
+ expect(actual).to eq(["foo", "bar", "speed-of-light", 2.781])
99
+ end
100
+ end
101
+
102
+ context "with the allowed number of args" do
103
+ it "runs" do
104
+ invoke3!("foo", "bar", "baz", "number4")
105
+ expect(actual).to eq(%w[foo bar baz number4])
106
+ end
107
+ end
108
+
109
+ context "with more than the allowed number of args" do
110
+ it "raises ExtraArguments" do
111
+ invoke3!("foo", "bar", "baz", "number4", "extra")
112
+ expect(actual).to be_a(::Simple::Service::ExtraArguments)
113
+ end
114
+ end
115
+
116
+ context "calling with extra named args" do
117
+ it "ignores extra args" do
118
+ invoke3!("foo", "bar", "baz", extra3: 3)
119
+ expect(actual).to eq(["foo", "bar", "baz", 2.781])
120
+ end
121
+ end
122
+
123
+ context "calling with an additional hash arg" do
124
+ xit "raises ExtraArguments" do
125
+ args = ["foo", "bar", "baz", extra3: 3]
126
+ invoke3!(*args)
127
+ expect(actual).to be_a(::Simple::Service::ExtraArguments)
128
+ end
129
+ end
130
+ end
131
+
132
+ context "calling an action w/named parameters" do
133
+ # reminder: this is the definition of named_params
134
+ #
135
+ # def named_params(a:, b:, c: "speed-of-light", e: 2.781)
136
+ # [a, b, c, e]
137
+ # end
138
+
139
+ let(:action) { :named_params }
140
+
141
+ context "without args" do
142
+ it "raises MissingArguments" do
143
+ invoke3!
144
+ expect(actual).to be_a(::Simple::Service::MissingArguments)
145
+ end
146
+ end
147
+
148
+ context "with the required number of args" do
149
+ it "runs" do
150
+ invoke3!(a: "foo", b: "bar")
151
+ expect(actual).to eq(["foo", "bar", "speed-of-light", 2.781])
152
+ end
153
+ end
154
+
155
+ context "with the allowed number of args" do
156
+ it "runs" do
157
+ invoke3!(a: "foo", b: "bar", c: "baz", e: "number4")
158
+ expect(actual).to eq(%w[foo bar baz number4])
159
+ end
160
+ end
161
+
162
+ context "with more than the allowed number of args" do
163
+ it "runs" do
164
+ invoke3!("foo", "bar", "baz", "number4", "extra")
165
+ expect(actual).to be_a(::Simple::Service::ExtraArguments)
166
+ end
167
+ end
168
+
169
+ context "with extra named args" do
170
+ it "ignores extra args" do
171
+ invoke3!(a: "foo", b: "bar", c: "baz", extra3: 3)
172
+ expect(actual).to eq(["foo", "bar", "baz", 2.781])
173
+ end
174
+ end
175
+ end
176
+
177
+ context "calling an action w/mixed and optional parameters" do
178
+ # reminder: this is the definition of named_params
179
+ #
180
+ # def mixed_optional_params(a, b = "default-b", c = "speed-of-light", e: 2.781)
181
+ # [a, b, c, e]
182
+ # end
183
+
184
+ let(:action) { :mixed_optional_params }
185
+
186
+ context "without args" do
187
+ it "raises MissingArguments" do
188
+ invoke3!
189
+ expect(actual).to be_a(::Simple::Service::MissingArguments)
190
+ end
191
+ end
192
+
193
+ context "with the required number of args" do
194
+ it "runs" do
195
+ invoke3!("foo")
196
+ expect(actual).to eq(["foo", "default-b", "speed-of-light", 2.781])
197
+ end
198
+ end
199
+
200
+ context "with the allowed number of args" do
201
+ it "runs" do
202
+ invoke3!("foo", "bar", "baz", e: "number4")
203
+ expect(actual).to eq(%w[foo bar baz number4])
204
+ end
205
+ end
206
+
207
+ context "with more than the allowed number of args" do
208
+ it "runs" do
209
+ invoke3!("foo", "bar", "baz", "extra", e: "number4")
210
+ expect(actual).to be_a(::Simple::Service::ExtraArguments)
211
+ end
212
+ end
213
+
214
+ context "with extra named args" do
215
+ it "ignores extra args" do
216
+ invoke3!("foo", "bar", "baz", e: "number4", extra3: 3)
217
+ expect(actual).to eq(["foo", "bar", "baz", "number4"])
218
+ end
219
+ end
220
+ end
221
+
222
+ context "calling an action w/mixed and variadic parameters" do
223
+ # reminder: this is the definition of variadic_params
224
+ #
225
+ # def variadic_params(a, b = "queen bee", *args, e: 2.781)
226
+ # [a, b, args, e]
227
+ # end
228
+
229
+ let(:action) { :variadic_params }
230
+
231
+ context "without args" do
232
+ it "raises MissingArguments" do
233
+ invoke3!
234
+ expect(actual).to be_a(::Simple::Service::MissingArguments)
235
+ end
236
+ end
237
+
238
+ context "with the required number of args" do
239
+ it "runs" do
240
+ invoke3!("foo")
241
+ expect(actual).to eq(["foo", "queen bee", [], 2.781])
242
+ end
243
+ end
244
+
245
+ context "with the allowed number of args" do
246
+ it "runs" do
247
+ invoke3!("foo", "bar", "baz", e: "number4")
248
+ expect(actual).to eq(["foo", "bar", ["baz"], "number4"])
249
+ end
250
+ end
251
+
252
+ context "with more than the allowed number of args" do
253
+ it "runs" do
254
+ invoke3!("foo", "bar", "baz", "extra", e: "number4")
255
+ expect(actual).to eq(["foo", "bar", ["baz", "extra"], "number4"])
256
+ end
257
+ end
258
+
259
+ context "with extra named args" do
260
+ it "ignores extra args" do
261
+ invoke3!("foo", "bar", "baz", e: "number4", extra3: 3)
262
+ expect(actual).to eq(["foo", "bar", ["baz"], "number4"])
263
+ end
264
+ end
265
+ end
266
+ end
@@ -15,8 +15,8 @@ describe "Simple::Service.invoke" do
15
15
  let(:action) { nil }
16
16
 
17
17
  # a shortcut
18
- def invoke!(*args, **keywords)
19
- @actual = ::Simple::Service.invoke(service, action, *args, **keywords)
18
+ def invoke!(args = {}, flags: {})
19
+ @actual = ::Simple::Service.invoke(service, action, args: args, flags: flags)
20
20
  # rescue ::StandardError => e
21
21
  rescue ::Simple::Service::ArgumentError => e
22
22
  @actual = e
@@ -24,16 +24,6 @@ describe "Simple::Service.invoke" do
24
24
 
25
25
  attr_reader :actual
26
26
 
27
- # when calling #invoke using positional arguments they will be matched against
28
- # positional arguments of the invoked method - but they will not be matched
29
- # against named arguments.
30
- #
31
- # When there are not enough positional arguments to match the number of required
32
- # positional arguments of the method we raise an ArgumentError.
33
- #
34
- # When there are more positional arguments provided than the number accepted
35
- # by the method we raise an ArgumentError.
36
-
37
27
  context "calling an action w/o parameters" do
38
28
  # reminder: this is the definition of no_params
39
29
  #
@@ -50,30 +40,12 @@ describe "Simple::Service.invoke" do
50
40
  end
51
41
  end
52
42
 
53
- context "calling with extra positional args" do
54
- it "raises ExtraArguments" do
55
- invoke!("foo", "bar")
56
- expect(actual).to be_a(::Simple::Service::ExtraArguments)
57
- expect(actual.to_s).to match(/"foo", "bar"/)
58
- end
59
- end
60
-
61
43
  context "calling with extra named args" do
62
44
  it "ignores extra args" do
63
- invoke!(foo: "foo", bar: "bar")
45
+ invoke!("foo" => "foo", "bar" => "bar")
64
46
  expect(actual).to eq("service2 return")
65
47
  end
66
48
  end
67
-
68
- context "calling with an additional hash arg" do
69
- xit "ignores extra args" do
70
- args = []
71
- args.push foo: "foo", bar: "bar"
72
- invoke!(*args)
73
-
74
- expect(actual).to be_a(::Simple::Service::ExtraArguments)
75
- end
76
- end
77
49
  end
78
50
 
79
51
  context "calling an action w/positional parameters" do
@@ -89,42 +61,28 @@ describe "Simple::Service.invoke" do
89
61
  it "raises MissingArguments" do
90
62
  invoke!
91
63
  expect(actual).to be_a(::Simple::Service::MissingArguments)
64
+ expect(actual.to_s).to match(/\ba, b\b/)
92
65
  end
93
66
  end
94
67
 
95
68
  context "with the required number of args" do
96
69
  it "runs" do
97
- invoke!("foo", "bar")
70
+ invoke!("a" => "foo", "b" => "bar")
98
71
  expect(actual).to eq(["foo", "bar", "speed-of-light", 2.781])
99
72
  end
100
73
  end
101
74
 
102
75
  context "with the allowed number of args" do
103
76
  it "runs" do
104
- invoke!("foo", "bar", "baz", "number4")
77
+ invoke!("a" => "foo", "b" => "bar", "c" => "baz", "e" => "number4")
105
78
  expect(actual).to eq(%w[foo bar baz number4])
106
79
  end
107
80
  end
108
81
 
109
- context "with more than the allowed number of args" do
110
- it "raises ExtraArguments" do
111
- invoke!("foo", "bar", "baz", "number4", "extra")
112
- expect(actual).to be_a(::Simple::Service::ExtraArguments)
113
- end
114
- end
115
-
116
82
  context "calling with extra named args" do
117
83
  it "ignores extra args" do
118
- invoke!("foo", "bar", "baz", extra3: 3)
119
- expect(actual).to eq(["foo", "bar", "baz", 2.781])
120
- end
121
- end
122
-
123
- context "calling with an additional hash arg" do
124
- xit "raises ExtraArguments" do
125
- args = ["foo", "bar", "baz", extra3: 3]
126
- invoke!(*args)
127
- expect(actual).to be_a(::Simple::Service::ExtraArguments)
84
+ invoke!("a" => "foo", "b" => "bar", "c" => "baz", "e" => "number4", "extra3" => 3)
85
+ expect(actual).to eq(%w[foo bar baz number4])
128
86
  end
129
87
  end
130
88
  end
@@ -132,7 +90,7 @@ describe "Simple::Service.invoke" do
132
90
  context "calling an action w/named parameters" do
133
91
  # reminder: this is the definition of named_params
134
92
  #
135
- # def named_params(a:, b:, c: "speed-of-light", e: 2.781)
93
+ # def named_params(a:, b:, "c" => "speed-of-light", e: 2.781)
136
94
  # [a, b, c, e]
137
95
  # end
138
96
 
@@ -142,33 +100,27 @@ describe "Simple::Service.invoke" do
142
100
  it "raises MissingArguments" do
143
101
  invoke!
144
102
  expect(actual).to be_a(::Simple::Service::MissingArguments)
103
+ expect(actual.to_s).to match(/\ba, b\b/)
145
104
  end
146
105
  end
147
106
 
148
107
  context "with the required number of args" do
149
108
  it "runs" do
150
- invoke!(a: "foo", b: "bar")
109
+ invoke!("a" => "foo", "b" => "bar")
151
110
  expect(actual).to eq(["foo", "bar", "speed-of-light", 2.781])
152
111
  end
153
112
  end
154
113
 
155
114
  context "with the allowed number of args" do
156
115
  it "runs" do
157
- invoke!(a: "foo", b: "bar", c: "baz", e: "number4")
116
+ invoke!("a" => "foo", "b" => "bar", "c" => "baz", "e" => "number4")
158
117
  expect(actual).to eq(%w[foo bar baz number4])
159
118
  end
160
119
  end
161
120
 
162
- context "with more than the allowed number of args" do
163
- it "runs" do
164
- invoke!("foo", "bar", "baz", "number4", "extra")
165
- expect(actual).to be_a(::Simple::Service::ExtraArguments)
166
- end
167
- end
168
-
169
121
  context "with extra named args" do
170
122
  it "ignores extra args" do
171
- invoke!(a: "foo", b: "bar", c: "baz", extra3: 3)
123
+ invoke!("a" => "foo", "b" => "bar", "c" => "baz", "extra3" => 3)
172
124
  expect(actual).to eq(["foo", "bar", "baz", 2.781])
173
125
  end
174
126
  end
@@ -192,75 +144,23 @@ describe "Simple::Service.invoke" do
192
144
 
193
145
  context "with the required number of args" do
194
146
  it "runs" do
195
- invoke!("foo")
147
+ invoke!("a" => "foo")
196
148
  expect(actual).to eq(["foo", "default-b", "speed-of-light", 2.781])
197
149
  end
198
150
  end
199
151
 
200
152
  context "with the allowed number of args" do
201
153
  it "runs" do
202
- invoke!("foo", "bar", "baz", e: "number4")
154
+ invoke!("a" => "foo", "b" => "bar", "c" => "baz", "e" => "number4")
203
155
  expect(actual).to eq(%w[foo bar baz number4])
204
156
  end
205
157
  end
206
158
 
207
- context "with more than the allowed number of args" do
208
- it "runs" do
209
- invoke!("foo", "bar", "baz", "extra", e: "number4")
210
- expect(actual).to be_a(::Simple::Service::ExtraArguments)
211
- end
212
- end
213
-
214
159
  context "with extra named args" do
215
160
  it "ignores extra args" do
216
- invoke!("foo", "bar", "baz", e: "number4", extra3: 3)
161
+ invoke!("a" => "foo", "b" => "bar", "c" => "baz", "e" => "number4", "extra3" => 3)
217
162
  expect(actual).to eq(["foo", "bar", "baz", "number4"])
218
163
  end
219
164
  end
220
165
  end
221
-
222
- context "calling an action w/mixed and variadic parameters" do
223
- # reminder: this is the definition of variadic_params
224
- #
225
- # def variadic_params(a, b = "queen bee", *args, e: 2.781)
226
- # [a, b, args, e]
227
- # end
228
-
229
- let(:action) { :variadic_params }
230
-
231
- context "without args" do
232
- it "raises MissingArguments" do
233
- invoke!
234
- expect(actual).to be_a(::Simple::Service::MissingArguments)
235
- end
236
- end
237
-
238
- context "with the required number of args" do
239
- it "runs" do
240
- invoke!("foo")
241
- expect(actual).to eq(["foo", "queen bee", [], 2.781])
242
- end
243
- end
244
-
245
- context "with the allowed number of args" do
246
- it "runs" do
247
- invoke!("foo", "bar", "baz", e: "number4")
248
- expect(actual).to eq(["foo", "bar", ["baz"], "number4"])
249
- end
250
- end
251
-
252
- context "with more than the allowed number of args" do
253
- it "runs" do
254
- invoke!("foo", "bar", "baz", "extra", e: "number4")
255
- expect(actual).to eq(["foo", "bar", ["baz", "extra"], "number4"])
256
- end
257
- end
258
-
259
- context "with extra named args" do
260
- it "ignores extra args" do
261
- invoke!("foo", "bar", "baz", e: "number4", extra3: 3)
262
- expect(actual).to eq(["foo", "bar", ["baz"], "number4"])
263
- end
264
- end
265
- end
266
166
  end
@@ -22,10 +22,10 @@ describe "Simple::Service" do
22
22
  end
23
23
  end
24
24
 
25
- describe ".invoke" do
25
+ describe ".invoke3" do
26
26
  it "raises an argument error" do
27
27
  ::Simple::Service.with_context do
28
- expect { Simple::Service.invoke(service, :service1, {}, {}, context: nil) }.to raise_error(::ArgumentError)
28
+ expect { Simple::Service.invoke3(service, :service1, {}, {}, context: nil) }.to raise_error(::ArgumentError)
29
29
  end
30
30
  end
31
31
  end
@@ -76,9 +76,10 @@ describe "Simple::Service" do
76
76
  end
77
77
  end
78
78
 
79
- describe ".invoke" do
80
- let(:positionals) { { a: "my_a", b: "my_b" } }
81
- let(:named) { { d: "my_d" } }
79
+ describe '.invoke3' do
80
+ def invoke3
81
+ Simple::Service.invoke3(service, :service1, "my_a", "my_b", d: "my_d")
82
+ end
82
83
 
83
84
  context "when context is not set" do
84
85
  it "raises a ContextMissingError" do
@@ -86,20 +87,70 @@ describe "Simple::Service" do
86
87
  expect(action).not_to receive(:invoke)
87
88
 
88
89
  expect do
89
- Simple::Service.invoke(service, :service1, *positionals, named_args: named)
90
+ invoke3
90
91
  end.to raise_error(::Simple::Service::ContextMissingError)
91
92
  end
92
93
  end
93
94
 
94
- context "when context is not set" do
95
- it "properly delegates call to action object" do
95
+ context "when context is set" do
96
+ it "calls Action#invoke with the right arguments" do
96
97
  action = Simple::Service.actions(service)[:service1]
97
- expect(action).to receive(:invoke).with(*positionals, named_args: named)
98
+ expect(action).to receive(:invoke).with(args: ["my_a", "my_b"], flags: { "d" => "my_d" })
98
99
 
99
100
  ::Simple::Service.with_context do
100
- Simple::Service.invoke(service, :service1, *positionals, named_args: named)
101
+ invoke3
102
+ end
103
+ end
104
+ end
105
+ end
106
+
107
+ describe ".invoke" do
108
+ context "with a args array" do
109
+ def invoke
110
+ Simple::Service.invoke(service, :service1, args: ["my_a", "my_b"], flags: { "d" => "my_d" })
111
+ end
112
+
113
+ context "when context is not set" do
114
+ it "raises a ContextMissingError" do
115
+ action = Simple::Service.actions(service)[:service1]
116
+ expect(action).not_to receive(:invoke)
117
+
118
+ expect do
119
+ invoke
120
+ end.to raise_error(::Simple::Service::ContextMissingError)
101
121
  end
102
122
  end
123
+
124
+ context "when context is set" do
125
+ it "calls Action#invoke with the right arguments" do
126
+ action = Simple::Service.actions(service)[:service1]
127
+ expect(action).to receive(:invoke).with(args: ["my_a", "my_b"], flags: { "d" => "my_d" }).and_call_original
128
+
129
+ ::Simple::Service.with_context do
130
+ invoke
131
+ end
132
+ end
133
+ end
134
+ end
135
+ end
136
+
137
+ describe "documentation example" do
138
+ def invoke(*args, **flags)
139
+ Simple::Service.invoke(SpecTestService, :foo, *args, **flags)
140
+ end
141
+
142
+ def invoke3(*args, **flags)
143
+ Simple::Service.invoke3(SpecTestService, :foo, *args, **flags)
144
+ end
145
+
146
+ it "calls Action#invoke with the right arguments" do
147
+ expected = ["bar-value", "baz-value"]
148
+ ::Simple::Service.with_context do
149
+ expect(invoke3("bar-value", baz: "baz-value")).to eq(expected)
150
+ expect(invoke3(bar: "bar-value", baz: "baz-value")).to eq(expected)
151
+ expect(invoke(args: ["bar-value"], flags: { "baz" => "baz-value" })).to eq(expected)
152
+ expect(invoke(args: { "bar" => "bar-value", "baz" => "baz-value" })).to eq(expected)
153
+ end
103
154
  end
104
155
  end
105
156
  end
@@ -48,3 +48,11 @@ module InvokeTestService
48
48
  [a, b, args, e]
49
49
  end
50
50
  end
51
+
52
+ module SpecTestService
53
+ include Simple::Service
54
+
55
+ def foo(bar, baz:)
56
+ [ bar, baz ]
57
+ end
58
+ 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.4
4
+ version: 0.1.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - radiospiel
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-12-03 00:00:00.000000000 Z
11
+ date: 2019-12-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: expectation
@@ -77,7 +77,6 @@ files:
77
77
  - lib/simple/service.rb
78
78
  - lib/simple/service/action.rb
79
79
  - lib/simple/service/action/comment.rb
80
- - lib/simple/service/action/indie_hash.rb
81
80
  - lib/simple/service/action/method_reflection.rb
82
81
  - lib/simple/service/action/parameter.rb
83
82
  - lib/simple/service/context.rb
@@ -89,7 +88,7 @@ files:
89
88
  - scripts/stats
90
89
  - scripts/watch
91
90
  - simple-service.gemspec
92
- - spec/simple/service/action_invoke2_spec.rb
91
+ - spec/simple/service/action_invoke3_spec.rb
93
92
  - spec/simple/service/action_invoke_spec.rb
94
93
  - spec/simple/service/action_spec.rb
95
94
  - spec/simple/service/context_spec.rb
@@ -120,7 +119,7 @@ signing_key:
120
119
  specification_version: 4
121
120
  summary: Pretty simple and somewhat abstract service description
122
121
  test_files:
123
- - spec/simple/service/action_invoke2_spec.rb
122
+ - spec/simple/service/action_invoke3_spec.rb
124
123
  - spec/simple/service/action_invoke_spec.rb
125
124
  - spec/simple/service/action_spec.rb
126
125
  - spec/simple/service/context_spec.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,166 +0,0 @@
1
- # rubocop:disable Style/WordArray
2
-
3
- require "spec_helper"
4
-
5
- describe "Simple::Service.invoke2" 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 invoke2!(**hsh)
19
- @actual = ::Simple::Service.invoke2(service, action, args: hsh)
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
- invoke2!
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
- invoke2!(foo: "foo", bar: "bar")
46
- expect(actual).to eq("service2 return")
47
- end
48
- end
49
- end
50
-
51
- context "calling an action w/positional parameters" do
52
- # reminder: this is the definition of positional_params
53
- #
54
- # def positional_params(a, b, c = "speed-of-light", e = 2.781)
55
- # [a, b, c, e]
56
- # end
57
-
58
- let(:action) { :positional_params }
59
-
60
- context "without args" do
61
- it "raises MissingArguments" do
62
- invoke2!
63
- expect(actual).to be_a(::Simple::Service::MissingArguments)
64
- expect(actual.to_s).to match(/\ba, b\b/)
65
- end
66
- end
67
-
68
- context "with the required number of args" do
69
- it "runs" do
70
- invoke2!(a: "foo", b: "bar")
71
- expect(actual).to eq(["foo", "bar", "speed-of-light", 2.781])
72
- end
73
- end
74
-
75
- context "with the allowed number of args" do
76
- it "runs" do
77
- invoke2!(a: "foo", b: "bar", c: "baz", e: "number4")
78
- expect(actual).to eq(%w[foo bar baz number4])
79
- end
80
- end
81
-
82
- context "calling with extra named args" do
83
- it "ignores extra args" do
84
- invoke2!(a: "foo", b: "bar", c: "baz", e: "number4", extra3: 3)
85
- expect(actual).to eq(%w[foo bar baz number4])
86
- end
87
- end
88
- end
89
-
90
- context "calling an action w/named parameters" do
91
- # reminder: this is the definition of named_params
92
- #
93
- # def named_params(a:, b:, c: "speed-of-light", e: 2.781)
94
- # [a, b, c, e]
95
- # end
96
-
97
- let(:action) { :named_params }
98
-
99
- context "without args" do
100
- it "raises MissingArguments" do
101
- invoke2!
102
- expect(actual).to be_a(::Simple::Service::MissingArguments)
103
- expect(actual.to_s).to match(/\ba, b\b/)
104
- end
105
- end
106
-
107
- context "with the required number of args" do
108
- it "runs" do
109
- invoke2!(a: "foo", b: "bar")
110
- expect(actual).to eq(["foo", "bar", "speed-of-light", 2.781])
111
- end
112
- end
113
-
114
- context "with the allowed number of args" do
115
- it "runs" do
116
- invoke2!(a: "foo", b: "bar", c: "baz", e: "number4")
117
- expect(actual).to eq(%w[foo bar baz number4])
118
- end
119
- end
120
-
121
- context "with extra named args" do
122
- it "ignores extra args" do
123
- invoke2!(a: "foo", b: "bar", c: "baz", extra3: 3)
124
- expect(actual).to eq(["foo", "bar", "baz", 2.781])
125
- end
126
- end
127
- end
128
-
129
- context "calling an action w/mixed and optional parameters" do
130
- # reminder: this is the definition of named_params
131
- #
132
- # def mixed_optional_params(a, b = "default-b", c = "speed-of-light", e: 2.781)
133
- # [a, b, c, e]
134
- # end
135
-
136
- let(:action) { :mixed_optional_params }
137
-
138
- context "without args" do
139
- it "raises MissingArguments" do
140
- invoke2!
141
- expect(actual).to be_a(::Simple::Service::MissingArguments)
142
- end
143
- end
144
-
145
- context "with the required number of args" do
146
- it "runs" do
147
- invoke2!(a: "foo")
148
- expect(actual).to eq(["foo", "default-b", "speed-of-light", 2.781])
149
- end
150
- end
151
-
152
- context "with the allowed number of args" do
153
- it "runs" do
154
- invoke2!(a: "foo", b: "bar", c: "baz", e: "number4")
155
- expect(actual).to eq(%w[foo bar baz number4])
156
- end
157
- end
158
-
159
- context "with extra named args" do
160
- it "ignores extra args" do
161
- invoke2!(a: "foo", b: "bar", c: "baz", e: "number4", extra3: 3)
162
- expect(actual).to eq(["foo", "bar", "baz", "number4"])
163
- end
164
- end
165
- end
166
- end