oyster 0.9.1 → 0.9.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,6 +1,17 @@
1
- === 1.0.0 / 2008-07-09
1
+ === 0.9.2 / 2009-06-19
2
2
 
3
- * 1 major enhancement
3
+ * Use Curses to set the width of help output.
4
+ * Fix some formatting and layout bugs in help text.
4
5
 
5
- * Birthday!
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
 
@@ -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 (--example) and short (-e) names, including compound (-zxvf) short options
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 --help flag. This example demonstrates a wide range of 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
- :desc => 'Print verbose output'
53
+ :desc => 'Print verbose output'
49
54
 
50
55
  flag :recurse, :default => true,
51
- :desc => 'Enter directories recursively'
56
+ :desc => 'Enter directories recursively'
57
+
58
+ shortcut :all, '--verbose --recurse'
52
59
 
53
60
  string :type, :default => 'f',
54
- :desc => 'Which type of files to move'
61
+ :desc => 'Which type of files to move'
55
62
 
56
63
  integer :status, :default => 200,
57
- :desc => 'Tell the program the status code to return'
64
+ :desc => 'Tell the program the status code to return'
58
65
 
59
66
  float :quality, :default => 0.5,
60
- :desc => 'Level of compression loss incurred when copying'
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. If the program is invoked using
91
- --help, Oyster will throw a <tt>Oyster::HelpRendered</tt> exception that you can
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
@@ -4,7 +4,7 @@ require 'rubygems'
4
4
  require 'hoe'
5
5
  require './lib/oyster.rb'
6
6
 
7
- Hoe.new('oyster', Oyster::VERSION) do |p|
7
+ Hoe.spec('oyster') do |p|
8
8
  p.developer('James Coglan', 'jcoglan@googlemail.com')
9
9
  end
10
10
 
@@ -1,11 +1,14 @@
1
1
  module Oyster
2
- VERSION = '0.9.1'
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 = 72
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
 
@@ -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 =~ /^no-/)
65
- long.sub!(/^no-/, '') if negative
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
- display(@data[:name], 1, 'NAME')
100
- display(@data[:synopsis], 1, 'SYNOPSIS', false, true)
101
- display(@data[:description], 1, 'DESCRIPTION')
102
- puts "\n#{ bold }OPTIONS#{ normal }"
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
- display(option.help_names.join(', '), 1, nil, false, true)
105
- display(option.description, 2)
106
- puts "\n"
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
- display(@data[:notes], 1, 'NOTES')
109
- display(@data[:author], 1, 'AUTHOR')
110
- display(@data[:copyright], 1, 'COPYRIGHT')
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
- def display(text, level = 1, title = nil, join = true, man = false)
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 = HELP_WIDTH - indent
144
+ width = display_width - indent
126
145
 
127
146
  lines.map { |line|
128
147
  line.sub(/\s*$/, '').sub(%r{^\s{#{outdent}}}, '')
@@ -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] =~ /Oyster::VERSION/
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.1
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-01-30 00:00:00 +00:00
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: 1.8.2
23
+ version: 2.0.0
24
24
  version:
25
- description: Oyster is a command-line input parser that doesn't hate you. It provides a simple API that you use to write a spec for the user interface to your program, and it handles mapping the input to a hash for you. It supports both long and short option names, subcommands, and various types of input data.
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.1
79
+ rubygems_version: 1.3.3
78
80
  signing_key:
79
- specification_version: 2
80
- summary: Oyster is a command-line input parser that doesn't hate you
81
+ specification_version: 3
82
+ summary: ""
81
83
  test_files:
82
84
  - test/test_oyster.rb