runger_config 4.0.0 → 5.1.0

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.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +8 -0
  3. data/bin/release +27 -0
  4. data/lib/generators/runger/app_config/app_config_generator.rb +6 -10
  5. data/lib/generators/runger/config/config_generator.rb +44 -41
  6. data/lib/generators/runger/install/install_generator.rb +35 -37
  7. data/lib/runger/auto_cast.rb +3 -3
  8. data/lib/runger/config.rb +114 -94
  9. data/lib/runger/dynamic_config.rb +21 -23
  10. data/lib/runger/ejson_parser.rb +24 -24
  11. data/lib/runger/env.rb +50 -52
  12. data/lib/runger/ext/deep_dup.rb +33 -36
  13. data/lib/runger/ext/deep_freeze.rb +28 -32
  14. data/lib/runger/ext/flatten_names.rb +23 -27
  15. data/lib/runger/ext/hash.rb +26 -29
  16. data/lib/runger/ext/string_constantize.rb +12 -15
  17. data/lib/runger/loaders/base.rb +11 -15
  18. data/lib/runger/loaders/doppler.rb +38 -42
  19. data/lib/runger/loaders/ejson.rb +65 -63
  20. data/lib/runger/loaders/env.rb +6 -10
  21. data/lib/runger/loaders/yaml.rb +69 -66
  22. data/lib/runger/loaders.rb +69 -71
  23. data/lib/runger/option_parser_builder.rb +16 -18
  24. data/lib/runger/optparse_config.rb +11 -10
  25. data/lib/runger/rails/autoload.rb +24 -26
  26. data/lib/runger/rails/config.rb +13 -17
  27. data/lib/runger/rails/loaders/credentials.rb +53 -57
  28. data/lib/runger/rails/loaders/secrets.rb +21 -25
  29. data/lib/runger/rails/loaders/yaml.rb +1 -6
  30. data/lib/runger/rails/loaders.rb +3 -3
  31. data/lib/runger/rails/settings.rb +49 -49
  32. data/lib/runger/rails.rb +9 -11
  33. data/lib/runger/railtie.rb +3 -2
  34. data/lib/runger/rbs.rb +29 -29
  35. data/lib/runger/settings.rb +82 -84
  36. data/lib/runger/testing/helpers.rb +26 -28
  37. data/lib/runger/testing.rb +2 -2
  38. data/lib/runger/tracing.rb +143 -136
  39. data/lib/runger/type_casting.rb +16 -11
  40. data/lib/runger/utils/which.rb +10 -12
  41. data/lib/runger/version.rb +1 -1
  42. data/lib/runger.rb +1 -1
  43. data/lib/runger_config.rb +34 -27
  44. metadata +20 -19
@@ -1,188 +1,195 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Runger
4
- # Provides method to trace values association
5
- module Tracing
6
- using Runger::Ext::DeepDup
7
-
8
- using(Module.new do
9
- refine Thread::Backtrace::Location do
10
- def path_lineno = "#{path}:#{lineno}"
11
- end
12
- end)
3
+ # Provides method to trace values association
4
+ module Runger::Tracing
5
+ using Runger::Ext::DeepDup
13
6
 
14
- class Trace
15
- UNDEF = Object.new
7
+ using(Module.new do
8
+ refine Thread::Backtrace::Location do
9
+ def path_lineno = "#{path}:#{lineno}"
10
+ end
11
+ end)
16
12
 
17
- attr_reader :type, :value, :source
13
+ class Trace
14
+ UNDEF = Object.new
18
15
 
19
- def initialize(type = :trace, value = UNDEF, **source)
20
- @type = type
21
- @source = source
22
- @value = (value == UNDEF) ? Hash.new { |h, k| h[k] = Trace.new(:trace) } : value
23
- end
16
+ attr_reader :type, :value, :source
24
17
 
25
- def dig(...)
26
- value.dig(...)
27
- end
18
+ def initialize(type = :trace, value = UNDEF, **source)
19
+ @type = type
20
+ @source = source
21
+ @value = (value == UNDEF) ? Hash.new { |h, k| h[k] = Trace.new(:trace) } : value
22
+ end
23
+
24
+ def dig(...)
25
+ value.dig(...)
26
+ end
28
27
 
29
- def record_value(val, *path, **)
30
- key = path.pop
31
- trace = if val.is_a?(Hash)
32
- Trace.new.tap { _1.merge_values(val, **) }
28
+ def record_value(val, *path, **options)
29
+ key = path.pop
30
+ trace =
31
+ if val.is_a?(Hash)
32
+ Trace.new.tap { _1.merge_values(val, **options) }
33
33
  else
34
- Trace.new(:value, val, **)
34
+ Trace.new(:value, val, **options)
35
35
  end
36
36
 
37
- target_trace = path.empty? ? self : value.dig(*path)
38
- target_trace.record_key(key.to_s, trace)
37
+ target_trace = path.empty? ? self : value.dig(*path)
38
+ target_trace.record_key(key.to_s, trace)
39
39
 
40
- val
41
- end
40
+ val
41
+ end
42
42
 
43
- def merge_values(hash, **)
44
- return hash unless hash
43
+ def merge_values(hash, **options)
44
+ return hash unless hash
45
45
 
46
- hash.each do |key, val|
47
- if val.is_a?(Hash)
48
- value[key.to_s].merge_values(val, **)
49
- else
50
- value[key.to_s] = Trace.new(:value, val, **)
51
- end
46
+ hash.each do |key, val|
47
+ if val.is_a?(Hash)
48
+ value[key.to_s].merge_values(val, **options)
49
+ else
50
+ value[key.to_s] = Trace.new(:value, val, **options)
52
51
  end
53
-
54
- hash
55
52
  end
56
53
 
57
- def record_key(key, key_trace)
58
- @value = Hash.new { |h, k| h[k] = Trace.new(:trace) } unless value.is_a?(::Hash)
54
+ hash
55
+ end
59
56
 
60
- value[key] = key_trace
61
- end
57
+ def record_key(key, key_trace)
58
+ @value = Hash.new { |h, k| h[k] = Trace.new(:trace) } unless value.is_a?(::Hash)
62
59
 
63
- def merge!(another_trace)
64
- raise ArgumentError, "You can only merge into a :trace type, and this is :#{type}" unless trace?
65
- raise ArgumentError, "You can only merge a :trace type, but trying :#{type}" unless another_trace.trace?
60
+ value[key] = key_trace
61
+ end
66
62
 
67
- another_trace.value.each do |key, sub_trace|
68
- if sub_trace.trace?
69
- value[key].merge! sub_trace
70
- else
71
- value[key] = sub_trace
72
- end
73
- end
63
+ def merge!(another_trace)
64
+ unless trace?
65
+ raise(ArgumentError,
66
+ "You can only merge into a :trace type, and this is :#{type}")
67
+ end
68
+ unless another_trace.trace?
69
+ raise(ArgumentError,
70
+ "You can only merge a :trace type, but trying :#{type}")
74
71
  end
75
72
 
76
- def keep_if(...)
77
- raise ArgumentError, "You can only filter :trace type, and this is :#{type}" unless trace?
78
- value.keep_if(...)
73
+ another_trace.value.each do |key, sub_trace|
74
+ if sub_trace.trace?
75
+ value[key].merge!(sub_trace)
76
+ else
77
+ value[key] = sub_trace
78
+ end
79
79
  end
80
+ end
80
81
 
81
- def clear = value.clear
82
+ def keep_if(...)
83
+ raise(ArgumentError, "You can only filter :trace type, and this is :#{type}") unless trace?
82
84
 
83
- def trace? = type == :trace
85
+ value.keep_if(...)
86
+ end
84
87
 
85
- def to_h
86
- if trace?
87
- value.transform_values(&:to_h).tap { _1.default_proc = nil }
88
- else
89
- {value:, source:}
90
- end
88
+ def clear = value.clear
89
+
90
+ def trace? = type == :trace
91
+
92
+ def to_h
93
+ if trace?
94
+ value.transform_values(&:to_h).tap { _1.default_proc = nil }
95
+ else
96
+ { value:, source: }
91
97
  end
98
+ end
92
99
 
93
- def dup = self.class.new(type, value.dup, **source)
94
-
95
- def pretty_print(q)
96
- if trace?
97
- q.nest(2) do
98
- q.breakable ""
99
- q.seplist(value, nil, :each) do |k, v|
100
- q.group do
101
- q.text k
102
- q.text " =>"
103
- if v.trace?
104
- q.text " { "
105
- q.pp v
106
- q.breakable " "
107
- q.text "}"
108
- else
109
- q.breakable " "
110
- q.pp v
111
- end
100
+ def dup = self.class.new(type, value.dup, **source)
101
+
102
+ def pretty_print(q)
103
+ if trace?
104
+ q.nest(2) do
105
+ q.breakable('')
106
+ q.seplist(value, nil, :each) do |k, v|
107
+ q.group do
108
+ q.text k
109
+ q.text ' =>'
110
+ if v.trace?
111
+ q.text ' { '
112
+ q.pp(v)
113
+ q.breakable(' ')
114
+ q.text '}'
115
+ else
116
+ q.breakable(' ')
117
+ q.pp(v)
112
118
  end
113
119
  end
114
120
  end
115
- else
116
- q.pp value
117
- q.group(0, " (", ")") do
118
- q.seplist(source, lambda { q.breakable " " }, :each) do |k, v|
119
- q.group do
120
- q.text k.to_s
121
- q.text "="
122
- q.text v.to_s
123
- end
121
+ end
122
+ else
123
+ q.pp(value)
124
+ q.group(0, ' (', ')') do
125
+ q.seplist(source, lambda { q.breakable(' ') }, :each) do |k, v|
126
+ q.group do
127
+ q.text k.to_s
128
+ q.text '='
129
+ q.text v.to_s
124
130
  end
125
131
  end
126
132
  end
127
133
  end
128
134
  end
135
+ end
129
136
 
130
- class << self
131
- def capture
132
- unless Settings.tracing_enabled
133
- yield
134
- return
135
- end
136
-
137
- trace = Trace.new
138
- trace_stack.push trace
137
+ class << self
138
+ def capture
139
+ unless ::Runger::Settings.tracing_enabled
139
140
  yield
140
- trace_stack.last
141
- ensure
142
- trace_stack.pop
141
+ return
143
142
  end
144
143
 
145
- def trace_stack
146
- (Thread.current[:__runger__trace_stack__] ||= [])
147
- end
144
+ trace = Trace.new
145
+ trace_stack.push(trace)
146
+ yield
147
+ trace_stack.last
148
+ ensure
149
+ trace_stack.pop
150
+ end
148
151
 
149
- def current_trace = trace_stack.last
152
+ def trace_stack
153
+ (Thread.current[:__runger__trace_stack__] ||= [])
154
+ end
150
155
 
151
- alias_method :tracing?, :current_trace
156
+ def current_trace = trace_stack.last
152
157
 
153
- def source_stack
154
- (Thread.current[:__runger__trace_source_stack__] ||= [])
155
- end
158
+ alias tracing? current_trace
156
159
 
157
- def current_trace_source
158
- source_stack.last || accessor_source(caller_locations(2, 1).first)
159
- end
160
+ def source_stack
161
+ (Thread.current[:__runger__trace_source_stack__] ||= [])
162
+ end
160
163
 
161
- def with_trace_source(src)
162
- source_stack << src
163
- yield
164
- ensure
165
- source_stack.pop
166
- end
164
+ def current_trace_source
165
+ source_stack.last || accessor_source(caller_locations(2, 1).first)
166
+ end
167
+
168
+ def with_trace_source(src)
169
+ source_stack << src
170
+ yield
171
+ ensure
172
+ source_stack.pop
173
+ end
167
174
 
168
- private
175
+ private
169
176
 
170
- def accessor_source(location)
171
- {type: :accessor, called_from: location.path_lineno}
172
- end
177
+ def accessor_source(location)
178
+ { type: :accessor, called_from: location.path_lineno }
173
179
  end
180
+ end
174
181
 
175
- module_function
182
+ module_function
176
183
 
177
- def trace!(type, *path, **)
178
- return yield unless Tracing.tracing?
179
- val = yield
180
- if val.is_a?(Hash)
181
- Tracing.current_trace.merge_values(val, type:, **)
182
- elsif !path.empty?
183
- Tracing.current_trace.record_value(val, *path, type:, **)
184
- end
185
- val
184
+ def trace!(type, *path, **options)
185
+ return yield unless ::Runger::Tracing.tracing?
186
+
187
+ val = yield
188
+ if val.is_a?(Hash)
189
+ ::Runger::Tracing.current_trace.merge_values(val, type:, **options)
190
+ elsif !path.empty?
191
+ ::Runger::Tracing.current_trace.record_value(val, *path, type:, **options)
186
192
  end
193
+ val
187
194
  end
188
195
  end
@@ -15,7 +15,8 @@ module Runger
15
15
 
16
16
  def accept(name_or_object, &block)
17
17
  if !block && !name_or_object.respond_to?(:call)
18
- raise ArgumentError, "Please, provide a type casting block or an object implementing #call(val) method"
18
+ raise(ArgumentError,
19
+ 'Please, provide a type casting block or an object implementing #call(val) method')
19
20
  end
20
21
 
21
22
  registry[name_or_object] = block || name_or_object
@@ -26,9 +27,13 @@ module Runger
26
27
 
27
28
  caster =
28
29
  if type_id.is_a?(Symbol) || type_id.nil?
29
- registry.fetch(type_id) { raise ArgumentError, "Unknown type: #{type_id}" }
30
+ registry.fetch(type_id) { raise(ArgumentError, "Unknown type: #{type_id}") }
30
31
  else
31
- raise ArgumentError, "Type must implement #call(val): #{type_id}" unless type_id.respond_to?(:call)
32
+ unless type_id.respond_to?(:call)
33
+ raise(ArgumentError,
34
+ "Type must implement #call(val): #{type_id}")
35
+ end
36
+
32
37
  type_id
33
38
  end
34
39
 
@@ -58,7 +63,7 @@ module Runger
58
63
  obj.accept(:float, &:to_f)
59
64
 
60
65
  obj.accept(:date) do
61
- require "date" unless defined?(::Date)
66
+ require 'date' unless defined?(::Date)
62
67
 
63
68
  next _1 if _1.is_a?(::Date)
64
69
 
@@ -68,7 +73,7 @@ module Runger
68
73
  end
69
74
 
70
75
  obj.accept(:datetime) do
71
- require "date" unless defined?(::Date)
76
+ require 'date' unless defined?(::Date)
72
77
 
73
78
  next _1 if _1.is_a?(::DateTime)
74
79
 
@@ -78,7 +83,7 @@ module Runger
78
83
  end
79
84
 
80
85
  obj.accept(:uri) do
81
- require "uri" unless defined?(::URI)
86
+ require 'uri' unless defined?(::URI)
82
87
 
83
88
  next _1 if _1.is_a?(::URI)
84
89
 
@@ -90,8 +95,8 @@ module Runger
90
95
  end
91
96
  end
92
97
 
93
- unless "".respond_to?(:safe_constantize)
94
- require "runger/ext/string_constantize"
98
+ unless ''.respond_to?(:safe_constantize)
99
+ require 'runger/ext/string_constantize'
95
100
  using Runger::Ext::StringConstantize
96
101
  end
97
102
 
@@ -115,16 +120,16 @@ module Runger
115
120
 
116
121
  case caster_config
117
122
  in Hash[array:, type:, **nil]
118
- registry.deserialize(val, type, array: array)
123
+ registry.deserialize(val, type, array:)
119
124
  in Hash[config: subconfig]
120
125
  subconfig = subconfig.safe_constantize if subconfig.is_a?(::String)
121
- raise ArgumentError, "Config is not found: #{subconfig}" unless subconfig
126
+ raise(ArgumentError, "Config is not found: #{subconfig}") unless subconfig
122
127
 
123
128
  subconfig.new(val)
124
129
  in Hash
125
130
  return val unless val.is_a?(Hash)
126
131
 
127
- caster_config.each do |k, v|
132
+ caster_config.each_key do |k|
128
133
  ks = k.to_s
129
134
  next unless val.key?(ks)
130
135
 
@@ -1,18 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Runger
4
- module Utils
5
- # Cross-platform solution
6
- # taken from https://stackoverflow.com/a/5471032
7
- def self.which(cmd)
8
- exts = ENV["PATHEXT"] ? ENV["PATHEXT"].split(";") : [""]
9
- ENV["PATH"].split(File::PATH_SEPARATOR).each do |path|
10
- exts.each do |ext|
11
- exe = File.join(path, "#{cmd}#{ext}")
12
- return exe if File.executable?(exe) && !File.directory?(exe)
13
- end
3
+ module Runger::Utils
4
+ # Cross-platform solution
5
+ # taken from https://stackoverflow.com/a/5471032
6
+ def self.which(cmd)
7
+ exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : ['']
8
+ ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
9
+ exts.each do |ext|
10
+ exe = File.join(path, "#{cmd}#{ext}")
11
+ return exe if File.executable?(exe) && !File.directory?(exe)
14
12
  end
15
- nil
16
13
  end
14
+ nil
17
15
  end
18
16
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Runger # :nodoc:
4
- VERSION = "4.0.0"
4
+ VERSION = '5.1.0'
5
5
  end
data/lib/runger.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "runger_config"
3
+ require 'runger_config'
data/lib/runger_config.rb CHANGED
@@ -1,23 +1,30 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "runger/version"
4
-
5
- require "runger/ext/deep_dup"
6
- require "runger/ext/deep_freeze"
7
- require "runger/ext/hash"
8
- require "runger/ext/flatten_names"
9
-
10
- require "runger/utils/deep_merge"
11
- require "runger/utils/which"
12
-
13
- require "runger/settings"
14
- require "runger/tracing"
15
- require "runger/config"
16
- require "runger/auto_cast"
17
- require "runger/type_casting"
18
- require "runger/env"
19
- require "runger/loaders"
20
- require "runger/rbs"
3
+ require 'runger/version'
4
+
5
+ module Runger ; end
6
+ module Runger::Ext ; end
7
+ module Runger::Utils ; end
8
+ module Runger::Tracing ; end
9
+ module Runger::Loaders ; end
10
+ module Runger::Testing ; end
11
+
12
+ require 'runger/ext/deep_dup'
13
+ require 'runger/ext/deep_freeze'
14
+ require 'runger/ext/flatten_names'
15
+ require 'runger/ext/hash'
16
+
17
+ require 'runger/utils/deep_merge'
18
+ require 'runger/utils/which'
19
+
20
+ require 'runger/auto_cast'
21
+ require 'runger/config'
22
+ require 'runger/env'
23
+ require 'runger/loaders'
24
+ require 'runger/rbs'
25
+ require 'runger/settings'
26
+ require 'runger/tracing'
27
+ require 'runger/type_casting'
21
28
 
22
29
  module Runger # :nodoc:
23
30
  class << self
@@ -31,19 +38,19 @@ module Runger # :nodoc:
31
38
  end
32
39
 
33
40
  # Configure default loaders
34
- loaders.append :yml, Loaders::YAML
35
- loaders.append :ejson, Loaders::EJSON if Utils.which("ejson")
36
- loaders.append :env, Loaders::Env
41
+ loaders.append(:yml, Loaders::YAML)
42
+ loaders.append(:ejson, Loaders::EJSON) if Utils.which('ejson')
43
+ loaders.append(:env, Loaders::Env)
37
44
 
38
- if ENV.key?("DOPPLER_TOKEN") && ENV["RUNGER_CONFIG_DISABLE_DOPPLER"] != "true"
39
- loaders.append :doppler, Loaders::Doppler
45
+ if ENV.key?('DOPPLER_TOKEN') && ENV['RUNGER_CONFIG_DISABLE_DOPPLER'] != 'true'
46
+ loaders.append(:doppler, Loaders::Doppler)
40
47
  end
41
48
  end
42
49
 
43
- if defined?(::Rails::VERSION)
44
- require "runger/rails"
50
+ if defined?(Rails::VERSION)
51
+ require 'runger/rails'
45
52
  else
46
- require "runger/rails/autoload"
53
+ require 'runger/rails/autoload'
47
54
  end
48
55
 
49
- require "runger/testing" if ENV["RACK_ENV"] == "test" || ENV["RAILS_ENV"] == "test"
56
+ require 'runger/testing' if ENV['RACK_ENV'] == 'test' || ENV['RAILS_ENV'] == 'test'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: runger_config
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.0.0
4
+ version: 5.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Runger
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-11-20 00:00:00.000000000 Z
11
+ date: 2024-06-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -38,6 +38,20 @@ dependencies:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: 1.1.3
41
+ - !ruby/object:Gem::Dependency
42
+ name: ejson
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: 1.3.1
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: 1.3.1
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: rake
43
57
  requirement: !ruby/object:Gem::Requirement
@@ -80,20 +94,6 @@ dependencies:
80
94
  - - "~>"
81
95
  - !ruby/object:Gem::Version
82
96
  version: '3.18'
83
- - !ruby/object:Gem::Dependency
84
- name: ejson
85
- requirement: !ruby/object:Gem::Requirement
86
- requirements:
87
- - - ">="
88
- - !ruby/object:Gem::Version
89
- version: 1.3.1
90
- type: :development
91
- prerelease: false
92
- version_requirements: !ruby/object:Gem::Requirement
93
- requirements:
94
- - - ">="
95
- - !ruby/object:Gem::Version
96
- version: 1.3.1
97
97
  description: "\n Configuration DSL for Ruby libraries and applications.\n Allows
98
98
  you to easily follow the twelve-factor application principles (https://12factor.net/config).\n
99
99
  \ "
@@ -106,6 +106,7 @@ files:
106
106
  - CHANGELOG.md
107
107
  - LICENSE.txt
108
108
  - README.md
109
+ - bin/release
109
110
  - lib/generators/runger/app_config/USAGE
110
111
  - lib/generators/runger/app_config/app_config_generator.rb
111
112
  - lib/generators/runger/config/USAGE
@@ -160,7 +161,7 @@ licenses:
160
161
  - MIT
161
162
  metadata:
162
163
  bug_tracker_uri: http://github.com/davidrunger/runger_config/issues
163
- changelog_uri: https://github.com/davidrunger/runger_config/blob/master/CHANGELOG.md
164
+ changelog_uri: https://github.com/davidrunger/runger_config/blob/main/CHANGELOG.md
164
165
  documentation_uri: http://github.com/davidrunger/runger_config
165
166
  funding_uri: https://github.com/sponsors/davidrunger
166
167
  homepage_uri: http://github.com/davidrunger/runger_config
@@ -174,14 +175,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
174
175
  requirements:
175
176
  - - ">="
176
177
  - !ruby/object:Gem::Version
177
- version: 3.2.2
178
+ version: 3.3.0
178
179
  required_rubygems_version: !ruby/object:Gem::Requirement
179
180
  requirements:
180
181
  - - ">="
181
182
  - !ruby/object:Gem::Version
182
183
  version: '0'
183
184
  requirements: []
184
- rubygems_version: 3.4.22
185
+ rubygems_version: 3.5.11
185
186
  signing_key:
186
187
  specification_version: 4
187
188
  summary: Configuration DSL for Ruby libraries and applications