clin 0.2.0 → 0.3.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/.travis.yml +0 -1
- data/CHANGELOG.md +7 -0
- data/README.md +1 -0
- data/clin.gemspec +1 -1
- data/examples/auto_option.rb +17 -0
- data/examples/dispatcher.rb +17 -23
- data/examples/list_option.rb +3 -8
- data/examples/nested_dispatcher.rb +8 -53
- data/examples/simple.rb +3 -22
- data/examples/test.rb +9 -9
- data/lib/clin/argument.rb +3 -3
- data/lib/clin/command.rb +11 -126
- data/lib/clin/command_mixin/core.rb +152 -0
- data/lib/clin/command_mixin/dispatcher.rb +34 -0
- data/lib/clin/command_mixin/options.rb +134 -0
- data/lib/clin/command_mixin.rb +9 -0
- data/lib/clin/general_option.rb +3 -1
- data/lib/clin/option.rb +37 -3
- data/lib/clin/option_list.rb +1 -1
- data/lib/clin/shell.rb +111 -0
- data/lib/clin/shell_interaction/choose.rb +59 -0
- data/lib/clin/shell_interaction/file_conflict.rb +53 -0
- data/lib/clin/shell_interaction/yes_or_no.rb +16 -0
- data/lib/clin/shell_interaction.rb +34 -0
- data/lib/clin/version.rb +1 -1
- data/lib/clin.rb +10 -1
- data/spec/clin/command_dispacher_spec.rb +3 -3
- data/spec/clin/command_mixin/core_spec.rb +37 -0
- data/spec/clin/{command_options_mixin_spec.rb → command_mixin/options_spec.rb} +11 -8
- data/spec/clin/command_parser_spec.rb +2 -2
- data/spec/clin/command_spec.rb +3 -3
- data/spec/clin/option_spec.rb +40 -0
- data/spec/clin/shell_interaction/choose_spec.rb +54 -0
- data/spec/clin/shell_spec.rb +147 -0
- data/spec/examples/auto_option_spec.rb +11 -0
- metadata +24 -7
- data/lib/clin/command_options_mixin.rb +0 -118
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: be4386269225e68a69c419a0a4a90668f5da8287
|
4
|
+
data.tar.gz: 0a33c686511f6a0498fe40276c936b6574fbe497
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2878f163e2974a9a3c93e9f565e9b5fdaf5ec91bcced8856b95b7045f45eca8427da8a22631f1741da582982ab1c575e19c6115cee4dd8078a69a08f217cf41d
|
7
|
+
data.tar.gz: eba57a52877c4ea5fca71571ab1a534459f173d9715028774b76a6be8fb9e7721b077fdc8371839ba770a43dfde17bd34fd7bf2c71e2001e88c6898be7458fab
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,7 +1,14 @@
|
|
1
|
+
## 0.3.0
|
2
|
+
Features:
|
3
|
+
- Added a shell class for any user interaction.
|
4
|
+
- Added `priority` to test commands in specific order and not the order they where loaded.(#4)
|
5
|
+
- Added `auto_option` to define specific options cleaner.(#5)
|
6
|
+
|
1
7
|
## 0.2.0
|
2
8
|
Features:
|
3
9
|
- Allow unknown options to be ignored and not raise Error(#1)
|
4
10
|
- Added list options. For options that can be multiple times in the same command(#2)
|
5
11
|
- Added default value for options.(#3)
|
12
|
+
|
6
13
|
## 0.1.0
|
7
14
|
Inital release.
|
data/README.md
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
[](https://coveralls.io/r/timcolonel/clin?branch=master)
|
4
4
|
[](https://codeclimate.com/github/timcolonel/clin)
|
5
5
|
[](http://inch-ci.org/github/timcolonel/clin)
|
6
|
+
|
6
7
|
Clin is Command Line Interface library that provide an clean api for complex command configuration.
|
7
8
|
The way Clin is design allow a command defined by the user to be called via the command line as well as directly in the code without any additional configuration
|
8
9
|
## Installation
|
data/clin.gemspec
CHANGED
@@ -21,7 +21,7 @@ Gem::Specification.new do |spec|
|
|
21
21
|
spec.add_dependency 'activesupport', '>=4.0'
|
22
22
|
spec.add_development_dependency 'bundler', '~> 1.7'
|
23
23
|
spec.add_development_dependency 'rake', '~> 10.0'
|
24
|
-
spec.add_development_dependency 'rspec'
|
24
|
+
spec.add_development_dependency 'rspec', '>= 3.0'
|
25
25
|
spec.add_development_dependency 'coveralls'
|
26
26
|
spec.add_development_dependency 'faker'
|
27
27
|
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
$LOAD_PATH.push File.expand_path('../../lib', __FILE__)
|
2
|
+
require 'clin'
|
3
|
+
require 'clin'
|
4
|
+
|
5
|
+
# Simple command Example
|
6
|
+
class AutoOptionCommand < Clin::Command
|
7
|
+
auto_option :echo, '-e --eko=message Echo the message'
|
8
|
+
general_option Clin::HelpOptions
|
9
|
+
|
10
|
+
def run
|
11
|
+
puts @params[:echo]
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
# Run example:
|
16
|
+
# AutoOptionCommand.parse('-e "Some message 1"').run
|
17
|
+
# AutoOptionCommand.parse('--eko="Some message 2"').run
|
data/examples/dispatcher.rb
CHANGED
@@ -5,7 +5,7 @@ require 'clin'
|
|
5
5
|
class DisplayCommand < Clin::Command
|
6
6
|
arguments 'display <message>'
|
7
7
|
|
8
|
-
|
8
|
+
description 'Display the given message'
|
9
9
|
|
10
10
|
def run
|
11
11
|
puts "Display: '#{params[:message]}'"
|
@@ -16,33 +16,27 @@ end
|
|
16
16
|
class PrintCommand < Clin::Command
|
17
17
|
arguments 'print <message>'
|
18
18
|
|
19
|
-
|
19
|
+
description 'Print the given message'
|
20
20
|
|
21
21
|
def run
|
22
22
|
puts "Print: '#{params[:message]}'"
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
begin
|
36
|
-
Clin::CommandDispatcher.parse('display -h').run
|
37
|
-
rescue Clin::CommandLineError => e
|
38
|
-
puts e
|
39
|
-
end
|
40
|
-
puts
|
41
|
-
puts '=' * 60
|
42
|
-
puts
|
43
|
-
begin
|
44
|
-
Clin::CommandDispatcher.parse('-h')
|
45
|
-
rescue Clin::CommandLineError => e
|
46
|
-
puts e
|
26
|
+
# Simple command Example
|
27
|
+
class PrintAltCommand < Clin::Command
|
28
|
+
arguments 'print <message>'
|
29
|
+
|
30
|
+
description 'Print the given message alternative'
|
31
|
+
prioritize
|
32
|
+
|
33
|
+
def run
|
34
|
+
puts "Print alt: '#{params[:message]}'"
|
47
35
|
end
|
48
36
|
end
|
37
|
+
|
38
|
+
# Example of run:
|
39
|
+
# Clin::CommandDispatcher.parse('display "My Message"').run
|
40
|
+
# Clin::CommandDispatcher.parse('print "My Message"').run
|
41
|
+
# Clin::CommandDispatcher.parse('display -h').run
|
42
|
+
# Clin::CommandDispatcher.parse('-h')
|
data/examples/list_option.rb
CHANGED
@@ -17,11 +17,6 @@ class ListCommand < Clin::Command
|
|
17
17
|
end
|
18
18
|
end
|
19
19
|
end
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
puts
|
24
|
-
puts '=' * 60
|
25
|
-
puts
|
26
|
-
ListCommand.parse('--echo "Message 3" --echo "Message 4" -ll').run
|
27
|
-
end
|
20
|
+
# Use examples:
|
21
|
+
# ListCommand.parse('--echo "Message 1" --echo "Message 2"').run
|
22
|
+
# ListCommand.parse('--echo "Message 3" --echo "Message 4" -ll').run
|
@@ -9,7 +9,7 @@ class DispatchCommand < Clin::Command
|
|
9
9
|
|
10
10
|
flag_option :verbose, 'Verbose the output'
|
11
11
|
|
12
|
-
|
12
|
+
description 'YOU print the given message'
|
13
13
|
|
14
14
|
def run
|
15
15
|
puts 'Should not be called'
|
@@ -22,7 +22,7 @@ class DisplayCommand < DispatchCommand
|
|
22
22
|
option :echo, 'Display more text'
|
23
23
|
option :times, 'Display the text multiple times', type: Integer
|
24
24
|
|
25
|
-
|
25
|
+
description 'Display the given message'
|
26
26
|
|
27
27
|
def run
|
28
28
|
puts "I Display: '#{params[:message]}'"
|
@@ -33,60 +33,15 @@ end
|
|
33
33
|
class PrintCommand < DispatchCommand
|
34
34
|
arguments 'you print <message>'
|
35
35
|
|
36
|
-
|
36
|
+
description 'Print the given message'
|
37
37
|
|
38
38
|
def run
|
39
39
|
puts "I Print: '#{params[:message]}'"
|
40
40
|
end
|
41
41
|
end
|
42
42
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
Clin::CommandDispatcher.parse('you print "My Message"').run
|
49
|
-
puts
|
50
|
-
puts '=' * 60
|
51
|
-
puts
|
52
|
-
begin
|
53
|
-
Clin::CommandDispatcher.parse('you -h').run
|
54
|
-
rescue Clin::CommandLineError => e
|
55
|
-
puts e
|
56
|
-
end
|
57
|
-
puts
|
58
|
-
puts '=' * 60
|
59
|
-
puts
|
60
|
-
begin
|
61
|
-
Clin::CommandDispatcher.parse('-h')
|
62
|
-
rescue Clin::CommandLineError => e
|
63
|
-
puts e
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
# Output:
|
68
|
-
#
|
69
|
-
# $ ruby dispatcher.rb
|
70
|
-
# I Display: 'My Message'
|
71
|
-
#
|
72
|
-
# ============================================================
|
73
|
-
#
|
74
|
-
# I Print: 'My Message'
|
75
|
-
#
|
76
|
-
# ============================================================
|
77
|
-
#
|
78
|
-
# Usage: command you <args>... [Options]
|
79
|
-
#
|
80
|
-
# Options:
|
81
|
-
# -h, --help Show the help.
|
82
|
-
#
|
83
|
-
# Description:
|
84
|
-
# YOU print the given message
|
85
|
-
#
|
86
|
-
#
|
87
|
-
# ============================================================
|
88
|
-
#
|
89
|
-
# Usage:
|
90
|
-
# command you <args>... [Options]
|
91
|
-
# command you display <message> [Options]
|
92
|
-
# command you print <message> [Options]
|
43
|
+
# Example of run:
|
44
|
+
# Clin::CommandDispatcher.parse('you display "My Message"').run
|
45
|
+
# Clin::CommandDispatcher.parse('you print "My Message"').run
|
46
|
+
# Clin::CommandDispatcher.parse('you -h').run
|
47
|
+
# Clin::CommandDispatcher.parse('-h')
|
data/examples/simple.rb
CHANGED
@@ -15,25 +15,6 @@ class SimpleCommand < Clin::Command
|
|
15
15
|
end
|
16
16
|
end
|
17
17
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
puts '=' * 60
|
22
|
-
puts
|
23
|
-
begin
|
24
|
-
SimpleCommand.parse('').run
|
25
|
-
rescue Clin::HelpError => e
|
26
|
-
puts e
|
27
|
-
end
|
28
|
-
end
|
29
|
-
# $ ruby simple.rb
|
30
|
-
# My Message
|
31
|
-
# SOME
|
32
|
-
#
|
33
|
-
# ============================================================
|
34
|
-
#
|
35
|
-
# Usage: command display <message> [Options]
|
36
|
-
#
|
37
|
-
# Options:
|
38
|
-
# -e, --echo ECHO Echo some text
|
39
|
-
# -h, --help Show the help.
|
18
|
+
# Run example:
|
19
|
+
# SimpleCommand.parse('display "My Message" --echo SOME').run
|
20
|
+
# SimpleCommand.parse('').run
|
data/examples/test.rb
CHANGED
@@ -1,9 +1,9 @@
|
|
1
|
-
$LOAD_PATH.push File.expand_path('../../lib', __FILE__)
|
2
|
-
require 'clin'
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
puts
|
1
|
+
$LOAD_PATH.push File.expand_path('../../lib', __FILE__)
|
2
|
+
require 'clin'
|
3
|
+
|
4
|
+
|
5
|
+
shell = Clin::Shell.new
|
6
|
+
|
7
|
+
choice = shell.choose('What?', %w(france usa italy germany))
|
8
|
+
|
9
|
+
puts 'YOu ' + choice
|
data/lib/clin/argument.rb
CHANGED
@@ -20,7 +20,7 @@ class Clin::Argument
|
|
20
20
|
|
21
21
|
# Check if the argument is optional(i.e [arg])
|
22
22
|
def check_optional(argument)
|
23
|
-
if
|
23
|
+
if check_between(argument, '[', ']')
|
24
24
|
@optional = true
|
25
25
|
return argument[1...-1]
|
26
26
|
end
|
@@ -38,7 +38,7 @@ class Clin::Argument
|
|
38
38
|
|
39
39
|
# Check if the argument is variable(i.e <arg>)
|
40
40
|
def check_variable(argument)
|
41
|
-
if
|
41
|
+
if check_between(argument, '<', '>')
|
42
42
|
@variable = true
|
43
43
|
return argument[1...-1]
|
44
44
|
end
|
@@ -94,7 +94,7 @@ class Clin::Argument
|
|
94
94
|
# beck_between('[<arg>]', '<'. '>') # => false
|
95
95
|
# beck_between('[<arg>', '<'. '>') # => raise Clin::Error
|
96
96
|
# ```
|
97
|
-
def
|
97
|
+
def check_between(argument, start_char, end_char)
|
98
98
|
if argument[0] == start_char
|
99
99
|
if argument[-1] != end_char
|
100
100
|
fail Clin::Error, "Argument format error! Cannot start
|
data/lib/clin/command.rb
CHANGED
@@ -1,83 +1,15 @@
|
|
1
1
|
require 'clin'
|
2
|
-
require 'clin/command_options_mixin'
|
3
2
|
require 'clin/argument'
|
4
3
|
require 'shellwords'
|
5
4
|
require 'clin/common/help_options'
|
6
5
|
|
7
6
|
# Clin Command
|
8
|
-
class Clin::Command
|
9
|
-
|
10
|
-
|
7
|
+
class Clin::Command
|
8
|
+
include Clin::CommandMixin::Core
|
9
|
+
include Clin::CommandMixin::Dispatcher
|
10
|
+
include Clin::CommandMixin::Options
|
11
11
|
|
12
|
-
|
13
|
-
class_attribute :_redispatch_args
|
14
|
-
class_attribute :_abstract
|
15
|
-
class_attribute :_exe_name
|
16
|
-
class_attribute :_skip_options
|
17
|
-
|
18
|
-
self.args = []
|
19
|
-
self.description = ''
|
20
|
-
self._abstract = false
|
21
|
-
self._skip_options = false
|
22
|
-
|
23
|
-
# Trigger when a class inherit this class
|
24
|
-
# Rest class_attributes that should not be shared with subclass
|
25
|
-
# @param subclass [Clin::Command]
|
26
|
-
def self.inherited(subclass)
|
27
|
-
subclass._redispatch_args = nil
|
28
|
-
subclass._abstract = false
|
29
|
-
subclass._skip_options = false
|
30
|
-
super
|
31
|
-
end
|
32
|
-
|
33
|
-
# Mark the class as abstract
|
34
|
-
def self.abstract(value)
|
35
|
-
self._abstract = value
|
36
|
-
end
|
37
|
-
|
38
|
-
# Set or get the exe name.
|
39
|
-
# Executable name that will be display in the usage.
|
40
|
-
# If exe_name is not set in a class or it's parent it will use the global setting Clin.exe_name
|
41
|
-
# @param value [String] name of the exe.
|
42
|
-
# ```
|
43
|
-
# class Git < Clin::Command
|
44
|
-
# exe_name 'git'
|
45
|
-
# arguments '<command> <args>...'
|
46
|
-
# end
|
47
|
-
# Git.usage # => git <command> <args>...
|
48
|
-
# ```
|
49
|
-
def self.exe_name(value = nil)
|
50
|
-
self._exe_name = value unless value.nil?
|
51
|
-
self._exe_name ||= Clin.exe_name
|
52
|
-
end
|
53
|
-
|
54
|
-
def self.skip_options(value)
|
55
|
-
self._skip_options = value
|
56
|
-
end
|
57
|
-
|
58
|
-
def self.skip_options?
|
59
|
-
_skip_options
|
60
|
-
end
|
61
|
-
|
62
|
-
def self.redispatch?
|
63
|
-
!_redispatch_args.nil?
|
64
|
-
end
|
65
|
-
|
66
|
-
def self.arguments(args)
|
67
|
-
self.args = []
|
68
|
-
[*args].map(&:split).flatten.each do |arg|
|
69
|
-
self.args += [Clin::Argument.new(arg)]
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
def self.usage
|
74
|
-
a = [exe_name, args.map(&:original).join(' '), '[Options]']
|
75
|
-
a.reject(&:blank?).join(' ')
|
76
|
-
end
|
77
|
-
|
78
|
-
def self.banner
|
79
|
-
"Usage: #{usage}"
|
80
|
-
end
|
12
|
+
general_option 'Clin::HelpOptions'
|
81
13
|
|
82
14
|
# Parse the command and initialize the command object with the parsed options
|
83
15
|
# @param argv [Array|String] command line to parse.
|
@@ -86,63 +18,16 @@ class Clin::Command < Clin::CommandOptionsMixin
|
|
86
18
|
parser.parse
|
87
19
|
end
|
88
20
|
|
89
|
-
#
|
90
|
-
# Used to parse the option
|
91
|
-
# Useful for regenerating the help as well.
|
92
|
-
def self.option_parser(out = {})
|
93
|
-
OptionParser.new do |opts|
|
94
|
-
opts.banner = banner
|
95
|
-
opts.separator ''
|
96
|
-
opts.separator 'Options:'
|
97
|
-
register_options(opts, out)
|
98
|
-
dispatch_doc(opts)
|
99
|
-
unless description.blank?
|
100
|
-
opts.separator "\nDescription:"
|
101
|
-
opts.separator description
|
102
|
-
end
|
103
|
-
opts.separator ''
|
104
|
-
end
|
105
|
-
end
|
106
|
-
|
107
|
-
# Redispatch the command to a sub command with the given arguments
|
108
|
-
# @param args [Array<String>|String] New argument to parse
|
109
|
-
# @param prefix [String] Prefix to add to the beginning of the command
|
110
|
-
# @param commands [Array<Clin::Command.class>] Commands that will be tried against
|
111
|
-
# If no commands are given it will look for Clin::Command in the class namespace
|
112
|
-
# e.g. If those 2 classes are defined.
|
113
|
-
# `MyDispatcher < Clin::Command` and `MyDispatcher::ChildCommand < Clin::Command`
|
114
|
-
# Will test against ChildCommand
|
115
|
-
def self.dispatch(args, prefix: nil, commands: nil)
|
116
|
-
self._redispatch_args = [[*args], prefix, commands]
|
117
|
-
end
|
118
|
-
|
119
|
-
def self.dispatch_doc(opts)
|
120
|
-
return if _redispatch_args.nil?
|
121
|
-
opts.separator 'Examples: '
|
122
|
-
commands = (_redispatch_args[2] || default_commands)
|
123
|
-
commands.each do |cmd_cls|
|
124
|
-
opts.separator "\t#{cmd_cls.usage}"
|
125
|
-
end
|
126
|
-
end
|
127
|
-
|
128
|
-
def self.default_commands
|
129
|
-
# self.constants.map { |c| self.const_get(c) }
|
130
|
-
# .select { |c| c.is_a?(Class) && (c < Clin::Command) }
|
131
|
-
subcommands
|
132
|
-
end
|
133
|
-
|
134
|
-
# List the subcommands
|
135
|
-
# The subcommands are all the Classes inheriting this one that are not set to abstract
|
136
|
-
def self.subcommands
|
137
|
-
subclasses.reject(&:_abstract)
|
138
|
-
end
|
139
|
-
|
140
|
-
general_option 'Clin::HelpOptions'
|
141
|
-
|
21
|
+
# Contains the parameters
|
142
22
|
attr_accessor :params
|
143
23
|
|
24
|
+
# Contains a shell object for user interaction in the command
|
25
|
+
# @see Clin::Shell
|
26
|
+
attr_accessor :shell
|
27
|
+
|
144
28
|
def initialize(params = {})
|
145
29
|
@params = params
|
30
|
+
@shell = Clin::Shell.new
|
146
31
|
self.class.execute_general_options(params)
|
147
32
|
end
|
148
33
|
end
|
@@ -0,0 +1,152 @@
|
|
1
|
+
require 'clin'
|
2
|
+
|
3
|
+
# Contains the core class methods for the command mixin
|
4
|
+
module Clin::CommandMixin::Core
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
included do
|
7
|
+
@_arguments = []
|
8
|
+
@_default_priority = 1000
|
9
|
+
@_priority = 0
|
10
|
+
end
|
11
|
+
|
12
|
+
module ClassMethods # :nodoc:
|
13
|
+
attr_accessor :_arguments
|
14
|
+
attr_accessor :_description
|
15
|
+
attr_accessor :_abstract
|
16
|
+
attr_accessor :_exe_name
|
17
|
+
attr_accessor :_skip_options
|
18
|
+
attr_accessor :_default_priority
|
19
|
+
attr_accessor :_priority
|
20
|
+
|
21
|
+
# Trigger when a class inherit this class
|
22
|
+
# Rest class_attributes that should not be shared with subclass
|
23
|
+
# @param subclass [Clin::Command]
|
24
|
+
def inherited(subclass)
|
25
|
+
subclass._arguments = []
|
26
|
+
subclass._description = ''
|
27
|
+
subclass._abstract = false
|
28
|
+
subclass._skip_options = false
|
29
|
+
subclass._exe_name = @_exe_name
|
30
|
+
subclass._default_priority = @_default_priority.to_f / 2
|
31
|
+
subclass._priority = 0
|
32
|
+
super
|
33
|
+
end
|
34
|
+
|
35
|
+
# Mark the class as abstract
|
36
|
+
def abstract(value)
|
37
|
+
@_abstract = value
|
38
|
+
end
|
39
|
+
|
40
|
+
# Return if the current command class is abstract
|
41
|
+
# @return [Boolean]
|
42
|
+
def abstract?
|
43
|
+
@_abstract
|
44
|
+
end
|
45
|
+
|
46
|
+
# Set or get the exe name.
|
47
|
+
# Executable name that will be display in the usage.
|
48
|
+
# If exe_name is not set in a class or it's parent it will use the global setting Clin.exe_name
|
49
|
+
# @param value [String] name of the exe.
|
50
|
+
# ```
|
51
|
+
# class Git < Clin::Command
|
52
|
+
# exe_name 'git'
|
53
|
+
# arguments '<command> <args>...'
|
54
|
+
# end
|
55
|
+
# Git.usage # => git <command> <args>...
|
56
|
+
# ```
|
57
|
+
def exe_name(value = nil)
|
58
|
+
@_exe_name = value unless value.nil?
|
59
|
+
@_exe_name ||= Clin.exe_name
|
60
|
+
end
|
61
|
+
|
62
|
+
# Allow the current option to skip unknown options.
|
63
|
+
# @param value [Boolean] skip or not
|
64
|
+
def skip_options(value)
|
65
|
+
@_skip_options = value
|
66
|
+
end
|
67
|
+
|
68
|
+
# Is the current command skipping options
|
69
|
+
def skip_options?
|
70
|
+
@_skip_options
|
71
|
+
end
|
72
|
+
|
73
|
+
# Set or get the arguments for the command
|
74
|
+
# @param args [Array<String>] List of arguments to set. If nil it just return the current args.
|
75
|
+
def arguments(args = nil)
|
76
|
+
return @_arguments if args.nil?
|
77
|
+
@_arguments = []
|
78
|
+
[*args].map(&:split).flatten.each do |arg|
|
79
|
+
@_arguments << Clin::Argument.new(arg)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
alias_method :args, :arguments
|
84
|
+
|
85
|
+
# Set or get the description
|
86
|
+
# @param desc [String] Description to set. If nil it just return the current value.
|
87
|
+
def description(desc = nil)
|
88
|
+
@_description = desc unless desc.nil?
|
89
|
+
@_description
|
90
|
+
end
|
91
|
+
|
92
|
+
def usage
|
93
|
+
a = [exe_name, @_arguments.map(&:original).join(' '), '[Options]']
|
94
|
+
a.reject(&:blank?).join(' ')
|
95
|
+
end
|
96
|
+
|
97
|
+
def banner
|
98
|
+
"Usage: #{usage}"
|
99
|
+
end
|
100
|
+
|
101
|
+
# Priorities this command.
|
102
|
+
# This does not set the priority. It add +value+ to the default priority
|
103
|
+
# The default priority is computed using half of the parent default priority.
|
104
|
+
# e.g.
|
105
|
+
# ```
|
106
|
+
# Parent = Class.new(Clin::Command)
|
107
|
+
# Child1 = Class.new(Parent)
|
108
|
+
# Child2 = Class.new(Parent)
|
109
|
+
# Parent.priority # => 500
|
110
|
+
# Child1.priority # => 250
|
111
|
+
# Child2.priority # => 250
|
112
|
+
# Child2.prioritize
|
113
|
+
# Child2.priority # => 251
|
114
|
+
# ```
|
115
|
+
# When dispatching commands they are sorted by priority
|
116
|
+
def prioritize(value = 1)
|
117
|
+
@_priority = value
|
118
|
+
end
|
119
|
+
|
120
|
+
def priority
|
121
|
+
@_default_priority + @_priority
|
122
|
+
end
|
123
|
+
|
124
|
+
# Build the Option Parser object
|
125
|
+
# Used to parse the option
|
126
|
+
# Useful for regenerating the help as well.
|
127
|
+
def option_parser(out = {})
|
128
|
+
OptionParser.new do |opts|
|
129
|
+
opts.banner = banner
|
130
|
+
opts.separator ''
|
131
|
+
opts.separator 'Options:'
|
132
|
+
register_options(opts, out)
|
133
|
+
dispatch_doc(opts)
|
134
|
+
unless @description.blank?
|
135
|
+
opts.separator "\nDescription:"
|
136
|
+
opts.separator @description
|
137
|
+
end
|
138
|
+
opts.separator ''
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
def default_commands
|
143
|
+
subcommands.sort_by(&:priority).reverse
|
144
|
+
end
|
145
|
+
|
146
|
+
# List the subcommands
|
147
|
+
# The subcommands are all the Classes inheriting this one that are not set to abstract
|
148
|
+
def subcommands
|
149
|
+
subclasses.reject(&:abstract?)
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'clin'
|
2
|
+
|
3
|
+
# Dispatcher mixin contains the class methods for command that need to redispatch to subcommands
|
4
|
+
module Clin::CommandMixin::Dispatcher
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
module ClassMethods # :nodoc:
|
7
|
+
attr_accessor :_redispatch_args
|
8
|
+
|
9
|
+
# Redispatch the command to a sub command with the given arguments
|
10
|
+
# @param args [Array<String>|String] New argument to parse
|
11
|
+
# @param prefix [String] Prefix to add to the beginning of the command
|
12
|
+
# @param commands [Array<Clin::Command.class>] Commands that will be tried against
|
13
|
+
# If no commands are given it will look for Clin::Command in the class namespace
|
14
|
+
# e.g. If those 2 classes are defined.
|
15
|
+
# `MyDispatcher < Clin::Command` and `MyDispatcher::ChildCommand < Clin::Command`
|
16
|
+
# Will test against ChildCommand
|
17
|
+
def dispatch(args, prefix: nil, commands: nil)
|
18
|
+
@_redispatch_args = [[*args], prefix, commands]
|
19
|
+
end
|
20
|
+
|
21
|
+
def redispatch?
|
22
|
+
!@_redispatch_args.nil?
|
23
|
+
end
|
24
|
+
|
25
|
+
def dispatch_doc(opts)
|
26
|
+
return if _redispatch_args.nil?
|
27
|
+
opts.separator 'Examples: '
|
28
|
+
commands = (_redispatch_args[2] || default_commands)
|
29
|
+
commands.each do |cmd_cls|
|
30
|
+
opts.separator "\t#{cmd_cls.usage}"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|