clin 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
[![Coverage Status](https://coveralls.io/repos/timcolonel/clin/badge.svg?branch=master)](https://coveralls.io/r/timcolonel/clin?branch=master)
|
4
4
|
[![Code Climate](https://codeclimate.com/github/timcolonel/clin/badges/gpa.svg)](https://codeclimate.com/github/timcolonel/clin)
|
5
5
|
[![Inline docs](http://inch-ci.org/github/timcolonel/clin.svg?branch=master)](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
|