kxi 1.0.1 → 1.0.2
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.
- checksums.yaml +4 -4
- data/lib/kxi.rb +44 -39
- data/lib/kxi/application/config.rb +177 -177
- data/lib/kxi/application/config_reader.rb +16 -16
- data/lib/kxi/application/event.rb +35 -35
- data/lib/kxi/application/logger.rb +155 -155
- data/lib/kxi/application/version.rb +106 -74
- data/lib/kxi/application/version_expression.rb +94 -69
- data/lib/kxi/application/workspace.rb +105 -0
- data/lib/kxi/cli/anonymous_argument.rb +50 -50
- data/lib/kxi/cli/argument.rb +56 -56
- data/lib/kxi/cli/argument_values.rb +83 -83
- data/lib/kxi/cli/explicit_argument.rb +38 -38
- data/lib/kxi/cli/flag_argument.rb +15 -15
- data/lib/kxi/cli/named_argument.rb +59 -59
- data/lib/kxi/cli/property_list.rb +57 -48
- data/lib/kxi/cli/table.rb +82 -62
- data/lib/kxi/cli/verb.rb +282 -280
- data/lib/kxi/collections/array_collection.rb +106 -106
- data/lib/kxi/collections/enumerable.rb +527 -527
- data/lib/kxi/collections/enumerator.rb +31 -31
- data/lib/kxi/collections/hash_collection.rb +100 -100
- data/lib/kxi/collections/protected_collection.rb +20 -19
- data/lib/kxi/exceptions/abstract_exception.rb +34 -34
- data/lib/kxi/exceptions/argument_exception.rb +21 -21
- data/lib/kxi/exceptions/collection_exception.rb +13 -13
- data/lib/kxi/exceptions/configuration_exception.rb +36 -25
- data/lib/kxi/exceptions/dimension_mismatch_exception.rb +29 -0
- data/lib/kxi/exceptions/invalid_type_exception.rb +32 -32
- data/lib/kxi/exceptions/no_argument_exception.rb +20 -20
- data/lib/kxi/exceptions/not_implemented_exception.rb +12 -12
- data/lib/kxi/exceptions/out_of_range_exception.rb +43 -43
- data/lib/kxi/exceptions/parse_exception.rb +28 -20
- data/lib/kxi/exceptions/verb_expected_exception.rb +20 -20
- data/lib/kxi/exceptions/workspace_collision_exception.rb +21 -0
- data/lib/kxi/math/math.rb +45 -0
- data/lib/kxi/math/matrix.rb +303 -0
- data/lib/kxi/math/polynomial.rb +141 -101
- data/lib/kxi/math/vector.rb +181 -0
- data/lib/kxi/platform.rb +103 -57
- data/lib/kxi/reflection/stack_frame.rb +80 -80
- data/lib/kxi/version.rb +4 -4
- metadata +8 -3
- data/lib/kxi/exceptions/invalid_operation_exception.rb +0 -11
data/lib/kxi/cli/table.rb
CHANGED
@@ -1,63 +1,83 @@
|
|
1
|
-
# Created by Matyáš Pokorný on 2018-01-24.
|
2
|
-
|
3
|
-
module KXI
|
4
|
-
module CLI
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
end
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
1
|
+
# Created by Matyáš Pokorný on 2018-01-24.
|
2
|
+
|
3
|
+
module KXI
|
4
|
+
module CLI
|
5
|
+
# Table renderer
|
6
|
+
class Table
|
7
|
+
# Instantiate the {KXI::CLI::Table} class
|
8
|
+
def initialize
|
9
|
+
@cols = KXI::Collections::ArrayCollection.new
|
10
|
+
@rows = 0
|
11
|
+
yield(self) if block_given?
|
12
|
+
end
|
13
|
+
|
14
|
+
# Defines a column of table
|
15
|
+
# @param [string] name Name of column
|
16
|
+
# @return [KXI::CLI::Table::Column] Defined column
|
17
|
+
def column(name)
|
18
|
+
col = Column.new(name)
|
19
|
+
@cols.add(col)
|
20
|
+
return col
|
21
|
+
end
|
22
|
+
|
23
|
+
# Adds a row to table
|
24
|
+
# @param [Hash<string, any>] e Row to add
|
25
|
+
# @return [integer] Current number of rows
|
26
|
+
def row(e)
|
27
|
+
e.each_key { |c| @cols.first { |i| i.name == c }&.row(e[c].to_s.strip.chomp) }
|
28
|
+
@rows += 1
|
29
|
+
end
|
30
|
+
|
31
|
+
# Renders the table into stdout
|
32
|
+
def render
|
33
|
+
@rows.times do |row|
|
34
|
+
f = true
|
35
|
+
@cols.foreach do |col|
|
36
|
+
print(' ') unless f
|
37
|
+
f = false
|
38
|
+
col.write(row)
|
39
|
+
end
|
40
|
+
puts
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# Represents a column of table
|
45
|
+
class Column
|
46
|
+
# Gets the length of the longest value
|
47
|
+
# @return [integer] Length of the longest value
|
48
|
+
def align
|
49
|
+
@align
|
50
|
+
end
|
51
|
+
|
52
|
+
# Gets the name of column
|
53
|
+
# @return [string] Name of column
|
54
|
+
def name
|
55
|
+
@name
|
56
|
+
end
|
57
|
+
|
58
|
+
# Instantiates the {KXI::CLI::Table::Column} class
|
59
|
+
# @param [string] name Name of column
|
60
|
+
def initialize(name)
|
61
|
+
@name = name
|
62
|
+
@align = 0
|
63
|
+
@data = []
|
64
|
+
end
|
65
|
+
|
66
|
+
# Adds a row to the column
|
67
|
+
# @param [string] str Value of row to add
|
68
|
+
def row(str)
|
69
|
+
@align = str.length if @align < str.length
|
70
|
+
@data.push(str)
|
71
|
+
end
|
72
|
+
|
73
|
+
# Writes the value of a row at given index to stdout
|
74
|
+
# @param [integer] row Index of the row to write
|
75
|
+
def write(row)
|
76
|
+
str = @data[row]
|
77
|
+
str = '' if str == nil
|
78
|
+
print(str.ljust(@align))
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
63
83
|
end
|
data/lib/kxi/cli/verb.rb
CHANGED
@@ -1,281 +1,283 @@
|
|
1
|
-
# Created by Matyáš Pokorný on 2018-01-20.
|
2
|
-
|
3
|
-
module KXI
|
4
|
-
module CLI
|
5
|
-
# Represents a verb of console interface
|
6
|
-
class Verb
|
7
|
-
# Gets the name of verb
|
8
|
-
# @return [String] Name of verb
|
9
|
-
def name
|
10
|
-
@name
|
11
|
-
end
|
12
|
-
|
13
|
-
# Gets the description of verb
|
14
|
-
# @return [String] Description of verb
|
15
|
-
def description
|
16
|
-
@desc
|
17
|
-
end
|
18
|
-
|
19
|
-
# Assigns action to this verb
|
20
|
-
# @yield [args] Action of verb
|
21
|
-
# @yieldparam args [KXI::CLI::ArgumentValues] Parsed values of arguments
|
22
|
-
def action(&block)
|
23
|
-
@action = block
|
24
|
-
end
|
25
|
-
|
26
|
-
# Gets the arguments assigned to this verb
|
27
|
-
# @return [KXI::Collections::ProtectedCollection] Arguments of verb
|
28
|
-
def arguments
|
29
|
-
KXI::Collections::ProtectedCollection.new(@args)
|
30
|
-
end
|
31
|
-
|
32
|
-
# Enables help for this verb and it's children
|
33
|
-
def enable_help
|
34
|
-
unless @help
|
35
|
-
@help = true
|
36
|
-
@verbs.foreach { |i| i.enable_help }
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
# Instantiates the {KXI::CLI::Verb} class
|
41
|
-
# @param nm [String] Name of verb
|
42
|
-
# @param desc [String] Description of verb
|
43
|
-
# @param ctx [String] Context of verb
|
44
|
-
# @yield [verb] Initialization body of verb
|
45
|
-
# @yieldparam verb [KXI::CLI::Verb] Initialized verb
|
46
|
-
# @raise [Exception] When name of verb is invalid
|
47
|
-
def initialize(nm, desc, ctx = nil)
|
48
|
-
raise(Exception.new('Invalid name of verb!')) unless /^[A-Za-z0-9][A-Za-z0-9\-]*$/m =~ nm
|
49
|
-
@name = nm.downcase
|
50
|
-
@desc = desc
|
51
|
-
@verbs = KXI::Collections::ArrayCollection.new
|
52
|
-
@args = KXI::Collections::ArrayCollection.new
|
53
|
-
@action = nil
|
54
|
-
@ctx = ctx
|
55
|
-
@help = false
|
56
|
-
yield(self) if block_given?
|
57
|
-
end
|
58
|
-
|
59
|
-
# Creates a new child verb
|
60
|
-
# @param name [String] Name of verb
|
61
|
-
# @param desc [String] Description of verb
|
62
|
-
# @return [KXI::CLI::Verb] Child verb
|
63
|
-
def verb(name, desc)
|
64
|
-
check_name(name)
|
65
|
-
add_verb(Verb.new(name, desc, @ctx == nil ? @name : "#{@ctx} #{@name}") { |v| yield(v) if block_given? })
|
66
|
-
end
|
67
|
-
|
68
|
-
# Creates new optional anonymous argument
|
69
|
-
# @param name [String] Name of argument
|
70
|
-
# @param desc [String] Description of argument
|
71
|
-
# @param df [Object, nil] Default value of argument
|
72
|
-
# @param var [Bool] Determines whether argument is variadic
|
73
|
-
# @yield [val] Validator function for value of argument
|
74
|
-
# @yieldparam val [String, Array<String>] Value of argument
|
75
|
-
# @return [KXI::CLI::AnonymousArgument] Anonymous argument
|
76
|
-
def anonymous(name, desc, df = nil, var = false, &validator)
|
77
|
-
add_argument(KXI::CLI::AnonymousArgument.new(name, desc, false, df, var, &validator))
|
78
|
-
end
|
79
|
-
|
80
|
-
|
81
|
-
# Creates new mandatory anonymous argument
|
82
|
-
# @param name [String] Name of argument
|
83
|
-
# @param desc [String] Description of argument
|
84
|
-
# @param var [Bool] Determines whether argument is variadic
|
85
|
-
# @yield [val] Validator function for value of argument
|
86
|
-
# @yieldparam val [String, Array<String>] Value of argument
|
87
|
-
# @return [KXI::CLI::AnonymousArgument] Anonymous argument
|
88
|
-
def anonymous!(name, desc, var = false, &validator)
|
89
|
-
add_argument(KXI::CLI::AnonymousArgument.new(name, desc, true, nil, var, &validator))
|
90
|
-
end
|
91
|
-
|
92
|
-
# Creates new optional named argument
|
93
|
-
# @param name [String] Name of argument
|
94
|
-
# @param val [String] Name of value
|
95
|
-
# @param desc [String] Description of argument
|
96
|
-
# @param sh [String, nil] Shortcut symbol
|
97
|
-
# @param df [Object, nil] Default value of argument
|
98
|
-
# @param var [Bool] Determines whether argument is variadic
|
99
|
-
# @yield [val] Validator function for value of argument
|
100
|
-
# @yieldparam val [String, Array<String>] Value of argument
|
101
|
-
# @return [KXI::CLI::NamedArgument] Named argument
|
102
|
-
def named(name, val, desc, sh = nil, df = nil, var = false, &validator)
|
103
|
-
add_argument(KXI::CLI::NamedArgument.new(name, val, desc, sh, false, df, var, &validator))
|
104
|
-
end
|
105
|
-
|
106
|
-
|
107
|
-
# Creates new mandatory named argument
|
108
|
-
# @param name [String] Name of argument
|
109
|
-
# @param val [String] Name of value
|
110
|
-
# @param desc [String] Description of argument
|
111
|
-
# @param sh [String, nil] Shortcut symbol
|
112
|
-
# @param var [Bool] Determines whether argument is variadic
|
113
|
-
# @yield [val] Validator function for value of argument
|
114
|
-
# @yieldparam val [String, Array<String>] Value of argument
|
115
|
-
# @return [KXI::CLI::NamedArgument] Named argument
|
116
|
-
def named!(name, val, desc, sh = nil, var = false, &validator)
|
117
|
-
add_argument(KXI::CLI::NamedArgument.new(name, val, desc, sh, true, nil, var, &validator))
|
118
|
-
end
|
119
|
-
|
120
|
-
|
121
|
-
# Creates new flag argument
|
122
|
-
# @param name [String] Name of flag
|
123
|
-
# @param desc [String] Description of flag
|
124
|
-
# @param sh [String, nil] Shortcut symbol
|
125
|
-
# @return [KXI::CLI::FlagArgument] Flag argument
|
126
|
-
def flag(name, desc, sh = nil)
|
127
|
-
add_argument(KXI::CLI::FlagArgument.new(name, desc, sh))
|
128
|
-
end
|
129
|
-
|
130
|
-
# Parses and executes action of verb
|
131
|
-
# @param args [Array<String>] Given arguments
|
132
|
-
def act(args = nil)
|
133
|
-
args = ARGV if args == nil
|
134
|
-
hf = (args.include?('-h') or args.include?('--help') or args.include?('-?'))
|
135
|
-
if @verbs.count > 0
|
136
|
-
v = args.shift
|
137
|
-
if @help and (v == 'help' or hf)
|
138
|
-
if v == 'help' or v == nil
|
139
|
-
help
|
140
|
-
else
|
141
|
-
verb = @verbs.first { |i| i.name == v.downcase }
|
142
|
-
if verb == nil
|
143
|
-
help
|
144
|
-
else
|
145
|
-
verb.act(args)
|
146
|
-
end
|
147
|
-
end
|
148
|
-
else
|
149
|
-
raise(KXI::Exceptions::VerbExpectedException.new(@verbs.select { |i| i.name }.to_array)) if v == nil
|
150
|
-
verb = @verbs.first { |i| i.name == v.downcase }
|
151
|
-
raise(KXI::Exceptions::VerbExpectedException.new(@verbs.select { |i| i.name }.to_array)) if verb == nil
|
152
|
-
verb.act(args)
|
153
|
-
end
|
154
|
-
else
|
155
|
-
if @help and hf
|
156
|
-
help
|
157
|
-
else
|
158
|
-
vals = KXI::CLI::ArgumentValues.new(@args.to_array)
|
159
|
-
anon = @args.of_type(KXI::CLI::AnonymousArgument).order_by_descending { |a, b| a.order <=> b.order }
|
160
|
-
|
161
|
-
ar = nil
|
162
|
-
args.each do |val|
|
163
|
-
if val.start_with?('-')
|
164
|
-
raise(KXI::Exceptions::ArgumentException.new(ar.name, 'Expected value!')) if ar != nil
|
165
|
-
raise(KXI::Exceptions::ArgumentException.new(val, 'Invalid syntax!')) if val.start_with?('---')
|
166
|
-
if val.start_with?('--')
|
167
|
-
raise(KXI::Exceptions::ArgumentException.new(val, 'Expected argument name!')) if val.length == 2
|
168
|
-
nm = val[2..val.length - 1].downcase
|
169
|
-
arg = @args.first { |i| i.name == nm }
|
170
|
-
raise(KXI::Exceptions::ArgumentException.new(nm, 'No such argument exists!')) if arg == nil
|
171
|
-
if arg.is_a?(KXI::CLI::FlagArgument)
|
172
|
-
vals.set(arg, true)
|
173
|
-
elsif arg.is_a?(KXI::CLI::NamedArgument)
|
174
|
-
ar = arg
|
175
|
-
else
|
176
|
-
raise(KXI::Exceptions::ArgumentException.new(nm, 'Argument cannot be assigned explicitly!'))
|
177
|
-
end
|
178
|
-
else
|
179
|
-
raise(KXI::Exceptions::ArgumentException.new(val, 'Expected short argument name!')) if val.length == 1
|
180
|
-
nm = val[1]
|
181
|
-
arg = @args.of_type(KXI::CLI::ExplicitArgument).first { |i| i.shortcut == nm }
|
182
|
-
raise(KXI::Exceptions::ArgumentException.new(nm, 'No such argument exists!')) if arg == nil
|
183
|
-
if arg.is_a?(KXI::CLI::FlagArgument)
|
184
|
-
vals.set(arg, true)
|
185
|
-
elsif arg.is_a?(KXI::CLI::NamedArgument)
|
186
|
-
if val.length == 2
|
187
|
-
ar = arg
|
188
|
-
else
|
189
|
-
vals.set(arg, val[2..val.length - 1])
|
190
|
-
end
|
191
|
-
end
|
192
|
-
end
|
193
|
-
else
|
194
|
-
if ar != nil
|
195
|
-
vals.set(ar, val)
|
196
|
-
ar = nil
|
197
|
-
else
|
198
|
-
an = anon.first
|
199
|
-
raise(KXI::Exceptions::NoArgumentException.new(val)) if an == nil
|
200
|
-
vals.set(an, val)
|
201
|
-
anon.remove_at(0) unless an.variadic?
|
202
|
-
end
|
203
|
-
end
|
204
|
-
end
|
205
|
-
vals.finish
|
206
|
-
if @action == nil
|
207
|
-
raise(KXI::Exceptions::NotImplementedException.new)
|
208
|
-
else
|
209
|
-
@action.call(vals)
|
210
|
-
end
|
211
|
-
end
|
212
|
-
end
|
213
|
-
end
|
214
|
-
|
215
|
-
# Prints help message of verb
|
216
|
-
def help
|
217
|
-
puts(@name)
|
218
|
-
puts("\t#{@desc}")
|
219
|
-
puts
|
220
|
-
puts('Usage:')
|
221
|
-
if @verbs.count == 0
|
222
|
-
print("\t")
|
223
|
-
print("#{@ctx} ") if @ctx != nil
|
224
|
-
print(@name)
|
225
|
-
args = @args.order_by_descending { |a, b| a.order <=> b.order }
|
226
|
-
args.where { |i| i.required? or i.is_a?(KXI::CLI::AnonymousArgument) }.foreach do |i|
|
227
|
-
print(" #{i.syntax}")
|
228
|
-
end
|
229
|
-
puts
|
230
|
-
if args.count > 0
|
231
|
-
puts
|
232
|
-
max = args.max { |a, b| a.headline.length <=> b.headline.length }.headline.length
|
233
|
-
args.foreach do |a|
|
234
|
-
puts("\t#{a.headline.ljust(max)} #{a.description}")
|
235
|
-
end
|
236
|
-
end
|
237
|
-
else
|
238
|
-
max = @verbs.max { |a, b| a.name.length <=> b.name.length }.name.length
|
239
|
-
@verbs.foreach do |v|
|
240
|
-
print("\t")
|
241
|
-
print("#{@ctx} ") if @ctx != nil
|
242
|
-
puts("#{@name} #{v.name.ljust(max)} #{v.description}")
|
243
|
-
end
|
244
|
-
end
|
245
|
-
end
|
246
|
-
|
247
|
-
# Adds argument
|
248
|
-
# @param arg [KXI::CLI::Argument] Argument to add
|
249
|
-
def add_argument(arg)
|
250
|
-
check_name(arg.name)
|
251
|
-
if arg.is_a?(KXI::CLI::ExplicitArgument) and arg.shortcut != nil
|
252
|
-
raise(Exception.new("Short name '#{arg.shortcut}' is already in use!")) if @args.of_type(KXI::CLI::ExplicitArgument).any { |i| i.shortcut == arg.shortcut }
|
253
|
-
end
|
254
|
-
if arg.is_a?(KXI::CLI::AnonymousArgument) and arg.variadic?
|
255
|
-
raise(Exception.new("Verb can have only one variadic anonymous argument! (argument '#{arg.name}')")) if @args.of_type(KXI::CLI::AnonymousArgument).any { |i| i.variadic? }
|
256
|
-
raise(Exception.new("Verb cannot contain both optional and variadic anonymous arguments! (argument '#{arg.name}')")) if @args.of_type(KXI::CLI::AnonymousArgument).any { |i| not i.required? }
|
257
|
-
end
|
258
|
-
@args.add(arg)
|
259
|
-
@verbs.foreach { |i| i.add_argument(arg) }
|
260
|
-
return arg
|
261
|
-
end
|
262
|
-
|
263
|
-
# Adds child verb
|
264
|
-
# @param v [KXI::CLI::Verb] Verb to add
|
265
|
-
def add_verb(v)
|
266
|
-
@args.foreach { |a| v.add_argument(a) }
|
267
|
-
@verbs.add(v)
|
268
|
-
v.enable_help if @help
|
269
|
-
return v
|
270
|
-
end
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
raise(Exception.new(
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
1
|
+
# Created by Matyáš Pokorný on 2018-01-20.
|
2
|
+
|
3
|
+
module KXI
|
4
|
+
module CLI
|
5
|
+
# Represents a verb of console interface
|
6
|
+
class Verb
|
7
|
+
# Gets the name of verb
|
8
|
+
# @return [String] Name of verb
|
9
|
+
def name
|
10
|
+
@name
|
11
|
+
end
|
12
|
+
|
13
|
+
# Gets the description of verb
|
14
|
+
# @return [String] Description of verb
|
15
|
+
def description
|
16
|
+
@desc
|
17
|
+
end
|
18
|
+
|
19
|
+
# Assigns action to this verb
|
20
|
+
# @yield [args] Action of verb
|
21
|
+
# @yieldparam args [KXI::CLI::ArgumentValues] Parsed values of arguments
|
22
|
+
def action(&block)
|
23
|
+
@action = block
|
24
|
+
end
|
25
|
+
|
26
|
+
# Gets the arguments assigned to this verb
|
27
|
+
# @return [KXI::Collections::ProtectedCollection] Arguments of verb
|
28
|
+
def arguments
|
29
|
+
KXI::Collections::ProtectedCollection.new(@args)
|
30
|
+
end
|
31
|
+
|
32
|
+
# Enables help for this verb and it's children
|
33
|
+
def enable_help
|
34
|
+
unless @help
|
35
|
+
@help = true
|
36
|
+
@verbs.foreach { |i| i.enable_help }
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# Instantiates the {KXI::CLI::Verb} class
|
41
|
+
# @param nm [String] Name of verb
|
42
|
+
# @param desc [String] Description of verb
|
43
|
+
# @param ctx [String] Context of verb
|
44
|
+
# @yield [verb] Initialization body of verb
|
45
|
+
# @yieldparam verb [KXI::CLI::Verb] Initialized verb
|
46
|
+
# @raise [Exception] When name of verb is invalid
|
47
|
+
def initialize(nm, desc, ctx = nil)
|
48
|
+
raise(Exception.new('Invalid name of verb!')) unless /^[A-Za-z0-9][A-Za-z0-9\-]*$/m =~ nm
|
49
|
+
@name = nm.downcase
|
50
|
+
@desc = desc
|
51
|
+
@verbs = KXI::Collections::ArrayCollection.new
|
52
|
+
@args = KXI::Collections::ArrayCollection.new
|
53
|
+
@action = nil
|
54
|
+
@ctx = ctx
|
55
|
+
@help = false
|
56
|
+
yield(self) if block_given?
|
57
|
+
end
|
58
|
+
|
59
|
+
# Creates a new child verb
|
60
|
+
# @param name [String] Name of verb
|
61
|
+
# @param desc [String] Description of verb
|
62
|
+
# @return [KXI::CLI::Verb] Child verb
|
63
|
+
def verb(name, desc)
|
64
|
+
check_name(name)
|
65
|
+
add_verb(Verb.new(name, desc, @ctx == nil ? @name : "#{@ctx} #{@name}") { |v| yield(v) if block_given? })
|
66
|
+
end
|
67
|
+
|
68
|
+
# Creates new optional anonymous argument
|
69
|
+
# @param name [String] Name of argument
|
70
|
+
# @param desc [String] Description of argument
|
71
|
+
# @param df [Object, nil] Default value of argument
|
72
|
+
# @param var [Bool] Determines whether argument is variadic
|
73
|
+
# @yield [val] Validator function for value of argument
|
74
|
+
# @yieldparam val [String, Array<String>] Value of argument
|
75
|
+
# @return [KXI::CLI::AnonymousArgument] Anonymous argument
|
76
|
+
def anonymous(name, desc, df = nil, var = false, &validator)
|
77
|
+
add_argument(KXI::CLI::AnonymousArgument.new(name, desc, false, df, var, &validator))
|
78
|
+
end
|
79
|
+
|
80
|
+
|
81
|
+
# Creates new mandatory anonymous argument
|
82
|
+
# @param name [String] Name of argument
|
83
|
+
# @param desc [String] Description of argument
|
84
|
+
# @param var [Bool] Determines whether argument is variadic
|
85
|
+
# @yield [val] Validator function for value of argument
|
86
|
+
# @yieldparam val [String, Array<String>] Value of argument
|
87
|
+
# @return [KXI::CLI::AnonymousArgument] Anonymous argument
|
88
|
+
def anonymous!(name, desc, var = false, &validator)
|
89
|
+
add_argument(KXI::CLI::AnonymousArgument.new(name, desc, true, nil, var, &validator))
|
90
|
+
end
|
91
|
+
|
92
|
+
# Creates new optional named argument
|
93
|
+
# @param name [String] Name of argument
|
94
|
+
# @param val [String] Name of value
|
95
|
+
# @param desc [String] Description of argument
|
96
|
+
# @param sh [String, nil] Shortcut symbol
|
97
|
+
# @param df [Object, nil] Default value of argument
|
98
|
+
# @param var [Bool] Determines whether argument is variadic
|
99
|
+
# @yield [val] Validator function for value of argument
|
100
|
+
# @yieldparam val [String, Array<String>] Value of argument
|
101
|
+
# @return [KXI::CLI::NamedArgument] Named argument
|
102
|
+
def named(name, val, desc, sh = nil, df = nil, var = false, &validator)
|
103
|
+
add_argument(KXI::CLI::NamedArgument.new(name, val, desc, sh, false, df, var, &validator))
|
104
|
+
end
|
105
|
+
|
106
|
+
|
107
|
+
# Creates new mandatory named argument
|
108
|
+
# @param name [String] Name of argument
|
109
|
+
# @param val [String] Name of value
|
110
|
+
# @param desc [String] Description of argument
|
111
|
+
# @param sh [String, nil] Shortcut symbol
|
112
|
+
# @param var [Bool] Determines whether argument is variadic
|
113
|
+
# @yield [val] Validator function for value of argument
|
114
|
+
# @yieldparam val [String, Array<String>] Value of argument
|
115
|
+
# @return [KXI::CLI::NamedArgument] Named argument
|
116
|
+
def named!(name, val, desc, sh = nil, var = false, &validator)
|
117
|
+
add_argument(KXI::CLI::NamedArgument.new(name, val, desc, sh, true, nil, var, &validator))
|
118
|
+
end
|
119
|
+
|
120
|
+
|
121
|
+
# Creates new flag argument
|
122
|
+
# @param name [String] Name of flag
|
123
|
+
# @param desc [String] Description of flag
|
124
|
+
# @param sh [String, nil] Shortcut symbol
|
125
|
+
# @return [KXI::CLI::FlagArgument] Flag argument
|
126
|
+
def flag(name, desc, sh = nil)
|
127
|
+
add_argument(KXI::CLI::FlagArgument.new(name, desc, sh))
|
128
|
+
end
|
129
|
+
|
130
|
+
# Parses and executes action of verb
|
131
|
+
# @param args [Array<String>] Given arguments
|
132
|
+
def act(args = nil)
|
133
|
+
args = ARGV if args == nil
|
134
|
+
hf = (args.include?('-h') or args.include?('--help') or args.include?('-?'))
|
135
|
+
if @verbs.count > 0
|
136
|
+
v = args.shift
|
137
|
+
if @help and (v == 'help' or hf)
|
138
|
+
if v == 'help' or v == nil
|
139
|
+
help
|
140
|
+
else
|
141
|
+
verb = @verbs.first { |i| i.name == v.downcase }
|
142
|
+
if verb == nil
|
143
|
+
help
|
144
|
+
else
|
145
|
+
verb.act(args)
|
146
|
+
end
|
147
|
+
end
|
148
|
+
else
|
149
|
+
raise(KXI::Exceptions::VerbExpectedException.new(@verbs.select { |i| i.name }.to_array)) if v == nil
|
150
|
+
verb = @verbs.first { |i| i.name == v.downcase }
|
151
|
+
raise(KXI::Exceptions::VerbExpectedException.new(@verbs.select { |i| i.name }.to_array)) if verb == nil
|
152
|
+
verb.act(args)
|
153
|
+
end
|
154
|
+
else
|
155
|
+
if @help and hf
|
156
|
+
help
|
157
|
+
else
|
158
|
+
vals = KXI::CLI::ArgumentValues.new(@args.to_array)
|
159
|
+
anon = @args.of_type(KXI::CLI::AnonymousArgument).order_by_descending { |a, b| a.order <=> b.order }
|
160
|
+
|
161
|
+
ar = nil
|
162
|
+
args.each do |val|
|
163
|
+
if val.start_with?('-')
|
164
|
+
raise(KXI::Exceptions::ArgumentException.new(ar.name, 'Expected value!')) if ar != nil
|
165
|
+
raise(KXI::Exceptions::ArgumentException.new(val, 'Invalid syntax!')) if val.start_with?('---')
|
166
|
+
if val.start_with?('--')
|
167
|
+
raise(KXI::Exceptions::ArgumentException.new(val, 'Expected argument name!')) if val.length == 2
|
168
|
+
nm = val[2..val.length - 1].downcase
|
169
|
+
arg = @args.first { |i| i.name == nm }
|
170
|
+
raise(KXI::Exceptions::ArgumentException.new(nm, 'No such argument exists!')) if arg == nil
|
171
|
+
if arg.is_a?(KXI::CLI::FlagArgument)
|
172
|
+
vals.set(arg, true)
|
173
|
+
elsif arg.is_a?(KXI::CLI::NamedArgument)
|
174
|
+
ar = arg
|
175
|
+
else
|
176
|
+
raise(KXI::Exceptions::ArgumentException.new(nm, 'Argument cannot be assigned explicitly!'))
|
177
|
+
end
|
178
|
+
else
|
179
|
+
raise(KXI::Exceptions::ArgumentException.new(val, 'Expected short argument name!')) if val.length == 1
|
180
|
+
nm = val[1]
|
181
|
+
arg = @args.of_type(KXI::CLI::ExplicitArgument).first { |i| i.shortcut == nm }
|
182
|
+
raise(KXI::Exceptions::ArgumentException.new(nm, 'No such argument exists!')) if arg == nil
|
183
|
+
if arg.is_a?(KXI::CLI::FlagArgument)
|
184
|
+
vals.set(arg, true)
|
185
|
+
elsif arg.is_a?(KXI::CLI::NamedArgument)
|
186
|
+
if val.length == 2
|
187
|
+
ar = arg
|
188
|
+
else
|
189
|
+
vals.set(arg, val[2..val.length - 1])
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
193
|
+
else
|
194
|
+
if ar != nil
|
195
|
+
vals.set(ar, val)
|
196
|
+
ar = nil
|
197
|
+
else
|
198
|
+
an = anon.first
|
199
|
+
raise(KXI::Exceptions::NoArgumentException.new(val)) if an == nil
|
200
|
+
vals.set(an, val)
|
201
|
+
anon.remove_at(0) unless an.variadic?
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|
205
|
+
vals.finish
|
206
|
+
if @action == nil
|
207
|
+
raise(KXI::Exceptions::NotImplementedException.new)
|
208
|
+
else
|
209
|
+
@action.call(vals)
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
# Prints help message of verb
|
216
|
+
def help
|
217
|
+
puts(@name)
|
218
|
+
puts("\t#{@desc}")
|
219
|
+
puts
|
220
|
+
puts('Usage:')
|
221
|
+
if @verbs.count == 0
|
222
|
+
print("\t")
|
223
|
+
print("#{@ctx} ") if @ctx != nil
|
224
|
+
print(@name)
|
225
|
+
args = @args.order_by_descending { |a, b| a.order <=> b.order }
|
226
|
+
args.where { |i| i.required? or i.is_a?(KXI::CLI::AnonymousArgument) }.foreach do |i|
|
227
|
+
print(" #{i.syntax}")
|
228
|
+
end
|
229
|
+
puts
|
230
|
+
if args.count > 0
|
231
|
+
puts
|
232
|
+
max = args.max { |a, b| a.headline.length <=> b.headline.length }.headline.length
|
233
|
+
args.foreach do |a|
|
234
|
+
puts("\t#{a.headline.ljust(max)} #{a.description}")
|
235
|
+
end
|
236
|
+
end
|
237
|
+
else
|
238
|
+
max = @verbs.max { |a, b| a.name.length <=> b.name.length }.name.length
|
239
|
+
@verbs.foreach do |v|
|
240
|
+
print("\t")
|
241
|
+
print("#{@ctx} ") if @ctx != nil
|
242
|
+
puts("#{@name} #{v.name.ljust(max)} #{v.description}")
|
243
|
+
end
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
# Adds argument
|
248
|
+
# @param arg [KXI::CLI::Argument] Argument to add
|
249
|
+
def add_argument(arg)
|
250
|
+
check_name(arg.name)
|
251
|
+
if arg.is_a?(KXI::CLI::ExplicitArgument) and arg.shortcut != nil
|
252
|
+
raise(Exception.new("Short name '#{arg.shortcut}' is already in use!")) if @args.of_type(KXI::CLI::ExplicitArgument).any { |i| i.shortcut == arg.shortcut }
|
253
|
+
end
|
254
|
+
if arg.is_a?(KXI::CLI::AnonymousArgument) and arg.variadic?
|
255
|
+
raise(Exception.new("Verb can have only one variadic anonymous argument! (argument '#{arg.name}')")) if @args.of_type(KXI::CLI::AnonymousArgument).any { |i| i.variadic? }
|
256
|
+
raise(Exception.new("Verb cannot contain both optional and variadic anonymous arguments! (argument '#{arg.name}')")) if @args.of_type(KXI::CLI::AnonymousArgument).any { |i| not i.required? }
|
257
|
+
end
|
258
|
+
@args.add(arg)
|
259
|
+
@verbs.foreach { |i| i.add_argument(arg) }
|
260
|
+
return arg
|
261
|
+
end
|
262
|
+
|
263
|
+
# Adds child verb
|
264
|
+
# @param v [KXI::CLI::Verb] Verb to add
|
265
|
+
def add_verb(v)
|
266
|
+
@args.foreach { |a| v.add_argument(a) }
|
267
|
+
@verbs.add(v)
|
268
|
+
v.enable_help if @help
|
269
|
+
return v
|
270
|
+
end
|
271
|
+
|
272
|
+
# Checks an argument name
|
273
|
+
# @param [string] nm Name to check
|
274
|
+
def check_name(nm)
|
275
|
+
raise(Exception.new('Name must contain at least two characters!')) if nm == nil or nm.length < 2
|
276
|
+
nm = nm.downcase
|
277
|
+
raise(Exception.new("Name '#{nm}' is already in use!")) unless @verbs.all { |i| i.name != nm } && @args.all { |i| i.name != nm }
|
278
|
+
end
|
279
|
+
|
280
|
+
private :check_name
|
281
|
+
end
|
282
|
+
end
|
281
283
|
end
|