bovem 2.4.1 → 3.0.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 (70) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -1
  3. data/Gemfile +1 -1
  4. data/README.md +98 -2
  5. data/bovem.gemspec +3 -3
  6. data/doc/Bovem.html +25 -6
  7. data/doc/Bovem/Application.html +3057 -0
  8. data/doc/Bovem/Command.html +7031 -0
  9. data/doc/Bovem/CommandMethods.html +125 -0
  10. data/doc/Bovem/CommandMethods/Children.html +1285 -0
  11. data/doc/Bovem/CommandMethods/Help.html +209 -0
  12. data/doc/Bovem/Configuration.html +3 -3
  13. data/doc/Bovem/Console.html +8 -8
  14. data/doc/Bovem/ConsoleMethods.html +3 -3
  15. data/doc/Bovem/ConsoleMethods/Interactions.html +3 -3
  16. data/doc/Bovem/ConsoleMethods/Interactions/ClassMethods.html +3 -3
  17. data/doc/Bovem/ConsoleMethods/Logging.html +4 -4
  18. data/doc/Bovem/ConsoleMethods/Logging/ClassMethods.html +3 -3
  19. data/doc/Bovem/ConsoleMethods/Output.html +3 -3
  20. data/doc/Bovem/ConsoleMethods/StyleHandling.html +4 -4
  21. data/doc/Bovem/ConsoleMethods/StyleHandling/ClassMethods.html +8 -8
  22. data/doc/Bovem/Errors.html +4 -4
  23. data/doc/Bovem/Errors/Error.html +631 -0
  24. data/doc/Bovem/Errors/InvalidConfiguration.html +3 -3
  25. data/doc/Bovem/Errors/InvalidLogger.html +3 -3
  26. data/doc/Bovem/Localizer.html +376 -0
  27. data/doc/Bovem/Logger.html +64 -160
  28. data/doc/Bovem/Option.html +7009 -0
  29. data/doc/Bovem/Parser.html +276 -0
  30. data/doc/Bovem/ParserMethods.html +125 -0
  31. data/doc/Bovem/ParserMethods/General.html +134 -0
  32. data/doc/Bovem/ParserMethods/General/ClassMethods.html +574 -0
  33. data/doc/Bovem/Shell.html +8 -8
  34. data/doc/Bovem/ShellMethods.html +3 -3
  35. data/doc/Bovem/ShellMethods/Directories.html +3 -3
  36. data/doc/Bovem/ShellMethods/Execute.html +3 -3
  37. data/doc/Bovem/ShellMethods/General.html +3 -3
  38. data/doc/Bovem/ShellMethods/Read.html +3 -3
  39. data/doc/Bovem/ShellMethods/Write.html +3 -3
  40. data/doc/Bovem/Version.html +6 -6
  41. data/doc/_index.html +119 -11
  42. data/doc/class_list.html +1 -1
  43. data/doc/file.README.html +98 -5
  44. data/doc/frames.html +1 -1
  45. data/doc/index.html +98 -5
  46. data/doc/method_list.html +476 -26
  47. data/doc/top-level-namespace.html +3 -3
  48. data/lib/bovem.rb +8 -1
  49. data/lib/bovem/application.rb +158 -0
  50. data/lib/bovem/command.rb +529 -0
  51. data/lib/bovem/console.rb +8 -8
  52. data/lib/bovem/errors.rb +27 -0
  53. data/lib/bovem/localizer.rb +27 -0
  54. data/lib/bovem/logger.rb +2 -8
  55. data/lib/bovem/option.rb +250 -0
  56. data/lib/bovem/parser.rb +317 -0
  57. data/lib/bovem/shell.rb +2 -2
  58. data/lib/bovem/version.rb +3 -3
  59. data/locales/en.yml +33 -0
  60. data/locales/it.yml +33 -0
  61. data/spec/bovem/application_spec.rb +170 -0
  62. data/spec/bovem/command_spec.rb +526 -0
  63. data/spec/bovem/configuration_spec.rb +4 -4
  64. data/spec/bovem/console_spec.rb +22 -22
  65. data/spec/bovem/errors_spec.rb +18 -0
  66. data/spec/bovem/logger_spec.rb +22 -12
  67. data/spec/bovem/option_spec.rb +307 -0
  68. data/spec/bovem/parser_spec.rb +126 -0
  69. data/spec/bovem/shell_spec.rb +4 -4
  70. metadata +32 -5
@@ -6,7 +6,7 @@
6
6
  <title>
7
7
  Top Level Namespace
8
8
 
9
- &mdash; Documentation by YARD 0.8.6.2
9
+ &mdash; Documentation by YARD 0.8.7
10
10
 
11
11
  </title>
12
12
 
@@ -103,9 +103,9 @@
103
103
  </div>
104
104
 
105
105
  <div id="footer">
106
- Generated on Sat Aug 3 12:38:42 2013 by
106
+ Generated on Sat Aug 3 13:50:14 2013 by
107
107
  <a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
108
- 0.8.6.2 (ruby-2.0.0).
108
+ 0.8.7 (ruby-2.0.0).
109
109
  </div>
110
110
 
111
111
  </body>
data/lib/bovem.rb CHANGED
@@ -4,6 +4,8 @@
4
4
  # Licensed under the MIT license, which can be found at http://www.opensource.org/licenses/mit-license.php.
5
5
  #
6
6
 
7
+ require "optparse"
8
+ require "prettyprint"
7
9
  require "logger"
8
10
  require "open4"
9
11
  require "find"
@@ -14,7 +16,12 @@ Lazier.load!(:object, :boolean, :math)
14
16
 
15
17
  require "bovem/version" if !defined?(Bovem::Version)
16
18
  require "bovem/errors"
19
+ require "bovem/localizer"
17
20
  require "bovem/configuration"
18
21
  require "bovem/logger"
19
22
  require "bovem/console"
20
- require "bovem/shell"
23
+ require "bovem/shell"
24
+ require "bovem/command"
25
+ require "bovem/option"
26
+ require "bovem/application"
27
+ require "bovem/parser"
@@ -0,0 +1,158 @@
1
+ # encoding: utf-8
2
+ #
3
+ # This file is part of the bovem gem. Copyright (C) 2013 and above Shogun <shogun_panda@me.com>.
4
+ # Licensed under the MIT license, which can be found at http://www.opensource.org/licenses/mit-license.php.
5
+ #
6
+
7
+ module Bovem
8
+ # This is the main class for a Bovem application.
9
+ #
10
+ # Basically is the same of a command, but it adds support for application version.
11
+ #
12
+ # @attribute version
13
+ # @return [String] The version of the application.
14
+ # @attribute shell
15
+ # @return [Bovem::Shell] A shell helper.
16
+ # @attribute console
17
+ # @return [Bovem::Console] A console helper.
18
+ # @attribute skip_commands
19
+ # @return [Boolean] If to skip commands run via {#run}.
20
+ # @attribute show_commands
21
+ # @return [Boolean] If to show command lines run via {#run}.
22
+ # @attribute output_commands
23
+ # @return [Boolean] If to show the output of the commands run via {#run}.
24
+ class Application < Bovem::Command
25
+ attr_accessor :version
26
+ attr_accessor :shell
27
+ attr_accessor :console
28
+ attr_accessor :skip_commands
29
+ attr_accessor :show_commands
30
+ attr_accessor :output_commands
31
+
32
+ # Initializes a new Bovem application.
33
+ #
34
+ # In options, you can override the command line arguments with `:__args__`, and you can skip execution by specifying `run: false`.
35
+ #
36
+ # @see Command#setup_with
37
+ #
38
+ # @param options [Hash] The settings to initialize the application with.
39
+ # @return [Application] The created application.
40
+ def self.create(options = {}, &block)
41
+ raise Bovem::Errors::Error.new(Bovem::Application, :missing_block, Bovem::Localizer.localize_on_locale(options[:locale], :missing_app_block)) if !block_given?
42
+ run, args, options = setup_application_option(options)
43
+
44
+ begin
45
+ create_application(run, args, options, &block)
46
+ rescue => e
47
+ Kernel.puts(e.to_s)
48
+ Kernel.exit(1)
49
+ end
50
+ end
51
+
52
+ # Creates a new application.
53
+ #
54
+ # @param options [Hash] The settings to initialize the application with.
55
+ def initialize(options = {}, &block)
56
+ super(options, &block)
57
+
58
+ @shell = Bovem::Shell.instance
59
+ @console = @shell.console
60
+ @skip_commands = false
61
+ @show_commands = false
62
+ @output_commands = false
63
+
64
+ help_option
65
+ end
66
+
67
+ # Reads and optionally sets the version of this application.
68
+ #
69
+ # @param value [String|nil] The new version of this application.
70
+ # @return [String|nil] The version of this application.
71
+ def version(value = nil)
72
+ @version = value.ensure_string if !value.nil?
73
+ @version
74
+ end
75
+
76
+ # Executes this application.
77
+ #
78
+ # @param args [Array] The command line to pass to this application. Defaults to `ARGV`.
79
+ def execute(args = nil)
80
+ super(args || ARGV)
81
+ end
82
+
83
+ # Adds a help command and a help option to this application.
84
+ def help_option
85
+ command(:help, description: i18n.help_command_description) do
86
+ action { |command| application.command_help(command) }
87
+ end
88
+
89
+ option(:help, [i18n.help_option_short_form, i18n.help_option_long_form], help: i18n.help_message){ |application, _| application.show_help }
90
+ end
91
+
92
+ # The name of the current executable.
93
+ #
94
+ # @return [String] The name of the current executable.
95
+ def executable_name
96
+ $0
97
+ end
98
+
99
+ # Shows a help about a command.
100
+ #
101
+ # @param command [Command] The command to show help for.
102
+ def command_help(command)
103
+ fetch_commands_for_help(command).each do |arg|
104
+ # Find the command across
105
+ next_command = Bovem::Parser.find_command(arg, command, [])
106
+
107
+ if next_command then
108
+ command = command.commands[next_command[:name]]
109
+ else
110
+ break
111
+ end
112
+ end
113
+
114
+ command.show_help
115
+ end
116
+
117
+ # Runs a command into the shell.
118
+ #
119
+ # @param command [String] The string to run.
120
+ # @param message [String] A message to show before running.
121
+ # @param show_exit [Boolean] If show the exit status.
122
+ # @param fatal [Boolean] If quit in case of fatal errors.
123
+ # @return [Hash] An hash with `status` and `output` keys.
124
+ def run(command, message = nil, show_exit = true, fatal = true)
125
+ @shell.run(command, message, !@skip_commands, show_exit, @output_commands, @show_commands, fatal)
126
+ end
127
+
128
+ private
129
+ # Setup options for application creation.
130
+ #
131
+ # @param options [Hash] The options to setups.
132
+ # @return [Array] If to run the application, the arguments and the specified options.
133
+ def self.setup_application_option(options)
134
+ options = {name: Bovem::Localizer.localize_on_locale(options[:locale], :default_application_name), parent: nil, application: nil}.merge(options.ensure_hash)
135
+ run = options.delete(:run)
136
+ [(!run.nil? ? run : true).to_boolean, options.delete(:__args__), options]
137
+ end
138
+
139
+ # Create the application.
140
+ #
141
+ # @param run [Boolean ]If to run the application.
142
+ # @param args [Hash] The arguments to use for running.
143
+ # @param options [Hash] The options of the application.
144
+ # @return [Application] The new application.
145
+ def self.create_application(run, args, options, &block)
146
+ application = new(options, &block)
147
+ application.execute(args) if application && run
148
+ application
149
+ end
150
+
151
+ # Fetch a command list for showing help.
152
+ #
153
+ # @param command [Command] The command to show help for.
154
+ def fetch_commands_for_help(command)
155
+ command.arguments.collect {|c| c.split(":") }.flatten.collect(&:strip).select(&:present?)
156
+ end
157
+ end
158
+ end
@@ -0,0 +1,529 @@
1
+ # encoding: utf-8
2
+ #
3
+ # This file is part of the bovem gem. Copyright (C) 2013 and above Shogun <shogun_panda@me.com>.
4
+ # Licensed under the MIT license, which can be found at http://www.opensource.org/licenses/mit-license.php.
5
+ #
6
+
7
+ module Bovem
8
+ # Methods for the {Command Command} class.
9
+ module CommandMethods
10
+ # Methods for showing help messages.
11
+ module Help
12
+ # Shows a help about this command.
13
+ def show_help
14
+ console = is_application? ? self.console : application.console
15
+ is_application? ? show_help_application_summary(console) : show_help_command_summary(console)
16
+ show_help_banner(console) if has_banner?
17
+ show_help_options(console) if has_options?
18
+ show_help_commands(console) if has_commands?
19
+ Kernel.exit(0)
20
+ end
21
+
22
+ private
23
+ # Prints a help summary about the application.
24
+ #
25
+ # @param console [Bovem::Console] The console object to use to print.
26
+ def show_help_application_summary(console)
27
+ # Application
28
+ console.write(i18n.help_name)
29
+ console.write("%s %s%s" % [name, version, has_description? ? " - " + description : ""], "\n", 4, true)
30
+ show_synopsis(console)
31
+ end
32
+
33
+ # Prints a synopsis about the application.
34
+ #
35
+ # @param console [Bovem::Console] The console object to use to print.
36
+ def show_synopsis(console)
37
+ console.write("")
38
+ console.write(i18n.help_synopsis)
39
+ console.write(synopsis.present? ? synopsis : i18n.help_application_synopsis % [executable_name, has_commands? ? i18n.help_subcommand_invocation : ""], "\n", 4, true)
40
+ end
41
+
42
+ # Prints a help summary about the command.
43
+ #
44
+ # @param console [Bovem::Console] The console object to use to print.
45
+ def show_help_command_summary(console)
46
+ console.write(i18n.help_synopsis)
47
+ console.write(synopsis.present? ? synopsis : i18n.help_command_synopsis % [application.executable_name, full_name(nil, " "), has_commands? ? i18n.help_subsubcommand_invocation : ""], "\n", 4, true)
48
+ end
49
+
50
+ # Prints the description of the command.
51
+ #
52
+ # @param console [Bovem::Console] The console object to use to print.
53
+ def show_help_banner(console)
54
+ console.write("")
55
+ console.write(i18n.help_description)
56
+ console.write(banner, "\n", 4, true)
57
+ end
58
+
59
+ # Prints information about the command's options.
60
+ #
61
+ # @param console [Bovem::Console] The console object to use to print.
62
+ def show_help_options(console)
63
+ console.write("")
64
+ console.write(is_application? ? i18n.help_global_options : i18n.help_options)
65
+
66
+ # First of all, grab all options and construct labels
67
+ lefts = show_help_options_build_labels
68
+
69
+ console.with_indentation(4) do
70
+ lefts.keys.sort.each do |head|
71
+ show_help_option(console, lefts, head)
72
+ end
73
+ end
74
+ end
75
+
76
+ # Adjusts options names for printing.
77
+ #
78
+ # @return [Hash] The adjusted options for printing.
79
+ def show_help_options_build_labels
80
+ options.values.inject({}) do |lefts, option|
81
+ left = [option.complete_short, option.complete_long]
82
+ left.collect!{|l| l + " " + option.meta } if option.requires_argument?
83
+ lefts[left.join(", ")] = option.has_help? ? option.help : i18n.help_no_description
84
+ lefts
85
+ end
86
+ end
87
+
88
+ # Prints information about an option.
89
+ #
90
+ # @param console [Bovem::Console] The console object to use to print.
91
+ # @param lefts [Hash] The list of adjusted options.
92
+ # @param head [String] The option to print.
93
+ def show_help_option(console, lefts, head)
94
+ alignment = lefts.keys.collect(&:length).max
95
+ help = lefts[head]
96
+ console.write("%s - %s" % [head.ljust(alignment, " "), help], "\n", true, true)
97
+ end
98
+
99
+ # Prints information about the command's subcommands.
100
+ #
101
+ # @param console [Bovem::Console] The console object to use to print.
102
+ def show_help_commands(console)
103
+ alignment = prepare_show_help_commands(console)
104
+
105
+ console.with_indentation(4) do
106
+ commands.keys.sort.each do |name|
107
+ show_help_command(console, name, alignment)
108
+ end
109
+ end
110
+ end
111
+
112
+ # Starts printing information about the command's subcommands.
113
+ #
114
+ # @param console [Bovem::Console] The console object to use to print.
115
+ def prepare_show_help_commands(console)
116
+ console.write("")
117
+ console.write(is_application? ? i18n.help_commands : i18n.help_subcommands)
118
+ commands.keys.collect(&:length).max
119
+ end
120
+
121
+ # Prints information about a command's subcommand.
122
+ #
123
+ # @param name [String] The name of command to print.
124
+ # @param console [Bovem::Console] The console object to use to print.
125
+ def show_help_command(console, name, alignment)
126
+ # Find the maximum length of the commands
127
+ command = commands[name]
128
+ console.write("%s - %s" % [name.ljust(alignment, " "), command.description.present? ? command.description : i18n.help_no_description], "\n", true, true)
129
+ end
130
+ end
131
+
132
+ # Methods to manage options and subcommands.
133
+ module Children
134
+ attr_reader :commands
135
+ attr_reader :options
136
+
137
+ # Adds a new subcommand to this command.
138
+ #
139
+ # @param name [String] The name of this command. Must be unique.
140
+ # @param options [Hash] A set of options for this command.
141
+ # @return [Command] The newly added command.
142
+ def command(name, options = {}, &block)
143
+ @commands ||= HashWithIndifferentAccess.new
144
+
145
+ options = {name: name.to_s, parent: self, application: application}.merge(options.ensure_hash)
146
+ raise Bovem::Errors::Error.new(self, :duplicate_command, i18n.existing_command(full_name(name))) if @commands[name.to_s]
147
+
148
+ create_command(name, options, &block)
149
+ end
150
+
151
+ # Adds a new option to this command.
152
+ #
153
+ # @see Option#initialize
154
+ #
155
+ # @param name [String] The name of the option. Must be unique.
156
+ # @param forms [Array] An array of short and long forms for this option.
157
+ # @param options [Hash] The settings for the option.
158
+ # @param action [Proc] An optional action to pass to the option.
159
+ # @return [Option] The newly added option.
160
+ def option(name, forms = [], options = {}, &action)
161
+ name = name.ensure_string
162
+ @options ||= HashWithIndifferentAccess.new
163
+
164
+ if @options[name] then
165
+ if is_application? then
166
+ raise Bovem::Errors::Error.new(self, :duplicate_option, i18n.existing_option_global(name))
167
+ else
168
+ raise Bovem::Errors::Error.new(self, :duplicate_option, i18n.existing_option(name, full_name))
169
+ end
170
+ end
171
+
172
+ option = Bovem::Option.new(name, forms, options, &action)
173
+ option.parent = self
174
+ @options[name] = option
175
+ option
176
+ end
177
+
178
+ # Returns the list of subcommands of this command.
179
+ #
180
+ # @return [HashWithIndifferentAccess] The list of subcommands of this command.
181
+ def commands
182
+ @commands || HashWithIndifferentAccess.new
183
+ end
184
+
185
+ # Clear all subcommands of this commands.
186
+ #
187
+ # @return [Hash] The new (empty) list of subcommands of this command.
188
+ def clear_commands
189
+ @commands = {}
190
+ end
191
+
192
+ # Check if this command has subcommands.
193
+ #
194
+ # @return [Boolean] `true` if this command has subcommands, `false` otherwise.
195
+ def has_commands?
196
+ commands.length > 0
197
+ end
198
+
199
+ # Returns the list of options of this command.
200
+ #
201
+ # @return [HashWithIndifferentAccess] The list of options of this command.
202
+ def options
203
+ @options || HashWithIndifferentAccess.new
204
+ end
205
+
206
+ # Clear all the options of this commands.
207
+ # @return [Hash] The new (empty) list of the options of this command.
208
+ def clear_options
209
+ @options = {}
210
+ end
211
+
212
+ # Check if this command has options.
213
+ #
214
+ # @return [Boolean] `true` if this command has options, `false` otherwise.
215
+ def has_options?
216
+ options.length > 0
217
+ end
218
+
219
+ # Adds a new argument to this command.
220
+ #
221
+ # @param value [String] The argument to add.
222
+ def argument(value)
223
+ @args ||= []
224
+ @args << value
225
+ end
226
+
227
+ # Returns the list of arguments of this command.
228
+ #
229
+ # @return [Array] The list of arguments of this command.
230
+ def arguments
231
+ @args || []
232
+ end
233
+
234
+ # Get the list of the options of this command as an hash, where the keys are the options and the values are either
235
+ # the user inputs or the defaults values.
236
+ #
237
+ # If the two prefixes collides, the command options take precedence over application options.
238
+ #
239
+ # @param unprovided [Boolean] If to include also options that were not provided by the user and that don't have any default value.
240
+ # @param application [String] The prefix to use for including application's options. If falsy, only current command options will be included.
241
+ # @param prefix [String] The prefix to add to the option of this command.
242
+ # @param whitelist [Array] The list of options to include. By default all options are included.
243
+ # @return [HashWithIndifferentAccess] The requested options.
244
+ def get_options(unprovided = false, application = "application_", prefix = "", *whitelist)
245
+ rv = HashWithIndifferentAccess.new
246
+ rv.merge!(self.application.get_options(unprovided, nil, application, *whitelist)) if application && !is_application?
247
+ rv.merge!(get_current_options(unprovided, prefix, whitelist))
248
+ rv
249
+ end
250
+
251
+ private
252
+ # Creates a new command.
253
+ #
254
+ # @param name [String] The name of this command.
255
+ # @param options [Hash] The settings for this command.
256
+ # @return [Command] The new command.
257
+ def create_command(name, options, &block)
258
+ command = Bovem::Command.new(options, &block)
259
+ command.option(:help, [i18n.help_option_short_form, i18n.help_option_long_form], help: i18n.help_message){|c, _| c.show_help }
260
+ @commands[name.to_s] = command
261
+ command
262
+ end
263
+
264
+ # Gets the list of the options of this command.
265
+ # @param unprovided [Boolean] If to include also options that were not provided by the user and that don't have any default value.
266
+ # @param prefix [String] The prefix to add to the option of this command.
267
+ # @param whitelist [Array] The list of options to include. By default all options are included.
268
+ # @return [HashWithIndifferentAccess] The requested options.
269
+ def get_current_options(unprovided, prefix, whitelist)
270
+ rv = HashWithIndifferentAccess.new
271
+ whitelist = (whitelist.present? ? whitelist : options.keys).collect(&:to_s)
272
+
273
+ options.each do |key, option|
274
+ rv["#{prefix}#{key}"] = option.value if include_option?(whitelist, unprovided, key, option)
275
+ end
276
+
277
+ rv
278
+ end
279
+
280
+ # Checks if a option must be included in a hash.
281
+ #
282
+ # @param whitelist [Array] The list of options to include.
283
+ # @param unprovided [Boolean] If to include also options that were not provided by the user and that don't have any default value.
284
+ # @param key [String] The option name.
285
+ # @param option [Option] The option to include.
286
+ # @return [Boolean] Whether to include the option.
287
+ def include_option?(whitelist, unprovided, key, option)
288
+ whitelist.include?(key.to_s) && (option.provided? || option.has_default? || (unprovided && option.action.nil?))
289
+ end
290
+ end
291
+ end
292
+
293
+ # This class represent a command (action) for Bovem.
294
+ #
295
+ # Every command has the execution block and a set of option. Optionally, it also has before and after hooks.
296
+ #
297
+ # @attribute name
298
+ # @return [String] The name of this command. At runtime you can invoke it using the minimum number of letters to uniquely distinguish it from others.
299
+ # @attribute description
300
+ # @return [String] A very short description of what this command does.
301
+ # @attribute banner
302
+ # @return [String] A long description of this command.
303
+ # @attribute synopsis
304
+ # @return [String] A synopsis of the typical command line usage.
305
+ # @attribute before
306
+ # @return [Proc] A hook to execute before the command's action. It is executed only if no subcommand is executed.
307
+ # @attribute action
308
+ # @return [Proc] The action of this command. It is executed only if no subcommand is executed.
309
+ # @attribute after
310
+ # @return [Proc] A hook to execute after the command's action. It is executed only if no subcommand is executed.
311
+ # @attribute application
312
+ # @return [Application] The application this command belongs to.
313
+ # @attribute parent
314
+ # @return [Command] The parent of this command.
315
+ # @attribute [r] commands
316
+ # @return [Array] The subcommands associated to this command.
317
+ # @attribute [r] options
318
+ # @return [Array] The options available for this command.
319
+ # @attribute [r] arguments
320
+ # @return [Array] The arguments provided to this command.
321
+ class Command
322
+ attr_accessor :name
323
+ attr_accessor :description
324
+ attr_accessor :banner
325
+ attr_accessor :synopsis
326
+ attr_accessor :before
327
+ attr_accessor :action
328
+ attr_accessor :after
329
+ attr_accessor :application
330
+ attr_accessor :parent
331
+
332
+ include Lazier::I18n
333
+ include Bovem::CommandMethods::Help
334
+ include Bovem::CommandMethods::Children
335
+
336
+ # Creates a new command.
337
+ #
338
+ # @param options [Hash] The settings to initialize the command with.
339
+ def initialize(options = {}, &block)
340
+ setup_with(options)
341
+ instance_eval(&block) if block_given?
342
+ end
343
+
344
+ # Reads and optionally sets the name of this command.
345
+ #
346
+ # @param value [NilClass|Object] The new name of this command.
347
+ # @return [String] The name of this command.
348
+ def name(value = nil)
349
+ @name = value if !value.nil?
350
+ @name
351
+ end
352
+
353
+ # Gets a full name, that is the name of this command and its ancestor. Optionally it also appends a suffix
354
+ #
355
+ # @param suffix [String] A suffix to append.
356
+ # @param separator [String] The separator to use for components.
357
+ # @return [String] The full name.
358
+ def full_name(suffix = nil, separator = ":")
359
+ if is_application? then
360
+ nil
361
+ else
362
+ [@parent ? @parent.full_name(nil, separator) : nil, !is_application? ? name : nil, suffix].compact.join(separator)
363
+ end
364
+ end
365
+
366
+ # Reads and optionally sets the short description of this command.
367
+ #
368
+ # @param value [NilClass|Object] The new short description of this command.
369
+ # @return [String] The short description of this command.
370
+ def description(value = nil)
371
+ @description = value if !value.nil?
372
+ @description
373
+ end
374
+
375
+ # Reads and optionally sets the description of this command.
376
+ #
377
+ # @param value [NilClass|Object] The new description of this command.
378
+ # @return [String] The description of this command.
379
+ def banner(value = nil)
380
+ @banner = value if !value.nil?
381
+ @banner
382
+ end
383
+
384
+ # Reads and optionally sets the synopsis of this command.
385
+ #
386
+ # @param value [NilClass|Object] The new synopsis of this command.
387
+ # @return [String] The synopsis of this command.
388
+ def synopsis(value = nil)
389
+ @synopsis = value if !value.nil?
390
+ @synopsis
391
+ end
392
+
393
+ # Reads and optionally sets the before hook, that is a block executed before the action of this command.
394
+ #
395
+ # This hook is only executed if no subcommand is executed.
396
+ #
397
+ # @param method [String|Symbol|NilClass] The method of the application to hookup.
398
+ # @param hook [Proc] The block to hookup if method is not provided.
399
+ # @return [Proc|Symbol|NilClass] The before hook of this command.
400
+ def before(method = nil, &hook)
401
+ @before = assign_hook(method, &hook) if method || hook
402
+ @before
403
+ end
404
+
405
+ # Reads and optionally sets the action of this command.
406
+ #
407
+ # A command action is only executed if no subcommand is executed.
408
+ #
409
+ # @param method [String|Symbol|NilClass] The method of the application to hookup.
410
+ # @param hook [Proc] The block to hookup if method is not provided.
411
+ # @return [Proc|Symbol|NilClass] The action of this command.
412
+ def action(method = nil, &hook)
413
+ @action = assign_hook(method, &hook) if method || hook
414
+ @action
415
+ end
416
+
417
+ # Sets the after hook, that is a block executed after the action of this command.
418
+ #
419
+ # This hook is only executed if no subcommand is executed.
420
+ #
421
+ # @param method [String|Symbol|NilClass] The method of the application to hookup.
422
+ # @param hook [Proc] The block to hookup if method is not provided.
423
+ # @return [Proc|Symbol|NilClass] The after hook of this command.
424
+ def after(method = nil, &hook)
425
+ @after = assign_hook(method, &hook) if method || hook
426
+ @after
427
+ end
428
+
429
+ # Returns the application this command belongs to.
430
+ #
431
+ # @return [Application] The application this command belongs to or `self`, if the command is an Application.
432
+ def application
433
+ is_application? ? self : @application
434
+ end
435
+
436
+ # Checks if the command is an application.
437
+ #
438
+ # @return [Boolean] `true` if command is an application, `false` otherwise.
439
+ def is_application?
440
+ is_a?(Bovem::Application)
441
+ end
442
+
443
+ # Check if this command has a description.
444
+ #
445
+ # @return [Boolean] `true` if this command has a description, `false` otherwise.
446
+ def has_description?
447
+ description.present?
448
+ end
449
+
450
+ # Check if this command has a banner.
451
+ #
452
+ # @return [Boolean] `true` if this command has a banner, `false` otherwise.
453
+ def has_banner?
454
+ banner.present?
455
+ end
456
+
457
+ # Setups the command.
458
+ #
459
+ # @param options [Hash] The settings for this command.
460
+ # @return [Command] The command.
461
+ def setup_with(options = {})
462
+ options = {} if !options.is_a?(::Hash)
463
+ setup_i18n(options)
464
+
465
+ options.each_pair do |option, value|
466
+ method = option.to_s
467
+
468
+ if respond_to?(method) && self.method(method).arity != 0 then
469
+ send(method, value)
470
+ elsif respond_to?(method + "=") then
471
+ send(method + "=", value)
472
+ end
473
+ end
474
+
475
+ self
476
+ end
477
+
478
+ # Executes this command, running its action or a subcommand.
479
+ #
480
+ # @param args [Array] The arguments to pass to the command.
481
+ def execute(args)
482
+ subcommand = Bovem::Parser.parse(self, args)
483
+
484
+ if subcommand.present? then # We have a subcommand to call
485
+ commands[subcommand[:name]].execute(subcommand[:args])
486
+ elsif action then # Run our action
487
+ # Run the before hook
488
+ execute_hook(before)
489
+
490
+ # Run the action
491
+ execute_hook(action)
492
+
493
+ # Run the after hook
494
+ execute_hook(after)
495
+ else # Show the help
496
+ show_help
497
+ end
498
+ end
499
+
500
+ private
501
+ # Setups the application localization.
502
+ #
503
+ # @param options [Hash] The settings for this command.
504
+ def setup_i18n(options)
505
+ i18n_setup("bovem.application", ::File.absolute_path(::Pathname.new(::File.dirname(__FILE__)).to_s + "/../../locales/"))
506
+ self.i18n = (options[:locale]).ensure_string
507
+ end
508
+
509
+ # Assigns a hook to a command.
510
+ #
511
+ # @param method [String|Symbol|NilClass] The method of the application to hookup.
512
+ # @param block [Proc] The block to hookup if method is not provided.
513
+ def assign_hook(method, &hook)
514
+ assigned = nil
515
+ assigned = method if method.is_a?(::String) || method.is_a?(::Symbol)
516
+ assigned = hook if !assigned && hook && hook.arity == 1
517
+ assigned
518
+ end
519
+
520
+ # Executes a hook.
521
+ #
522
+ # @param hook [String|Symbol|Proc|NilClass] The hook to execute.
523
+ def execute_hook(hook)
524
+ if hook then
525
+ hook.is_a?(::String) || hook.is_a?(::Symbol) ? application.send(hook, self) : hook.call(self)
526
+ end
527
+ end
528
+ end
529
+ end