ragol 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/ragol/args.rb +77 -0
- data/lib/ragol/argslist.rb +60 -0
- data/lib/ragol/boolean_option.rb +15 -0
- data/lib/ragol/doc.rb +79 -0
- data/lib/ragol/exception.rb +7 -0
- data/lib/ragol/fixnum_option.rb +19 -0
- data/lib/ragol/float_option.rb +19 -0
- data/lib/ragol/hash.rb +16 -0
- data/lib/ragol/matcher.rb +48 -0
- data/lib/ragol/matchers.rb +64 -0
- data/lib/ragol/option.rb +168 -0
- data/lib/ragol/optproc/optproc.rb +4 -0
- data/lib/ragol/optproc/optset.rb +19 -0
- data/lib/ragol/optset.rb +197 -0
- data/lib/ragol/regexp_option.rb +17 -0
- data/lib/ragol/results.rb +69 -0
- data/lib/ragol/string_option.rb +14 -0
- data/lib/ragol/synoption/args.rb +26 -0
- data/lib/ragol/synoption/boolean_option.rb +22 -0
- data/lib/ragol/synoption/fixnum_option.rb +12 -0
- data/lib/ragol/synoption/float_option.rb +12 -0
- data/lib/ragol/synoption/option.rb +27 -0
- data/lib/ragol/synoption/optset.rb +9 -0
- metadata +83 -0
data/lib/ragol/args.rb
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
#!/usr/bin/ruby -w
|
2
|
+
# -*- ruby -*-
|
3
|
+
|
4
|
+
require 'ragol/hash'
|
5
|
+
|
6
|
+
module Ragol
|
7
|
+
class OptionArguments < Hash
|
8
|
+
VAR_TYPES = {
|
9
|
+
:boolean => :boolean,
|
10
|
+
:string => :string,
|
11
|
+
:float => :float,
|
12
|
+
:integer => :fixnum,
|
13
|
+
:fixnum => :fixnum,
|
14
|
+
:regexp => :regexp,
|
15
|
+
}
|
16
|
+
|
17
|
+
OLD_OPTIONS = {
|
18
|
+
:regexps => [ Regexp.new('--fo+'), Regexp.new('--ba*r') ],
|
19
|
+
:tags => [ '--foo', '-b' ],
|
20
|
+
:arg => [ [ :boolean, :string, :float, :integer, :fixnum, :regexp ], [ :optional, :required, :none ] ],
|
21
|
+
:set => Proc.new { },
|
22
|
+
:rcnames => [ "foo" ],
|
23
|
+
:rc => [ ]
|
24
|
+
}
|
25
|
+
|
26
|
+
NEW_OPTIONS = {
|
27
|
+
:regexps => [ Regexp.new('--fo+'), Regexp.new('--ba*r') ],
|
28
|
+
:tags => [ '--foo', '-b' ],
|
29
|
+
:rcnames => [ 'foo', 'foobar' ],
|
30
|
+
:takesvalue => [ true, :optional, false ],
|
31
|
+
:valuetype => [ :boolean, :string, :float, :integer, :fixnum, :regexp ],
|
32
|
+
:valueregexp => Regexp.new('(one|two|three)'),
|
33
|
+
:default => nil,
|
34
|
+
:process => Proc.new { |val| },
|
35
|
+
:postproc => Proc.new { |optset, results, unprocessed| },
|
36
|
+
:description => "a description"
|
37
|
+
}
|
38
|
+
|
39
|
+
def initialize origargs = Hash.new
|
40
|
+
super()
|
41
|
+
|
42
|
+
if origargs[:arg]
|
43
|
+
if re = origargs[:arg].find { |x| x.kind_of?(Regexp) }
|
44
|
+
self[:valueregexp] = re
|
45
|
+
self[:valuetype] = :regexp
|
46
|
+
else
|
47
|
+
self[:valuetype] = Ragol::HashUtil.hash_array_value VAR_TYPES, origargs[:arg]
|
48
|
+
end
|
49
|
+
|
50
|
+
self[:takesvalue] = if self[:valuetype] == :boolean
|
51
|
+
false
|
52
|
+
else
|
53
|
+
hasvaluetype = self[:valuetype] != nil
|
54
|
+
takes = { :optional => :optional, :required => true, :none => hasvaluetype, nil => hasvaluetype }
|
55
|
+
Ragol::HashUtil.hash_array_value takes, origargs[:arg]
|
56
|
+
end
|
57
|
+
else
|
58
|
+
Ragol::HashUtil.copy_hash self, origargs, [ [ :takesvalue, :valuereq ], [ :valuetype ], [ :valueregexp ] ]
|
59
|
+
if self[:valuetype]
|
60
|
+
self[:takesvalue] ||= true
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
fields = [
|
65
|
+
[ :regexps, :regexp, :res, :re ],
|
66
|
+
[ :tags ],
|
67
|
+
[ :process, :set ],
|
68
|
+
[ :postproc ],
|
69
|
+
[ :rcnames, :rcname, :rc ],
|
70
|
+
[ :default ],
|
71
|
+
[ :unsets, :unset ],
|
72
|
+
[ :description ],
|
73
|
+
]
|
74
|
+
Ragol::HashUtil.copy_hash self, origargs, fields
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
#!/usr/bin/ruby -w
|
2
|
+
# -*- ruby -*-
|
3
|
+
|
4
|
+
module Ragol
|
5
|
+
class ArgsList
|
6
|
+
attr_accessor :args
|
7
|
+
|
8
|
+
def initialize args = Array.new
|
9
|
+
@args = args
|
10
|
+
end
|
11
|
+
|
12
|
+
def next_arg
|
13
|
+
curr = @args.shift
|
14
|
+
re = Regexp.new('^- (?:(\d+)(\D+) | ([a-zA-Z])(\w+) )', Regexp::EXTENDED)
|
15
|
+
|
16
|
+
if md = re.match(curr)
|
17
|
+
mi = md[1] ? 1 : 3
|
18
|
+
arg, newarg = ('-' + md[mi]), ('-' + md[mi + 1])
|
19
|
+
@args.unshift newarg
|
20
|
+
arg
|
21
|
+
else
|
22
|
+
curr
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def shift_arg
|
27
|
+
@args.shift
|
28
|
+
end
|
29
|
+
|
30
|
+
def args_empty?
|
31
|
+
@args.empty?
|
32
|
+
end
|
33
|
+
|
34
|
+
def empty?
|
35
|
+
@args.empty?
|
36
|
+
end
|
37
|
+
|
38
|
+
def current_arg
|
39
|
+
curr = @args[0]
|
40
|
+
re = Regexp.new('^-(?:\d+|\w)')
|
41
|
+
if md = re.match(curr)
|
42
|
+
md[0]
|
43
|
+
else
|
44
|
+
curr
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def eql? args
|
49
|
+
@args == args
|
50
|
+
end
|
51
|
+
|
52
|
+
def [] idx
|
53
|
+
@args[idx]
|
54
|
+
end
|
55
|
+
|
56
|
+
def end_of_options?
|
57
|
+
current_arg == '--'
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
#!/usr/bin/ruby -w
|
2
|
+
# -*- ruby -*-
|
3
|
+
|
4
|
+
require 'ragol/option'
|
5
|
+
|
6
|
+
module Ragol
|
7
|
+
# a boolean option maps to a single tag, not a tag and value. For example,
|
8
|
+
# "-v" (verbose) is a boolean option, but "-r 3444" (revision) is a option
|
9
|
+
# with a value.
|
10
|
+
class BooleanOption < Option
|
11
|
+
def takes_value?
|
12
|
+
false
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
data/lib/ragol/doc.rb
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
#!/usr/bin/ruby -w
|
2
|
+
# -*- ruby -*-
|
3
|
+
|
4
|
+
require 'logue/loggable'
|
5
|
+
|
6
|
+
module Ragol
|
7
|
+
# documentation for an option.
|
8
|
+
class Doc
|
9
|
+
include Logue::Loggable
|
10
|
+
|
11
|
+
def initialize option
|
12
|
+
@option = option
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_doc_tag
|
16
|
+
tags = @option.matchers.tags.elements
|
17
|
+
longopts, shortopts = tags.partition { |tag| tag[0 .. 1] == '--' }
|
18
|
+
tagline = [ shortopts, longopts ].flatten.join ', '
|
19
|
+
if @option.takes_value?
|
20
|
+
tagline << " ARG"
|
21
|
+
end
|
22
|
+
tagline
|
23
|
+
end
|
24
|
+
|
25
|
+
# returns an option regexp as a 'cleaner' string
|
26
|
+
def re_to_string re
|
27
|
+
re.source.gsub(%r{\\d\+?}, 'N').gsub(%r{[\^\?\$\\\(\)]}, '')
|
28
|
+
end
|
29
|
+
|
30
|
+
def to_doc_negate
|
31
|
+
doc = nil
|
32
|
+
@option.matchers.negatives.elements.each do |neg|
|
33
|
+
str = if neg.kind_of? Regexp
|
34
|
+
str = re_to_string neg
|
35
|
+
else
|
36
|
+
str = neg
|
37
|
+
end
|
38
|
+
|
39
|
+
if doc
|
40
|
+
doc << " [#{str}]"
|
41
|
+
else
|
42
|
+
doc = str
|
43
|
+
end
|
44
|
+
end
|
45
|
+
doc
|
46
|
+
end
|
47
|
+
|
48
|
+
# -g [--use-merge-history] : use/display additional information from merge
|
49
|
+
# 01234567890123456789012345678901234567890123456789012345678901234567890123456789
|
50
|
+
# 0 1 2 3 4 5 6
|
51
|
+
|
52
|
+
def to_doc_line lhs, rhs, sep = ""
|
53
|
+
fmt = " %-24s %1s %s"
|
54
|
+
sprintf fmt, lhs, sep, rhs
|
55
|
+
end
|
56
|
+
|
57
|
+
def to_doc io
|
58
|
+
# wrap optdesc?
|
59
|
+
|
60
|
+
[ @option.description ].flatten.each_with_index do |descline, idx|
|
61
|
+
lhs = idx == 0 ? to_doc_tag : ""
|
62
|
+
io.puts to_doc_line lhs, descline, idx == 0 ? ":" : ""
|
63
|
+
end
|
64
|
+
|
65
|
+
if defval = @option.default
|
66
|
+
io.puts to_doc_line "", " default: #{defval}"
|
67
|
+
end
|
68
|
+
|
69
|
+
if re = @option.matchers.regexps
|
70
|
+
io.puts to_doc_line re_to_string(re), "same as above", ":"
|
71
|
+
end
|
72
|
+
|
73
|
+
if @option.matchers.negatives
|
74
|
+
lhs = to_doc_negate
|
75
|
+
io.puts to_doc_line lhs, "", ""
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
#!/usr/bin/ruby -w
|
2
|
+
# -*- ruby -*-
|
3
|
+
|
4
|
+
require 'ragol/option'
|
5
|
+
|
6
|
+
module Ragol
|
7
|
+
class FixnumOption < Option
|
8
|
+
REGEXP = Regexp.new '^ ([\-\+]?\d+) $ ', Regexp::EXTENDED
|
9
|
+
|
10
|
+
def value_regexp
|
11
|
+
REGEXP
|
12
|
+
end
|
13
|
+
|
14
|
+
def convert md
|
15
|
+
return unless val = md && md[-1]
|
16
|
+
val.to_i
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
#!/usr/bin/ruby -w
|
2
|
+
# -*- ruby -*-
|
3
|
+
|
4
|
+
require 'ragol/option'
|
5
|
+
|
6
|
+
module Ragol
|
7
|
+
class FloatOption < Option
|
8
|
+
REGEXP = Regexp.new '^ ([\-\+]?\d* (?:\.\d+)?) $ ', Regexp::EXTENDED
|
9
|
+
|
10
|
+
def value_regexp
|
11
|
+
REGEXP
|
12
|
+
end
|
13
|
+
|
14
|
+
def convert md
|
15
|
+
return unless val = md && md[-1]
|
16
|
+
val.to_f
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/lib/ragol/hash.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
#!/usr/bin/ruby -w
|
2
|
+
# -*- ruby -*-
|
3
|
+
|
4
|
+
module Ragol
|
5
|
+
module HashUtil
|
6
|
+
def self.copy_hash to_hash, from_hash, fields = Array.new
|
7
|
+
fields.each do |fieldnames|
|
8
|
+
to_hash[fieldnames.first] = from_hash[fieldnames.find { |x| from_hash[x] }]
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.hash_array_value hash, array
|
13
|
+
hash[(array & hash.keys)[0]]
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
#!/usr/bin/ruby -w
|
2
|
+
# -*- ruby -*-
|
3
|
+
|
4
|
+
require 'logue/loggable'
|
5
|
+
|
6
|
+
module Ragol
|
7
|
+
class Matcher
|
8
|
+
include Logue::Loggable
|
9
|
+
|
10
|
+
attr_reader :elements
|
11
|
+
|
12
|
+
def initialize tags
|
13
|
+
@elements = [ tags ].flatten.compact
|
14
|
+
end
|
15
|
+
|
16
|
+
def find_match opt
|
17
|
+
tag = opt.split('=', 2)[0] || opt
|
18
|
+
|
19
|
+
@elements.each do |elmt|
|
20
|
+
if elmt.kind_of?(Regexp)
|
21
|
+
if md = elmt.match(tag)
|
22
|
+
return [ :regexp, md ]
|
23
|
+
end
|
24
|
+
elsif tag.length > elmt.length
|
25
|
+
next
|
26
|
+
elsif elmt.index(tag) == 0
|
27
|
+
score = tag.length == elmt.length ? 1.0 : tag.length * 0.01
|
28
|
+
return [ :string, score ]
|
29
|
+
end
|
30
|
+
end
|
31
|
+
nil
|
32
|
+
end
|
33
|
+
|
34
|
+
def match? opt
|
35
|
+
type, val = find_match(opt)
|
36
|
+
type && val
|
37
|
+
end
|
38
|
+
|
39
|
+
def score opt
|
40
|
+
type, val = find_match(opt)
|
41
|
+
type && (type == :regexp ? 1.0 : val)
|
42
|
+
end
|
43
|
+
|
44
|
+
def to_s
|
45
|
+
@elements.join(', ')
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
#!/usr/bin/ruby -w
|
2
|
+
# -*- ruby -*-
|
3
|
+
|
4
|
+
require 'logue/loggable'
|
5
|
+
require 'ragol/matcher'
|
6
|
+
|
7
|
+
module Ragol
|
8
|
+
class Matchers
|
9
|
+
include Logue::Loggable
|
10
|
+
|
11
|
+
attr_reader :tags
|
12
|
+
attr_reader :negatives
|
13
|
+
attr_reader :regexps
|
14
|
+
|
15
|
+
def initialize tags, negate, regexp
|
16
|
+
@tags = tags
|
17
|
+
@negatives = negate
|
18
|
+
@regexps = regexp
|
19
|
+
end
|
20
|
+
|
21
|
+
def tag_match? arg
|
22
|
+
@tags and @tags.match? arg
|
23
|
+
end
|
24
|
+
|
25
|
+
def negative_match? arg
|
26
|
+
@negatives and @negatives.match? arg
|
27
|
+
end
|
28
|
+
|
29
|
+
def regexp_match? arg
|
30
|
+
@regexps and @regexps.match? arg
|
31
|
+
end
|
32
|
+
|
33
|
+
def match_type? arg
|
34
|
+
case
|
35
|
+
when tm = tag_match?(arg)
|
36
|
+
[ :tag_match, tm ]
|
37
|
+
when nm = negative_match?(arg)
|
38
|
+
[ :negative_match, nm ]
|
39
|
+
when rm = regexp_match?(arg)
|
40
|
+
[ :regexp_match, rm ]
|
41
|
+
else
|
42
|
+
nil
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def name
|
47
|
+
@name ||= begin
|
48
|
+
if @tags
|
49
|
+
if longtag = @tags.elements.find { |t| t[0, 2] == '--' }
|
50
|
+
longtag.sub(%r{^--}, '')
|
51
|
+
else
|
52
|
+
@tags.elements[0][1 .. -1]
|
53
|
+
end
|
54
|
+
elsif @regexps
|
55
|
+
@regexps.elements[0].to_s
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def to_s
|
61
|
+
[ @tags, @regexps ].compact.collect { |x| x.to_s }.join(' ')
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
data/lib/ragol/option.rb
ADDED
@@ -0,0 +1,168 @@
|
|
1
|
+
#!/usr/bin/ruby -w
|
2
|
+
# -*- ruby -*-
|
3
|
+
|
4
|
+
require 'logue/loggable'
|
5
|
+
require 'ragol/matcher'
|
6
|
+
require 'ragol/matchers'
|
7
|
+
require 'ragol/doc'
|
8
|
+
|
9
|
+
module Ragol
|
10
|
+
class Option
|
11
|
+
include Logue::Loggable
|
12
|
+
|
13
|
+
attr_reader :matchers
|
14
|
+
|
15
|
+
attr_accessor :name
|
16
|
+
attr_accessor :default
|
17
|
+
attr_accessor :description
|
18
|
+
attr_accessor :tags
|
19
|
+
attr_accessor :negates
|
20
|
+
attr_accessor :regexps
|
21
|
+
|
22
|
+
def initialize options = Hash.new, &blk
|
23
|
+
@tags = nil
|
24
|
+
@negates = nil
|
25
|
+
@regexps = nil
|
26
|
+
@name = nil
|
27
|
+
@default = nil
|
28
|
+
@unsets = nil
|
29
|
+
@process = nil
|
30
|
+
@takesvalue = nil
|
31
|
+
@rcnames = nil
|
32
|
+
@description = nil
|
33
|
+
|
34
|
+
if blk
|
35
|
+
blk.call self
|
36
|
+
end
|
37
|
+
|
38
|
+
tagsmatch = to_matcher(@tags || options[:tags])
|
39
|
+
negatesmatch = to_matcher(@negates || options[:negates])
|
40
|
+
regexpsmatch = to_matcher(@regexps || options[:regexps])
|
41
|
+
|
42
|
+
@matchers = Ragol::Matchers.new tagsmatch, negatesmatch, regexpsmatch
|
43
|
+
|
44
|
+
@name ||= options[:name] || @matchers.name
|
45
|
+
|
46
|
+
@default ||= options[:default]
|
47
|
+
@unsets ||= options[:unsets]
|
48
|
+
@process ||= options[:process]
|
49
|
+
@takesvalue ||= options[:takesvalue]
|
50
|
+
@rcnames ||= [ options[:rcnames] ].flatten
|
51
|
+
@description ||= options[:description]
|
52
|
+
end
|
53
|
+
|
54
|
+
def match_rc? field
|
55
|
+
@rcnames.include?(field)
|
56
|
+
end
|
57
|
+
|
58
|
+
def to_matcher elements
|
59
|
+
elements && Ragol::Matcher.new(elements)
|
60
|
+
end
|
61
|
+
|
62
|
+
def takes_value?
|
63
|
+
@takesvalue
|
64
|
+
end
|
65
|
+
|
66
|
+
def post_process option_set, results, unprocessed
|
67
|
+
resolve_value option_set, results, unprocessed
|
68
|
+
|
69
|
+
if @unsets
|
70
|
+
option_set.unset results, @unsets
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def resolve_value option_set, results, unprocessed
|
75
|
+
end
|
76
|
+
|
77
|
+
def to_s
|
78
|
+
@matchers.to_s
|
79
|
+
end
|
80
|
+
|
81
|
+
def value_regexp
|
82
|
+
end
|
83
|
+
|
84
|
+
def convert md
|
85
|
+
md.kind_of?(MatchData) ? md[-1] : md
|
86
|
+
end
|
87
|
+
|
88
|
+
def do_match val
|
89
|
+
if valuere = value_regexp
|
90
|
+
unless md = valuere.match(val)
|
91
|
+
raise "invalid argument '#{val}' for option: #{self}"
|
92
|
+
end
|
93
|
+
md
|
94
|
+
else
|
95
|
+
val
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def take_eq_value opt
|
100
|
+
val = opt.split('=', 2)[1]
|
101
|
+
val && do_match(val)
|
102
|
+
end
|
103
|
+
|
104
|
+
def argument_missing
|
105
|
+
if takes_value? == true
|
106
|
+
raise "value expected for option: #{self}"
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def match_next_value_required results
|
111
|
+
val = results.shift_arg
|
112
|
+
val && do_match(val)
|
113
|
+
end
|
114
|
+
|
115
|
+
def match_next_value_optional results
|
116
|
+
return unless val = results.current_arg
|
117
|
+
return true if val[0] == '-'
|
118
|
+
return results.shift_arg unless valuere = value_regexp
|
119
|
+
|
120
|
+
if md = valuere.match(results.current_arg)
|
121
|
+
results.shift_arg
|
122
|
+
md
|
123
|
+
else
|
124
|
+
true
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
def match_next_value results
|
129
|
+
if takes_value? == true
|
130
|
+
match_next_value_required results
|
131
|
+
else
|
132
|
+
match_next_value_optional results
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
def set_value_for_tag results, arg
|
137
|
+
md = if takes_value?
|
138
|
+
take_eq_value(arg) || match_next_value(results) || argument_missing
|
139
|
+
else
|
140
|
+
true
|
141
|
+
end
|
142
|
+
set_option_value md, arg, results
|
143
|
+
end
|
144
|
+
|
145
|
+
def set_value_negative results, arg
|
146
|
+
set_option_value false, arg, results
|
147
|
+
end
|
148
|
+
|
149
|
+
def set_value_regexp results, arg
|
150
|
+
md = @matchers.regexp_match? arg
|
151
|
+
set_option_value md, arg, results
|
152
|
+
end
|
153
|
+
|
154
|
+
def set_option_value md, arg, results
|
155
|
+
value = md == true ? true : convert(md)
|
156
|
+
if @process
|
157
|
+
setargs = [ value, arg, results.unprocessed ][0 ... @process.arity]
|
158
|
+
@process.call(*setargs)
|
159
|
+
end
|
160
|
+
results.set_value name, value
|
161
|
+
end
|
162
|
+
|
163
|
+
def to_doc io
|
164
|
+
doc = Ragol::Doc.new self
|
165
|
+
doc.to_doc io
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
#!/usr/bin/ruby -w
|
2
|
+
# -*- ruby -*-
|
3
|
+
|
4
|
+
require 'ragol/optset'
|
5
|
+
|
6
|
+
module OptProc
|
7
|
+
class OptionSet < Ragol::OptionSet
|
8
|
+
include Logue::Loggable
|
9
|
+
|
10
|
+
def initialize data
|
11
|
+
super :data => data
|
12
|
+
end
|
13
|
+
|
14
|
+
# this is a legacy method; process should be used instead.
|
15
|
+
def process_option argslist
|
16
|
+
set_option argslist
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/lib/ragol/optset.rb
ADDED
@@ -0,0 +1,197 @@
|
|
1
|
+
#!/usr/bin/ruby -w
|
2
|
+
# -*- ruby -*-
|
3
|
+
|
4
|
+
require 'logue/loggable'
|
5
|
+
require 'ragol/results'
|
6
|
+
require 'ragol/exception'
|
7
|
+
require 'ragol/args'
|
8
|
+
|
9
|
+
module Ragol
|
10
|
+
class OptionSet
|
11
|
+
include Logue::Loggable
|
12
|
+
|
13
|
+
# maps from an OptionSet class to the valid options for that class.
|
14
|
+
@@options_for_class = Hash.new { |h, k| h[k] = Array.new }
|
15
|
+
|
16
|
+
def self.has_option optcls, optargs = Hash.new
|
17
|
+
@@options_for_class[self] << { :class => optcls, :args => optargs }
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.options_for_class cls
|
21
|
+
@@options_for_class[cls]
|
22
|
+
end
|
23
|
+
|
24
|
+
attr_reader :options
|
25
|
+
|
26
|
+
def initialize(*options)
|
27
|
+
# puts "options: #{options.inspect}"
|
28
|
+
if options[0] && options[0].kind_of?(Hash)
|
29
|
+
data = options[0][:data]
|
30
|
+
options = data.collect do |optdata|
|
31
|
+
optargs = OptionArguments.new(optdata)
|
32
|
+
|
33
|
+
opttype = optargs[:valuetype]
|
34
|
+
clstype = OptionArguments::VAR_TYPES[opttype]
|
35
|
+
|
36
|
+
if clstype
|
37
|
+
clsstr = clstype.to_s
|
38
|
+
require 'ragol/' + clsstr + '_option'
|
39
|
+
clssym = (clsstr.capitalize + 'Option').to_sym
|
40
|
+
optcls = ::Ragol.const_get(clssym)
|
41
|
+
optcls.new(optargs)
|
42
|
+
else
|
43
|
+
Ragol::Option.new(optargs)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
@options = options
|
49
|
+
|
50
|
+
cls = self.class
|
51
|
+
while cls <= OptionSet
|
52
|
+
opts = self.class.options_for_class(cls)
|
53
|
+
|
54
|
+
opts.each do |option|
|
55
|
+
args = option[:args]
|
56
|
+
opt = option[:class].new(*args)
|
57
|
+
|
58
|
+
add opt
|
59
|
+
end
|
60
|
+
|
61
|
+
cls = cls.superclass
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def name
|
66
|
+
@name ||= self.class.to_s.sub(%r{.*?(\w+)OptionSet}, '\1').downcase
|
67
|
+
end
|
68
|
+
|
69
|
+
def inspect
|
70
|
+
@options.collect { |opt| opt.inspect }.join("\n")
|
71
|
+
end
|
72
|
+
|
73
|
+
def find_by_name name
|
74
|
+
@options.find { |opt| opt.name == name }
|
75
|
+
end
|
76
|
+
|
77
|
+
def << option
|
78
|
+
add option
|
79
|
+
end
|
80
|
+
|
81
|
+
def add option
|
82
|
+
@options << option
|
83
|
+
option
|
84
|
+
end
|
85
|
+
|
86
|
+
def get_best_match results
|
87
|
+
tag_matches = Hash.new { |h, k| h[k] = Array.new }
|
88
|
+
negative_match = nil
|
89
|
+
regexp_match = nil
|
90
|
+
|
91
|
+
options.each do |opt|
|
92
|
+
if mt = opt.matchers.match_type?(results.current_arg)
|
93
|
+
case mt[0]
|
94
|
+
when :tag_match
|
95
|
+
tag_matches[mt[1]] << opt
|
96
|
+
when :negative_match
|
97
|
+
negative_match = opt
|
98
|
+
when :regexp_match
|
99
|
+
regexp_match = opt
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
if tag_matches.keys.any?
|
105
|
+
highest = tag_matches.keys.sort[-1]
|
106
|
+
opts = tag_matches[highest]
|
107
|
+
if opts.size > 1
|
108
|
+
optstr = opts.collect { |opt| '(' + opt.to_s + ')' }.join(', ')
|
109
|
+
raise "ambiguous match of '#{results.current_arg}'; matches options: #{optstr}"
|
110
|
+
end
|
111
|
+
[ :tag_match, opts.first ]
|
112
|
+
elsif negative_match
|
113
|
+
[ :negative_match, negative_match ]
|
114
|
+
elsif regexp_match
|
115
|
+
[ :regexp_match, regexp_match ]
|
116
|
+
else
|
117
|
+
nil
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def find_matching_option results
|
122
|
+
type, opt = get_best_match(results)
|
123
|
+
|
124
|
+
unless type
|
125
|
+
raise OptionException.new "#{name}: invalid option '#{results.current_arg}'"
|
126
|
+
end
|
127
|
+
|
128
|
+
[ type, opt ]
|
129
|
+
end
|
130
|
+
|
131
|
+
def set_option results
|
132
|
+
type, opt = find_matching_option(results)
|
133
|
+
|
134
|
+
case type
|
135
|
+
when :tag_match
|
136
|
+
arg = results.next_arg
|
137
|
+
opt.set_value_for_tag results, arg
|
138
|
+
when :negative_match
|
139
|
+
arg = results.next_arg
|
140
|
+
opt.set_value_negative results, arg
|
141
|
+
when :regexp_match
|
142
|
+
arg = results.next_arg
|
143
|
+
opt.set_value_regexp results, arg
|
144
|
+
end
|
145
|
+
|
146
|
+
opt
|
147
|
+
end
|
148
|
+
|
149
|
+
def process args, results = Ragol::Results.new(options, args)
|
150
|
+
options_processed = Array.new
|
151
|
+
|
152
|
+
while !results.args_empty?
|
153
|
+
if results.end_of_options?
|
154
|
+
results.shift_arg
|
155
|
+
break
|
156
|
+
elsif results.current_arg[0] != '-'
|
157
|
+
break
|
158
|
+
end
|
159
|
+
|
160
|
+
option = set_option(results)
|
161
|
+
if option
|
162
|
+
options_processed << option
|
163
|
+
else
|
164
|
+
break
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
options_processed.each do |opt|
|
169
|
+
opt.post_process self, results, results.args
|
170
|
+
end
|
171
|
+
|
172
|
+
results
|
173
|
+
end
|
174
|
+
|
175
|
+
def unset results, key
|
176
|
+
if opt = find_by_name(key)
|
177
|
+
results.unset_value opt.name
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
def read_rclines lines, results = Ragol::Results.new(options, nil)
|
182
|
+
options_processed = Array.new
|
183
|
+
|
184
|
+
lines.each do |line|
|
185
|
+
line.sub!(%r{\#.*}, '')
|
186
|
+
next if line.empty?
|
187
|
+
name, val = line.split(%r{\s*:\s*})
|
188
|
+
opt = @options.detect { |op| op.match_rc? name }
|
189
|
+
if opt
|
190
|
+
opt.set_option_value val, name, results
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
results
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
#!/usr/bin/ruby -w
|
2
|
+
# -*- ruby -*-
|
3
|
+
|
4
|
+
require 'logue/loggable'
|
5
|
+
require 'ragol/option'
|
6
|
+
require 'ragol/argslist'
|
7
|
+
|
8
|
+
module Ragol
|
9
|
+
class Results
|
10
|
+
include Logue::Loggable
|
11
|
+
|
12
|
+
attr_reader :options
|
13
|
+
|
14
|
+
def initialize options, args = Array.new
|
15
|
+
@argslist = Ragol::ArgsList.new(args)
|
16
|
+
@values = Hash.new
|
17
|
+
|
18
|
+
options.each do |option|
|
19
|
+
@values[option.name] = option.default
|
20
|
+
|
21
|
+
define_singleton_method option.name do
|
22
|
+
instance_eval do
|
23
|
+
@values[option.name]
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def value optname
|
30
|
+
@values[optname]
|
31
|
+
end
|
32
|
+
|
33
|
+
def set_value optname, value
|
34
|
+
@values[optname] = value
|
35
|
+
end
|
36
|
+
|
37
|
+
def unset_value optname
|
38
|
+
@values.delete optname
|
39
|
+
end
|
40
|
+
|
41
|
+
def unprocessed
|
42
|
+
@argslist
|
43
|
+
end
|
44
|
+
|
45
|
+
def end_of_options?
|
46
|
+
@argslist.end_of_options?
|
47
|
+
end
|
48
|
+
|
49
|
+
def args
|
50
|
+
@argslist.args
|
51
|
+
end
|
52
|
+
|
53
|
+
def next_arg
|
54
|
+
@argslist.next_arg
|
55
|
+
end
|
56
|
+
|
57
|
+
def shift_arg
|
58
|
+
@argslist.shift_arg
|
59
|
+
end
|
60
|
+
|
61
|
+
def args_empty?
|
62
|
+
@argslist.args_empty?
|
63
|
+
end
|
64
|
+
|
65
|
+
def current_arg
|
66
|
+
@argslist.current_arg
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
#!/usr/bin/ruby -w
|
2
|
+
# -*- ruby -*-
|
3
|
+
|
4
|
+
module Synoption
|
5
|
+
class OptionArguments < Hash
|
6
|
+
def initialize name, tag, description, default, origargs
|
7
|
+
super()
|
8
|
+
|
9
|
+
merge! origargs.dup
|
10
|
+
|
11
|
+
takesvalue = if origargs.has_key?(:takesvalue)
|
12
|
+
origargs[:takesvalue]
|
13
|
+
else
|
14
|
+
true
|
15
|
+
end
|
16
|
+
|
17
|
+
self[:takesvalue] = takesvalue
|
18
|
+
self[:regexps] ||= origargs[:regexp]
|
19
|
+
self[:negates] ||= origargs[:negate]
|
20
|
+
self[:tags] = [ tag, '--' + name.to_s.gsub('_', '-') ]
|
21
|
+
self[:description] = description
|
22
|
+
self[:name] = name
|
23
|
+
self[:default] = default
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
#!/usr/bin/ruby -w
|
2
|
+
# -*- ruby -*-
|
3
|
+
|
4
|
+
require 'ragol/boolean_option'
|
5
|
+
require 'ragol/synoption/option'
|
6
|
+
|
7
|
+
module Synoption
|
8
|
+
# a boolean option maps to a single tag, not a tag and value. For example,
|
9
|
+
# "-v" (verbose) is a boolean option, but "-r 3444" (revision) is a option
|
10
|
+
# with a value.
|
11
|
+
class BooleanOption < Ragol::Option
|
12
|
+
include OptionInit
|
13
|
+
|
14
|
+
def default_value
|
15
|
+
false
|
16
|
+
end
|
17
|
+
|
18
|
+
def takes_value?
|
19
|
+
false
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
#!/usr/bin/ruby -w
|
2
|
+
# -*- ruby -*-
|
3
|
+
|
4
|
+
require 'ragol/fixnum_option'
|
5
|
+
require 'ragol/synoption/option'
|
6
|
+
|
7
|
+
module Synoption
|
8
|
+
# An option that has a fixnum (integer) as its value.
|
9
|
+
class FixnumOption < Ragol::FixnumOption
|
10
|
+
include Synoption::OptionInit
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
#!/usr/bin/ruby -w
|
2
|
+
# -*- ruby -*-
|
3
|
+
|
4
|
+
require 'ragol/option'
|
5
|
+
require 'ragol/synoption/args'
|
6
|
+
|
7
|
+
module Synoption
|
8
|
+
module OptionInit
|
9
|
+
def initialize(*args, &blk)
|
10
|
+
name, tag, description, deflt, options = *args
|
11
|
+
options ||= Hash.new
|
12
|
+
deflt ||= default_value
|
13
|
+
args = OptionArguments.new name, tag, description, deflt, options
|
14
|
+
super args, &blk
|
15
|
+
end
|
16
|
+
|
17
|
+
def default_value
|
18
|
+
nil
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
module Synoption
|
24
|
+
class Option < Ragol::Option
|
25
|
+
include OptionInit
|
26
|
+
end
|
27
|
+
end
|
metadata
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ragol
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.3
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Jeff Pace
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-05-05 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: logue
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 0.0.1
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 0.0.1
|
30
|
+
description: Another implementation of an option processor.
|
31
|
+
email: jeugenepace@gmail.com
|
32
|
+
executables: []
|
33
|
+
extensions: []
|
34
|
+
extra_rdoc_files: []
|
35
|
+
files:
|
36
|
+
- lib/ragol/args.rb
|
37
|
+
- lib/ragol/argslist.rb
|
38
|
+
- lib/ragol/boolean_option.rb
|
39
|
+
- lib/ragol/doc.rb
|
40
|
+
- lib/ragol/exception.rb
|
41
|
+
- lib/ragol/fixnum_option.rb
|
42
|
+
- lib/ragol/float_option.rb
|
43
|
+
- lib/ragol/hash.rb
|
44
|
+
- lib/ragol/matcher.rb
|
45
|
+
- lib/ragol/matchers.rb
|
46
|
+
- lib/ragol/option.rb
|
47
|
+
- lib/ragol/optproc/optproc.rb
|
48
|
+
- lib/ragol/optproc/optset.rb
|
49
|
+
- lib/ragol/optset.rb
|
50
|
+
- lib/ragol/regexp_option.rb
|
51
|
+
- lib/ragol/results.rb
|
52
|
+
- lib/ragol/string_option.rb
|
53
|
+
- lib/ragol/synoption/args.rb
|
54
|
+
- lib/ragol/synoption/boolean_option.rb
|
55
|
+
- lib/ragol/synoption/fixnum_option.rb
|
56
|
+
- lib/ragol/synoption/float_option.rb
|
57
|
+
- lib/ragol/synoption/option.rb
|
58
|
+
- lib/ragol/synoption/optset.rb
|
59
|
+
homepage: http://github.com/jpace/ragol
|
60
|
+
licenses: []
|
61
|
+
post_install_message:
|
62
|
+
rdoc_options: []
|
63
|
+
require_paths:
|
64
|
+
- lib
|
65
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
66
|
+
none: false
|
67
|
+
requirements:
|
68
|
+
- - ! '>='
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: '0'
|
71
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
72
|
+
none: false
|
73
|
+
requirements:
|
74
|
+
- - ! '>='
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0'
|
77
|
+
requirements: []
|
78
|
+
rubyforge_project:
|
79
|
+
rubygems_version: 1.8.23
|
80
|
+
signing_key:
|
81
|
+
specification_version: 3
|
82
|
+
summary: ! 'Ragol: Another GetOpt Library.'
|
83
|
+
test_files: []
|