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
data/lib/bovem/shell.rb
CHANGED
@@ -561,12 +561,12 @@ module Bovem
|
|
561
561
|
#
|
562
562
|
# @return [Shell] A new instance.
|
563
563
|
def self.instance
|
564
|
-
@instance ||=
|
564
|
+
@instance ||= Bovem::Shell.new
|
565
565
|
end
|
566
566
|
|
567
567
|
# Initializes a new Shell.
|
568
568
|
def initialize
|
569
|
-
@console =
|
569
|
+
@console = Bovem::Console.instance
|
570
570
|
i18n_setup(:bovem, ::File.absolute_path(::Pathname.new(::File.dirname(__FILE__)).to_s + "/../../locales/"))
|
571
571
|
end
|
572
572
|
end
|
data/lib/bovem/version.rb
CHANGED
@@ -11,13 +11,13 @@ module Bovem
|
|
11
11
|
# @see http://semver.org
|
12
12
|
module Version
|
13
13
|
# The major version.
|
14
|
-
MAJOR =
|
14
|
+
MAJOR = 3
|
15
15
|
|
16
16
|
# The minor version.
|
17
|
-
MINOR =
|
17
|
+
MINOR = 0
|
18
18
|
|
19
19
|
# The patch version.
|
20
|
-
PATCH =
|
20
|
+
PATCH = 0
|
21
21
|
|
22
22
|
# The current version number of Bovem.
|
23
23
|
STRING = [MAJOR, MINOR, PATCH].compact.join(".")
|
data/locales/en.yml
CHANGED
@@ -41,3 +41,36 @@
|
|
41
41
|
mkdir_file: "Path {mark=bright}%1{/mark} is currently a file."
|
42
42
|
mkdir_denied: "Cannot create following directory due to permission denied: {mark=bright}%1{/mark}."
|
43
43
|
mkdir_error: "Cannot create following directories:"
|
44
|
+
application:
|
45
|
+
default_application_name: "__APPLICATION__"
|
46
|
+
ambigous_command: "Command shortcut \"%1\" is ambiguous across commands %2. Please add some other characters."
|
47
|
+
needless_argument: "Option %1 does not expects an argument."
|
48
|
+
missing_argument: "Option %1 expects an argument."
|
49
|
+
invalid_option: "Invalid option %1."
|
50
|
+
invalid_integer: "Option %1 expects a valid integer as argument."
|
51
|
+
invalid_float: "Option %1 expects a valid floating number as argument."
|
52
|
+
conflicting_options: "Options %1 and %2 have conflicting forms."
|
53
|
+
missing_option: "Required option %1 is missing."
|
54
|
+
invalid_value: "Value of option %1 must be one of these values: %2."
|
55
|
+
invalid_for_regexp: "Value of option %1 must match the regular expression: %2."
|
56
|
+
help_option_short_form: "-h"
|
57
|
+
help_option_long_form: "--help"
|
58
|
+
help_message: "Shows this message."
|
59
|
+
help_arg: "ARG"
|
60
|
+
help_name: "[NAME]"
|
61
|
+
help_application_synopsis: "%s [options] %s[command-options] [arguments] "
|
62
|
+
help_command_synopsis: "%s [options] %s %s[command-options] [arguments] "
|
63
|
+
help_synopsis: "[SYNOPSIS]"
|
64
|
+
help_description: "[DESCRIPTION]"
|
65
|
+
help_no_description: "*NO DESCRIPTION PROVIDED*"
|
66
|
+
help_options: "[OPTIONS]"
|
67
|
+
help_global_options: "[GLOBAL OPTIONS]"
|
68
|
+
help_commands: "[COMMANDS]"
|
69
|
+
help_subcommands: "[SUBCOMMANDS]"
|
70
|
+
help_subcommand_invocation: "[command [sub-command ...]] "
|
71
|
+
help_subsubcommand_invocation: "[sub-command [sub-sub-command ...]] "
|
72
|
+
help_command_description: "Shows a help about a command."
|
73
|
+
existing_command: "The command \"%1\" already exists."
|
74
|
+
existing_option_global: "The global option \"%1\" already exists."
|
75
|
+
existing_option: "The option \"%1\" already exists for the command \"%2\"."
|
76
|
+
missing_app_block: "You have to provide a block to the Bovem::Application constructor!"
|
data/locales/it.yml
CHANGED
@@ -41,3 +41,36 @@
|
|
41
41
|
mkdir_file: "Il percorso {mark=bright}%1{/mark} è attualmente un file."
|
42
42
|
mkdir_denied: "Impossible creare la seguente cartella a causa di permessi negati: {mark=bright}%1{/mark}."
|
43
43
|
mkdir_error: "Impossibile creare le seguenti cartelle:"
|
44
|
+
application:
|
45
|
+
default_application_name: "__APPLICAZIONE__"
|
46
|
+
ambigous_command: "La scorciatoia di comando \"%1\" è ambigua tra i seguenti comandi %2. Per favore aggiungi qualche altro carattere."
|
47
|
+
needless_argument: "L'opzione %1 non richiede un argomento."
|
48
|
+
missing_argument: "L'opzione %1 richiede un argomento."
|
49
|
+
invalid_option: "L'opzione %1 non è valida."
|
50
|
+
invalid_integer: "L'opzione %1 richiede un numero intero valido come argomento."
|
51
|
+
invalid_float: "L'opzione %1 richiede un numero decimale valido come argomento."
|
52
|
+
conflicting_options: "Le opzioni %1 e %2 hanno forme in conflitto."
|
53
|
+
missing_option: "L'opzione richiesta %1 è mancante."
|
54
|
+
invalid_value: "Il valore dell'opzione %1 deve essere uno dei seguenti valori: %2."
|
55
|
+
invalid_for_regexp: "Il valore dell'opzione %1 deve soddisfare questa espressione regolare: %2."
|
56
|
+
help_option_short_form: "-h"
|
57
|
+
help_option_long_form: "--help"
|
58
|
+
help_message: "Mostra questo messaggio."
|
59
|
+
help_arg: "ARG"
|
60
|
+
help_name: "[NOME]"
|
61
|
+
help_application_synopsis: "%s [opzioni] %s[opzioni-comando] [argomenti] "
|
62
|
+
help_command_synopsis: "%s [opzioni] %s %s[opzioni-comando] [argomenti] "
|
63
|
+
help_synopsis: "[UTILIZZO]"
|
64
|
+
help_description: "[DESCRIZIONE]"
|
65
|
+
help_no_description: "*NESSUNA DESCRIZIONE FORNITA*"
|
66
|
+
help_options: "[OPZIONI]"
|
67
|
+
help_global_options: "[OPZIONI GLOBALI]"
|
68
|
+
help_commands: "[COMANDI]"
|
69
|
+
help_subcommands: "[SOTTOCOMANDI]"
|
70
|
+
help_subcommand_invocation: "[comando [sotto-comando ...]] "
|
71
|
+
help_subsubcommand_invocation: "[sotto-comando [sotto-sotto-comando ...]] "
|
72
|
+
help_command_description: "Mostra aiuto riguardo un comando."
|
73
|
+
existing_command: "Il comando \"%1\" è già esistente."
|
74
|
+
existing_option_global: "L'opzione globale \"%1\" è già esistente."
|
75
|
+
existing_option: "L'opzione \"%1\" è già esistente per il comando \"%2\"."
|
76
|
+
missing_app_block: "Devi fornire un blocco per il costruttore di Bovem::Application!"
|
@@ -0,0 +1,170 @@
|
|
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
|
+
require "spec_helper"
|
8
|
+
|
9
|
+
describe Bovem::Application do
|
10
|
+
let(:application) { Bovem::Application.new(locale: :en) }
|
11
|
+
|
12
|
+
describe "#initialize" do
|
13
|
+
it "should call the parent constructor" do
|
14
|
+
options = {a: :b}
|
15
|
+
block = Proc.new {}
|
16
|
+
|
17
|
+
expect(Bovem::Command).to receive(:new).with(options, &block)
|
18
|
+
Bovem::Application.new(options, &block)
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should set good defaults" do
|
22
|
+
expect(application.shell).to eq(Bovem::Shell.instance)
|
23
|
+
expect(application.console).to eq(application.shell.console)
|
24
|
+
expect(application.skip_commands).to be_false
|
25
|
+
expect(application.show_commands).to be_false
|
26
|
+
expect(application.output_commands).to be_false
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe "#version" do
|
31
|
+
it "should set and return the version" do
|
32
|
+
expect(application.version).to be_nil
|
33
|
+
expect(application.version("another")).to eq("another")
|
34
|
+
expect(application.version(nil)).to eq("another")
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe "#help_option" do
|
39
|
+
it "should add a command and a option" do
|
40
|
+
expect(application).to receive(:command).with(:help, {description: "Shows a help about a command."})
|
41
|
+
expect(application).to receive(:option).with(:help, ["-h", "--help"], {help: "Shows this message."})
|
42
|
+
application.help_option
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should execute associated actions" do
|
46
|
+
expect(application).to receive(:show_help).exactly(2)
|
47
|
+
expect(application).to receive(:command_help)
|
48
|
+
|
49
|
+
application.execute(["help", "command"])
|
50
|
+
application.execute("-h")
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
describe "#executable_name" do
|
55
|
+
it "should return executable name" do
|
56
|
+
expect(application.executable_name).to eq($0)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
describe "#command_help" do
|
61
|
+
it "should show the help for the command" do
|
62
|
+
command = application.command "command"
|
63
|
+
subcommand = command.command "subcommand"
|
64
|
+
|
65
|
+
expect(application).to receive(:show_help)
|
66
|
+
application.command_help(application)
|
67
|
+
|
68
|
+
expect(command).to receive(:show_help)
|
69
|
+
application.argument(command.name)
|
70
|
+
application.command_help(application)
|
71
|
+
|
72
|
+
expect(subcommand).to receive(:show_help)
|
73
|
+
application.argument(subcommand.name)
|
74
|
+
application.command_help(application)
|
75
|
+
|
76
|
+
expect(subcommand).to receive(:show_help)
|
77
|
+
application.argument("foo")
|
78
|
+
application.command_help(application)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
describe "#run" do
|
83
|
+
it "should forward to the shell" do
|
84
|
+
expect(application.shell).to receive(:run).with("COMMAND", "MESSAGE", true, "A", false, false, "B")
|
85
|
+
application.run("COMMAND", "MESSAGE", "A", "B")
|
86
|
+
|
87
|
+
application.skip_commands = true
|
88
|
+
application.output_commands = true
|
89
|
+
application.show_commands = true
|
90
|
+
expect(application.shell).to receive(:run).with("COMMAND", "MESSAGE", false, "C", true, true, "D")
|
91
|
+
application.run("COMMAND", "MESSAGE", "C", "D")
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
describe ".create" do
|
96
|
+
it "should complain about a missing block" do
|
97
|
+
expect { Bovem::Application.create }.to raise_error(Bovem::Errors::Error)
|
98
|
+
end
|
99
|
+
|
100
|
+
it "should print errors" do
|
101
|
+
allow(Bovem::Application).to receive(:create_application).and_raise(ArgumentError.new("ERROR"))
|
102
|
+
expect(Kernel).to receive(:puts).with("ERROR")
|
103
|
+
expect(Kernel).to receive(:exit).with(1)
|
104
|
+
Bovem::Application.create(__args__: []) {}
|
105
|
+
end
|
106
|
+
|
107
|
+
it "should create a default application" do
|
108
|
+
expect(Bovem::Application).to receive(:new).with({name: "__APPLICATION__", parent: nil, application: nil, locale: :en})
|
109
|
+
Bovem::Application.create({locale: :en}) {}
|
110
|
+
end
|
111
|
+
|
112
|
+
it "should create an application with given options and block" do
|
113
|
+
options = {name: "OK"}
|
114
|
+
|
115
|
+
expect(Bovem::Application).to receive(:new).with({name: "OK", parent: nil, application: nil})
|
116
|
+
application = Bovem::Application.create(options) {}
|
117
|
+
end
|
118
|
+
|
119
|
+
it "should execute the block" do
|
120
|
+
allow_any_instance_of(Bovem::Console).to receive(:write)
|
121
|
+
allow(Kernel).to receive(:exit)
|
122
|
+
options = {name: "OK", __args__: []}
|
123
|
+
check = false
|
124
|
+
|
125
|
+
application = Bovem::Application.create(options) { check = true }
|
126
|
+
expect(check).to be_true
|
127
|
+
expect(application.name).to eq("OK")
|
128
|
+
end
|
129
|
+
|
130
|
+
it "should execute the new application" do
|
131
|
+
args = []
|
132
|
+
|
133
|
+
application = Bovem::Application.create do
|
134
|
+
option("require", [], {})
|
135
|
+
option("format", [], {})
|
136
|
+
option("example", [], {})
|
137
|
+
|
138
|
+
action do |command|
|
139
|
+
args = command.arguments.join("-")
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
expect(args).to eq(ARGV.reject {|a| a =~ /^--/ }.join("-"))
|
144
|
+
end
|
145
|
+
|
146
|
+
it "can override arguments" do
|
147
|
+
args = []
|
148
|
+
|
149
|
+
application = Bovem::Application.create({__args__: ["C", "D"]}) do
|
150
|
+
action do |command|
|
151
|
+
args = command.arguments.join("-")
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
expect(args).to eq("C-D")
|
156
|
+
end
|
157
|
+
|
158
|
+
it "should not execute the application if requested to" do
|
159
|
+
args = []
|
160
|
+
|
161
|
+
application = Bovem::Application.create(run: false) do
|
162
|
+
action do |command|
|
163
|
+
args = command.arguments.join("-")
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
expect(args).to eq([])
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
@@ -0,0 +1,526 @@
|
|
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
|
+
require "spec_helper"
|
8
|
+
|
9
|
+
describe Bovem::Command do
|
10
|
+
let(:application) {
|
11
|
+
Bovem::Application.new(locale: :en) {
|
12
|
+
action {}
|
13
|
+
}
|
14
|
+
}
|
15
|
+
|
16
|
+
let(:command) {
|
17
|
+
c = Bovem::Command.new(locale: :en)
|
18
|
+
c.application = application
|
19
|
+
c
|
20
|
+
}
|
21
|
+
|
22
|
+
describe "#initialize" do
|
23
|
+
it "should forward to #setup_with" do
|
24
|
+
expect(Bovem::Command.new(name: "command").name).to eq("command")
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should call the block" do
|
28
|
+
count = 0
|
29
|
+
Bovem::Command.new(name: "command") { count += 1 }
|
30
|
+
expect(count).to eq(1)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
describe "#name" do
|
35
|
+
it "should set and return the name" do
|
36
|
+
expect(command.name).to be_nil
|
37
|
+
expect(command.name("another")).to eq("another")
|
38
|
+
expect(command.name(nil)).to eq("another")
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe "#full_name" do
|
43
|
+
it "should retrieve the full hierarchy of the name" do
|
44
|
+
command.name = "root"
|
45
|
+
expect(command.full_name).to eq("root")
|
46
|
+
|
47
|
+
subcommand = Bovem::Command.new(name: "child")
|
48
|
+
subcommand.parent = command
|
49
|
+
expect(subcommand.full_name).to eq("root:child")
|
50
|
+
expect(subcommand.full_name(nil, " ")).to eq("root child")
|
51
|
+
expect(subcommand.full_name("A", " ")).to eq("root child A")
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
describe "#description" do
|
56
|
+
it "should set and return the description" do
|
57
|
+
expect(command.description).to be_nil
|
58
|
+
expect(command.description("another")).to eq("another")
|
59
|
+
expect(command.description(nil)).to eq("another")
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
describe "#banner" do
|
64
|
+
it "should set and return the banner" do
|
65
|
+
expect(command.banner).to be_nil
|
66
|
+
expect(command.banner("another")).to eq("another")
|
67
|
+
expect(command.banner(nil)).to eq("another")
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
|
72
|
+
describe "#synopsis" do
|
73
|
+
it "should set and return the synopsis" do
|
74
|
+
expect(command.synopsis).to be_nil
|
75
|
+
expect(command.synopsis("another")).to eq("another")
|
76
|
+
expect(command.synopsis(nil)).to eq("another")
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
describe "#before" do
|
81
|
+
it "should set and return the before hook" do
|
82
|
+
valid = Proc.new{|a| puts "OK" }
|
83
|
+
|
84
|
+
expect(command.before).to be_nil
|
85
|
+
expect(command.before(1)).to be_nil
|
86
|
+
expect(command.before { puts "OK" }).to be_nil
|
87
|
+
expect(command.before {|a, b| puts "OK" }).to be_nil
|
88
|
+
expect(command.before(:method)).to eq(:method)
|
89
|
+
expect(command.action("METHOD")).to eq("METHOD")
|
90
|
+
expect(command.before(&valid)).to eq(valid)
|
91
|
+
expect(command.before("METHOD", &valid)).to eq("METHOD")
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
describe "#action" do
|
96
|
+
it "should set and return the action" do
|
97
|
+
valid = Proc.new{|a| puts "OK" }
|
98
|
+
|
99
|
+
expect(command.action).to be_nil
|
100
|
+
expect(command.action(1)).to be_nil
|
101
|
+
expect(command.action { puts "OK" }).to be_nil
|
102
|
+
expect(command.action {|a, b| puts "OK" }).to be_nil
|
103
|
+
expect(command.action(:method)).to eq(:method)
|
104
|
+
expect(command.action("METHOD")).to eq("METHOD")
|
105
|
+
expect(command.action(&valid)).to eq(valid)
|
106
|
+
expect(command.action("METHOD", &valid)).to eq("METHOD")
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
describe "#after" do
|
111
|
+
it "should set and return the after hook" do
|
112
|
+
valid = Proc.new{|a| puts "OK" }
|
113
|
+
|
114
|
+
expect(command.after).to be_nil
|
115
|
+
expect(command.after(1)).to be_nil
|
116
|
+
expect(command.after { puts "OK" }).to be_nil
|
117
|
+
expect(command.after {|a, b| puts "OK" }).to be_nil
|
118
|
+
expect(command.after(:method)).to eq(:method)
|
119
|
+
expect(command.after("METHOD")).to eq("METHOD")
|
120
|
+
expect(command.after(&valid)).to eq(valid)
|
121
|
+
expect(command.after("METHOD", &valid)).to eq("METHOD")
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
describe "#has_description?" do
|
126
|
+
it "should check if the command has a description" do
|
127
|
+
expect(Bovem::Command.new.has_description?).to be_false
|
128
|
+
expect(Bovem::Command.new({description: "DESCRIPTION"}).has_description?).to be_true
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
describe "#has_banner?" do
|
133
|
+
it "should check if the command has a banner" do
|
134
|
+
expect(Bovem::Command.new.has_banner?).to be_false
|
135
|
+
expect(Bovem::Command.new({banner: "BANNER"}).has_banner?).to be_true
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
describe "#command" do
|
140
|
+
it "should add a subcommand" do
|
141
|
+
command.command("subcommand", {banner: "BANNER"}) do |option|
|
142
|
+
description("DESCRIPTION")
|
143
|
+
end
|
144
|
+
|
145
|
+
subcommand = command.commands["subcommand"]
|
146
|
+
|
147
|
+
expect(subcommand.name).to eq("subcommand")
|
148
|
+
expect(subcommand.parent).to be(command)
|
149
|
+
expect(subcommand.application).to be(application)
|
150
|
+
expect(subcommand.banner).to eq("BANNER")
|
151
|
+
expect(subcommand.description).to eq("DESCRIPTION")
|
152
|
+
end
|
153
|
+
|
154
|
+
it "should check for duplicates" do
|
155
|
+
command.command("subcommand")
|
156
|
+
expect {command.command("subcommand")}.to raise_error(Bovem::Errors::Error)
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
describe "#option" do
|
161
|
+
it "should add a subcommand" do
|
162
|
+
command.option("option", ["short", "long"], {type: String, help: "HELP"})
|
163
|
+
|
164
|
+
option = command.options["option"]
|
165
|
+
|
166
|
+
expect(option.name).to eq("option")
|
167
|
+
expect(option.short).to eq("s")
|
168
|
+
expect(option.long).to eq("long")
|
169
|
+
expect(option.help).to eq("HELP")
|
170
|
+
end
|
171
|
+
|
172
|
+
it "should check for duplicates" do
|
173
|
+
application.option("option")
|
174
|
+
command.option("option")
|
175
|
+
expect {command.option("option")}.to raise_error(Bovem::Errors::Error)
|
176
|
+
expect {application.option("option")}.to raise_error(Bovem::Errors::Error)
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
describe "#commands" do
|
181
|
+
it "should return the list of commands" do
|
182
|
+
expect(command.commands).to eq({})
|
183
|
+
command.command("subcommand1")
|
184
|
+
command.command("subcommand2")
|
185
|
+
expect(command.commands.values.collect(&:name).sort).to eq(["subcommand1", "subcommand2"])
|
186
|
+
end
|
187
|
+
|
188
|
+
it "should let access both with Symbol or String" do
|
189
|
+
command.command("subcommand1")
|
190
|
+
expect(command.commands).to be_a(HashWithIndifferentAccess)
|
191
|
+
expect(command.commands[:subcommand1]).to eq(command.commands["subcommand1"])
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
describe "#clear_commands" do
|
196
|
+
it "should remove commands" do
|
197
|
+
command.command("subcommand")
|
198
|
+
expect(command.commands.length == 1)
|
199
|
+
command.clear_commands
|
200
|
+
expect(command.commands.length == 0)
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
describe "#has_commands?" do
|
205
|
+
it "should check if the command has subcommands" do
|
206
|
+
expect(command.has_commands?).to be_false
|
207
|
+
command.command("subcommand")
|
208
|
+
expect(command.has_commands?).to be_true
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
describe "#clear_options" do
|
213
|
+
it "should remove options" do
|
214
|
+
command.option("option")
|
215
|
+
expect(command.options.length == 1)
|
216
|
+
command.clear_options
|
217
|
+
expect(command.options.length == 0)
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
describe "#options" do
|
222
|
+
it "should return the list of options" do
|
223
|
+
expect(command.options).to eq({})
|
224
|
+
command.option("option1")
|
225
|
+
command.option("option2")
|
226
|
+
expect(command.options.values.collect(&:name).sort).to eq(["option1", "option2"])
|
227
|
+
end
|
228
|
+
|
229
|
+
it "should let access both with Symbol or String" do
|
230
|
+
command.option("option1")
|
231
|
+
expect(command.options).to be_a(HashWithIndifferentAccess)
|
232
|
+
expect(command.options[:option1]).to eq(command.options["option1"])
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
describe "#has_options?" do
|
237
|
+
it "should check if the command has options" do
|
238
|
+
expect(command.has_options?).to be_false
|
239
|
+
command.option("option")
|
240
|
+
expect(command.has_options?).to be_true
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
describe "#argument" do
|
245
|
+
it "should add an argument to the command" do
|
246
|
+
expect(command.arguments).to eq([])
|
247
|
+
command.argument("A")
|
248
|
+
expect(command.arguments).to eq(["A"])
|
249
|
+
command.argument("B")
|
250
|
+
expect(command.arguments).to eq(["A", "B"])
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
describe "#arguments" do
|
255
|
+
it "should return arguments" do
|
256
|
+
expect(command.arguments).to eq([])
|
257
|
+
command.argument("A")
|
258
|
+
expect(command.arguments).to eq(["A"])
|
259
|
+
command.argument("B")
|
260
|
+
expect(command.arguments).to eq(["A", "B"])
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
264
|
+
describe "#application" do
|
265
|
+
it "should return the application" do
|
266
|
+
expect(command.application).to be(application)
|
267
|
+
expect(application.application).to be(application)
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
describe "#is_application?" do
|
272
|
+
it "should check if the command is an application" do
|
273
|
+
expect(command.is_application?).to be_false
|
274
|
+
expect(application.is_application?).to be_true
|
275
|
+
end
|
276
|
+
end
|
277
|
+
|
278
|
+
describe "#setup_with" do
|
279
|
+
it "should setup required option by calling proper methods" do
|
280
|
+
expect(command).to receive("name").with("new-command")
|
281
|
+
expect(command).to receive("application=").with(nil)
|
282
|
+
command.setup_with({name: "new-command", application: nil, invalid: false})
|
283
|
+
end
|
284
|
+
end
|
285
|
+
|
286
|
+
describe "#execute" do
|
287
|
+
it "should parse command line" do
|
288
|
+
allow(Kernel).to receive(:exit)
|
289
|
+
allow_any_instance_of(Bovem::Console).to receive(:write)
|
290
|
+
|
291
|
+
args = ["command"]
|
292
|
+
expect(Bovem::Parser).to receive(:parse).with(command, args)
|
293
|
+
command.execute(args)
|
294
|
+
end
|
295
|
+
|
296
|
+
it "should execute hooks and actions in sequence" do
|
297
|
+
check = []
|
298
|
+
child = []
|
299
|
+
args = ["command"]
|
300
|
+
|
301
|
+
command.before do |command|
|
302
|
+
check << "A"
|
303
|
+
end
|
304
|
+
|
305
|
+
command.action do |command|
|
306
|
+
check << "B"
|
307
|
+
end
|
308
|
+
|
309
|
+
command.after do |command|
|
310
|
+
check << "C"
|
311
|
+
end
|
312
|
+
|
313
|
+
command.command("subcommand") do
|
314
|
+
before do |command|
|
315
|
+
check << "D"
|
316
|
+
end
|
317
|
+
|
318
|
+
action do |command|
|
319
|
+
check << "E"
|
320
|
+
end
|
321
|
+
|
322
|
+
after do |command|
|
323
|
+
check << "F"
|
324
|
+
end
|
325
|
+
end
|
326
|
+
|
327
|
+
allow(Bovem::Parser).to receive(:parse).and_return(nil)
|
328
|
+
command.execute(args)
|
329
|
+
expect(check).to eq(["A", "B", "C"])
|
330
|
+
end
|
331
|
+
|
332
|
+
it "should execute the hooks even they are methods" do
|
333
|
+
check = []
|
334
|
+
child = []
|
335
|
+
args = ["command"]
|
336
|
+
|
337
|
+
allow(command).to receive(:application).and_return(Object.new)
|
338
|
+
allow(command.application).to receive(:action_before) { check << "A" }
|
339
|
+
allow(command.application).to receive("action_perform") { check << "B" }
|
340
|
+
allow(command.application).to receive(:action_after) { check << "C" }
|
341
|
+
|
342
|
+
command.before(:action_before)
|
343
|
+
command.action("action_perform")
|
344
|
+
command.after(:action_after)
|
345
|
+
|
346
|
+
allow(Bovem::Parser).to receive(:parse).and_return(nil)
|
347
|
+
command.execute(args)
|
348
|
+
expect(check).to eq(["A", "B", "C"])
|
349
|
+
end
|
350
|
+
|
351
|
+
it "should skip its actions and hooks and pass control to the subcommand" do
|
352
|
+
check = []
|
353
|
+
child = []
|
354
|
+
args = ["command"]
|
355
|
+
|
356
|
+
command.before do |command|
|
357
|
+
check << "A"
|
358
|
+
end
|
359
|
+
|
360
|
+
command.action do |command|
|
361
|
+
check << "B"
|
362
|
+
end
|
363
|
+
|
364
|
+
command.after do |command|
|
365
|
+
check << "C"
|
366
|
+
end
|
367
|
+
|
368
|
+
command.command("subcommand") do
|
369
|
+
before do |command|
|
370
|
+
check << "D"
|
371
|
+
end
|
372
|
+
|
373
|
+
action do |command|
|
374
|
+
check << "E"
|
375
|
+
end
|
376
|
+
|
377
|
+
after do |command|
|
378
|
+
check << "F"
|
379
|
+
end
|
380
|
+
end
|
381
|
+
|
382
|
+
allow(Bovem::Parser).to receive(:parse) do |cmd, args|
|
383
|
+
cmd == command ? {name: "subcommand", args: args} : nil
|
384
|
+
end
|
385
|
+
command.execute(args)
|
386
|
+
expect(check).to eq(["D", "E", "F"])
|
387
|
+
end
|
388
|
+
|
389
|
+
it "should show help if action is not defined and no subcommand is found" do
|
390
|
+
check = []
|
391
|
+
child = []
|
392
|
+
args = ["command"]
|
393
|
+
|
394
|
+
command.command("subcommand") do
|
395
|
+
before do |command|
|
396
|
+
check << "D"
|
397
|
+
end
|
398
|
+
|
399
|
+
action do |command|
|
400
|
+
check << "E"
|
401
|
+
end
|
402
|
+
|
403
|
+
after do |command|
|
404
|
+
check << "F"
|
405
|
+
end
|
406
|
+
end
|
407
|
+
|
408
|
+
allow(Bovem::Parser).to receive(:parse).and_return(nil)
|
409
|
+
expect(command).to receive(:show_help)
|
410
|
+
command.execute(args)
|
411
|
+
expect(check).to eq([])
|
412
|
+
end
|
413
|
+
end
|
414
|
+
|
415
|
+
describe "#get_options" do
|
416
|
+
let(:reference){
|
417
|
+
c = Bovem::Command.new("command") do
|
418
|
+
option("aaa", [], {type: Integer, default: 456})
|
419
|
+
option("bbb", [], {type: String})
|
420
|
+
option("ccc", [], {type: Array, default: ["1", "2"]})
|
421
|
+
end
|
422
|
+
|
423
|
+
c.application = Bovem::Application.new do |a|
|
424
|
+
option("aaa", [], {type: Integer, default: 123})
|
425
|
+
option("ddd", [], {type: Float})
|
426
|
+
action {}
|
427
|
+
end
|
428
|
+
|
429
|
+
c
|
430
|
+
}
|
431
|
+
|
432
|
+
it "should return the full list of options" do
|
433
|
+
Bovem::Parser.parse(reference.application, ["--aaa", "111", "--ddd", "2.0"])
|
434
|
+
Bovem::Parser.parse(reference, ["--bbb", "2.0", "--ccc", "A,B,C"])
|
435
|
+
expect(reference.get_options.symbolize_keys).to eq({application_aaa: 111, application_ddd: 2.0, aaa: 456, bbb: "2.0", ccc: ["A", "B", "C"]})
|
436
|
+
end
|
437
|
+
|
438
|
+
it "should only return provided options if required to" do
|
439
|
+
Bovem::Parser.parse(reference.application, ["--aaa", "111"])
|
440
|
+
Bovem::Parser.parse(reference, ["--ccc", "2.0"])
|
441
|
+
expect(reference.get_options(false).symbolize_keys).to eq({application_aaa: 111, aaa: 456, ccc: ["2.0"]})
|
442
|
+
end
|
443
|
+
|
444
|
+
it "should skip application options if required to" do
|
445
|
+
Bovem::Parser.parse(reference.application, ["--aaa", "111", "--ddd", "2.0"])
|
446
|
+
Bovem::Parser.parse(reference, ["--bbb", "2.0", "--ccc", "A,B,C"])
|
447
|
+
expect(reference.get_options(true, false).symbolize_keys).to eq({aaa: 456, bbb: "2.0", ccc: ["A", "B", "C"]})
|
448
|
+
expect(reference.get_options(true, nil).symbolize_keys).to eq({aaa: 456, bbb: "2.0", ccc: ["A", "B", "C"]})
|
449
|
+
end
|
450
|
+
|
451
|
+
it "should apply the requested prefix for command options" do
|
452
|
+
Bovem::Parser.parse(reference.application, ["--aaa", "111", "--ddd", "2.0"])
|
453
|
+
Bovem::Parser.parse(reference, ["--bbb", "2.0", "--ccc", "A,B,C"])
|
454
|
+
expect(reference.get_options(true, false, "PREFIX").symbolize_keys).to eq({PREFIXaaa: 456, PREFIXbbb: "2.0", PREFIXccc: ["A", "B", "C"]})
|
455
|
+
end
|
456
|
+
|
457
|
+
it "should apply the requested prefix for application options" do
|
458
|
+
Bovem::Parser.parse(reference.application, ["--aaa", "111", "--ddd", "2.0"])
|
459
|
+
Bovem::Parser.parse(reference, ["--bbb", "2.0", "--ccc", "A,B,C"])
|
460
|
+
expect(reference.get_options(true, "APP").symbolize_keys).to eq({APPaaa: 111, APPddd: 2.0, aaa: 456, bbb: "2.0", ccc: ["A", "B", "C"]})
|
461
|
+
end
|
462
|
+
|
463
|
+
it "should only return requested options" do
|
464
|
+
Bovem::Parser.parse(reference.application, ["--aaa", "111", "--ddd", "2.0"])
|
465
|
+
Bovem::Parser.parse(reference, ["--bbb", "2.0", "--ccc", "A,B,C"])
|
466
|
+
expect(reference.get_options(true, "application_", "", :aaa, :bbb).symbolize_keys).to eq({application_aaa: 111, aaa: 456, bbb: "2.0"})
|
467
|
+
end
|
468
|
+
|
469
|
+
it "should apply higher precedence to command options in case of conflicts" do
|
470
|
+
Bovem::Parser.parse(reference.application, ["--aaa", "111", "--ddd", "2.0"])
|
471
|
+
Bovem::Parser.parse(reference, ["--bbb", "2.0", "--ccc", "A,B,C"])
|
472
|
+
expect(reference.get_options(true, "", "").symbolize_keys).to eq({ddd: 2.0, aaa: 456, bbb: "2.0", ccc: ["A", "B", "C"]})
|
473
|
+
end
|
474
|
+
end
|
475
|
+
|
476
|
+
describe "#show_help" do
|
477
|
+
it "should behave differently for application" do
|
478
|
+
allow(Kernel).to receive(:exit).and_return(0)
|
479
|
+
|
480
|
+
expect(application.console).to receive(:write).with("[NAME]")
|
481
|
+
expect(application.console).to receive(:write).at_least(1)
|
482
|
+
application.show_help
|
483
|
+
end
|
484
|
+
|
485
|
+
it "should print a banner" do
|
486
|
+
allow(Kernel).to receive(:exit).and_return(0)
|
487
|
+
|
488
|
+
command.banner = "BANNER"
|
489
|
+
expect(application.console).to receive(:write).with("[DESCRIPTION]")
|
490
|
+
expect(application.console).to receive(:write).at_least(1)
|
491
|
+
command.show_help
|
492
|
+
end
|
493
|
+
|
494
|
+
it "should print options" do
|
495
|
+
allow(Kernel).to receive(:exit).and_return(0)
|
496
|
+
|
497
|
+
application.option("global", [], {type: String})
|
498
|
+
command.option("local")
|
499
|
+
|
500
|
+
expect(application.console).to receive(:write).with("[GLOBAL OPTIONS]")
|
501
|
+
expect(application.console).to receive(:write).with("[OPTIONS]")
|
502
|
+
expect(application.console).to receive(:write).at_least(1)
|
503
|
+
application.show_help
|
504
|
+
command.show_help
|
505
|
+
end
|
506
|
+
|
507
|
+
it "should print subcommands" do
|
508
|
+
allow(Kernel).to receive(:exit).and_return(0)
|
509
|
+
|
510
|
+
command.command("subcommand")
|
511
|
+
expect(application.console).to receive(:write).with("[COMMANDS]")
|
512
|
+
expect(application.console).to receive(:write).with("[SUBCOMMANDS]")
|
513
|
+
expect(application.console).to receive(:write).at_least(1)
|
514
|
+
application.show_help
|
515
|
+
command.show_help
|
516
|
+
end
|
517
|
+
|
518
|
+
it "should exit" do
|
519
|
+
allow(Kernel).to receive(:puts)
|
520
|
+
allow(Bovem::Console.any_instance).to receive(:write)
|
521
|
+
|
522
|
+
expect(Kernel).to receive(:exit).with(0).exactly(1)
|
523
|
+
application.show_help
|
524
|
+
end
|
525
|
+
end
|
526
|
+
end
|