convoy 1.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 +7 -0
- data/.gitignore +20 -0
- data/.irbrc +3 -0
- data/.rspec +3 -0
- data/.ruby-version +1 -0
- data/.travis.yml +8 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +705 -0
- data/Rakefile +1 -0
- data/convoy.gemspec +24 -0
- data/examples/.my_apprc +24 -0
- data/examples/basic +10 -0
- data/examples/basic_config_file +16 -0
- data/examples/basic_conflicts +17 -0
- data/examples/basic_depends_on +25 -0
- data/examples/basic_flags +15 -0
- data/examples/basic_options +14 -0
- data/examples/basic_options_multi +15 -0
- data/examples/basic_require_arguments +17 -0
- data/examples/basic_texts +21 -0
- data/examples/basic_validations +21 -0
- data/examples/basic_with_everything +30 -0
- data/examples/commands/example_command.rb +13 -0
- data/examples/suite_complex +65 -0
- data/examples/suite_simple +19 -0
- data/examples/suite_with_sub_commands +94 -0
- data/lib/convoy.rb +83 -0
- data/lib/convoy/action_command/base.rb +85 -0
- data/lib/convoy/action_command/escort_utility_command.rb +53 -0
- data/lib/convoy/app.rb +127 -0
- data/lib/convoy/arguments.rb +20 -0
- data/lib/convoy/auto_options.rb +71 -0
- data/lib/convoy/error/error.rb +33 -0
- data/lib/convoy/formatter/command.rb +87 -0
- data/lib/convoy/formatter/commands.rb +37 -0
- data/lib/convoy/formatter/cursor_position.rb +29 -0
- data/lib/convoy/formatter/default_help_formatter.rb +117 -0
- data/lib/convoy/formatter/global_command.rb +17 -0
- data/lib/convoy/formatter/option.rb +152 -0
- data/lib/convoy/formatter/options.rb +28 -0
- data/lib/convoy/formatter/shell_command_executor.rb +49 -0
- data/lib/convoy/formatter/stream_output_formatter.rb +88 -0
- data/lib/convoy/formatter/string_grid.rb +108 -0
- data/lib/convoy/formatter/string_splitter.rb +50 -0
- data/lib/convoy/formatter/terminal.rb +30 -0
- data/lib/convoy/global_pre_parser.rb +43 -0
- data/lib/convoy/logger.rb +75 -0
- data/lib/convoy/option_dependency_validator.rb +82 -0
- data/lib/convoy/option_parser.rb +155 -0
- data/lib/convoy/setup/configuration/generator.rb +75 -0
- data/lib/convoy/setup/configuration/instance.rb +34 -0
- data/lib/convoy/setup/configuration/loader.rb +43 -0
- data/lib/convoy/setup/configuration/locator/base.rb +19 -0
- data/lib/convoy/setup/configuration/locator/chaining.rb +29 -0
- data/lib/convoy/setup/configuration/locator/descending_to_home.rb +23 -0
- data/lib/convoy/setup/configuration/locator/executing_script_directory.rb +15 -0
- data/lib/convoy/setup/configuration/locator/specified_directory.rb +21 -0
- data/lib/convoy/setup/configuration/merge_tool.rb +38 -0
- data/lib/convoy/setup/configuration/reader.rb +36 -0
- data/lib/convoy/setup/configuration/writer.rb +46 -0
- data/lib/convoy/setup/dsl/action.rb +17 -0
- data/lib/convoy/setup/dsl/command.rb +67 -0
- data/lib/convoy/setup/dsl/config_file.rb +13 -0
- data/lib/convoy/setup/dsl/global.rb +29 -0
- data/lib/convoy/setup/dsl/options.rb +81 -0
- data/lib/convoy/setup_accessor.rb +206 -0
- data/lib/convoy/trollop.rb +861 -0
- data/lib/convoy/utils.rb +21 -0
- data/lib/convoy/validator.rb +45 -0
- data/spec/integration/basic_config_file_spec.rb +126 -0
- data/spec/integration/basic_conflicts_spec.rb +47 -0
- data/spec/integration/basic_depends_on_spec.rb +275 -0
- data/spec/integration/basic_options_spec.rb +41 -0
- data/spec/integration/basic_options_with_multi_spec.rb +30 -0
- data/spec/integration/basic_spec.rb +38 -0
- data/spec/integration/basic_validations_spec.rb +77 -0
- data/spec/integration/basic_with_arguments_spec.rb +35 -0
- data/spec/integration/basic_with_text_fields_spec.rb +21 -0
- data/spec/integration/suite_simple_spec.rb +45 -0
- data/spec/integration/suite_sub_command_spec.rb +51 -0
- data/spec/lib/convoy/action_command/base_spec.rb +200 -0
- data/spec/lib/convoy/formatter/command_spec.rb +238 -0
- data/spec/lib/convoy/formatter/global_command_spec.rb +50 -0
- data/spec/lib/convoy/formatter/option_spec.rb +300 -0
- data/spec/lib/convoy/formatter/shell_command_executor_spec.rb +59 -0
- data/spec/lib/convoy/formatter/stream_output_formatter_spec.rb +214 -0
- data/spec/lib/convoy/formatter/string_grid_spec.rb +59 -0
- data/spec/lib/convoy/formatter/string_splitter_spec.rb +50 -0
- data/spec/lib/convoy/formatter/terminal_spec.rb +19 -0
- data/spec/lib/convoy/setup/configuration/generator_spec.rb +101 -0
- data/spec/lib/convoy/setup/configuration/loader_spec.rb +79 -0
- data/spec/lib/convoy/setup/configuration/locator/chaining_spec.rb +81 -0
- data/spec/lib/convoy/setup/configuration/locator/descending_to_home_spec.rb +57 -0
- data/spec/lib/convoy/setup/configuration/locator/executing_script_directory_spec.rb +29 -0
- data/spec/lib/convoy/setup/configuration/locator/specified_directory_spec.rb +33 -0
- data/spec/lib/convoy/setup/configuration/merge_tool_spec.rb +41 -0
- data/spec/lib/convoy/setup/configuration/reader_spec.rb +41 -0
- data/spec/lib/convoy/setup/configuration/writer_spec.rb +75 -0
- data/spec/lib/convoy/setup_accessor_spec.rb +226 -0
- data/spec/lib/convoy/utils_spec.rb +30 -0
- data/spec/spec_helper.rb +29 -0
- data/spec/support/integration_helpers.rb +2 -0
- data/spec/support/matchers/execute_action_for_command_matcher.rb +21 -0
- data/spec/support/matchers/execute_action_with_arguments_matcher.rb +25 -0
- data/spec/support/matchers/execute_action_with_options_matcher.rb +29 -0
- data/spec/support/matchers/exit_with_code_matcher.rb +29 -0
- data/spec/support/shared_contexts/integration_setup.rb +34 -0
- metadata +292 -0
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
module Convoy
|
|
2
|
+
module Setup
|
|
3
|
+
module Configuration
|
|
4
|
+
module Locator
|
|
5
|
+
class ExecutingScriptDirectory < Base
|
|
6
|
+
def locate
|
|
7
|
+
location_directory = File.dirname($0)
|
|
8
|
+
filepath = File.expand_path(File.join(location_directory, filename))
|
|
9
|
+
File.exists?(filepath) ? filepath : nil
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
module Convoy
|
|
2
|
+
module Setup
|
|
3
|
+
module Configuration
|
|
4
|
+
module Locator
|
|
5
|
+
class SpecifiedDirectory < Base
|
|
6
|
+
attr_reader :location_directory
|
|
7
|
+
|
|
8
|
+
def initialize(filename, location_directory)
|
|
9
|
+
super(filename)
|
|
10
|
+
@location_directory = location_directory
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def locate
|
|
14
|
+
filepath = File.expand_path(File.join(location_directory, filename))
|
|
15
|
+
File.exists?(filepath) ? filepath : nil
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
module Convoy
|
|
2
|
+
module Setup
|
|
3
|
+
module Configuration
|
|
4
|
+
class MergeTool
|
|
5
|
+
def initialize(new_config_hash, old_config_hash)
|
|
6
|
+
@new_config_hash = new_config_hash
|
|
7
|
+
@old_config_hash = old_config_hash
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def config_hash
|
|
11
|
+
merge_config(@new_config_hash, @old_config_hash)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
private
|
|
15
|
+
|
|
16
|
+
def merge_config(new_hash, old_hash)
|
|
17
|
+
new_hash.keys.each do |key|
|
|
18
|
+
new_config_value = new_hash[key]
|
|
19
|
+
old_config_value = old_hash[key]
|
|
20
|
+
|
|
21
|
+
if new_config_value.kind_of?(Hash) && old_config_value.kind_of?(Hash)
|
|
22
|
+
new_hash[key] = merge_config(new_config_value, old_config_value)
|
|
23
|
+
elsif old_config_value.nil?
|
|
24
|
+
new_hash[key] = new_config_value
|
|
25
|
+
else
|
|
26
|
+
new_hash[key] = old_config_value
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
if key == :user
|
|
30
|
+
new_hash[key] = old_config_value
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
new_hash
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
require 'json'
|
|
2
|
+
|
|
3
|
+
module Convoy
|
|
4
|
+
module Setup
|
|
5
|
+
module Configuration
|
|
6
|
+
class Reader
|
|
7
|
+
attr_reader :path
|
|
8
|
+
|
|
9
|
+
def initialize(path)
|
|
10
|
+
@path = path
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def read
|
|
14
|
+
data = {}
|
|
15
|
+
data = load_config_at_path if path
|
|
16
|
+
Instance.new(path, data)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
private
|
|
20
|
+
|
|
21
|
+
def load_config_at_path
|
|
22
|
+
data = {}
|
|
23
|
+
begin
|
|
24
|
+
json = File.read(path)
|
|
25
|
+
hash = ::JSON.parse(json)
|
|
26
|
+
data = Convoy::Utils.symbolize_keys(hash)
|
|
27
|
+
rescue => e
|
|
28
|
+
error_logger.warn { "Found config at #{path}, but failed to load it, perhaps your JSON syntax is invalid. Attempting to continue without..." }
|
|
29
|
+
error_logger.debug(e)
|
|
30
|
+
end
|
|
31
|
+
data
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
require 'json'
|
|
2
|
+
require 'fileutils'
|
|
3
|
+
|
|
4
|
+
module Convoy
|
|
5
|
+
module Setup
|
|
6
|
+
module Configuration
|
|
7
|
+
class Writer
|
|
8
|
+
attr_reader :path, :data
|
|
9
|
+
|
|
10
|
+
def initialize(path, data)
|
|
11
|
+
@path = path
|
|
12
|
+
@data = data
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def write
|
|
16
|
+
if path && !File.exists?(path)
|
|
17
|
+
save_to_file
|
|
18
|
+
Instance.new(path, data)
|
|
19
|
+
else
|
|
20
|
+
Instance.blank
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def update
|
|
25
|
+
current_data = {}
|
|
26
|
+
if File.exists? path
|
|
27
|
+
current_data = Reader.new(path).read.data
|
|
28
|
+
end
|
|
29
|
+
@data = Convoy::Setup::Configuration::MergeTool.new(data, current_data).config_hash
|
|
30
|
+
save_to_file
|
|
31
|
+
Instance.new(path, data)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
private
|
|
35
|
+
|
|
36
|
+
def save_to_file
|
|
37
|
+
current_path = File.expand_path(path)
|
|
38
|
+
FileUtils.mkdir_p(File.dirname(current_path))
|
|
39
|
+
File.open(current_path, "w") do |f|
|
|
40
|
+
f.puts ::JSON.pretty_generate(data)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
module Convoy
|
|
2
|
+
module Setup
|
|
3
|
+
module Dsl
|
|
4
|
+
class Action
|
|
5
|
+
class << self
|
|
6
|
+
def action(command_name, instance, &block)
|
|
7
|
+
instance.instance_variable_set(:"@block", block)
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def initialize(command_name = :global)
|
|
12
|
+
@command_name = command_name
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
module Convoy
|
|
2
|
+
module Setup
|
|
3
|
+
module Dsl
|
|
4
|
+
class Command
|
|
5
|
+
def initialize(name, options = {}, &block)
|
|
6
|
+
reset(name)
|
|
7
|
+
@description = options[:description] || options[:desc] || ""
|
|
8
|
+
@aliases = [options[:aliases] || []].flatten
|
|
9
|
+
@requires_arguments ||= options[:requires_arguments]
|
|
10
|
+
block.call(self) if block_given?
|
|
11
|
+
rescue => e
|
|
12
|
+
raise Convoy::ClientError.new("Problem with syntax of command '#{@name}' configuration", e)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def options(&block)
|
|
16
|
+
Options.options(@name, @options, &block)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def action(&block)
|
|
20
|
+
Action.action(@name, @action, &block)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def command(name, options = {}, &block)
|
|
24
|
+
options[:requires_arguments] = @requires_arguments
|
|
25
|
+
command = Command.new(name.to_sym, options, &block)
|
|
26
|
+
aliases = [options[:aliases] || []].flatten + [name]
|
|
27
|
+
aliases.each do |name|
|
|
28
|
+
@commands[name.to_sym] = command
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def requires_arguments(boolean = true)
|
|
33
|
+
raise Convoy::ClientError.new("Parameter to 'requires_arguments' must be a boolean") unless [true, false].include?(boolean)
|
|
34
|
+
@requires_arguments = boolean
|
|
35
|
+
@commands.each do |command|
|
|
36
|
+
command.requires_arguments(boolean)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def summary(summary)
|
|
41
|
+
@summary = summary
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def description(description)
|
|
45
|
+
@description = description
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
private
|
|
49
|
+
|
|
50
|
+
def reset(name)
|
|
51
|
+
@name = name
|
|
52
|
+
@summary = nil
|
|
53
|
+
@description = nil
|
|
54
|
+
@requires_arguments = false
|
|
55
|
+
@commands = {}
|
|
56
|
+
@options = Options.new(name)
|
|
57
|
+
@action = Action.new(name)
|
|
58
|
+
custom_reset
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def custom_reset
|
|
62
|
+
@aliases = []
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
module Convoy
|
|
2
|
+
module Setup
|
|
3
|
+
module Dsl
|
|
4
|
+
class Global < Command
|
|
5
|
+
def initialize(&block)
|
|
6
|
+
reset(:global)
|
|
7
|
+
block.call(self)
|
|
8
|
+
rescue => e
|
|
9
|
+
raise Convoy::ClientError.new("Problem with syntax of global configuration", e)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def config_file(name, options = {})
|
|
13
|
+
@config_file = ConfigFile.new(name, options)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def version(version)
|
|
17
|
+
@version = version
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
private
|
|
21
|
+
|
|
22
|
+
def custom_reset
|
|
23
|
+
@version = nil
|
|
24
|
+
@config_file = nil
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
module Convoy
|
|
2
|
+
module Setup
|
|
3
|
+
module Dsl
|
|
4
|
+
class Options
|
|
5
|
+
class << self
|
|
6
|
+
def options(command_name, instance, &block)
|
|
7
|
+
block.call(instance) if block_given?
|
|
8
|
+
rescue => e
|
|
9
|
+
raise Convoy::ClientError.new("Problem with syntax of #{instance.instance_variable_get(:"@command_name")} options block", e)
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def initialize(command_name = :global)
|
|
14
|
+
@command_name = command_name
|
|
15
|
+
@options = {}
|
|
16
|
+
@dependencies = {}
|
|
17
|
+
@conflicts = {}
|
|
18
|
+
@validations = {}
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def opt(name, desc="", opts={})
|
|
22
|
+
opts[:desc] ||= desc
|
|
23
|
+
@options[name] ||= opts
|
|
24
|
+
dependency(name, :on => opts[:depends_on]) if opts[:depends_on]
|
|
25
|
+
conflict(*[name, opts[:conflicts_with]].flatten) if opts[:conflicts_with]
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def validate(name, description, &block)
|
|
29
|
+
@validations[name] ||= []
|
|
30
|
+
@validations[name] << {:desc => description, :block => block}
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def dependency(option_name, opts = {})
|
|
34
|
+
ensure_dependency_specification_syntax(opts)
|
|
35
|
+
@dependencies[option_name] ||= []
|
|
36
|
+
rules_as_array(opts).each do |rule|
|
|
37
|
+
ensure_no_self_dependency(option_name, rule)
|
|
38
|
+
@dependencies[option_name] << rule
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def conflict(*opts)
|
|
43
|
+
opts.each do |opt|
|
|
44
|
+
conflicts_for_opt = opts.reject { |value| value == opt }
|
|
45
|
+
@conflicts[opt] ||= []
|
|
46
|
+
@conflicts[opt] += conflicts_for_opt
|
|
47
|
+
@conflicts[opt].uniq!
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
private
|
|
52
|
+
def ensure_no_self_dependency(option_name, rule)
|
|
53
|
+
case rule
|
|
54
|
+
when Hash
|
|
55
|
+
rule.each_pair do |rule_option, rule_option_value|
|
|
56
|
+
handle_possible_self_dependency(option_name, rule_option)
|
|
57
|
+
end
|
|
58
|
+
else
|
|
59
|
+
handle_possible_self_dependency(option_name, rule)
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def ensure_dependency_specification_syntax(opts)
|
|
64
|
+
unless opts[:on]
|
|
65
|
+
raise Convoy::ClientError.new("Problem with syntax of dependency specification in #{@command_name} options block, #{option_name} missing ':on' condition")
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def rules_as_array(opts)
|
|
70
|
+
[opts[:on]].flatten
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def handle_possible_self_dependency(option_name, rule)
|
|
74
|
+
if option_name == rule
|
|
75
|
+
raise Convoy::ClientError.new("Problem with syntax of dependency specification in #{@command_name} options block, #{option_name} is set to depend on itself")
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
module Convoy
|
|
2
|
+
class SetupAccessor
|
|
3
|
+
attr_reader :global_instance
|
|
4
|
+
|
|
5
|
+
def initialize(global_instance)
|
|
6
|
+
@global_instance = global_instance
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def options_for(context = [])
|
|
10
|
+
with_context(context) do |current_context|
|
|
11
|
+
options_hash_from(current_context)
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def conflicting_options_for(context = [])
|
|
16
|
+
with_context(context) do |current_context|
|
|
17
|
+
conflicts_hash_for(current_context)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def validations_for(context = [])
|
|
22
|
+
with_context(context) do |current_context|
|
|
23
|
+
validations_hash_from(current_context)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def dependencies_for(context = [])
|
|
28
|
+
with_context(context) do |current_context|
|
|
29
|
+
dependencies_hash_from(current_context)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def command_names_for(context = [])
|
|
34
|
+
with_context(context) do |current_context|
|
|
35
|
+
command_names_from(current_context)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def canonical_command_names_for(context = [])
|
|
40
|
+
with_context(context) do |current_context|
|
|
41
|
+
canonical_command_names_from(current_context)
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def action_for(context = [])
|
|
46
|
+
with_context(context) do |current_context|
|
|
47
|
+
action_block_from(current_context)
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def arguments_required_for(context = [])
|
|
52
|
+
with_context(context) do |current_context|
|
|
53
|
+
context_requires_arguments(current_context)
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def has_config_file?
|
|
58
|
+
config_file_object != nil
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def config_file_autocreatable?
|
|
62
|
+
autocreatable = fetch_instance_variable_from(config_file_object, :autocreate)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def config_file
|
|
66
|
+
name = fetch_instance_variable_from(config_file_object, :name)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def version
|
|
70
|
+
version_string = fetch_instance_variable_from(global_instance, :version)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def summary_for(context = [])
|
|
74
|
+
with_context(context) do |current_context|
|
|
75
|
+
fetch_instance_variable_from(current_context, :summary)
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def description_for(context = [])
|
|
80
|
+
with_context(context) do |current_context|
|
|
81
|
+
fetch_instance_variable_from(current_context, :description)
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def command_description_for(command_name, context = [])
|
|
86
|
+
with_context(context) do |current_context|
|
|
87
|
+
commands = fetch_instance_variable_from(current_context, :commands)
|
|
88
|
+
fetch_instance_variable_from(commands[command_name], :description)
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def command_summary_for(command_name, context = [])
|
|
93
|
+
with_context(context) do |current_context|
|
|
94
|
+
commands = fetch_instance_variable_from(current_context, :commands)
|
|
95
|
+
fetch_instance_variable_from(commands[command_name], :summary)
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def command_aliases_for(command_name, context = [])
|
|
100
|
+
with_context(context) do |current_context|
|
|
101
|
+
commands = fetch_instance_variable_from(current_context, :commands)
|
|
102
|
+
description = fetch_instance_variable_from(commands[command_name], :aliases)
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def add_global_option(name, desc, options = {})
|
|
107
|
+
with_context([]) do |current_context|
|
|
108
|
+
options_object = options_object_from(current_context)
|
|
109
|
+
options_object.opt name, desc, options
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def add_global_command(name, options = {}, &block)
|
|
114
|
+
global_instance.command(name, options, &block)
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
private
|
|
118
|
+
|
|
119
|
+
def config_file_object
|
|
120
|
+
config_file = fetch_instance_variable_from(global_instance, :config_file)
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def with_context(context = [], &block)
|
|
124
|
+
context = [] if context.nil? || context.empty?
|
|
125
|
+
context = [context] unless context.kind_of?(Array)
|
|
126
|
+
current_context = global_instance
|
|
127
|
+
context.each do |command_name|
|
|
128
|
+
commands = fetch_instance_variable_from(current_context, :commands)
|
|
129
|
+
current_context = commands[command_name.to_sym]
|
|
130
|
+
end
|
|
131
|
+
block.call(current_context)
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def context_requires_arguments(context_object)
|
|
135
|
+
requires_arguments = fetch_instance_variable_from(context_object, :requires_arguments)
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def action_block_from(context_object)
|
|
139
|
+
action_object = fetch_instance_variable_from(context_object, :action)
|
|
140
|
+
block = fetch_instance_variable_from(action_object, :block)
|
|
141
|
+
#TODO make sure that if there is no block we exit with a client error
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def command_names_from(context_object)
|
|
145
|
+
commands = fetch_instance_variable_from(context_object, :commands)
|
|
146
|
+
commands.keys
|
|
147
|
+
#TODO make sure there can be no errors here and at worst it is an empty array
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def canonical_command_names_from(context_object)
|
|
151
|
+
commands = fetch_instance_variable_from(context_object, :commands)
|
|
152
|
+
commands.select do |key, command|
|
|
153
|
+
aliases = fetch_instance_variable_from(command, :aliases)
|
|
154
|
+
!aliases.include?(key)
|
|
155
|
+
end.keys
|
|
156
|
+
#TODO make sure there can be no errors here and at worst it is an empty array
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
def options_hash_from(context_object)
|
|
160
|
+
ensure_context_object(context_object, {}) do
|
|
161
|
+
options_object = options_object_from(context_object)
|
|
162
|
+
fetch_instance_variable_from(options_object, :options)
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
def options_object_from(context_object)
|
|
167
|
+
ensure_context_object(context_object, nil) do
|
|
168
|
+
fetch_instance_variable_from(context_object, :options)
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
def conflicts_hash_for(context_object)
|
|
173
|
+
ensure_context_object(context_object, {}) do
|
|
174
|
+
options_object = options_object_from(context_object)
|
|
175
|
+
fetch_instance_variable_from(options_object, :conflicts)
|
|
176
|
+
end
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
def validations_hash_from(context_object)
|
|
180
|
+
ensure_context_object(context_object, {}) do
|
|
181
|
+
validations_object = fetch_instance_variable_from(context_object, :options)
|
|
182
|
+
fetch_instance_variable_from(validations_object, :validations)
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
def dependencies_hash_from(context_object)
|
|
187
|
+
ensure_context_object(context_object, {}) do
|
|
188
|
+
options_object = options_object_from(context_object)
|
|
189
|
+
fetch_instance_variable_from(options_object, :dependencies)
|
|
190
|
+
end
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
def fetch_instance_variable_from_setup(instance_variable)
|
|
194
|
+
fetch_instance_variable_from(global_instance, instance_variable)
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
def fetch_instance_variable_from(instance, instance_variable)
|
|
198
|
+
instance_variable_symbol = :"@#{instance_variable.to_s}"
|
|
199
|
+
instance.instance_variable_get(instance_variable_symbol)
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
def ensure_context_object(context_object, default_value, &block)
|
|
203
|
+
context_object ? block.call : default_value
|
|
204
|
+
end
|
|
205
|
+
end
|
|
206
|
+
end
|