heist 0.1.0 → 0.2.0
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.
- data/History.txt +17 -0
- data/Manifest.txt +23 -19
- data/README.txt +84 -52
- data/lib/builtin/library.scm +208 -10
- data/lib/builtin/primitives.rb +154 -92
- data/lib/builtin/syntax.scm +22 -5
- data/lib/heist.rb +49 -17
- data/lib/parser/nodes.rb +47 -24
- data/lib/parser/ruby.rb +29 -0
- data/lib/parser/scheme.rb +455 -143
- data/lib/parser/scheme.tt +23 -5
- data/lib/repl.rb +19 -16
- data/lib/runtime/binding.rb +24 -2
- data/lib/runtime/callable/continuation.rb +23 -2
- data/lib/runtime/callable/function.rb +122 -21
- data/lib/runtime/callable/macro.rb +169 -123
- data/lib/runtime/callable/macro/expansion.rb +137 -2
- data/lib/runtime/callable/macro/matches.rb +125 -41
- data/lib/runtime/callable/macro/tree.rb +141 -0
- data/lib/runtime/callable/syntax.rb +44 -0
- data/lib/runtime/data/cons.rb +234 -0
- data/lib/runtime/data/expression.rb +15 -6
- data/lib/runtime/data/identifier.rb +19 -2
- data/lib/runtime/frame.rb +102 -35
- data/lib/runtime/runtime.rb +44 -19
- data/lib/runtime/scope.rb +145 -30
- data/lib/runtime/stack.rb +103 -1
- data/lib/runtime/stackless.rb +48 -6
- data/test/arithmetic.scm +11 -2
- data/test/continuations.scm +16 -2
- data/test/equivalence.scm +34 -0
- data/test/functional.scm +4 -0
- data/test/lists.scm +78 -0
- data/test/macro-helpers.scm +1 -0
- data/test/macros.scm +111 -24
- data/test/numbers.scm +30 -8
- data/test/test_heist.rb +67 -12
- metadata +25 -21
- data/lib/builtin/syntax.rb +0 -166
- data/lib/runtime/callable/macro/splice.rb +0 -56
- data/lib/runtime/data/list.rb +0 -36
data/test/numbers.scm
CHANGED
@@ -1,19 +1,41 @@
|
|
1
|
-
(assert (eqv? 42 42))
|
2
|
-
(assert (not (eqv? 42 #f)))
|
3
|
-
(assert (not (eqv? 42 42.0)))
|
4
1
|
(assert (= 42 42))
|
5
2
|
(assert (= 42 42.0))
|
6
3
|
|
7
4
|
(assert (number? 42))
|
8
5
|
(assert (not (number? #t)))
|
9
|
-
|
10
|
-
|
6
|
+
(assert (complex? 2+3i))
|
7
|
+
(assert (not (real? 2+3i)))
|
11
8
|
(assert (real? 3.1416))
|
12
9
|
(assert (real? 22/7))
|
13
10
|
(assert (real? 42))
|
14
|
-
|
15
|
-
|
16
|
-
|
11
|
+
(assert (not (rational? 2+3i)))
|
12
|
+
(assert (not (rational? 3.1416)))
|
13
|
+
(assert (rational? 22/7))
|
17
14
|
(assert (not (integer? 22/7)))
|
18
15
|
(assert (integer? 42))
|
19
16
|
|
17
|
+
(assert (zero? 0))
|
18
|
+
(assert (not (zero? 1)))
|
19
|
+
(assert (odd? 1))
|
20
|
+
(assert (not (odd? 2)))
|
21
|
+
(assert (even? 6))
|
22
|
+
(assert (not (even? 7)))
|
23
|
+
(assert (positive? 5))
|
24
|
+
(assert (not (positive? -4)))
|
25
|
+
(assert (negative? -13))
|
26
|
+
(assert (not (negative? 0)))
|
27
|
+
|
28
|
+
(assert-equal 9 (max 8 2 7 3 9 5))
|
29
|
+
(assert-equal 2 (min 8 2 7 3 9 5))
|
30
|
+
|
31
|
+
(assert (exact? 8))
|
32
|
+
(assert (exact? 4/3))
|
33
|
+
(assert (exact? 5+3i))
|
34
|
+
(assert (inexact? 8.5))
|
35
|
+
(assert (inexact? 8.5+4i))
|
36
|
+
|
37
|
+
(assert (rational? (/ 4 3)))
|
38
|
+
(assert (rational? (/ 4)))
|
39
|
+
|
40
|
+
(assert-equal 1 (make-polar 1 0))
|
41
|
+
|
data/test/test_heist.rb
CHANGED
@@ -13,7 +13,7 @@ Class.new(Test::Unit::TestCase) do
|
|
13
13
|
def setup
|
14
14
|
return @@env if @@env
|
15
15
|
@@env = Heist::Runtime.new(Heist::BIN_SPEC.parse($args))
|
16
|
-
|
16
|
+
puts @@env.info
|
17
17
|
|
18
18
|
@@env.define('assert') do |value|
|
19
19
|
assert(value)
|
@@ -21,18 +21,21 @@ Class.new(Test::Unit::TestCase) do
|
|
21
21
|
@@env.define('assert-equal') do |expected, actual|
|
22
22
|
assert_equal(expected, actual)
|
23
23
|
end
|
24
|
-
@@env.syntax('assert-raise') do |scope,
|
25
|
-
exception = Heist.const_get(
|
26
|
-
assert_raise(exception) {
|
24
|
+
@@env.syntax('assert-raise') do |scope, cells|
|
25
|
+
exception = Heist.const_get(cells.car.to_s)
|
26
|
+
assert_raise(exception) { scope.eval(cells.cdr.car) }
|
27
27
|
end
|
28
28
|
end
|
29
29
|
|
30
30
|
%w[ booleans
|
31
31
|
numbers
|
32
|
+
lists
|
33
|
+
equivalence
|
32
34
|
arithmetic
|
33
35
|
define_values
|
34
36
|
define_functions
|
35
37
|
closures
|
38
|
+
functional
|
36
39
|
let
|
37
40
|
conditionals
|
38
41
|
file_loading
|
@@ -45,6 +48,39 @@ Class.new(Test::Unit::TestCase) do
|
|
45
48
|
end
|
46
49
|
end
|
47
50
|
|
51
|
+
def test_cons
|
52
|
+
cons = Heist::Runtime::Cons
|
53
|
+
|
54
|
+
empty = cons[[]]
|
55
|
+
assert empty.list?
|
56
|
+
assert !empty.pair?
|
57
|
+
assert_equal cons::NULL, empty
|
58
|
+
assert_equal 0, empty.length
|
59
|
+
|
60
|
+
single = cons[[4]]
|
61
|
+
assert single.list?
|
62
|
+
assert single.pair?
|
63
|
+
assert_equal 1, single.length
|
64
|
+
|
65
|
+
multi = cons[[2,4,7]]
|
66
|
+
assert multi.list?
|
67
|
+
assert multi.pair?
|
68
|
+
assert_equal 3, multi.length
|
69
|
+
|
70
|
+
multi.tail.cdr = 8
|
71
|
+
assert multi.pair?
|
72
|
+
assert !multi.list?
|
73
|
+
assert_raise(Heist::TypeError) { multi.size }
|
74
|
+
|
75
|
+
nested = cons[[2,4,6,cons.new(7,8)]]
|
76
|
+
assert nested.list?
|
77
|
+
assert nested.pair?
|
78
|
+
assert_equal 4, nested.length
|
79
|
+
assert !nested.cdr.cdr.cdr.car.list?
|
80
|
+
assert nested.cdr.cdr.cdr.car.pair?
|
81
|
+
assert_equal 8, nested.cdr.cdr.cdr.car.cdr
|
82
|
+
end
|
83
|
+
|
48
84
|
def test_macro_hygiene
|
49
85
|
@@env.run($dir + '/' + (@@env.hygienic? ? 'hygienic' : 'unhygienic'))
|
50
86
|
end
|
@@ -55,14 +91,25 @@ Class.new(Test::Unit::TestCase) do
|
|
55
91
|
end
|
56
92
|
|
57
93
|
def test_quotes
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
assert_equal 7,
|
62
|
-
assert_equal [:+,
|
63
|
-
|
64
|
-
|
65
|
-
assert_equal [
|
94
|
+
cons = Heist::Runtime::Cons
|
95
|
+
c = cons.method(:new)
|
96
|
+
|
97
|
+
assert_equal 7, @@env.eval("(+ 3 4)")
|
98
|
+
assert_equal [:+, 3, 4], @@env.eval("'(+ 3 4)").to_ruby
|
99
|
+
assert cons === @@env.eval("'(+ 3 4)")
|
100
|
+
assert_equal 7, @@env.eval("(+ '3 4)")
|
101
|
+
assert_equal c[1,8], @@env.eval("'(1 . 8)")
|
102
|
+
assert_equal c[1,8], @@env.eval("`(1 . 8)")
|
103
|
+
assert_equal [:+, [:-, 7, 9], 4], @@env.eval("'(+ (- 7 9) 4)").to_ruby
|
104
|
+
assert_equal [7, 9, 6], @@env.eval("`(7 ,(+ 4 5) 6)").to_ruby
|
105
|
+
assert cons === @@env.eval("`(7 ,(+ 4 5) 6)")
|
106
|
+
assert_equal [3, 7, 6, 2, 6, 9], @@env.eval("`(3 7 6 ,@((lambda () '(2 6))) 9)").to_ruby
|
107
|
+
assert_equal [1, 2, 10], @@env.eval("`(1 2 ,(+ 4 6))").to_ruby
|
108
|
+
assert_equal [3, 2, 9, 8], @@env.eval("`(,(/ 9 3) 2 ,@(list 9 8))").to_ruby
|
109
|
+
assert_equal [1, 2, 4, 9, 8, 5], @@env.eval("`(,@(list 1 2) 4 ,@(list 9 8) 5)").to_ruby
|
110
|
+
assert_equal c[9,c[8,c[5,7]]], @@env.eval("`(,@(list 9 8) 5 . 7)")
|
111
|
+
assert_equal c[9,c[8,24]], @@env.eval("`(,@(list 9 8) . ,(* 4 6))")
|
112
|
+
assert_equal [:quote, []], @@env.eval("''()").to_ruby
|
66
113
|
end
|
67
114
|
|
68
115
|
def test_birds
|
@@ -80,5 +127,13 @@ Class.new(Test::Unit::TestCase) do
|
|
80
127
|
|
81
128
|
assert_equal 45, @@env.eval("((K 45) 6)")
|
82
129
|
end
|
130
|
+
|
131
|
+
def test_ruby_execution
|
132
|
+
expr = [[:lambda, [:x], [:+, 1, :x]], 3]
|
133
|
+
assert_equal 4, @@env.exec(expr)
|
134
|
+
list = Heist.parse(expr)
|
135
|
+
assert Heist::Runtime::Cons === list
|
136
|
+
assert_equal expr, list.to_ruby
|
137
|
+
end
|
83
138
|
end
|
84
139
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: heist
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- James Coglan
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-
|
12
|
+
date: 2009-04-01 00:00:00 +01:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -57,37 +57,37 @@ extra_rdoc_files:
|
|
57
57
|
files:
|
58
58
|
- History.txt
|
59
59
|
- Manifest.txt
|
60
|
-
- README.txt
|
61
60
|
- Rakefile
|
61
|
+
- README.txt
|
62
62
|
- bin/heist
|
63
|
-
- lib/heist.rb
|
64
63
|
- lib/bin_spec.rb
|
64
|
+
- lib/heist.rb
|
65
65
|
- lib/repl.rb
|
66
|
+
- lib/builtin/library.scm
|
66
67
|
- lib/builtin/primitives.rb
|
67
|
-
- lib/builtin/syntax.rb
|
68
68
|
- lib/builtin/syntax.scm
|
69
|
-
- lib/builtin/library.scm
|
70
|
-
- lib/parser/scheme.tt
|
71
|
-
- lib/parser/scheme.rb
|
72
69
|
- lib/parser/nodes.rb
|
73
|
-
- lib/
|
74
|
-
- lib/
|
75
|
-
- lib/
|
76
|
-
- lib/runtime/
|
70
|
+
- lib/parser/ruby.rb
|
71
|
+
- lib/parser/scheme.rb
|
72
|
+
- lib/parser/scheme.tt
|
73
|
+
- lib/runtime/callable/continuation.rb
|
77
74
|
- lib/runtime/callable/function.rb
|
75
|
+
- lib/runtime/callable/syntax.rb
|
78
76
|
- lib/runtime/callable/macro.rb
|
79
77
|
- lib/runtime/callable/macro/matches.rb
|
80
|
-
- lib/runtime/callable/macro/
|
78
|
+
- lib/runtime/callable/macro/tree.rb
|
81
79
|
- lib/runtime/callable/macro/expansion.rb
|
82
|
-
- lib/runtime/
|
83
|
-
- lib/runtime/
|
84
|
-
- lib/runtime/
|
80
|
+
- lib/runtime/data/cons.rb
|
81
|
+
- lib/runtime/data/expression.rb
|
82
|
+
- lib/runtime/data/identifier.rb
|
83
|
+
- lib/runtime/binding.rb
|
85
84
|
- lib/runtime/frame.rb
|
85
|
+
- lib/runtime/runtime.rb
|
86
86
|
- lib/runtime/scope.rb
|
87
|
-
- lib/runtime/
|
87
|
+
- lib/runtime/stack.rb
|
88
|
+
- lib/runtime/stackless.rb
|
88
89
|
- lib/stdlib/benchmark.scm
|
89
90
|
- lib/stdlib/birdhouse.scm
|
90
|
-
- test/test_heist.rb
|
91
91
|
- test/arithmetic.scm
|
92
92
|
- test/benchmarks.scm
|
93
93
|
- test/booleans.scm
|
@@ -97,15 +97,19 @@ files:
|
|
97
97
|
- test/define_functions.scm
|
98
98
|
- test/define_values.scm
|
99
99
|
- test/delay.scm
|
100
|
+
- test/equivalence.scm
|
100
101
|
- test/file_loading.scm
|
102
|
+
- test/functional.scm
|
103
|
+
- test/hygienic.scm
|
101
104
|
- test/let.scm
|
102
105
|
- test/lib.scm
|
106
|
+
- test/lists.scm
|
103
107
|
- test/macro-helpers.scm
|
104
108
|
- test/macros.scm
|
105
|
-
- test/hygienic.scm
|
106
|
-
- test/unhygienic.scm
|
107
|
-
- test/plt-macros.txt
|
108
109
|
- test/numbers.scm
|
110
|
+
- test/plt-macros.txt
|
111
|
+
- test/test_heist.rb
|
112
|
+
- test/unhygienic.scm
|
109
113
|
- test/vars.scm
|
110
114
|
has_rdoc: true
|
111
115
|
homepage: Heist is a Scheme interpreter written in Ruby. It provides an executable
|
data/lib/builtin/syntax.rb
DELETED
@@ -1,166 +0,0 @@
|
|
1
|
-
# Control structures
|
2
|
-
|
3
|
-
# (cond) goes through a list of tests, evaluating each one
|
4
|
-
# in order of appearance. Once a matching precondition is
|
5
|
-
# found, its consequent is tail-called and no further
|
6
|
-
# preconditions are evaluated.
|
7
|
-
syntax('cond') do |scope, *pairs|
|
8
|
-
result = nil
|
9
|
-
pairs.each do |list|
|
10
|
-
next if result
|
11
|
-
test = list.first.to_s == 'else' || Heist.evaluate(list.first, scope)
|
12
|
-
next unless test
|
13
|
-
result = list[1].to_s == '=>' ?
|
14
|
-
Heist.evaluate(list[2], scope).call(scope, [test]) :
|
15
|
-
Body.new(list.rest, scope)
|
16
|
-
end
|
17
|
-
result
|
18
|
-
end
|
19
|
-
|
20
|
-
# (case) acts like Ruby's case statement. The value of the
|
21
|
-
# given expression is compared against a series of lists;
|
22
|
-
# once a list is found to include the value, the expressions
|
23
|
-
# following the list are evaluated and no further lists
|
24
|
-
# are tested.
|
25
|
-
syntax('case') do |scope, key, *clauses|
|
26
|
-
value = Heist.evaluate(key, scope)
|
27
|
-
result = nil
|
28
|
-
clauses.each do |list|
|
29
|
-
next if result
|
30
|
-
values = call('quote', scope, list.first)
|
31
|
-
result = Body.new(list.rest, scope) if values == :else or
|
32
|
-
values.include?(value)
|
33
|
-
end
|
34
|
-
result
|
35
|
-
end
|
36
|
-
|
37
|
-
#----------------------------------------------------------------
|
38
|
-
|
39
|
-
# Binding constructs
|
40
|
-
|
41
|
-
# (let), (let*) and (letrec) each create a new scope and bind
|
42
|
-
# values to some symbols before executing a series of lists.
|
43
|
-
# They differ according to how they evaluate the bound values.
|
44
|
-
|
45
|
-
# (let) evaluates values in the enclosing scope, so lambdas will
|
46
|
-
# not be able to refer to other values assigned using the (let).
|
47
|
-
syntax('let') do |scope, assignments, *body|
|
48
|
-
if Identifier === assignments
|
49
|
-
name = assignments
|
50
|
-
assignments = body.first
|
51
|
-
formals = assignments.map { |pair| pair.first }
|
52
|
-
values = assignments.map { |pair| pair.last }
|
53
|
-
closure = Scope.new(scope)
|
54
|
-
closure[name] = Function.new(closure, formals, body[1..-1])
|
55
|
-
closure[name].call(scope, values)
|
56
|
-
else
|
57
|
-
closure = Scope.new(scope)
|
58
|
-
assignments.each do |assign|
|
59
|
-
closure[assign.first] = Heist.evaluate(assign.last, scope)
|
60
|
-
end
|
61
|
-
call('begin', closure, *body)
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
# (let*) creates a new scope for each variable and evaluates
|
66
|
-
# each expression in its enclosing scope. Basically a shorthand
|
67
|
-
# for several nested (let)s. Variables may refer to those that
|
68
|
-
# preceed them but not vice versa.
|
69
|
-
syntax('let*') do |scope, assignments, *body|
|
70
|
-
closure = assignments.inject(scope) do |outer, assign|
|
71
|
-
inner = Scope.new(outer)
|
72
|
-
inner[assign.first] = Heist.evaluate(assign.last, outer)
|
73
|
-
inner
|
74
|
-
end
|
75
|
-
call('begin', closure, *body)
|
76
|
-
end
|
77
|
-
|
78
|
-
# (letrec) evaluates values in the inner scope, so lambdas are
|
79
|
-
# able to refer to other values assigned using the (letrec).
|
80
|
-
syntax('letrec') do |scope, assignments, *body|
|
81
|
-
closure = Scope.new(scope)
|
82
|
-
assignments.each do |assign|
|
83
|
-
closure[assign.first] = Heist.evaluate(assign.last, closure)
|
84
|
-
end
|
85
|
-
call('begin', closure, *body)
|
86
|
-
end
|
87
|
-
|
88
|
-
syntax('let-syntax') do |*args|
|
89
|
-
call('let', *args)
|
90
|
-
end
|
91
|
-
|
92
|
-
syntax('letrec-syntax') do |*args|
|
93
|
-
call('letrec', *args)
|
94
|
-
end
|
95
|
-
|
96
|
-
#----------------------------------------------------------------
|
97
|
-
|
98
|
-
# Iteration
|
99
|
-
|
100
|
-
# (do) is similar to the 'while' construct in procedural
|
101
|
-
# languages. It assigns initial values to a set of variables,
|
102
|
-
# then performs the list of given commands in a loop. If
|
103
|
-
# before any iteration the test is found to be false, the
|
104
|
-
# loop is halted and the value of the expression following
|
105
|
-
# the test is returned.
|
106
|
-
syntax('do') do |scope, assignments, test, *commands|
|
107
|
-
closure = Scope.new(scope)
|
108
|
-
assignments.each do |assign|
|
109
|
-
closure[assign.first] = Heist.evaluate(assign[1], scope)
|
110
|
-
end
|
111
|
-
while not Heist.evaluate(test.first, closure)
|
112
|
-
commands.each { |expr| Heist.evaluate(expr, closure) }
|
113
|
-
temp = {}
|
114
|
-
assignments.each do |assign|
|
115
|
-
step = assign[2] || assign[0]
|
116
|
-
temp[assign.first] = Heist.evaluate(step, closure)
|
117
|
-
end
|
118
|
-
assignments.each do |assign|
|
119
|
-
closure[assign.first] = temp[assign.first]
|
120
|
-
end
|
121
|
-
end
|
122
|
-
call('begin', closure, *test.rest)
|
123
|
-
end
|
124
|
-
|
125
|
-
#----------------------------------------------------------------
|
126
|
-
|
127
|
-
# Boolean combinators
|
128
|
-
|
129
|
-
# (and) returns the first falsey value returned by the list
|
130
|
-
# of expressions, or returns the value of the last expression
|
131
|
-
# if all values are truthy.
|
132
|
-
syntax('and') do |scope, *args|
|
133
|
-
result = true
|
134
|
-
args.each do |arg|
|
135
|
-
next if not result
|
136
|
-
result = Heist.evaluate(arg, scope)
|
137
|
-
end
|
138
|
-
result
|
139
|
-
end
|
140
|
-
|
141
|
-
# (or) returns the first truthy value returned by the list
|
142
|
-
# of expressions, or returns the value of the last expression
|
143
|
-
# if all values are falsey.
|
144
|
-
syntax('or') do |scope, *args|
|
145
|
-
result = false
|
146
|
-
args.each do |arg|
|
147
|
-
next if result
|
148
|
-
result = Heist.evaluate(arg, scope)
|
149
|
-
end
|
150
|
-
result
|
151
|
-
end
|
152
|
-
|
153
|
-
#----------------------------------------------------------------
|
154
|
-
|
155
|
-
# Delayed evaluation
|
156
|
-
|
157
|
-
# (delay) allows the evaluation of an expression to be delayed
|
158
|
-
# by wrapping it in a promise. Use (force) to evaluate the promise
|
159
|
-
# at a later time. The expression inside a promise is only
|
160
|
-
# ever evaluated once, so a promise can be implemented as a
|
161
|
-
# memoized closure.
|
162
|
-
syntax('delay') do |scope, expression|
|
163
|
-
promise = Binding.new(expression, scope)
|
164
|
-
Function.new(scope) { promise.extract }
|
165
|
-
end
|
166
|
-
|
@@ -1,56 +0,0 @@
|
|
1
|
-
module Heist
|
2
|
-
class Runtime
|
3
|
-
class Macro
|
4
|
-
|
5
|
-
class Splice
|
6
|
-
attr_reader :name, :depth
|
7
|
-
|
8
|
-
def initialize(name, depth)
|
9
|
-
@name, @depth = name, depth
|
10
|
-
@data = []
|
11
|
-
(0...@depth).inject(@data) { |list, d| list << []; list.last }
|
12
|
-
@indexes = (0..@depth).map { 0 }
|
13
|
-
@stack = []
|
14
|
-
end
|
15
|
-
|
16
|
-
def <<(value)
|
17
|
-
@stack.pop.call() while not @stack.empty?
|
18
|
-
tail(@depth) << value
|
19
|
-
end
|
20
|
-
|
21
|
-
def mark!(depth)
|
22
|
-
@stack << lambda { tail(depth) << [] }
|
23
|
-
end
|
24
|
-
|
25
|
-
def size(depth)
|
26
|
-
current(depth).size
|
27
|
-
end
|
28
|
-
|
29
|
-
def read
|
30
|
-
current(@depth)[@indexes[@depth]]
|
31
|
-
end
|
32
|
-
|
33
|
-
def shift!(depth)
|
34
|
-
@indexes[depth] += 1
|
35
|
-
@indexes[depth] = 0 if @indexes[depth] >= current(depth).size
|
36
|
-
end
|
37
|
-
|
38
|
-
def to_s(depth = 0)
|
39
|
-
"#{@name}#{' ...' * (@depth - depth)}"
|
40
|
-
end
|
41
|
-
|
42
|
-
private
|
43
|
-
|
44
|
-
def tail(depth)
|
45
|
-
(0...depth).inject(@data) { |list, d| list.last }
|
46
|
-
end
|
47
|
-
|
48
|
-
def current(depth)
|
49
|
-
@indexes[0...depth].inject(@data) { |list, i| list[i] }
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|