Cmdline_Parser 0.1.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/README.txt +13 -0
- data/cmdlineparser.rb +3 -0
- data/lib/cmdline_parser.rb +190 -0
- data/test/test_cmdline.rb +51 -0
- data/test/test_cmdline_parser.rb +50 -0
- metadata +57 -0
data/README.txt
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
Cmdline Parser
|
2
|
+
______________
|
3
|
+
|
4
|
+
I intended to design the command line parser to be embedded into my application.
|
5
|
+
However, since more and more project of mine include this as library, i decided to separate it out as gem so that
|
6
|
+
i can share it with all my project instead. After all, if i update in one place, all my project received the update.
|
7
|
+
|
8
|
+
Please sent me comment of your usage of the library! I would love to hear that!
|
9
|
+
|
10
|
+
Author : Chris Liaw
|
11
|
+
Copyright : Chris Liaw
|
12
|
+
License : GNU GPL
|
13
|
+
|
data/cmdlineparser.rb
ADDED
@@ -0,0 +1,190 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
class CmdlineParser
|
4
|
+
attr_accessor :choices, :params
|
5
|
+
|
6
|
+
VERSION = "0.1.0"
|
7
|
+
|
8
|
+
def initialize(opt = {})
|
9
|
+
@choices = []
|
10
|
+
@short_map = {}
|
11
|
+
@long_map = {}
|
12
|
+
@params = []
|
13
|
+
@mandatory_choice = {}
|
14
|
+
@search = {}
|
15
|
+
@error_as_message = opt[:error_as_message]
|
16
|
+
@error_as_message ||= false
|
17
|
+
end
|
18
|
+
|
19
|
+
def choice(name)
|
20
|
+
opt = Opt.new
|
21
|
+
opt.name = name
|
22
|
+
yield opt
|
23
|
+
@choices << opt
|
24
|
+
@search[opt.name] = opt
|
25
|
+
end
|
26
|
+
|
27
|
+
def parse_array(argv)
|
28
|
+
prepare_index
|
29
|
+
ignore_value = []
|
30
|
+
0.upto(argv.length-1) do |i|
|
31
|
+
token = argv[i].strip
|
32
|
+
if @short_map.keys.include? token
|
33
|
+
opt = @short_map[token]
|
34
|
+
opt.activated = true
|
35
|
+
if opt.has_value == true
|
36
|
+
tmpVal = argv[i+1]
|
37
|
+
if is_command(tmpVal)
|
38
|
+
if @error_as_message
|
39
|
+
STDERR.puts "Argument needed for flag #{token}"
|
40
|
+
else
|
41
|
+
raise MissingArgumentException, "Argument needed for flag #{token}"
|
42
|
+
end
|
43
|
+
else
|
44
|
+
if tmpVal != nil
|
45
|
+
opt.value = tmpVal
|
46
|
+
ignore_value << tmpVal
|
47
|
+
else
|
48
|
+
if @error_as_message
|
49
|
+
STDERR.puts "Argument needed for flag #{token}"
|
50
|
+
else
|
51
|
+
raise MissingArgumentException, "Argument needed for flag #{token}"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
if @mandatory_choice.keys.include? opt.name
|
58
|
+
@mandatory_choice.delete(opt.name)
|
59
|
+
end
|
60
|
+
|
61
|
+
elsif @long_map.keys.include? token
|
62
|
+
opt = @long_map[token]
|
63
|
+
opt.activated = true
|
64
|
+
if opt.has_value == true
|
65
|
+
tmpVal = argv[i+1]
|
66
|
+
if is_command(tmpVal)
|
67
|
+
if @error_as_message
|
68
|
+
STDERR.puts "Argument needed for flag #{token}"
|
69
|
+
else
|
70
|
+
raise MissingArgumentException, "Argument needed for flag #{token}"
|
71
|
+
end
|
72
|
+
else
|
73
|
+
if tmpVal != nil
|
74
|
+
opt.value = tmpVal
|
75
|
+
ignore_value << tmpVal
|
76
|
+
else
|
77
|
+
if @error_as_message
|
78
|
+
STDERR.puts "Argument needed for flag #{token}"
|
79
|
+
else
|
80
|
+
raise MissingArgumentException, "Argument needed for flag #{token}"
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
if @mandatory_choice.keys.include? opt.name
|
87
|
+
@mandatory_choice.delete(opt.name)
|
88
|
+
end
|
89
|
+
|
90
|
+
else
|
91
|
+
if not ignore_value.include? token
|
92
|
+
@params << token
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
if @mandatory_choice.length > 0
|
98
|
+
msg = []
|
99
|
+
@mandatory_choice.values.each do |ch|
|
100
|
+
msg << "#{ch.short} or #{ch.long}"
|
101
|
+
end
|
102
|
+
|
103
|
+
if @error_as_message
|
104
|
+
STDERR.puts "Error : Flag #{msg.join(",")} is required for this command"
|
105
|
+
else
|
106
|
+
raise MissingArgumentException,"Flag #{msg.join(",")} is required for this command"
|
107
|
+
end
|
108
|
+
|
109
|
+
end
|
110
|
+
|
111
|
+
end
|
112
|
+
|
113
|
+
def show_help
|
114
|
+
STDOUT.puts ""
|
115
|
+
STDOUT.puts "Ruby Cmdline Parser version #{CmdlineParser::VERSION}"
|
116
|
+
STDOUT.puts ""
|
117
|
+
STDOUT.puts " Available commands:"
|
118
|
+
# STDOUT.puts ""
|
119
|
+
@choices.each do |c|
|
120
|
+
STDOUT.print "%5s or %-12s" % [c.short, c.long]
|
121
|
+
if c.has_value
|
122
|
+
STDOUT.print "<param> "
|
123
|
+
else
|
124
|
+
STDOUT.print " "
|
125
|
+
end
|
126
|
+
|
127
|
+
if c.mandatory
|
128
|
+
STDOUT.print "[Required] "
|
129
|
+
else
|
130
|
+
STDOUT.print " "
|
131
|
+
end
|
132
|
+
STDOUT.puts c.desc
|
133
|
+
end
|
134
|
+
STDOUT.puts ""
|
135
|
+
|
136
|
+
end
|
137
|
+
|
138
|
+
private
|
139
|
+
def is_command(token)
|
140
|
+
if token != nil
|
141
|
+
token[0].chr == "-" || token[0..1] == "--"
|
142
|
+
else
|
143
|
+
false
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
def prepare_index
|
148
|
+
@choices.each do |ch|
|
149
|
+
@short_map[ch.short] = ch
|
150
|
+
@long_map[ch.long] = ch
|
151
|
+
if ch.mandatory == true
|
152
|
+
@mandatory_choice[ch.name] = ch
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
alias :old_method_missing :method_missing
|
158
|
+
def method_missing(arg)
|
159
|
+
if @search[arg] != nil
|
160
|
+
return @search[arg].to_s
|
161
|
+
end
|
162
|
+
|
163
|
+
if arg.to_s()[arg.to_s.length-4..-1] == "_obj"
|
164
|
+
key = arg.to_s()[0...-4]
|
165
|
+
if @search[key.to_sym] != nil
|
166
|
+
return @search[key.to_sym]
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
old_method_missing(arg)
|
171
|
+
#puts "method missing! #{arg}"
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
class Opt
|
176
|
+
attr_accessor :name, :short, :long, :desc, :mandatory, :default, :value, :has_value, :activated
|
177
|
+
def initialize
|
178
|
+
@mandatory = false
|
179
|
+
@has_value = false
|
180
|
+
@activated = false
|
181
|
+
end
|
182
|
+
|
183
|
+
def to_s
|
184
|
+
value
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
class MissingArgumentException < Exception
|
189
|
+
|
190
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
|
2
|
+
if __FILE__ == $0
|
3
|
+
require '../lib/cmdline_parser'
|
4
|
+
|
5
|
+
parser = CmdlineParser.new
|
6
|
+
parser.choice :first do |opt|
|
7
|
+
opt.short = "-f"
|
8
|
+
opt.long = "--first"
|
9
|
+
opt.has_value = true
|
10
|
+
opt.mandatory = true
|
11
|
+
opt.desc = "First param"
|
12
|
+
end
|
13
|
+
|
14
|
+
parser.choice :second do |opt|
|
15
|
+
opt.short = "-s"
|
16
|
+
opt.long = "--second"
|
17
|
+
opt.desc = "Second param"
|
18
|
+
end
|
19
|
+
|
20
|
+
parser.choice :third do |opt|
|
21
|
+
opt.short = "-t"
|
22
|
+
opt.long = "--third"
|
23
|
+
opt.desc = "Third param"
|
24
|
+
opt.has_value = true
|
25
|
+
end
|
26
|
+
|
27
|
+
begin
|
28
|
+
parser.parse_array(ARGV)
|
29
|
+
rescue MissingArgumentException => ex
|
30
|
+
STDERR.puts "Error : #{ex.message}"
|
31
|
+
parser.show_help
|
32
|
+
exit(1)
|
33
|
+
end
|
34
|
+
|
35
|
+
parser.choices.each do |c|
|
36
|
+
if c.activated
|
37
|
+
STDOUT.print "Flag '#{c.name}' activated by user"
|
38
|
+
else
|
39
|
+
STDOUT.print "Flag '#{c.name}' not activated by user"
|
40
|
+
end
|
41
|
+
|
42
|
+
if c.value
|
43
|
+
STDOUT.puts " with value '#{c.value}'"
|
44
|
+
else
|
45
|
+
STDOUT.puts ""
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
STDOUT.puts "Extra parameter for command : #{parser.params.join(" , ")}"
|
50
|
+
|
51
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
|
2
|
+
require '../lib/cmdline_parser'
|
3
|
+
require 'test/unit'
|
4
|
+
|
5
|
+
class TestCmdlineParser < Test::Unit::TestCase
|
6
|
+
def test_output
|
7
|
+
list = ["-f","/media/share/testing.txt","--revision","10", "--mandatory","extra_parameter"]
|
8
|
+
parser = CmdlineParser.new
|
9
|
+
parser.choice :file do |opt|
|
10
|
+
opt.short = "-f"
|
11
|
+
opt.long = "--file"
|
12
|
+
opt.has_value = true
|
13
|
+
opt.desc = "File parameter"
|
14
|
+
end
|
15
|
+
|
16
|
+
parser.choice :revision do |opt|
|
17
|
+
opt.short = "-r"
|
18
|
+
opt.long = "--revision"
|
19
|
+
opt.desc = "Particular revision"
|
20
|
+
opt.has_value = true
|
21
|
+
end
|
22
|
+
|
23
|
+
parser.choice :mand do |opt|
|
24
|
+
opt.short = "-m"
|
25
|
+
opt.long = "--mandatory"
|
26
|
+
opt.desc = "Mandatory field!"
|
27
|
+
opt.mandatory = true
|
28
|
+
end
|
29
|
+
|
30
|
+
parser.choice :ignore do |opt|
|
31
|
+
opt.short = "-i"
|
32
|
+
opt.long = "--ignore"
|
33
|
+
opt.desc = "meant to be ignore!"
|
34
|
+
end
|
35
|
+
|
36
|
+
parser.parse_array(list)
|
37
|
+
|
38
|
+
assert_equal(parser.file,list[1])
|
39
|
+
assert_equal(parser.file_obj.activated,true)
|
40
|
+
|
41
|
+
assert_equal(parser.revision,list[3])
|
42
|
+
assert_equal(parser.revision_obj.activated,true)
|
43
|
+
|
44
|
+
assert_equal(parser.mand_obj.activated,true)
|
45
|
+
|
46
|
+
assert_equal(parser.ignore_obj.activated,false)
|
47
|
+
|
48
|
+
assert_equal(parser.params,[list[5]])
|
49
|
+
end
|
50
|
+
end
|
metadata
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
3
|
+
requirements:
|
4
|
+
- - '>='
|
5
|
+
- !ruby/object:Gem::Version
|
6
|
+
version: "0"
|
7
|
+
version:
|
8
|
+
email: omikron.tech@gmail.com
|
9
|
+
cert_chain: []
|
10
|
+
|
11
|
+
summary: Another Ruby command line parser, intended to be embedded into application.
|
12
|
+
post_install_message:
|
13
|
+
extra_rdoc_files:
|
14
|
+
- README.txt
|
15
|
+
homepage:
|
16
|
+
signing_key:
|
17
|
+
name: Cmdline_Parser
|
18
|
+
rdoc_options: []
|
19
|
+
|
20
|
+
autorequire: cmdlineparser.rb
|
21
|
+
rubyforge_project:
|
22
|
+
executables: []
|
23
|
+
|
24
|
+
description:
|
25
|
+
specification_version: 2
|
26
|
+
default_executable:
|
27
|
+
files:
|
28
|
+
- README.txt
|
29
|
+
- cmdlineparser.rb
|
30
|
+
- lib/cmdline_parser.rb
|
31
|
+
- test/test_cmdline_parser.rb
|
32
|
+
- test/test_cmdline.rb
|
33
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
34
|
+
requirements:
|
35
|
+
- - '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: "0"
|
38
|
+
version:
|
39
|
+
extensions: []
|
40
|
+
|
41
|
+
rubygems_version: 1.3.1
|
42
|
+
requirements: []
|
43
|
+
|
44
|
+
authors:
|
45
|
+
- Chris Liaw Man Cheon
|
46
|
+
date: 2009-08-17 16:00:00 +00:00
|
47
|
+
platform: ruby
|
48
|
+
test_files: []
|
49
|
+
|
50
|
+
version: !ruby/object:Gem::Version
|
51
|
+
version: 0.1.0
|
52
|
+
require_paths:
|
53
|
+
- .
|
54
|
+
dependencies: []
|
55
|
+
|
56
|
+
bindir: bin
|
57
|
+
has_rdoc: false
|