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
@@ -0,0 +1,181 @@
1
+ # Created by Matyáš Pokorný on 2018-04-14.
2
+
3
+ module KXI
4
+ module Math
5
+ # Represents a vector
6
+ class Vector
7
+ # Returns the dimension of vector
8
+ # @return [Integer] Dimension of vector
9
+ def dimension
10
+ @dim
11
+ end
12
+
13
+ # Instantiates the {KXI::Math::Vector} class
14
+ # @param [Integer] dim Dimension of vector
15
+ # @yield [d] Generator function
16
+ # @yieldparam Dimension to generate
17
+ # @yieldreturn [Numeric] Result of generator
18
+ # @raise [KXI::Exceptions::InvalidTypeException] When generator function returns value of invalid type
19
+ def initialize(dim)
20
+ @dim = dim
21
+ if block_given?
22
+ @data = []
23
+ dim.times do |d|
24
+ val = yield(d)
25
+ raise(KXI::Exceptions::InvalidTypeException.new(val.type, Numeric)) unless val.is_a?(Numeric)
26
+ @data.push(val.to_f)
27
+ end
28
+ else
29
+ @data = [0.0] * dim
30
+ end
31
+ end
32
+
33
+ def str(num)
34
+ return (num == num.to_i ? num.to_i : num).to_s
35
+ end
36
+
37
+ # Gets the value of vector at specific dimension
38
+ # @param [Integer] idx Dimension to return
39
+ # @raise [KXI::Exceptions::OutOfRangeException] When dimension is out of range
40
+ # @return [Numeric] Value of vector at given dimension
41
+ def [](idx)
42
+ raise(KXI::Exceptions::OutOfRangeException.new(idx, 0, @dim - 1)) if idx < 0 or idx >= @dim
43
+ raise(KXI::Exceptions::InvalidTypeException.new(value.type, Numeric)) unless value.is_a?(Numeric)
44
+ return @data[idx]
45
+ end
46
+
47
+ # Sets the value of vector at specific dimension
48
+ # @overload []=(idx, val)
49
+ # Sets the value of vector at specific dimension
50
+ # @param [Integer] idx Dimension to set
51
+ # @param [Integer] val Value to set the dimension to
52
+ # @raise [KXI::Exceptions::OutOfRangeException] When dimension is out of range
53
+ # @raise [KXI::Exceptions::InvalidTypeException] When value has invalid type
54
+ # @return [Numeric] Value passed to function
55
+ # @overload []=(idx, val)
56
+ # Sets the values of vector to range of values starting from specific dimension
57
+ # @param [Integer] idx Dimension to start at
58
+ # @param [Array] val Values to set the dimensions to
59
+ # @raise [KXI::Exceptions::OutOfRangeException] When dimension is out of range
60
+ # @raise [KXI::Exceptions::InvalidTypeException] When value has invalid type
61
+ # @return [Numeric] Value passed to function
62
+ def []=(idx, val)
63
+ raise(KXI::Exceptions::OutOfRangeException.new(idx, 0, @dim - 1)) if idx < 0 or idx >= @dim
64
+ if val.is_a?(Numeric)
65
+ @data[idx] = val.to_f
66
+ elsif val.is_a?(Array)
67
+ i = 0
68
+ while idx + i < @dim and i < val.length
69
+ v = val[i]
70
+ raise(KXI::Exceptions::InvalidTypeException.new(v.type, Numeric)) unless v.is_a?(Numeric)
71
+ @data[idx + i] = v.to_f
72
+ end
73
+ else
74
+ raise(KXI::Exceptions::InvalidTypeException.new(val.type, Numeric, Array))
75
+ end
76
+ return val
77
+ end
78
+
79
+ # Iterates over each element of vector
80
+ # @yield [d, val] Iterator function
81
+ # @yieldparam [Integer] d Dimension passed to iterator
82
+ # @yieldparam [Numeric] val Value at that specific dimension
83
+ def each
84
+ return unless block_given?
85
+ @dim.times do |d|
86
+ yield(d, @data[d])
87
+ end
88
+ end
89
+
90
+ # Dot multiplies vectors
91
+ # @param [KXI::Math::Vector] vec Vector to multiply with
92
+ # @return [Numeric] Dot product of vectors
93
+ def dot(vec)
94
+ raise(KXI::Exception::DimensionMismatchException.new(vec.dimension, dimension)) unless vec.dimension == dimension
95
+ sum = 0
96
+ @dim.times { |d| sum += @data[d] * vec[d] }
97
+ return sum
98
+ end
99
+
100
+ # Converts vector to string
101
+ # @param [Boolean] d Determines whether string should be decorated
102
+ # @return [String] String representation of vector
103
+ def to_s(d = true)
104
+ just = 0
105
+ @dim.times { |m| len = str(@data[m]).length; just = len if len > just }
106
+ ret = ''
107
+ @dim.times do |m|
108
+ ret += $/ if m > 0
109
+ ret += '|' if d
110
+ ret += str(@data[m]).rjust(just, ' ')
111
+ ret += '|' if d
112
+ end
113
+ return ret
114
+ end
115
+
116
+ # Adds vectors
117
+ # @param [Vector] other Vector to add
118
+ # @raise [KXI::Exceptions::InvalidTypeException] When type of value is invalid
119
+ # @return [KXI::Math::Vector] New vector equivalent to the sum of vectors
120
+ def +(other)
121
+ if other.is_a?(KXI::Math::Vector)
122
+ return KXI::Math::Vector.new(@dim) { |d| @data[d] + other[d] }
123
+ else
124
+ raise(KXI::Exceptions::InvalidTypeException.new(other.class, Numeric))
125
+ end
126
+ end
127
+
128
+ # Subtracts vectors
129
+ # @param [Vector] other Vector to subtract
130
+ # @raise [KXI::Exceptions::InvalidTypeException] When type of value is invalid
131
+ # @return [KXI::Math::Vector] New vector equivalent to the difference of vectors
132
+ def -(other)
133
+ if other.is_a?(KXI::Math::Vector)
134
+ return KXI::Math::Vector.new(@dim) { |d| @data[d] - other[d] }
135
+ else
136
+ raise(KXI::Exceptions::InvalidTypeException.new(other.class, Numeric))
137
+ end
138
+ end
139
+
140
+ # Multiplies the vector with -1
141
+ # @return [KXI::Math::Vector] New opposite vector
142
+ def -@
143
+ return KXI::Math::Vector.new(@dim) { |d| -@data[d] }
144
+ end
145
+
146
+ # Multiplies vector
147
+ # @overload *(other)
148
+ # Preforms scalar-vector multiplication
149
+ # @param [Numeric] other Scalar to multiply with
150
+ # @raise [KXI::Exceptions::InvalidTypeException] When other value is of invalid type
151
+ # @return [KXI::Math::Vector] New vector equivalent to the scaled vector
152
+ # @overload *(other)
153
+ # Preforms vector-vector multiplication
154
+ # @param [Numeric] other Vector to multiply with
155
+ # @raise [KXI::Exceptions::InvalidTypeException] When other value is of invalid type
156
+ # @return [KXI::Math::Vector] New vector equivalent to the multiplied vector
157
+ def *(other)
158
+ if other.is_a?(Numeric)
159
+ return KXI::Math::Vector.new(@dim) { |d| other * @data[d] }
160
+ elsif other.is_a?(KXI::Math::Vector)
161
+ return KXI::Math::Vector.new(@dim) { |d| @data[d] * other[d] }
162
+ elsif raise(KXI::Exceptions::InvalidTypeException.new(other.class, Numeric, KXI::Math::Vector))
163
+ end
164
+ end
165
+
166
+ # Compares vector
167
+ # @param [void] other Value to compare to
168
+ # @return [Boolean] True if vector is equivalent to given value; false otherwise
169
+ def ==(other)
170
+ return false unless other.is_a?(KXI::Math::Vector)
171
+ return false if @dim != other.dimension
172
+ @dim.times do |d|
173
+ return false if @data[d] != other[d]
174
+ end
175
+ return true
176
+ end
177
+
178
+ private :str
179
+ end
180
+ end
181
+ end
@@ -1,58 +1,104 @@
1
- # Created by Matyáš Pokorný on 2018-01-28.
2
-
3
- module KXI
4
- class Platform
5
- def name
6
- @name
7
- end
8
-
9
- def version
10
- @version
11
- end
12
-
13
- def library_extensions
14
- @libs
15
- end
16
-
17
- def path_separator
18
- @ps
19
- end
20
-
21
- def initialize(nm, ver, ps, *libs)
22
- @name = nm
23
- @version = KXI::Application::Version.parse(ver)
24
- @ps = ps
25
- @libs = libs
26
- end
27
-
28
- def self.this
29
- if /cygwin|mswin|mingw|bccwin|wince|emx/ =~ RUBY_PLATFORM
30
- return Platform.new('windows', `wmic os get Version /value`.split('=').last.strip.chomp, ';', 'dll')
31
- elsif /darwin/ =~ RUBY_PLATFORM
32
- return Platform.new('osx', `defaults read loginwindow SystemVersionStampAsString`, ':', 'dylib')
33
- else
34
- return Platform.new('linux', `uname -r`.split('-')[0], ':', 'so')
35
- end
36
- end
37
-
38
- def exec(name, *dir)
39
- dir = Platform.env('path').split(@ps) if dir.length == 0
40
- ext = Platform.env('pathext')
41
- (ext != nil ? ext.split(@ps) + [''] : ['']).each do |e|
42
- dir.each do |d|
43
- f = File.join(d, "#{name}#{e}")
44
- return f if File.exists?(f)
45
- end
46
- end
47
- return nil
48
- end
49
-
50
- def self.env(key)
51
- key = key.downcase
52
- ENV.each_pair do |k, v|
53
- return v if k.downcase == key
54
- end
55
- return nil
56
- end
57
- end
1
+ # Created by Matyáš Pokorný on 2018-01-28.
2
+
3
+ module KXI
4
+ # Represents an platform of execution
5
+ class Platform
6
+ @@this = nil
7
+ # Microsoft Windows
8
+ WINDOWS = 'windows'
9
+ # Apple macOS
10
+ OSX = 'osx'
11
+ # Linux-based system
12
+ LINUX = 'linux'
13
+
14
+ # Gets the name of platform
15
+ # @return [string] Name of platform
16
+ def name
17
+ @name
18
+ end
19
+
20
+ # Gets the version of platform
21
+ # @return [KXI::Application::Version] Version of platform
22
+ def version
23
+ @version
24
+ end
25
+
26
+ # Gets the file extensions of libraries
27
+ # @return [Array<string>] File extensions of libraries
28
+ def library_extensions
29
+ @libs
30
+ end
31
+
32
+ # Gets the separator of paths
33
+ # @return [string] Separator of paths
34
+ def path_separator
35
+ @ps
36
+ end
37
+
38
+ # Gets the separator of directories within a path
39
+ # @return [string] Separator of directories
40
+ def directory_separator
41
+ @ds
42
+ end
43
+
44
+ # Determines whether paths are case-sensitive
45
+ # @return [bool] True if paths are case-sensitive; false otherwise
46
+ def path_case_sensitive?
47
+ @cs
48
+ end
49
+
50
+ # Instantiates the {KXI::Platform} class
51
+ # @param [string] nm Name of platform
52
+ # @param [string] ver Version of platform
53
+ # @param [string] ds Directory separator
54
+ # @param [string] ps Path separator
55
+ # @param [string] cs Determines whether paths are case-sensitive
56
+ # @param [string] libs File extensions of libraries
57
+ def initialize(nm, ver, ds, ps, cs, *libs)
58
+ @name = nm
59
+ @version = KXI::Application::Version.parse(ver)
60
+ @ds = ds
61
+ @ps = ps
62
+ @cs = cs
63
+ @libs = libs
64
+ end
65
+
66
+ # Gets the current platform
67
+ # @return [KXI::Platform] Current platform
68
+ def self.this
69
+ return @@this if @@this != nil
70
+ if /cygwin|mswin|mingw|bccwin|wince|emx/ =~ RUBY_PLATFORM
71
+ @@this = Platform.new(WINDOWS, `wmic os get Version /value`.split('=').last.strip.chomp, '\\', ';', false, 'dll')
72
+ elsif /darwin/ =~ RUBY_PLATFORM
73
+ @@this = Platform.new(OSX, `defaults read loginwindow SystemVersionStampAsString`, '/', ':', true, 'dylib')
74
+ else
75
+ @@this = Platform.new(LINUX, `uname -r`.split('-')[0], '/', ':', true, 'so')
76
+ end
77
+ return @@this
78
+ end
79
+
80
+ # Finds an executable within the PATH of platform
81
+ # @return [string,nil] Path of executable if found; otherwise nil
82
+ def exec(name, *dir)
83
+ dir = Platform.env('path').split(@ps) if dir.length == 0
84
+ ext = Platform.env('pathext')
85
+ (ext != nil ? ext.split(@ps) + [''] : ['']).each do |e|
86
+ dir.each do |d|
87
+ f = File.join(d, "#{name}#{e}")
88
+ return f if File.exists?(f)
89
+ end
90
+ end
91
+ return nil
92
+ end
93
+
94
+ # Gets an environment variable
95
+ # @return [string] Value of environment variable if found; otherwise nil
96
+ def self.env(key)
97
+ key = key.downcase
98
+ ENV.each_pair do |k, v|
99
+ return v if k.downcase == key
100
+ end
101
+ return nil
102
+ end
103
+ end
58
104
  end
@@ -1,81 +1,81 @@
1
- # Created by Matyáš Pokorný on 2017-12-28.
2
- module KXI
3
- module Reflection
4
- # Represents frame of call stack
5
- class StackFrame
6
- # Returns the file of frame
7
- # @return [String] File of frame
8
- def file
9
- @file
10
- end
11
-
12
- # Returns the line number of frame
13
- # @return [Number] Line number of frame
14
- def line
15
- @line
16
- end
17
-
18
- # Returns the context of frame
19
- # @return [String] Context of frame
20
- def context
21
- @context
22
- end
23
-
24
- # Indicates whether frame is block
25
- # @return [Bool] True if stack frame represents call to block; false otherwise
26
- def block?
27
- @block != nil
28
- end
29
-
30
- # Returns containing method of frame; nil if none
31
- # @return [String, nil] Name of method that the stack frame represents
32
- def method
33
- return nil if @block != nil and @block[0] == '<' and @block[@block.length - 1] == '>'
34
- return @block unless @block == nil
35
- return nil if @context != nil and @context[0] == '<' and @context[@context.length - 1] == '>'
36
- @context
37
- end
38
-
39
- # Instantiates the {KXI::Reflection::StackFrame} class
40
- # @param file [String] File of frame
41
- # @param line [Number] Line number of frame
42
- # @param context [String, nil] Context of frame
43
- def initialize(file, line, context = nil)
44
- @file = file
45
- @line = line
46
- @context = context
47
- if context == nil
48
- @block = nil
49
- else
50
- mt = /^block (\((?'levels'\d+) levels\) )?in (?'method'.+)$/mi.match(context)
51
- @block = mt == nil ? nil : mt['method']
52
- end
53
- end
54
-
55
- # Converts class to string
56
- # @return [String] Equivalent string
57
- def to_s
58
- "#{@file}:#{@line}#{(@context != nil ? ": in `#{@context}'" : '')}"
59
- end
60
-
61
- # Parses callstack into array of {KXI::Reflection::StackFrame}
62
- # @param skip [Number] Number of callstack records to ignore
63
- # @return [Array<KXI::Reflection::StackFrame>] Equivalent array of stack frames
64
- def self.callstack(skip = 1)
65
- ret = []
66
- caller(skip).each do |bt|
67
- ret.push(from_backtrace(bt))
68
- end
69
- return ret
70
- end
71
-
72
- # Parses backtrace line into {KXI::Reflection::StackFrame}
73
- # @param bt [String] Backtrace line
74
- # @return [KXI::Reflection::StackFrame] Equivalent stack frame
75
- def self.from_backtrace(bt)
76
- mt = /(?'file'.+?):(?'line'\d+)(:\s*in\s*`(?'context'.+?)')?/.match(bt)
77
- StackFrame.new(mt['file'], mt['line'].to_i, mt['context'])
78
- end
79
- end
80
- end
1
+ # Created by Matyáš Pokorný on 2017-12-28.
2
+ module KXI
3
+ module Reflection
4
+ # Represents frame of call stack
5
+ class StackFrame
6
+ # Returns the file of frame
7
+ # @return [String] File of frame
8
+ def file
9
+ @file
10
+ end
11
+
12
+ # Returns the line number of frame
13
+ # @return [Number] Line number of frame
14
+ def line
15
+ @line
16
+ end
17
+
18
+ # Returns the context of frame
19
+ # @return [String] Context of frame
20
+ def context
21
+ @context
22
+ end
23
+
24
+ # Indicates whether frame is block
25
+ # @return [Bool] True if stack frame represents call to block; false otherwise
26
+ def block?
27
+ @block != nil
28
+ end
29
+
30
+ # Returns containing method of frame; nil if none
31
+ # @return [String, nil] Name of method that the stack frame represents
32
+ def method
33
+ return nil if @block != nil and @block[0] == '<' and @block[@block.length - 1] == '>'
34
+ return @block unless @block == nil
35
+ return nil if @context != nil and @context[0] == '<' and @context[@context.length - 1] == '>'
36
+ @context
37
+ end
38
+
39
+ # Instantiates the {KXI::Reflection::StackFrame} class
40
+ # @param file [String] File of frame
41
+ # @param line [Number] Line number of frame
42
+ # @param context [String, nil] Context of frame
43
+ def initialize(file, line, context = nil)
44
+ @file = file
45
+ @line = line
46
+ @context = context
47
+ if context == nil
48
+ @block = nil
49
+ else
50
+ mt = /^block (\((?'levels'\d+) levels\) )?in (?'method'.+)$/mi.match(context)
51
+ @block = mt == nil ? nil : mt['method']
52
+ end
53
+ end
54
+
55
+ # Converts class to string
56
+ # @return [String] Equivalent string
57
+ def to_s
58
+ "#{@file}:#{@line}#{(@context != nil ? ": in `#{@context}'" : '')}"
59
+ end
60
+
61
+ # Parses callstack into array of {KXI::Reflection::StackFrame}
62
+ # @param skip [Number] Number of callstack records to ignore
63
+ # @return [Array<KXI::Reflection::StackFrame>] Equivalent array of stack frames
64
+ def self.callstack(skip = 1)
65
+ ret = []
66
+ caller(skip).each do |bt|
67
+ ret.push(from_backtrace(bt))
68
+ end
69
+ return ret
70
+ end
71
+
72
+ # Parses backtrace line into {KXI::Reflection::StackFrame}
73
+ # @param bt [String] Backtrace line
74
+ # @return [KXI::Reflection::StackFrame] Equivalent stack frame
75
+ def self.from_backtrace(bt)
76
+ mt = /(?'file'.+?):(?'line'\d+)(:\s*in\s*`(?'context'.+?)')?/.match(bt)
77
+ StackFrame.new(mt['file'], mt['line'].to_i, mt['context'])
78
+ end
79
+ end
80
+ end
81
81
  end