optopus 0.1.0

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 +49 -0
  2. data/lib/optopus.rb +189 -0
  3. metadata +68 -0
data/README ADDED
@@ -0,0 +1,49 @@
1
+ = optopus
2
+
3
+ == Description
4
+
5
+ Enhanced option parser.
6
+
7
+ == Install
8
+
9
+ gem install optopus
10
+
11
+ == Example
12
+
13
+ require 'rubygems'
14
+ require 'optopus'
15
+
16
+ opts = optopus do
17
+ desc 'print lots of debugging information'
18
+ option :debug, '-d', '--debug'
19
+
20
+ desc 'log messages to FILE.'
21
+ option :output_file, '-o', '--output-file FILE', :default => '/var/log/xxx.log'
22
+
23
+ desc 'set number of retries to NUMBER (0 unlimits)'
24
+ option :tries, '-t', '--tries NUMBER', :type => Integer, :default => 0 do
25
+ # custom validation
26
+ invalid_argument if @value < 0
27
+ end
28
+
29
+ desc 'comma-separated list of accepted extensions'
30
+ option :accept, '-A', '--accept LIST', :type => Array, :default => []
31
+
32
+ desc 'access timestamp'
33
+ option :timestamp, '-T', '--timestamp TIME', :type => Time
34
+
35
+ # read yaml config file and overwrite options
36
+ file '-c', '--config-file FILE'
37
+
38
+ after do
39
+ # postprocessing
40
+ # @options.each { ... }
41
+ end
42
+
43
+ exception do |e|
44
+ $stderr.puts e.message
45
+ exit 1
46
+ end
47
+ end
48
+
49
+ p opts
data/lib/optopus.rb ADDED
@@ -0,0 +1,189 @@
1
+ require 'optparse'
2
+ require 'optparse/date'
3
+ require 'optparse/shellwords'
4
+ require 'optparse/time'
5
+ require 'optparse/uri'
6
+ require 'yaml'
7
+
8
+ module Optopus
9
+ class DefinerContext
10
+ def self.evaluate(opts, &block)
11
+ self.new(opts).instance_eval(&block)
12
+ end
13
+
14
+ def initialize(opts)
15
+ @opts = opts
16
+ end
17
+
18
+ def desc(str)
19
+ @desc = str
20
+ end
21
+
22
+ def option(name, args_hd, *args_tl, &block)
23
+ @opts.add(name, [args_hd] + args_tl, @desc, block)
24
+ @desc = nil
25
+ end
26
+
27
+ def file(args_hd, *args_tl)
28
+ @desc ||= 'reading config file'
29
+ @opts.add_file([args_hd] + args_tl, @desc)
30
+ @desc = nil
31
+ end
32
+
33
+ def after(&block)
34
+ @opts.add_after(block)
35
+ end
36
+
37
+ def exception(&block)
38
+ @opts.add_exception(block)
39
+ end
40
+ end # DefinerContext
41
+
42
+ class CheckerContext
43
+ def self.evaluate(args, vars = {}, &block)
44
+ self.new(args, vars).instance_eval(&block)
45
+ end
46
+
47
+ def initialize(value, vars = {})
48
+ @args = value ? [value] : []
49
+
50
+ vars.each do |name, value|
51
+ instance_variable_set("@#{name}", value)
52
+ end
53
+ end
54
+
55
+ def parse_error(reason)
56
+ e = OptionParser::ParseError.new(*@args)
57
+ e.reason = reason
58
+ raise e
59
+ end
60
+
61
+ def ambiguous_option
62
+ raise OptionParser::AmbiguousOption.new(*@args)
63
+ end
64
+
65
+ def needless_argument
66
+ raise OptionParser::NeedlessArgument.new(*@args)
67
+ end
68
+
69
+ def missing_argument
70
+ raise OptionParser::MissingArgument.new(*@args)
71
+ end
72
+
73
+ def invalid_option
74
+ raise OptionParser::InvalidOption.new(*@args)
75
+ end
76
+
77
+ def invalid_argument
78
+ raise OptionParser::InvalidArgument.new(*@args)
79
+ end
80
+
81
+ def ambiguous_argument
82
+ raise OptionParser::AmbiguousArgument.new(*@args)
83
+ end
84
+ end # CheckerContext
85
+
86
+ class Options
87
+ def initialize
88
+ @opts_args = []
89
+ end
90
+
91
+ def add(name, args, desc, block)
92
+ args, defval = fix_args(args, desc)
93
+ @opts_args << [name.to_sym, args, defval, block]
94
+ end
95
+
96
+ def add_file(args, desc)
97
+ args, defval = fix_args(args, desc)
98
+ @file_args = args
99
+ end
100
+
101
+ def add_after(block)
102
+ @on_after = block
103
+ end
104
+
105
+ def add_exception(block)
106
+ @on_exception = block
107
+ end
108
+
109
+ def parse!
110
+ parser = OptionParser.new
111
+ options = {}
112
+ has_arg_h = false
113
+
114
+ @opts_args.each do |name, args, defval, block|
115
+ options[name] = defval
116
+ has_arg_h = (args.first == '-h')
117
+
118
+ parser.on(*args) do |*v|
119
+ value = v.first || true
120
+ options[name] = value
121
+ CheckerContext.evaluate(v, {:value => value}, &block) if block
122
+ end
123
+ end
124
+
125
+ if @file_args
126
+ parser.on(*@file_args) do |v|
127
+ config = YAML.load_file(v)
128
+
129
+ @opts_args.each do |name, args, defval, block|
130
+ value = config[name] || config[name.to_s]
131
+
132
+ next unless value
133
+
134
+ value = value.to_s
135
+ type = args.find {|i| i.kind_of?(Class) }
136
+ pat, conv = OptionParser::DefaultList.atype[type]
137
+
138
+ if pat and pat !~ value
139
+ raise OptionParser::InvalidArgument.new("(#{name}: #{value})")
140
+ end
141
+
142
+ value = conv.call(value) if conv
143
+
144
+ options[name] = value
145
+ end
146
+ end
147
+ end
148
+
149
+ unless has_arg_h
150
+ parser.on_tail('-h', '--help', 'Show this message') do
151
+ puts parser.help
152
+ exit
153
+ end
154
+ end
155
+
156
+ parser.parse!(ARGV)
157
+ CheckerContext.evaluate([], {:options => options},&@on_after) if @on_after
158
+
159
+ return options
160
+ rescue => e
161
+ if @on_exception
162
+ @on_exception.call(e)
163
+ else
164
+ raise e
165
+ end
166
+ end
167
+
168
+ private
169
+ def fix_args(args, desc)
170
+ defval = nil
171
+
172
+ if args.last.kind_of?(Hash)
173
+ hash = args.pop
174
+ args = (args.slice(0, 2) + [hash[:type], hash[:desc] || desc]).select {|i| i }
175
+ defval = hash[:default]
176
+ elsif desc
177
+ args = args + [desc]
178
+ end
179
+
180
+ return [args, defval]
181
+ end
182
+ end # Options
183
+ end # Optopus
184
+
185
+ def optopus(&block)
186
+ opts = Optopus::Options.new
187
+ Optopus::DefinerContext.evaluate(opts, &block)
188
+ opts.parse!
189
+ end
metadata ADDED
@@ -0,0 +1,68 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: optopus
3
+ version: !ruby/object:Gem::Version
4
+ hash: 27
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 1
9
+ - 0
10
+ version: 0.1.0
11
+ platform: ruby
12
+ authors:
13
+ - winebarrel
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-05-31 00:00:00 +09:00
19
+ default_executable:
20
+ dependencies: []
21
+
22
+ description:
23
+ email: sgwr_dts@yahoo.co.jp
24
+ executables: []
25
+
26
+ extensions: []
27
+
28
+ extra_rdoc_files: []
29
+
30
+ files:
31
+ - README
32
+ - lib/optopus.rb
33
+ has_rdoc: true
34
+ homepage: https://bitbucket.org/winebarrel/optopus
35
+ licenses: []
36
+
37
+ post_install_message:
38
+ rdoc_options: []
39
+
40
+ require_paths:
41
+ - lib
42
+ required_ruby_version: !ruby/object:Gem::Requirement
43
+ none: false
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ hash: 3
48
+ segments:
49
+ - 0
50
+ version: "0"
51
+ required_rubygems_version: !ruby/object:Gem::Requirement
52
+ none: false
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ hash: 3
57
+ segments:
58
+ - 0
59
+ version: "0"
60
+ requirements: []
61
+
62
+ rubyforge_project:
63
+ rubygems_version: 1.4.2
64
+ signing_key:
65
+ specification_version: 3
66
+ summary: Enhanced option parser.
67
+ test_files: []
68
+