clive 0.8.1 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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.