oyster 0.9.1 → 0.9.2
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.
- 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
|