cooloptions 0.1.0 → 1.0.0

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 CHANGED
@@ -1,3 +1,9 @@
1
+ == 1.0.0 /
2
+
3
+ * Added test for short options specification.
4
+ * Improved the documentation.
5
+ * Re-vamped option specification completely.
6
+
1
7
  == 0.1.0 / 2006-11-30
2
8
 
3
9
  * Initial Release
data/README.txt CHANGED
@@ -8,26 +8,64 @@ CoolOptions is a simple wrapper around optparse that provides less options and m
8
8
 
9
9
  == SYNOPSYS:
10
10
 
11
+ === Declaration:
12
+
11
13
  options = CoolOptions.parse!("[options] PROJECTNAME") do |o|
12
- o.on :svk, "[no-]svk", "Use svk.", true
13
- o.on :project_path, "project-path PATH", "Root of project workspaces.", File.expand_path("~/svk")
14
- o.on :repository, "repository URL", "Remote subversion repository."
15
- o.on :repository_path, "repository-path PATH", "Remote repository path.", "/", "l"
16
- o.on :mirror_path, "mirror-path SVKPATH", "SVK mirror path.", "//"
17
- o.on :local_path, "local-path SVKPATH", "SVK local path.", "//local", "t"
18
- o.on :create_structure, "[no-]create-structure", "Create trunk/tags/branches structure.", true
19
- o.on :finish, "[no-]finish" , "Prep and commit the new project.", true
20
-
14
+ o.on "repository URL", "Remote subversion repository."
15
+ o.on "svk", "Use svk.", true
16
+ o.on "project-path PATH", "Root of project workspaces.", File.expand_path("~/svk")
17
+ o.on "l)repository-path PATH", "Remote repository path.", "/"
18
+ o.on "mirror-path SVKPATH", "SVK mirror path.", "//"
19
+ o.on "local-pa(t)h SVKPATH", "SVK local path.", "//local"
20
+ o.on "create-structure", "Create trunk/tags/branches structure.", true
21
+ o.on "finish", "Prep and commit the new project.", true
22
+
21
23
  o.after do |r|
22
24
  r.project_path = File.expand_path(r.project_path)
23
- raise "Invalid path." unless File.exist?(r.project_path)
25
+ o.error("Invalid path.") unless File.exist?(r.project_path)
24
26
  r.project_name = ARGV.shift
27
+ o.error("Project name is required.") unless r.project_name
28
+ o.error("Project name is too funky.") unless /^\w+$/ =~ r.project_name
25
29
  end
26
30
  end
31
+
32
+ === Usage:
33
+
34
+ $ ./new_rails_project --no-svk -r http://terralien.com/svn/terralien/ --no-finish
35
+
36
+ === Result:
37
+
38
+ p options.svk # => false
39
+ p options.project_path # => '/Users/ntalbott/svk'
40
+ p options.repository # => 'http://terralien.com/svn/terralien/'
41
+ p options.finish # => false
42
+ p options.create_structure # => true
43
+ p options.project_name # => 'myproject'
44
+
45
+ === Also:
46
+
47
+ $ ./new_rails_project --help
48
+ Usage: t.rb [options] PROJECTNAME
49
+ -s, --[no-]svk Use svk.
50
+ Default is: true
51
+ -p, --project-path PATH Root of project workspaces.
52
+ Default is: /Users/ntalbott/svk
53
+ -r, --repository URL Remote subversion repository.
54
+ -l, --repository-path PATH Remote repository path.
55
+ Default is: /
56
+ -m, --mirror-path SVKPATH SVK mirror path.
57
+ Default is: //
58
+ -t, --local-path SVKPATH SVK local path.
59
+ Default is: //local
60
+ -c, --[no-]create-structure Create trunk/tags/branches structure.
61
+ Default is: true
62
+ -f, --[no-]finish Prep and commit the new project.
63
+ Default is: true
64
+ -h, --help This help info.
27
65
 
28
66
  == REQUIREMENTS:
29
67
 
30
- optparse (included in Ruby stdlib)
68
+ optparse & ostruct (included in Ruby standard library).
31
69
 
32
70
  == INSTALL:
33
71
 
data/Rakefile CHANGED
@@ -5,7 +5,7 @@ require './lib/cooloptions.rb'
5
5
  Hoe.new('cooloptions', CoolOptions::VERSION) do |p|
6
6
  p.rubyforge_name = 'cooloptions'
7
7
  p.summary = p.description = 'CoolOptions is a simple wrapper around optparse that provides less options and more convenience.'
8
- p.url = 'https://rubyforge.org/projects/cooloptions/'
8
+ p.url = 'http://cooloptions.rubyforge.org/'
9
9
  p.changes = p.paragraphs_of('History.txt', 0..1).join("\n\n")
10
10
  p.author = "Nathaniel Talbott"
11
11
  p.email = "nathaniel@terralien.com"
data/lib/cooloptions.rb CHANGED
@@ -1,19 +1,30 @@
1
- # Copyright (c) 2006 Nathaniel Talbott and Terralien, Inc. All Rights Reserved.
2
- # Licensed under the RUBY license.
1
+ # Copyright:: Copyright (c) 2006 Nathaniel Talbott and Terralien, Inc. All Rights Reserved.
2
+ # License:: Licensed under the RUBY license.
3
3
 
4
4
  require 'optparse'
5
5
  require 'ostruct'
6
6
 
7
+ # For a high-level overview of using CoolOptions, see README.txt.
8
+ #
9
+ # == Usage
10
+ #
11
+ # :include:samples/literate.rb
12
+
7
13
  class CoolOptions
8
- VERSION = '0.1.0'
14
+ VERSION = '1.0.0' #:nodoc:
9
15
 
10
16
  class Error < StandardError #:nodoc:
11
17
  end
12
18
 
13
- def self.parse!(*args)
14
- o = new
19
+ # Takes an optional banner and the arguments you want to parse (defaults to
20
+ # ARGV) and yields a new CoolOptions to the supplied block. You can then
21
+ # declare your options in the block using the #on method, and do post-
22
+ # processing using #after. When processing is done, an OpenStruct
23
+ # containing the parsed options is returned.
24
+ def self.parse!(banner="[options]", argv=ARGV) #:yields: cooloptions
25
+ o = new(banner)
15
26
  yield o
16
- o.parse!(*args)
27
+ o.parse!(argv)
17
28
  rescue Error => e
18
29
  out.puts e.message
19
30
  o.help true
@@ -31,59 +42,75 @@ class CoolOptions
31
42
  @out = out
32
43
  end
33
44
 
34
- def initialize
35
- @options = []
45
+ attr_reader :parser, :result
46
+
47
+ def initialize(banner) #:nodoc:
48
+ @parser = OptionParser.new
49
+ @parser.banner = "Usage: #{File.basename($0)} #{banner}"
50
+
51
+ @required = []
52
+ @result = {}
36
53
  @after = nil
37
54
  end
38
55
 
39
- def on(key, long, message, default=nil, short=nil)
40
- unless short
41
- short = if /^\[/ =~ long
42
- long.split(/\]/).last
43
- else
44
- long
45
- end[0,1]
56
+ NO_DEFAULT = Object.new #:nodoc:
57
+
58
+ # Called on cooloptions within the #parse! block to add options to parse on.
59
+ # Long is the long option itself, description is, well, the description, and
60
+ # default is the default value for the option, if any.
61
+ def on(long, description, default=NO_DEFAULT)
62
+ if /^(.)\)(.+)$/ =~ long
63
+ short, long = $1, $2
64
+ elsif /^(.*)\((.)\)(.*)$/ =~ long
65
+ short = $2
66
+ long = $1 + $2 + $3
46
67
  end
47
- @options << [key, short, long, message, default]
68
+ short = long[0,1] unless short
69
+
70
+ key = long.split(/ /).first.gsub('-', '_').to_sym
71
+
72
+ unless long =~ / /
73
+ long = "[no-]#{long}"
74
+ end
75
+
76
+ args = ["-#{short}", "--#{long}", description]
77
+ if default == NO_DEFAULT
78
+ @required << key
79
+ else
80
+ @result[key] = default
81
+ args << "Default is: #{default}"
82
+ end
83
+
84
+ @parser.on(*args){|e| self.result[key] = e}
48
85
  end
49
86
 
50
- def parse!(banner="[options]", argv=ARGV)
51
- result = {}
52
- required = []
53
- OptionParser.new do |o|
54
- @o = o
55
- o.banner = "Usage: #{File.basename($0)} #{banner}"
87
+ def parse!(argv) #:nodoc:
88
+ @parser.on('-h', '--help', "This help info."){help}
89
+ @parser.parse!(argv)
90
+
91
+ @required.reject!{|e| @result.key?(e)}
92
+ error "Missing required options: #{@required.join(', ')}" unless @required.empty?
56
93
 
57
- @options.each do |(key, short, long, message, default)|
58
- args = ["-#{short}", "--#{long}", message]
59
- if default.nil?
60
- required << key
61
- else
62
- result[key] = default
63
- args << "Default is: #{default}"
64
- end
65
- o.on(*args){|e| result[key] = e}
66
- end
67
-
68
- o.on('-h', '--help', "This help info."){help}
69
- end.parse!(argv)
70
- required.reject!{|e| result.key?(e)}
71
- error "Missing required options: #{required.join(', ')}" unless required.empty?
72
- result = OpenStruct.new(result)
73
- @after.call(result) if @after
74
- result
94
+ r = OpenStruct.new(@result)
95
+ @after.call(r) if @after
96
+ r
75
97
  end
76
98
 
99
+ # If you want to throw an option parsing error, just call #error with a
100
+ # message and CoolOptions will bail out and display the help message.
77
101
  def error(message)
78
102
  raise Error, message, caller
79
103
  end
80
104
 
105
+ # CoolOptions only handles options parsing, and it only does rudimentary
106
+ # option validation. If you want to do more, #after is a convenient place do
107
+ # it, especially since the right thing will just happen if you call #error.
81
108
  def after(&after)
82
109
  @after = after
83
110
  end
84
111
 
85
- def help(error=false)
86
- out.puts @o
112
+ def help(error=false) #:nodoc:
113
+ out.puts @parser
87
114
  exit(error ? 1 : 0)
88
115
  end
89
116
  end
@@ -20,10 +20,10 @@ class TestCoolOptions < Test::Unit::TestCase
20
20
 
21
21
  def test_should_handle_booleans
22
22
  r = parse!(%w(-a --no-b --c)) do |o|
23
- o.on :a, '[no-]a', 'a', false
24
- o.on :b, '[no-]b', 'b', true
25
- o.on :c, '[no-]c', 'c', false
26
- o.on :d, '[no-]d', 'd', true
23
+ o.on 'a', 'a', false
24
+ o.on 'b', 'b', true
25
+ o.on 'c', 'c', false
26
+ o.on 'd', 'd', true
27
27
  end
28
28
 
29
29
  assert r.a
@@ -34,8 +34,8 @@ class TestCoolOptions < Test::Unit::TestCase
34
34
 
35
35
  def test_should_handle_strings
36
36
  r = parse!(%w(-a b --c=d)) do |o|
37
- o.on :a, 'a ARG', 'a'
38
- o.on :c, 'c ARG', 'c'
37
+ o.on 'a ARG', 'a'
38
+ o.on 'c ARG', 'c'
39
39
  end
40
40
 
41
41
  assert_equal 'b', r.a
@@ -44,7 +44,7 @@ class TestCoolOptions < Test::Unit::TestCase
44
44
 
45
45
  def test_should_ignore_non_options
46
46
  r = CoolOptions.parse!('', argv=%w(ab -c de)) do |o|
47
- o.on :c, '[no-]c', 'c'
47
+ o.on 'c', 'c'
48
48
  end
49
49
 
50
50
  assert r.c
@@ -54,7 +54,7 @@ class TestCoolOptions < Test::Unit::TestCase
54
54
  def test_should_call_after
55
55
  called = false
56
56
  r = parse!(%w(-a)) do |o|
57
- o.on :a, '[no-]a', 'a'
57
+ o.on 'a', 'a'
58
58
  o.after{|r| assert r.a; called=true}
59
59
  end
60
60
  assert called
@@ -71,7 +71,7 @@ class TestCoolOptions < Test::Unit::TestCase
71
71
  def test_should_output_help
72
72
  begin
73
73
  r = CoolOptions.parse!('details', %w(--help)) do |o|
74
- o.on :a, '[no-]a', 'aa'
74
+ o.on 'a', 'aa'
75
75
  end
76
76
  rescue SystemExit
77
77
  rescued = true
@@ -88,8 +88,39 @@ EOH
88
88
  def test_should_require_options_with_no_default
89
89
  assert_raise(SystemExit) do
90
90
  CoolOptions.parse!([]) do |o|
91
- o.on :a, 'a A', 'a'
91
+ o.on 'a A', 'a'
92
92
  end
93
93
  end
94
+ assert_nothing_raised do
95
+ CoolOptions.parse!([]) do |o|
96
+ o.on 'a A', 'a', nil
97
+ end
98
+ end
99
+ end
100
+
101
+ def test_should_allow_specification_of_alternate_short_form
102
+ r = parse!(%w(-a -b c -c d)) do |o|
103
+ o.on 'a', 'a', false
104
+ o.on 'b)aa VALUE', 'aa'
105
+ o.on 'b(c) VALUE', 'bc'
106
+ end
107
+ assert_equal true, r.a
108
+ assert_equal 'c', r.aa
109
+ assert_equal 'd', r.bc
110
+ end
111
+
112
+ def test_should_replace_dashes
113
+ r = parse!(%w(--a-b c)) do |o|
114
+ o.on 'a-b A', 'a'
115
+ end
116
+ assert_equal 'c', r.a_b
117
+ end
118
+
119
+ def test_should_provide_access_to_the_parser
120
+ called = false
121
+ r = parse!(%w(-d)) do |o|
122
+ o.parser.on('-d'){called = true}
123
+ end
124
+ assert called
94
125
  end
95
126
  end
metadata CHANGED
@@ -3,13 +3,13 @@ rubygems_version: 0.8.11
3
3
  specification_version: 1
4
4
  name: cooloptions
5
5
  version: !ruby/object:Gem::Version
6
- version: 0.1.0
7
- date: 2006-12-07 00:00:00 -05:00
6
+ version: 1.0.0
7
+ date: 2006-12-09 00:00:00 -05:00
8
8
  summary: CoolOptions is a simple wrapper around optparse that provides less options and more convenience.
9
9
  require_paths:
10
10
  - lib
11
11
  email: nathaniel@terralien.com
12
- homepage: https://rubyforge.org/projects/cooloptions/
12
+ homepage: http://cooloptions.rubyforge.org/
13
13
  rubyforge_project: cooloptions
14
14
  description: CoolOptions is a simple wrapper around optparse that provides less options and more convenience.
15
15
  autorequire: