kxi 1.0.1 → 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/lib/kxi.rb +44 -39
  3. data/lib/kxi/application/config.rb +177 -177
  4. data/lib/kxi/application/config_reader.rb +16 -16
  5. data/lib/kxi/application/event.rb +35 -35
  6. data/lib/kxi/application/logger.rb +155 -155
  7. data/lib/kxi/application/version.rb +106 -74
  8. data/lib/kxi/application/version_expression.rb +94 -69
  9. data/lib/kxi/application/workspace.rb +105 -0
  10. data/lib/kxi/cli/anonymous_argument.rb +50 -50
  11. data/lib/kxi/cli/argument.rb +56 -56
  12. data/lib/kxi/cli/argument_values.rb +83 -83
  13. data/lib/kxi/cli/explicit_argument.rb +38 -38
  14. data/lib/kxi/cli/flag_argument.rb +15 -15
  15. data/lib/kxi/cli/named_argument.rb +59 -59
  16. data/lib/kxi/cli/property_list.rb +57 -48
  17. data/lib/kxi/cli/table.rb +82 -62
  18. data/lib/kxi/cli/verb.rb +282 -280
  19. data/lib/kxi/collections/array_collection.rb +106 -106
  20. data/lib/kxi/collections/enumerable.rb +527 -527
  21. data/lib/kxi/collections/enumerator.rb +31 -31
  22. data/lib/kxi/collections/hash_collection.rb +100 -100
  23. data/lib/kxi/collections/protected_collection.rb +20 -19
  24. data/lib/kxi/exceptions/abstract_exception.rb +34 -34
  25. data/lib/kxi/exceptions/argument_exception.rb +21 -21
  26. data/lib/kxi/exceptions/collection_exception.rb +13 -13
  27. data/lib/kxi/exceptions/configuration_exception.rb +36 -25
  28. data/lib/kxi/exceptions/dimension_mismatch_exception.rb +29 -0
  29. data/lib/kxi/exceptions/invalid_type_exception.rb +32 -32
  30. data/lib/kxi/exceptions/no_argument_exception.rb +20 -20
  31. data/lib/kxi/exceptions/not_implemented_exception.rb +12 -12
  32. data/lib/kxi/exceptions/out_of_range_exception.rb +43 -43
  33. data/lib/kxi/exceptions/parse_exception.rb +28 -20
  34. data/lib/kxi/exceptions/verb_expected_exception.rb +20 -20
  35. data/lib/kxi/exceptions/workspace_collision_exception.rb +21 -0
  36. data/lib/kxi/math/math.rb +45 -0
  37. data/lib/kxi/math/matrix.rb +303 -0
  38. data/lib/kxi/math/polynomial.rb +141 -101
  39. data/lib/kxi/math/vector.rb +181 -0
  40. data/lib/kxi/platform.rb +103 -57
  41. data/lib/kxi/reflection/stack_frame.rb +80 -80
  42. data/lib/kxi/version.rb +4 -4
  43. metadata +8 -3
  44. data/lib/kxi/exceptions/invalid_operation_exception.rb +0 -11
@@ -1,63 +1,83 @@
1
- # Created by Matyáš Pokorný on 2018-01-24.
2
-
3
- module KXI
4
- module CLI
5
- class Table
6
- def initialize
7
- @cols = KXI::Collections::ArrayCollection.new
8
- @rows = 0
9
- yield(self) if block_given?
10
- end
11
-
12
- def column(name)
13
- col = Column.new(name)
14
- @cols.add(col)
15
- return col
16
- end
17
-
18
- def row(e)
19
- e.each_key { |c| @cols.first { |i| i.name == c }&.row(e[c].to_s.strip.chomp) }
20
- @rows += 1
21
- end
22
-
23
- def render
24
- @rows.times do |row|
25
- f = true
26
- @cols.foreach do |col|
27
- print(' ') unless f
28
- f = false
29
- col.write(row)
30
- end
31
- puts
32
- end
33
- end
34
-
35
- class Column
36
- def align
37
- @align
38
- end
39
-
40
- def name
41
- @name
42
- end
43
-
44
- def initialize(name)
45
- @name = name
46
- @align = 0
47
- @data = []
48
- end
49
-
50
- def row(str)
51
- @align = str.length if @align < str.length
52
- @data.push(str)
53
- end
54
-
55
- def write(row)
56
- str = @data[row]
57
- str = '' if str == nil
58
- print(str.ljust(@align))
59
- end
60
- end
61
- end
62
- end
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
@@ -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
- def check_name(nm)
273
- raise(Exception.new('Name must contain at least two characters!')) if nm == nil or nm.length < 2
274
- nm = nm.downcase
275
- raise(Exception.new("Name '#{nm}' is already in use!")) unless @verbs.all { |i| i.name != nm } && @args.all { |i| i.name != nm }
276
- end
277
-
278
- private :check_name
279
- end
280
- end
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