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.
- checksums.yaml +4 -4
- data/lib/kxi.rb +44 -39
- data/lib/kxi/application/config.rb +177 -177
- data/lib/kxi/application/config_reader.rb +16 -16
- data/lib/kxi/application/event.rb +35 -35
- data/lib/kxi/application/logger.rb +155 -155
- data/lib/kxi/application/version.rb +106 -74
- data/lib/kxi/application/version_expression.rb +94 -69
- data/lib/kxi/application/workspace.rb +105 -0
- data/lib/kxi/cli/anonymous_argument.rb +50 -50
- data/lib/kxi/cli/argument.rb +56 -56
- data/lib/kxi/cli/argument_values.rb +83 -83
- data/lib/kxi/cli/explicit_argument.rb +38 -38
- data/lib/kxi/cli/flag_argument.rb +15 -15
- data/lib/kxi/cli/named_argument.rb +59 -59
- data/lib/kxi/cli/property_list.rb +57 -48
- data/lib/kxi/cli/table.rb +82 -62
- data/lib/kxi/cli/verb.rb +282 -280
- data/lib/kxi/collections/array_collection.rb +106 -106
- data/lib/kxi/collections/enumerable.rb +527 -527
- data/lib/kxi/collections/enumerator.rb +31 -31
- data/lib/kxi/collections/hash_collection.rb +100 -100
- data/lib/kxi/collections/protected_collection.rb +20 -19
- data/lib/kxi/exceptions/abstract_exception.rb +34 -34
- data/lib/kxi/exceptions/argument_exception.rb +21 -21
- data/lib/kxi/exceptions/collection_exception.rb +13 -13
- data/lib/kxi/exceptions/configuration_exception.rb +36 -25
- data/lib/kxi/exceptions/dimension_mismatch_exception.rb +29 -0
- data/lib/kxi/exceptions/invalid_type_exception.rb +32 -32
- data/lib/kxi/exceptions/no_argument_exception.rb +20 -20
- data/lib/kxi/exceptions/not_implemented_exception.rb +12 -12
- data/lib/kxi/exceptions/out_of_range_exception.rb +43 -43
- data/lib/kxi/exceptions/parse_exception.rb +28 -20
- data/lib/kxi/exceptions/verb_expected_exception.rb +20 -20
- data/lib/kxi/exceptions/workspace_collision_exception.rb +21 -0
- data/lib/kxi/math/math.rb +45 -0
- data/lib/kxi/math/matrix.rb +303 -0
- data/lib/kxi/math/polynomial.rb +141 -101
- data/lib/kxi/math/vector.rb +181 -0
- data/lib/kxi/platform.rb +103 -57
- data/lib/kxi/reflection/stack_frame.rb +80 -80
- data/lib/kxi/version.rb +4 -4
- metadata +8 -3
- 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
|
data/lib/kxi/platform.rb
CHANGED
@@ -1,58 +1,104 @@
|
|
1
|
-
# Created by Matyáš Pokorný on 2018-01-28.
|
2
|
-
|
3
|
-
module KXI
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
@version
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
def
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
end
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
end
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
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
|