keisan 0.5.0 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +49 -1
- data/keisan.gemspec +1 -0
- data/lib/keisan.rb +30 -0
- data/lib/keisan/ast/assignment.rb +44 -17
- data/lib/keisan/ast/block.rb +60 -0
- data/lib/keisan/ast/boolean.rb +5 -5
- data/lib/keisan/ast/builder.rb +10 -207
- data/lib/keisan/ast/cell.rb +60 -0
- data/lib/keisan/ast/constant_literal.rb +9 -0
- data/lib/keisan/ast/exponent.rb +6 -6
- data/lib/keisan/ast/function.rb +12 -8
- data/lib/keisan/ast/indexing.rb +25 -15
- data/lib/keisan/ast/line_builder.rb +230 -0
- data/lib/keisan/ast/list.rb +28 -1
- data/lib/keisan/ast/literal.rb +0 -8
- data/lib/keisan/ast/logical_and.rb +1 -1
- data/lib/keisan/ast/logical_or.rb +1 -1
- data/lib/keisan/ast/multi_line.rb +28 -0
- data/lib/keisan/ast/node.rb +32 -24
- data/lib/keisan/ast/number.rb +31 -31
- data/lib/keisan/ast/operator.rb +12 -4
- data/lib/keisan/ast/parent.rb +4 -4
- data/lib/keisan/ast/plus.rb +10 -10
- data/lib/keisan/ast/string.rb +3 -3
- data/lib/keisan/ast/times.rb +8 -8
- data/lib/keisan/ast/unary_identity.rb +1 -1
- data/lib/keisan/ast/unary_inverse.rb +7 -7
- data/lib/keisan/ast/unary_minus.rb +5 -5
- data/lib/keisan/ast/unary_operator.rb +2 -2
- data/lib/keisan/ast/unary_plus.rb +2 -2
- data/lib/keisan/ast/variable.rb +26 -10
- data/lib/keisan/context.rb +5 -5
- data/lib/keisan/evaluator.rb +15 -8
- data/lib/keisan/function.rb +24 -6
- data/lib/keisan/functions/cbrt.rb +1 -1
- data/lib/keisan/functions/cos.rb +1 -1
- data/lib/keisan/functions/cosh.rb +1 -1
- data/lib/keisan/functions/cot.rb +1 -1
- data/lib/keisan/functions/coth.rb +1 -1
- data/lib/keisan/functions/csc.rb +1 -1
- data/lib/keisan/functions/csch.rb +1 -1
- data/lib/keisan/functions/default_registry.rb +53 -74
- data/lib/keisan/functions/diff.rb +18 -14
- data/lib/keisan/functions/erf.rb +15 -0
- data/lib/keisan/functions/exp.rb +1 -1
- data/lib/keisan/functions/expression_function.rb +15 -21
- data/lib/keisan/functions/filter.rb +13 -15
- data/lib/keisan/functions/if.rb +14 -20
- data/lib/keisan/functions/let.rb +36 -0
- data/lib/keisan/functions/map.rb +11 -13
- data/lib/keisan/functions/math_function.rb +2 -2
- data/lib/keisan/functions/proc_function.rb +10 -6
- data/lib/keisan/functions/rand.rb +2 -1
- data/lib/keisan/functions/range.rb +74 -0
- data/lib/keisan/functions/reduce.rb +12 -14
- data/lib/keisan/functions/registry.rb +7 -7
- data/lib/keisan/functions/replace.rb +8 -8
- data/lib/keisan/functions/sample.rb +2 -1
- data/lib/keisan/functions/sec.rb +1 -1
- data/lib/keisan/functions/sech.rb +1 -1
- data/lib/keisan/functions/sin.rb +1 -1
- data/lib/keisan/functions/sinh.rb +1 -1
- data/lib/keisan/functions/sqrt.rb +1 -1
- data/lib/keisan/functions/tan.rb +1 -1
- data/lib/keisan/functions/tanh.rb +1 -1
- data/lib/keisan/functions/while.rb +46 -0
- data/lib/keisan/parser.rb +121 -79
- data/lib/keisan/parsing/assignment.rb +1 -1
- data/lib/keisan/parsing/bitwise_and.rb +1 -1
- data/lib/keisan/parsing/bitwise_not.rb +1 -1
- data/lib/keisan/parsing/bitwise_not_not.rb +1 -1
- data/lib/keisan/parsing/bitwise_or.rb +1 -1
- data/lib/keisan/parsing/bitwise_xor.rb +1 -1
- data/lib/keisan/parsing/curly_group.rb +6 -0
- data/lib/keisan/parsing/divide.rb +1 -1
- data/lib/keisan/parsing/exponent.rb +1 -1
- data/lib/keisan/parsing/function.rb +1 -1
- data/lib/keisan/parsing/group.rb +1 -1
- data/lib/keisan/parsing/indexing.rb +1 -1
- data/lib/keisan/parsing/line_separator.rb +6 -0
- data/lib/keisan/parsing/logical_and.rb +1 -1
- data/lib/keisan/parsing/logical_equal.rb +1 -1
- data/lib/keisan/parsing/logical_greater_than.rb +1 -1
- data/lib/keisan/parsing/logical_greater_than_or_equal_to.rb +1 -1
- data/lib/keisan/parsing/logical_less_than.rb +1 -1
- data/lib/keisan/parsing/logical_less_than_or_equal_to.rb +1 -1
- data/lib/keisan/parsing/logical_not.rb +1 -1
- data/lib/keisan/parsing/logical_not_equal.rb +1 -1
- data/lib/keisan/parsing/logical_not_not.rb +1 -1
- data/lib/keisan/parsing/logical_or.rb +1 -1
- data/lib/keisan/parsing/minus.rb +1 -1
- data/lib/keisan/parsing/modulo.rb +1 -1
- data/lib/keisan/parsing/operator.rb +1 -1
- data/lib/keisan/parsing/plus.rb +1 -1
- data/lib/keisan/parsing/times.rb +1 -1
- data/lib/keisan/parsing/unary_minus.rb +1 -1
- data/lib/keisan/parsing/unary_operator.rb +1 -1
- data/lib/keisan/parsing/unary_plus.rb +1 -1
- data/lib/keisan/repl.rb +1 -1
- data/lib/keisan/tokenizer.rb +4 -9
- data/lib/keisan/tokens/group.rb +3 -1
- data/lib/keisan/tokens/line_separator.rb +11 -0
- data/lib/keisan/variables/default_registry.rb +0 -5
- data/lib/keisan/variables/registry.rb +7 -7
- data/lib/keisan/version.rb +1 -1
- metadata +27 -2
data/lib/keisan/functions/cos.rb
CHANGED
data/lib/keisan/functions/cot.rb
CHANGED
data/lib/keisan/functions/csc.rb
CHANGED
@@ -8,7 +8,7 @@ module Keisan
|
|
8
8
|
protected
|
9
9
|
|
10
10
|
def self.derivative(argument)
|
11
|
-
-
|
11
|
+
-AST::Function.new([argument], "cos") * AST::Exponent.new([AST::Function.new([argument], "sin"), -2])
|
12
12
|
end
|
13
13
|
end
|
14
14
|
end
|
@@ -8,7 +8,7 @@ module Keisan
|
|
8
8
|
protected
|
9
9
|
|
10
10
|
def self.derivative(argument)
|
11
|
-
-
|
11
|
+
-AST::Function.new([argument], "cosh") * AST::Exponent.new([AST::Function.new([argument], "sinh"), -2])
|
12
12
|
end
|
13
13
|
end
|
14
14
|
end
|
@@ -1,6 +1,10 @@
|
|
1
|
+
require_relative "let"
|
2
|
+
|
1
3
|
require_relative "if"
|
4
|
+
require_relative "while"
|
2
5
|
require_relative "diff"
|
3
6
|
require_relative "replace"
|
7
|
+
require_relative "range"
|
4
8
|
require_relative "map"
|
5
9
|
require_relative "filter"
|
6
10
|
require_relative "reduce"
|
@@ -8,6 +12,7 @@ require_relative "rand"
|
|
8
12
|
require_relative "sample"
|
9
13
|
require_relative "math_function"
|
10
14
|
require_relative "cmath_function"
|
15
|
+
require_relative "erf"
|
11
16
|
require_relative "exp"
|
12
17
|
require_relative "log"
|
13
18
|
require_relative "sin"
|
@@ -40,43 +45,27 @@ module Keisan
|
|
40
45
|
private
|
41
46
|
|
42
47
|
def self.register_defaults!(registry)
|
43
|
-
registry.register!(:
|
44
|
-
|
45
|
-
registry.register!(:
|
46
|
-
registry.register!(:
|
47
|
-
registry.register!(:
|
48
|
-
registry.register!(:
|
49
|
-
registry.register!(:
|
50
|
-
registry.register!(:
|
51
|
-
registry.register!(:
|
52
|
-
|
53
|
-
|
48
|
+
registry.register!(:let, Let.new, force: true)
|
49
|
+
|
50
|
+
registry.register!(:if, If.new, force: true)
|
51
|
+
registry.register!(:while, While.new, force: true)
|
52
|
+
registry.register!(:diff, Diff.new, force: true)
|
53
|
+
registry.register!(:replace, Replace.new, force: true)
|
54
|
+
registry.register!(:map, Map.new, force: true)
|
55
|
+
registry.register!(:collect, Map.new, force: true)
|
56
|
+
registry.register!(:filter, Filter.new, force: true)
|
57
|
+
registry.register!(:select, Filter.new, force: true)
|
58
|
+
registry.register!(:reduce, Reduce.new, force: true)
|
59
|
+
registry.register!(:inject, Reduce.new, force: true)
|
60
|
+
|
61
|
+
register_math!(registry)
|
54
62
|
register_array_methods!(registry)
|
55
63
|
register_random_methods!(registry)
|
64
|
+
end
|
56
65
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
registry.register!(:sin, Keisan::Functions::Sin.new, force: true)
|
61
|
-
registry.register!(:cos, Keisan::Functions::Cos.new, force: true)
|
62
|
-
registry.register!(:tan, Keisan::Functions::Tan.new, force: true)
|
63
|
-
registry.register!(:cot, Keisan::Functions::Cot.new, force: true)
|
64
|
-
registry.register!(:sec, Keisan::Functions::Sec.new, force: true)
|
65
|
-
registry.register!(:csc, Keisan::Functions::Csc.new, force: true)
|
66
|
-
|
67
|
-
registry.register!(:sinh, Keisan::Functions::Sinh.new, force: true)
|
68
|
-
registry.register!(:cosh, Keisan::Functions::Cosh.new, force: true)
|
69
|
-
registry.register!(:tanh, Keisan::Functions::Tanh.new, force: true)
|
70
|
-
registry.register!(:coth, Keisan::Functions::Coth.new, force: true)
|
71
|
-
registry.register!(:sech, Keisan::Functions::Sech.new, force: true)
|
72
|
-
registry.register!(:csch, Keisan::Functions::Csch.new, force: true)
|
73
|
-
|
74
|
-
registry.register!(:sqrt, Keisan::Functions::Sqrt.new, force: true)
|
75
|
-
registry.register!(:cbrt, Keisan::Functions::Cbrt.new, force: true)
|
76
|
-
|
77
|
-
registry.register!(:abs, Keisan::Functions::Abs.new, force: true)
|
78
|
-
registry.register!(:real, Keisan::Functions::Real.new, force: true)
|
79
|
-
registry.register!(:imag, Keisan::Functions::Imag.new, force: true)
|
66
|
+
def self.register_math!(registry)
|
67
|
+
register_builtin_math!(registry)
|
68
|
+
register_custom_math!(registry)
|
80
69
|
end
|
81
70
|
|
82
71
|
def self.register_builtin_math!(registry)
|
@@ -92,54 +81,44 @@ module Keisan
|
|
92
81
|
end
|
93
82
|
end
|
94
83
|
|
84
|
+
CUSTOM_MATH_FUNCTIONS = %i(erf exp log sin cos tan cot sec csc sinh cosh tanh coth sech csch sqrt cbrt abs real imag).freeze
|
85
|
+
|
86
|
+
def self.register_custom_math!(registry)
|
87
|
+
factorial = Proc.new {|n|
|
88
|
+
(1..n).inject(1) do |res, i|
|
89
|
+
res * i
|
90
|
+
end
|
91
|
+
}
|
92
|
+
nPk = Proc.new {|n, k|
|
93
|
+
factorial.call(n) / factorial.call(n-k)
|
94
|
+
}
|
95
|
+
nCk = Proc.new {|n, k|
|
96
|
+
factorial.call(n) / factorial.call(k) / factorial.call(n-k)
|
97
|
+
}
|
98
|
+
|
99
|
+
registry.register!(:factorial, factorial, force: true)
|
100
|
+
registry.register!(:nPk, nPk, force: true)
|
101
|
+
registry.register!(:permute, nPk, force: true)
|
102
|
+
registry.register!(:nCk, nCk, force: true)
|
103
|
+
registry.register!(:choose, nCk, force: true)
|
104
|
+
|
105
|
+
CUSTOM_MATH_FUNCTIONS.each do |method|
|
106
|
+
klass = Keisan::Functions.const_get(method.to_s.capitalize)
|
107
|
+
registry.register!(method, klass.new, force: true)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
95
111
|
def self.register_array_methods!(registry)
|
96
112
|
%i(min max size flatten reverse).each do |method|
|
97
113
|
registry.register!(method, Proc.new {|a| a.send(method)}, force: true)
|
98
114
|
end
|
99
115
|
|
100
|
-
|
101
|
-
# range(5, 15) => Integers from 5 inclusive to 15 exclusive
|
102
|
-
# range(10, -1, -2) => Integers from 10 inclusive to -1 exclusive, decreasing by twos
|
103
|
-
# i.e.: [10, 8, 6, 4, 2, 0]
|
104
|
-
registry.register!("range", Proc.new {|*args|
|
105
|
-
case args.count
|
106
|
-
when 1
|
107
|
-
(0...args[0]).to_a
|
108
|
-
when 2
|
109
|
-
(args[0]...args[1]).to_a
|
110
|
-
when 3
|
111
|
-
current = args[0]
|
112
|
-
final = args[1]
|
113
|
-
shift = args[2]
|
114
|
-
|
115
|
-
if shift == 0 or !shift.is_a?(Integer)
|
116
|
-
raise Keisan::Exceptions::InvalidFunctionError.new("range's 3rd argument must be non-zero integer")
|
117
|
-
end
|
118
|
-
|
119
|
-
result = []
|
120
|
-
|
121
|
-
if shift > 0
|
122
|
-
while current < final
|
123
|
-
result << current
|
124
|
-
current += shift
|
125
|
-
end
|
126
|
-
else
|
127
|
-
while current > final
|
128
|
-
result << current
|
129
|
-
current += shift
|
130
|
-
end
|
131
|
-
end
|
132
|
-
|
133
|
-
result
|
134
|
-
else
|
135
|
-
raise Keisan::Exceptions::InvalidFunctionError.new("range takes 1 to 3 arguments")
|
136
|
-
end
|
137
|
-
}, force: true)
|
116
|
+
registry.register!("range", Functions::Range.new, force: true)
|
138
117
|
end
|
139
118
|
|
140
119
|
def self.register_random_methods!(registry)
|
141
|
-
registry.register!(:rand,
|
142
|
-
registry.register!(:sample,
|
120
|
+
registry.register!(:rand, Rand.new, force: true)
|
121
|
+
registry.register!(:sample, Sample.new, force: true)
|
143
122
|
end
|
144
123
|
end
|
145
124
|
end
|
@@ -1,23 +1,26 @@
|
|
1
1
|
module Keisan
|
2
2
|
module Functions
|
3
|
-
class Diff <
|
3
|
+
class Diff < Function
|
4
4
|
def initialize
|
5
|
+
super("diff", -1)
|
5
6
|
@name = "diff"
|
6
7
|
end
|
7
8
|
|
8
9
|
def value(ast_function, context = nil)
|
9
|
-
|
10
|
+
validate_arguments!(ast_function.children.count)
|
11
|
+
context ||= Context.new
|
10
12
|
evaluation = evaluate(ast_function, context)
|
11
13
|
|
12
14
|
if is_ast_derivative?(evaluation)
|
13
|
-
raise
|
15
|
+
raise Exceptions::NonDifferentiableError.new
|
14
16
|
else
|
15
17
|
evaluation.value(context)
|
16
18
|
end
|
17
19
|
end
|
18
20
|
|
19
21
|
def evaluate(ast_function, context = nil)
|
20
|
-
|
22
|
+
validate_arguments!(ast_function.children.count)
|
23
|
+
context ||= Context.new
|
21
24
|
function, variables = function_and_variables(ast_function)
|
22
25
|
local = context_from(variables, context)
|
23
26
|
|
@@ -30,7 +33,7 @@ module Keisan
|
|
30
33
|
end
|
31
34
|
|
32
35
|
case result
|
33
|
-
when
|
36
|
+
when AST::Function
|
34
37
|
result.name == "diff" ? result : result.simplify(context)
|
35
38
|
else
|
36
39
|
result.simplify(context)
|
@@ -38,9 +41,10 @@ module Keisan
|
|
38
41
|
end
|
39
42
|
|
40
43
|
def simplify(ast_function, context = nil)
|
41
|
-
|
44
|
+
validate_arguments!(ast_function.children.count)
|
45
|
+
raise Exceptions::InternalError.new("received non-diff function") unless ast_function.name == "diff"
|
42
46
|
function, variables = function_and_variables(ast_function)
|
43
|
-
context ||=
|
47
|
+
context ||= Context.new
|
44
48
|
local = context_from(variables, context)
|
45
49
|
|
46
50
|
result = variables.inject(function.simplify(local)) do |result, variable|
|
@@ -52,7 +56,7 @@ module Keisan
|
|
52
56
|
end
|
53
57
|
|
54
58
|
case result
|
55
|
-
when
|
59
|
+
when AST::Function
|
56
60
|
result.name == "diff" ? result : result.simplify(context)
|
57
61
|
else
|
58
62
|
result.simplify(context)
|
@@ -62,7 +66,7 @@ module Keisan
|
|
62
66
|
private
|
63
67
|
|
64
68
|
def is_ast_derivative?(node)
|
65
|
-
node.is_a?(
|
69
|
+
node.is_a?(AST::Function) && node.name == name
|
66
70
|
end
|
67
71
|
|
68
72
|
def differentiate(node, variable, context)
|
@@ -71,7 +75,7 @@ module Keisan
|
|
71
75
|
else
|
72
76
|
return AST::Number.new(0)
|
73
77
|
end
|
74
|
-
rescue
|
78
|
+
rescue Exceptions::NonDifferentiableError => e
|
75
79
|
return AST::Function.new(
|
76
80
|
[node, variable],
|
77
81
|
"diff"
|
@@ -79,14 +83,14 @@ module Keisan
|
|
79
83
|
end
|
80
84
|
|
81
85
|
def function_and_variables(ast_function)
|
82
|
-
unless ast_function.is_a?(
|
83
|
-
raise
|
86
|
+
unless ast_function.is_a?(AST::Function) && ast_function.name == name
|
87
|
+
raise Exceptions::InvalidFunctionError.new("Must receive diff function")
|
84
88
|
end
|
85
89
|
|
86
90
|
variables = ast_function.children[1..-1]
|
87
91
|
|
88
92
|
unless variables.all? {|var| var.is_a?(AST::Variable)}
|
89
|
-
raise
|
93
|
+
raise Exceptions::InvalidFunctionError.new("Diff must differentiate with respect to variables")
|
90
94
|
end
|
91
95
|
|
92
96
|
[
|
@@ -96,7 +100,7 @@ module Keisan
|
|
96
100
|
end
|
97
101
|
|
98
102
|
def context_from(variables, context = nil)
|
99
|
-
context ||=
|
103
|
+
context ||= Context.new(shadowed: variables.map(&:name))
|
100
104
|
context.spawn_child(shadowed: variables.map(&:name))
|
101
105
|
end
|
102
106
|
end
|
data/lib/keisan/functions/exp.rb
CHANGED
@@ -1,17 +1,17 @@
|
|
1
1
|
module Keisan
|
2
2
|
module Functions
|
3
|
-
class ExpressionFunction <
|
3
|
+
class ExpressionFunction < Function
|
4
4
|
attr_reader :arguments, :expression
|
5
5
|
|
6
6
|
def initialize(name, arguments, expression, transient_definitions)
|
7
|
-
super(name)
|
7
|
+
super(name, arguments.count)
|
8
8
|
@expression = expression.deep_dup
|
9
9
|
@arguments = arguments
|
10
10
|
@transient_definitions = transient_definitions
|
11
11
|
end
|
12
12
|
|
13
13
|
def call(context, *args)
|
14
|
-
|
14
|
+
validate_arguments!(args.count)
|
15
15
|
|
16
16
|
local = local_context_for(context)
|
17
17
|
arguments.each.with_index do |arg_name, i|
|
@@ -22,17 +22,17 @@ module Keisan
|
|
22
22
|
end
|
23
23
|
|
24
24
|
def value(ast_function, context = nil)
|
25
|
-
|
25
|
+
validate_arguments!(ast_function.children.count)
|
26
26
|
|
27
|
-
context ||=
|
27
|
+
context ||= Context.new
|
28
28
|
argument_values = ast_function.children.map {|child| child.value(context)}
|
29
29
|
call(context, *argument_values)
|
30
30
|
end
|
31
31
|
|
32
32
|
def evaluate(ast_function, context = nil)
|
33
|
-
|
33
|
+
validate_arguments!(ast_function.children.count)
|
34
34
|
|
35
|
-
context ||=
|
35
|
+
context ||= Context.new
|
36
36
|
local = local_context_for(context)
|
37
37
|
|
38
38
|
argument_values = ast_function.children.map {|child| child.evaluate(context)}
|
@@ -41,18 +41,18 @@ module Keisan
|
|
41
41
|
local.register_variable!(arg_name, argument_values[i].evaluate(context))
|
42
42
|
end
|
43
43
|
|
44
|
-
expression.
|
44
|
+
expression.evaluated(local)
|
45
45
|
end
|
46
46
|
|
47
47
|
def simplify(ast_function, context = nil)
|
48
|
-
|
48
|
+
validate_arguments!(ast_function.children.count)
|
49
49
|
|
50
50
|
ast_function.instance_variable_set(
|
51
51
|
:@children,
|
52
52
|
ast_function.children.map {|child| child.evaluate(context)}
|
53
53
|
)
|
54
54
|
|
55
|
-
if ast_function.children.all? {|child| child.is_a?(
|
55
|
+
if ast_function.children.all? {|child| child.is_a?(AST::ConstantLiteral)}
|
56
56
|
value(ast_function, context).to_node.simplify(context)
|
57
57
|
else
|
58
58
|
ast_function
|
@@ -66,7 +66,7 @@ module Keisan
|
|
66
66
|
# dx(t)/dt * f_x(x(t), y(t)) + dy(t)/dt * f_y(x(t), y(t)),
|
67
67
|
# where f_x and f_y are the x and y partial derivatives respectively.
|
68
68
|
def differentiate(ast_function, variable, context = nil)
|
69
|
-
|
69
|
+
validate_arguments!(ast_function.children.count)
|
70
70
|
|
71
71
|
local = local_context_for(context)
|
72
72
|
|
@@ -78,10 +78,10 @@ module Keisan
|
|
78
78
|
child.differentiate(variable, context)
|
79
79
|
end
|
80
80
|
|
81
|
-
|
81
|
+
AST::Plus.new(
|
82
82
|
argument_derivatives.map.with_index {|argument_derivative, i|
|
83
83
|
partial_derivative = partial_derivatives[i].replace(argument_variables[i], argument_values[i])
|
84
|
-
|
84
|
+
AST::Times.new([argument_derivative, partial_derivative])
|
85
85
|
}
|
86
86
|
)
|
87
87
|
end
|
@@ -89,7 +89,7 @@ module Keisan
|
|
89
89
|
private
|
90
90
|
|
91
91
|
def argument_variables
|
92
|
-
@argument_variables ||= arguments.map {|argument|
|
92
|
+
@argument_variables ||= arguments.map {|argument| AST::Variable.new(argument)}
|
93
93
|
end
|
94
94
|
|
95
95
|
def partial_derivatives
|
@@ -98,14 +98,8 @@ module Keisan
|
|
98
98
|
end
|
99
99
|
end
|
100
100
|
|
101
|
-
def verify_argument_size!(argument_size)
|
102
|
-
unless @arguments.count == argument_size
|
103
|
-
raise Keisan::Exceptions::InvalidFunctionError.new("Invalid number of arguments for #{name} function")
|
104
|
-
end
|
105
|
-
end
|
106
|
-
|
107
101
|
def local_context_for(context = nil)
|
108
|
-
context ||=
|
102
|
+
context ||= Context.new
|
109
103
|
context.spawn_child(definitions: @transient_definitions, shadowed: @arguments, transient: true)
|
110
104
|
end
|
111
105
|
end
|