docopt 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. data/README.md +172 -0
  2. data/docopt.rb +116 -0
  3. metadata +47 -0
@@ -0,0 +1,172 @@
1
+ `docopt` – command line option parser, that will make you smile
2
+ ===============================================================================
3
+
4
+ Help porting [docopt](http://docopt.org/) to Ruby!
5
+
6
+ Isn't it awesome how `optparse` and other option parsers generate help and
7
+ usage-messages based on your code?!
8
+
9
+ Hell no! You know what's awesome? It's when the option parser *is* generated
10
+ based on the help and usage-message that you write in a docstring! This way
11
+ you don't need to write this stupid repeatable parser-code, and instead can
12
+ write a beautiful usage-message (the way you want it!), which adds readability
13
+ to your code.
14
+
15
+ Now you can write an awesome, readable, clean, DRY code like *that*:
16
+
17
+ ```ruby
18
+ doc = "Usage: example.rb [options] <arguments>...
19
+
20
+ Options:
21
+ -h --help show this help message and exit
22
+ --version show version and exit
23
+ -v --verbose print status messages
24
+ -q --quiet report only file names
25
+ -r --repeat show all occurrences of the same error
26
+ --exclude=patterns exclude files or directories which match these comma
27
+ separated patterns [default: .svn,CVS,.bzr,.hg,.git]
28
+ --filename=patterns when parsing directories, only check filenames matching
29
+ these comma separated patterns [default: *.rb]
30
+ --select=errors select errors and warnings (e.g. E,W6)
31
+ --ignore=errors skip errors and warnings (e.g. E4,W)
32
+ --show-source show source code for each error
33
+ --statistics count errors and warnings
34
+ --count print total number of errors and warnings to standard
35
+ error and set exit code to 1 if total is not null
36
+ --benchmark measure processing speed
37
+ --testsuite=dir run regression tests from dir
38
+ --doctest run doctest on myself"
39
+
40
+ require 'docopt'
41
+
42
+
43
+ if __FILE__ == $0
44
+ options = docopt(doc, '1.0.0') # parse options based on doc above
45
+ puts options.inspect
46
+ puts ARGV.inspect
47
+ end
48
+ ```
49
+
50
+ Hell yeah! The option parser is generated based on `doc` string above, that you
51
+ pass to the `docopt` function.
52
+
53
+ API `require 'docopt'`
54
+ ===============================================================================
55
+
56
+ ###`options = docopt(doc, version=nil, help=true)`
57
+
58
+ `docopt` takes 1 required and 2 optional arguments:
59
+
60
+ - `doc` should be a string that
61
+ describes **options** in a human-readable format, that will be parsed to create
62
+ the option parser. The simple rules of how to write such a docstring
63
+ (in order to generate option parser from it successfully) are given in the next
64
+ section. Here is a quick example of such a string:
65
+
66
+ Usage: your_program.rb [options]
67
+
68
+ -h --help Show this.
69
+ -v --verbose Print more text.
70
+ --quiet Print less text.
71
+ -o FILE Specify output file [default: ./test.txt].
72
+
73
+ - `help`, by default `true`, specifies whether the parser should automatically
74
+ print the usage-message (supplied as `doc`) in case `-h` or `--help` options
75
+ are encountered. After showing the usage-message, the program will terminate.
76
+ If you want to handle `-h` or `--help` options manually (as all other options),
77
+ set `help=false`.
78
+
79
+ - `version`, by default `nil`, is an optional argument that specifies the
80
+ version of your program. If supplied, then, if the parser encounters
81
+ `--version` option, it will print the supplied version and terminate.
82
+ `version` could be any printable object, but most likely a string,
83
+ e.g. `'2.1.0rc1'`.
84
+
85
+ Note, when `docopt` is set to automatically handle `-h`, `--help` and
86
+ `--version` options, you still need to mention them in the options description
87
+ (`doc`) for your users to know about them.
88
+
89
+ The **return** value is a hash with option values
90
+ (giving long options precedence), e.g:
91
+
92
+ {"--benchmark"=>true,
93
+ "--count"=>true,
94
+ "--doctest"=>false,
95
+ "--exclude"=>".svn,CVS,.bzr,.hg,.git",
96
+ "--filename"=>"*.rb",
97
+ "--help"=>false,
98
+ "--ignore"=>false,
99
+ "--quiet"=>false,
100
+ "--repeat"=>false,
101
+ "--select"=>"*.rb",
102
+ "--show-source"=>true,
103
+ "--statistics"=>true,
104
+ "--testsuite"=>false,
105
+ "--verbose"=>true,
106
+ "--version"=>false}
107
+
108
+ You can access positional arguments in `ARGV`.
109
+
110
+ `doc` string format for your usage-message
111
+ ===============================================================================
112
+
113
+ The main idea behind `docopt` is that a good usage-message (that describes
114
+ options and defaults unambiguously) is enough to generate an option parser.
115
+
116
+ Here are the simple rules (that you probably already follow) for your
117
+ usage-message to be parsable:
118
+
119
+ - Every line that starts with `-` or `--` (not counting spaces) is treated
120
+ as an option description, e.g.:
121
+
122
+ Options:
123
+ --verbose # GOOD
124
+ -o FILE # GOOD
125
+ Other: --bad # BAD, line does not start with dash "-"
126
+
127
+ - To specify that an option has an argument, put a word describing that
128
+ argument after space (or equals `=` sign) as shown below.
129
+ You can use comma if you want to separate options. In the example below both
130
+ lines are valid, however you are recommended to stick to a single style.
131
+
132
+ -o FILE --output=FILE # without comma, with "=" sign
133
+ -i <file>, --input <file> # with comma, wihtout "=" sing
134
+
135
+ - Use two spaces to separate options with their informal description.
136
+
137
+ --verbose More text. # BAD, will be treated as if verbose option had
138
+ # an argument "More", so use 2 spaces instead
139
+ -q Quit. # GOOD
140
+ -o FILE Output file. # GOOD
141
+ --stdout Use stdout. # GOOD, 2 spaces
142
+
143
+ - If you want to set a default value for an option with an argument, put it
144
+ into the option description, in form `[default: <my-default-value>]`.
145
+
146
+ -i INSTANCE Instance of something [default: 1]
147
+ --coefficient=K The K coefficient [default: 2.95]
148
+ --output=FILE Output file [default: test.txt]
149
+ --directory=DIR Some directory [default: ./]
150
+
151
+ Something missing? Help porting [docopt](http://docopt.org/) to Ruby!
152
+ ===============================================================================
153
+
154
+ Compatibility notice:
155
+ ===============================================================================
156
+
157
+ In order to maintain your program's compatibility with future versions
158
+ of `docopt.rb` (as porting more features continues) you are recommended to
159
+ keep the following in the begining of `doc` argument:
160
+
161
+ Usage: my_program.rb [options] <arguments>...
162
+
163
+ or
164
+
165
+ Usage: my_program.rb [options] <argument>
166
+
167
+ or
168
+
169
+ Usage: my_program.rb [options]
170
+
171
+ (followed by an empty line), where you are free to change `my_program.rb`
172
+ and `argument(s)` name inside of `<...>`.
@@ -0,0 +1,116 @@
1
+ require 'getoptlong'
2
+
3
+
4
+ class Option
5
+
6
+ attr_reader :short, :long, :argcount, :value
7
+
8
+ def initialize(short=nil, long=nil, argcount=0, value=false)
9
+ @short, @long, @argcount, @value = short, long, argcount, value
10
+ end
11
+
12
+ def getopt
13
+ [@long, @short, @argcount].compact
14
+ end
15
+
16
+ def inspect
17
+ "Option.new(#{@short}, #{@long}, #{@argcount}, #{@value})"
18
+ end
19
+
20
+ def == other
21
+ self.inspect == other.inspect
22
+ end
23
+
24
+ end
25
+
26
+
27
+ def option parse
28
+ options, _, description = parse.strip.partition(' ')
29
+ options = options.sub(',', ' ').sub('=', ' ')
30
+ short, long, argcount, value = nil, nil, 0, false
31
+ for s in options.split
32
+ if s.start_with? '--'
33
+ long = s
34
+ elsif s.start_with? '-'
35
+ short = s
36
+ else
37
+ argcount = 1
38
+ end
39
+ end
40
+ if argcount == 1
41
+ matched = description.scan(/\[default: (.*)\]/)[0]
42
+ value = matched ? matched[0] : false
43
+ end
44
+ Option.new(short, long, argcount, value)
45
+ end
46
+
47
+
48
+ class MyHash < Hash
49
+ def inspect
50
+ "{#{self.to_a.sort.map {|i| "%p=>%p" % i}.join(",\n ")}}"
51
+ end
52
+ end
53
+
54
+
55
+ def docopt(doc, version=nil, help=true)
56
+ ret = MyHash.new
57
+ docopts = []
58
+ doc.split(/^ *-|\n *-/)[1..-1].each do |s|
59
+ docopt = option('-' + s)
60
+ docopts += [docopt]
61
+ ret[(docopt.long or docopt.short)] = docopt.value
62
+ end
63
+ begin
64
+ GetoptLong.new(*docopts.map {|e| e.getopt}).each do |opt, arg|
65
+ if help and (opt == '--help' or opt == '-h')
66
+ puts doc.strip
67
+ exit
68
+ elsif version and opt == '--version'
69
+ puts version
70
+ exit
71
+ elsif (docopts.select {|d|(d.long or d.short)==opt})[0].argcount==0
72
+ ret[opt] = true
73
+ else
74
+ ret[opt] = arg
75
+ end
76
+ end
77
+ rescue
78
+ exit 1
79
+ end
80
+ ret
81
+ end
82
+
83
+
84
+ if __FILE__ == $0
85
+
86
+ def assert cond
87
+ print cond ? '.' : 'F'
88
+ end
89
+
90
+ assert option('-h') == Option.new('-h', nil)
91
+ assert option('--help') == Option.new(nil, '--help')
92
+ assert option('-h --help') == Option.new('-h', '--help')
93
+ assert option('-h, --help') == Option.new('-h', '--help')
94
+
95
+ assert option('-h TOPIC') == Option.new('-h', nil, 1)
96
+ assert option('--help TOPIC') == Option.new(nil, '--help', 1)
97
+ assert option('-h TOPIC --help TOPIC') == Option.new('-h', '--help', 1)
98
+ assert option('-h TOPIC, --help TOPIC') == Option.new('-h', '--help', 1)
99
+ assert option('-h TOPIC, --help=TOPIC') == Option.new('-h', '--help', 1)
100
+
101
+ assert option('-h Description...') == Option.new('-h', nil)
102
+ assert option('-h --help Description...') == Option.new('-h', '--help')
103
+ assert option('-h TOPIC Description...') == Option.new('-h', nil, 1)
104
+
105
+ assert option(' -h') == Option.new('-h', nil)
106
+
107
+ assert option('-h TOPIC Descripton... [default: 2]') ==
108
+ Option.new('-h', nil, 1, '2')
109
+ assert option('-h TOPIC Descripton... [default: topic-1]') ==
110
+ Option.new('-h', nil, 1, 'topic-1')
111
+ assert option('--help=TOPIC ... [default: 3.14]') ==
112
+ Option.new(nil, '--help', 1, '3.14')
113
+ assert option('-h, --help=DIR ... [default: ./]') ==
114
+ Option.new('-h', '--help', 1, "./")
115
+
116
+ end
metadata ADDED
@@ -0,0 +1,47 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: docopt
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Vladimir Keleshev
9
+ - Alex Speller
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+ date: 2012-06-03 00:00:00.000000000 Z
14
+ dependencies: []
15
+ description: A command line option parser, that will make you smile.
16
+ email:
17
+ executables: []
18
+ extensions: []
19
+ extra_rdoc_files: []
20
+ files:
21
+ - README.md
22
+ - docopt.rb
23
+ homepage: http://github.com/alexspeller/docopt.rb
24
+ licenses: []
25
+ post_install_message:
26
+ rdoc_options: []
27
+ require_paths:
28
+ - lib
29
+ required_ruby_version: !ruby/object:Gem::Requirement
30
+ none: false
31
+ requirements:
32
+ - - ! '>='
33
+ - !ruby/object:Gem::Version
34
+ version: '0'
35
+ required_rubygems_version: !ruby/object:Gem::Requirement
36
+ none: false
37
+ requirements:
38
+ - - ! '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ requirements: []
42
+ rubyforge_project:
43
+ rubygems_version: 1.8.23
44
+ signing_key:
45
+ specification_version: 3
46
+ summary: A command line option parser, that will make you smile.
47
+ test_files: []