hierarchical_config 0.11 → 0.13
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.github/workflows/ruby.yml +52 -0
- data/.gitignore +2 -0
- data/.rubocop.yml +68 -0
- data/.ruby-version +1 -0
- data/Gemfile +15 -2
- data/Gemfile.2.4 +19 -0
- data/Gemfile.2.4.lock +117 -0
- data/Gemfile.lock +124 -25
- data/README.md +0 -2
- data/bin/console +3 -3
- data/bin/tapioca +29 -0
- data/hierarchical_config.gemspec +14 -13
- data/lib/hierarchical_config/version.rb +3 -1
- data/lib/hierarchical_config.rb +164 -102
- data/sorbet/config +2 -0
- data/sorbet/rbi/annotations/activesupport.rbi +128 -0
- data/sorbet/rbi/annotations/rainbow.rbi +269 -0
- data/sorbet/rbi/gems/activesupport@7.0.4.2.rbi +16155 -0
- data/sorbet/rbi/gems/ast@2.4.2.rbi +584 -0
- data/sorbet/rbi/gems/binding_of_caller@1.0.0.rbi +55 -0
- data/sorbet/rbi/gems/coderay@1.1.3.rbi +3426 -0
- data/sorbet/rbi/gems/concurrent-ruby@1.2.2.rbi +11545 -0
- data/sorbet/rbi/gems/debug_inspector@1.1.0.rbi +23 -0
- data/sorbet/rbi/gems/diff-lcs@1.5.0.rbi +1083 -0
- data/sorbet/rbi/gems/i18n@1.12.0.rbi +2296 -0
- data/sorbet/rbi/gems/interception@0.5.rbi +138 -0
- data/sorbet/rbi/gems/json@2.6.3.rbi +1541 -0
- data/sorbet/rbi/gems/method_source@1.0.0.rbi +272 -0
- data/sorbet/rbi/gems/minitest@5.17.0.rbi +1457 -0
- data/sorbet/rbi/gems/netrc@0.11.0.rbi +158 -0
- data/sorbet/rbi/gems/parallel@1.22.1.rbi +277 -0
- data/sorbet/rbi/gems/parser@3.2.1.0.rbi +7252 -0
- data/sorbet/rbi/gems/pry-rescue@1.5.2.rbi +186 -0
- data/sorbet/rbi/gems/pry-stack_explorer@0.6.1.rbi +295 -0
- data/sorbet/rbi/gems/pry@0.14.2.rbi +10081 -0
- data/sorbet/rbi/gems/rainbow@3.1.1.rbi +402 -0
- data/sorbet/rbi/gems/rake@13.0.6.rbi +3018 -0
- data/sorbet/rbi/gems/rbi@0.0.16.rbi +3008 -0
- data/sorbet/rbi/gems/regexp_parser@2.7.0.rbi +3580 -0
- data/sorbet/rbi/gems/rexml@3.2.5.rbi +4717 -0
- data/sorbet/rbi/gems/rspec-core@3.12.1.rbi +10845 -0
- data/sorbet/rbi/gems/rspec-expectations@3.12.2.rbi +8100 -0
- data/sorbet/rbi/gems/rspec-mocks@3.12.3.rbi +5299 -0
- data/sorbet/rbi/gems/rspec-support@3.12.0.rbi +1611 -0
- data/sorbet/rbi/gems/rspec@3.12.0.rbi +82 -0
- data/sorbet/rbi/gems/rubocop-ast@1.27.0.rbi +6998 -0
- data/sorbet/rbi/gems/rubocop-performance@1.16.0.rbi +3004 -0
- data/sorbet/rbi/gems/rubocop@1.46.0.rbi +54549 -0
- data/sorbet/rbi/gems/ruby-progressbar@1.11.0.rbi +1239 -0
- data/sorbet/rbi/gems/spoom@1.1.15.rbi +2383 -0
- data/sorbet/rbi/gems/tapioca@0.11.1.rbi +3255 -0
- data/sorbet/rbi/gems/thor@1.2.1.rbi +3956 -0
- data/sorbet/rbi/gems/tzinfo@2.0.6.rbi +5917 -0
- data/sorbet/rbi/gems/unicode-display_width@2.4.2.rbi +65 -0
- data/sorbet/rbi/gems/unparser@0.6.7.rbi +4524 -0
- data/sorbet/rbi/gems/webrick@1.7.0.rbi +2555 -0
- data/sorbet/rbi/gems/yard-sorbet@0.8.0.rbi +441 -0
- data/sorbet/rbi/gems/yard@0.9.28.rbi +17841 -0
- data/sorbet/tapioca/config.yml +13 -0
- data/sorbet/tapioca/require.rb +4 -0
- metadata +74 -50
- data/.travis.yml +0 -6
data/lib/hierarchical_config.rb
CHANGED
@@ -1,84 +1,174 @@
|
|
1
|
-
|
1
|
+
# typed: strict
|
2
|
+
|
2
3
|
require 'yaml'
|
3
4
|
require 'erb'
|
4
5
|
require 'set'
|
6
|
+
require 'sorbet-runtime'
|
7
|
+
require 'active_support'
|
8
|
+
require 'active_support/core_ext/hash/keys'
|
5
9
|
|
6
|
-
require
|
10
|
+
require 'hierarchical_config/version'
|
7
11
|
|
8
12
|
module HierarchicalConfig
|
9
13
|
REQUIRED = :REQUIRED
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
14
|
+
T.unsafe(YAML).add_domain_type(nil, 'REQUIRED'){REQUIRED}
|
15
|
+
|
16
|
+
ClassOrModule = T.type_alias{T.any(Class, Module)}
|
17
|
+
|
18
|
+
module ConfigStruct
|
19
|
+
extend T::Sig
|
20
|
+
include Kernel
|
21
|
+
|
22
|
+
sig{returns(T::Hash[Symbol, T.untyped])}
|
23
|
+
def to_hash
|
24
|
+
Hash[self.class.props.keys.map{|key| [key, item_to_hash(send(key))]}] # rubocop:disable Style/HashConversion
|
25
|
+
end
|
26
|
+
|
27
|
+
sig{params(key: T.any(String, Symbol)).returns(T.untyped)}
|
28
|
+
def [](key)
|
29
|
+
send(key)
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
sig{params(item: BasicObject).returns(T.any(BasicObject, T::Hash[T.untyped, T.untyped]))}
|
35
|
+
def item_to_hash(item)
|
36
|
+
case item
|
37
|
+
when ConfigStruct
|
38
|
+
item.to_hash
|
39
|
+
when Array
|
40
|
+
item.map{|i| item_to_hash(i)}
|
28
41
|
else
|
29
|
-
|
42
|
+
item
|
30
43
|
end
|
31
44
|
end
|
45
|
+
end
|
46
|
+
|
47
|
+
@@root_index = T.let(0, Integer) # rubocop:disable Style/ClassVars
|
32
48
|
|
33
|
-
|
34
|
-
|
49
|
+
class << self
|
50
|
+
extend T::Sig
|
51
|
+
|
52
|
+
sig{params(value: T.untyped, path: String).returns(T::Array[String])}
|
53
|
+
def detect_errors(value, path)
|
54
|
+
errors = T.let([], T::Array[String])
|
55
|
+
case value
|
56
|
+
when Hash
|
57
|
+
value.each do |key, item|
|
58
|
+
errors += detect_errors(item, "#{path}.#{key}")
|
59
|
+
end
|
60
|
+
when Array
|
61
|
+
value.each_with_index do |item, index|
|
62
|
+
errors += detect_errors(item, "#{path}[#{index}]")
|
63
|
+
end
|
64
|
+
when REQUIRED
|
65
|
+
errors << "#{path} is REQUIRED"
|
66
|
+
end
|
67
|
+
errors
|
35
68
|
end
|
36
69
|
|
37
|
-
|
70
|
+
sig{params(current_item: Object, name: String, parent_class: ClassOrModule).returns(T.any(Class, T::Types::Base))}
|
71
|
+
def build_types(current_item, name, parent_class)
|
72
|
+
case current_item
|
73
|
+
when Hash
|
74
|
+
new_type_name = ActiveSupport::Inflector.camelize(ActiveSupport::Inflector.underscore(name))
|
75
|
+
|
76
|
+
return Hash if current_item.keys.to_a.any?{|k| k =~ /^[0-9]/ || k =~ /[- ]/}
|
38
77
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
78
|
+
new_type =
|
79
|
+
if parent_class.const_defined?(new_type_name, false)
|
80
|
+
parent_class.const_get(new_type_name, false)
|
81
|
+
else
|
82
|
+
parent_class.const_set(new_type_name, Class.new(T::Struct).tap{|c| c.include ConfigStruct})
|
83
|
+
end
|
84
|
+
|
85
|
+
current_item.each do |key, value|
|
86
|
+
next if new_type.props.key?(key.to_sym)
|
87
|
+
|
88
|
+
new_type.const key.to_sym, build_types(value, key, new_type)
|
89
|
+
new_type.send(:define_method, "#{key}?") do
|
90
|
+
!!send(key)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
new_type
|
95
|
+
when Array
|
96
|
+
types = current_item.each_with_index.map do |item, index|
|
97
|
+
build_types(item, "#{name}_#{index}", parent_class)
|
98
|
+
end
|
99
|
+
case types.size
|
100
|
+
when 0
|
101
|
+
T.untyped
|
102
|
+
when 1
|
103
|
+
T::Array[types.first]
|
104
|
+
else
|
105
|
+
T::Array[T.unsafe(T).any(*types)]
|
106
|
+
end
|
107
|
+
else
|
108
|
+
current_item.class
|
44
109
|
end
|
45
110
|
end
|
46
111
|
|
47
|
-
|
112
|
+
sig{params(current_item: Object, name: String, parent_class: ClassOrModule).returns(T.untyped)}
|
113
|
+
def build_config(current_item, name, parent_class)
|
114
|
+
case current_item
|
115
|
+
when Hash
|
116
|
+
return current_item.symbolize_keys if current_item.keys.to_a.any?{|k| k =~ /^[0-9]/ || k =~ /[- ]/}
|
48
117
|
|
49
|
-
|
50
|
-
|
118
|
+
current_type = parent_class.const_get(ActiveSupport::Inflector.camelize(name))
|
119
|
+
current_type.new(Hash[current_item.map{|key, value| [key.to_sym, build_config(value, key, current_type)]}]) # rubocop:disable Style/HashConversion
|
51
120
|
when Array
|
52
|
-
|
53
|
-
|
54
|
-
|
121
|
+
current_item.each_with_index.map do |item, index|
|
122
|
+
build_config(item, "#{name}_#{index}", parent_class)
|
123
|
+
end.freeze
|
55
124
|
else
|
56
|
-
|
125
|
+
current_item.freeze
|
57
126
|
end
|
58
127
|
end
|
59
|
-
end
|
60
128
|
|
61
|
-
|
62
|
-
def
|
129
|
+
sig{returns(Class)}
|
130
|
+
def build_new_root
|
131
|
+
@@root_index += 1 # rubocop:disable Style/ClassVars
|
132
|
+
const_set("ConfigRoot#{@@root_index}", Class.new)
|
133
|
+
end
|
134
|
+
|
135
|
+
sig do
|
136
|
+
params(
|
137
|
+
name: String,
|
138
|
+
dir: String,
|
139
|
+
environment: String,
|
140
|
+
preprocess_with: T.nilable(Symbol),
|
141
|
+
root_class: ClassOrModule,
|
142
|
+
).returns(T::Struct)
|
143
|
+
end
|
144
|
+
def load_config(name, dir, environment, preprocess_with = :erb, root_class = build_new_root)
|
63
145
|
primary_config_file = "#{dir}/#{name}.yml"
|
64
146
|
overrides_config_file = "#{dir}/#{name}-overrides.yml"
|
65
147
|
|
66
|
-
config_hash = load_hash_for_env(
|
148
|
+
config_hash = load_hash_for_env(primary_config_file, environment, preprocess_with)
|
67
149
|
|
68
|
-
if File.
|
69
|
-
overrides_config_hash = load_hash_for_env(
|
70
|
-
config_hash = deep_merge(
|
150
|
+
if File.exist?(overrides_config_file)
|
151
|
+
overrides_config_hash = load_hash_for_env(overrides_config_file, environment, preprocess_with)
|
152
|
+
config_hash = deep_merge(config_hash, overrides_config_hash)
|
71
153
|
end
|
72
154
|
|
73
|
-
|
155
|
+
errors = detect_errors(config_hash, name)
|
156
|
+
raise errors.map{|error| "#{error} for #{environment}"}.inspect unless errors.empty?
|
74
157
|
|
75
|
-
|
158
|
+
build_types(config_hash, name, root_class)
|
76
159
|
|
77
|
-
config_hash
|
160
|
+
build_config(config_hash, name, root_class)
|
78
161
|
end
|
79
162
|
|
80
|
-
|
81
|
-
|
163
|
+
sig do
|
164
|
+
params(
|
165
|
+
file: String,
|
166
|
+
environment: String,
|
167
|
+
preprocess_with: T.nilable(Symbol),
|
168
|
+
).returns(T::Hash[String, BasicObject])
|
169
|
+
end
|
170
|
+
def load_hash_for_env(file, environment, preprocess_with)
|
171
|
+
file_contents = File.read(file)
|
82
172
|
yaml_contents = case preprocess_with
|
83
173
|
when :erb
|
84
174
|
ERB.new(file_contents).result
|
@@ -87,103 +177,75 @@ module HierarchicalConfig
|
|
87
177
|
else
|
88
178
|
raise "Unknown preprocessor <#{preprocess_with}>"
|
89
179
|
end
|
90
|
-
yaml_config = YAML
|
180
|
+
yaml_config = YAML.safe_load(yaml_contents)
|
91
181
|
|
92
182
|
ordered_stanza_labels = []
|
93
183
|
ordered_stanza_labels << 'defaults' if yaml_config.key? 'defaults'
|
94
|
-
ordered_stanza_labels += yaml_config.keys.grep(/^defaults\[.*#{environment}/).sort_by{
|
184
|
+
ordered_stanza_labels += yaml_config.keys.grep(/^defaults\[.*#{environment}/).sort_by{|a| a.count(',')}
|
95
185
|
ordered_stanza_labels << environment if yaml_config.key? environment
|
96
186
|
|
97
187
|
config = deep_merge_hashes_in_keys(ordered_stanza_labels, yaml_config)
|
98
188
|
|
99
189
|
env_config_labels = []
|
100
190
|
env_config_labels << 'env_vars' if yaml_config.key? 'env_vars'
|
101
|
-
env_config_labels += yaml_config.keys.grep(/^env_vars\[.*#{environment}/).sort_by{
|
191
|
+
env_config_labels += yaml_config.keys.grep(/^env_vars\[.*#{environment}/).sort_by{|a| a.count(',')}
|
102
192
|
|
103
193
|
env_config = deep_merge_hashes_in_keys(env_config_labels, yaml_config)
|
104
194
|
env_config = fill_in_env_vars(env_config)
|
105
195
|
|
106
196
|
deep_merge(config, env_config)
|
107
|
-
|
108
197
|
rescue StandardError => e
|
109
198
|
raise <<-ERROR
|
110
199
|
Error loading config from file #{file}.
|
111
|
-
#{
|
112
|
-
#{
|
200
|
+
#{$ERROR_INFO.inspect}
|
201
|
+
#{$ERROR_POSITION}
|
202
|
+
#{e}
|
113
203
|
ERROR
|
114
204
|
end
|
115
205
|
|
116
206
|
private
|
117
207
|
|
208
|
+
sig do
|
209
|
+
params(keys: T::Array[String],
|
210
|
+
root_hash: T::Hash[String,
|
211
|
+
T::Hash[String, T.untyped]]).returns(T::Hash[T.untyped, T.untyped])
|
212
|
+
end
|
118
213
|
def deep_merge_hashes_in_keys(keys, root_hash)
|
119
214
|
keys.inject({}) do |acc, label|
|
120
|
-
deep_merge(
|
215
|
+
deep_merge(acc, T.must(root_hash[label]))
|
121
216
|
end
|
122
217
|
end
|
123
218
|
|
219
|
+
sig{params(hash: T::Hash[T.untyped, T.untyped]).returns(T::Hash[T.untyped, T.untyped])}
|
124
220
|
def fill_in_env_vars(hash)
|
125
221
|
r = {}
|
126
|
-
hash.each do |key,value|
|
222
|
+
hash.each do |key, value|
|
127
223
|
if value.is_a? Hash
|
128
224
|
leaf_hash = fill_in_env_vars(value)
|
129
|
-
r[key]=leaf_hash unless leaf_hash.keys.empty?
|
225
|
+
r[key] = leaf_hash unless leaf_hash.keys.empty?
|
130
226
|
elsif !value.nil? && ENV.key?(value)
|
131
|
-
r[key]=ENV
|
227
|
+
r[key] = ENV.fetch(value, nil)
|
132
228
|
end
|
133
229
|
end
|
134
230
|
r
|
135
231
|
end
|
136
232
|
|
137
233
|
# merges two hashes with nested hashes if present
|
138
|
-
|
234
|
+
sig do
|
235
|
+
params(hash1: T::Hash[T.untyped, T.untyped],
|
236
|
+
hash2: T::Hash[T.untyped, T.untyped]).returns(T::Hash[T.untyped, T.untyped])
|
237
|
+
end
|
238
|
+
def deep_merge(hash1, hash2)
|
139
239
|
hash1 = hash1.dup
|
140
|
-
(
|
141
|
-
if hash1.key?(
|
142
|
-
hash1[key].is_a?(
|
143
|
-
|
144
|
-
elsif hash2.key?(
|
240
|
+
(hash1.keys + hash2.keys).each do |key|
|
241
|
+
if hash1.key?(key) && hash2.key?(key) &&
|
242
|
+
hash1[key].is_a?(Hash) && hash2[key].is_a?(Hash)
|
243
|
+
hash1[key] = deep_merge(hash1[key], hash2[key])
|
244
|
+
elsif hash2.key?(key)
|
145
245
|
hash1[key] = hash2[key]
|
146
246
|
end
|
147
247
|
end
|
148
248
|
hash1
|
149
249
|
end
|
150
|
-
|
151
|
-
# Mutator method that does three things:
|
152
|
-
# * checks if any of the keys were required and not set. Upon finding
|
153
|
-
# it adds key to the error set
|
154
|
-
# * recursively sets open structs for deep hashes
|
155
|
-
# * recursively freezes config objects
|
156
|
-
def lock_down_and_ostructify!( _hash, path, environment)
|
157
|
-
hash = Hash[_hash.map{|k,v|[k.to_s, v]}] #stringify keys
|
158
|
-
errors = []
|
159
|
-
hash.each do | key, value |
|
160
|
-
hash[key], child_errors = lock_down_and_ostructify_item!(value, path + '.' + key, environment)
|
161
|
-
errors += child_errors
|
162
|
-
end
|
163
|
-
return OpenStruct.new(hash).freeze, errors
|
164
|
-
end
|
165
|
-
|
166
|
-
def lock_down_and_ostructify_item!(value, path, environment)
|
167
|
-
errors = []
|
168
|
-
return_value = case value
|
169
|
-
when Hash
|
170
|
-
child_hash, child_errors = lock_down_and_ostructify!( value, path, environment )
|
171
|
-
errors += child_errors
|
172
|
-
child_hash
|
173
|
-
when Array
|
174
|
-
value.each_with_index.map do |item, index|
|
175
|
-
child_item, child_errors = lock_down_and_ostructify_item!( item, "#{path}[#{index}]", environment )
|
176
|
-
errors += child_errors
|
177
|
-
child_item
|
178
|
-
end.freeze
|
179
|
-
when REQUIRED
|
180
|
-
errors << "#{path} is REQUIRED for #{environment}"
|
181
|
-
nil
|
182
|
-
else
|
183
|
-
value.freeze
|
184
|
-
end
|
185
|
-
|
186
|
-
return return_value, errors
|
187
|
-
end
|
188
250
|
end
|
189
251
|
end
|
data/sorbet/config
ADDED
@@ -0,0 +1,128 @@
|
|
1
|
+
# typed: strict
|
2
|
+
|
3
|
+
# DO NOT EDIT MANUALLY
|
4
|
+
# This file was pulled from a central RBI files repository.
|
5
|
+
# Please run `bin/tapioca annotations` to update it.
|
6
|
+
|
7
|
+
module ActiveSupport::Testing::Declarative
|
8
|
+
sig { params(name: String, block: T.proc.bind(T.untyped).void).void }
|
9
|
+
def test(name, &block); end
|
10
|
+
end
|
11
|
+
|
12
|
+
class ActiveSupport::EnvironmentInquirer
|
13
|
+
sig { returns(T::Boolean) }
|
14
|
+
def development?; end
|
15
|
+
|
16
|
+
sig { returns(T::Boolean) }
|
17
|
+
def production?; end
|
18
|
+
|
19
|
+
sig { returns(T::Boolean) }
|
20
|
+
def test?; end
|
21
|
+
|
22
|
+
# @method_missing: delegated to String through ActiveSupport::StringInquirer
|
23
|
+
sig { returns(T::Boolean) }
|
24
|
+
def staging?; end
|
25
|
+
end
|
26
|
+
|
27
|
+
module ActiveSupport::Testing::SetupAndTeardown::ClassMethods
|
28
|
+
sig { params(args: T.untyped, block: T.nilable(T.proc.bind(T.untyped).void)).void }
|
29
|
+
def setup(*args, &block); end
|
30
|
+
|
31
|
+
sig { params(args: T.untyped, block: T.nilable(T.proc.bind(T.untyped).void)).void }
|
32
|
+
def teardown(*args, &block); end
|
33
|
+
end
|
34
|
+
|
35
|
+
class ActiveSupport::TestCase
|
36
|
+
sig { params(args: T.untyped, block: T.nilable(T.proc.bind(T.attached_class).void)).void }
|
37
|
+
def self.setup(*args, &block); end
|
38
|
+
|
39
|
+
sig { params(args: T.untyped, block: T.nilable(T.proc.bind(T.attached_class).void)).void }
|
40
|
+
def self.teardown(*args, &block); end
|
41
|
+
|
42
|
+
sig { params(name: String, block: T.proc.bind(T.attached_class).void).void }
|
43
|
+
def self.test(name, &block); end
|
44
|
+
end
|
45
|
+
|
46
|
+
class Object
|
47
|
+
sig { returns(T::Boolean) }
|
48
|
+
def blank?; end
|
49
|
+
|
50
|
+
sig { returns(T::Boolean) }
|
51
|
+
def present?; end
|
52
|
+
end
|
53
|
+
|
54
|
+
class Hash
|
55
|
+
sig { returns(T::Boolean) }
|
56
|
+
def extractable_options?; end
|
57
|
+
end
|
58
|
+
|
59
|
+
class Array
|
60
|
+
sig { params(position: Integer).returns(T.self_type) }
|
61
|
+
def from(position); end
|
62
|
+
|
63
|
+
sig { params(position: Integer).returns(T.self_type) }
|
64
|
+
def to(position); end
|
65
|
+
|
66
|
+
sig { params(elements: T.untyped).returns(T::Array[T.untyped]) }
|
67
|
+
def including(*elements); end
|
68
|
+
|
69
|
+
sig { params(elements: T.untyped).returns(T.self_type) }
|
70
|
+
def excluding(*elements); end
|
71
|
+
|
72
|
+
sig { params(elements: T.untyped).returns(T.self_type) }
|
73
|
+
def without(*elements); end
|
74
|
+
|
75
|
+
sig { returns(T.nilable(Elem)) }
|
76
|
+
def second; end
|
77
|
+
|
78
|
+
sig { returns(T.nilable(Elem)) }
|
79
|
+
def third; end
|
80
|
+
|
81
|
+
sig { returns(T.nilable(Elem)) }
|
82
|
+
def fourth; end
|
83
|
+
|
84
|
+
sig { returns(T.nilable(Elem)) }
|
85
|
+
def fifth; end
|
86
|
+
|
87
|
+
sig { returns(T.nilable(Elem)) }
|
88
|
+
def forty_two; end
|
89
|
+
|
90
|
+
sig { returns(T.nilable(Elem)) }
|
91
|
+
def third_to_last; end
|
92
|
+
|
93
|
+
sig { returns(T.nilable(Elem)) }
|
94
|
+
def second_to_last; end
|
95
|
+
|
96
|
+
sig { params(options: T::Hash[T.untyped, T.untyped]).returns(String) }
|
97
|
+
def to_sentence(options = {}); end
|
98
|
+
|
99
|
+
sig { params(format: Symbol).returns(String) }
|
100
|
+
def to_fs(format = :default); end
|
101
|
+
|
102
|
+
sig { params(format: Symbol).returns(String) }
|
103
|
+
def to_formatted_s(format = :default); end
|
104
|
+
|
105
|
+
sig { returns(String) }
|
106
|
+
def to_xml; end
|
107
|
+
|
108
|
+
sig { returns(T::Hash[T.untyped, T.untyped]) }
|
109
|
+
def extract_options!; end
|
110
|
+
|
111
|
+
sig { type_parameters(:FillType).params(number: Integer, fill_with: T.type_parameter(:FillType), block: T.nilable(T.proc.params(group: T::Array[T.any(Elem, T.type_parameter(:FillType))]).void)).returns(T::Array[T::Array[T.any(Elem, T.type_parameter(:FillType))]]) }
|
112
|
+
def in_groups(number, fill_with = T.unsafe(nil), &block); end
|
113
|
+
|
114
|
+
sig { type_parameters(:FillType).params(number: Integer, fill_with: T.type_parameter(:FillType), block: T.nilable(T.proc.params(group: T::Array[T.any(Elem, T.type_parameter(:FillType))]).void)).returns(T::Array[T::Array[T.any(Elem, T.type_parameter(:FillType))]]) }
|
115
|
+
def in_groups_of(number, fill_with = T.unsafe(nil), &block); end
|
116
|
+
|
117
|
+
sig { params(value: T.untyped, block: T.nilable(T.proc.params(element: Elem).returns(T.untyped))).returns(T::Array[T::Array[Elem]]) }
|
118
|
+
def split(value = nil, &block); end
|
119
|
+
|
120
|
+
sig { params(object: T.untyped).returns(T::Array[T.untyped]) }
|
121
|
+
def self.wrap(object); end
|
122
|
+
|
123
|
+
sig { returns(T.untyped) }
|
124
|
+
def extract!; end
|
125
|
+
|
126
|
+
sig { returns(ActiveSupport::ArrayInquirer) }
|
127
|
+
def inquiry; end
|
128
|
+
end
|