mamertes 2.4.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. checksums.yaml +15 -0
  2. data/.DS_Store +0 -0
  3. data/.gitignore +6 -0
  4. data/.travis-gemfile +15 -0
  5. data/.travis.yml +10 -0
  6. data/.yardopts +1 -0
  7. data/Gemfile +21 -0
  8. data/README.md +126 -0
  9. data/Rakefile +29 -0
  10. data/doc/Mamertes.html +155 -0
  11. data/doc/Mamertes/Application.html +3057 -0
  12. data/doc/Mamertes/Command.html +7031 -0
  13. data/doc/Mamertes/CommandMethods.html +125 -0
  14. data/doc/Mamertes/CommandMethods/Children.html +1286 -0
  15. data/doc/Mamertes/CommandMethods/Help.html +209 -0
  16. data/doc/Mamertes/Error.html +631 -0
  17. data/doc/Mamertes/Localizer.html +376 -0
  18. data/doc/Mamertes/Option.html +6671 -0
  19. data/doc/Mamertes/Parser.html +276 -0
  20. data/doc/Mamertes/ParserMethods.html +125 -0
  21. data/doc/Mamertes/ParserMethods/General.html +134 -0
  22. data/doc/Mamertes/ParserMethods/General/ClassMethods.html +574 -0
  23. data/doc/Mamertes/Version.html +189 -0
  24. data/doc/_index.html +276 -0
  25. data/doc/class_list.html +54 -0
  26. data/doc/css/common.css +1 -0
  27. data/doc/css/full_list.css +57 -0
  28. data/doc/css/style.css +338 -0
  29. data/doc/file.README.html +198 -0
  30. data/doc/file_list.html +56 -0
  31. data/doc/frames.html +28 -0
  32. data/doc/index.html +198 -0
  33. data/doc/js/app.js +214 -0
  34. data/doc/js/full_list.js +178 -0
  35. data/doc/js/jquery.js +4 -0
  36. data/doc/method_list.html +509 -0
  37. data/doc/top-level-namespace.html +112 -0
  38. data/lib/mamertes.rb +18 -0
  39. data/lib/mamertes/application.rb +206 -0
  40. data/lib/mamertes/command.rb +529 -0
  41. data/lib/mamertes/option.rb +236 -0
  42. data/lib/mamertes/parser.rb +317 -0
  43. data/lib/mamertes/version.rb +24 -0
  44. data/locales/en.yml +40 -0
  45. data/locales/it.yml +40 -0
  46. data/mamertes.gemspec +30 -0
  47. data/spec/coverage_helper.rb +20 -0
  48. data/spec/mamertes/application_spec.rb +181 -0
  49. data/spec/mamertes/command_spec.rb +526 -0
  50. data/spec/mamertes/option_spec.rb +274 -0
  51. data/spec/mamertes/parser_spec.rb +126 -0
  52. data/spec/spec_helper.rb +15 -0
  53. metadata +115 -0
@@ -0,0 +1,24 @@
1
+ # encoding: utf-8
2
+ #
3
+ # This file is part of the mamertes 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 Mamertes
8
+ # The current version of Mamertes, according to semantic versioning.
9
+ #
10
+ # @see http://semver.org
11
+ module Version
12
+ # The major version.
13
+ MAJOR = 2
14
+
15
+ # The minor version.
16
+ MINOR = 4
17
+
18
+ # The patch version.
19
+ PATCH = 1
20
+
21
+ # The current version number of Mamertes.
22
+ STRING = [MAJOR, MINOR, PATCH].compact.join(".")
23
+ end
24
+ end
@@ -0,0 +1,40 @@
1
+ # encoding: utf-8
2
+ #
3
+ # This file is part of the mamertes 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
+ ---
8
+ mamertes:
9
+ default_application_name: "__APPLICATION__"
10
+ ambigous_command: "Command shortcut \"%1\" is ambiguous across commands %2. Please add some other characters."
11
+ needless_argument: "Option %1 does not expects an argument."
12
+ missing_argument: "Option %1 expects an argument."
13
+ invalid_option: "Invalid option %1."
14
+ invalid_integer: "Option %1 expects a valid integer as argument."
15
+ invalid_float: "Option %1 expects a valid floating number as argument."
16
+ conflicting_options: "Options %1 and %2 have conflicting forms."
17
+ missing_option: "Required option %1 is missing."
18
+ invalid_value: "Value of option %1 must be one of these values: %2."
19
+ invalid_for_regexp: "Value of option %1 must match the regular expression: %2."
20
+ help_option_short_form: "-h"
21
+ help_option_long_form: "--help"
22
+ help_message: "Shows this message."
23
+ help_arg: "ARG"
24
+ help_name: "[NAME]"
25
+ help_application_synopsis: "%s [options] %s[command-options] [arguments] "
26
+ help_command_synopsis: "%s [options] %s %s[command-options] [arguments] "
27
+ help_synopsis: "[SYNOPSIS]"
28
+ help_description: "[DESCRIPTION]"
29
+ help_no_description: "*NO DESCRIPTION PROVIDED*"
30
+ help_options: "[OPTIONS]"
31
+ help_global_options: "[GLOBAL OPTIONS]"
32
+ help_commands: "[COMMANDS]"
33
+ help_subcommands: "[SUBCOMMANDS]"
34
+ help_subcommand_invocation: "[command [sub-command ...]] "
35
+ help_subsubcommand_invocation: "[sub-command [sub-sub-command ...]] "
36
+ help_command_description: "Shows a help about a command."
37
+ existing_command: "The command \"%1\" already exists."
38
+ existing_option_global: "The global option \"%1\" already exists."
39
+ existing_option: "The option \"%1\" already exists for the command \"%2\"."
40
+ missing_app_block: "You have to provide a block to Mamertes::App!"
@@ -0,0 +1,40 @@
1
+ # encoding: utf-8
2
+ #
3
+ # This file is part of the mamertes 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
+ ---
8
+ mamertes:
9
+ default_application_name: "__APPLICAZIONE__"
10
+ ambigous_command: "La scorciatoia di comando \"%1\" è ambigua tra i seguenti comandi %2. Per favore aggiungi qualche altro carattere."
11
+ needless_argument: "L'opzione %1 non richiede un argomento."
12
+ missing_argument: "L'opzione %1 richiede un argomento."
13
+ invalid_option: "L'opzione %1 non è valida."
14
+ invalid_integer: "L'opzione %1 richiede un numero intero valido come argomento."
15
+ invalid_float: "L'opzione %1 richiede un numero decimale valido come argomento."
16
+ conflicting_options: "Le opzioni %1 e %2 hanno forme in conflitto."
17
+ missing_option: "L'opzione richiesta %1 è mancante."
18
+ invalid_value: "Il valore dell'opzione %1 deve essere uno dei seguenti valori: %2."
19
+ invalid_for_regexp: "Il valore dell'opzione %1 deve soddisfare questa espressione regolare: %2."
20
+ help_option_short_form: "-h"
21
+ help_option_long_form: "--help"
22
+ help_message: "Mostra questo messaggio."
23
+ help_arg: "ARG"
24
+ help_name: "[NOME]"
25
+ help_application_synopsis: "%s [opzioni] %s[opzioni-comando] [argomenti] "
26
+ help_command_synopsis: "%s [opzioni] %s %s[opzioni-comando] [argomenti] "
27
+ help_synopsis: "[UTILIZZO]"
28
+ help_description: "[DESCRIZIONE]"
29
+ help_no_description: "*NESSUNA DESCRIZIONE FORNITA*"
30
+ help_options: "[OPZIONI]"
31
+ help_global_options: "[OPZIONI GLOBALI]"
32
+ help_commands: "[COMANDI]"
33
+ help_subcommands: "[SOTTOCOMANDI]"
34
+ help_subcommand_invocation: "[comando [sotto-comando ...]] "
35
+ help_subsubcommand_invocation: "[sotto-comando [sotto-sotto-comando ...]] "
36
+ help_command_description: "Mostra aiuto riguardo un comando."
37
+ existing_command: "Il comando \"%1\" è già esistente."
38
+ existing_option_global: "L'opzione globale \"%1\" è già esistente."
39
+ existing_option: "L'opzione \"%1\" è già esistente per il comando \"%2\"."
40
+ missing_app_block: "Devi fornire un blocco per Mamertes::App!"
@@ -0,0 +1,30 @@
1
+ # encoding: utf-8
2
+ #
3
+ # This file is part of the mamertes 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 "./lib/mamertes/version"
8
+
9
+ Gem::Specification.new do |gem|
10
+ gem.name = "mamertes"
11
+ gem.version = Mamertes::Version::STRING
12
+ gem.authors = ["Shogun"]
13
+ gem.email = ["shogun_panda@me.com"]
14
+ gem.homepage = "http://sw.cow.tc/mamertes"
15
+ gem.summary = %q{Yet another command line manager.}
16
+ gem.description = %q{Yet another command line manager.}
17
+
18
+ gem.rubyforge_project = "mamertes"
19
+ gem.files = `git ls-files`.split("\n")
20
+ gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
21
+ gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
22
+ gem.require_paths = ["lib"]
23
+
24
+ gem.required_ruby_version = ">= 1.9.3"
25
+
26
+ gem.add_dependency("bovem", "~> 2.4.0")
27
+ end
28
+
29
+
30
+
@@ -0,0 +1,20 @@
1
+ # encoding: utf-8
2
+ #
3
+ # This file is part of the mamertes 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 "pathname"
8
+ require "simplecov"
9
+ require "coveralls"
10
+
11
+ Coveralls.wear! if ENV["CI"] || ENV["JENKINS_URL"]
12
+
13
+ SimpleCov.start do
14
+ root = Pathname.new(File.dirname(__FILE__)) + ".."
15
+
16
+ add_filter do |src_file|
17
+ path = Pathname.new(src_file.filename).relative_path_from(root).to_s
18
+ path !~ /^(bin|lib)/
19
+ end
20
+ end
@@ -0,0 +1,181 @@
1
+ # encoding: utf-8
2
+ #
3
+ # This file is part of the mamertes 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 Mamertes::Error do
10
+ describe "#initialize" do
11
+ it "copies attributes" do
12
+ error = ::Mamertes::Error.new("A", "B", "C")
13
+ expect(error.target).to eq("A")
14
+ expect(error.reason).to eq("B")
15
+ expect(error.message).to eq("C")
16
+ end
17
+ end
18
+ end
19
+
20
+ describe Mamertes::Application do
21
+ let(:application) { ::Mamertes::Application.new(locale: :en) }
22
+
23
+ describe "#initialize" do
24
+ it "should call the parent constructor" do
25
+ options = {a: :b}
26
+ block = Proc.new {}
27
+
28
+ expect(::Mamertes::Command).to receive(:new).with(options, &block)
29
+ ::Mamertes::Application.new(options, &block)
30
+ end
31
+
32
+ it "should set good defaults" do
33
+ expect(application.shell).to eq(::Bovem::Shell.instance)
34
+ expect(application.console).to eq(application.shell.console)
35
+ expect(application.skip_commands).to be_false
36
+ expect(application.show_commands).to be_false
37
+ expect(application.output_commands).to be_false
38
+ end
39
+ end
40
+
41
+ describe "#version" do
42
+ it "should set and return the version" do
43
+ expect(application.version).to be_nil
44
+ expect(application.version("another")).to eq("another")
45
+ expect(application.version(nil)).to eq("another")
46
+ end
47
+ end
48
+
49
+ describe "#help_option" do
50
+ it "should add a command and a option" do
51
+ expect(application).to receive(:command).with(:help, {description: "Shows a help about a command."})
52
+ expect(application).to receive(:option).with(:help, ["-h", "--help"], {help: "Shows this message."})
53
+ application.help_option
54
+ end
55
+
56
+ it "should execute associated actions" do
57
+ expect(application).to receive(:show_help).exactly(2)
58
+ expect(application).to receive(:command_help)
59
+
60
+ application.execute(["help", "command"])
61
+ application.execute("-h")
62
+ end
63
+ end
64
+
65
+ describe "#executable_name" do
66
+ it "should return executable name" do
67
+ expect(application.executable_name).to eq($0)
68
+ end
69
+ end
70
+
71
+ describe "#command_help" do
72
+ it "should show the help for the command" do
73
+ command = application.command "command"
74
+ subcommand = command.command "subcommand"
75
+
76
+ expect(application).to receive(:show_help)
77
+ application.command_help(application)
78
+
79
+ expect(command).to receive(:show_help)
80
+ application.argument(command.name)
81
+ application.command_help(application)
82
+
83
+ expect(subcommand).to receive(:show_help)
84
+ application.argument(subcommand.name)
85
+ application.command_help(application)
86
+
87
+ expect(subcommand).to receive(:show_help)
88
+ application.argument("foo")
89
+ application.command_help(application)
90
+ end
91
+ end
92
+
93
+ describe "#run" do
94
+ it "should forward to the shell" do
95
+ expect(application.shell).to receive(:run).with("COMMAND", "MESSAGE", true, "A", false, false, "B")
96
+ application.run("COMMAND", "MESSAGE", "A", "B")
97
+
98
+ application.skip_commands = true
99
+ application.output_commands = true
100
+ application.show_commands = true
101
+ expect(application.shell).to receive(:run).with("COMMAND", "MESSAGE", false, "C", true, true, "D")
102
+ application.run("COMMAND", "MESSAGE", "C", "D")
103
+ end
104
+ end
105
+
106
+ describe ".create" do
107
+ it "should complain about a missing block" do
108
+ expect { ::Mamertes::Application.create }.to raise_error(::Mamertes::Error)
109
+ end
110
+
111
+ it "should print errors" do
112
+ allow(::Mamertes::Application).to receive(:create_application).and_raise(ArgumentError.new("ERROR"))
113
+ expect(Kernel).to receive(:puts).with("ERROR")
114
+ expect(Kernel).to receive(:exit).with(1)
115
+ ::Mamertes::Application.create(__args__: []) {}
116
+ end
117
+
118
+ it "should create a default application" do
119
+ expect(::Mamertes::Application).to receive(:new).with({name: "__APPLICATION__", parent: nil, application: nil, locale: :en})
120
+ ::Mamertes::Application.create({locale: :en}) {}
121
+ end
122
+
123
+ it "should create an application with given options and block" do
124
+ options = {name: "OK"}
125
+
126
+ expect(::Mamertes::Application).to receive(:new).with({name: "OK", parent: nil, application: nil})
127
+ application = ::Mamertes::Application.create(options) {}
128
+ end
129
+
130
+ it "should execute the block" do
131
+ allow_any_instance_of(::Bovem::Console).to receive(:write)
132
+ allow(Kernel).to receive(:exit)
133
+ options = {name: "OK", __args__: []}
134
+ check = false
135
+
136
+ application = ::Mamertes::Application.create(options) { check = true }
137
+ expect(check).to be_true
138
+ expect(application.name).to eq("OK")
139
+ end
140
+
141
+ it "should execute the new application" do
142
+ args = []
143
+
144
+ application = ::Mamertes::Application.create do
145
+ option("require", [], {})
146
+ option("format", [], {})
147
+ option("example", [], {})
148
+
149
+ action do |command|
150
+ args = command.arguments.join("-")
151
+ end
152
+ end
153
+
154
+ expect(args).to eq(ARGV.reject {|a| a =~ /^--/ }.join("-"))
155
+ end
156
+
157
+ it "can override arguments" do
158
+ args = []
159
+
160
+ application = ::Mamertes::Application.create({__args__: ["C", "D"]}) do
161
+ action do |command|
162
+ args = command.arguments.join("-")
163
+ end
164
+ end
165
+
166
+ expect(args).to eq("C-D")
167
+ end
168
+
169
+ it "should not execute the application if requested to" do
170
+ args = []
171
+
172
+ application = ::Mamertes::Application.create(run: false) do
173
+ action do |command|
174
+ args = command.arguments.join("-")
175
+ end
176
+ end
177
+
178
+ expect(args).to eq([])
179
+ end
180
+ end
181
+ end
@@ -0,0 +1,526 @@
1
+ # encoding: utf-8
2
+ #
3
+ # This file is part of the mamertes 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 Mamertes::Command do
10
+ let(:application) {
11
+ ::Mamertes::Application.new(locale: :en) {
12
+ action {}
13
+ }
14
+ }
15
+
16
+ let(:command) {
17
+ c = ::Mamertes::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(::Mamertes::Command.new(name: "command").name).to eq("command")
25
+ end
26
+
27
+ it "should call the block" do
28
+ count = 0
29
+ ::Mamertes::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 = ::Mamertes::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(::Mamertes::Command.new.has_description?).to be_false
128
+ expect(::Mamertes::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(::Mamertes::Command.new.has_banner?).to be_false
135
+ expect(::Mamertes::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(::Mamertes::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(::Mamertes::Error)
176
+ expect {application.option("option")}.to raise_error(::Mamertes::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(::Mamertes::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(::Mamertes::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(::Mamertes::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(::Mamertes::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(::Mamertes::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 = ::Mamertes::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 = ::Mamertes::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
+ Mamertes::Parser.parse(reference.application, ["--aaa", "111", "--ddd", "2.0"])
434
+ Mamertes::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
+ Mamertes::Parser.parse(reference.application, ["--aaa", "111"])
440
+ Mamertes::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
+ Mamertes::Parser.parse(reference.application, ["--aaa", "111", "--ddd", "2.0"])
446
+ Mamertes::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
+ Mamertes::Parser.parse(reference.application, ["--aaa", "111", "--ddd", "2.0"])
453
+ Mamertes::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
+ Mamertes::Parser.parse(reference.application, ["--aaa", "111", "--ddd", "2.0"])
459
+ Mamertes::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
+ Mamertes::Parser.parse(reference.application, ["--aaa", "111", "--ddd", "2.0"])
465
+ Mamertes::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
+ Mamertes::Parser.parse(reference.application, ["--aaa", "111", "--ddd", "2.0"])
471
+ Mamertes::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