wlang 2.0.1 → 2.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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'
|