kxi 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: a376bd573bfb44dbeae16f773f883a1f55daedd7
4
+ data.tar.gz: 4cbb2897d3c73fe15b882a26d79f8d3bdc387244
5
+ SHA512:
6
+ metadata.gz: 7d040d8a1a051f68268ba981ea84e69fcf5bd547f801c3411511bcb3b3edd2da4e23befcb9171fe6b43655bdd2adca2ef6b8de387fa5874f8d8b76b79cbabac7
7
+ data.tar.gz: c35695494016d0625076379ffcc9370e5c4299cc47cc19f4979d10ee0cd4f9ac01c3d4f3e27051f1c2859c18a4099aa830324545fb1ef0d0ab45ec671c405ed8
@@ -0,0 +1,51 @@
1
+ # Created by Matyáš Pokorný on 2018-01-20.
2
+
3
+ module KXI
4
+ module CLI
5
+ # Represents anonymous argument (eg.: verb VALUE)
6
+ class AnonymousArgument < KXI::CLI::Argument
7
+ # Gets default value of argument
8
+ # @return [Object] Default value of argument
9
+ def default
10
+ @def
11
+ end
12
+
13
+ # Gets whether argument is variadic
14
+ # @return [Bool] True if argument is variadic; false otherwise
15
+ def variadic?
16
+ @var
17
+ end
18
+
19
+ # Gets syntax of argument
20
+ # @return [String] Syntax of argument
21
+ def syntax
22
+ "#{required? ? '<' : '['}#{name}#{required? ? '>' : ']'}"
23
+ end
24
+
25
+ # Gets full descriptive name of argument
26
+ # @return [String] Full name of argument
27
+ def headline
28
+ super.upcase
29
+ end
30
+
31
+ # Instantiates the {KXI::CLI::AnonymousArgument} class
32
+ # @param nm [String] Name of argument
33
+ # @param desc [String] Description of argument
34
+ # @param rq [Bool] Indicates whether argument is required
35
+ # @param df Default value of argument
36
+ # @param var [Bool] Indicates whether argument is variadic
37
+ def initialize(nm, desc, rq = true, df = nil, var = false, &validator)
38
+ super(nm, desc, rq, 5 - (var ? 1 : 0) - (rq ? 0 : 1))
39
+ @def = df
40
+ @var = var
41
+ @val = validator
42
+ end
43
+
44
+ # Validates value of argument
45
+ # @param val [String, Array<String>] Value of argument
46
+ def validate(val)
47
+ @val.call(val) if @val != nil
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,57 @@
1
+ # Created by Matyáš Pokorný on 2018-01-20.
2
+
3
+ module KXI
4
+ module CLI
5
+ # Represents argument of command-line interface
6
+ class Argument
7
+ # Gets the name of argument
8
+ # @return [String] Name of argument
9
+ def name
10
+ @name
11
+ end
12
+
13
+ # Gets syntax of argument
14
+ # @return [String] Syntax of argument
15
+ def syntax
16
+ name
17
+ end
18
+
19
+ # Gets full descriptive name of argument
20
+ # @return [String] Full name of argument
21
+ def headline
22
+ name
23
+ end
24
+
25
+ # Gets the description of argument
26
+ # @return [String] Description of argument
27
+ def description
28
+ @desc
29
+ end
30
+
31
+ # Indicates whether argument is mandatory
32
+ # @return [Bool] True if argument is mandatory; otherwise false
33
+ def required?
34
+ @req
35
+ end
36
+
37
+ # Gets the order of argument (in descending order)
38
+ # @return [Number] Order of argument
39
+ def order
40
+ @order
41
+ end
42
+
43
+ # Instantiates the {KXI::CLI::Argument} class
44
+ # @param nm [String] Name of argument
45
+ # @param desc [String] Description of argument
46
+ # @param req [Bool] Determines whether argument is mandatory
47
+ # @param order [Number] Order of argument
48
+ def initialize(nm, desc, req, order)
49
+ raise(Exception.new('Invalid argument name!')) unless /^[A-Za-z0-9\-]+$/m =~ nm
50
+ @name = nm.downcase
51
+ @desc = desc
52
+ @req = req
53
+ @order = order
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,84 @@
1
+ # Created by Matyáš Pokorný on 2018-01-21.
2
+
3
+ module KXI
4
+ module CLI
5
+ # Manages values of arguments
6
+ class ArgumentValues
7
+ # Instantiates the {KXI::CLI::ArgumentValues} class
8
+ # @param args [Array<KXI::CLI::Argument>] Expected arguments
9
+ def initialize(args)
10
+ @args = args
11
+ @vals = {}
12
+ args.each do |a|
13
+ if a.is_a?(KXI::CLI::FlagArgument)
14
+ @vals[a.name] = { :argument => a, :value => false }
15
+ end
16
+ end
17
+ end
18
+
19
+ # Assigns (or adds) a value to argument
20
+ # @param arg [KXI::CLI::Argument] Argument to set
21
+ # @param val [String] Value to assign
22
+ def set(arg, val)
23
+ if arg.is_a?(KXI::CLI::FlagArgument)
24
+ raise(KXI::Exceptions::ArgumentException.new(arg.name, 'Flag set multiple times!')) if @vals[arg.name][:value]
25
+ @vals[arg.name][:value] = val
26
+ else
27
+ if arg.variadic?
28
+ @vals[arg.name] = { :argument => arg, :value => [] } if @vals[arg.name] == nil
29
+ @vals[arg.name][:value].push(val)
30
+ else
31
+ raise(KXI::Exceptions::ArgumentException.new(arg.name, 'Argument set multiple times!')) if @vals[arg.name] != nil
32
+ begin
33
+ arg.validate(val)
34
+ rescue Exception => ex
35
+ raise(KXI::Exceptions::ArgumentException.new(arg.name, ex.message))
36
+ end
37
+ @vals[arg.name] = { :argument => arg, :value => val }
38
+ end
39
+ end
40
+ end
41
+
42
+ # Gets value of argument
43
+ # @param index [String, Symbol, KXI::CLI::Argument] Name of argument
44
+ # @return [String] Value of argument
45
+ def []=(index)
46
+ if index.is_a?(Symbol)
47
+ index = index.to_s
48
+ elsif index.is_a?(KXI::CLI::Argument)
49
+ index = index.name
50
+ end
51
+ raise(Exception.new("Undefined argument #{index}!")) if @vals[index] == nil
52
+ return @vals[index][:value]
53
+ end
54
+
55
+ # Converts class to {Hash}
56
+ # @return [Hash] Equivalent hash
57
+ def to_h
58
+ ret = {}
59
+ @vals.each_pair do |k, v|
60
+ ret[k] = v[:value]
61
+ end
62
+ return ret
63
+ end
64
+
65
+ # Validates variadic arguments and checks for minimal argument requirements
66
+ def finish
67
+ @args.each do |arg|
68
+ if @vals[arg.name] != nil
69
+ unless arg.is_a?(KXI::CLI::FlagArgument)
70
+ begin
71
+ arg.validate(@vals[arg.name][:value])
72
+ rescue Exception => ex
73
+ raise(KXI::Exceptions::ArgumentException.new(arg.name, ex.message))
74
+ end
75
+ end
76
+ else
77
+ raise(KXI::Exceptions::ArgumentException.new(arg.name, 'Argument is mandatory!')) if arg.required?
78
+ @vals[arg.name] = arg.default
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,39 @@
1
+ # Created by Matyáš Pokorný on 2018-01-20.
2
+
3
+ module KXI
4
+ module CLI
5
+ # Represents argument specified explicitly with name
6
+ class ExplicitArgument < KXI::CLI::Argument
7
+ # Gets full descriptive name of argument
8
+ # @return [String] Full name of argument
9
+ def headline
10
+ ret = ''
11
+ ret = "-#{@sh}, " if @sh != nil
12
+ ret += "--#{name}"
13
+ return ret
14
+ end
15
+
16
+ # Gets syntax of argument
17
+ # @return [String] Syntax of argument
18
+ def syntax
19
+ headline
20
+ end
21
+
22
+ # Gets the shortcut symbol of argument
23
+ # @return [String] Shortcut symbol of argument
24
+ def shortcut
25
+ @sh
26
+ end
27
+
28
+ # Instantiates the {KXI::CLI::ExplicitArgument} class
29
+ # @param nm [String] Name of argument
30
+ # @param desc [String] Description of argument
31
+ # @param sh [String, nil] Shortcut of argument
32
+ # @param req [Bool] Specifies whether argument is mandatory
33
+ def initialize(nm, desc, sh = nil, req = false)
34
+ super(nm, desc, req, req ? 2 : 1)
35
+ @sh = sh
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,16 @@
1
+ # Created by Matyáš Pokorný on 2018-01-20.
2
+
3
+ module KXI
4
+ module CLI
5
+ # Represents the flag argument (eg.: -f, --flag)
6
+ class FlagArgument < KXI::CLI::ExplicitArgument
7
+ # Instantiates the {KXI::CLI::FlagArgument} class
8
+ # @param nm [String] Name of argument
9
+ # @param desc [String] Description of argument
10
+ # @param sh [String] Shortcut of argument
11
+ def initialize(nm, desc, sh = nil)
12
+ super(nm, desc, sh)
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,60 @@
1
+ # Created by Matyáš Pokorný on 2018-01-20.
2
+
3
+ module KXI
4
+ module CLI
5
+ # Represents named argument (eg.: -a VALUE, --argument VALUE)
6
+ class NamedArgument < KXI::CLI::ExplicitArgument
7
+ # Gets default value of argument
8
+ # @return [Object] Default value of argument
9
+ def default
10
+ @def
11
+ end
12
+
13
+ # Gets whether argument is variadic
14
+ # @return [Bool] True if argument is variadic; false otherwise
15
+ def variadic?
16
+ @var
17
+ end
18
+
19
+ # Gets name of argument value
20
+ # @return [String] Name of argument value
21
+ def value_name
22
+ @vnm
23
+ end
24
+
25
+ # Gets full descriptive name of argument
26
+ # @return [String] Full name of argument
27
+ def headline
28
+ "#{super} #{@var ? '...' : ''}#{@vnm.upcase}"
29
+ end
30
+
31
+ # Gets syntax of argument
32
+ # @return [String] Syntax of argument
33
+ def syntax
34
+ "-#{(shortcut != nil ? shortcut : "-#{name}")} #{required? ? '<' : '['}#{@var ? '...' : ''}#{@vnm}#{required? ? '>' : ']'}"
35
+ end
36
+
37
+ # Instantiates the {KXI::CLI::NamedArgument} class
38
+ # @param nm [String] Name of argument
39
+ # @param vn [String] Name of value
40
+ # @param desc [String] Description of argument
41
+ # @param sh [String] Shortcut of argument
42
+ # @param rq [Bool] Indicates whether argument is required
43
+ # @param df Default value of argument
44
+ # @param var [Bool] Indicates whether argument is variadic
45
+ def initialize(nm, vn, desc, sh = nil, rq = true, df = nil, var = false, &validator)
46
+ super(nm, desc, sh, rq)
47
+ @def = df
48
+ @vnm = vn
49
+ @var = var
50
+ @val = validator
51
+ end
52
+
53
+ # Validates value of argument
54
+ # @param val [String, Array<String>] Value of argument
55
+ def validate(val)
56
+ @val.call(val) if @val != nil
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,281 @@
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)
133
+ args = ARGV if args.length == 0
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.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)
202
+ end
203
+ end
204
+ end
205
+ if @action == nil
206
+ raise(KXI::Exceptions::NotImplementedException.new)
207
+ else
208
+ vals.finish
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
281
+ end