sleeping_king_studios-tasks 0.1.0 → 0.4.1
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 +5 -5
- data/CHANGELOG.md +21 -0
- data/DEVELOPMENT.md +4 -0
- data/README.md +6 -6
- data/lib/sleeping_king_studios/tasks/apps.rb +1 -1
- data/lib/sleeping_king_studios/tasks/apps/app_configuration.rb +1 -1
- data/lib/sleeping_king_studios/tasks/apps/ci/results_reporter.rb +8 -6
- data/lib/sleeping_king_studios/tasks/apps/ci/rspec_task.rb +1 -1
- data/lib/sleeping_king_studios/tasks/apps/ci/rubocop_task.rb +1 -1
- data/lib/sleeping_king_studios/tasks/ci/cucumber_parser.rb +4 -3
- data/lib/sleeping_king_studios/tasks/ci/cucumber_results.rb +3 -3
- data/lib/sleeping_king_studios/tasks/ci/cucumber_task.rb +1 -1
- data/lib/sleeping_king_studios/tasks/ci/eslint_results.rb +112 -0
- data/lib/sleeping_king_studios/tasks/ci/eslint_runner.rb +51 -0
- data/lib/sleeping_king_studios/tasks/ci/eslint_task.rb +32 -0
- data/lib/sleeping_king_studios/tasks/ci/jest_results.rb +106 -0
- data/lib/sleeping_king_studios/tasks/ci/jest_runner.rb +51 -0
- data/lib/sleeping_king_studios/tasks/ci/jest_task.rb +43 -0
- data/lib/sleeping_king_studios/tasks/ci/rspec_each_results.rb +1 -1
- data/lib/sleeping_king_studios/tasks/ci/rspec_each_task.rb +18 -2
- data/lib/sleeping_king_studios/tasks/ci/rspec_results.rb +1 -1
- data/lib/sleeping_king_studios/tasks/ci/rspec_task.rb +12 -2
- data/lib/sleeping_king_studios/tasks/ci/rubocop_task.rb +1 -1
- data/lib/sleeping_king_studios/tasks/ci/simplecov_results.rb +4 -5
- data/lib/sleeping_king_studios/tasks/ci/steps_runner.rb +1 -1
- data/lib/sleeping_king_studios/tasks/ci/steps_task.rb +1 -1
- data/lib/sleeping_king_studios/tasks/ci/tasks.thor +4 -0
- data/lib/sleeping_king_studios/tasks/configuration.rb +25 -4
- data/lib/sleeping_king_studios/tasks/file/new_task.rb +16 -14
- data/lib/sleeping_king_studios/tasks/file/templates/rspec.erb +13 -0
- data/lib/sleeping_king_studios/tasks/file/templates/ruby.erb +28 -0
- data/lib/sleeping_king_studios/tasks/process_runner.rb +15 -5
- data/lib/sleeping_king_studios/tasks/task.rb +2 -2
- data/lib/sleeping_king_studios/tasks/version.rb +2 -2
- data/lib/sleeping_king_studios/tools/toolbox/configuration.rb +280 -0
- metadata +31 -37
@@ -29,8 +29,8 @@ module SleepingKingStudios::Tasks
|
|
29
29
|
end # method base_command
|
30
30
|
|
31
31
|
def build_command **kwargs
|
32
|
-
env = build_environment(kwargs)
|
33
|
-
opts = build_options(kwargs)
|
32
|
+
env = build_environment(**kwargs)
|
33
|
+
opts = build_options(**kwargs)
|
34
34
|
|
35
35
|
"#{env} #{base_command} #{opts}".strip
|
36
36
|
end # method build_command
|
@@ -39,7 +39,7 @@ module SleepingKingStudios::Tasks
|
|
39
39
|
default_env.
|
40
40
|
merge(env).
|
41
41
|
map do |key, value|
|
42
|
-
key = tools.
|
42
|
+
key = tools.str.underscore(key).upcase
|
43
43
|
value = %("#{value}") if value.is_a?(String)
|
44
44
|
|
45
45
|
"#{key}=#{value}"
|
@@ -52,7 +52,7 @@ module SleepingKingStudios::Tasks
|
|
52
52
|
end # method build_options
|
53
53
|
|
54
54
|
def stream_process command
|
55
|
-
|
55
|
+
unbundled_env do
|
56
56
|
IO.popen(command) do |io|
|
57
57
|
loop do
|
58
58
|
char = io.getc
|
@@ -60,11 +60,21 @@ module SleepingKingStudios::Tasks
|
|
60
60
|
char ? print(char) : break
|
61
61
|
end # loop
|
62
62
|
end # popen
|
63
|
-
end #
|
63
|
+
end # with_unbundled_env
|
64
64
|
end # method stream_process
|
65
65
|
|
66
66
|
def tools
|
67
67
|
SleepingKingStudios::Tools::Toolbelt.new
|
68
68
|
end # method tools
|
69
|
+
|
70
|
+
def unbundled_env
|
71
|
+
# :nocov:
|
72
|
+
if Bundler.respond_to?(:with_unbundled_env)
|
73
|
+
Bundler.with_unbundled_env { yield }
|
74
|
+
else
|
75
|
+
Bundler.with_clean_env { yield }
|
76
|
+
end
|
77
|
+
# :nocov:
|
78
|
+
end
|
69
79
|
end # class
|
70
80
|
end # module
|
@@ -36,14 +36,14 @@ module SleepingKingStudios::Tasks
|
|
36
36
|
def task_name
|
37
37
|
tools = SleepingKingStudios::Tools::Toolbelt.instance
|
38
38
|
|
39
|
-
tools.
|
39
|
+
tools.str.underscore(name.split('::').last).sub(/_task$/, '')
|
40
40
|
end # method task_name
|
41
41
|
|
42
42
|
private
|
43
43
|
|
44
44
|
def define_helpers option_name, option_params
|
45
45
|
tools = SleepingKingStudios::Tools::Toolbelt.instance
|
46
|
-
name = tools.
|
46
|
+
name = tools.str.underscore option_name
|
47
47
|
|
48
48
|
define_method(name) { options[option_name.to_s] }
|
49
49
|
|
@@ -0,0 +1,280 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'sleeping_king_studios/tools/core_tools'
|
4
|
+
require 'sleeping_king_studios/tools/toolbox'
|
5
|
+
|
6
|
+
# :nocov:
|
7
|
+
module SleepingKingStudios::Tools::Toolbox
|
8
|
+
# Abstract base class for defining configuration objects.
|
9
|
+
class Configuration # rubocop:disable Metrics/ClassLength
|
10
|
+
# Class methods for configuration objects.
|
11
|
+
module ClassMethods
|
12
|
+
DEFAULT_OPTION = Object.new.freeze
|
13
|
+
|
14
|
+
# Defines a nested namespace for the configuration object.
|
15
|
+
#
|
16
|
+
# A namespace is represented by a nested configuration object, which has
|
17
|
+
# its own options and namespaces.
|
18
|
+
#
|
19
|
+
# @param namespace_name [String] The name of the namespace.
|
20
|
+
#
|
21
|
+
# @yield namespace If a block is given, that block will be executed in the
|
22
|
+
# context of the newly created namespace.
|
23
|
+
#
|
24
|
+
# @return [Configuration] the created namespace object.
|
25
|
+
def namespace(namespace_name, &block)
|
26
|
+
guard_abstract_class!
|
27
|
+
|
28
|
+
namespace =
|
29
|
+
(@namespaces ||= {}).fetch(namespace_name) do
|
30
|
+
@namespaces[namespace_name] = define_namespace namespace_name
|
31
|
+
end
|
32
|
+
|
33
|
+
namespace.instance_exec(namespace, &block) if block_given?
|
34
|
+
|
35
|
+
namespace
|
36
|
+
end
|
37
|
+
|
38
|
+
# Defines an option for the configuration object.
|
39
|
+
#
|
40
|
+
# A configuration option has a name and a value. It can be defined with a
|
41
|
+
# default value, or to allow or prohibit nil values or restrict possible
|
42
|
+
# values to a given set.
|
43
|
+
#
|
44
|
+
# @param option_name [String] The name of the option.
|
45
|
+
# @param allow_nil [true, false] If false, setting the option value to nil
|
46
|
+
# or an empty value will raise an error, as will trying to access the
|
47
|
+
# value when it has not been set. Defaults to false.
|
48
|
+
# @param default [Object] The default value for the option. If this is not
|
49
|
+
# set, the default value for the option will be nil.
|
50
|
+
# @param enum [Array] An enumerable list of valid values for the option.
|
51
|
+
def option(
|
52
|
+
option_name,
|
53
|
+
allow_nil: false,
|
54
|
+
default: DEFAULT_OPTION,
|
55
|
+
enum: nil
|
56
|
+
)
|
57
|
+
guard_abstract_class!
|
58
|
+
|
59
|
+
options = {
|
60
|
+
allow_nil: allow_nil,
|
61
|
+
default: default,
|
62
|
+
enum: enum
|
63
|
+
}
|
64
|
+
|
65
|
+
define_option_accessor option_name, options
|
66
|
+
define_option_mutator option_name, options
|
67
|
+
|
68
|
+
option_name.intern
|
69
|
+
end
|
70
|
+
|
71
|
+
private
|
72
|
+
|
73
|
+
def define_namespace(namespace_name)
|
74
|
+
namespace =
|
75
|
+
Class.new(SleepingKingStudios::Tools::Toolbox::Configuration)
|
76
|
+
|
77
|
+
define_namespace_accessor(namespace_name, namespace)
|
78
|
+
|
79
|
+
namespace
|
80
|
+
end
|
81
|
+
|
82
|
+
def define_namespace_accessor(namespace_name, namespace_class)
|
83
|
+
namespace_ivar = :"@#{namespace_name}"
|
84
|
+
|
85
|
+
define_method namespace_name do |&block|
|
86
|
+
if instance_variable_defined?(namespace_ivar)
|
87
|
+
return instance_variable_get(namespace_ivar).tap do |config|
|
88
|
+
block&.call(config)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
initialize_namespace(namespace_name, namespace_class, &block)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def define_option_accessor(option_name, options)
|
97
|
+
define_method option_name do
|
98
|
+
get_value(option_name, options)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def define_option_mutator(option_name, options)
|
103
|
+
writer_name = :"#{option_name}="
|
104
|
+
|
105
|
+
define_method writer_name do |value|
|
106
|
+
set_value(option_name, value, options)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def guard_abstract_class!
|
111
|
+
return unless self == SleepingKingStudios::Tools::Toolbox::Configuration
|
112
|
+
|
113
|
+
raise "can't define namespace or option on abstract class"
|
114
|
+
end
|
115
|
+
end
|
116
|
+
extend ClassMethods
|
117
|
+
|
118
|
+
DEFAULT_OPTION = ClassMethods::DEFAULT_OPTION
|
119
|
+
|
120
|
+
# @param data [Hash, Object] The data source used to populate configuration
|
121
|
+
# values. Can be a Hash or a data object. If the data source is nil, or no
|
122
|
+
# data source is given, values will be set to their respective defaults.
|
123
|
+
#
|
124
|
+
# @yieldparam [Class] The singleton class of the new configuration object.
|
125
|
+
def initialize(data = nil)
|
126
|
+
@data = convert_data_to_struct(data)
|
127
|
+
@root_namespace = self
|
128
|
+
|
129
|
+
return unless block_given?
|
130
|
+
|
131
|
+
SleepingKingStudios::Tools::CoreTools
|
132
|
+
.deprecate('Configuration#initialize with a block')
|
133
|
+
|
134
|
+
yield(singleton_class)
|
135
|
+
end
|
136
|
+
|
137
|
+
def [](key)
|
138
|
+
send(key) if respond_to?(key)
|
139
|
+
end
|
140
|
+
|
141
|
+
def []=(key, value)
|
142
|
+
send(:"#{key}=", value) if respond_to?(key)
|
143
|
+
end
|
144
|
+
|
145
|
+
def dig(*keys)
|
146
|
+
keys.reduce(self) do |config, key|
|
147
|
+
value = config[key]
|
148
|
+
|
149
|
+
return value if value.nil?
|
150
|
+
|
151
|
+
value
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
def fetch(key, default = DEFAULT_OPTION)
|
156
|
+
return send(key) if respond_to?(key)
|
157
|
+
|
158
|
+
return default unless default == DEFAULT_OPTION
|
159
|
+
|
160
|
+
return yield(key) if block_given?
|
161
|
+
|
162
|
+
raise KeyError, "key not found: #{key.inspect}"
|
163
|
+
end
|
164
|
+
|
165
|
+
protected
|
166
|
+
|
167
|
+
attr_accessor :root_namespace
|
168
|
+
|
169
|
+
private
|
170
|
+
|
171
|
+
attr_reader :data
|
172
|
+
|
173
|
+
def blank_value?(value)
|
174
|
+
value.nil? || (value.respond_to?(:empty?) && value.empty?)
|
175
|
+
end
|
176
|
+
|
177
|
+
def convert_data_to_struct(data)
|
178
|
+
return data unless data.is_a?(Hash)
|
179
|
+
|
180
|
+
return Object.new if data.empty?
|
181
|
+
|
182
|
+
obj = Struct.new(*data.keys).new
|
183
|
+
|
184
|
+
data.each do |key, value|
|
185
|
+
val = value.is_a?(Hash) ? convert_data_to_struct(value) : value
|
186
|
+
|
187
|
+
obj.send :"#{key}=", val
|
188
|
+
end
|
189
|
+
|
190
|
+
obj
|
191
|
+
end
|
192
|
+
|
193
|
+
def evaluate_default(default)
|
194
|
+
return default unless default.is_a?(Proc)
|
195
|
+
|
196
|
+
root_namespace.instance_exec(&default)
|
197
|
+
end
|
198
|
+
|
199
|
+
def get_default_value(options)
|
200
|
+
value = evaluate_default(options[:default])
|
201
|
+
|
202
|
+
validate_value value, options
|
203
|
+
|
204
|
+
value
|
205
|
+
end
|
206
|
+
|
207
|
+
def get_method_value(name, options)
|
208
|
+
value = data.send(name)
|
209
|
+
|
210
|
+
if value.nil? && options[:default] != DEFAULT_OPTION
|
211
|
+
value = evaluate_default(options[:default])
|
212
|
+
end
|
213
|
+
|
214
|
+
validate_value(value, options)
|
215
|
+
|
216
|
+
value
|
217
|
+
end
|
218
|
+
|
219
|
+
def get_value(name, options)
|
220
|
+
if data.respond_to?(name)
|
221
|
+
get_method_value(name, options)
|
222
|
+
elsif instance_variable_defined?(:"@#{name}")
|
223
|
+
instance_variable_get(:"@#{name}")
|
224
|
+
elsif options[:default] != DEFAULT_OPTION
|
225
|
+
get_default_value(options)
|
226
|
+
else
|
227
|
+
validate_value(nil, options)
|
228
|
+
|
229
|
+
nil
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
def initialize_namespace(namespace_name, namespace_class, &block)
|
234
|
+
data = get_value(namespace_name, default: Object.new)
|
235
|
+
config = namespace_class.new(data)
|
236
|
+
|
237
|
+
config.root_namespace = root_namespace || self
|
238
|
+
|
239
|
+
instance_variable_set(:"@#{namespace_name}", config)
|
240
|
+
|
241
|
+
block.call(config) if block_given?
|
242
|
+
|
243
|
+
config
|
244
|
+
end
|
245
|
+
|
246
|
+
def invalid_value_message(value, options)
|
247
|
+
array_tools = ::SleepingKingStudios::Tools::ArrayTools
|
248
|
+
valid_options =
|
249
|
+
array_tools
|
250
|
+
.humanize_list(
|
251
|
+
options[:enum].map(&:inspect),
|
252
|
+
last_separator: ' or '
|
253
|
+
)
|
254
|
+
|
255
|
+
"expected option to be #{valid_options}, but was #{value.inspect}"
|
256
|
+
end
|
257
|
+
|
258
|
+
def set_value(name, value, options)
|
259
|
+
writer_name = :"#{name}="
|
260
|
+
|
261
|
+
validate_value value, options
|
262
|
+
|
263
|
+
if data.respond_to?(writer_name)
|
264
|
+
data.send(writer_name, value)
|
265
|
+
else
|
266
|
+
# Store values locally if data source is immutable.
|
267
|
+
instance_variable_set(:"@#{name}", value)
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
def validate_value(value, options)
|
272
|
+
return if blank_value?(value) && options[:allow_nil]
|
273
|
+
|
274
|
+
return unless options[:enum] && !options[:enum].include?(value)
|
275
|
+
|
276
|
+
raise invalid_value_message(value, options)
|
277
|
+
end
|
278
|
+
end
|
279
|
+
end
|
280
|
+
# :nocov:
|
metadata
CHANGED
@@ -1,69 +1,55 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sleeping_king_studios-tasks
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1
|
4
|
+
version: 0.4.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Rob "Merlin" Smith
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-01-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
-
- !ruby/object:Gem::Dependency
|
14
|
-
name: rake
|
15
|
-
requirement: !ruby/object:Gem::Requirement
|
16
|
-
requirements:
|
17
|
-
- - "~>"
|
18
|
-
- !ruby/object:Gem::Version
|
19
|
-
version: '12.0'
|
20
|
-
type: :runtime
|
21
|
-
prerelease: false
|
22
|
-
version_requirements: !ruby/object:Gem::Requirement
|
23
|
-
requirements:
|
24
|
-
- - "~>"
|
25
|
-
- !ruby/object:Gem::Version
|
26
|
-
version: '12.0'
|
27
13
|
- !ruby/object:Gem::Dependency
|
28
14
|
name: thor
|
29
15
|
requirement: !ruby/object:Gem::Requirement
|
30
16
|
requirements:
|
31
|
-
- - "~>"
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
version: '0.19'
|
34
17
|
- - ">="
|
35
18
|
- !ruby/object:Gem::Version
|
36
19
|
version: 0.19.4
|
20
|
+
- - "<"
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '2.0'
|
37
23
|
type: :runtime
|
38
24
|
prerelease: false
|
39
25
|
version_requirements: !ruby/object:Gem::Requirement
|
40
26
|
requirements:
|
41
|
-
- - "~>"
|
42
|
-
- !ruby/object:Gem::Version
|
43
|
-
version: '0.19'
|
44
27
|
- - ">="
|
45
28
|
- !ruby/object:Gem::Version
|
46
29
|
version: 0.19.4
|
30
|
+
- - "<"
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '2.0'
|
47
33
|
- !ruby/object:Gem::Dependency
|
48
34
|
name: sleeping_king_studios-tools
|
49
35
|
requirement: !ruby/object:Gem::Requirement
|
50
36
|
requirements:
|
51
|
-
- - "~>"
|
52
|
-
- !ruby/object:Gem::Version
|
53
|
-
version: '0.7'
|
54
37
|
- - ">="
|
55
38
|
- !ruby/object:Gem::Version
|
56
|
-
version: 0.
|
39
|
+
version: 0.8.0
|
40
|
+
- - "<"
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: '2'
|
57
43
|
type: :runtime
|
58
44
|
prerelease: false
|
59
45
|
version_requirements: !ruby/object:Gem::Requirement
|
60
46
|
requirements:
|
61
|
-
- - "~>"
|
62
|
-
- !ruby/object:Gem::Version
|
63
|
-
version: '0.7'
|
64
47
|
- - ">="
|
65
48
|
- !ruby/object:Gem::Version
|
66
|
-
version: 0.
|
49
|
+
version: 0.8.0
|
50
|
+
- - "<"
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: '2'
|
67
53
|
- !ruby/object:Gem::Dependency
|
68
54
|
name: erubi
|
69
55
|
requirement: !ruby/object:Gem::Requirement
|
@@ -138,14 +124,14 @@ dependencies:
|
|
138
124
|
requirements:
|
139
125
|
- - "~>"
|
140
126
|
- !ruby/object:Gem::Version
|
141
|
-
version: 0.
|
127
|
+
version: 0.49.0
|
142
128
|
type: :development
|
143
129
|
prerelease: false
|
144
130
|
version_requirements: !ruby/object:Gem::Requirement
|
145
131
|
requirements:
|
146
132
|
- - "~>"
|
147
133
|
- !ruby/object:Gem::Version
|
148
|
-
version: 0.
|
134
|
+
version: 0.49.0
|
149
135
|
- !ruby/object:Gem::Dependency
|
150
136
|
name: cucumber
|
151
137
|
requirement: !ruby/object:Gem::Requirement
|
@@ -232,6 +218,12 @@ files:
|
|
232
218
|
- lib/sleeping_king_studios/tasks/ci/cucumber_results.rb
|
233
219
|
- lib/sleeping_king_studios/tasks/ci/cucumber_runner.rb
|
234
220
|
- lib/sleeping_king_studios/tasks/ci/cucumber_task.rb
|
221
|
+
- lib/sleeping_king_studios/tasks/ci/eslint_results.rb
|
222
|
+
- lib/sleeping_king_studios/tasks/ci/eslint_runner.rb
|
223
|
+
- lib/sleeping_king_studios/tasks/ci/eslint_task.rb
|
224
|
+
- lib/sleeping_king_studios/tasks/ci/jest_results.rb
|
225
|
+
- lib/sleeping_king_studios/tasks/ci/jest_runner.rb
|
226
|
+
- lib/sleeping_king_studios/tasks/ci/jest_task.rb
|
235
227
|
- lib/sleeping_king_studios/tasks/ci/results_helpers.rb
|
236
228
|
- lib/sleeping_king_studios/tasks/ci/rspec_each_results.rb
|
237
229
|
- lib/sleeping_king_studios/tasks/ci/rspec_each_task.rb
|
@@ -250,15 +242,18 @@ files:
|
|
250
242
|
- lib/sleeping_king_studios/tasks/file.rb
|
251
243
|
- lib/sleeping_king_studios/tasks/file/new_task.rb
|
252
244
|
- lib/sleeping_king_studios/tasks/file/tasks.thor
|
245
|
+
- lib/sleeping_king_studios/tasks/file/templates/rspec.erb
|
246
|
+
- lib/sleeping_king_studios/tasks/file/templates/ruby.erb
|
253
247
|
- lib/sleeping_king_studios/tasks/process_runner.rb
|
254
248
|
- lib/sleeping_king_studios/tasks/task.rb
|
255
249
|
- lib/sleeping_king_studios/tasks/task_group.rb
|
256
250
|
- lib/sleeping_king_studios/tasks/version.rb
|
251
|
+
- lib/sleeping_king_studios/tools/toolbox/configuration.rb
|
257
252
|
homepage: http://sleepingkingstudios.com
|
258
253
|
licenses:
|
259
254
|
- MIT
|
260
255
|
metadata: {}
|
261
|
-
post_install_message:
|
256
|
+
post_install_message:
|
262
257
|
rdoc_options: []
|
263
258
|
require_paths:
|
264
259
|
- lib
|
@@ -273,9 +268,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
273
268
|
- !ruby/object:Gem::Version
|
274
269
|
version: '0'
|
275
270
|
requirements: []
|
276
|
-
|
277
|
-
|
278
|
-
signing_key:
|
271
|
+
rubygems_version: 3.2.3
|
272
|
+
signing_key:
|
279
273
|
specification_version: 4
|
280
274
|
summary: A tasks toolkit for rapid development.
|
281
275
|
test_files: []
|