simple-service 0.1.4 → 0.1.5

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