wlang 2.0.1 → 2.1.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/CHANGELOG.md +27 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +16 -0
- data/README.md +32 -55
- data/lib/wlang.rb +8 -0
- data/lib/wlang/compiler/grammar.citrus +19 -16
- data/lib/wlang/dialect.rb +18 -14
- data/lib/wlang/html.rb +7 -11
- data/lib/wlang/scope.rb +68 -28
- data/lib/wlang/scope/binding_scope.rb +3 -3
- data/lib/wlang/scope/null_scope.rb +34 -0
- data/lib/wlang/scope/object_scope.rb +18 -7
- data/lib/wlang/scope/proc_scope.rb +4 -4
- data/lib/wlang/scope/sinatra_scope.rb +44 -0
- data/lib/wlang/template.rb +10 -2
- data/lib/wlang/tilt/wlang_template.rb +1 -1
- data/lib/wlang/version.rb +2 -2
- data/spec/assumptions/test_core.rb +8 -0
- data/spec/fixtures/templates/hello_from_sinatra.wlang +1 -0
- data/spec/integration/html/test_greater.rb +12 -2
- data/spec/integration/sinatra/test_partials.rb +35 -0
- data/spec/integration/test_examples.rb +2 -2
- data/spec/spec_helper.rb +7 -0
- data/spec/unit/compiler/test_grammar.rb +1 -1
- data/spec/unit/compiler/test_parser.rb +17 -0
- data/spec/unit/dialect/test_context.rb +28 -0
- data/spec/unit/dialect/test_evaluate.rb +10 -0
- data/spec/unit/dialect/test_render.rb +4 -0
- data/spec/unit/scope/sinatra_scope/test_fetch.rb +28 -0
- data/spec/unit/scope/test_binding_scope.rb +1 -1
- data/spec/unit/scope/test_chain.rb +5 -5
- data/spec/unit/scope/test_coerce.rb +7 -3
- data/spec/unit/scope/test_null_scope.rb +35 -0
- data/spec/unit/scope/test_object_scope.rb +1 -1
- data/spec/unit/scope/test_proc_scope.rb +1 -1
- data/spec/unit/scope/test_push.rb +70 -0
- data/spec/unit/template/test_call_args_conventions.rb +101 -0
- data/spec/unit/test_assumptions.rb +12 -0
- data/spec/unit/test_scope.rb +26 -16
- data/wlang.gemspec +2 -0
- data/wlang.noespec +3 -1
- metadata +143 -33
- data/lib/wlang/scope/proxy_scope.rb +0 -18
- data/lib/wlang/scope/root_scope.rb +0 -24
- data/spec/unit/scope/test_proxy_scope.rb +0 -22
- data/spec/unit/scope/test_root_scope.rb +0 -22
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,30 @@
|
|
1
|
+
# 2.1.0 / 2012-11-28
|
2
|
+
|
3
|
+
## Enhancements
|
4
|
+
|
5
|
+
* The scoping mechanism has been clarified and enhanced (mostly private APIs).
|
6
|
+
In particular,
|
7
|
+
* Template#render and Dialect#render now accepts multiple scoping objects and chain them
|
8
|
+
as a unique scope. The latter is branched with template locals, which are always the
|
9
|
+
most-specific and therefore have highest priority.
|
10
|
+
* RootScope as been renamed to NullScope, Scope.root to Scope.null accordingly
|
11
|
+
* ProxyScope has been removed to keep scopes linear chains.
|
12
|
+
|
13
|
+
* Added Dialect#context, which allows knowing the subject of the less specific scope, that
|
14
|
+
is the first argument of Dialect#render and Template#render. In Sinatra/Tilt situation,
|
15
|
+
this simply correspond to the `scope`, typically the Sinatra app.
|
16
|
+
|
17
|
+
* Dialect#evaluate (through Scope#evaluate) now accepts an optional block for specifying
|
18
|
+
a computed default value instead of failing.
|
19
|
+
|
20
|
+
* WLang::Html partial tag >{...} now recognizes a Proc and simply renders the result of
|
21
|
+
calling it. This allows to use >{yield} in layouts instead of the less idomatic +{yield}.
|
22
|
+
|
23
|
+
## Bug fixes
|
24
|
+
|
25
|
+
* Fixed a bug when parsing "hello { ${wlang} }" constructs (typically javascript or java)
|
26
|
+
(wlang inner constructions was not properly parsed)
|
27
|
+
|
1
28
|
# 2.0.1 / 2012-06-12
|
2
29
|
|
3
30
|
* Fix support for 1.8.7 and jruby (undefined method `ord' for String)
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,3 +1,12 @@
|
|
1
|
+
GIT
|
2
|
+
remote: git://github.com/sinatra/sinatra
|
3
|
+
revision: 8752085a05c33edd13d3ec8d3187d1406456d404
|
4
|
+
specs:
|
5
|
+
sinatra (1.4.0)
|
6
|
+
rack (~> 1.3, >= 1.3.6)
|
7
|
+
rack-protection (~> 1.2)
|
8
|
+
tilt (~> 1.3, >= 1.3.3)
|
9
|
+
|
1
10
|
GEM
|
2
11
|
remote: http://rubygems.org/
|
3
12
|
specs:
|
@@ -8,6 +17,11 @@ GEM
|
|
8
17
|
diff-lcs (1.1.3)
|
9
18
|
epath (0.2.0)
|
10
19
|
quickl (0.4.3)
|
20
|
+
rack (1.4.1)
|
21
|
+
rack-protection (1.2.0)
|
22
|
+
rack
|
23
|
+
rack-test (0.6.1)
|
24
|
+
rack (>= 1.0)
|
11
25
|
rake (0.9.2.2)
|
12
26
|
rspec (2.10.0)
|
13
27
|
rspec-core (~> 2.10.0)
|
@@ -32,8 +46,10 @@ DEPENDENCIES
|
|
32
46
|
citrus (~> 2.4.1)
|
33
47
|
epath (>= 0.2)
|
34
48
|
quickl (~> 0.4.3)
|
49
|
+
rack-test (~> 0.6.1)
|
35
50
|
rake (~> 0.9.2)
|
36
51
|
rspec (~> 2.10.0)
|
52
|
+
sinatra!
|
37
53
|
temple (~> 0.4.0)
|
38
54
|
tilt (~> 1.3)
|
39
55
|
yard (~> 0.8.1)
|
data/README.md
CHANGED
@@ -23,7 +23,7 @@ WLang is a powerful code generation and templating engine, implemented on top of
|
|
23
23
|
WLang 2.0 also has a few remaining issues.
|
24
24
|
|
25
25
|
* It does not support rubinius so far, due to an incompatibility with the Citrus parser generator.
|
26
|
-
* It
|
26
|
+
* It has some issues with spacing; not a big issue for HTML rendering but might prevent certain generation tasks.
|
27
27
|
|
28
28
|
## Tunable templating engine
|
29
29
|
|
@@ -55,75 +55,52 @@ Highlighter.render('Hello ${who}!'), who: 'you & the world'
|
|
55
55
|
|
56
56
|
WLang already provides a few useful dialects, such as WLang::Html (inspired by Mustache but a bit more powerful in my opinion). If they don't match your needs, it is up to you to define you own dialect for making your generation task easy. Have a look at the implementation of WLang's ones, it's pretty simple to get started!
|
57
57
|
|
58
|
-
|
58
|
+
# Tilt integration
|
59
59
|
|
60
|
-
WLang has
|
60
|
+
WLang has built-in support for [Tilt](https://github.com/rtomayko/tilt) facade to templating engines. In order to use that API:
|
61
61
|
|
62
|
-
```
|
63
|
-
|
64
|
-
|
62
|
+
```ruby
|
63
|
+
require 'tilt' # needed in your bundle, not a wlang dependency
|
64
|
+
require 'wlang' # loads Tilt support provided Tilt has already been required
|
65
65
|
|
66
|
-
|
66
|
+
template = Tilt.new("path/to/a/template.wlang") # suppose 'Hello ${who}!'
|
67
|
+
template.render(:who => "world")
|
68
|
+
# => Hello world!
|
67
69
|
|
68
|
-
|
69
|
-
(
|
70
|
+
template = Tilt.new("path/to/a/template.wlang", :dialect => Highlighter)
|
71
|
+
template.render(:who => "world")
|
72
|
+
# => Hello WORLD!
|
70
73
|
```
|
71
74
|
|
72
|
-
|
73
|
-
string `"Hello"` with the result of the higher-order function `($ )` (that itself takes another function as a parameter, corresponding to the sub-template in its brackets delimited blocks) and then the string `" !"`. Providing a concrete semantics to those high-order functions yields so called WLang _dialects_, as we've seen before.
|
74
|
-
|
75
|
-
Having a well-defined semantics allows wlang to properly compile your user-defined dialect and its instantiation engine so as to preserve decent performances. The WLang architecture is a typical compiler chain. This means that, provided some additional coding, you could even define your own language/syntax and reuse the compilation mechanism, provided that you preserve the semantics above.
|
75
|
+
Please note that you should require tilt first, then wlang. Otherwise, you'll have to require `wlang/tilt` explicitely.
|
76
76
|
|
77
|
-
|
77
|
+
# Sinatra integration
|
78
78
|
|
79
|
-
|
79
|
+
WLang comes bundled with built-in support for [Sinatra](https://github.com/sinatra/sinatra). As usual in Sinatra, you can simply invoke wlang as follows:
|
80
80
|
|
81
|
-
|
82
|
-
|
83
|
-
```ruby
|
84
|
-
HighLevel.render 'Hello *{ ${collection} }{ ${self} }{ and } !',
|
85
|
-
collection: 'whos', whos: [ "you", "wlang", "world" ]
|
86
|
-
# => "Hello you and wlang and world"
|
87
|
-
```
|
88
|
-
|
89
|
-
An implementation of `HighLevel` might be as follows:
|
90
|
-
|
91
|
-
```ruby
|
92
|
-
class HighLevel < WLang::Dialect
|
93
|
-
|
94
|
-
def join(buf, expr, main, between)
|
95
|
-
evaluate(expr).each_with_index do |val,i|
|
96
|
-
buf << render(between, val) unless i==0
|
97
|
-
buf << render(main, val).strip
|
81
|
+
get '/' do
|
82
|
+
wlang :index, :locals => { ... }
|
98
83
|
end
|
99
|
-
end
|
100
84
|
|
101
|
-
|
102
|
-
buf << evaluate(fn).to_s
|
103
|
-
end
|
85
|
+
As wlang encourages logic-less templates, you should always use locals. However, there is specific support for layouts and partials, as the following example demonstrates:
|
104
86
|
|
105
|
-
|
106
|
-
|
107
|
-
end
|
108
|
-
```
|
87
|
+
get '/' do
|
88
|
+
wlang :index, :locals => {:who => "world"}
|
89
|
+
end
|
109
90
|
|
110
|
-
|
91
|
+
__END__
|
111
92
|
|
112
|
-
|
93
|
+
@@layout
|
94
|
+
<html>
|
95
|
+
>{yield}
|
96
|
+
</html>
|
113
97
|
|
114
|
-
|
98
|
+
@@index
|
99
|
+
Hello from a partial: >{partial}
|
115
100
|
|
116
|
-
|
117
|
-
|
118
|
-
require 'wlang' # loads Tilt support provided Tilt has already been required
|
119
|
-
|
120
|
-
template = Tilt.new("path/to/a/template.wlang") # suppose 'Hello ${who}!'
|
121
|
-
template.render(:who => "world")
|
122
|
-
# => Hello world!
|
101
|
+
@@partial
|
102
|
+
yeah, a partial saying hello to '${who}'!
|
123
103
|
|
124
|
-
|
125
|
-
template.render(:who => "world")
|
126
|
-
# => Hello WORLD!
|
127
|
-
```
|
104
|
+
Returned body will be (ignoring carriage returns):
|
128
105
|
|
129
|
-
|
106
|
+
<html>Hello from a partial: yeah, a partial saying hello to 'world'!</html>
|
data/lib/wlang.rb
CHANGED
@@ -27,6 +27,14 @@ module WLang
|
|
27
27
|
end
|
28
28
|
module_function :dialect
|
29
29
|
|
30
|
+
SinatraApp = proc{|arg|
|
31
|
+
defined?(Sinatra::Base) && Sinatra::Base===arg
|
32
|
+
}
|
33
|
+
|
34
|
+
TiltTemplate = proc{|arg|
|
35
|
+
defined?(Tilt::Template) && Tilt::Template===arg
|
36
|
+
}
|
37
|
+
|
30
38
|
end # module WLang
|
31
39
|
require 'wlang/compiler'
|
32
40
|
require 'wlang/source'
|
@@ -1,11 +1,11 @@
|
|
1
1
|
grammar WLang::Grammar
|
2
|
-
|
2
|
+
|
3
3
|
rule template
|
4
4
|
(strconcat !.){
|
5
5
|
[:template, [:fn, strconcat.value]]
|
6
6
|
}
|
7
7
|
end
|
8
|
-
|
8
|
+
|
9
9
|
rule strconcat
|
10
10
|
(non_static | static)* {
|
11
11
|
if matches.size == 1
|
@@ -15,53 +15,56 @@ grammar WLang::Grammar
|
|
15
15
|
end
|
16
16
|
}
|
17
17
|
end
|
18
|
-
|
18
|
+
|
19
19
|
rule static
|
20
|
-
(!stop_char .)+ {
|
21
|
-
[:static, to_s]
|
20
|
+
(!stop_char .)+ {
|
21
|
+
[:static, to_s]
|
22
22
|
}
|
23
23
|
end
|
24
|
-
|
24
|
+
|
25
25
|
rule non_static
|
26
26
|
block | wlang
|
27
27
|
end
|
28
|
-
|
28
|
+
|
29
29
|
rule block
|
30
30
|
(fn_start strconcat fn_stop){
|
31
|
-
[:
|
31
|
+
[:strconcat,
|
32
|
+
[:static, captures[:fn_start].first.to_s],
|
33
|
+
captures[:strconcat].first.value,
|
34
|
+
[:static, captures[:fn_stop].first.to_s]]
|
32
35
|
}
|
33
36
|
end
|
34
|
-
|
37
|
+
|
35
38
|
rule wlang
|
36
39
|
(symbols functions){
|
37
40
|
[:wlang, symbols.to_s] + functions.value
|
38
41
|
}
|
39
42
|
end
|
40
|
-
|
43
|
+
|
41
44
|
rule functions
|
42
45
|
function+ { matches.map{|fn| [:fn, fn.value]} }
|
43
46
|
end
|
44
|
-
|
47
|
+
|
45
48
|
rule function
|
46
49
|
(fn_start strconcat fn_stop){
|
47
50
|
strconcat.value
|
48
51
|
}
|
49
52
|
end
|
50
|
-
|
53
|
+
|
51
54
|
rule stop_char
|
52
55
|
fn_start | fn_stop | (symbols fn_start)
|
53
56
|
end
|
54
|
-
|
57
|
+
|
55
58
|
rule symbols
|
56
59
|
/[!\^%"\$&'\*\+\?@~\#,\-\.\/:;=<>\|_]+/
|
57
60
|
end
|
58
|
-
|
61
|
+
|
59
62
|
rule fn_start
|
60
63
|
'{'
|
61
64
|
end
|
62
|
-
|
65
|
+
|
63
66
|
rule fn_stop
|
64
67
|
'}'
|
65
68
|
end
|
66
|
-
|
69
|
+
|
67
70
|
end
|
data/lib/wlang/dialect.rb
CHANGED
@@ -14,8 +14,8 @@ module WLang
|
|
14
14
|
Template.new source, :dialect => self
|
15
15
|
end
|
16
16
|
|
17
|
-
def render(source,
|
18
|
-
compile(source).call(
|
17
|
+
def render(source, *args)
|
18
|
+
compile(source).call(*args)
|
19
19
|
end
|
20
20
|
|
21
21
|
# tag installation and dispatching
|
@@ -139,14 +139,12 @@ module WLang
|
|
139
139
|
def render(fn, scope = nil, buffer = "")
|
140
140
|
if scope.nil?
|
141
141
|
case fn
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
fn.
|
146
|
-
|
147
|
-
|
148
|
-
else
|
149
|
-
raise ArgumentError, "Unable to render `#{fn}`"
|
142
|
+
when String then buffer << fn
|
143
|
+
when Proc then fn.call(self, buffer)
|
144
|
+
when Template then fn.call(@scope, buffer)
|
145
|
+
when TiltTemplate then buffer << fn.render(@scope)
|
146
|
+
else
|
147
|
+
raise ArgumentError, "Unable to render `#{fn}`"
|
150
148
|
end
|
151
149
|
buffer
|
152
150
|
else
|
@@ -156,9 +154,14 @@ module WLang
|
|
156
154
|
|
157
155
|
# evaluation
|
158
156
|
|
157
|
+
# Returns the execution context, defined as the subject of the root scope.
|
158
|
+
def context
|
159
|
+
scope.root.subject
|
160
|
+
end
|
161
|
+
|
159
162
|
# Returns the current rendering scope.
|
160
163
|
def scope
|
161
|
-
@scope
|
164
|
+
@scope || Scope.null
|
162
165
|
end
|
163
166
|
|
164
167
|
# Yields the block with a scope branched with a sub-scope `x`.
|
@@ -177,17 +180,18 @@ module WLang
|
|
177
180
|
# Evaluation is delegated to the scope (@see Scope#evaluate) and the result returned
|
178
181
|
# by this method.
|
179
182
|
#
|
180
|
-
def evaluate(expr, *default)
|
183
|
+
def evaluate(expr, *default, &bl)
|
181
184
|
case expr
|
182
185
|
when Symbol, String
|
183
186
|
catch(:fail) do
|
184
|
-
return scope.evaluate(expr, *default)
|
187
|
+
return scope.evaluate(expr, self, *default, &bl)
|
185
188
|
end
|
186
189
|
raise NameError, "Unable to find `#{expr}`"
|
187
190
|
else
|
188
|
-
evaluate(render(expr), *default)
|
191
|
+
evaluate(render(expr), *default, &bl)
|
189
192
|
end
|
190
193
|
end
|
194
|
+
alias :value_of :evaluate
|
191
195
|
|
192
196
|
end # class Dialect
|
193
197
|
end # module WLang
|
data/lib/wlang/html.rb
CHANGED
@@ -5,11 +5,6 @@ module WLang
|
|
5
5
|
|
6
6
|
module Helpers
|
7
7
|
|
8
|
-
def value_of(fn, *defaults)
|
9
|
-
evaluate(render(fn).to_s.strip, *defaults)
|
10
|
-
end
|
11
|
-
private :value_of
|
12
|
-
|
13
8
|
def to_html(val)
|
14
9
|
val = val.to_html if val.respond_to?(:to_html)
|
15
10
|
val = to_html(val.call) if val.is_a?(Proc)
|
@@ -28,12 +23,12 @@ module WLang
|
|
28
23
|
module HighOrderFunctions
|
29
24
|
|
30
25
|
def bang(buf, fn)
|
31
|
-
val =
|
26
|
+
val = evaluate(fn).to_s
|
32
27
|
render(val, nil, buf)
|
33
28
|
end
|
34
29
|
|
35
30
|
def plus(buf, fn)
|
36
|
-
val =
|
31
|
+
val = evaluate(fn)
|
37
32
|
val = to_html(val) unless val.is_a?(Template)
|
38
33
|
render(val, nil, buf)
|
39
34
|
end
|
@@ -56,7 +51,7 @@ module WLang
|
|
56
51
|
end
|
57
52
|
|
58
53
|
def question(buf, fn_if, fn_then, fn_else)
|
59
|
-
val =
|
54
|
+
val = evaluate(fn_if)
|
60
55
|
val = val.call if Proc===val
|
61
56
|
block = val ? fn_then : fn_else
|
62
57
|
render(block, nil, buf) if block
|
@@ -67,7 +62,7 @@ module WLang
|
|
67
62
|
end
|
68
63
|
|
69
64
|
def star(buf, coll_fn, elm_fn, between_fn)
|
70
|
-
collection =
|
65
|
+
collection = evaluate(coll_fn)
|
71
66
|
collection.each_with_index do |elm,i|
|
72
67
|
render(between_fn, elm, buf) if between_fn and (i > 0)
|
73
68
|
render(elm_fn, elm, buf)
|
@@ -75,13 +70,14 @@ module WLang
|
|
75
70
|
end
|
76
71
|
|
77
72
|
def greater(buf, fn)
|
78
|
-
val =
|
73
|
+
val = evaluate(fn)
|
79
74
|
val = Html.compile(val) if String === val
|
75
|
+
val = val.call if Proc === val and val.arity<=0
|
80
76
|
render(val, nil, buf)
|
81
77
|
end
|
82
78
|
|
83
79
|
def sharp(buf, who_fn, then_fn)
|
84
|
-
val =
|
80
|
+
val = evaluate(who_fn, nil)
|
85
81
|
if val and not(val.respond_to?(:empty?) and val.empty?)
|
86
82
|
render(then_fn, val, buf)
|
87
83
|
end
|
data/lib/wlang/scope.rb
CHANGED
@@ -4,36 +4,37 @@ module WLang
|
|
4
4
|
attr_reader :subject
|
5
5
|
attr_reader :parent
|
6
6
|
|
7
|
-
def initialize(subject
|
8
|
-
@subject
|
7
|
+
def initialize(subject)
|
8
|
+
@subject = subject
|
9
|
+
@parent = nil
|
9
10
|
end
|
10
11
|
|
11
|
-
def self.
|
12
|
-
@
|
12
|
+
def self.null
|
13
|
+
@null ||= NullScope.new
|
13
14
|
end
|
14
15
|
|
15
|
-
def self.coerce(arg
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
else
|
26
|
-
ObjectScope
|
27
|
-
end
|
28
|
-
clazz.new(arg, parent)
|
16
|
+
def self.coerce(arg)
|
17
|
+
case arg
|
18
|
+
when Hash then ObjectScope.new(arg)
|
19
|
+
when Scope then arg
|
20
|
+
when SinatraApp then SinatraScope.new(arg)
|
21
|
+
when Binding then BindingScope.new(arg)
|
22
|
+
when Proc then ProcScope.new(arg)
|
23
|
+
else
|
24
|
+
ObjectScope.new(arg)
|
25
|
+
end
|
29
26
|
end
|
30
27
|
|
31
28
|
def self.chain(scopes)
|
32
|
-
scopes.compact.inject(
|
29
|
+
scopes.compact.inject(Scope.null){|p,c| p.push(c)}
|
30
|
+
end
|
31
|
+
|
32
|
+
def root
|
33
|
+
parent ? parent.root : self
|
33
34
|
end
|
34
35
|
|
35
36
|
def push(x)
|
36
|
-
Scope.coerce(x
|
37
|
+
append(Scope.coerce(x))
|
37
38
|
end
|
38
39
|
|
39
40
|
def pop
|
@@ -44,23 +45,62 @@ module WLang
|
|
44
45
|
yield(self.push(x))
|
45
46
|
end
|
46
47
|
|
47
|
-
def evaluate(expr, *default)
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
48
|
+
def evaluate(expr, dialect, *default, &bl)
|
49
|
+
expr = expr.to_s.strip
|
50
|
+
unfound = lambda do
|
51
|
+
if default.empty?
|
52
|
+
bl ? bl.call(expr) : throw(:fail)
|
53
|
+
else
|
54
|
+
default.first
|
55
|
+
end
|
56
|
+
end
|
57
|
+
if expr.index('.').nil?
|
58
|
+
fetch(expr.to_sym, dialect, unfound)
|
52
59
|
else
|
53
60
|
keys = expr.split('.').map(&:to_sym)
|
54
61
|
keys.inject(self){|scope,key|
|
55
|
-
|
62
|
+
found = scope.fetch(key, dialect, unfound)
|
63
|
+
Scope.coerce(found)
|
56
64
|
}.subject
|
57
65
|
end
|
58
66
|
end
|
59
67
|
|
68
|
+
def subjects
|
69
|
+
arr = []
|
70
|
+
visit(:top_down){|s| arr << s.subject}
|
71
|
+
arr
|
72
|
+
end
|
73
|
+
|
74
|
+
protected
|
75
|
+
|
76
|
+
def visit(mode = :top_down, &visitor)
|
77
|
+
visitor.call(self) unless mode == :top_down
|
78
|
+
parent.visit(mode, &visitor) if parent
|
79
|
+
visitor.call(self) if mode == :top_down
|
80
|
+
end
|
81
|
+
|
82
|
+
def append(x)
|
83
|
+
x.prepend(self)
|
84
|
+
end
|
85
|
+
|
86
|
+
def prepend(x)
|
87
|
+
newp = parent ? parent.prepend(x) : x
|
88
|
+
dup.with_parent!(newp)
|
89
|
+
end
|
90
|
+
|
91
|
+
def with_parent!(p)
|
92
|
+
@parent = p
|
93
|
+
self
|
94
|
+
end
|
95
|
+
|
96
|
+
def safe_parent
|
97
|
+
parent || Scope.null
|
98
|
+
end
|
99
|
+
|
60
100
|
end # class Scope
|
61
101
|
end # module WLang
|
62
|
-
require 'wlang/scope/
|
63
|
-
require 'wlang/scope/proxy_scope'
|
102
|
+
require 'wlang/scope/null_scope'
|
64
103
|
require 'wlang/scope/object_scope'
|
65
104
|
require 'wlang/scope/binding_scope'
|
66
105
|
require 'wlang/scope/proc_scope'
|
106
|
+
require 'wlang/scope/sinatra_scope'
|