bovem 3.0.5 → 4.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 +4 -3
- data/.rubocop.yml +82 -0
- data/.travis-gemfile +4 -5
- data/.travis.yml +8 -6
- data/CHANGELOG.md +12 -0
- data/Gemfile +9 -8
- data/README.md +1 -1
- data/Rakefile +22 -6
- data/bovem.gemspec +5 -5
- data/doc/Bovem.html +10 -10
- data/doc/Bovem/Application.html +670 -318
- data/doc/Bovem/Command.html +1447 -1125
- data/doc/Bovem/CommandMethods.html +4 -4
- data/doc/Bovem/CommandMethods/Children.html +173 -179
- data/doc/Bovem/CommandMethods/Help.html +9 -9
- data/doc/Bovem/Configuration.html +239 -24
- data/doc/Bovem/Console.html +267 -128
- data/doc/Bovem/ConsoleMethods.html +4 -4
- data/doc/Bovem/ConsoleMethods/Interactions.html +57 -70
- data/doc/Bovem/ConsoleMethods/Interactions/ClassMethods.html +9 -9
- data/doc/Bovem/ConsoleMethods/Logging.html +258 -298
- data/doc/Bovem/ConsoleMethods/Logging/ClassMethods.html +8 -8
- data/doc/Bovem/ConsoleMethods/Output.html +96 -118
- data/doc/Bovem/ConsoleMethods/StyleHandling.html +8 -8
- data/doc/Bovem/ConsoleMethods/StyleHandling/ClassMethods.html +26 -39
- data/doc/Bovem/Errors.html +4 -4
- data/doc/Bovem/Errors/Error.html +4 -4
- data/doc/Bovem/Errors/InvalidConfiguration.html +4 -4
- data/doc/Bovem/Errors/InvalidLogger.html +4 -4
- data/doc/Bovem/I18n.html +175 -0
- data/doc/Bovem/Logger.html +95 -83
- data/doc/Bovem/Option.html +669 -862
- data/doc/Bovem/Parser.html +10 -10
- data/doc/Bovem/ParserMethods.html +4 -4
- data/doc/Bovem/ParserMethods/General.html +4 -4
- data/doc/Bovem/ParserMethods/General/ClassMethods.html +26 -38
- data/doc/Bovem/Shell.html +169 -48
- data/doc/Bovem/ShellMethods.html +4 -4
- data/doc/Bovem/ShellMethods/Directories.html +46 -62
- data/doc/Bovem/ShellMethods/Execute.html +51 -99
- data/doc/Bovem/ShellMethods/General.html +4 -445
- data/doc/Bovem/ShellMethods/Read.html +56 -61
- data/doc/Bovem/ShellMethods/Write.html +22 -242
- data/doc/Bovem/Version.html +6 -6
- data/doc/_index.html +18 -18
- data/doc/class_list.html +6 -2
- data/doc/css/style.css +1 -0
- data/doc/file.README.html +5 -5
- data/doc/file_list.html +5 -1
- data/doc/frames.html +1 -1
- data/doc/index.html +5 -5
- data/doc/js/full_list.js +4 -1
- data/doc/method_list.html +161 -157
- data/doc/top-level-namespace.html +4 -4
- data/lib/bovem.rb +3 -4
- data/lib/bovem/application.rb +47 -39
- data/lib/bovem/command.rb +175 -193
- data/lib/bovem/configuration.rb +28 -29
- data/lib/bovem/console.rb +244 -171
- data/lib/bovem/errors.rb +1 -1
- data/lib/bovem/i18n.rb +18 -0
- data/lib/bovem/logger.rb +26 -26
- data/lib/bovem/option.rb +49 -58
- data/lib/bovem/parser.rb +174 -222
- data/lib/bovem/shell.rb +272 -320
- data/lib/bovem/version.rb +2 -2
- data/locales/en.yml +39 -38
- data/locales/it.yml +39 -38
- data/spec/bovem/application_spec.rb +6 -5
- data/spec/bovem/command_spec.rb +23 -23
- data/spec/bovem/console_spec.rb +101 -102
- data/spec/bovem/i18n_spec.rb +21 -0
- data/spec/bovem/logger_spec.rb +4 -4
- data/spec/bovem/option_spec.rb +43 -43
- data/spec/bovem/parser_spec.rb +13 -13
- data/spec/bovem/shell_spec.rb +106 -115
- data/spec/spec_helper.rb +19 -6
- metadata +14 -13
- data/doc/Bovem/Localizer.html +0 -376
- data/lib/bovem/localizer.rb +0 -27
- data/spec/coverage_helper.rb +0 -20
data/lib/bovem/errors.rb
CHANGED
data/lib/bovem/i18n.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
#
|
3
|
+
# This file is part of the bovem gem. Copyright (C) 2013 and above Shogun <shogun@cowtech.it>.
|
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
|
+
# Extension of Lazier::I18n to support method based access.
|
9
|
+
class I18n < ::Lazier::I18n
|
10
|
+
private
|
11
|
+
|
12
|
+
def method_missing(method, *args)
|
13
|
+
rv = send(:t, method)
|
14
|
+
rv = sprintf(rv, *args) if rv.index(/%([\d.]*)[sdf]/) && args.present?
|
15
|
+
rv
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
data/lib/bovem/logger.rb
CHANGED
@@ -12,6 +12,9 @@ module Bovem
|
|
12
12
|
class Logger < ::Logger
|
13
13
|
attr_reader :device
|
14
14
|
|
15
|
+
# List of valid logger levels.
|
16
|
+
LEVEL_NAMES = {"DEBUG" => :cyan, "INFO" => :green, "WARN" => :yellow, "ERROR" => :red, "FATAL" => :magenta}.freeze
|
17
|
+
|
15
18
|
# Creates a new logger.
|
16
19
|
#
|
17
20
|
# @see http://www.ruby-doc.org/stdlib-1.9.3/libdoc/logger/rdoc/Logger.html
|
@@ -19,7 +22,7 @@ module Bovem
|
|
19
22
|
# @param logdev [String|IO] The log device. This is a filename (String) or IO object (typically STDOUT, STDERR, or an open file).
|
20
23
|
# @param shift_age [Fixnum] Number of old log files to keep, or frequency of rotation (daily, weekly or monthly).
|
21
24
|
# @param shift_size [Fixnum] Maximum logfile size (only applies when shift_age is a number).
|
22
|
-
def initialize(logdev, shift_age = 0, shift_size =
|
25
|
+
def initialize(logdev, shift_age = 0, shift_size = 1_048_576)
|
23
26
|
@device = logdev
|
24
27
|
super(logdev, shift_age, shift_size)
|
25
28
|
end
|
@@ -30,15 +33,13 @@ module Bovem
|
|
30
33
|
# @param level [Fixnum] The minimum severity to log. See http://www.ruby-doc.org/stdlib-1.9.3/libdoc/logger/rdoc/Logger.html for valid levels.
|
31
34
|
# @param formatter [Proc] The formatter to use for logging.
|
32
35
|
# @return [Logger] The new logger.
|
33
|
-
def self.create(file = nil, level
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
raise Bovem::Errors::InvalidLogger
|
41
|
-
end
|
36
|
+
def self.create(file = nil, level: Logger::INFO, formatter: nil)
|
37
|
+
rv = new(get_real_file(file || default_file))
|
38
|
+
rv.level = level.to_integer
|
39
|
+
rv.formatter = formatter || default_formatter
|
40
|
+
rv
|
41
|
+
rescue
|
42
|
+
raise Bovem::Errors::InvalidLogger
|
42
43
|
end
|
43
44
|
|
44
45
|
# Translates a file to standard input or standard output in some special cases.
|
@@ -47,9 +48,9 @@ module Bovem
|
|
47
48
|
# @return [String|IO] The translated file name.
|
48
49
|
def self.get_real_file(file)
|
49
50
|
case file
|
50
|
-
|
51
|
-
|
52
|
-
|
51
|
+
when "STDOUT" then $stdout
|
52
|
+
when "STDERR" then $stderr
|
53
|
+
else file
|
53
54
|
end
|
54
55
|
end
|
55
56
|
|
@@ -62,19 +63,18 @@ module Bovem
|
|
62
63
|
# The default formatter for logging.
|
63
64
|
# @return [Proc] The default formatter for logging.
|
64
65
|
def self.default_formatter
|
65
|
-
@default_formatter ||= ::Proc.new
|
66
|
-
color =
|
67
|
-
when "DEBUG" then :cyan
|
68
|
-
when "INFO" then :green
|
69
|
-
when "WARN" then :yellow
|
70
|
-
when "ERROR" then :red
|
71
|
-
when "FATAL" then :magenta
|
72
|
-
else :white
|
73
|
-
end
|
66
|
+
@default_formatter ||= ::Proc.new do |severity, datetime, _, msg|
|
67
|
+
color = LEVEL_NAMES.fetch(severity, :white)
|
74
68
|
|
75
|
-
header = Bovem::Console.replace_markers(
|
76
|
-
|
77
|
-
|
69
|
+
header = Bovem::Console.replace_markers(
|
70
|
+
sprintf(
|
71
|
+
"{mark=bright-#{color}}[%s T+%0.5f] %s:{/mark}", datetime.strftime("%Y/%b/%d %H:%M:%S"),
|
72
|
+
[datetime.to_f - start_time.to_f, 0].max, severity.rjust(5)
|
73
|
+
)
|
74
|
+
)
|
75
|
+
|
76
|
+
sprintf("%s %s\n", header, msg)
|
77
|
+
end
|
78
78
|
end
|
79
79
|
|
80
80
|
# The log time of the first logger. This allows to show a `T+0.1234` information into the log.
|
@@ -83,4 +83,4 @@ module Bovem
|
|
83
83
|
@start_time ||= ::Time.now
|
84
84
|
end
|
85
85
|
end
|
86
|
-
end
|
86
|
+
end
|
data/lib/bovem/option.rb
CHANGED
@@ -10,8 +10,7 @@ module Bovem
|
|
10
10
|
# Values are the default values for that type.
|
11
11
|
#
|
12
12
|
# For any unknown type, the default value is `false`, it means that any unknown type is managed as a Boolean value with no argument.
|
13
|
-
OPTION_TYPES = {String => "", Integer => 0, Fixnum => 0, Bignum => 0, Float => 0.0, Array => []}
|
14
|
-
OPTION_TYPES.default = false
|
13
|
+
OPTION_TYPES = {String => "", Integer => 0, Fixnum => 0, Bignum => 0, Float => 0.0, Array => []}.freeze
|
15
14
|
|
16
15
|
# This class represents an option for a command.
|
17
16
|
#
|
@@ -71,7 +70,7 @@ module Bovem
|
|
71
70
|
#
|
72
71
|
# @param value [String] The short form of this option.
|
73
72
|
def short=(value)
|
74
|
-
value = @name[0, 1]
|
73
|
+
value = @name[0, 1] unless value.present?
|
75
74
|
|
76
75
|
# Clean value
|
77
76
|
final_value = value.to_s.match(/^-{0,2}([a-z0-9])(.*)$/i)[1]
|
@@ -83,7 +82,7 @@ module Bovem
|
|
83
82
|
#
|
84
83
|
# @param value [String] The short form of this option.
|
85
84
|
def long=(value)
|
86
|
-
value = @name
|
85
|
+
value = @name unless value.present?
|
87
86
|
|
88
87
|
# Clean value
|
89
88
|
final_value = value.to_s.match(/^-{0,2}(.+)$/)[1]
|
@@ -96,7 +95,7 @@ module Bovem
|
|
96
95
|
# @param value [String] The validator of this option.
|
97
96
|
def validator=(value)
|
98
97
|
value = nil if value.blank? || (value.is_a?(Regexp) && value.source.blank?)
|
99
|
-
value = value.ensure_array(
|
98
|
+
value = value.ensure_array(no_duplicates: true, compact: true, flatten: true) if !value.nil? && !value.is_a?(Regexp) && !value.is_a?(Proc)
|
100
99
|
@validator = value
|
101
100
|
end
|
102
101
|
|
@@ -123,22 +122,24 @@ module Bovem
|
|
123
122
|
|
124
123
|
# Returns the meta argument for this option.
|
125
124
|
#
|
126
|
-
# @return [String|NilClass] Returns the current meta argument for this option (the default value is the option name uppercased) or `nil`,
|
125
|
+
# @return [String|NilClass] Returns the current meta argument for this option (the default value is the option name uppercased) or `nil`,
|
126
|
+
# if this option doesn't require a meta argument.
|
127
127
|
def meta
|
128
|
-
|
128
|
+
return nil unless requires_argument?
|
129
|
+
@meta.present? ? @meta : @name.upcase
|
129
130
|
end
|
130
131
|
|
131
132
|
# Get the current default value for this option.
|
132
133
|
#
|
133
134
|
# @return [Object] The default value for this option.
|
134
135
|
def default
|
135
|
-
@default || Bovem::OPTION_TYPES[@type]
|
136
|
+
@default || Bovem::OPTION_TYPES[@type] || false
|
136
137
|
end
|
137
138
|
|
138
139
|
# Check if the current option has a default value.
|
139
140
|
#
|
140
141
|
# @return [Boolean] If the current option has a default value.
|
141
|
-
def
|
142
|
+
def default?
|
142
143
|
!@default.nil?
|
143
144
|
end
|
144
145
|
|
@@ -151,7 +152,7 @@ module Bovem
|
|
151
152
|
vs = get_validator_method(@validator)
|
152
153
|
rv = vs ? @validator.send(vs, value) : true
|
153
154
|
|
154
|
-
if rv
|
155
|
+
if rv
|
155
156
|
@value = value
|
156
157
|
@provided = true
|
157
158
|
else # Validation failed
|
@@ -164,10 +165,9 @@ module Bovem
|
|
164
165
|
|
165
166
|
# Executes the action associated to this option.
|
166
167
|
def execute_action
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
end
|
168
|
+
return nil unless @action.present?
|
169
|
+
@provided = true
|
170
|
+
@action.call(parent, self)
|
171
171
|
end
|
172
172
|
|
173
173
|
# Checks if this option requires an argument.
|
@@ -187,7 +187,7 @@ module Bovem
|
|
187
187
|
# Check if this command has a help.
|
188
188
|
#
|
189
189
|
# @return [Boolean] `true` if this command has a help, `false` otherwise.
|
190
|
-
def
|
190
|
+
def help?
|
191
191
|
@help.present?
|
192
192
|
end
|
193
193
|
|
@@ -199,56 +199,47 @@ module Bovem
|
|
199
199
|
end
|
200
200
|
|
201
201
|
private
|
202
|
-
# Setups the forms of the this option.
|
203
|
-
#
|
204
|
-
# @param forms [Array] An array of short and long forms for this option. Missing forms will be inferred by the name.
|
205
|
-
def setup_forms(forms)
|
206
|
-
self.short = forms.length > 0 ? forms[0] : @name[0, 1]
|
207
|
-
self.long = forms.length == 2 ? forms[1] : @name
|
208
|
-
end
|
209
202
|
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
send("#{option}=", value) if respond_to?("#{option}=")
|
216
|
-
end
|
217
|
-
end
|
203
|
+
# :nodoc:
|
204
|
+
def setup_forms(forms)
|
205
|
+
self.short = !forms.empty? ? forms[0] : @name[0, 1]
|
206
|
+
self.long = forms.length == 2 ? forms[1] : @name
|
207
|
+
end
|
218
208
|
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
@action = action if action.present? && action.respond_to?(:call) && action.try(:arity) == 2
|
209
|
+
# :nodoc:
|
210
|
+
def setup_options(options)
|
211
|
+
(options.is_a?(::Hash) ? options : {}).each_pair do |option, value|
|
212
|
+
send("#{option}=", value) if respond_to?("#{option}=")
|
224
213
|
end
|
214
|
+
end
|
225
215
|
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
216
|
+
# :nodoc:
|
217
|
+
def setup_action(action)
|
218
|
+
@action = action if action.present? && action.respond_to?(:call) && action.try(:arity) == 2
|
219
|
+
end
|
220
|
+
|
221
|
+
# :nodoc:
|
222
|
+
def handle_set_failure(vs)
|
223
|
+
locale = @parent.i18n
|
231
224
|
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
225
|
+
message =
|
226
|
+
case vs
|
227
|
+
when "match" then locale.invalid_for_regexp(label, @validator.inspect)
|
228
|
+
when "call" then locale.invalid_for_proc(label)
|
229
|
+
else locale.invalid_value(label, Bovem::Parser.smart_join(@validator.ensure_array, separator: ", ", last_separator: locale.join_separator).html_safe)
|
236
230
|
end
|
237
231
|
|
238
|
-
|
239
|
-
|
232
|
+
raise Bovem::Errors::Error.new(self, :validation_failed, message)
|
233
|
+
end
|
240
234
|
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
when "Regexp" then "match"
|
249
|
-
when "Proc" then "call"
|
250
|
-
else false
|
251
|
-
end
|
235
|
+
# :nodoc:
|
236
|
+
def get_validator_method(validator)
|
237
|
+
case validator.class.to_s
|
238
|
+
when "Array" then "include?"
|
239
|
+
when "Regexp" then "match"
|
240
|
+
when "Proc" then "call"
|
241
|
+
else false
|
252
242
|
end
|
243
|
+
end
|
253
244
|
end
|
254
|
-
end
|
245
|
+
end
|
data/lib/bovem/parser.rb
CHANGED
@@ -20,11 +20,11 @@ module Bovem
|
|
20
20
|
# @param last_separator [String] The separator to use for the last join.
|
21
21
|
# @param quote [String] If not nil, elements are quoted with that element.
|
22
22
|
# @return [String] The joined array.
|
23
|
-
def smart_join(array, separator
|
23
|
+
def smart_join(array, separator: ", ", last_separator: " and ", quote: "\"")
|
24
24
|
separator = separator.ensure_string
|
25
25
|
last_separator = last_separator.ensure_string
|
26
|
-
array = array.ensure_array {|a| quote.present? ? "#{quote}#{a}#{quote}" : a.ensure_string }
|
27
|
-
|
26
|
+
array = array.ensure_array { |a| quote.present? ? "#{quote}#{a}#{quote}" : a.ensure_string }
|
27
|
+
perform_smart_join(array, last_separator, separator)
|
28
28
|
end
|
29
29
|
|
30
30
|
# Finds a command which corresponds to an argument.
|
@@ -34,18 +34,16 @@ module Bovem
|
|
34
34
|
# @param args [String] The complete list of arguments passed.
|
35
35
|
# @param separator [String] The separator for joined syntax commands.
|
36
36
|
# @return [Hash|NilClass] An hash with `name` and `args` keys if a valid subcommand is found, `nil` otherwise.
|
37
|
-
def find_command(arg, command, args, separator
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
else
|
48
|
-
nil
|
37
|
+
def find_command(arg, command, args: {}, separator: ":")
|
38
|
+
return nil unless command.commands.present?
|
39
|
+
|
40
|
+
arg, args = adjust_command(arg, args, separator)
|
41
|
+
|
42
|
+
matching = match_subcommands(arg, command)
|
43
|
+
if matching.length == 1 # Found a command
|
44
|
+
{name: matching[0], args: args}
|
45
|
+
elsif matching.length > 1 # Ambiguous match
|
46
|
+
raise Bovem::Errors::Error.new(command, :ambiguous_command, command.i18n.ambigous_command(arg, format_alternatives(matching, command)))
|
49
47
|
end
|
50
48
|
end
|
51
49
|
|
@@ -59,41 +57,34 @@ module Bovem
|
|
59
57
|
end
|
60
58
|
|
61
59
|
private
|
62
|
-
# Adjusts a command so that it only specify a single command.
|
63
|
-
#
|
64
|
-
# @param arg [String] The string to match.
|
65
|
-
# @param args [String] The complete list of arguments passed.
|
66
|
-
# @param separator [String] The separator for joined syntax commands.
|
67
|
-
# @return [Array] Adjust command and arguments.
|
68
|
-
def adjust_command(arg, args, separator)
|
69
|
-
args = args.ensure_array.dup
|
70
|
-
|
71
|
-
if arg.index(separator) then
|
72
|
-
tokens = arg.split(separator, 2)
|
73
|
-
arg = tokens[0]
|
74
|
-
args.insert(0, tokens[1])
|
75
|
-
end
|
76
|
-
|
77
|
-
[arg, args]
|
78
|
-
end
|
79
60
|
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
# @param command [Command] The command to search subcommand in.
|
84
|
-
# @return [Array] The matching subcommands.
|
85
|
-
def match_subcommands(arg, command)
|
86
|
-
command.commands.keys.select {|c| c =~ /^(#{Regexp.quote(arg)})/ }.compact
|
87
|
-
end
|
61
|
+
# :nodoc:
|
62
|
+
def adjust_command(arg, args, separator)
|
63
|
+
args = args.ensure_array.dup
|
88
64
|
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
# @return [String] The formatted alternatives.
|
94
|
-
def format_alternatives(matching, command)
|
95
|
-
Bovem::Parser.smart_join(matching, ", ", command.i18n.join_separator).html_safe
|
65
|
+
if arg.index(separator)
|
66
|
+
tokens = arg.split(separator, 2)
|
67
|
+
arg = tokens[0]
|
68
|
+
args.insert(0, tokens[1])
|
96
69
|
end
|
70
|
+
|
71
|
+
[arg, args]
|
72
|
+
end
|
73
|
+
|
74
|
+
# :nodoc:
|
75
|
+
def match_subcommands(arg, command)
|
76
|
+
command.commands.keys.select { |c| c =~ /^(#{Regexp.quote(arg)})/ }.compact
|
77
|
+
end
|
78
|
+
|
79
|
+
# :nodoc:
|
80
|
+
def format_alternatives(matching, command)
|
81
|
+
Bovem::Parser.smart_join(matching, separator: ", ", last_separator: command.i18n.join_separator).html_safe
|
82
|
+
end
|
83
|
+
|
84
|
+
# :nodoc:
|
85
|
+
def perform_smart_join(array, last_separator, separator)
|
86
|
+
array.length < 2 ? (array[0] || "") : (array[0, array.length - 1].join(separator) + last_separator + array[-1])
|
87
|
+
end
|
97
88
|
end
|
98
89
|
end
|
99
90
|
end
|
@@ -114,213 +105,174 @@ module Bovem
|
|
114
105
|
end
|
115
106
|
|
116
107
|
private
|
117
|
-
# Creates a new option parser.
|
118
|
-
#
|
119
|
-
# @param command [Command] The command or application to parse.
|
120
|
-
# @return [OptionParser] The new parser
|
121
|
-
def create_parser(command)
|
122
|
-
forms = {}
|
123
|
-
parser = OptionParser.new do |opts|
|
124
|
-
# Add every option
|
125
|
-
command.options.each_pair do |_, option|
|
126
|
-
check_unique(command, forms, option)
|
127
|
-
setup_option(command, opts, option)
|
128
|
-
end
|
129
|
-
end
|
130
108
|
|
131
|
-
|
109
|
+
# :nodoc:
|
110
|
+
def create_parser(command)
|
111
|
+
forms = {}
|
112
|
+
parser = OptionParser.new do |opts|
|
113
|
+
# Add every option
|
114
|
+
command.options.each_pair do |_, option|
|
115
|
+
check_unique(command, forms, option)
|
116
|
+
setup_option(command, opts, option)
|
117
|
+
end
|
132
118
|
end
|
133
119
|
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
def perform_parsing(parser, command, args, forms)
|
141
|
-
rv = nil
|
142
|
-
|
143
|
-
begin
|
144
|
-
rv = execute_parsing(parser, command, args)
|
145
|
-
rescue OptionParser::NeedlessArgument, OptionParser::MissingArgument, OptionParser::InvalidOption => oe
|
146
|
-
type = oe.class.to_s.gsub("OptionParser::", "").underscore.to_sym
|
147
|
-
opt = oe.args.first
|
148
|
-
raise Bovem::Errors::Error.new(forms[opt], type, command.i18n.send(type, opt))
|
149
|
-
rescue => e
|
150
|
-
raise e
|
151
|
-
end
|
120
|
+
[forms, parser]
|
121
|
+
end
|
122
|
+
|
123
|
+
# :nodoc:
|
124
|
+
def perform_parsing(parser, command, args, forms)
|
125
|
+
rv = nil
|
152
126
|
|
153
|
-
|
127
|
+
begin
|
128
|
+
rv = execute_parsing(parser, command, args)
|
129
|
+
rescue OptionParser::NeedlessArgument, OptionParser::MissingArgument, OptionParser::InvalidOption => e
|
130
|
+
fail_invalid_option(command, forms, e)
|
131
|
+
rescue => e
|
132
|
+
raise e
|
154
133
|
end
|
155
134
|
|
156
|
-
|
157
|
-
|
158
|
-
# @param parser [OptionParser] The option parser.
|
159
|
-
# @param command [Command] The command or application to parse.
|
160
|
-
# @param args [Array] The arguments to parse.
|
161
|
-
# @return [Command|nil] A command to execute or `nil` if no valid command was found.
|
162
|
-
def execute_parsing(parser, command, args)
|
163
|
-
rv = nil
|
164
|
-
|
165
|
-
if command.options.present? then
|
166
|
-
rv = parse_options(parser, command, args)
|
167
|
-
check_required_options(command)
|
168
|
-
elsif args.present? then
|
169
|
-
rv = find_command_to_execute(command, args)
|
170
|
-
end
|
135
|
+
rv
|
136
|
+
end
|
171
137
|
|
172
|
-
|
173
|
-
|
138
|
+
# :nodoc:
|
139
|
+
def fail_invalid_option(command, forms, oe)
|
140
|
+
type = oe.class.to_s.gsub("OptionParser::", "").underscore.to_sym
|
141
|
+
opt = oe.args.first
|
142
|
+
raise Bovem::Errors::Error.new(forms[opt], type, command.i18n.send(type, opt))
|
143
|
+
end
|
174
144
|
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
# @param opts [Object] The current set options.
|
179
|
-
# @param option [Option] The option to set.
|
180
|
-
def setup_option(command, opts, option)
|
181
|
-
case option.type.to_s
|
182
|
-
when "String" then parse_string(command, opts, option)
|
183
|
-
when "Integer", "Fixnum", "Bignum" then parse_number(command, opts, option, :is_integer?, :to_integer, command.i18n.invalid_integer(option.label))
|
184
|
-
when "Float" then parse_number(command, opts, option, :is_float?, :to_float, command.i18n.invalid_float(option.label))
|
185
|
-
when "Array" then parse_array(command, opts, option)
|
186
|
-
else option.action.present? ? parse_action(opts, option) : parse_boolean(opts, option)
|
187
|
-
end
|
188
|
-
end
|
145
|
+
# :nodoc:
|
146
|
+
def execute_parsing(parser, command, args)
|
147
|
+
rv = nil
|
189
148
|
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
def check_unique(command, forms, option)
|
196
|
-
if forms[option.complete_short] || forms[option.complete_long] then
|
197
|
-
raise Bovem::Errors::Error.new(command, :ambiguous_form, command.i18n.conflicting_options(option.label, forms[option.complete_short].label))
|
198
|
-
else
|
199
|
-
forms[option.complete_short] = option.dup
|
200
|
-
forms[option.complete_long] = option.dup
|
201
|
-
end
|
149
|
+
if command.options.present?
|
150
|
+
rv = parse_options(parser, command, args)
|
151
|
+
check_required_options(command)
|
152
|
+
elsif args.present?
|
153
|
+
rv = find_command_to_execute(command, args)
|
202
154
|
end
|
203
155
|
|
204
|
-
|
205
|
-
|
206
|
-
# @param command [Command] The command or application to parse.
|
207
|
-
# @param opts [Object] The current set options.
|
208
|
-
# @param option [Option] The option to set.
|
209
|
-
def parse_option(command, opts, option)
|
210
|
-
opts.on("#{option.complete_short} #{option.meta || command.i18n.help_arg}", "#{option.complete_long} #{option.meta || command.i18n.help_arg}") do |value|
|
211
|
-
yield(value)
|
212
|
-
end
|
213
|
-
end
|
156
|
+
rv
|
157
|
+
end
|
214
158
|
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
159
|
+
# :nodoc:
|
160
|
+
def setup_option(command, opts, option)
|
161
|
+
case option.type.to_s
|
162
|
+
when "String" then parse_string(command, opts, option)
|
163
|
+
when "Integer", "Fixnum", "Bignum" then setup_int_option(command, option, opts)
|
164
|
+
when "Float" then parse_number(command, opts, option, :float?, :to_float, command.i18n.invalid_float(option.label))
|
165
|
+
when "Array" then parse_array(command, opts, option)
|
166
|
+
else option.action.present? ? parse_action(opts, option) : parse_boolean(opts, option)
|
223
167
|
end
|
168
|
+
end
|
169
|
+
|
170
|
+
# :nodoc:
|
171
|
+
def setup_int_option(command, option, opts)
|
172
|
+
parse_number(command, opts, option, :integer?, :to_integer, command.i18n.invalid_integer(option.label))
|
173
|
+
end
|
224
174
|
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
175
|
+
# :nodoc:
|
176
|
+
def check_unique(command, forms, option)
|
177
|
+
if forms[option.complete_short] || forms[option.complete_long]
|
178
|
+
fail_non_unique_option(command, forms, option)
|
179
|
+
else
|
180
|
+
forms[option.complete_short] = option.dup
|
181
|
+
forms[option.complete_long] = option.dup
|
232
182
|
end
|
183
|
+
end
|
233
184
|
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
#
|
242
|
-
|
243
|
-
parse_option(command, opts, option) do |value|
|
244
|
-
raise Bovem::Errors::Error.new(option, :invalid_argument, invalid_message) if !value.send(check_method)
|
245
|
-
option.set(value.send(convert_method))
|
246
|
-
end
|
185
|
+
# :nodoc:
|
186
|
+
def fail_non_unique_option(command, forms, option)
|
187
|
+
raise Bovem::Errors::Error.new(command, :ambiguous_form, command.i18n.conflicting_options(option.label, forms[option.complete_short].label))
|
188
|
+
end
|
189
|
+
|
190
|
+
# :nodoc:
|
191
|
+
def parse_option(command, opts, option)
|
192
|
+
opts.on("#{option.complete_short} #{option.meta || command.i18n.help_arg}", "#{option.complete_long} #{option.meta || command.i18n.help_arg}") do |value|
|
193
|
+
yield(value)
|
247
194
|
end
|
195
|
+
end
|
248
196
|
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
# @param option [Option] The option to set.
|
254
|
-
def parse_array(command, opts, option)
|
255
|
-
opts.on("#{option.complete_short} #{option.meta || command.i18n.help_arg}", "#{option.complete_long} #{option.meta || command.i18n.help_arg}", Array) do |value|
|
256
|
-
option.set(value.ensure_array)
|
257
|
-
end
|
197
|
+
# :nodoc:
|
198
|
+
def parse_action(opts, option)
|
199
|
+
opts.on("-#{option.short}", "--#{option.long}") do |_|
|
200
|
+
option.execute_action
|
258
201
|
end
|
202
|
+
end
|
259
203
|
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
204
|
+
# :nodoc:
|
205
|
+
def parse_string(command, opts, option)
|
206
|
+
parse_option(command, opts, option) { |value| option.set(value) }
|
207
|
+
end
|
208
|
+
|
209
|
+
# :nodoc:
|
210
|
+
def parse_number(command, opts, option, check_method, convert_method, invalid_message)
|
211
|
+
parse_option(command, opts, option) do |value|
|
212
|
+
raise Bovem::Errors::Error.new(option, :invalid_argument, invalid_message) unless value.send(check_method)
|
213
|
+
option.set(value.send(convert_method))
|
268
214
|
end
|
215
|
+
end
|
269
216
|
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
# @param command [Command] The command or application to parse.
|
274
|
-
# @param args [Array] The arguments to parse.
|
275
|
-
# @return [Command|nil] A command to execute or `nil` if no command was found.
|
276
|
-
def parse_options(parser, command, args)
|
277
|
-
rv = nil
|
278
|
-
|
279
|
-
# Parse options
|
280
|
-
parser.order!(args) do |arg|
|
281
|
-
fc = Bovem::Parser.find_command(arg, command, args)
|
282
|
-
|
283
|
-
if fc.present? then
|
284
|
-
rv = fc
|
285
|
-
parser.terminate
|
286
|
-
else
|
287
|
-
command.argument(arg)
|
288
|
-
end
|
289
|
-
end
|
217
|
+
# :nodoc:
|
218
|
+
def parse_array(command, opts, option)
|
219
|
+
meta = option.meta || command.i18n.help_arg
|
290
220
|
|
291
|
-
|
221
|
+
opts.on("#{option.complete_short} #{meta}", "#{option.complete_long} #{meta}", Array) do |value|
|
222
|
+
option.set(value.ensure_array)
|
292
223
|
end
|
224
|
+
end
|
293
225
|
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
# Check if any required option is missing.
|
299
|
-
command.options.each_pair do |name, option|
|
300
|
-
raise Bovem::Errors::Error.new(option, :missing_option, command.i18n.missing_option(option.label)) if option.required && !option.provided?
|
301
|
-
end
|
226
|
+
# :nodoc:
|
227
|
+
def parse_boolean(opts, option)
|
228
|
+
opts.on("-#{option.short}", "--#{option.long}") do |value|
|
229
|
+
option.set(value.to_boolean)
|
302
230
|
end
|
231
|
+
end
|
303
232
|
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
# @param args [Array] The arguments to parse.
|
308
|
-
# @return [Command|nil] A command to execute or `nil` if no command was found.
|
309
|
-
def find_command_to_execute(command, args)
|
310
|
-
rv = nil
|
233
|
+
# :nodoc:
|
234
|
+
def parse_options(parser, command, args)
|
235
|
+
rv = nil
|
311
236
|
|
312
|
-
|
313
|
-
|
237
|
+
# Parse options
|
238
|
+
parser.order!(args) do |arg|
|
239
|
+
fc = Bovem::Parser.find_command(arg, command, args: args)
|
314
240
|
|
315
|
-
if fc.present?
|
241
|
+
if fc.present?
|
316
242
|
rv = fc
|
243
|
+
parser.terminate
|
317
244
|
else
|
318
|
-
|
319
|
-
command.argument(arg)
|
320
|
-
end
|
245
|
+
command.argument(arg)
|
321
246
|
end
|
247
|
+
end
|
248
|
+
|
249
|
+
rv
|
250
|
+
end
|
322
251
|
|
323
|
-
|
252
|
+
# :nodoc:
|
253
|
+
def check_required_options(command)
|
254
|
+
# Check if any required option is missing.
|
255
|
+
command.options.each_pair do |_, option|
|
256
|
+
raise Bovem::Errors::Error.new(option, :missing_option, command.i18n.missing_option(option.label)) if option.required && !option.provided?
|
324
257
|
end
|
258
|
+
end
|
259
|
+
|
260
|
+
# :nodoc:
|
261
|
+
def find_command_to_execute(command, args)
|
262
|
+
rv = nil
|
263
|
+
|
264
|
+
# Try to find a command into the first argument
|
265
|
+
fc = Bovem::Parser.find_command(args[0], command, args: args[1, args.length - 1])
|
266
|
+
|
267
|
+
if fc.present?
|
268
|
+
rv = fc
|
269
|
+
else
|
270
|
+
args.each do |arg|
|
271
|
+
command.argument(arg)
|
272
|
+
end
|
273
|
+
end
|
274
|
+
|
275
|
+
rv
|
276
|
+
end
|
325
277
|
end
|
326
|
-
end
|
278
|
+
end
|