hierarchical_config 0.11 → 0.13.2

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 (67) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/release.yml +41 -0
  3. data/.github/workflows/ruby.yml +55 -0
  4. data/.gitignore +2 -0
  5. data/.release-please-manifest.json +3 -0
  6. data/.rubocop.yml +68 -0
  7. data/.ruby-version +1 -0
  8. data/CHANGELOG.md +15 -0
  9. data/Gemfile +15 -2
  10. data/Gemfile.2.4 +19 -0
  11. data/Gemfile.2.4.lock +117 -0
  12. data/Gemfile.lock +126 -25
  13. data/README.md +0 -2
  14. data/bin/console +3 -3
  15. data/bin/tapioca +29 -0
  16. data/hierarchical_config.gemspec +14 -13
  17. data/lib/hierarchical_config/version.rb +3 -1
  18. data/lib/hierarchical_config.rb +195 -98
  19. data/release-please-config.json +14 -0
  20. data/sorbet/config +2 -0
  21. data/sorbet/rbi/annotations/activesupport.rbi +128 -0
  22. data/sorbet/rbi/annotations/rainbow.rbi +269 -0
  23. data/sorbet/rbi/gems/activesupport@7.0.4.2.rbi +16155 -0
  24. data/sorbet/rbi/gems/ast@2.4.2.rbi +584 -0
  25. data/sorbet/rbi/gems/binding_of_caller@1.0.0.rbi +55 -0
  26. data/sorbet/rbi/gems/coderay@1.1.3.rbi +3426 -0
  27. data/sorbet/rbi/gems/concurrent-ruby@1.2.2.rbi +11545 -0
  28. data/sorbet/rbi/gems/debug_inspector@1.1.0.rbi +23 -0
  29. data/sorbet/rbi/gems/diff-lcs@1.5.0.rbi +1083 -0
  30. data/sorbet/rbi/gems/i18n@1.12.0.rbi +2296 -0
  31. data/sorbet/rbi/gems/interception@0.5.rbi +138 -0
  32. data/sorbet/rbi/gems/json@2.6.3.rbi +1541 -0
  33. data/sorbet/rbi/gems/method_source@1.0.0.rbi +272 -0
  34. data/sorbet/rbi/gems/minitest@5.17.0.rbi +1457 -0
  35. data/sorbet/rbi/gems/netrc@0.11.0.rbi +158 -0
  36. data/sorbet/rbi/gems/parallel@1.22.1.rbi +277 -0
  37. data/sorbet/rbi/gems/parser@3.2.1.0.rbi +7252 -0
  38. data/sorbet/rbi/gems/pry-rescue@1.5.2.rbi +186 -0
  39. data/sorbet/rbi/gems/pry-stack_explorer@0.6.1.rbi +295 -0
  40. data/sorbet/rbi/gems/pry@0.14.2.rbi +10081 -0
  41. data/sorbet/rbi/gems/rainbow@3.1.1.rbi +402 -0
  42. data/sorbet/rbi/gems/rake@13.0.6.rbi +3018 -0
  43. data/sorbet/rbi/gems/rbi@0.0.16.rbi +3008 -0
  44. data/sorbet/rbi/gems/regexp_parser@2.7.0.rbi +3580 -0
  45. data/sorbet/rbi/gems/rexml@3.2.5.rbi +4717 -0
  46. data/sorbet/rbi/gems/rspec-core@3.12.1.rbi +10845 -0
  47. data/sorbet/rbi/gems/rspec-expectations@3.12.2.rbi +8100 -0
  48. data/sorbet/rbi/gems/rspec-mocks@3.12.3.rbi +5299 -0
  49. data/sorbet/rbi/gems/rspec-support@3.12.0.rbi +1611 -0
  50. data/sorbet/rbi/gems/rspec@3.12.0.rbi +82 -0
  51. data/sorbet/rbi/gems/rubocop-ast@1.27.0.rbi +6998 -0
  52. data/sorbet/rbi/gems/rubocop-performance@1.16.0.rbi +3004 -0
  53. data/sorbet/rbi/gems/rubocop@1.46.0.rbi +54549 -0
  54. data/sorbet/rbi/gems/ruby-progressbar@1.11.0.rbi +1239 -0
  55. data/sorbet/rbi/gems/spoom@1.1.15.rbi +2383 -0
  56. data/sorbet/rbi/gems/tapioca@0.11.1.rbi +3255 -0
  57. data/sorbet/rbi/gems/thor@1.2.1.rbi +3956 -0
  58. data/sorbet/rbi/gems/tzinfo@2.0.6.rbi +5917 -0
  59. data/sorbet/rbi/gems/unicode-display_width@2.4.2.rbi +65 -0
  60. data/sorbet/rbi/gems/unparser@0.6.7.rbi +4524 -0
  61. data/sorbet/rbi/gems/webrick@1.7.0.rbi +2555 -0
  62. data/sorbet/rbi/gems/yard-sorbet@0.8.0.rbi +441 -0
  63. data/sorbet/rbi/gems/yard@0.9.28.rbi +17841 -0
  64. data/sorbet/tapioca/config.yml +13 -0
  65. data/sorbet/tapioca/require.rb +4 -0
  66. metadata +75 -47
  67. data/.travis.yml +0 -6
@@ -1,84 +1,204 @@
1
- require 'ostruct'
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 "hierarchical_config/version"
10
+ require 'hierarchical_config/version'
7
11
 
8
12
  module HierarchicalConfig
9
13
  REQUIRED = :REQUIRED
10
- #this is the incantation that works for ruby 1.8.7 (syck)
11
- YAML.add_builtin_type( 'REQUIRED' ){ REQUIRED }
12
- #and this works for 1.9.3 (Psych)
13
- YAML.add_domain_type( nil, 'REQUIRED' ){ REQUIRED }
14
-
15
- class OpenStruct < ::OpenStruct
16
- def method_missing( mid, *args ) # :nodoc:
17
- mname = mid.id2name
18
- len = args.length
19
- if mname.chomp!('=')
20
- if len != 1
21
- raise ArgumentError, "wrong number of arguments (#{len} for 1)", caller(1)
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 do
28
+ type_parameters(:A, :B).
29
+ params(
30
+ blk: T.nilable(
31
+ T.proc.params(name: Symbol, value: T.untyped).
32
+ returns([T.type_parameter(:A), T.type_parameter(:B)]),
33
+ ),
34
+ ).
35
+ returns(
36
+ T.any(
37
+ T::Hash[T.type_parameter(:A), T.type_parameter(:B)],
38
+ T::Hash[Symbol, T.untyped],
39
+ ),
40
+ )
41
+ end
42
+ def to_h(&blk)
43
+ hash = self.class.props.keys.map{|key| [key, send(key)]}
44
+ if blk
45
+ # copied from https://github.com/marcandre/backports/blob/36572870cbdc0cda30e5bab81af8ba390a6cf7c7/lib/backports/2.6.0/hash/to_h.rb#L3C39-L3C39
46
+ # to implement to_h with block for ruby < 2.6.0
47
+ if {n: true}.to_h{[:ok, true]}[:n]
48
+ T.unsafe(hash).map(&blk).to_h
49
+ else
50
+ hash.to_h(&blk)
22
51
  end
23
- modifiable[new_ostruct_member(mname)] = args[0]
24
- elsif mname =~ /\?$/
25
- !!send(mname.gsub("?",""))
26
- elsif len == 0 && @table.key?( mid )
27
- @table[mid]
28
52
  else
29
- raise NoMethodError, "undefined method `#{mname}' for #{self}", caller(1)
53
+ hash.to_h
30
54
  end
31
55
  end
32
56
 
33
- def [](attribute)
34
- send(attribute)
57
+ sig{params(key: T.any(String, Symbol)).returns(T.untyped)}
58
+ def [](key)
59
+ send(key)
35
60
  end
36
61
 
37
- alias :each :each_pair
62
+ private
38
63
 
39
- def to_hash
40
- @table.inject({}) do |hash, key_value|
41
- key, value = *key_value
42
- hash[key] = item_to_hash(value)
43
- hash
64
+ sig{params(item: BasicObject).returns(T.any(BasicObject, T::Hash[T.untyped, T.untyped]))}
65
+ def item_to_hash(item)
66
+ case item
67
+ when ConfigStruct
68
+ item.to_hash
69
+ when Array
70
+ item.map{|i| item_to_hash(i)}
71
+ else
72
+ item
44
73
  end
45
74
  end
75
+ end
46
76
 
47
- private
77
+ @@root_index = T.let(0, Integer) # rubocop:disable Style/ClassVars
78
+
79
+ class << self
80
+ extend T::Sig
48
81
 
49
- def item_to_hash(value)
82
+ sig{params(value: T.untyped, path: String).returns(T::Array[String])}
83
+ def detect_errors(value, path)
84
+ errors = T.let([], T::Array[String])
50
85
  case value
86
+ when Hash
87
+ value.each do |key, item|
88
+ errors += detect_errors(item, "#{path}.#{key}")
89
+ end
90
+ when Array
91
+ value.each_with_index do |item, index|
92
+ errors += detect_errors(item, "#{path}[#{index}]")
93
+ end
94
+ when REQUIRED
95
+ errors << "#{path} is REQUIRED"
96
+ end
97
+ errors
98
+ end
99
+
100
+ sig{params(current_item: Object, name: String, parent_class: ClassOrModule).returns(T.any(Class, T::Types::Base))}
101
+ def build_types(current_item, name, parent_class)
102
+ case current_item
103
+ when Hash
104
+ new_type_name = inflect_typename(name)
105
+
106
+ return Hash if current_item.keys.to_a.any?{|k| k =~ /^[0-9]/ || k =~ /[- ]/}
107
+
108
+ new_type =
109
+ if parent_class.const_defined?(new_type_name, false)
110
+ parent_class.const_get(new_type_name, false)
111
+ else
112
+ parent_class.const_set(new_type_name, Class.new(T::Struct).tap{|c| c.include ConfigStruct})
113
+ end
114
+
115
+ current_item.each do |key, value|
116
+ next if new_type.props.key?(key.to_sym)
117
+
118
+ new_type.const key.to_sym, build_types(value, key, new_type)
119
+ new_type.send(:define_method, "#{key}?") do
120
+ !!send(key)
121
+ end
122
+ end
123
+
124
+ new_type
51
125
  when Array
52
- value.map{|item| item_to_hash(item)}
53
- when OpenStruct
54
- value.to_hash
126
+ types = current_item.each_with_index.map do |item, index|
127
+ build_types(item, "#{name}_#{index}", parent_class)
128
+ end
129
+ case types.size
130
+ when 0
131
+ T.untyped
132
+ when 1
133
+ T::Array[types.first]
134
+ else
135
+ T::Array[T.unsafe(T).any(*types)]
136
+ end
55
137
  else
56
- value
138
+ current_item.class
57
139
  end
58
140
  end
59
- end
60
141
 
61
- class << self
62
- def load_config( name, dir, environment, preprocess_with=:erb )
142
+ sig{params(current_item: Object, name: String, parent_class: ClassOrModule).returns(T.untyped)}
143
+ def build_config(current_item, name, parent_class)
144
+ case current_item
145
+ when Hash
146
+ return current_item.symbolize_keys if current_item.keys.to_a.any?{|k| k =~ /^[0-9]/ || k =~ /[- ]/}
147
+
148
+ current_type = parent_class.const_get(inflect_typename(name))
149
+ current_type.new(Hash[current_item.map{|key, value| [key.to_sym, build_config(value, key, current_type)]}]) # rubocop:disable Style/HashConversion
150
+ when Array
151
+ current_item.each_with_index.map do |item, index|
152
+ build_config(item, "#{name}_#{index}", parent_class)
153
+ end.freeze
154
+ else
155
+ current_item.freeze
156
+ end
157
+ end
158
+
159
+ sig{returns(Class)}
160
+ def build_new_root
161
+ @@root_index += 1 # rubocop:disable Style/ClassVars
162
+ const_set("ConfigRoot#{@@root_index}", Class.new)
163
+ end
164
+
165
+ sig do
166
+ params(
167
+ name: String,
168
+ dir: String,
169
+ environment: String,
170
+ preprocess_with: T.nilable(Symbol),
171
+ root_class: ClassOrModule,
172
+ ).returns(T::Struct)
173
+ end
174
+ def load_config(name, dir, environment, preprocess_with = :erb, root_class = build_new_root)
63
175
  primary_config_file = "#{dir}/#{name}.yml"
64
176
  overrides_config_file = "#{dir}/#{name}-overrides.yml"
65
177
 
66
- config_hash = load_hash_for_env( primary_config_file, environment, preprocess_with )
178
+ config_hash = load_hash_for_env(primary_config_file, environment, preprocess_with)
67
179
 
68
- if File.exists?( overrides_config_file )
69
- overrides_config_hash = load_hash_for_env( overrides_config_file, environment, preprocess_with )
70
- config_hash = deep_merge( config_hash, overrides_config_hash )
180
+ if File.exist?(overrides_config_file)
181
+ overrides_config_hash = load_hash_for_env(overrides_config_file, environment, preprocess_with)
182
+ config_hash = deep_merge(config_hash, overrides_config_hash)
71
183
  end
72
184
 
73
- config_hash, errors = lock_down_and_ostructify!( config_hash, name, environment )
185
+ errors = detect_errors(config_hash, name)
186
+ raise errors.map{|error| "#{error} for #{environment}"}.inspect unless errors.empty?
74
187
 
75
- raise errors.inspect unless errors.empty?
188
+ build_types(config_hash, name, root_class)
76
189
 
77
- config_hash
190
+ build_config(config_hash, name, root_class)
78
191
  end
79
192
 
80
- def load_hash_for_env( file, environment, preprocess_with )
81
- file_contents = IO.read(file)
193
+ sig do
194
+ params(
195
+ file: String,
196
+ environment: String,
197
+ preprocess_with: T.nilable(Symbol),
198
+ ).returns(T::Hash[String, BasicObject])
199
+ end
200
+ def load_hash_for_env(file, environment, preprocess_with)
201
+ file_contents = File.read(file)
82
202
  yaml_contents = case preprocess_with
83
203
  when :erb
84
204
  ERB.new(file_contents).result
@@ -87,103 +207,80 @@ module HierarchicalConfig
87
207
  else
88
208
  raise "Unknown preprocessor <#{preprocess_with}>"
89
209
  end
90
- yaml_config = YAML::load(yaml_contents)
210
+ yaml_config = YAML.safe_load(yaml_contents)
91
211
 
92
212
  ordered_stanza_labels = []
93
213
  ordered_stanza_labels << 'defaults' if yaml_config.key? 'defaults'
94
- ordered_stanza_labels += yaml_config.keys.grep(/^defaults\[.*#{environment}/).sort_by{ |a| a.count(',') }
214
+ ordered_stanza_labels += yaml_config.keys.grep(/^defaults\[.*#{environment}/).sort_by{|a| a.count(',')}
95
215
  ordered_stanza_labels << environment if yaml_config.key? environment
96
216
 
97
217
  config = deep_merge_hashes_in_keys(ordered_stanza_labels, yaml_config)
98
218
 
99
219
  env_config_labels = []
100
220
  env_config_labels << 'env_vars' if yaml_config.key? 'env_vars'
101
- env_config_labels += yaml_config.keys.grep(/^env_vars\[.*#{environment}/).sort_by{ |a| a.count(',') }
221
+ env_config_labels += yaml_config.keys.grep(/^env_vars\[.*#{environment}/).sort_by{|a| a.count(',')}
102
222
 
103
223
  env_config = deep_merge_hashes_in_keys(env_config_labels, yaml_config)
104
224
  env_config = fill_in_env_vars(env_config)
105
225
 
106
226
  deep_merge(config, env_config)
107
-
108
227
  rescue StandardError => e
109
228
  raise <<-ERROR
110
229
  Error loading config from file #{file}.
111
- #{$!.inspect}
112
- #{$@}
230
+ #{$ERROR_INFO.inspect}
231
+ #{$ERROR_POSITION}
232
+ #{e}
113
233
  ERROR
114
234
  end
115
235
 
116
236
  private
117
237
 
238
+ sig do
239
+ params(keys: T::Array[String],
240
+ root_hash: T::Hash[String,
241
+ T::Hash[String, T.untyped]]).returns(T::Hash[T.untyped, T.untyped])
242
+ end
118
243
  def deep_merge_hashes_in_keys(keys, root_hash)
119
244
  keys.inject({}) do |acc, label|
120
- deep_merge( acc, root_hash[label] )
245
+ deep_merge(acc, T.must(root_hash[label]))
121
246
  end
122
247
  end
123
248
 
249
+ sig{params(hash: T::Hash[T.untyped, T.untyped]).returns(T::Hash[T.untyped, T.untyped])}
124
250
  def fill_in_env_vars(hash)
125
251
  r = {}
126
- hash.each do |key,value|
252
+ hash.each do |key, value|
127
253
  if value.is_a? Hash
128
254
  leaf_hash = fill_in_env_vars(value)
129
- r[key]=leaf_hash unless leaf_hash.keys.empty?
255
+ r[key] = leaf_hash unless leaf_hash.keys.empty?
130
256
  elsif !value.nil? && ENV.key?(value)
131
- r[key]=ENV[value]
257
+ r[key] = ENV.fetch(value, nil)
132
258
  end
133
259
  end
134
260
  r
135
261
  end
136
262
 
137
263
  # merges two hashes with nested hashes if present
138
- def deep_merge( hash1, hash2 )
264
+ sig do
265
+ params(hash1: T::Hash[T.untyped, T.untyped],
266
+ hash2: T::Hash[T.untyped, T.untyped]).returns(T::Hash[T.untyped, T.untyped])
267
+ end
268
+ def deep_merge(hash1, hash2)
139
269
  hash1 = hash1.dup
140
- ( hash1.keys + hash2.keys ).each do | key |
141
- if hash1.key?( key ) && hash2.key?( key ) &&
142
- hash1[key].is_a?( Hash ) && hash2[key].is_a?( Hash )
143
- hash1[key] = deep_merge( hash1[key], hash2[key] )
144
- elsif hash2.key?( key )
270
+ (hash1.keys + hash2.keys).each do |key|
271
+ if hash1.key?(key) && hash2.key?(key) &&
272
+ hash1[key].is_a?(Hash) && hash2[key].is_a?(Hash)
273
+ hash1[key] = deep_merge(hash1[key], hash2[key])
274
+ elsif hash2.key?(key)
145
275
  hash1[key] = hash2[key]
146
276
  end
147
277
  end
148
278
  hash1
149
279
  end
150
280
 
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
281
+ sig{params(name: String).returns(String)}
282
+ def inflect_typename(name)
283
+ ActiveSupport::Inflector.camelize(name)
187
284
  end
188
285
  end
189
286
  end
@@ -0,0 +1,14 @@
1
+ {
2
+ "packages": {
3
+ ".": {
4
+ "changelog-path": "CHANGELOG.md",
5
+ "release-type": "ruby",
6
+ "bump-minor-pre-major": true,
7
+ "bump-patch-for-minor-pre-major": true,
8
+ "draft": false,
9
+ "prerelease": false,
10
+ "version-file": "lib/hierarchical_config/version.rb"
11
+ }
12
+ },
13
+ "$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json"
14
+ }
data/sorbet/config ADDED
@@ -0,0 +1,2 @@
1
+ --dir
2
+ .
@@ -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