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.
- checksums.yaml +4 -4
- data/.gitignore +2 -1
- data/Gemfile +1 -1
- data/README.md +98 -2
- data/bovem.gemspec +3 -3
- data/doc/Bovem.html +25 -6
- data/doc/Bovem/Application.html +3057 -0
- data/doc/Bovem/Command.html +7031 -0
- data/doc/Bovem/CommandMethods.html +125 -0
- data/doc/Bovem/CommandMethods/Children.html +1285 -0
- data/doc/Bovem/CommandMethods/Help.html +209 -0
- data/doc/Bovem/Configuration.html +3 -3
- data/doc/Bovem/Console.html +8 -8
- data/doc/Bovem/ConsoleMethods.html +3 -3
- data/doc/Bovem/ConsoleMethods/Interactions.html +3 -3
- data/doc/Bovem/ConsoleMethods/Interactions/ClassMethods.html +3 -3
- data/doc/Bovem/ConsoleMethods/Logging.html +4 -4
- data/doc/Bovem/ConsoleMethods/Logging/ClassMethods.html +3 -3
- data/doc/Bovem/ConsoleMethods/Output.html +3 -3
- data/doc/Bovem/ConsoleMethods/StyleHandling.html +4 -4
- data/doc/Bovem/ConsoleMethods/StyleHandling/ClassMethods.html +8 -8
- data/doc/Bovem/Errors.html +4 -4
- data/doc/Bovem/Errors/Error.html +631 -0
- data/doc/Bovem/Errors/InvalidConfiguration.html +3 -3
- data/doc/Bovem/Errors/InvalidLogger.html +3 -3
- data/doc/Bovem/Localizer.html +376 -0
- data/doc/Bovem/Logger.html +64 -160
- data/doc/Bovem/Option.html +7009 -0
- data/doc/Bovem/Parser.html +276 -0
- data/doc/Bovem/ParserMethods.html +125 -0
- data/doc/Bovem/ParserMethods/General.html +134 -0
- data/doc/Bovem/ParserMethods/General/ClassMethods.html +574 -0
- data/doc/Bovem/Shell.html +8 -8
- data/doc/Bovem/ShellMethods.html +3 -3
- data/doc/Bovem/ShellMethods/Directories.html +3 -3
- data/doc/Bovem/ShellMethods/Execute.html +3 -3
- data/doc/Bovem/ShellMethods/General.html +3 -3
- data/doc/Bovem/ShellMethods/Read.html +3 -3
- data/doc/Bovem/ShellMethods/Write.html +3 -3
- data/doc/Bovem/Version.html +6 -6
- data/doc/_index.html +119 -11
- data/doc/class_list.html +1 -1
- data/doc/file.README.html +98 -5
- data/doc/frames.html +1 -1
- data/doc/index.html +98 -5
- data/doc/method_list.html +476 -26
- data/doc/top-level-namespace.html +3 -3
- data/lib/bovem.rb +8 -1
- data/lib/bovem/application.rb +158 -0
- data/lib/bovem/command.rb +529 -0
- data/lib/bovem/console.rb +8 -8
- data/lib/bovem/errors.rb +27 -0
- data/lib/bovem/localizer.rb +27 -0
- data/lib/bovem/logger.rb +2 -8
- data/lib/bovem/option.rb +250 -0
- data/lib/bovem/parser.rb +317 -0
- data/lib/bovem/shell.rb +2 -2
- data/lib/bovem/version.rb +3 -3
- data/locales/en.yml +33 -0
- data/locales/it.yml +33 -0
- data/spec/bovem/application_spec.rb +170 -0
- data/spec/bovem/command_spec.rb +526 -0
- data/spec/bovem/configuration_spec.rb +4 -4
- data/spec/bovem/console_spec.rb +22 -22
- data/spec/bovem/errors_spec.rb +18 -0
- data/spec/bovem/logger_spec.rb +22 -12
- data/spec/bovem/option_spec.rb +307 -0
- data/spec/bovem/parser_spec.rb +126 -0
- data/spec/bovem/shell_spec.rb +4 -4
- metadata +32 -5
@@ -6,7 +6,7 @@
|
|
6
6
|
<title>
|
7
7
|
Top Level Namespace
|
8
8
|
|
9
|
-
— Documentation by YARD 0.8.
|
9
|
+
— 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
|
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.
|
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
|