ronin-core 0.1.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (109) hide show
  1. checksums.yaml +7 -0
  2. data/.document +5 -0
  3. data/.github/workflows/ruby.yml +41 -0
  4. data/.gitignore +12 -0
  5. data/.rspec +1 -0
  6. data/.rubocop.yml +160 -0
  7. data/.ruby-version +1 -0
  8. data/.yardopts +1 -0
  9. data/COPYING.txt +165 -0
  10. data/ChangeLog.md +11 -0
  11. data/Gemfile +30 -0
  12. data/README.md +299 -0
  13. data/Rakefile +34 -0
  14. data/examples/ruby_shell.rb +11 -0
  15. data/gemspec.yml +28 -0
  16. data/lib/ronin/core/class_registry.rb +246 -0
  17. data/lib/ronin/core/cli/command.rb +87 -0
  18. data/lib/ronin/core/cli/command_shell/command.rb +110 -0
  19. data/lib/ronin/core/cli/command_shell.rb +345 -0
  20. data/lib/ronin/core/cli/generator/options/author.rb +106 -0
  21. data/lib/ronin/core/cli/generator/options/description.rb +54 -0
  22. data/lib/ronin/core/cli/generator/options/reference.rb +60 -0
  23. data/lib/ronin/core/cli/generator/options/summary.rb +54 -0
  24. data/lib/ronin/core/cli/generator.rb +238 -0
  25. data/lib/ronin/core/cli/logging.rb +59 -0
  26. data/lib/ronin/core/cli/options/param.rb +68 -0
  27. data/lib/ronin/core/cli/options/values/arches.rb +45 -0
  28. data/lib/ronin/core/cli/options/values/oses.rb +32 -0
  29. data/lib/ronin/core/cli/printing/arch.rb +71 -0
  30. data/lib/ronin/core/cli/printing/metadata.rb +113 -0
  31. data/lib/ronin/core/cli/printing/os.rb +54 -0
  32. data/lib/ronin/core/cli/printing/params.rb +69 -0
  33. data/lib/ronin/core/cli/ruby_shell.rb +131 -0
  34. data/lib/ronin/core/cli/shell.rb +186 -0
  35. data/lib/ronin/core/git.rb +73 -0
  36. data/lib/ronin/core/home.rb +86 -0
  37. data/lib/ronin/core/metadata/authors/author.rb +241 -0
  38. data/lib/ronin/core/metadata/authors.rb +120 -0
  39. data/lib/ronin/core/metadata/description.rb +100 -0
  40. data/lib/ronin/core/metadata/id.rb +88 -0
  41. data/lib/ronin/core/metadata/references.rb +87 -0
  42. data/lib/ronin/core/metadata/summary.rb +78 -0
  43. data/lib/ronin/core/metadata/version.rb +74 -0
  44. data/lib/ronin/core/params/exceptions.rb +38 -0
  45. data/lib/ronin/core/params/mixin.rb +317 -0
  46. data/lib/ronin/core/params/param.rb +137 -0
  47. data/lib/ronin/core/params/types/boolean.rb +64 -0
  48. data/lib/ronin/core/params/types/enum.rb +107 -0
  49. data/lib/ronin/core/params/types/float.rb +68 -0
  50. data/lib/ronin/core/params/types/integer.rb +100 -0
  51. data/lib/ronin/core/params/types/numeric.rb +106 -0
  52. data/lib/ronin/core/params/types/regexp.rb +67 -0
  53. data/lib/ronin/core/params/types/string.rb +118 -0
  54. data/lib/ronin/core/params/types/type.rb +54 -0
  55. data/lib/ronin/core/params/types/uri.rb +72 -0
  56. data/lib/ronin/core/params/types.rb +62 -0
  57. data/lib/ronin/core/params.rb +19 -0
  58. data/lib/ronin/core/version.rb +24 -0
  59. data/ronin-core.gemspec +59 -0
  60. data/spec/class_registry_spec.rb +224 -0
  61. data/spec/cli/command_shell/command_spec.rb +113 -0
  62. data/spec/cli/command_shell_spec.rb +1114 -0
  63. data/spec/cli/command_spec.rb +16 -0
  64. data/spec/cli/fixtures/irb_command +8 -0
  65. data/spec/cli/fixtures/template/dir/file1.txt +1 -0
  66. data/spec/cli/fixtures/template/dir/file2.txt +1 -0
  67. data/spec/cli/fixtures/template/file.erb +1 -0
  68. data/spec/cli/fixtures/template/file.txt +1 -0
  69. data/spec/cli/generator/options/author_spec.rb +121 -0
  70. data/spec/cli/generator/options/description_spec.rb +45 -0
  71. data/spec/cli/generator/options/reference_spec.rb +53 -0
  72. data/spec/cli/generator/options/summary_spec.rb +45 -0
  73. data/spec/cli/generator_spec.rb +244 -0
  74. data/spec/cli/logging_spec.rb +95 -0
  75. data/spec/cli/options/param_spec.rb +67 -0
  76. data/spec/cli/options/values/arches_spec.rb +62 -0
  77. data/spec/cli/printing/arch_spec.rb +130 -0
  78. data/spec/cli/printing/metadata_spec.rb +211 -0
  79. data/spec/cli/printing/os_spec.rb +64 -0
  80. data/spec/cli/printing/params_spec.rb +63 -0
  81. data/spec/cli/ruby_shell.rb +99 -0
  82. data/spec/cli/shell_spec.rb +211 -0
  83. data/spec/fixtures/example_class_registry/base_class.rb +9 -0
  84. data/spec/fixtures/example_class_registry/classes/loaded_class.rb +9 -0
  85. data/spec/fixtures/example_class_registry/classes/name_mismatch.rb +9 -0
  86. data/spec/fixtures/example_class_registry/classes/no_module.rb +4 -0
  87. data/spec/fixtures/example_class_registry.rb +8 -0
  88. data/spec/git_spec.rb +58 -0
  89. data/spec/home_spec.rb +64 -0
  90. data/spec/metadata/authors/author_spec.rb +335 -0
  91. data/spec/metadata/authors_spec.rb +126 -0
  92. data/spec/metadata/description_spec.rb +74 -0
  93. data/spec/metadata/id_spec.rb +92 -0
  94. data/spec/metadata/references_spec.rb +100 -0
  95. data/spec/metadata/summary_spec.rb +74 -0
  96. data/spec/metadata/version_spec.rb +72 -0
  97. data/spec/params/mixin_spec.rb +484 -0
  98. data/spec/params/param_spec.rb +164 -0
  99. data/spec/params/types/boolean_spec.rb +56 -0
  100. data/spec/params/types/enum_spec.rb +94 -0
  101. data/spec/params/types/float_spec.rb +107 -0
  102. data/spec/params/types/integer_spec.rb +155 -0
  103. data/spec/params/types/numeric_spec.rb +138 -0
  104. data/spec/params/types/regexp_spec.rb +64 -0
  105. data/spec/params/types/string_spec.rb +174 -0
  106. data/spec/params/types/type_spec.rb +14 -0
  107. data/spec/params/types/uri_spec.rb +62 -0
  108. data/spec/spec_helper.rb +11 -0
  109. metadata +252 -0
@@ -0,0 +1,110 @@
1
+ # frozen_string_literal: true
2
+ #
3
+ # Copyright (c) 2021-2022 Hal Brodigan (postmodern.mod3 at gmail.com)
4
+ #
5
+ # ronin-core is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU Lesser General Public License as published
7
+ # by the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # ronin-core is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU Lesser General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU Lesser General Public License
16
+ # along with ronin-core. If not, see <https://www.gnu.org/licenses/>.
17
+ #
18
+
19
+ require 'ronin/core/cli/shell'
20
+
21
+ module Ronin
22
+ module Core
23
+ module CLI
24
+ class CommandShell < Shell
25
+ class Command
26
+
27
+ # The command's name.
28
+ #
29
+ # @return [Symbol]
30
+ attr_reader :name
31
+
32
+ # The command's method name.
33
+ #
34
+ # @return [Symbol]
35
+ attr_reader :method_name
36
+
37
+ # The usage string for the command's arguments.
38
+ #
39
+ # @return [String, nil]
40
+ attr_reader :usage
41
+
42
+ # Possible tab completion values for the command's arguments.
43
+ #
44
+ # @return [Array<String>, Symbol, nil]
45
+ attr_reader :completions
46
+
47
+ # The command's one-line summary.
48
+ #
49
+ # @return [String]
50
+ attr_reader :summary
51
+
52
+ # The command's multi-line help output.
53
+ #
54
+ # @return [String]
55
+ attr_reader :help
56
+
57
+ #
58
+ # Initializes a command value object.
59
+ #
60
+ # @param [Symbol] name
61
+ # The name of the command.
62
+ #
63
+ # @param [Symbol] method_name
64
+ # The command's method name. Defaults to the name argument.
65
+ #
66
+ # @param [String, nil] usage
67
+ # The usage string for the command's arguments.
68
+ #
69
+ # @param [Array<String>, Symbol, nil] completions
70
+ # Potential tab completion values, or a method name, to complete
71
+ # the command's arguments.
72
+ #
73
+ # @param [String] summary
74
+ # A single line summary for the command.
75
+ #
76
+ # @param [String] help
77
+ # Multi-line help information for the command.
78
+ #
79
+ def initialize(name, method_name: name,
80
+ usage: nil,
81
+ completions: nil,
82
+ summary: ,
83
+ help: summary)
84
+ @name = name
85
+ @method_name = method_name
86
+ @usage = usage
87
+ @summary = summary
88
+ @help = help
89
+ @completions = completions
90
+ end
91
+
92
+ #
93
+ # Converts the command to a String.
94
+ #
95
+ # @return [String]
96
+ # The command name and the optional usage.
97
+ #
98
+ def to_s
99
+ if @usage
100
+ "#{@name} #{@usage}"
101
+ else
102
+ @name.to_s
103
+ end
104
+ end
105
+
106
+ end
107
+ end
108
+ end
109
+ end
110
+ end
@@ -0,0 +1,345 @@
1
+ # frozen_string_literal: true
2
+ #
3
+ # Copyright (c) 2021-2022 Hal Brodigan (postmodern.mod3 at gmail.com)
4
+ #
5
+ # ronin-core is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU Lesser General Public License as published
7
+ # by the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # ronin-core is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU Lesser General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU Lesser General Public License
16
+ # along with ronin-core. If not, see <https://www.gnu.org/licenses/>.
17
+ #
18
+
19
+ require 'ronin/core/cli/shell'
20
+ require 'ronin/core/cli/command_shell/command'
21
+
22
+ require 'shellwords'
23
+
24
+ module Ronin
25
+ module Core
26
+ module CLI
27
+ #
28
+ # Base class for all custom command shells.
29
+ #
30
+ # ## Example
31
+ #
32
+ # class HTTPShell < Ronin::Core::CLI::Shell
33
+ #
34
+ # shell_name 'http'
35
+ #
36
+ # command :get, usage: 'PATH [HEADERS...]',
37
+ # summary: 'Sends a GET request'
38
+ # def get(path,*headers)
39
+ # # ...
40
+ # end
41
+ #
42
+ # command :post, usage: 'PATH DATA [HEADERS...]',
43
+ # summary: 'Sends a POST request'
44
+ # def post(path,data,*headers)
45
+ # # ...
46
+ # end
47
+ #
48
+ # end
49
+ #
50
+ # HTTPShell.start
51
+ # # http> get /foo
52
+ #
53
+ # @api semipublic
54
+ #
55
+ class CommandShell < Shell
56
+
57
+ #
58
+ # The registered shell commands.
59
+ #
60
+ # @return [Hash{String => CommandShell::Command}]
61
+ # The registered shell commands.
62
+ #
63
+ def self.commands
64
+ @commands ||= if superclass <= CommandShell
65
+ superclass.commands.dup
66
+ else
67
+ {}
68
+ end
69
+ end
70
+
71
+ #
72
+ # Registers a shell command.
73
+ #
74
+ # @param [Symbol] name
75
+ # The name of the shell command.
76
+ #
77
+ # @param [Symbol] method_name
78
+ # Optional method name to use. Defaults to the name argument.
79
+ #
80
+ # @param [String, nil] usage
81
+ # A usage string indicating the shell command's options/arguments.
82
+ #
83
+ # @param [Array<String>, Symbol, nil] completions
84
+ # The possible tab completion values, or a method name, to complete
85
+ # the command's arguments.
86
+ #
87
+ # @param [String] summary
88
+ # A one-line summary of the shell command.
89
+ #
90
+ # @param [String] help
91
+ # Multi-line help output for the shell command.
92
+ #
93
+ def self.command(name, method_name: name,
94
+ usage: nil,
95
+ completions: nil,
96
+ summary: ,
97
+ help: summary)
98
+ commands[name.to_s] = Command.new(name, method_name: method_name,
99
+ usage: usage,
100
+ completions: completions,
101
+ summary: summary,
102
+ help: help.strip)
103
+ end
104
+
105
+ #
106
+ # Parses a line of input.
107
+ #
108
+ # @param [String] line
109
+ # A line of input.
110
+ #
111
+ # @return [String, Array<String>]
112
+ # The command name and any additional arguments.
113
+ #
114
+ def self.parse_command(line)
115
+ Shellwords.shellsplit(line)
116
+ end
117
+
118
+ #
119
+ # The partially input being tab completed.
120
+ #
121
+ # @param [String] word
122
+ # The partial input being tab completed.
123
+ #
124
+ # @param [String] preposing
125
+ # The optional command name that preceeds the argument that's being
126
+ # tab completed.
127
+ #
128
+ # @return [Array<String>, nil]
129
+ # The possible completion values.
130
+ #
131
+ # @raise [NotImplementedError]
132
+ # The command defined a completion method name but the command shell
133
+ # does not define the complete method name.
134
+ #
135
+ def complete(word,preposing)
136
+ if preposing.empty?
137
+ self.class.commands.keys.select { |name| name.start_with?(word) }
138
+ else
139
+ name = preposing.split(/\s+/,2).first
140
+
141
+ if (command = self.class.commands[name])
142
+ completions = case command.completions
143
+ when Array then command.completions
144
+ when Symbol
145
+ unless respond_to?(command.completions)
146
+ raise(NotImplementedError,"#{self.class}##{command.completions} was not defined")
147
+ end
148
+
149
+ send(command.completions,word,preposing)
150
+ end
151
+
152
+ if completions
153
+ completions.select { |arg| arg.start_with?(word) }
154
+ end
155
+ end
156
+ end
157
+ end
158
+
159
+ #
160
+ # Executes a command.
161
+ #
162
+ # @param [String] command
163
+ # The command to execute.
164
+ #
165
+ # @return [Boolean]
166
+ # Indicates whether the command was successfully executed.
167
+ #
168
+ def exec(command)
169
+ call(*self.class.parse_command(command))
170
+ end
171
+
172
+ #
173
+ # Invokes the command with the matching name.
174
+ #
175
+ # @param [String] name
176
+ # The command name.
177
+ #
178
+ # @param [Array<String>] args
179
+ # Additional arguments for the command.
180
+ #
181
+ # @return [Boolean]
182
+ # Indicates whether the command was successfully executed.
183
+ #
184
+ # @raise [NotImplementedError]
185
+ # The method for the command was not defined.
186
+ #
187
+ def call(name,*args)
188
+ unless (command = self.class.commands[name])
189
+ return command_missing(name,*args)
190
+ end
191
+
192
+ method_name = command.method_name
193
+
194
+ unless respond_to?(method_name,false)
195
+ raise(NotImplementedError,"#{self.class}##{method_name} was not defined for the #{name.inspect} command")
196
+ end
197
+
198
+ unless method_arity_check(method_name,args)
199
+ return false
200
+ end
201
+
202
+ begin
203
+ send(method_name,*args)
204
+ rescue => error
205
+ print_exception(error)
206
+ print_error "an unhandled exception occurred in the #{name} command"
207
+ return false
208
+ end
209
+
210
+ return true
211
+ end
212
+
213
+ #
214
+ # Default method that is called when an unknown command is called.
215
+ #
216
+ # @param [String] name
217
+ #
218
+ # @param [Array<String>] args
219
+ #
220
+ def command_missing(name,*args)
221
+ command_not_found(name)
222
+ return false
223
+ end
224
+
225
+ #
226
+ # Prints an error message when an unknown command is given.
227
+ #
228
+ # @param [String] name
229
+ #
230
+ def command_not_found(name)
231
+ print_error "unknown command: #{name}"
232
+ end
233
+
234
+ command :help, usage: '[COMMAND]',
235
+ summary: 'Prints the list of commands or additional help'
236
+
237
+ #
238
+ # Prints all commands or help information for the given command.
239
+ #
240
+ # @param [String, nil] command
241
+ # Optional command name to print help information for.
242
+ #
243
+ def help(command=nil)
244
+ if command then help_command(command)
245
+ else help_commands
246
+ end
247
+ end
248
+
249
+ private
250
+
251
+ #
252
+ # Prints a list of all registered commands.
253
+ #
254
+ def help_commands
255
+ command_table = self.class.commands.map do |name,command|
256
+ [command.to_s, command.summary]
257
+ end
258
+
259
+ max_command_string = command_table.map { |command_string,summary|
260
+ command_string.length
261
+ }.max
262
+
263
+ command_table.each do |command_string,summary|
264
+ puts " #{command_string.ljust(max_command_string)}\t#{summary}"
265
+ end
266
+ end
267
+
268
+ #
269
+ # Prints help information about a specific command.
270
+ #
271
+ # @param [String] name
272
+ # The given command name.
273
+ #
274
+ def help_command(name)
275
+ unless (command = self.class.commands[name])
276
+ print_error "help: unknown command: #{name}"
277
+ return
278
+ end
279
+
280
+ puts "usage: #{command}"
281
+
282
+ if command.help
283
+ puts
284
+ puts command.help
285
+ end
286
+ end
287
+
288
+ #
289
+ # Calculates the minimum and maximum number of arguments for a given
290
+ # command method.
291
+ #
292
+ # @param [String] name
293
+ # The method name.
294
+ #
295
+ # @return [(Integer, Integer)]
296
+ # The minimum and maximum number of arguments for the method.
297
+ #
298
+ def minimum_maximum_args(name)
299
+ minimum = maximum = 0
300
+
301
+ method(name).parameters.each do |(type,arg)|
302
+ case type
303
+ when :req
304
+ minimum += 1
305
+ maximum += 1
306
+ when :opt then maximum += 1
307
+ when :rest then maximum = Float::INFINITY
308
+ end
309
+ end
310
+
311
+ return minimum, maximum
312
+ end
313
+
314
+ #
315
+ # Performs an arity check between the method's number of arguments and
316
+ # the number of arguments given.
317
+ #
318
+ # @param [String] name
319
+ # The method name to lookup.
320
+ #
321
+ # @param [Array<String>] args
322
+ # The given arguments.
323
+ #
324
+ # @return [Boolean]
325
+ # Indicates whether the method can accept the given number of
326
+ # arguments.
327
+ #
328
+ def method_arity_check(name,args)
329
+ minimum_args, maximum_args = minimum_maximum_args(name)
330
+
331
+ if args.length > maximum_args
332
+ print_error "#{name}: too many arguments given"
333
+ return false
334
+ elsif args.length < minimum_args
335
+ print_error "#{name}: too few arguments given"
336
+ return false
337
+ end
338
+
339
+ return true
340
+ end
341
+
342
+ end
343
+ end
344
+ end
345
+ end
@@ -0,0 +1,106 @@
1
+ # frozen_string_literal: true
2
+ #
3
+ # Copyright (c) 2021-2022 Hal Brodigan (postmodern.mod3 at gmail.com)
4
+ #
5
+ # ronin-core is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU Lesser General Public License as published
7
+ # by the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # ronin-core is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU Lesser General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU Lesser General Public License
16
+ # along with ronin-core. If not, see <https://www.gnu.org/licenses/>.
17
+ #
18
+
19
+ require 'ronin/core/git'
20
+
21
+ module Ronin
22
+ module Core
23
+ module CLI
24
+ module Generator
25
+ module Options
26
+ #
27
+ # Adds the `-a,--author NAME` and `-e,--author-email EMAIL` options
28
+ # for the generator command.
29
+ #
30
+ module Author
31
+
32
+ #
33
+ # The default author name.
34
+ #
35
+ # @return [String, nil]
36
+ #
37
+ def self.default_name
38
+ Core::Git.user_name || ENV['USERNAME']
39
+ end
40
+
41
+ #
42
+ # The default author email.
43
+ #
44
+ # @return [String, nil]
45
+ #
46
+ def self.default_email
47
+ Core::Git.user_email
48
+ end
49
+
50
+ #
51
+ # Defines the `-a,--author NAME` and `-e,--author-email EMAIL`
52
+ # options.
53
+ #
54
+ # @param [Class<Comand>] command
55
+ # The command class including {Author}.
56
+ #
57
+ def self.included(command)
58
+ command.option :author, short: '-a',
59
+ value: {
60
+ type: String,
61
+ usage: 'NAME',
62
+ default: ->{ default_name }
63
+ },
64
+ desc: 'The name of the author' do |author|
65
+ @author_name = author
66
+ end
67
+
68
+ command.option :author_email, short: '-e',
69
+ value: {
70
+ type: String,
71
+ usage: 'EMAIL',
72
+ default: ->{ default_email }
73
+ },
74
+ desc: 'The email address of the author' do |email|
75
+ @author_email = email
76
+ end
77
+ end
78
+
79
+ # The author name.
80
+ #
81
+ # @return [String]
82
+ attr_reader :author_name
83
+
84
+ # The author email.
85
+ #
86
+ # @return [String]
87
+ attr_reader :author_email
88
+
89
+ #
90
+ # Initializes {#author_name} and {#author_email}.
91
+ #
92
+ # @param [Hash{Symbol => Object}] kwargs
93
+ # Additional keyword arguments.
94
+ #
95
+ def initialize(**kwargs)
96
+ super(**kwargs)
97
+
98
+ @author_name = Author.default_name
99
+ @author_email = Author.default_email
100
+ end
101
+ end
102
+ end
103
+ end
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+ #
3
+ # Copyright (c) 2021-2022 Hal Brodigan (postmodern.mod3 at gmail.com)
4
+ #
5
+ # ronin-core is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU Lesser General Public License as published
7
+ # by the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # ronin-core is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU Lesser General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU Lesser General Public License
16
+ # along with ronin-core. If not, see <https://www.gnu.org/licenses/>.
17
+ #
18
+
19
+ module Ronin
20
+ module Core
21
+ module CLI
22
+ module Generator
23
+ module Options
24
+ #
25
+ # Adds the `-D,--description TEXT` option to the generator command.
26
+ #
27
+ module Description
28
+ #
29
+ # Defines the `-D,--description TEXT` option.
30
+ #
31
+ # @param [Class<Comand>] command
32
+ # The command class including {Description}.
33
+ #
34
+ def self.included(command)
35
+ command.option :description, short: '-D',
36
+ value: {
37
+ type: String,
38
+ usage: 'TEXT'
39
+ },
40
+ desc: 'A longer description' do |text|
41
+ @description = text
42
+ end
43
+ end
44
+
45
+ # The description text to output.
46
+ #
47
+ # @return [String, nil]
48
+ attr_reader :description
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+ #
3
+ # Copyright (c) 2021-2022 Hal Brodigan (postmodern.mod3 at gmail.com)
4
+ #
5
+ # ronin-core is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU Lesser General Public License as published
7
+ # by the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # ronin-core is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU Lesser General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU Lesser General Public License
16
+ # along with ronin-core. If not, see <https://www.gnu.org/licenses/>.
17
+ #
18
+
19
+ module Ronin
20
+ module Core
21
+ module CLI
22
+ module Generator
23
+ module Options
24
+ #
25
+ # Adds the `-R,--reference URL` option to the generator command.
26
+ #
27
+ module Reference
28
+ def self.included(command)
29
+ command.option :reference, short: '-R',
30
+ value: {
31
+ type: String,
32
+ usage: 'URL'
33
+ },
34
+ desc: 'Adds a reference URL' do |url|
35
+ @references << url
36
+ end
37
+ end
38
+
39
+ # The reference URLs to output.
40
+ #
41
+ # @return [Array<String>]
42
+ attr_reader :references
43
+
44
+ #
45
+ # Initializes {#references}.
46
+ #
47
+ # @param [Hash{Symbol => Object}] kwargs
48
+ # Additional keyword arguments.
49
+ #
50
+ def initialize(**kwargs)
51
+ super(**kwargs)
52
+
53
+ @references = []
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end