summaryrefslogtreecommitdiff
path: root/README.md
blob: f9acd7d26dde2de8423abff1254329063a6db043 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
Slop
====

Slop is a simple option parser with an easy to remember syntax and friendly API.

Installation
------------

### Rubygems

    gem install slop

### GitHub

    git clone git://github.com/injekt/slop.git
    gem build slop.gemspec
    gem install slop-<version>.gem

Usage
-----
    # parse assumes ARGV, otherwise you can pass it your own Array
    opts = Slop.parse do
      on :v, :verbose, 'Enable verbose mode' 	   # boolean value
      on :n, :name, 'Your name', true              # compulsory argument
      on :s, :sex, 'Your sex', :optional => false  # the same thing
      on :a, :age, 'Your age', :optional => true   # optional argument
    end

    # if ARGV is `-v --name 'lee jarvis' -s male`
    opts.verbose? #=> true
    opts.name?    #=> true
    opts[:name]   #=> 'lee jarvis'
    opts.age?     #=> false
    opts[:age]    #=> nil

You can also return your options as a Hash

    opts.to_hash #=> {'name' => 'Lee Jarvis', 'verbose' => true, 'age' => nil, 'sex' => 'male'}

    # Symbols
    opts.to_hash(true) #=> {:name => 'Lee Jarvis', :verbose => true, :age => nil, :sex => 'male'}

If you don't like the method `on` (because it sounds like the option **expects**
a block), you can use the `opt` or `option` alternatives.

    on :v, :verbose
    opt :v, :verbose
    option :v, :verbose

If you don't like that Slop evaluates your block, or you want slop access
inside of your block without referring to `self`, you can pass a block argument to
`parse`.

    Slop.parse do |opts|
      opts.on :v, :verbose
      opts.on :n, :name, 'Your name', true
    end

If you want some pretty output for the user to see your options, you can just
send the Slop object to `puts` or use the `help` method.

    puts opts
    puts opts.help

Will output something like

    -v, --verbose      Enable verbose mode
    -n, --name         Your name
    -a, --age          Your age

You can also add a banner using the `banner` method

    opts = Slop.parse
    opts.banner = "Usage: foo.rb [options]"

or

    opts = Slop.parse do
      banner "Usage: foo.rb [options]"
    end

or

    opts = Slop.new "Usage: foo.rb [options]"

Helpful Help
------------

Long form:

    Slop.parse do
      ...
      on :h, :help, 'Print this help message', :tail => true do
        puts help
        exit
      end
    end

Shortcut:

    Slop.parse :help => true do
      ...
    end

Parsing
-------

Slop's pretty good at parsing, let's take a look at what it'll extract for you

    Slop.parse do
      on 's', 'server', true
      on 'p', 'port', true, :as => :integer
      on 'username', true, :matches => /[^a-zA-Z]+$/
      on 'password', true
    end

Now throw some options at it:

    -s ftp://foobar.com -p1234 --username=FooBar --password 'hello there'

Here's what we'll get back

    {
    	:server=>"ftp://foobar.com",
    	:port=>1234,
    	:username=>"FooBar",
    	:password=>"hello there"
    }

Callbacks
---------

If you'd like to trigger an event when an option is used, you can pass a
block to your option. Here's how:

    Slop.parse do
      on :V, :version, 'Print the version' do
        puts 'Version 1.0.0'
        exit
      end
    end

Now when using the `--version` option on the command line, the trigger will
be called and its contents executed.

Yielding Non Options
--------------------

If you pass a block to `Slop#parse`, Slop will yield non-options as
they're found, just like
[OptionParser](http://rubydoc.info/stdlib/optparse/1.9.2/OptionParser:order)
does it.

    opts = Slop.new do
      on :n, :name, :optional => false
    end

    opts.parse do |arg|
      puts arg
    end

    # if ARGV is `foo --name Lee bar`
    foo
    bar

Negative Options
----------------

Slop also allows you to prefix `--no-` to an option which will force the option
to return a false value.

    opts = Slop.parse do
    	on :v, :verbose, :default => true
    end

    # with no command line options
    opts[:verbose] #=> true

    # with `--no-verbose`
    opts[:verbose] #=> false
    opts.verbose?  #=> false

Short Switches
--------------

Want to enable multiple switches at once like rsync does? By default Slop will
parse `-abcd` as the option `a` with the argument `bcd`, this can be disabled
by passing the `:multiple_switches` option to a new Slop object.

    opts = Slop.new(:strict, :multiple_switches) do
      on :a, 'First switch'
      on :b, 'Second switch'
      on :c, 'Third switch'
    end

    opts.parse

    # Using `-ac`
    opts[:a] #=> true
    opts[:b] #=> false
    opts[:c] #=> true

Lists
-----

You can of course also parse lists into options. Here's how:

    opts = Slop.parse do
      opt :people, true, :as => Array
    end

    # ARGV is `--people lee,john,bill`
    opts[:people] #=> ['lee', 'john', 'bill']

You can also change both the split delimiter and limit

    opts = Slop.parse do
      opt :people, true, :as => Array, :delimiter => ':', :limit => 2)
    end

    # ARGV is `--people lee:injekt:bob`
    opts[:people] #=> ["lee", "injekt:bob"]

Ranges
------

What would Slop be if it didn't know what ranges were?

    opts = Slop.parse do
      opt :r, :range, true, :as => Range
    end

    # ARGV is `--range 1..10` or 1-10, or 1,10 (yes Slop supports them all)
    opts[:range].to_a #=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

Ugh, Symbols
------------

Fine, don't use them

    Slop.parse do
      on :n, :name, 'Your name'
      on 'n', 'name', 'Your name'
      on '-n', '--name', 'Your name'
    end

All of these options will do the same thing

Ugh, Blocks
-----------

C'mon man, this is Ruby, GTFO if you don't like blocks.

    opts = Slop.new
    opts.on :v, :verbose
    opts.parse

Smart
-----

Slop is pretty smart when it comes to building your options, for example if you
want your option to have a flag attribute, but no `--option` attribute, you
can do this:

    on :n, "Your name"

and Slop will detect a description in place of an option, so you don't have to
do this:

    on :n, nil, "Your name", true

You can also try other variations:

    on :name, "Your name"
    on :n, :name
    on :name, true

Strict Mode
-----------

Passing `strict => true` to `Slop.parse` causes it to raise a `Slop::InvalidOptionError`
when an invalid option is found (`false` by default):

    Slop.new(:strict => true).parse(%w/--foo/)
    # => Slop::InvalidOptionError: Unknown option -- 'foo'

and it handles multiple invalid options with a sprinkling of pluralization:

    Slop.new(:strict => true).parse(%w/--foo --bar -z/)
    # => Slop::InvalidOptionError: Unknown options -- 'foo', 'bar', 'z'

Significantly, however, Slop will still parse the valid options:

    slop = Slop.new(:strict => true, :help => true) do
      banner "Usage:\n\t./awesome_sauce [options]\n\nOptions:"
      on :n, :name, 'Your name'
    end

    begin
      slop.parse(%w/--foo --bar -z/)
    rescue Slop::InvalidOptionError => e
      puts "\n#{e.message}\n\n"
      puts slop
      exit
    end

yields:

    Unknown options -- 'foo', 'bar', 'z'

    Usage:
    	./awesome_sauce [options]

    Options:
        -n, --name      Your name
        -h, --help      Print this help message

Commands
--------

Slop allows you to nest more instances of Slop inside of `commands`. These
instances will then be used to parse arguments if they're called upon.

Slop will use the first argument in the list of items passed to `parse` to
check if it is a `command`.

    Slop.parse ['foo', '--bar', 'baz']

Slop will look to see if the `foo` command exists, and if it does, it'll pass
the options `['--bar', 'baz']` to the instance of Slop that belongs to `foo`.
Here's how commands might look:

    opts = Slop.new do
      command :foo do
        on :b, :bar, 'something', true
      end

      command :clean do
        on :v, :verbose, do
          puts 'Enabled verbose mode for clean'
        end
      end

      # non-command specific options
      on :v, :version do
        puts 'version 1'
      end
    end

* Run with `run.rb -v`
* Output:  `version 1`

* Run with: `run.rb clean -v`
* Output:   `Enabled verbose mode for clean`

Woah woah, why you hating on OptionParser?
------------------------------------------

I'm not, honestly! I love OptionParser. I really do, it's a fantastic library.
So why did I build Slop? Well, I find myself using OptionParser to simply
gather a bunch of key/value options, usually you would do something like this:

    require 'optparse'

    things = {}

    opt = OptionParser.new do |opt|
      opt.on('-n', '--name NAME', 'Your name') do |name|
        things[:name] = name
      end

      opt.on('-a', '--age AGE', 'Your age') do |age|
    	things[:age] = age
      end

      # you get the point
    end

    opt.parse
    things #=> { :name => 'lee', :age => 105 }

Which is all great and stuff, but it can lead to some repetition, the same
thing in Slop:

    require 'slop'

    opts = Slop.parse do
      on :n, :name, 'Your name', true
      on :a, :age, 'Your age', true
    end

    opts.to_hash(true) #=> { :name => 'lee', :age => 105 }