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