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.
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