facets 2.0.5 → 2.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/WHATSNEW +11 -0
- data/lib/core/facets/enumerable/collect.rb +7 -2
- data/lib/core/facets/enumerable/permutation.rb +7 -26
- data/lib/core/facets/module/alias.rb +36 -12
- data/lib/core/facets/module/attr.rb +83 -35
- data/lib/core/facets/module/include.rb +10 -0
- data/lib/methods/facets/module/alias_accessor.rb +1 -1
- data/lib/methods/facets/module/alias_reader.rb +1 -0
- data/lib/methods/facets/module/alias_setter.rb +1 -0
- data/lib/methods/facets/module/alias_switcher.rb +1 -0
- data/lib/methods/facets/module/alias_tester.rb +1 -0
- data/lib/methods/facets/module/alias_toggler.rb +1 -0
- data/lib/methods/facets/module/alias_validator.rb +1 -0
- data/lib/methods/facets/module/alias_writer.rb +1 -0
- data/lib/methods/facets/module/attr_accessor.rb +1 -0
- data/lib/methods/facets/module/attr_reader.rb +1 -0
- data/lib/methods/facets/module/attr_switcher.rb +1 -0
- data/lib/methods/facets/module/attr_writer.rb +1 -0
- data/lib/more/facets/arguments.rb +2 -1
- data/lib/more/facets/command.rb +258 -395
- data/lib/more/facets/crypt.rb +242 -28
- data/lib/more/facets/ziputils.rb +1 -1
- data/log/changelog.txt +0 -0
- data/log/history.txt +22 -0
- data/log/release.txt +10 -0
- data/log/todo.txt +4 -0
- data/meta/{facets-2.0.5.roll → facets-2.1.0.roll} +0 -0
- data/meta/google_ad.html +15 -0
- data/meta/icli.yaml +3 -3
- data/meta/manifest.txt +24 -3
- data/task/clobber/package +10 -0
- data/task/config/general.yaml +21 -3
- data/task/isotest +2 -1
- data/task/loadtest +2 -0
- data/task/prepare +4 -2
- data/task/rdoc +122 -73
- data/task/release +12 -0
- data/task/special/quickopts +15 -0
- data/task/syntax +2 -0
- data/task/test +3 -1
- data/test/unit/enumerable/test_collect.rb +17 -0
- data/test/unit/enumerable/test_permutation.rb +20 -30
- data/test/unit/test_crypt.rb +29 -36
- metadata +40 -12
- data/RELEASE +0 -12
- data/test/unit/test_command.rb +0 -286
data/WHATSNEW
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
Facets 2.1.0 is in the wild!
|
2
|
+
|
3
|
+
Major changes include a new and much-improved
|
4
|
+
command.rb, a new BiCrypt class for simple two-way
|
5
|
+
crypotgraphy, as well as attr_reader!, attr_writer!
|
6
|
+
and attr_accessor! for flag attributes, plus
|
7
|
+
alias_xxx methods for all attr_xxx methods.
|
8
|
+
|
9
|
+
Enjoy!
|
10
|
+
|
11
|
+
http://facets.rubyforge.org
|
@@ -113,6 +113,12 @@ module Enumerable
|
|
113
113
|
end
|
114
114
|
end
|
115
115
|
|
116
|
+
# TODO Faster implementation? Verify equivalency.
|
117
|
+
#def injecting(res, &block)
|
118
|
+
# ([res]*length).zip(to_a).each(&block)
|
119
|
+
# res
|
120
|
+
#end
|
121
|
+
|
116
122
|
# The #group_by method is best explained by example.
|
117
123
|
#
|
118
124
|
# (1..5).partition_by { |n| n % 3 }
|
@@ -150,8 +156,7 @@ module Enumerable
|
|
150
156
|
# CREDIT Erik Veenstra
|
151
157
|
|
152
158
|
def cluster_by(&b)
|
153
|
-
#group_by(&b).values
|
154
|
-
group_by(&b).sort.transpose.pop
|
159
|
+
group_by(&b).sort.transpose.pop || [] # group_by(&b).values ?
|
155
160
|
end
|
156
161
|
|
157
162
|
# Split on matching pattern.
|
@@ -6,7 +6,6 @@
|
|
6
6
|
#
|
7
7
|
# AUTHORS:
|
8
8
|
# - Florian Gross
|
9
|
-
# - Thomas Sawyer
|
10
9
|
|
11
10
|
require 'facets/integer/factorial'
|
12
11
|
|
@@ -17,6 +16,8 @@ module Enumerable
|
|
17
16
|
# Each is index by a permutation number. The maximum number of
|
18
17
|
# arrangements is the factorial of the size of the array.
|
19
18
|
#
|
19
|
+
# CREDIT Florian Gross
|
20
|
+
|
20
21
|
def permutation(number)
|
21
22
|
arr = to_a
|
22
23
|
out = arr[0..0]
|
@@ -34,7 +35,10 @@ module Enumerable
|
|
34
35
|
end
|
35
36
|
alias :permute :permutation
|
36
37
|
|
38
|
+
# Calculate permutation number.
|
37
39
|
#
|
40
|
+
# CREDIT Florian Gross
|
41
|
+
|
38
42
|
def permutation_number(original_array=self.to_a.sort)
|
39
43
|
arr = to_a
|
40
44
|
m = 1
|
@@ -62,6 +66,8 @@ module Enumerable
|
|
62
66
|
# cab
|
63
67
|
# cba
|
64
68
|
#
|
69
|
+
# CREDIT Florian Gross
|
70
|
+
|
65
71
|
def each_permutation()
|
66
72
|
arr = to_a
|
67
73
|
size = arr.size
|
@@ -98,28 +104,3 @@ module Enumerable
|
|
98
104
|
#++
|
99
105
|
|
100
106
|
end
|
101
|
-
|
102
|
-
|
103
|
-
# _____ _
|
104
|
-
# |_ _|__ ___| |_
|
105
|
-
# | |/ _ \/ __| __|
|
106
|
-
# | | __/\__ \ |_
|
107
|
-
# |_|\___||___/\__|
|
108
|
-
#
|
109
|
-
=begin test
|
110
|
-
|
111
|
-
require 'test/unit'
|
112
|
-
require 'set'
|
113
|
-
|
114
|
-
class TestEnumerablePermutation < Test::Unit::TestCase
|
115
|
-
|
116
|
-
def test_permutation
|
117
|
-
o = Set.new
|
118
|
-
%w[a b c].each_permutation { |x| o << x.join('') }
|
119
|
-
r = Set.new(['abc','acb','bac','bca','cab','cba'])
|
120
|
-
assert_equal( r, o )
|
121
|
-
end
|
122
|
-
|
123
|
-
end
|
124
|
-
|
125
|
-
=end
|
@@ -23,15 +23,6 @@ class Module
|
|
23
23
|
|
24
24
|
private
|
25
25
|
|
26
|
-
# Like module_funtion but makes the instance method
|
27
|
-
# public rather than private. This can not work
|
28
|
-
# as a sectional modifier however.
|
29
|
-
|
30
|
-
def module_method *meth
|
31
|
-
module_function *meth
|
32
|
-
public *meth
|
33
|
-
end
|
34
|
-
|
35
26
|
# As with alias_method, but alias both reader and writer.
|
36
27
|
#
|
37
28
|
# attr_accessor :x
|
@@ -41,9 +32,42 @@ class Module
|
|
41
32
|
# self.y = 2
|
42
33
|
# x #=> 2
|
43
34
|
|
44
|
-
def alias_accessor(
|
45
|
-
|
46
|
-
|
35
|
+
def alias_accessor(*args)
|
36
|
+
orig = args.last
|
37
|
+
args = args - [orig]
|
38
|
+
args.each do |name|
|
39
|
+
alias_method(name, orig)
|
40
|
+
alias_method("#{name}=", "#{orig}=")
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# As with alias_accessor, but just for the reader.
|
45
|
+
|
46
|
+
def alias_reader(*args)
|
47
|
+
orig = args.last
|
48
|
+
args = args - [orig]
|
49
|
+
args.each do |name|
|
50
|
+
alias_method(name, orig)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# As with alias_method but does the writer instead.
|
55
|
+
|
56
|
+
def alias_writer(*args)
|
57
|
+
orig = args.last
|
58
|
+
args = args - [orig]
|
59
|
+
args.each do |name|
|
60
|
+
alias_method("#{name}=", "#{orig}=")
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# Like module_funtion but makes the instance method
|
65
|
+
# public rather than private. This can not work
|
66
|
+
# as a sectional modifier however.
|
67
|
+
|
68
|
+
def module_method *meth
|
69
|
+
module_function *meth
|
70
|
+
public *meth
|
47
71
|
end
|
48
72
|
|
49
73
|
# Alias a module function so that the alias is also
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# TITLE:
|
2
2
|
#
|
3
|
-
# Attributes Methods
|
3
|
+
# Extra Attributes Methods
|
4
4
|
#
|
5
5
|
# SUMMARY:
|
6
6
|
#
|
@@ -9,9 +9,6 @@
|
|
9
9
|
# AUTHORS:
|
10
10
|
#
|
11
11
|
# - Thomas Sawyer
|
12
|
-
#
|
13
|
-
# TODO:
|
14
|
-
# - Need better name for attr_toggler, since it's not realy a "toggle".
|
15
12
|
|
16
13
|
#
|
17
14
|
class Module
|
@@ -30,7 +27,16 @@ class Module
|
|
30
27
|
end
|
31
28
|
made << "#{symbol}=".to_sym
|
32
29
|
end
|
33
|
-
|
30
|
+
made
|
31
|
+
end
|
32
|
+
|
33
|
+
def alias_validator(*args)
|
34
|
+
orig = args.last
|
35
|
+
args = args - [orig]
|
36
|
+
args.each do |name|
|
37
|
+
alias_method(name, orig)
|
38
|
+
alias_method("#{name}=", "#{orig}=")
|
39
|
+
end
|
34
40
|
end
|
35
41
|
|
36
42
|
# TODO Perhaps need to make a check against overriding annotated version.
|
@@ -62,31 +68,62 @@ class Module
|
|
62
68
|
made << "#{a}".to_sym
|
63
69
|
end
|
64
70
|
module_eval code
|
65
|
-
|
71
|
+
made
|
72
|
+
end
|
73
|
+
|
74
|
+
def alias_setter(*args)
|
75
|
+
args = args - [orig]
|
76
|
+
args.each do |name|
|
77
|
+
alias_method(name, orig)
|
78
|
+
end
|
66
79
|
end
|
67
80
|
|
68
|
-
# Create
|
69
|
-
# each given
|
70
|
-
#
|
81
|
+
# Create a toggle attribute. This creates two methods for
|
82
|
+
# each given name. One is a form of tester and the other
|
83
|
+
# is used to toggle the value.
|
71
84
|
#
|
72
|
-
#
|
85
|
+
# attr_accessor! :a
|
73
86
|
#
|
74
87
|
# is equivalent to
|
75
88
|
#
|
76
89
|
# def a?
|
77
|
-
# @a
|
90
|
+
# @a
|
78
91
|
# end
|
79
92
|
#
|
80
|
-
# def a!(
|
81
|
-
#
|
82
|
-
#
|
83
|
-
#
|
84
|
-
|
85
|
-
|
86
|
-
|
93
|
+
# def a!(value=true)
|
94
|
+
# @a = value
|
95
|
+
# self
|
96
|
+
# end
|
97
|
+
|
98
|
+
def attr_accessor!(*args)
|
99
|
+
attr_reader!(*args) + attr_writer!(*args)
|
100
|
+
end
|
101
|
+
alias_method :attr_switcher, :attr_accessor!
|
102
|
+
alias_method :attr_toggler, :attr_accessor!
|
103
|
+
|
104
|
+
def alias_accessor!(*args)
|
105
|
+
orig = args.last
|
106
|
+
args = args - [orig]
|
107
|
+
args.each do |name|
|
108
|
+
alias_method("#{name}?", "#{orig}?")
|
109
|
+
alias_method("#{name}!", "#{orig}!")
|
110
|
+
end
|
111
|
+
end
|
112
|
+
alias_method :alias_switcher, :alias_accessor!
|
113
|
+
alias_method :alias_toggler, :alias_accessor!
|
114
|
+
|
115
|
+
# Create an tester attribute. This creates a single methods
|
116
|
+
# used to test the attribute for truth.
|
117
|
+
#
|
118
|
+
# attr_reader! :a
|
119
|
+
#
|
120
|
+
# is equivalent to
|
121
|
+
#
|
122
|
+
# def a?
|
123
|
+
# @a ? true : @a
|
87
124
|
# end
|
88
125
|
|
89
|
-
def
|
126
|
+
def attr_reader!(*args)
|
90
127
|
code, made = '', []
|
91
128
|
args.each do |a|
|
92
129
|
code << %{
|
@@ -97,43 +134,54 @@ class Module
|
|
97
134
|
made << "#{a}?".to_sym
|
98
135
|
end
|
99
136
|
module_eval code
|
100
|
-
|
137
|
+
made
|
101
138
|
end
|
139
|
+
alias_method :attr_reader?, :attr_reader!
|
140
|
+
alias_method :attr_tester, :attr_reader!
|
102
141
|
|
103
|
-
|
104
|
-
|
105
|
-
|
142
|
+
def alias_reader!(*args)
|
143
|
+
orig = args.last
|
144
|
+
args = args - [orig]
|
145
|
+
args.each do |name|
|
146
|
+
alias_method("#{name}?", "#{orig}?")
|
147
|
+
end
|
148
|
+
end
|
149
|
+
alias_method :alias_reader?, :alias_reader!
|
150
|
+
alias_method :alias_tester, :alias_reader!
|
151
|
+
|
152
|
+
# Create a flaggable attribute. This creates a single methods
|
153
|
+
# used to set an attribute to "true".
|
106
154
|
#
|
107
|
-
#
|
155
|
+
# attr_writer! :a
|
108
156
|
#
|
109
157
|
# is equivalent to
|
110
158
|
#
|
111
|
-
# def a?
|
112
|
-
# @a
|
113
|
-
# end
|
114
|
-
#
|
115
159
|
# def a!(value=true)
|
116
160
|
# @a = value
|
117
161
|
# self
|
118
162
|
# end
|
119
163
|
|
120
|
-
def
|
164
|
+
def attr_writer!(*args)
|
121
165
|
code, made = '', []
|
122
166
|
args.each do |a|
|
123
167
|
code << %{
|
124
168
|
def #{a}!(value=true)
|
125
|
-
|
169
|
+
@#{a} = value
|
126
170
|
self
|
127
171
|
end
|
128
|
-
def #{a}?
|
129
|
-
@#{a}
|
130
|
-
end
|
131
172
|
}
|
132
173
|
made << "#{a}!".to_sym
|
133
|
-
made << "#{a}?".to_sym
|
134
174
|
end
|
135
175
|
module_eval code
|
136
|
-
|
176
|
+
made
|
177
|
+
end
|
178
|
+
|
179
|
+
def alias_writer!(*args)
|
180
|
+
orig = args.last
|
181
|
+
args = args - [orig]
|
182
|
+
args.each do |name|
|
183
|
+
alias_method("#{name}!", "#{orig}!")
|
184
|
+
end
|
137
185
|
end
|
138
186
|
|
139
187
|
end
|
@@ -10,6 +10,16 @@ class Module
|
|
10
10
|
#
|
11
11
|
alias_method :is, :include
|
12
12
|
|
13
|
+
# TODO
|
14
|
+
# def is(*mods)
|
15
|
+
# mods.each do |mod|
|
16
|
+
# if mod.const_defined?(:Self)
|
17
|
+
# extend mod.const_get(:Self)
|
18
|
+
# end
|
19
|
+
# end
|
20
|
+
# include(*mods)
|
21
|
+
# end
|
22
|
+
|
13
23
|
# Expirmental idea for #is.
|
14
24
|
#
|
15
25
|
# If the module has #append_function_function
|
@@ -1 +1 @@
|
|
1
|
-
require 'facets/module/
|
1
|
+
require 'facets/module/attr.rb'
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'facets/module/attr.rb'
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'facets/module/attr.rb'
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'facets/module/attr.rb'
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'facets/module/attr.rb'
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'facets/module/attr.rb'
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'facets/module/attr.rb'
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'facets/module/attr.rb'
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'facets/module/attr.rb'
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'facets/module/attr.rb'
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'facets/module/attr.rb'
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'facets/module/attr.rb'
|
@@ -58,7 +58,7 @@ class Console::Arguments
|
|
58
58
|
# Takes the command line string (or array) and options.
|
59
59
|
# Options have flags and end with a hash of option arity.
|
60
60
|
#
|
61
|
-
def initialize(
|
61
|
+
def initialize(line=nil, arity=nil)
|
62
62
|
@line, @argv = parse_line(line)
|
63
63
|
@arity = parse_arity(arity||{})
|
64
64
|
parse
|
@@ -237,6 +237,7 @@ class Console::Arguments
|
|
237
237
|
key, val = key.split('=')
|
238
238
|
elsif a = arity[key]
|
239
239
|
val = args.slice!(0,a)
|
240
|
+
val = val.first if a == 1
|
240
241
|
else
|
241
242
|
val = true
|
242
243
|
end
|
data/lib/more/facets/command.rb
CHANGED
@@ -20,182 +20,323 @@
|
|
20
20
|
#
|
21
21
|
# AUTHORS:
|
22
22
|
#
|
23
|
-
# -
|
24
|
-
# - Tyler Rick
|
23
|
+
# - Trans
|
25
24
|
#
|
26
|
-
#
|
25
|
+
# TODO:
|
27
26
|
#
|
28
|
-
# - Add
|
29
|
-
# -
|
30
|
-
#
|
31
|
-
# LOG:
|
32
|
-
#
|
33
|
-
# - 2007.10.31 TRANS
|
34
|
-
# Re-added support for __option notation.
|
27
|
+
# - Add global options to master command, or "all are master options" flag?
|
28
|
+
# - Add usage/help/documentation/man features.
|
35
29
|
|
36
|
-
require 'shellwords'
|
37
30
|
#require 'facets/annotations' # for help ?
|
31
|
+
#require 'facets/module/attr'
|
32
|
+
#require 'facets/kernel/constant'
|
33
|
+
#require 'shellwords'
|
34
|
+
require 'facets/arguments'
|
38
35
|
|
39
36
|
module Console
|
40
37
|
|
41
|
-
#
|
42
|
-
#
|
43
|
-
#
|
44
|
-
#
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
38
|
+
# For CommandOptions, but defined external to it, so
|
39
|
+
# that it is easy to access from user defined commands.
|
40
|
+
# (This lookup issue should be fixed in Ruby 1.9+, and then
|
41
|
+
# the class can be moved back into Command namespace.)
|
42
|
+
|
43
|
+
class NoOptionError < NoMethodError
|
44
|
+
def initialize(name, *arg)
|
45
|
+
super("unknown option -- #{name}", name, *args)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
class NoCommandError < NoMethodError
|
50
|
+
def initialize(name, *arg)
|
51
|
+
super("unknown subcommand -- #{name}", name, *args)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# Here is an example of usage:
|
50
56
|
#
|
51
|
-
#
|
57
|
+
# # General Options
|
52
58
|
#
|
53
|
-
#
|
54
|
-
#
|
55
|
-
#
|
59
|
+
# module GeneralOptions
|
60
|
+
# attr_accessor :dryrun ; alias_accessor :n, :noharm, :dryrun
|
61
|
+
# attr_accessor :quiet ; alias_accessor :q, :quiet
|
62
|
+
# attr_accessor :force
|
63
|
+
# attr_accessor :trace
|
56
64
|
# end
|
57
65
|
#
|
58
|
-
#
|
66
|
+
# # Build Subcommand
|
59
67
|
#
|
60
|
-
# class
|
68
|
+
# class BuildCommand < Console::Command
|
69
|
+
# include GeneralOptions
|
61
70
|
#
|
62
|
-
#
|
71
|
+
# # metadata files
|
72
|
+
# attr_accessor :file ; alias_accessor :f, :file
|
73
|
+
# attr_accessor :manifest ; alias_accessor :m, :manifest
|
63
74
|
#
|
64
|
-
#
|
65
|
-
#
|
75
|
+
# def call
|
76
|
+
# # do stuf here
|
66
77
|
# end
|
78
|
+
# end
|
67
79
|
#
|
68
|
-
#
|
69
|
-
#
|
70
|
-
#
|
80
|
+
# # Box Master Command
|
81
|
+
#
|
82
|
+
# class BoxCommand < Console::MasterCommand
|
83
|
+
# subcommand :build, BuildCommand
|
71
84
|
# end
|
72
85
|
#
|
86
|
+
# BoxCommand.start
|
73
87
|
|
74
|
-
class
|
88
|
+
class MasterCommand
|
89
|
+
|
90
|
+
#
|
75
91
|
|
76
|
-
|
92
|
+
module UniversalOptions
|
93
|
+
end
|
77
94
|
|
78
|
-
|
95
|
+
#
|
79
96
|
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
#cmd.instance_variable_set("@global_options",global_options)
|
84
|
-
cmd.execute(*args)
|
97
|
+
def self.option_arity(arity_hash=nil)
|
98
|
+
if arity_hash
|
99
|
+
(@option_arity ||= {}).merge!(arity_hash)
|
85
100
|
end
|
86
|
-
|
101
|
+
@option_arity
|
102
|
+
end
|
103
|
+
|
104
|
+
#
|
87
105
|
|
88
|
-
|
89
|
-
|
90
|
-
|
106
|
+
def self.start(line=nil)
|
107
|
+
cargs = Console::Arguments.new(line || ARGV, option_arity)
|
108
|
+
pre = cargs.preoptions
|
109
|
+
cmd, argv = *cargs.subcommand
|
110
|
+
args, opts = *argv
|
111
|
+
if is_a?(UniversalOptions)
|
112
|
+
new(pre, opts).call(cmd, args, opts)
|
113
|
+
else
|
114
|
+
new(pre).call(cmd, args, opts)
|
91
115
|
end
|
92
|
-
|
116
|
+
end
|
93
117
|
|
94
|
-
|
95
|
-
# or a block whihc will be used to create an Command::Options subclass.
|
118
|
+
#
|
96
119
|
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
120
|
+
def self.subcommand(name, command_class, options=nil)
|
121
|
+
options ||= {}
|
122
|
+
if options[:no_merge]
|
123
|
+
file, line = __FILE__, __LINE__+1
|
124
|
+
code = %{
|
125
|
+
def #{name}(args, opts)
|
126
|
+
#{command_class}.new(args, opts).call
|
127
|
+
end
|
128
|
+
}
|
129
|
+
else
|
130
|
+
file, line = __FILE__, __LINE__+1
|
131
|
+
code = %{
|
132
|
+
def #{name}(args, opts)
|
133
|
+
opts.merge(master_options)
|
134
|
+
#{command_class}.new(args, opts).call
|
135
|
+
end
|
136
|
+
}
|
104
137
|
end
|
105
|
-
|
106
|
-
|
138
|
+
class_eval(code, file, line)
|
139
|
+
end
|
140
|
+
|
141
|
+
private
|
107
142
|
|
108
|
-
|
143
|
+
attr :master_options
|
109
144
|
|
110
|
-
|
111
|
-
|
145
|
+
#
|
146
|
+
|
147
|
+
def initialize(*options)
|
148
|
+
initialize_options(*options)
|
149
|
+
end
|
150
|
+
|
151
|
+
#
|
152
|
+
|
153
|
+
def initialize_options(*options)
|
154
|
+
options = options.inject{ |h,o| h.merge(o) }
|
155
|
+
begin
|
156
|
+
opt, val = nil, nil
|
157
|
+
options.each do |opt, val|
|
158
|
+
send("#{opt}=", val)
|
159
|
+
end
|
160
|
+
rescue NoMethodError
|
161
|
+
option_missing(opt, val)
|
112
162
|
end
|
163
|
+
@master_options = options
|
164
|
+
end
|
165
|
+
|
166
|
+
public
|
113
167
|
|
114
|
-
|
168
|
+
#
|
115
169
|
|
116
|
-
|
117
|
-
|
170
|
+
def call(cmd, args, opts)
|
171
|
+
cmd = :default if cmd.nil?
|
172
|
+
begin
|
173
|
+
subcommand = method(cmd)
|
174
|
+
parameters = [args, opts]
|
175
|
+
rescue NameError
|
176
|
+
subcommand = method(:subcommand_missing)
|
177
|
+
parameters = [cmd, args, opts]
|
178
|
+
end
|
179
|
+
if subcommand.arity < 0
|
180
|
+
subcommand.call(*parameters[0..subcommand.arity])
|
181
|
+
else
|
182
|
+
subcommand.call(*parameters[0,subcommand.arity])
|
118
183
|
end
|
119
184
|
end
|
120
185
|
|
121
|
-
|
186
|
+
#
|
187
|
+
|
188
|
+
def help; end
|
122
189
|
|
123
|
-
|
124
|
-
|
125
|
-
|
190
|
+
def default ; help ; end
|
191
|
+
|
192
|
+
private
|
126
193
|
|
127
194
|
#
|
128
195
|
|
129
|
-
def
|
130
|
-
|
196
|
+
def subcommand_missing(cmd, args, opt)
|
197
|
+
help
|
198
|
+
#raise NoCommandError.new(cmd, args << opt)
|
199
|
+
end
|
131
200
|
|
132
|
-
|
133
|
-
g_keys = self.class.global_options
|
201
|
+
#
|
134
202
|
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
end
|
203
|
+
def option_missing(opt, arg=nil)
|
204
|
+
raise NoOptionError.new(opt)
|
205
|
+
end
|
139
206
|
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
argv = g_opts.parse(argv, :stop => true)
|
146
|
-
cmd = argv.find{ |s| s !~ /^-/ }
|
147
|
-
argv.delete_at(argv.index(cmd)) if cmd
|
148
|
-
cmd = :default unless cmd
|
149
|
-
cmd = cmd.to_sym
|
150
|
-
end
|
207
|
+
end
|
208
|
+
|
209
|
+
# = Command base class
|
210
|
+
#
|
211
|
+
# See MasterCommand for example.
|
151
212
|
|
152
|
-
|
213
|
+
class Command
|
153
214
|
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
215
|
+
def self.start(line=nil)
|
216
|
+
cargs = Console::Argument.new(line || ARGV)
|
217
|
+
pre = cargs.preoptions
|
218
|
+
args, opts = *cargs.parameters
|
219
|
+
new(args, opts).call
|
220
|
+
end
|
158
221
|
|
159
|
-
|
222
|
+
attr :arguments
|
223
|
+
attr :options
|
160
224
|
|
161
|
-
|
225
|
+
#
|
226
|
+
|
227
|
+
def call
|
228
|
+
puts "Not implemented yet."
|
162
229
|
end
|
163
230
|
|
231
|
+
private
|
232
|
+
|
164
233
|
#
|
165
234
|
|
166
|
-
def
|
167
|
-
|
235
|
+
def initialize(arguments, options=nil)
|
236
|
+
initialize_arguments(*arguments)
|
237
|
+
initialize_options(options)
|
238
|
+
end
|
168
239
|
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
#end
|
240
|
+
#
|
241
|
+
|
242
|
+
def initialize_arguments(*arguments)
|
243
|
+
@arguments = arguments
|
244
|
+
end
|
245
|
+
|
246
|
+
#
|
247
|
+
|
248
|
+
def initialize_options(options)
|
249
|
+
options = options || {}
|
250
|
+
begin
|
251
|
+
opt, val = nil, nil
|
252
|
+
options.each do |opt, val|
|
253
|
+
send("#{opt}=", val)
|
184
254
|
end
|
255
|
+
rescue NoMethodError
|
256
|
+
option_missing(opt, val)
|
185
257
|
end
|
258
|
+
@options = options
|
186
259
|
end
|
187
260
|
|
188
|
-
#
|
189
|
-
# self.class.global_options
|
190
|
-
#end
|
261
|
+
#
|
191
262
|
|
192
263
|
def option_missing(opt, arg=nil)
|
193
|
-
raise
|
264
|
+
raise NoOptionError.new(opt)
|
265
|
+
end
|
266
|
+
|
267
|
+
end
|
268
|
+
|
269
|
+
end
|
270
|
+
|
271
|
+
|
272
|
+
class Array
|
273
|
+
|
274
|
+
# Not empty?
|
275
|
+
|
276
|
+
def not_empty?
|
277
|
+
!empty?
|
278
|
+
end
|
279
|
+
|
280
|
+
# Convert an array into command line parameters.
|
281
|
+
# The array is accepted in the format of Ruby
|
282
|
+
# method arguments --ie. [arg1, arg2, ..., hash]
|
283
|
+
|
284
|
+
def to_console
|
285
|
+
flags = (Hash===last ? pop : {})
|
286
|
+
flags = flags.to_console
|
287
|
+
flags + ' ' + join(" ")
|
288
|
+
end
|
289
|
+
|
290
|
+
end
|
291
|
+
|
292
|
+
|
293
|
+
class Hash
|
294
|
+
|
295
|
+
# Convert an array into command line parameters.
|
296
|
+
# The array is accepted in the format of Ruby
|
297
|
+
# method arguments --ie. [arg1, arg2, ..., hash]
|
298
|
+
|
299
|
+
def to_console
|
300
|
+
flags = collect do |f,v|
|
301
|
+
m = f.to_s.size == 1 ? '-' : '--'
|
302
|
+
case v
|
303
|
+
when Array
|
304
|
+
v.collect{ |e| "#{m}#{f}='#{e}'" }.join(' ')
|
305
|
+
when true
|
306
|
+
"#{m}#{f}"
|
307
|
+
when false, nil
|
308
|
+
''
|
309
|
+
else
|
310
|
+
"#{m}#{f}='#{v}'"
|
311
|
+
end
|
194
312
|
end
|
313
|
+
flags.join(" ")
|
314
|
+
end
|
195
315
|
|
316
|
+
# Turn a hash into arguments.
|
317
|
+
#
|
318
|
+
# h = { :list => [1,2], :base => "HI" }
|
319
|
+
# h.argumentize #=> [ [], { :list => [1,2], :base => "HI" } ]
|
320
|
+
# h.argumentize(:list) #=> [ [1,2], { :base => "HI" } ]
|
321
|
+
#
|
322
|
+
def argumentize(args_field=nil)
|
323
|
+
config = dup
|
324
|
+
if args_field
|
325
|
+
args = [config.delete(args_field)].flatten.compact
|
326
|
+
else
|
327
|
+
args = []
|
328
|
+
end
|
329
|
+
args << config
|
330
|
+
return args
|
196
331
|
end
|
197
332
|
|
333
|
+
end
|
334
|
+
|
335
|
+
|
336
|
+
# SCRAP CODE FOR REFERENCE TO POSSIBLE ADD FUTURE FEATURES
|
337
|
+
|
198
338
|
=begin
|
339
|
+
|
199
340
|
# We include a module here so you can define your own help
|
200
341
|
# command and call #super to utilize this one.
|
201
342
|
|
@@ -264,248 +405,12 @@ module Console
|
|
264
405
|
|
265
406
|
include Help
|
266
407
|
extend Help::ClassMethods
|
267
|
-
=end
|
268
|
-
|
269
|
-
|
270
|
-
# = Command::Options
|
271
|
-
#
|
272
|
-
# CommandOptions provides the basis for Command to Object Mapping (COM).
|
273
|
-
# It is an commandline options parser that uses method definitions
|
274
|
-
# as means of interprting command arguments.
|
275
|
-
#
|
276
|
-
# == Synopsis
|
277
|
-
#
|
278
|
-
# Let's make an executable called 'mycmd'.
|
279
|
-
#
|
280
|
-
# #!/usr/bin/env ruby
|
281
|
-
#
|
282
|
-
# require 'facets/command_options'
|
283
|
-
#
|
284
|
-
# class MyOptions < CommandOptions
|
285
|
-
# attr_accessor :file
|
286
|
-
#
|
287
|
-
# def v!
|
288
|
-
# @verbose = true
|
289
|
-
# end
|
290
|
-
# end
|
291
|
-
#
|
292
|
-
# opts = MyOptions.parse("-v --file hello.rb")
|
293
|
-
#
|
294
|
-
# opts.verbose #=> true
|
295
|
-
# opts.file #=> "hello.rb"
|
296
|
-
#
|
297
|
-
#--
|
298
|
-
# == Global Options
|
299
|
-
#
|
300
|
-
# You can define <i>global options</i> which are options that will be
|
301
|
-
# processed no matter where they occur in the command line. In the above
|
302
|
-
# examples only the options occuring before the subcommand are processed
|
303
|
-
# globally. Anything occuring after the subcommand belonds strictly to
|
304
|
-
# the subcommand. For instance, if we had added the following to the above
|
305
|
-
# example:
|
306
|
-
#
|
307
|
-
# global_option :_v
|
308
|
-
#
|
309
|
-
# Then -v could appear anywhere in the command line, even on the end,
|
310
|
-
# and still work as expected.
|
311
|
-
#
|
312
|
-
# % mycmd jump -h 3 -v
|
313
|
-
#++
|
314
|
-
#
|
315
|
-
# == Missing Options
|
316
|
-
#
|
317
|
-
# You can use #option_missing to catch any options that are not explicility
|
318
|
-
# defined.
|
319
|
-
#
|
320
|
-
# The method signature should look like:
|
321
|
-
#
|
322
|
-
# option_missing(option_name, args)
|
323
|
-
#
|
324
|
-
# Example:
|
325
|
-
# def option_missing(option_name, args)
|
326
|
-
# p args if $debug
|
327
|
-
# case option_name
|
328
|
-
# when 'p'
|
329
|
-
# @a = args[0].to_i
|
330
|
-
# @b = args[1].to_i
|
331
|
-
# 2
|
332
|
-
# else
|
333
|
-
# raise InvalidOptionError(option_name, args)
|
334
|
-
# end
|
335
|
-
# end
|
336
|
-
#
|
337
|
-
# Its return value should be the effective "arity" of that options -- that is,
|
338
|
-
# how many arguments it consumed ("-p a b", for example, would consume 2 args:
|
339
|
-
# "a" and "b"). An arity of 1 is assumed if nil or false is returned.
|
340
|
-
|
341
|
-
class Command::Options
|
342
|
-
|
343
|
-
def self.parse(*line_and_options)
|
344
|
-
o = new
|
345
|
-
o.parse(*line_and_options)
|
346
|
-
o
|
347
|
-
end
|
348
|
-
|
349
|
-
def initialize(delegate=nil)
|
350
|
-
@__self__ = delegate || self
|
351
|
-
end
|
352
|
-
|
353
|
-
# Parse line for options in the context self.
|
354
|
-
#
|
355
|
-
# Options:
|
356
|
-
#
|
357
|
-
# :pass => true || false
|
358
|
-
#
|
359
|
-
# Setting this to true prevents the parse_missing routine from running.
|
360
|
-
#
|
361
|
-
# :only => [ global options, ... ]
|
362
|
-
#
|
363
|
-
# When processing global options, we only want to parse selected options.
|
364
|
-
# This also set +pass+ to true.
|
365
|
-
#
|
366
|
-
# :stop => true || false
|
367
|
-
#
|
368
|
-
# If we are parsing options for the *main* command and we are allowing
|
369
|
-
# subcommands, then we want to stop as soon as we get to the first non-option,
|
370
|
-
# because that non-option will be the name of our subcommand and all options that
|
371
|
-
# follow should be parsed later when we handle the subcommand.
|
372
|
-
# This also set +pass+ to true.
|
373
|
-
|
374
|
-
def parse(*line_and_options)
|
375
|
-
__self__ = @__self__
|
376
|
-
|
377
|
-
if Hash === line_and_options.last
|
378
|
-
options = line_and_options.pop
|
379
|
-
line = line_and_options.first
|
380
|
-
else
|
381
|
-
options = {}
|
382
|
-
line = line_and_options.first
|
383
|
-
end
|
384
408
|
|
385
|
-
|
386
|
-
when String
|
387
|
-
argv = Shellwords.shellwords(line)
|
388
|
-
when Array
|
389
|
-
argv = line.dup
|
390
|
-
else
|
391
|
-
argv = ARGV.dup
|
392
|
-
end
|
393
|
-
|
394
|
-
only = options[:only] # only parse these options
|
395
|
-
stop = options[:stop] # stop at first non-option
|
396
|
-
pass = options[:pass] || only || stop # don't run options_missing
|
397
|
-
|
398
|
-
if $debug
|
399
|
-
puts(only ? "\nGlobal parsing..." : "\nParsing...")
|
400
|
-
end
|
401
|
-
|
402
|
-
puts "# line: #{argv.inspect}" if $debug
|
403
|
-
|
404
|
-
# Split single letter option groupings into separate options.
|
405
|
-
# ie. -xyz => -x -y -z
|
406
|
-
argv = argv.collect { |arg|
|
407
|
-
if md = /^-(\w{2,})/.match( arg )
|
408
|
-
md[1].split(//).collect { |c| "-#{c}" }
|
409
|
-
else
|
410
|
-
arg
|
411
|
-
end
|
412
|
-
}.flatten
|
413
|
-
|
414
|
-
index = 0
|
415
|
-
|
416
|
-
until index >= argv.size
|
417
|
-
arg = argv.at(index)
|
418
|
-
break if arg == '--' # POSIX compliance
|
419
|
-
if arg[0,1] == '-'
|
420
|
-
puts "# option: #{arg}" if $debug
|
421
|
-
cnt = (arg[0,2] == '--' ? 2 : 1)
|
422
|
-
#opt = Option.new(arg)
|
423
|
-
#name = opt.methodize
|
424
|
-
name = arg.sub(/^-{1,2}/,'')
|
425
|
-
skip = only && only.include?(name)
|
426
|
-
unam = ('__'*cnt)+name
|
427
|
-
if __self__.respond_to?(unam)
|
428
|
-
puts "# method: #{uname}" if $debug
|
429
|
-
meth = method(unam)
|
430
|
-
arity = meth.arity
|
431
|
-
if arity < 0
|
432
|
-
meth.call(*argv.slice(index+1..-1)) unless skip
|
433
|
-
arity[index..-1] = nil # Get rid of the *name* and values
|
434
|
-
elsif arity == 0
|
435
|
-
meth.call unless skip
|
436
|
-
argv.delete_at(index) # Get rid of the *name* of the option
|
437
|
-
else
|
438
|
-
meth.call(*argv.slice(index+1, arity)) unless skip
|
439
|
-
#argv.delete_at(index) # Get rid of the *name* of the option
|
440
|
-
#arity.times{ argv.delete_at(index) } # Get rid of the *value* of the option
|
441
|
-
arity[index,arity] = nil
|
442
|
-
end
|
443
|
-
elsif __self__.respond_to?(name+'=')
|
444
|
-
puts "# method: #{name}=" if $debug
|
445
|
-
__self__.send(name+'=', *argv.slice(index+1, 1)) unless skip
|
446
|
-
argv.delete_at(index) # Get rid of the *name* of the option
|
447
|
-
argv.delete_at(index) # Get rid of the *value* of the option
|
448
|
-
elsif __self__.respond_to?(name+'!')
|
449
|
-
puts "# method: #{name}!" if $debug
|
450
|
-
__self__.send(name+'!') unless skip
|
451
|
-
argv.delete_at(index) # Get rid of the *name* of the option
|
452
|
-
else
|
453
|
-
index += 1
|
454
|
-
end
|
455
|
-
else
|
456
|
-
index += 1
|
457
|
-
break if stop
|
458
|
-
end
|
459
|
-
end
|
460
|
-
# parse missing ?
|
461
|
-
argv = parse_missing(argv) unless pass
|
462
|
-
# return the remaining argv
|
463
|
-
puts "# return: #{argv.inspect}" if $debug
|
464
|
-
return argv
|
465
|
-
end
|
466
|
-
|
467
|
-
#
|
468
|
-
|
469
|
-
def parse_missing(argv)
|
470
|
-
argv.each_with_index do |a,i|
|
471
|
-
if a =~ /^-/
|
472
|
-
#raise InvalidOptionError.new(a) unless @__self__.respond_to?(:option_missing)
|
473
|
-
kept = @__self__.option_missing(a, *argv[i+1,1])
|
474
|
-
argv.delete_at(i) if kept # delete if value kept
|
475
|
-
argv.delete_at(i) # delete option
|
476
|
-
end
|
477
|
-
end
|
478
|
-
return argv
|
479
|
-
end
|
480
|
-
|
481
|
-
#
|
482
|
-
|
483
|
-
def option_missing(opt, arg=nil)
|
484
|
-
raise InvalidOptionError.new(opt)
|
485
|
-
# #$stderr << "Unknown option '#{arg}'.\n"
|
486
|
-
# #exit -1
|
487
|
-
end
|
488
|
-
|
489
|
-
#
|
490
|
-
|
491
|
-
def to_h
|
492
|
-
opts = @__self__.public_methods(true).select{ |m| m =~ /^[A-Za-z0-9]+[=!]$/ || m =~ /^[_][A-Za-z0-9]+$/ }
|
493
|
-
#opts.reject!{ |k| k =~ /_$/ }
|
494
|
-
opts.collect!{ |m| m.chomp('=').chomp('!') }
|
495
|
-
opts.inject({}) do |h, m|
|
496
|
-
k = m.sub(/^_+/, '')
|
497
|
-
v = @__self__.send(m)
|
498
|
-
h[k] = v if v
|
499
|
-
h
|
500
|
-
end
|
409
|
+
=end
|
501
410
|
|
502
|
-
|
503
|
-
# next h if v == "@__self__"
|
504
|
-
# h[v[1..-1]] = @__self__.instance_variable_get(v); h
|
505
|
-
#end
|
506
|
-
end
|
411
|
+
=begin
|
507
412
|
|
508
|
-
|
413
|
+
# Provides a very basic usage help string.
|
509
414
|
#
|
510
415
|
# TODO Add support for __options.
|
511
416
|
def usage
|
@@ -559,48 +464,6 @@ module Console
|
|
559
464
|
return c
|
560
465
|
end
|
561
466
|
|
562
|
-
# # Single Option
|
563
|
-
#
|
564
|
-
# class Option < String
|
565
|
-
#
|
566
|
-
# def initialize(option)
|
567
|
-
# @flag = option
|
568
|
-
# @long = (/^--/ =~ option)
|
569
|
-
# super(option.sub(/^-{1,2}/,''))
|
570
|
-
# end
|
571
|
-
#
|
572
|
-
# def long?
|
573
|
-
# @long
|
574
|
-
# end
|
575
|
-
#
|
576
|
-
# def short?
|
577
|
-
# !@long
|
578
|
-
# end
|
579
|
-
#
|
580
|
-
# #def demethodize
|
581
|
-
# # sub('__','--').sub('_','-')
|
582
|
-
# #end
|
583
|
-
#
|
584
|
-
# def methodize
|
585
|
-
# @flag.sub(/^-{1,2}/,'')
|
586
|
-
# end
|
587
|
-
#
|
588
|
-
# end
|
589
|
-
|
590
|
-
end
|
591
|
-
|
592
|
-
# For CommandOptions, but defined external to it, so
|
593
|
-
# that it is easy to access from user defined commands.
|
594
|
-
# (This lookup issue should be fixed in Ruby 1.9+, and then
|
595
|
-
# the class can be moved back into Command namespace.)
|
596
|
-
|
597
|
-
class InvalidOptionError < StandardError
|
598
|
-
def initialize(option_name)
|
599
|
-
@option_name = option_name
|
600
|
-
end
|
601
|
-
def message
|
602
|
-
"Unknown option '#{@option_name}'."
|
603
|
-
end
|
604
467
|
end
|
605
468
|
|
606
|
-
end
|
469
|
+
=end
|