clive 0.6.2 → 0.7.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.
- data/README.md +129 -126
- data/lib/clive.rb +30 -119
- data/lib/clive/bool.rb +32 -34
- data/lib/clive/command.rb +171 -54
- data/lib/clive/exceptions.rb +2 -2
- data/lib/clive/ext.rb +21 -3
- data/lib/clive/flag.rb +80 -67
- data/lib/clive/formatter.rb +180 -0
- data/lib/clive/option.rb +41 -25
- data/lib/clive/output.rb +14 -18
- data/lib/clive/parser.rb +79 -16
- data/lib/clive/switch.rb +8 -17
- data/lib/clive/tokens.rb +1 -1
- data/lib/clive/version.rb +2 -2
- data/spec/clive/bool_spec.rb +54 -0
- data/spec/clive/command_spec.rb +260 -0
- data/spec/clive/exceptions_spec.rb +1 -0
- data/spec/clive/ext_spec.rb +1 -0
- data/spec/clive/flag_spec.rb +84 -0
- data/spec/clive/formatter_spec.rb +108 -0
- data/spec/clive/option_spec.rb +34 -0
- data/spec/clive/output_spec.rb +5 -0
- data/spec/clive/parser_spec.rb +106 -0
- data/spec/clive/switch_spec.rb +14 -0
- data/spec/clive/tokens_spec.rb +38 -0
- data/spec/shared_specs.rb +16 -0
- data/spec/spec_helper.rb +12 -0
- metadata +34 -8
data/README.md
CHANGED
@@ -12,190 +12,193 @@ Install with:
|
|
12
12
|
|
13
13
|
## How To
|
14
14
|
|
15
|
-
|
16
|
-
|
15
|
+
Simply include `Clive::Parser` to start using.
|
16
|
+
A simple example:
|
17
|
+
|
18
|
+
# test.rb
|
17
19
|
require 'clive'
|
18
20
|
|
19
|
-
|
20
|
-
|
21
|
-
|
21
|
+
class CLI
|
22
|
+
include Clive::Parser
|
23
|
+
option_hash :config
|
24
|
+
|
25
|
+
desc 'Run verbosely'
|
26
|
+
switch :v, :verbose do
|
27
|
+
config[:verbose] = true
|
28
|
+
end
|
29
|
+
|
22
30
|
end
|
23
|
-
|
24
|
-
p
|
31
|
+
CLI.parse(ARGV)
|
32
|
+
p CLI.config
|
25
33
|
|
26
34
|
This creates a very simple interface which can have one switch, you can then use the
|
27
35
|
long or short form to call the block.
|
28
36
|
|
29
|
-
|
37
|
+
test.rb -v
|
30
38
|
#=> {:verbose => true}
|
31
|
-
|
39
|
+
test.rb --verbose
|
32
40
|
#=> {:verbose => true}
|
33
41
|
|
34
42
|
|
35
43
|
### Switches
|
36
44
|
|
37
|
-
|
38
|
-
|
39
|
-
`-v`, or `switch(:verbose) {}` creates a switch that only responds to `--verbose`.
|
40
|
-
|
41
|
-
### Boolean
|
42
|
-
|
43
|
-
Boolean switches allow you to accept arguments like `--no-verbose` and `--verbose`,
|
44
|
-
and deal with both situations in the same block.
|
45
|
+
The most basic options. When they are called by either name the block is run. To create
|
46
|
+
a switch use `#switch`.
|
45
47
|
|
46
|
-
|
47
|
-
|
48
|
+
switch :s do
|
49
|
+
# code
|
48
50
|
end
|
49
|
-
|
51
|
+
# Called with '-s'
|
50
52
|
|
51
|
-
|
53
|
+
switch :long do
|
54
|
+
# code
|
55
|
+
end
|
56
|
+
# Called with '--long'
|
52
57
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
58
|
+
switch :b, :both do
|
59
|
+
# code
|
60
|
+
end
|
61
|
+
# Called with '-b' or '--both'
|
62
|
+
|
63
|
+
|
64
|
+
### Booleans
|
65
|
+
|
66
|
+
Boolean switches allow you to easily create a pair of switches, eg. `--force` and
|
67
|
+
`--no-force`. The block given is passed either true or false depending on which was
|
68
|
+
used.
|
69
|
+
|
70
|
+
bool :f, :force do |truth|
|
71
|
+
p truth
|
72
|
+
end
|
73
|
+
# '-f' returns true
|
74
|
+
# '--force' returns true
|
75
|
+
# '--no-force' returns false
|
76
|
+
|
77
|
+
You must provide a long name, a short name is optional.
|
59
78
|
|
60
|
-
As you can see the true case can be triggered with the short or long form, the false
|
61
|
-
case can be triggered by appending "no-" to the long form, and it can't be triggered
|
62
|
-
with a short form.
|
63
79
|
|
64
80
|
### Flags
|
65
81
|
|
66
|
-
Flags are like switches but
|
82
|
+
Flags are like switches but take one or more arguments, these are then passed to the
|
83
|
+
block.
|
67
84
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
end
|
85
|
+
# Creates a flag with a mandatory argument
|
86
|
+
flag :with, :args => "ARG" do |arg|
|
87
|
+
puts arg
|
72
88
|
end
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
#=> "short"
|
83
|
-
|
84
|
-
The argument is then passed into the block. As you can see you can use short, long,
|
85
|
-
equals, or no equals to call flags. As with switches you can call `flag(:p) {|i| ...}`
|
86
|
-
which responds to `-p ...`, `flag(:print) {|i| ...}` which responds to `--print ...`
|
87
|
-
or `--print=...`. Flags can have default values, for that situation put square brackets
|
88
|
-
round the argument name.
|
89
|
-
|
90
|
-
flag(:p, :print, "[ARG]", "Print ARG or "hey" by default) do |i|
|
91
|
-
i ||= "hey"
|
92
|
-
p i
|
89
|
+
|
90
|
+
# Creates a flag with an optional argument, by using []
|
91
|
+
flag :with, :args => "[ARG]" do |arg|
|
92
|
+
puts arg
|
93
|
+
end
|
94
|
+
|
95
|
+
# Creates a flag with multiple arguments
|
96
|
+
flag :with, :args => "FIRST [OPTIONAL]" do |i, j|
|
97
|
+
puts i, j
|
93
98
|
end
|
94
99
|
|
95
|
-
|
96
|
-
|
97
|
-
Commands work like in git, here's an example:
|
100
|
+
You can also provide a list of options to select from.
|
98
101
|
|
99
|
-
|
100
|
-
|
101
|
-
command(:add) do
|
102
|
-
opts[:add] = {}
|
103
|
-
flag(:r, :require, "Require a library") {|i| opts[:add][:lib] = i}
|
104
|
-
end
|
102
|
+
flag :choose, :args => %w(small med large) do |choice|
|
103
|
+
puts choice
|
105
104
|
end
|
106
|
-
c.parse(ARGV)
|
107
|
-
p opts
|
108
105
|
|
109
|
-
|
106
|
+
flag :number, :args => 1..5 do |num|
|
107
|
+
puts num
|
108
|
+
end
|
110
109
|
|
111
|
-
my_file add -r Clive
|
112
|
-
#=> {:add => {:lib => "Clive"}}
|
113
110
|
|
114
|
-
Commands
|
115
|
-
the command is executed on finding the command, this allows you to put other code within
|
116
|
-
the block specific for the command, as shown above.
|
111
|
+
### Commands
|
117
112
|
|
113
|
+
Commands allow you to group a collection of options (or more commands) under a keyword.
|
114
|
+
The block provided is run when one of the names for the command is encountered, but the
|
115
|
+
blocks of the options in it are only ran when they are found.
|
116
|
+
|
117
|
+
command :init, :create do
|
118
|
+
bool :force do |truth|
|
119
|
+
puts "Force"
|
120
|
+
end
|
121
|
+
end
|
122
|
+
# 'init --force'
|
123
|
+
|
118
124
|
|
119
125
|
### Arguments
|
120
126
|
|
121
|
-
Anything that
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
+
Anything that is not captured as a command, option or argument of a flag, is returned by
|
128
|
+
#parse in an array.
|
129
|
+
|
130
|
+
class Args
|
131
|
+
include Clive::Parser
|
132
|
+
|
133
|
+
switch(:hey) { puts "Hey" }
|
127
134
|
end
|
128
|
-
args =
|
135
|
+
args = Args.parse(ARGV)
|
129
136
|
p args
|
130
137
|
|
131
|
-
|
132
|
-
|
133
|
-
my_file --size big /usr/bin
|
134
|
-
#=> ["/usr/bin"]
|
138
|
+
# `file --hey argument "A string"`
|
139
|
+
#=> ['argument', 'A string']
|
135
140
|
|
136
141
|
|
137
|
-
###
|
142
|
+
### Option Handling
|
138
143
|
|
139
144
|
You are able to intercept errors when an option does not exist in a similar way to
|
140
145
|
`method_missing`.
|
141
146
|
|
142
|
-
|
147
|
+
class Missing
|
143
148
|
option_missing do |name|
|
144
149
|
puts "#{name} was used but not defined"
|
145
150
|
end
|
146
151
|
end
|
147
|
-
|
152
|
+
Missing.parse %w(--hey)
|
148
153
|
#=> hey was used but not defined
|
149
154
|
|
150
|
-
I was hoping to provide a similar way of intercepting commands as well but these could
|
151
|
-
also be arguments which means it could result in unexpected results. For this reason I
|
152
|
-
will not be implementing `command_missing`.
|
153
155
|
|
154
|
-
###
|
156
|
+
### Help Formatting
|
155
157
|
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
opts[:add][:framework] << i
|
169
|
-
end
|
170
|
-
|
171
|
-
command(:init, "Initialize the project after creating") do
|
172
|
-
switch(:m, :minimum, "Use minimum settings") {opts[:add][:min] = true}
|
173
|
-
flag(:w, :width) {|i| opts[:add][:width] = i.to_i}
|
174
|
-
end
|
175
|
-
|
176
|
-
end
|
177
|
-
|
178
|
-
switch(:version, "Show version") do
|
179
|
-
puts "1.0.0"
|
180
|
-
exit
|
158
|
+
There are two built in help formats the default, with colour, and a pure white one. To
|
159
|
+
change the formatter call `#help_formatter` with :default, or :white.
|
160
|
+
|
161
|
+
Optionally you can create your own formatter, like so:
|
162
|
+
|
163
|
+
class CLI
|
164
|
+
help_formatter do |h|
|
165
|
+
h.switch "{prepend}{names.join(', ')} {spaces}# {desc}"
|
166
|
+
h.bool "{prepend}{names.join(', ')} {spaces}# {desc}"
|
167
|
+
h.flag "{prepend}{names.join(', ')} {args.join(' ')} {spaces}# {desc}" <<
|
168
|
+
"{options.join('(', ', ', ')')}"
|
169
|
+
h.command "{prepend}{names.join(', ')} {spaces}# {desc}"
|
181
170
|
end
|
182
171
|
end
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
####
|
172
|
+
|
173
|
+
Which would look like:
|
174
|
+
|
175
|
+
Usage: my_app [command] [options]
|
188
176
|
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
177
|
+
Commands:
|
178
|
+
test # A command
|
179
|
+
|
180
|
+
Options:
|
181
|
+
-h, --help # Display help
|
182
|
+
--[no-]force # Force build
|
183
|
+
|
184
|
+
You have access to the variables:
|
185
|
+
|
186
|
+
* prepend - a string of spaces as specified when `#help_formatter` is called
|
187
|
+
* names - an array of names for the option
|
188
|
+
* spaces - a string of spaces to align the descriptions properly
|
189
|
+
* desc - a string of the description for the option
|
190
|
+
|
191
|
+
And for flags you have access to:
|
192
|
+
|
193
|
+
* args - an array of arguments for the flag
|
194
|
+
* options - an array of options to choose from
|
195
|
+
|
196
|
+
Inside the { and } you can put any ruby, so feel free to use joins on the array.
|
194
197
|
|
195
198
|
|
196
199
|
## Clive::Output
|
197
200
|
|
198
|
-
This is a new bit that allows you to
|
201
|
+
This is a new bit that allows you to colourise output from the command line, by patching a
|
199
202
|
few methods onto String.
|
200
203
|
|
201
204
|
require 'clive/output'
|
data/lib/clive.rb
CHANGED
@@ -1,137 +1,48 @@
|
|
1
1
|
require 'clive/parser'
|
2
|
-
require 'clive/output'
|
3
2
|
|
4
3
|
# Clive is a simple dsl for creating command line interfaces
|
5
4
|
#
|
6
5
|
# @example Simple Example
|
7
6
|
#
|
8
|
-
#
|
9
|
-
#
|
10
|
-
#
|
11
|
-
#
|
12
|
-
#
|
13
|
-
#
|
14
|
-
# c.parse(ARGV)
|
15
|
-
# # app -v
|
16
|
-
# #=> {:verbose => true}
|
17
|
-
#
|
18
|
-
# @example Class Style with Inheritence
|
19
|
-
#
|
20
|
-
# opts = {}
|
21
|
-
# class BasicCommands < Clive
|
22
|
-
# switch :basic do
|
23
|
-
# p "basic"
|
7
|
+
# class CLI
|
8
|
+
# include Clive::Parser
|
9
|
+
#
|
10
|
+
# desc 'A switch'
|
11
|
+
# switch :s, :switch do
|
12
|
+
# puts "You used a switch"
|
24
13
|
# end
|
25
|
-
#
|
26
|
-
#
|
27
|
-
#
|
28
|
-
#
|
29
|
-
# p "sub"
|
14
|
+
#
|
15
|
+
# desc 'A flag'
|
16
|
+
# flag :hello, :args => "NAME" do |name|
|
17
|
+
# puts "Hello, #{name}"
|
30
18
|
# end
|
31
|
-
# end
|
32
|
-
#
|
33
|
-
# SubCommands.parse(ARGV)
|
34
|
-
# # app --basic --sub
|
35
|
-
# #=> "basic"
|
36
|
-
# #=> "sub"
|
37
|
-
#
|
38
|
-
# @example Non-simple Example
|
39
|
-
#
|
40
|
-
# opts = {}
|
41
|
-
# c = Clive.new do
|
42
|
-
# bool(:v, :verbose, "Run verbosely") {|i| opts[:verbose] = i}
|
43
19
|
#
|
44
|
-
#
|
45
|
-
#
|
46
|
-
#
|
47
|
-
#
|
48
|
-
#
|
49
|
-
#
|
50
|
-
#
|
20
|
+
# desc 'True or false'
|
21
|
+
# bool :which do |which|
|
22
|
+
# case which
|
23
|
+
# when true
|
24
|
+
# puts "true, yay"
|
25
|
+
# when false
|
26
|
+
# puts "false, not yay"
|
27
|
+
# end
|
28
|
+
# end
|
29
|
+
#
|
30
|
+
# option_list :purchases
|
31
|
+
#
|
32
|
+
# command :new, :buy do
|
33
|
+
# switch :toaster do
|
34
|
+
# purchases << :toaster
|
51
35
|
# end
|
52
36
|
#
|
53
|
-
#
|
54
|
-
#
|
55
|
-
# flag(:w, :width) {|i| opts[:add][:width] = i.to_i}
|
37
|
+
# switch :tv do
|
38
|
+
# purchases << :tv
|
56
39
|
# end
|
57
|
-
#
|
58
40
|
# end
|
59
41
|
#
|
60
|
-
# switch :version, "Show version" do
|
61
|
-
# puts "1.0.0"
|
62
|
-
# exit
|
63
|
-
# end
|
64
42
|
# end
|
65
|
-
# ARGV = c.parse(ARGV)
|
66
|
-
# # app add framework=blueprint --force --verbose
|
67
|
-
# #=> {:add => {:framework => ['blueprint'], :force => true}, :verbose => true}
|
68
43
|
#
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
# is that it has no name and it's block is executed immediately on creation.
|
73
|
-
#
|
74
|
-
# @return [Command] the base command
|
75
|
-
#
|
76
|
-
attr_accessor :base
|
77
|
-
|
78
|
-
def initialize(&block)
|
79
|
-
@base = Command.new(true, &block)
|
80
|
-
end
|
81
|
-
|
82
|
-
# Parse the base command
|
83
|
-
def parse(argv)
|
84
|
-
@base.run(argv)
|
85
|
-
end
|
86
|
-
|
87
|
-
# @group Base Proxy Methods
|
88
|
-
|
89
|
-
# @see Command#switches
|
90
|
-
# @return [Array] switches in +base+
|
91
|
-
def switches
|
92
|
-
@base.switches
|
93
|
-
end
|
94
|
-
|
95
|
-
# @see Command#commands
|
96
|
-
# @return [Array] commands in +base+
|
97
|
-
def commands
|
98
|
-
@base.commands
|
99
|
-
end
|
100
|
-
|
101
|
-
# @see Command#flags
|
102
|
-
# @return [Array] flags in +base+
|
103
|
-
def flags
|
104
|
-
@base.flags
|
105
|
-
end
|
106
|
-
|
107
|
-
# @see Command#bools
|
108
|
-
# @return [Array] bools in +base+
|
109
|
-
def bools
|
110
|
-
@base.bools
|
111
|
-
end
|
112
|
-
|
113
|
-
# @group Clive Class Methods
|
114
|
-
|
115
|
-
@@base = Clive::Command.new(true)
|
116
|
-
|
117
|
-
def self.flag(*args, &block)
|
118
|
-
@@base.flag(*args, &block)
|
119
|
-
end
|
120
|
-
|
121
|
-
def self.switch(*args, &block)
|
122
|
-
@@base.switch(*args, &block)
|
123
|
-
end
|
124
|
-
|
125
|
-
def self.command(*args, &block)
|
126
|
-
@@base.command(*args, &block)
|
127
|
-
end
|
128
|
-
|
129
|
-
def self.bool(*args, &block)
|
130
|
-
@@base.bool(*args, &block)
|
131
|
-
end
|
132
|
-
|
133
|
-
def self.parse(argv)
|
134
|
-
@@base.run(argv)
|
135
|
-
end
|
44
|
+
# CLI.parse(ARGV)
|
45
|
+
#
|
46
|
+
module Clive
|
136
47
|
|
137
48
|
end
|