simple-service 0.1.3

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.
@@ -0,0 +1,54 @@
1
+ module Simple::Service
2
+ # Will be raised by ::Simple::Service.action.
3
+ class NoSuchAction < ::ArgumentError
4
+ attr_reader :service, :name
5
+ def initialize(service, name)
6
+ @service, @name = service, name
7
+ end
8
+
9
+ def to_s
10
+ action_names = ::Simple::Service.actions(service).keys.sort
11
+ informal = "service #{service} has these actions: #{action_names.map(&:inspect).join(", ")}"
12
+ "No such action #{name.inspect}; #{informal}"
13
+ end
14
+ end
15
+
16
+ class ArgumentError < ::ArgumentError
17
+ end
18
+
19
+ class MissingArguments < ArgumentError
20
+ attr_reader :action
21
+ attr_reader :parameters
22
+
23
+ def initialize(action, parameters)
24
+ @action, @parameters = action, parameters
25
+ end
26
+
27
+ def to_s
28
+ "#{action}: missing argument(s): #{parameters.map(&:to_s).join(", ")}"
29
+ end
30
+ end
31
+
32
+ class ExtraArguments < ArgumentError
33
+ attr_reader :action
34
+ attr_reader :arguments
35
+
36
+ def initialize(action, arguments)
37
+ @action, @arguments = action, arguments
38
+ end
39
+
40
+ def to_s
41
+ str = @arguments.map(&:inspect).join(", ")
42
+ "#{action}: extra argument(s) #{str}"
43
+ end
44
+ end
45
+
46
+ class ContextMissingError < ::StandardError
47
+ end
48
+
49
+ class ContextReadOnlyError < ::StandardError
50
+ def initialize(key)
51
+ super "Cannot overwrite existing context setting #{key.inspect}"
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,29 @@
1
+ module Simple # :nodoc:
2
+ end
3
+
4
+ module Simple::Service
5
+ module GemHelper # :nodoc:
6
+ extend self
7
+
8
+ def version(name)
9
+ spec = Gem.loaded_specs[name]
10
+ version = spec ? spec.version.to_s : "0.0.0"
11
+ version += "+unreleased" if !spec || unreleased?(spec)
12
+ version
13
+ end
14
+
15
+ private
16
+
17
+ def unreleased?(spec)
18
+ return false unless defined?(Bundler::Source::Gemspec)
19
+ return true if spec.source.is_a?(::Bundler::Source::Gemspec)
20
+ # :nocov:
21
+ return true if spec.source.is_a?(::Bundler::Source::Path)
22
+
23
+ false
24
+ # :nocov:
25
+ end
26
+ end
27
+
28
+ VERSION = GemHelper.version "simple-service"
29
+ end
File without changes
@@ -0,0 +1,2 @@
1
+ #!/bin/bash
2
+ $0.rb "$@"
@@ -0,0 +1,91 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # -- helpers ------------------------------------------------------------------
4
+
5
+ def sys(cmd)
6
+ STDERR.puts "> #{cmd}"
7
+ system cmd
8
+ return true if $?.success?
9
+
10
+ STDERR.puts "> #{cmd} returned with exitstatus #{$?.exitstatus}"
11
+ $?.success?
12
+ end
13
+
14
+ def sys!(cmd, error: nil)
15
+ return true if sys(cmd)
16
+ STDERR.puts error if error
17
+ exit 1
18
+ end
19
+
20
+ def die!(msg)
21
+ STDERR.puts msg
22
+ exit 1
23
+ end
24
+
25
+ ROOT = File.expand_path("#{File.dirname(__FILE__)}/..")
26
+
27
+ GEMSPEC = Dir.glob("*.gemspec").first || die!("Missing gemspec file.")
28
+
29
+ # -- Version reading and bumping ----------------------------------------------
30
+
31
+ module Version
32
+ extend self
33
+
34
+ VERSION_FILE = "#{Dir.getwd}/VERSION"
35
+
36
+ def read_version
37
+ version = File.exist?(VERSION_FILE) ? File.read(VERSION_FILE) : "0.0.1"
38
+ version.chomp!
39
+ raise "Invalid version number in #{VERSION_FILE}" unless version =~ /^\d+\.\d+\.\d+$/
40
+ version
41
+ end
42
+
43
+ def auto_version_bump
44
+ old_version_number = read_version
45
+ old = old_version_number.split('.')
46
+
47
+ current = old[0..-2] << old[-1].next
48
+ current.join('.')
49
+ end
50
+
51
+ def bump_version
52
+ next_version = ENV["VERSION"] || auto_version_bump
53
+ File.open(VERSION_FILE, "w") { |io| io.write next_version }
54
+ end
55
+ end
56
+
57
+ # -- check, bump, release a new gem version -----------------------------------
58
+
59
+ Dir.chdir ROOT
60
+ $BASE_BRANCH = ENV['BRANCH'] || 'master'
61
+
62
+ # ENV["BUNDLE_GEMFILE"] = "#{Dir.getwd}/Gemfile"
63
+ # sys! "bundle install"
64
+
65
+ sys! "git diff --exit-code > /dev/null", error: 'There are unstaged changes in your working directory'
66
+ sys! "git diff --cached --exit-code > /dev/null", error: 'There are staged but uncommitted changes'
67
+
68
+ sys! "git checkout #{$BASE_BRANCH}"
69
+ sys! "git pull"
70
+
71
+ Version.bump_version
72
+ version = Version.read_version
73
+
74
+ sys! "git add VERSION"
75
+ sys! "git commit -m \"bump gem to v#{version}\""
76
+ sys! "git tag -a v#{version} -m \"Tag #{version}\""
77
+
78
+ sys! "gem build #{GEMSPEC}"
79
+
80
+ sys! "git push origin #{$BASE_BRANCH}"
81
+ sys! 'git push --tags --force'
82
+ sys! "gem push #{Dir.glob('*.gem').first}"
83
+
84
+ sys! "mkdir -p pkg"
85
+ sys! "mv *.gem pkg"
86
+
87
+ STDERR.puts <<-MSG
88
+ ================================================================================
89
+ Thank you for releasing a new gem version. You made my day.
90
+ ================================================================================
91
+ MSG
@@ -0,0 +1,5 @@
1
+ #!/bin/bash
2
+
3
+ # cloc $(find lib/ -name *rb) | grep -E 'Language|Ruby' | sed 's-Language- -'
4
+ cloc --by-file --docstring-as-code --quiet --hide-rate $(find lib/ -name *rb)
5
+ printf "\n"
@@ -0,0 +1,2 @@
1
+ #!/bin/bash
2
+ watchr lib,spec rspec $@
@@ -0,0 +1,25 @@
1
+ # lib = File.expand_path('../lib', __FILE__)
2
+ # $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.name = "simple-service"
6
+ gem.version = File.read("VERSION")
7
+
8
+ gem.authors = [ "radiospiel" ]
9
+ gem.email = "eno@radiospiel.org"
10
+ gem.homepage = "http://github.com/radiospiel/simple-service"
11
+ gem.summary = "Pretty simple and somewhat abstract service description"
12
+
13
+ gem.description = "Pretty simple and somewhat abstract service description"
14
+
15
+ gem.files = `git ls-files`.split($/)
16
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
17
+ gem.require_paths = %w(lib)
18
+
19
+ # executables are used for development purposes only
20
+ gem.executables = []
21
+
22
+ gem.required_ruby_version = '~> 2.5'
23
+
24
+ gem.add_dependency "expectation", "~> 1"
25
+ end
@@ -0,0 +1,166 @@
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
@@ -0,0 +1,266 @@
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, **keywords)
19
+ @actual = ::Simple::Service.invoke(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 #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
+ 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
+ invoke!
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
+ 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
+ context "calling with extra named args" do
62
+ it "ignores extra args" do
63
+ invoke!(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
+ invoke!(*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
+ invoke!
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
+ invoke!("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
+ invoke!("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
+ invoke!("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
+ 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)
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
+ invoke!
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
+ invoke!(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
+ invoke!(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
+ invoke!("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
+ invoke!(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
+ invoke!
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
+ invoke!("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
+ invoke!("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
+ invoke!("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
+ invoke!("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
+ 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
+ end