clive 0.8.1 → 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.
Files changed (52) hide show
  1. data/LICENSE +1 -1
  2. data/README.md +328 -227
  3. data/lib/clive.rb +130 -50
  4. data/lib/clive/argument.rb +170 -0
  5. data/lib/clive/arguments.rb +139 -0
  6. data/lib/clive/arguments/parser.rb +210 -0
  7. data/lib/clive/base.rb +189 -0
  8. data/lib/clive/command.rb +342 -444
  9. data/lib/clive/error.rb +66 -0
  10. data/lib/clive/formatter.rb +57 -141
  11. data/lib/clive/formatter/colour.rb +37 -0
  12. data/lib/clive/formatter/plain.rb +172 -0
  13. data/lib/clive/option.rb +185 -75
  14. data/lib/clive/option/runner.rb +163 -0
  15. data/lib/clive/output.rb +141 -16
  16. data/lib/clive/parser.rb +180 -87
  17. data/lib/clive/struct_hash.rb +109 -0
  18. data/lib/clive/type.rb +117 -0
  19. data/lib/clive/type/definitions.rb +170 -0
  20. data/lib/clive/type/lookup.rb +23 -0
  21. data/lib/clive/version.rb +3 -3
  22. data/spec/clive/a_cli_spec.rb +245 -0
  23. data/spec/clive/argument_spec.rb +148 -0
  24. data/spec/clive/arguments/parser_spec.rb +35 -0
  25. data/spec/clive/arguments_spec.rb +191 -0
  26. data/spec/clive/command_spec.rb +276 -209
  27. data/spec/clive/formatter/colour_spec.rb +129 -0
  28. data/spec/clive/formatter/plain_spec.rb +129 -0
  29. data/spec/clive/option/runner_spec.rb +92 -0
  30. data/spec/clive/option_spec.rb +149 -23
  31. data/spec/clive/output_spec.rb +86 -2
  32. data/spec/clive/parser_spec.rb +201 -81
  33. data/spec/clive/struct_hash_spec.rb +82 -0
  34. data/spec/clive/type/definitions_spec.rb +312 -0
  35. data/spec/clive/type_spec.rb +107 -0
  36. data/spec/clive_spec.rb +60 -0
  37. data/spec/extras/expectations.rb +86 -0
  38. data/spec/extras/focus.rb +22 -0
  39. data/spec/helper.rb +35 -0
  40. metadata +56 -36
  41. data/lib/clive/bool.rb +0 -67
  42. data/lib/clive/exceptions.rb +0 -54
  43. data/lib/clive/flag.rb +0 -199
  44. data/lib/clive/switch.rb +0 -31
  45. data/lib/clive/tokens.rb +0 -141
  46. data/spec/clive/bool_spec.rb +0 -54
  47. data/spec/clive/flag_spec.rb +0 -117
  48. data/spec/clive/formatter_spec.rb +0 -108
  49. data/spec/clive/switch_spec.rb +0 -14
  50. data/spec/clive/tokens_spec.rb +0 -38
  51. data/spec/shared_specs.rb +0 -16
  52. data/spec/spec_helper.rb +0 -12
data/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2010 Joshua Hawxwell
1
+ Copyright (c) 2010-12 Joshua Hawxwell
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
data/README.md CHANGED
@@ -1,280 +1,381 @@
1
1
  # clive
2
2
 
3
- Clive is a DSL for creating a command line interface. It is for people who, like me,
4
- love [OptionParser's](http://ruby-doc.org/stdlib/libdoc/optparse/rdoc/classes/OptionParser.html) syntax and love [GLI's](http://github.com/davetron5000/gli) commands.
3
+ Clive lets you easily create command line interfaces, from simply checking for
4
+ the presence of a few flags to multiple command behemoths.
5
5
 
6
6
  ## Install
7
7
 
8
8
  Install with:
9
-
10
- (sudo) gem install clive
11
-
12
-
13
- ## How To
14
-
15
- Simply include `Clive::Parser` to start using.
16
- A simple example:
17
-
18
- # test.rb
19
- require 'clive'
20
-
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
-
30
- end
31
- CLI.parse(ARGV)
32
- p CLI.config
33
9
 
34
- This creates a very simple interface which can have one switch, you can then use the
35
- long or short form to call the block.
10
+ ``` bash
11
+ $ gem install clive
12
+ ```
36
13
 
37
- test.rb -v
38
- #=> {:verbose => true}
39
- test.rb --verbose
40
- #=> {:verbose => true}
41
-
42
14
 
43
- ### Switches
15
+ ## Usage
44
16
 
45
- The most basic options. When they are called by either name the block is run. To create
46
- a switch use `#switch`.
17
+ > __NOTE__: Throughout I will be using the new 1.9 `{a: b}` hash syntax,
18
+ > obviously the old `{:a => b}` syntax still works and can be used if you want
19
+ > or where 1.8 compatibility is needed.
47
20
 
48
- switch :s do
49
- # code
50
- end
51
- # Called with '-s'
52
-
53
- switch :long do
54
- # code
55
- end
56
- # Called with '--long'
57
-
58
- switch :b, :both do
59
- # code
60
- end
61
- # Called with '-b' or '--both'
21
+ Clive is generally used by creating a class to hold your command line interface
22
+ as shown in the example below.
23
+
24
+ ``` ruby
25
+ # my_app.rb
26
+ require 'clive'
62
27
 
28
+ module MyApp
29
+ VERSION = "0.1.4"
63
30
 
64
- ### Booleans
31
+ # some code
65
32
 
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.
33
+ class CLI < Clive
34
+ config name: 'myapp'
69
35
 
70
- bool :f, :force do |truth|
71
- p truth
36
+ opt :v, :version, 'Display the current version' do
37
+ puts MyApp::Version
38
+ exit 0
72
39
  end
73
- # '-f' returns true
74
- # '--force' returns true
75
- # '--no-force' returns false
40
+ end
41
+ end
76
42
 
77
- You must provide a long name, a short name is optional.
43
+ result = MyApp::CLI.run
44
+ ```
78
45
 
46
+ Then run with `my_app.rb --version` to display the version for MyApp. By default
47
+ `#run` will use `ARGV` as the input, but you can pass something else if
48
+ necessary.
79
49
 
80
- ### Flags
50
+ `.run` returns an instance of `Clive::StructHash` by default, this is a hybrid
51
+ hash and struct allowing you to access keys by calling them or using `#[]`. It
52
+ also stores any extra arguments that may have been passed which can be accessed
53
+ with `#args` or `#[:args]`.
81
54
 
82
- Flags are like switches but take one or more arguments, these are then passed to the
83
- block.
55
+ ``` ruby
56
+ class CLI
57
+ opt :n, :name, args: '<first> <last>'
58
+ opt :age, arg: '<age>', as: Integer
59
+ end
84
60
 
85
- # Creates a flag with a mandatory argument
86
- flag :with, :args => "ARG" do |arg|
87
- puts arg
88
- end
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
98
- end
61
+ result = CLI.run %w(--name John Doe --age 23 "I like coding!")
99
62
 
100
- You can also provide a list of options to select from.
101
-
102
- flag :choose, :args => %w(small med large) do |choice|
103
- puts choice
104
- end
105
-
106
- flag :number, :args => 1..5 do |num|
107
- puts num
108
- end
109
-
63
+ bio = result.args #=> "I like coding!"
64
+ name = result.name #=> ['John', 'Doe']
65
+ age = result.age #=> 23
66
+ ```
110
67
 
111
- ### Commands
68
+ This simple example shows how Clive can handle multiple arguments, casting to
69
+ types (Integer in this case) and how extra arguments are stored in `#args`.
112
70
 
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
71
 
117
- command :init, :create do
118
- bool :force do |truth|
119
- puts "Force"
120
- end
121
- end
122
- # 'init --force'
123
-
72
+ ## Options
124
73
 
125
- ### Arguments
74
+ Options are defined using `#opt` and/or `#option` they can have short (`-a`) or
75
+ long names (`--abc`) and can also have arguments. The description can be given
76
+ as an argument to `#opt` or can be defined before it using `#desc` (or
77
+ `#description`).
126
78
 
127
- Anything that is not captured as a command, option or argument of a flag, is returned by
128
- \#parse in an array.
79
+ ``` ruby
80
+ opt :v, :version, 'Display the current version' do
81
+ # ...
82
+ end
129
83
 
130
- class Args
131
- include Clive::Parser
132
-
133
- switch(:hey) { puts "Hey" }
134
- end
135
- args = Args.parse(ARGV)
136
- p args
137
-
138
- # `file --hey argument "A string"`
139
- #=> ['argument', 'A string']
84
+ # is equivalent to
140
85
 
86
+ desc 'Display the current version'
87
+ opt :v, :version do
88
+ # ...
89
+ end
90
+ ```
141
91
 
142
- ### Variables
92
+ Longer option names, containing `_`s are called by replacing the `_` with a `-` so
143
93
 
144
- Usually you'll want to set up some kind of variable, such as a hash to store your
145
- configuration in, or an array of items to do something with. This would be quite annoying
146
- due to the fact it's a class, so I addded some handy methods.
94
+ ``` ruby
95
+ opt :longer_name_than_expected
96
+ ```
147
97
 
148
- class CLI
149
- option_var :ok, false
150
- end
151
- CLI.ok #=> false
152
- CLI.ok = true
153
- CLI.ok #=> true
154
-
155
- class CLI
156
- option_hash :config
157
- #=> is same as option_var :config, {}
158
-
159
- flag :set, :args => "KEY VALUE" do |key, value|
160
- config[key.to_sym] = value
161
- end
162
-
163
- option_list :items
164
- # or option_array :items
165
- #=> are the same as option_var :items, []
166
- # option_var :a_list, []
167
-
168
- flag :add, :args => "ITEM" do |item|
169
- items << item
170
- end
171
- end
172
- CLI.parse %w(--set works true --add apple --add orange)
173
- CLI.config #=> {:works => true}
174
- CLI.items #=> ['apple', 'orange']
98
+ would be called with `--longer-name-than-expected`.
175
99
 
176
- ### Option Missing Handling
100
+ ### Boolean Options
177
101
 
178
- You are able to intercept errors when an option does not exist in a similar way to
179
- `method_missing`.
102
+ Boolean options are options which can be called with a `no-` prefix, which then
103
+ passes `false` to the block/state. For example,
180
104
 
181
- class Missing
182
- option_missing do |name|
183
- puts "#{name} was used but not defined"
184
- end
185
- end
186
- Missing.parse %w(--hey)
187
- #=> hey was used but not defined
105
+ ``` ruby
106
+ bool :a, :auto
107
+ ```
188
108
 
109
+ Can be called with `-a` or `--auto` which would set `:auto` to `true`, or
110
+ `--no-auto` which sets `:auto` to `false`. If a block is given you can retrieve
111
+ the truth by adding block parameters or using the `truth` variable which is
112
+ automatically set.
189
113
 
190
- ### Help Formatting
114
+ ``` ruby
115
+ bool :a, :auto do |t|
116
+ puts t
117
+ end
191
118
 
192
- There are two built in help formats the default, with colour, and a pure white one. To
193
- change the formatter call `#help_formatter` with :default, or :white.
119
+ # OR
194
120
 
195
- Optionally you can create your own formatter, like so:
121
+ bool :a, :auto do
122
+ puts truth
123
+ end
124
+ ```
196
125
 
197
- class CLI
198
- help_formatter do |h|
199
- h.switch "{prepend}{names.join(', ')} {spaces}# {desc}"
200
- h.bool "{prepend}{names.join(', ')} {spaces}# {desc}"
201
- h.flag "{prepend}{names.join(', ')} {args.join(' ')} {spaces}# {desc}" <<
202
- "{options.join('(', ', ', ')')}"
203
- h.command "{prepend}{names.join(', ')} {spaces}# {desc}"
204
- end
205
- end
126
+ Boolean options __must__ have a long name.
127
+
128
+
129
+ ## Commands
130
+
131
+ Commands are defined using `#command`. They can be used to group related Options
132
+ together acting like a namespace, but Commands are fully featured Options so can
133
+ also take arguments. Commands can be created with multiple names.
134
+
135
+ ``` ruby
136
+ desc 'Create a new project'
137
+ command :new, :create, arg: '<dir>', as: Pathname do
138
+
139
+ # Set the default type to use
140
+ set :type, :basic
141
+
142
+ desc 'Select type of template to use'
143
+ opt :type, arg: '<choice>', in: %w(basic complex custom), as: Symbol
144
+
145
+ bool :force, 'Force overwrite'
146
+
147
+ action do
148
+ puts "Creating #{get :type} in #{dir}"
149
+ # do writing
150
+ end
151
+ end
152
+ ```
153
+
154
+ The above example also shows using the `#set` and `#get` methods, these allow
155
+ you to set and get values from the state. Also note how the logic for executing
156
+ the `new` command is given to `#action`, this is because the block passed to
157
+ `#command` is used for option definition.
158
+
159
+
160
+ ## Arguments
161
+
162
+ As previously talked about Options and Commands can take arguments by passing a
163
+ hash with the key `:arg` or `:args`.
164
+
165
+ ``` ruby
166
+ opt :size, args: '<height> <width>'
167
+ ```
168
+
169
+ The option `--size` takes two arguments. These would be saved to state as an array,
170
+ for instance running with `--size 10 40` would set `:size` to `['10', '40']`.
171
+
172
+ Arguments can be made optional by enclosing one or more arguments with `[` and `]`:
173
+
174
+ ``` ruby
175
+ # both required
176
+ opt :size, args: '<h> <w>'
177
+ # --size 10 #=> Error
178
+
179
+ # first required
180
+ opt :size, args: '<h> [<w>]'
181
+ # --size 10 #=> [10, nil]
182
+
183
+ # second required
184
+ opt :size, args: '[<h>] <w>'
185
+ # --size 10 #=> [nil, 10]
186
+
187
+ # neither required
188
+ opt :size, args: '[<h> <w>]'
189
+ # --size 10 #=> [10, nil]
190
+ ```
191
+
192
+ There are also various options that can be passed to constrain or change the
193
+ arguments. If one of the below is passed to an option with `:arg` or `:args`
194
+ a generic argument called `<arg>` will be added.
195
+
196
+ ### Types (`:types`, `:type`, `:kind` or `:as`)
197
+
198
+ An argument will be checked if it matches how the type should look, then converts
199
+ it to that type. For more information see `lib/clive/type/definitions.rb`.
200
+
201
+ ``` ruby
202
+ opt :list, as: Array
203
+ ```
204
+
205
+ This accepts a comma delimited list of items, `--list a,b,c` and sets `:list` to
206
+ `['a', 'b', 'c']`.
207
+
208
+ ### Matches (`:matches` or `:match`)
209
+
210
+ Allows you to say that an argument must match a regular expression (or any object
211
+ which responds to `#match`).
212
+
213
+ ``` ruby
214
+ opt :word, match: /^\w+$/
215
+ ```
206
216
 
207
- Which would look like:
217
+ This accepts `--word hello` but not `--word 123`.
208
218
 
209
- Usage: my_app [command] [options]
210
-
211
- Commands:
212
- test # A command
213
-
214
- Options:
215
- -h, --help # Display help
216
- --[no-]force # Force build
219
+ ### Withins (`:withins`, `:within` or `:in`)
217
220
 
218
- You have access to the variables:
221
+ Allows you to say that an argument must be within a passed Array, Set or Range
222
+ (any object which responds to `#include?`).
219
223
 
220
- * prepend - a string of spaces as specified when `#help_formatter` is called
221
- * names - an array of names for the option
222
- * spaces - a string of spaces to align the descriptions properly
223
- * desc - a string of the description for the option
224
+ ``` ruby
225
+ opt :num, in: "1".."100"
226
+ ```
224
227
 
225
- And for flags you have access to:
228
+ This accepts `--num 50` but not `--num 900`. The example above had to use a range
229
+ of Strings because that is what is passed, you can use this with `:type` to use
230
+ Integers.
226
231
 
227
- * args - an array of arguments for the flag
228
- * options - an array of options to choose from
232
+ ``` ruby
233
+ opt :num, as: Integer, in: 1..100
234
+ ```
235
+
236
+ Would work in the same way as the one above but return an Integer.
237
+
238
+ ### Defaults (`:defaults` or `:default`)
239
+
240
+ Allows you to give a default value that should be used if an argument is not
241
+ given.
242
+
243
+ ``` ruby
244
+ opt :type, default: 'house'
245
+ ```
246
+
247
+ So `--type` would set `:type` to `'house'`, but `--type shed` would set `:type`
248
+ to `'shed'`. The default value is only set if the option is used. To set a value
249
+ regardless of whether the option is used use `#set` in the class or commands
250
+ body.
251
+
252
+ ``` ruby
253
+ set :type, 'house'
254
+ opt :type
255
+ ```
256
+
257
+ Would always set `:type` to `'house'` even when `--type` is not used.
258
+
259
+ ### Constraints (`:constraint` or `:constraint`)
260
+
261
+ Allows you to constrain the argument using a Proc, this is to cover the very
262
+ few events where the above options do not satisfy the requirements.
263
+
264
+ ``` ruby
265
+ opt :long_word, constraint: -> i { i.size >= 7 }
266
+ ```
267
+
268
+ Accepts `--long-word eventually` but not `--long-word event`. You can also pass
269
+ a symbol which will have `#to_proc` called on it.
270
+
271
+ ``` ruby
272
+ opt :odd, as: Integer, constraint: :odd?
273
+ ```
274
+
275
+ This only accepts odd Integers.
276
+
277
+
278
+ ## Runner
279
+
280
+ All blocks passed to options or given to a command's action are run in the Runner
281
+ class. This provides a few shortcuts to make life easier. Here is a quick run down
282
+ with examples.
283
+
284
+ ### Argument Referencing
285
+
286
+ You can reference an options or commands arguments directly by name without having
287
+ to use block parameters.
288
+
289
+ ``` ruby
290
+ opt :size, args: '<height> <width>', as: [Float, Float] do # no params!
291
+ puts "Area = #{height} * #{width} = #{height * width}"
292
+ end
293
+ ```
294
+
295
+ As shown earlier the truthiness of a boolean option is set to the value `truth`.
296
+
297
+ ### Working with the State
298
+
299
+ Four fundamental methods are defined for working with the state, `#get`, `#set`,
300
+ `#update` and `#has?`.
301
+
302
+ `#get` allows you to get values previously set.
303
+
304
+ ``` ruby
305
+ opt :get_some_key do
306
+ puts get(:some_key) #=> value set for :some_key
307
+ end
308
+ ```
309
+
310
+ `#set` allows you to set values in the state.
311
+
312
+ ``` ruby
313
+ opt :set_some_key, arg: '<value>' do
314
+ set :some_key, value
315
+ end
316
+ ```
317
+
318
+ `#update` allows you to modify a value in the state.
319
+
320
+ ``` ruby
321
+ set :list, []
322
+ opt :add, arg: '<item>' do
323
+ update :list, :<<, item
324
+
325
+ # or using a block
326
+ update(:list) {|l| l << item }
327
+ end
328
+ ```
329
+
330
+ `#has?` tells you whether a value has been set for the key.
331
+
332
+ ``` ruby
333
+ opt :has_some_key do
334
+ puts has?(:some_key)
335
+ end
336
+ ```
337
+
338
+
339
+ ## Help Formatters
340
+
341
+ Clive comes with two help formatters, one with colour and the other without. To use
342
+ the plain formatter (colour is default), use
343
+
344
+ ``` ruby
345
+ class CLI < Clive
346
+ config formatter: Clive::Formatter::Plain.new
347
+
348
+ # ...
349
+ end
350
+
351
+ CLI.run
352
+ ```
353
+
354
+ To create your own formatter take a look at `lib/clive/formatter.rb`.
229
355
 
230
- Inside the { and } you can put any ruby, so feel free to use joins on the array.
231
356
 
232
-
233
357
  ## Clive::Output
234
358
 
235
- This is a new bit that allows you to colourise output from the command line, by patching a
236
- few methods onto String.
237
-
238
- require 'clive/output'
239
- # or require 'clive'
240
-
241
- puts "I'm blue".blue # will print blue text
242
- puts "I'm red".red # will print red text
243
- puts "I'm green and bold".green.bold # will print green and bold text
244
- puts "Crazy".blue.l_yellow_bg.underline
245
- # etc
246
-
247
- Methods available are:
248
- - bold
249
- - underline
250
- - blink
251
- - reverse
252
-
253
- - white
254
- - green
255
- - red
256
- - magenta
257
- - yellow
258
- - blue
259
- - cyan
260
- - black (light version called grey not l_black)
261
-
262
- - + light versions of colours using l_colour)
263
- - + background setters using colour_bg
264
- - + light background using l_colour_bg
265
-
266
-
267
-
268
- ## Note on Patches/Pull Requests
269
-
270
- * Fork the project.
271
- * Make your feature addition or bug fix.
272
- * Add tests for it. This is important so I don't break it in a
273
- future version unintentionally.
274
- * Commit, do not mess with rakefile, version, or history.
275
- (if you want to have your own version, that is fine but bump version in a commit by itself so I can ignore when I pull)
276
- * Send me a pull request. Bonus points for topic branches.
359
+ `clive/output` contains various monkey patches on String that allow you to easily
360
+ colourise output.
361
+
362
+ ``` ruby
363
+ puts "I'm blue".blue # will print blue text
364
+ puts "I'm green and bold".green.bold # will print green and bold text
365
+ puts "Crazy".blue.l_yellow_bg.underline
366
+ # etc
367
+ ```
368
+
369
+ Colours available: white, green, red, magenta, yellow, blue, cyan, black.
370
+ Effects available: bold, underline, blink, reverse.
371
+
372
+ Light versions can be used by prepending the name with `l_`, ie. `l_red`, the light
373
+ version of black is called grey.
374
+
375
+ All colours can be used as backgrounds by appending `_bg`, ie. `red_bg`, light
376
+ backgrounds are as expected, `l_red_bg`.
377
+
277
378
 
278
379
  ## Copyright
279
380
 
280
- Copyright (c) 2010 Joshua Hawxwell. See LICENSE for details.
381
+ Copyright (c) 2010-12 Joshua Hawxwell. See LICENSE for details.