oyster 0.9.1 → 0.9.2
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +14 -3
- data/Manifest.txt +4 -4
- data/README.txt +26 -21
- data/Rakefile +1 -1
- data/lib/oyster.rb +6 -3
- data/lib/oyster/specification.rb +37 -18
- data/test/test_oyster.rb +8 -1
- metadata +13 -11
data/History.txt
CHANGED
@@ -1,6 +1,17 @@
|
|
1
|
-
===
|
1
|
+
=== 0.9.2 / 2009-06-19
|
2
2
|
|
3
|
-
*
|
3
|
+
* Use Curses to set the width of help output.
|
4
|
+
* Fix some formatting and layout bugs in help text.
|
4
5
|
|
5
|
-
|
6
|
+
|
7
|
+
=== 0.9.1 / 2009-01-30
|
8
|
+
|
9
|
+
* Ruby 1.9 compatibility fixes.
|
10
|
+
|
11
|
+
|
12
|
+
=== 0.9.0 / 2008-07-17
|
13
|
+
|
14
|
+
* Initial release. Includes option parsing for flags, strings, ints,
|
15
|
+
floats, globs, files, shortcuts and subcommands. Automatically
|
16
|
+
renders man-page-style help to stdout with the -h flag.
|
6
17
|
|
data/Manifest.txt
CHANGED
@@ -5,13 +5,13 @@ Rakefile
|
|
5
5
|
lib/oyster.rb
|
6
6
|
lib/oyster/specification.rb
|
7
7
|
lib/oyster/option.rb
|
8
|
+
lib/oyster/options/array.rb
|
9
|
+
lib/oyster/options/file.rb
|
8
10
|
lib/oyster/options/flag.rb
|
9
|
-
lib/oyster/options/string.rb
|
10
|
-
lib/oyster/options/integer.rb
|
11
11
|
lib/oyster/options/float.rb
|
12
|
-
lib/oyster/options/file.rb
|
13
|
-
lib/oyster/options/array.rb
|
14
12
|
lib/oyster/options/glob.rb
|
13
|
+
lib/oyster/options/integer.rb
|
15
14
|
lib/oyster/options/shortcut.rb
|
15
|
+
lib/oyster/options/string.rb
|
16
16
|
lib/oyster/options/subcommand.rb
|
17
17
|
test/test_oyster.rb
|
data/README.txt
CHANGED
@@ -1,18 +1,22 @@
|
|
1
1
|
= Oyster
|
2
2
|
|
3
|
-
http://github.com/jcoglan/oyster
|
4
|
-
|
5
|
-
=== Description
|
3
|
+
* http://github.com/jcoglan/oyster
|
6
4
|
|
7
5
|
Oyster is a command-line input parser that doesn't hate you. It provides a simple
|
8
6
|
API that you use to write a spec for the user interface to your program, and it
|
9
7
|
handles mapping the input to a hash for you. It supports both long and short option
|
10
8
|
names, subcommands, and various types of input data.
|
11
9
|
|
10
|
+
|
11
|
+
=== Installation
|
12
|
+
|
13
|
+
sudo gem install oyster
|
14
|
+
|
15
|
+
|
12
16
|
=== Features
|
13
17
|
|
14
18
|
* Parses command line options into a hash for easy access
|
15
|
-
* Supports long (
|
19
|
+
* Supports long (<tt>--example</tt>) and short (<tt>-e</tt>) names, including compound (<tt>-zxvf</tt>) short options
|
16
20
|
* Supports subcommand recognition
|
17
21
|
* Can parse options as booleans, strings, arrays, files, globs
|
18
22
|
* Automatically handles single-letter shortcuts for option names
|
@@ -20,12 +24,13 @@ names, subcommands, and various types of input data.
|
|
20
24
|
* Is easily extensible to support custom input types
|
21
25
|
* Automatically outputs man-page-style help for your program
|
22
26
|
|
27
|
+
|
23
28
|
=== Usage
|
24
29
|
|
25
30
|
You begin your command-line script by writing a spec for its options, layed out
|
26
31
|
like a Unix manual page. This spec will be used to parse input and to generate
|
27
|
-
help text using the
|
28
|
-
spec API. You can use as much or as little of it as you like, none of the fields
|
32
|
+
help text using the <tt>--help</tt> flag. This example demonstrates a wide range of
|
33
|
+
the spec API. You can use as much or as little of it as you like, none of the fields
|
29
34
|
are required.
|
30
35
|
|
31
36
|
require 'rubygems'
|
@@ -45,19 +50,21 @@ are required.
|
|
45
50
|
EOS
|
46
51
|
|
47
52
|
flag :verbose, :default => false,
|
48
|
-
|
53
|
+
:desc => 'Print verbose output'
|
49
54
|
|
50
55
|
flag :recurse, :default => true,
|
51
|
-
|
56
|
+
:desc => 'Enter directories recursively'
|
57
|
+
|
58
|
+
shortcut :all, '--verbose --recurse'
|
52
59
|
|
53
60
|
string :type, :default => 'f',
|
54
|
-
|
61
|
+
:desc => 'Which type of files to move'
|
55
62
|
|
56
63
|
integer :status, :default => 200,
|
57
|
-
|
64
|
+
:desc => 'Tell the program the status code to return'
|
58
65
|
|
59
66
|
float :quality, :default => 0.5,
|
60
|
-
|
67
|
+
:desc => 'Level of compression loss incurred when copying'
|
61
68
|
|
62
69
|
glob :files, :desc => <<-EOS
|
63
70
|
Pattern for selecting which files to move. For example, to select all the
|
@@ -87,8 +94,8 @@ are required.
|
|
87
94
|
end
|
88
95
|
|
89
96
|
Having defined your spec, you can use it to parse user input. Input is specified
|
90
|
-
as an array of string tokens, and defaults to ARGV
|
91
|
-
|
97
|
+
as an array of string tokens, and defaults to +ARGV+. If the program is invoked using
|
98
|
+
<tt>--help</tt>, Oyster will throw a <tt>Oyster::HelpRendered</tt> exception that you can
|
92
99
|
use to halt your program if necessary. An example taking input from the command
|
93
100
|
line:
|
94
101
|
|
@@ -105,6 +112,10 @@ as specified by the user. For example:
|
|
105
112
|
Input: --no-recurse
|
106
113
|
Oupput: opts[:recurse] == false
|
107
114
|
|
115
|
+
Input: --all
|
116
|
+
Output options[:verbose] == true
|
117
|
+
options[:recurse] == true
|
118
|
+
|
108
119
|
Input: --dest /path/to/mydir
|
109
120
|
Output: opts[:dest] == '/path/to/mydir'
|
110
121
|
|
@@ -136,6 +147,7 @@ glob before handing it to the Ruby interpreter.
|
|
136
147
|
-- Oyster will call Dir.glob('**/*.rb')
|
137
148
|
opts[:files] == ['foo.rb', 'bar.rb', 'dir/baz.rb', ...]
|
138
149
|
|
150
|
+
|
139
151
|
=== Unclaimed input
|
140
152
|
|
141
153
|
Any input tokens not absorbed by one of the option flags will be written to an
|
@@ -146,6 +158,7 @@ array in <tt>opts[:unclaimed]</tt>:
|
|
146
158
|
opts[:dest] == '/path/to/dir'
|
147
159
|
opts[:unclaimed] == ['some_arg']
|
148
160
|
|
161
|
+
|
149
162
|
=== Subcommands
|
150
163
|
|
151
164
|
You can easily create subcommands by nesting specs inside the main one:
|
@@ -179,14 +192,6 @@ Subcommand options are stored as a hash inside the main options hash:
|
|
179
192
|
Beware that you cannot give a subcommand the same name as an option flag,
|
180
193
|
otherwise you'll get a name collision in the output.
|
181
194
|
|
182
|
-
=== Requirements
|
183
|
-
|
184
|
-
* Rubygems
|
185
|
-
* Oyster gem
|
186
|
-
|
187
|
-
=== Installation
|
188
|
-
|
189
|
-
sudo gem install oyster
|
190
195
|
|
191
196
|
=== License
|
192
197
|
|
data/Rakefile
CHANGED
data/lib/oyster.rb
CHANGED
@@ -1,11 +1,14 @@
|
|
1
1
|
module Oyster
|
2
|
-
VERSION = '0.9.
|
2
|
+
VERSION = '0.9.2'
|
3
3
|
|
4
4
|
LONG_NAME = /^--([a-z\[][a-z0-9\]\-]+)$/i
|
5
5
|
SHORT_NAME = /^-([a-z0-9]+)$/i
|
6
6
|
|
7
7
|
HELP_INDENT = 7
|
8
|
-
HELP_WIDTH =
|
8
|
+
HELP_WIDTH = 80
|
9
|
+
|
10
|
+
STOP_FLAG = '--'
|
11
|
+
NEGATOR = /^no-/
|
9
12
|
|
10
13
|
WINDOWS = RUBY_PLATFORM.split('-').any? { |part| part =~ /mswin\d*/i }
|
11
14
|
|
@@ -19,7 +22,7 @@ module Oyster
|
|
19
22
|
end
|
20
23
|
|
21
24
|
def self.is_name?(string)
|
22
|
-
!string.nil? and !!(string =~ LONG_NAME || string =~ SHORT_NAME || string ==
|
25
|
+
!string.nil? and !!(string =~ LONG_NAME || string =~ SHORT_NAME || string == STOP_FLAG)
|
23
26
|
end
|
24
27
|
end
|
25
28
|
|
data/lib/oyster/specification.rb
CHANGED
@@ -49,7 +49,7 @@ module Oyster
|
|
49
49
|
output = {:unclaimed => []}
|
50
50
|
|
51
51
|
while token = input.shift
|
52
|
-
if token ==
|
52
|
+
if token == STOP_FLAG
|
53
53
|
output[:unclaimed] = output[:unclaimed] + input
|
54
54
|
break
|
55
55
|
end
|
@@ -61,8 +61,8 @@ module Oyster
|
|
61
61
|
|
62
62
|
input = short.scan(/./).map { |s| "-#{s}" } + input and next if short and short.size > 1
|
63
63
|
|
64
|
-
negative = !!(long && long =~
|
65
|
-
long.sub!(
|
64
|
+
negative = !!(long && long =~ NEGATOR)
|
65
|
+
long.sub!(NEGATOR, '') if negative
|
66
66
|
|
67
67
|
option ||= self[long] || self[short]
|
68
68
|
output[:unclaimed] << token and next unless option
|
@@ -95,34 +95,53 @@ module Oyster
|
|
95
95
|
initial
|
96
96
|
end
|
97
97
|
|
98
|
-
def help
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
98
|
+
def help(stream = $stdout)
|
99
|
+
render(stream, @data[:name], 1, 'NAME')
|
100
|
+
render(stream, @data[:synopsis], 1, 'SYNOPSIS', false, true)
|
101
|
+
render(stream, @data[:description], 1, 'DESCRIPTION')
|
102
|
+
|
103
|
+
i = 0
|
104
|
+
stream.puts "\n#{ bold }OPTIONS#{ normal }"
|
103
105
|
each do |option|
|
104
|
-
|
105
|
-
|
106
|
-
|
106
|
+
render(stream, option.help_names.join(', '), 1, nil, false, true)
|
107
|
+
render(stream, option.description, 2)
|
108
|
+
i += 1
|
109
|
+
stream.puts "\n" if i < @options.size
|
107
110
|
end
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
+
|
112
|
+
render(stream, @data[:notes], 1, 'NOTES')
|
113
|
+
render(stream, @data[:author], 1, 'AUTHOR')
|
114
|
+
render(stream, @data[:copyright], 1, 'COPYRIGHT')
|
115
|
+
stream.puts "\n"
|
111
116
|
self
|
112
117
|
end
|
113
118
|
|
114
|
-
|
119
|
+
# Plagiarised from Trollop, Copyright (c) 2008 William Morgan
|
120
|
+
def display_width
|
121
|
+
@width ||= begin
|
122
|
+
require 'curses'
|
123
|
+
Curses.init_screen
|
124
|
+
x = Curses.cols
|
125
|
+
Curses.close_screen
|
126
|
+
x
|
127
|
+
rescue
|
128
|
+
HELP_WIDTH
|
129
|
+
end
|
130
|
+
@width - HELP_INDENT
|
131
|
+
end
|
132
|
+
|
133
|
+
def render(stream, text, level = 1, title = nil, join = true, man = false)
|
115
134
|
return unless text
|
116
|
-
puts "\n" + format("#{ bold }#{ title }#{ normal }", level - 1) if title
|
135
|
+
stream.puts "\n" + format("#{ normal }#{ bold }#{ title }#{ normal }", level - 1) if title
|
117
136
|
text = man_format(text) if man
|
118
|
-
puts format(text, level, join)
|
137
|
+
stream.puts format(text, level, join)
|
119
138
|
end
|
120
139
|
|
121
140
|
def format(text, level = 1, join = true)
|
122
141
|
lines = text.split(/\n/)
|
123
142
|
outdent = lines.inject(1000) { |n,s| [s.scan(/^\s*/).first.size, n].min }
|
124
143
|
indent = level * HELP_INDENT
|
125
|
-
width =
|
144
|
+
width = display_width - indent
|
126
145
|
|
127
146
|
lines.map { |line|
|
128
147
|
line.sub(/\s*$/, '').sub(%r{^\s{#{outdent}}}, '')
|
data/test/test_oyster.rb
CHANGED
@@ -35,6 +35,13 @@ class OysterTest < Test::Unit::TestCase
|
|
35
35
|
Which binary to use. You can change the executable used to format the output
|
36
36
|
of this command, setting it to your scripting language of choice. This is just
|
37
37
|
a lot of text to make sure help formatting works.
|
38
|
+
|
39
|
+
class WeCan
|
40
|
+
attr_writer :write_code
|
41
|
+
|
42
|
+
def in_option_descriptions
|
43
|
+
end
|
44
|
+
end
|
38
45
|
EOS
|
39
46
|
|
40
47
|
integer :status, :default => 200,
|
@@ -188,7 +195,7 @@ class OysterTest < Test::Unit::TestCase
|
|
188
195
|
|
189
196
|
def test_file
|
190
197
|
opts = @spec.parse %w(--path Rakefile)
|
191
|
-
assert opts[:path] =~ /
|
198
|
+
assert opts[:path] =~ /Hoe/
|
192
199
|
end
|
193
200
|
|
194
201
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: oyster
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.9.
|
4
|
+
version: 0.9.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- James Coglan
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-
|
12
|
+
date: 2009-06-19 00:00:00 +01:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -20,9 +20,9 @@ dependencies:
|
|
20
20
|
requirements:
|
21
21
|
- - ">="
|
22
22
|
- !ruby/object:Gem::Version
|
23
|
-
version:
|
23
|
+
version: 2.0.0
|
24
24
|
version:
|
25
|
-
description:
|
25
|
+
description: ""
|
26
26
|
email:
|
27
27
|
- jcoglan@googlemail.com
|
28
28
|
executables: []
|
@@ -41,18 +41,20 @@ files:
|
|
41
41
|
- lib/oyster.rb
|
42
42
|
- lib/oyster/specification.rb
|
43
43
|
- lib/oyster/option.rb
|
44
|
+
- lib/oyster/options/array.rb
|
45
|
+
- lib/oyster/options/file.rb
|
44
46
|
- lib/oyster/options/flag.rb
|
45
|
-
- lib/oyster/options/string.rb
|
46
|
-
- lib/oyster/options/integer.rb
|
47
47
|
- lib/oyster/options/float.rb
|
48
|
-
- lib/oyster/options/file.rb
|
49
|
-
- lib/oyster/options/array.rb
|
50
48
|
- lib/oyster/options/glob.rb
|
49
|
+
- lib/oyster/options/integer.rb
|
51
50
|
- lib/oyster/options/shortcut.rb
|
51
|
+
- lib/oyster/options/string.rb
|
52
52
|
- lib/oyster/options/subcommand.rb
|
53
53
|
- test/test_oyster.rb
|
54
54
|
has_rdoc: true
|
55
55
|
homepage: http://github.com/jcoglan/oyster
|
56
|
+
licenses: []
|
57
|
+
|
56
58
|
post_install_message:
|
57
59
|
rdoc_options:
|
58
60
|
- --main
|
@@ -74,9 +76,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
74
76
|
requirements: []
|
75
77
|
|
76
78
|
rubyforge_project: oyster
|
77
|
-
rubygems_version: 1.3.
|
79
|
+
rubygems_version: 1.3.3
|
78
80
|
signing_key:
|
79
|
-
specification_version:
|
80
|
-
summary:
|
81
|
+
specification_version: 3
|
82
|
+
summary: ""
|
81
83
|
test_files:
|
82
84
|
- test/test_oyster.rb
|