gorails 0.1.2 → 0.1.5

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 +4 -4
  2. data/CHANGELOG.md +18 -1
  3. data/Gemfile.lock +1 -6
  4. data/bin/update-deps +95 -0
  5. data/exe/gorails +2 -1
  6. data/gorails.gemspec +0 -2
  7. data/lib/gorails/commands/railsbytes.rb +10 -10
  8. data/lib/gorails/commands/version.rb +15 -0
  9. data/lib/gorails/commands.rb +2 -5
  10. data/lib/gorails/version.rb +1 -1
  11. data/lib/gorails.rb +11 -20
  12. data/vendor/deps/cli-kit/REVISION +1 -0
  13. data/vendor/deps/cli-kit/lib/cli/kit/args/definition.rb +301 -0
  14. data/vendor/deps/cli-kit/lib/cli/kit/args/evaluation.rb +237 -0
  15. data/vendor/deps/cli-kit/lib/cli/kit/args/parser/node.rb +131 -0
  16. data/vendor/deps/cli-kit/lib/cli/kit/args/parser.rb +128 -0
  17. data/vendor/deps/cli-kit/lib/cli/kit/args/tokenizer.rb +132 -0
  18. data/vendor/deps/cli-kit/lib/cli/kit/args.rb +15 -0
  19. data/vendor/deps/cli-kit/lib/cli/kit/base_command.rb +29 -0
  20. data/vendor/deps/cli-kit/lib/cli/kit/command_help.rb +256 -0
  21. data/vendor/deps/cli-kit/lib/cli/kit/command_registry.rb +141 -0
  22. data/vendor/deps/cli-kit/lib/cli/kit/config.rb +137 -0
  23. data/vendor/deps/cli-kit/lib/cli/kit/core_ext.rb +30 -0
  24. data/vendor/deps/cli-kit/lib/cli/kit/error_handler.rb +165 -0
  25. data/vendor/deps/cli-kit/lib/cli/kit/executor.rb +99 -0
  26. data/vendor/deps/cli-kit/lib/cli/kit/ini.rb +94 -0
  27. data/vendor/deps/cli-kit/lib/cli/kit/levenshtein.rb +89 -0
  28. data/vendor/deps/cli-kit/lib/cli/kit/logger.rb +95 -0
  29. data/vendor/deps/cli-kit/lib/cli/kit/opts.rb +284 -0
  30. data/vendor/deps/cli-kit/lib/cli/kit/resolver.rb +67 -0
  31. data/vendor/deps/cli-kit/lib/cli/kit/sorbet_runtime_stub.rb +142 -0
  32. data/vendor/deps/cli-kit/lib/cli/kit/support/test_helper.rb +253 -0
  33. data/vendor/deps/cli-kit/lib/cli/kit/support.rb +10 -0
  34. data/vendor/deps/cli-kit/lib/cli/kit/system.rb +350 -0
  35. data/vendor/deps/cli-kit/lib/cli/kit/util.rb +133 -0
  36. data/vendor/deps/cli-kit/lib/cli/kit/version.rb +7 -0
  37. data/vendor/deps/cli-kit/lib/cli/kit.rb +151 -0
  38. data/vendor/deps/cli-ui/REVISION +1 -0
  39. data/vendor/deps/cli-ui/lib/cli/ui/ansi.rb +180 -0
  40. data/vendor/deps/cli-ui/lib/cli/ui/color.rb +98 -0
  41. data/vendor/deps/cli-ui/lib/cli/ui/formatter.rb +216 -0
  42. data/vendor/deps/cli-ui/lib/cli/ui/frame/frame_stack.rb +116 -0
  43. data/vendor/deps/cli-ui/lib/cli/ui/frame/frame_style/box.rb +176 -0
  44. data/vendor/deps/cli-ui/lib/cli/ui/frame/frame_style/bracket.rb +149 -0
  45. data/vendor/deps/cli-ui/lib/cli/ui/frame/frame_style.rb +112 -0
  46. data/vendor/deps/cli-ui/lib/cli/ui/frame.rb +300 -0
  47. data/vendor/deps/cli-ui/lib/cli/ui/glyph.rb +92 -0
  48. data/vendor/deps/cli-ui/lib/cli/ui/os.rb +58 -0
  49. data/vendor/deps/cli-ui/lib/cli/ui/printer.rb +72 -0
  50. data/vendor/deps/cli-ui/lib/cli/ui/progress.rb +102 -0
  51. data/vendor/deps/cli-ui/lib/cli/ui/prompt/interactive_options.rb +534 -0
  52. data/vendor/deps/cli-ui/lib/cli/ui/prompt/options_handler.rb +36 -0
  53. data/vendor/deps/cli-ui/lib/cli/ui/prompt.rb +354 -0
  54. data/vendor/deps/cli-ui/lib/cli/ui/sorbet_runtime_stub.rb +143 -0
  55. data/vendor/deps/cli-ui/lib/cli/ui/spinner/async.rb +46 -0
  56. data/vendor/deps/cli-ui/lib/cli/ui/spinner/spin_group.rb +292 -0
  57. data/vendor/deps/cli-ui/lib/cli/ui/spinner.rb +82 -0
  58. data/vendor/deps/cli-ui/lib/cli/ui/stdout_router.rb +264 -0
  59. data/vendor/deps/cli-ui/lib/cli/ui/terminal.rb +53 -0
  60. data/vendor/deps/cli-ui/lib/cli/ui/truncater.rb +107 -0
  61. data/vendor/deps/cli-ui/lib/cli/ui/version.rb +6 -0
  62. data/vendor/deps/cli-ui/lib/cli/ui/widgets/base.rb +37 -0
  63. data/vendor/deps/cli-ui/lib/cli/ui/widgets/status.rb +75 -0
  64. data/vendor/deps/cli-ui/lib/cli/ui/widgets.rb +91 -0
  65. data/vendor/deps/cli-ui/lib/cli/ui/wrap.rb +63 -0
  66. data/vendor/deps/cli-ui/lib/cli/ui.rb +356 -0
  67. metadata +58 -29
@@ -0,0 +1,256 @@
1
+ # typed: true
2
+ require 'cli/kit'
3
+
4
+ module CLI
5
+ module Kit
6
+ module CommandHelp
7
+ extend T::Sig
8
+ include Kernel # for sorbet
9
+
10
+ sig { params(args: T::Array[String], name: String).void }
11
+ def call(args, name)
12
+ begin
13
+ defn = Args::Definition.new
14
+ opts = self.class.opts_class
15
+ opts.new(defn).install_to_definition
16
+ tokens = Args::Tokenizer.tokenize(args)
17
+ parse = Args::Parser.new(defn).parse(tokens)
18
+ result = Args::Evaluation.new(defn, parse)
19
+ opts_inst = opts.new(result)
20
+ rescue Args::Evaluation::TooManyPositions, Args::Evaluation::MissingRequiredPosition => e
21
+ STDERR.puts CLI::UI.fmt("{{red:{{bold:Error: #{e.message}}}}}")
22
+ STDERR.puts
23
+ STDERR.puts self.class.build_help
24
+ raise(AbortSilent)
25
+ rescue Args::Error => e
26
+ raise(Abort, e)
27
+ end
28
+
29
+ if opts_inst.helpflag
30
+ puts self.class.build_help
31
+ else
32
+ res = begin
33
+ opts.new(result)
34
+ rescue Args::Error => e
35
+ raise(Abort, e)
36
+ end
37
+ invoke_wrapper(res, name)
38
+ end
39
+ end
40
+
41
+ # use to implement error handling
42
+ sig { params(op: T.untyped, name: String).void }
43
+ def invoke_wrapper(op, name)
44
+ invoke(op, name)
45
+ end
46
+
47
+ sig { params(op: T.untyped, name: String).void }
48
+ def invoke(op, name)
49
+ raise(NotImplementedError, '#invoke must be implemented, or #call overridden')
50
+ end
51
+
52
+ sig { params(name: String).void }
53
+ def self.tool_name=(name)
54
+ @tool_name = name
55
+ end
56
+
57
+ sig { returns(String) }
58
+ def self._tool_name
59
+ unless @tool_name
60
+ raise 'You must set CLI::Kit::CommandHelp.tool_name='
61
+ end
62
+
63
+ @tool_name
64
+ end
65
+
66
+ module ClassMethods
67
+ extend T::Sig
68
+ include Kernel # for sorbet
69
+
70
+ DEFAULT_HELP_SECTIONS = [
71
+ :desc,
72
+ :long_desc,
73
+ :usage,
74
+ :examples,
75
+ :options,
76
+ ]
77
+
78
+ sig { returns(String) }
79
+ def build_help
80
+ h = (@help_sections || DEFAULT_HELP_SECTIONS).map do |section|
81
+ case section
82
+ when :desc
83
+ build_desc
84
+ when :long_desc
85
+ @long_desc
86
+ when :usage
87
+ @usage_section ||= build_usage
88
+ when :examples
89
+ @examples_section ||= build_examples
90
+ when :options
91
+ @options_section ||= build_options
92
+ else
93
+ raise "Unknown help section: #{section}"
94
+ end
95
+ end.compact.map(&:chomp).join("\n\n") + "\n"
96
+ CLI::UI.fmt(h)
97
+ end
98
+
99
+ sig { returns(String) }
100
+ def _command_name
101
+ return @command_name if @command_name
102
+
103
+ last_camel = send(:name).split('::').last
104
+ last_camel.gsub(/([a-z])([A-Z])/, '\1-\2').downcase
105
+ end
106
+
107
+ sig { returns(String) }
108
+ def _desc
109
+ @desc
110
+ end
111
+
112
+ sig { returns(String) }
113
+ def build_desc
114
+ out = +"{{command:#{CommandHelp._tool_name} #{_command_name}}}"
115
+ if @desc
116
+ out << ": #{@desc}"
117
+ end
118
+ "{{bold:#{out}}}"
119
+ end
120
+
121
+ sig { returns(T.untyped) }
122
+ def opts_class
123
+ T.unsafe(self).const_get(:Opts) # rubocop:disable Sorbet/ConstantsFromStrings
124
+ rescue NameError
125
+ Class.new(CLI::Kit::Opts)
126
+ end
127
+
128
+ sig { returns(T.nilable(String)) }
129
+ def build_options
130
+ opts = opts_class
131
+ return(nil) unless opts
132
+
133
+ methods = []
134
+ loop do
135
+ methods.concat(opts.public_instance_methods(false))
136
+ break if opts.superclass == CLI::Kit::Opts
137
+
138
+ opts = opts.superclass
139
+ end
140
+
141
+ @defn = Args::Definition.new
142
+ o = opts.new(@defn)
143
+ o.install_to_definition
144
+
145
+ return nil if @defn.options.empty? && @defn.flags.empty?
146
+
147
+ merged = T.let(@defn.options, T::Array[T.any(Args::Definition::Option, Args::Definition::Flag)])
148
+ merged += @defn.flags
149
+ merged.sort_by!(&:name)
150
+ "{{bold:Options:}}\n" + merged.map do |o|
151
+ if o.is_a?(Args::Definition::Option)
152
+ z = ' ' + [o.short&.prepend('-'), o.long&.prepend('--')].compact.join(', ') + ' VALUE'
153
+ default = if o.dynamic_default?
154
+ '(generated default)'
155
+ elsif o.default.nil?
156
+ '(no default)'
157
+ else
158
+ "(default: #{o.default.inspect})"
159
+ end
160
+ z << if o.desc
161
+ " {{italic:{{gray:# #{o.desc} #{default}}}}}"
162
+ else
163
+ " {{italic:{{gray:# #{default}}}}}"
164
+ end
165
+ else
166
+ z = ' ' + [o.short&.prepend('-'), o.long&.prepend('--')].compact.join(', ')
167
+ if o.desc
168
+ z << " {{italic:{{gray:# #{o.desc}}}}}"
169
+ end
170
+ end
171
+ z
172
+ end.join("\n")
173
+ end
174
+
175
+ sig { params(sections: T::Array[Symbol]).void }
176
+ def help_sections(sections)
177
+ @help_sections = sections
178
+ end
179
+
180
+ sig { params(command_name: String).void }
181
+ def command_name(command_name)
182
+ if @command_name
183
+ raise(ArgumentError, "Command name already set to #{@command_name}")
184
+ end
185
+
186
+ @command_name = command_name
187
+ end
188
+
189
+ sig { params(desc: String).void }
190
+ def desc(desc)
191
+ if desc.size > 80
192
+ raise(ArgumentError, 'description must be 80 characters or less')
193
+ end
194
+ if @desc
195
+ raise(ArgumentError, 'description already set')
196
+ end
197
+
198
+ @desc = desc
199
+ end
200
+
201
+ sig { params(long_desc: String).void }
202
+ def long_desc(long_desc)
203
+ if @long_desc
204
+ raise(ArgumentError, 'long description already set')
205
+ end
206
+
207
+ @long_desc = long_desc
208
+ end
209
+
210
+ sig { returns(String) }
211
+ def build_usage
212
+ '{{bold:Usage:}}' + case (@usage || []).size
213
+ when 0
214
+ " {{command:#{CommandHelp._tool_name} #{_command_name}}} [options]\n"
215
+ when 1
216
+ " {{command:#{CommandHelp._tool_name} #{_command_name}}} #{@usage.first}\n"
217
+ else
218
+ "\n" + @usage.map do |usage|
219
+ " {{command:#{CommandHelp._tool_name} #{_command_name}}} #{usage}\n"
220
+ end.join
221
+ end
222
+ end
223
+
224
+ sig { returns(T.nilable(String)) }
225
+ def build_examples
226
+ return nil unless @examples
227
+
228
+ cmd_prefix = " {{command:#{CommandHelp._tool_name} #{_command_name}}}"
229
+ "{{bold:Examples:}}\n" + @examples.map do |command, explanation|
230
+ cmd = "#{cmd_prefix} #{command}"
231
+ exp = "{{italic:{{gray:# #{explanation}}}}}"
232
+
233
+ width = CLI::UI::ANSI.printing_width(CLI::UI.fmt("#{cmd} #{exp}"))
234
+ if width > CLI::UI::Terminal.width
235
+ " #{exp}\n#{cmd}"
236
+ else
237
+ "#{cmd} #{exp}"
238
+ end
239
+ end.join("\n\n")
240
+ end
241
+
242
+ sig { params(usage: String).void }
243
+ def usage(usage)
244
+ @usage ||= []
245
+ @usage << usage
246
+ end
247
+
248
+ sig { params(command: String, explanation: T.nilable(String)).void }
249
+ def example(command, explanation)
250
+ @examples ||= []
251
+ @examples << [command, explanation]
252
+ end
253
+ end
254
+ end
255
+ end
256
+ end
@@ -0,0 +1,141 @@
1
+ # typed: true
2
+ require 'cli/kit'
3
+
4
+ module CLI
5
+ module Kit
6
+ class CommandRegistry
7
+ extend T::Sig
8
+
9
+ CommandOrProc = T.type_alias do
10
+ T.any(T.class_of(CLI::Kit::BaseCommand), T.proc.returns(T.class_of(CLI::Kit::BaseCommand)))
11
+ end
12
+
13
+ sig { returns(T::Hash[String, CommandOrProc]) }
14
+ attr_reader :commands
15
+
16
+ sig { returns(T::Hash[String, String]) }
17
+ attr_reader :aliases
18
+
19
+ module ContextualResolver
20
+ extend T::Sig
21
+ extend T::Helpers
22
+ interface!
23
+
24
+ sig { abstract.returns(T::Array[String]) }
25
+ def command_names; end
26
+
27
+ sig { abstract.returns(T::Hash[String, String]) }
28
+ def aliases; end
29
+
30
+ sig { abstract.params(_name: String).returns(T.class_of(CLI::Kit::BaseCommand)) }
31
+ def command_class(_name); end
32
+ end
33
+
34
+ module NullContextualResolver
35
+ extend T::Sig
36
+ extend ContextualResolver
37
+
38
+ sig { override.returns(T::Array[String]) }
39
+ def self.command_names
40
+ []
41
+ end
42
+
43
+ sig { override.returns(T::Hash[String, String]) }
44
+ def self.aliases
45
+ {}
46
+ end
47
+
48
+ sig { override.params(_name: String).returns(T.class_of(CLI::Kit::BaseCommand)) }
49
+ def self.command_class(_name)
50
+ raise(CLI::Kit::Abort, 'Cannot be called on the NullContextualResolver since command_names is empty')
51
+ end
52
+ end
53
+
54
+ sig { params(default: String, contextual_resolver: ContextualResolver).void }
55
+ def initialize(default:, contextual_resolver: NullContextualResolver)
56
+ @commands = {}
57
+ @aliases = {}
58
+ @default = default
59
+ @contextual_resolver = contextual_resolver
60
+ end
61
+
62
+ sig { returns(T::Hash[String, T.class_of(CLI::Kit::BaseCommand)]) }
63
+ def resolved_commands
64
+ @commands.each_with_object({}) do |(k, v), a|
65
+ a[k] = resolve_class(v)
66
+ end
67
+ end
68
+
69
+ sig { params(const: CommandOrProc, name: String).void }
70
+ def add(const, name)
71
+ commands[name] = const
72
+ end
73
+
74
+ sig { params(name: T.nilable(String)).returns([T.nilable(T.class_of(CLI::Kit::BaseCommand)), String]) }
75
+ def lookup_command(name)
76
+ name = @default if name.to_s.empty?
77
+ resolve_command(T.must(name))
78
+ end
79
+
80
+ sig { params(from: String, to: String).void }
81
+ def add_alias(from, to)
82
+ aliases[from] = to unless aliases[from]
83
+ end
84
+
85
+ sig { returns(T::Array[String]) }
86
+ def command_names
87
+ @contextual_resolver.command_names + commands.keys
88
+ end
89
+
90
+ sig { params(name: String).returns(T::Boolean) }
91
+ def exist?(name)
92
+ !resolve_command(name).first.nil?
93
+ end
94
+
95
+ private
96
+
97
+ sig { params(name: String).returns(String) }
98
+ def resolve_alias(name)
99
+ aliases[name] || @contextual_resolver.aliases.fetch(name, name)
100
+ end
101
+
102
+ sig { params(name: String).returns([T.nilable(T.class_of(CLI::Kit::BaseCommand)), String]) }
103
+ def resolve_command(name)
104
+ name = resolve_alias(name)
105
+ resolve_global_command(name) || \
106
+ resolve_contextual_command(name) || \
107
+ [nil, name]
108
+ end
109
+
110
+ sig { params(name: String).returns(T.nilable([T.class_of(CLI::Kit::BaseCommand), String])) }
111
+ def resolve_global_command(name)
112
+ klass = resolve_class(commands.fetch(name, nil))
113
+ return nil unless klass
114
+
115
+ [klass, name]
116
+ rescue NameError
117
+ nil
118
+ end
119
+
120
+ sig { params(name: String).returns(T.nilable([T.class_of(CLI::Kit::BaseCommand), String])) }
121
+ def resolve_contextual_command(name)
122
+ found = @contextual_resolver.command_names.include?(name)
123
+ return nil unless found
124
+
125
+ [@contextual_resolver.command_class(name), name]
126
+ end
127
+
128
+ sig { params(class_or_proc: T.nilable(CommandOrProc)).returns(T.nilable(T.class_of(CLI::Kit::BaseCommand))) }
129
+ def resolve_class(class_or_proc)
130
+ case class_or_proc
131
+ when nil
132
+ nil
133
+ when Proc
134
+ class_or_proc.call
135
+ else
136
+ class_or_proc
137
+ end
138
+ end
139
+ end
140
+ end
141
+ end
@@ -0,0 +1,137 @@
1
+ # typed: true
2
+ require 'cli/kit'
3
+ require 'fileutils'
4
+
5
+ module CLI
6
+ module Kit
7
+ class Config
8
+ extend T::Sig
9
+
10
+ XDG_CONFIG_HOME = 'XDG_CONFIG_HOME'
11
+
12
+ sig { params(tool_name: String).void }
13
+ def initialize(tool_name:)
14
+ @tool_name = tool_name
15
+ end
16
+
17
+ # Returns the config corresponding to `name` from the config file
18
+ # `false` is returned if it doesn't exist
19
+ #
20
+ # #### Parameters
21
+ # `section` : the section of the config value you are looking for
22
+ # `name` : the name of the config value you are looking for
23
+ #
24
+ # #### Returns
25
+ # `value` : the value of the config variable (nil if none)
26
+ #
27
+ # #### Example Usage
28
+ # `config.get('name.of.config')`
29
+ #
30
+ sig { params(section: String, name: String, default: T.nilable(String)).returns(T.nilable(String)) }
31
+ def get(section, name, default: nil)
32
+ all_configs.dig("[#{section}]", name) || default
33
+ end
34
+
35
+ # Coalesce and enforce the value of a config to a boolean
36
+ sig { params(section: String, name: String, default: T.nilable(T::Boolean)).returns(T.nilable(T::Boolean)) }
37
+ def get_bool(section, name, default: false)
38
+ case get(section, name)
39
+ when 'true'
40
+ true
41
+ when 'false'
42
+ false
43
+ when nil
44
+ default
45
+ else
46
+ raise CLI::Kit::Abort, "Invalid config: #{section}.#{name} is expected to be true or false"
47
+ end
48
+ end
49
+
50
+ # Sets the config value in the config file
51
+ #
52
+ # #### Parameters
53
+ # `section` : the section of the config you are setting
54
+ # `name` : the name of the config you are setting
55
+ # `value` : the value of the config you are setting
56
+ #
57
+ # #### Example Usage
58
+ # `config.set('section', 'name.of.config', 'value')`
59
+ #
60
+ sig { params(section: String, name: String, value: T.nilable(T.any(String, T::Boolean))).void }
61
+ def set(section, name, value)
62
+ all_configs["[#{section}]"] ||= {}
63
+ case value
64
+ when nil
65
+ T.must(all_configs["[#{section}]"]).delete(name)
66
+ else
67
+ T.must(all_configs["[#{section}]"])[name] = value.to_s
68
+ end
69
+ write_config
70
+ end
71
+
72
+ # Unsets a config value in the config file
73
+ #
74
+ # #### Parameters
75
+ # `section` : the section of the config you are deleting
76
+ # `name` : the name of the config you are deleting
77
+ #
78
+ # #### Example Usage
79
+ # `config.unset('section', 'name.of.config')`
80
+ #
81
+ sig { params(section: String, name: String).void }
82
+ def unset(section, name)
83
+ set(section, name, nil)
84
+ end
85
+
86
+ # Gets the hash for the entire section
87
+ #
88
+ # #### Parameters
89
+ # `section` : the section of the config you are getting
90
+ #
91
+ # #### Example Usage
92
+ # `config.get_section('section')`
93
+ #
94
+ sig { params(section: String).returns(T::Hash[String, String]) }
95
+ def get_section(section)
96
+ (all_configs["[#{section}]"] || {}).dup
97
+ end
98
+
99
+ sig { returns(String) }
100
+ def to_s
101
+ ini.to_s
102
+ end
103
+
104
+ # The path on disk at which the configuration is stored:
105
+ # `$XDG_CONFIG_HOME/<toolname>/config`
106
+ # if ENV['XDG_CONFIG_HOME'] is not set, we default to ~/.config, e.g.:
107
+ # ~/.config/tool/config
108
+ #
109
+ sig { returns(String) }
110
+ def file
111
+ config_home = ENV.fetch(XDG_CONFIG_HOME, '~/.config')
112
+ File.expand_path(File.join(@tool_name, 'config'), config_home)
113
+ end
114
+
115
+ private
116
+
117
+ sig { returns(T::Hash[String, T::Hash[String, String]]) }
118
+ def all_configs
119
+ ini.ini
120
+ end
121
+
122
+ sig { returns(CLI::Kit::Ini) }
123
+ def ini
124
+ @ini ||= CLI::Kit::Ini.new(file).tap(&:parse)
125
+ end
126
+
127
+ sig { void }
128
+ def write_config
129
+ all_configs.each do |section, sub_config|
130
+ all_configs.delete(section) if sub_config.empty?
131
+ end
132
+ FileUtils.mkdir_p(File.dirname(file))
133
+ File.write(file, to_s)
134
+ end
135
+ end
136
+ end
137
+ end
@@ -0,0 +1,30 @@
1
+ # typed: strong
2
+ # frozen_string_literal: true
3
+
4
+ class Exception
5
+ extend(T::Sig)
6
+
7
+ # You'd think instance variables @bug and @silent would work here. They
8
+ # don't. I'm not sure why. If you, the reader, want to take some time to
9
+ # figure it out, go ahead and refactor to that.
10
+
11
+ sig { returns(T::Boolean) }
12
+ def bug?
13
+ true
14
+ end
15
+
16
+ sig { returns(T::Boolean) }
17
+ def silent?
18
+ false
19
+ end
20
+
21
+ sig { params(bug: T::Boolean).void }
22
+ def bug!(bug = true)
23
+ singleton_class.define_method(:bug?) { bug }
24
+ end
25
+
26
+ sig { params(silent: T::Boolean).void }
27
+ def silent!(silent = true)
28
+ singleton_class.define_method(:silent?) { silent }
29
+ end
30
+ end