wlang 2.0.0.beta → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +2 -8
- data/Gemfile.lock +4 -8
- data/Manifest.txt +0 -2
- data/README.md +36 -7
- data/lib/wlang.rb +3 -0
- data/lib/wlang/command.rb +3 -11
- data/lib/wlang/compiler.rb +11 -20
- data/lib/wlang/compiler/autospacing.rb +4 -2
- data/lib/wlang/compiler/dialect_enforcer.rb +1 -1
- data/lib/wlang/compiler/to_ruby_code.rb +1 -1
- data/lib/wlang/dialect.rb +163 -23
- data/lib/wlang/html.rb +9 -8
- data/lib/wlang/loader.rb +2 -4
- data/lib/wlang/scope.rb +17 -8
- data/lib/wlang/scope/proc_scope.rb +18 -0
- data/lib/wlang/source.rb +56 -0
- data/lib/wlang/source/front_matter.rb +51 -0
- data/lib/wlang/template.rb +55 -17
- data/lib/wlang/tilt.rb +3 -0
- data/lib/wlang/tilt/wlang_template.rb +43 -0
- data/lib/wlang/version.rb +1 -2
- data/spec/fixtures/templates/{hello.tpl → hello.wlang} +0 -0
- data/spec/fixtures/templates/hello_with_data.wlang +4 -0
- data/spec/fixtures/templates/hello_with_explicit_locals.wlang +6 -0
- data/spec/fixtures/templates/hello_with_partials.wlang +7 -0
- data/spec/integration/examples/{1-basics.txt → 1-html-intro/1-basics.md} +1 -1
- data/spec/integration/examples/{2-imperative.txt → 1-html-intro/2-imperative.md} +1 -1
- data/spec/integration/examples/{3-partials.txt → 1-html-intro/3-partials.md} +0 -0
- data/spec/integration/examples/{4-recursion.txt → 1-html-intro/4-recursion.md} +1 -2
- data/spec/integration/examples/1-html-intro/5-polymorphism.md +17 -0
- data/spec/integration/html/test_caret.rb +15 -2
- data/spec/integration/html/test_question.rb +12 -2
- data/spec/integration/html/test_sharp.rb +5 -1
- data/spec/integration/html/test_star.rb +1 -3
- data/spec/integration/test_examples.rb +2 -1
- data/spec/integration/test_readme.rb +14 -2
- data/spec/integration/tilt/test_wlang_template.rb +13 -0
- data/spec/spec_helper.rb +3 -3
- data/spec/unit/compiler/test_dialect_enforcer.rb +1 -1
- data/spec/unit/compiler/test_to_ruby_proc.rb +15 -0
- data/spec/unit/dialect/test_compile.rb +0 -10
- data/spec/unit/dialect/test_evaluate.rb +36 -28
- data/spec/unit/dialect/test_new.rb +61 -0
- data/spec/unit/dialect/test_tag.rb +36 -0
- data/spec/unit/dialect/test_tag_dispatching_name.rb +22 -0
- data/spec/unit/dialect/test_with_scope.rb +8 -11
- data/spec/unit/scope/test_chain.rb +29 -0
- data/spec/unit/scope/test_coerce.rb +13 -2
- data/spec/unit/scope/test_proc_scope.rb +18 -0
- data/spec/unit/source/front_matter/test_locals.rb +39 -0
- data/spec/unit/source/front_matter/test_template_content.rb +22 -0
- data/spec/unit/source/test_locals.rb +12 -0
- data/spec/unit/source/test_path.rb +27 -0
- data/spec/unit/source/test_template_content.rb +37 -0
- data/spec/unit/source/test_with_front_matter.rb +19 -0
- data/spec/unit/template/test_call.rb +16 -0
- data/spec/unit/template/test_new.rb +20 -0
- data/spec/unit/template/test_path.rb +28 -0
- data/spec/unit/template/test_render.rb +44 -0
- data/spec/unit/template/test_to_ast.rb +12 -0
- data/spec/unit/template/test_to_ruby_code.rb +13 -0
- data/spec/unit/template/test_to_ruby_proc.rb +12 -0
- data/spec/unit/template/test_yaml_front_matter.rb +22 -0
- data/spec/unit/tilt/test_wlang_template.rb +65 -0
- data/wlang.gemspec +3 -5
- data/wlang.noespec +12 -17
- metadata +117 -85
- data/lib/wlang/dialect/dispatching.rb +0 -51
- data/lib/wlang/dialect/evaluation.rb +0 -30
- data/lib/wlang/dialect/tags.rb +0 -50
- data/lib/wlang/mustang.rb +0 -90
- data/spec/integration/test_mustang.rb +0 -120
- data/spec/unit/dialect/test_dispatching.rb +0 -19
- data/spec/unit/dialect/test_tags.rb +0 -32
@@ -1,30 +0,0 @@
|
|
1
|
-
module WLang
|
2
|
-
class Dialect
|
3
|
-
module Evaluation
|
4
|
-
|
5
|
-
def scope
|
6
|
-
@scope ||= Scope.root
|
7
|
-
end
|
8
|
-
|
9
|
-
def with_scope(x)
|
10
|
-
@scope = scope.push(x)
|
11
|
-
res = yield
|
12
|
-
@scope = scope.pop
|
13
|
-
res
|
14
|
-
end
|
15
|
-
|
16
|
-
def evaluate(expr, *default)
|
17
|
-
case expr
|
18
|
-
when Symbol, String
|
19
|
-
catch(:fail) do
|
20
|
-
return scope.evaluate(expr, *default)
|
21
|
-
end
|
22
|
-
raise NameError, "Unable to find `#{expr}`"
|
23
|
-
else
|
24
|
-
evaluate(render(expr), *default)
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
end # module Evaluation
|
29
|
-
end # class Dialect
|
30
|
-
end # module WLang
|
data/lib/wlang/dialect/tags.rb
DELETED
@@ -1,50 +0,0 @@
|
|
1
|
-
module WLang
|
2
|
-
class Dialect
|
3
|
-
module Tags
|
4
|
-
|
5
|
-
module ClassMethods
|
6
|
-
|
7
|
-
protected
|
8
|
-
|
9
|
-
def tag(symbols, dialects = nil, method = nil, &block)
|
10
|
-
if block
|
11
|
-
tag(symbols, dialects, block)
|
12
|
-
else
|
13
|
-
dialects, method = nil, dialects if method.nil?
|
14
|
-
define_tag_method(symbols, dialects, method)
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
end
|
19
|
-
|
20
|
-
module InstanceMethods
|
21
|
-
|
22
|
-
protected
|
23
|
-
|
24
|
-
def render(fn, scope = nil, buffer = "")
|
25
|
-
if scope.nil?
|
26
|
-
case fn
|
27
|
-
when String
|
28
|
-
buffer << fn
|
29
|
-
when Proc
|
30
|
-
fn.call(self, buffer)
|
31
|
-
when Template
|
32
|
-
fn.call(@scope, buffer)
|
33
|
-
else
|
34
|
-
raise ArgumentError, "Unable to render `#{fn}`"
|
35
|
-
end
|
36
|
-
else
|
37
|
-
with_scope(scope){ render(fn, nil, buffer) }
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
end
|
42
|
-
|
43
|
-
def self.included(mod)
|
44
|
-
mod.instance_eval{ include(InstanceMethods) }
|
45
|
-
mod.extend(ClassMethods)
|
46
|
-
end
|
47
|
-
|
48
|
-
end # module Tags
|
49
|
-
end # class Dialect
|
50
|
-
end # module WLang
|
data/lib/wlang/mustang.rb
DELETED
@@ -1,90 +0,0 @@
|
|
1
|
-
require 'wlang'
|
2
|
-
require 'wlang/dummy'
|
3
|
-
module WLang
|
4
|
-
#
|
5
|
-
# A WLang dialect mimicing the excellent Mustache.
|
6
|
-
#
|
7
|
-
# This dialect installs the following high-order functions:
|
8
|
-
#
|
9
|
-
# * `${...}` mimics mustache's `{{ ... }}` that is, it evaluates the variable and
|
10
|
-
# returns the HTML-escaped string
|
11
|
-
# * `+{...}` mimics mustache's `{{{ ... }}}` that is, it evaluates the variable and
|
12
|
-
# returns its string representation (through `to_s`)
|
13
|
-
# * `#{..1..}{..2..}` mimics mustache's `{{#..1..}}..2..{{/..1..}}`. For false and nil,
|
14
|
-
# it returns nil. For scopes and ranges, it instantiates the second block in the scope
|
15
|
-
# of each element in turn and returns the concatenation of instantiation results. For
|
16
|
-
# a Proc, it calls it, passing a rendering continuation as first argument. Every other
|
17
|
-
# object is used as a new scope in which the second block is instantiated.
|
18
|
-
# * `^{..1..}{..2..}` mimics mustache's `{{^..1..}}..2..{{/..1..}}`, instantiating the
|
19
|
-
# second only if the evaluation of the first yields false, nil, an empty list or an
|
20
|
-
# unbound variable.
|
21
|
-
# * `>{...}` mimics mustache's `{{>...}}`, instantiating the partial denoted by the
|
22
|
-
# evaluated expression.
|
23
|
-
# * `!{...}` mimics mustache's `{{!...}}`, taking the block content as a comment
|
24
|
-
# therefore skipping it.
|
25
|
-
#
|
26
|
-
class Mustang < WLang::Dialect
|
27
|
-
|
28
|
-
module HighOrderFunctions
|
29
|
-
|
30
|
-
def plus(buf, fn)
|
31
|
-
if x = evaluate(fn)
|
32
|
-
buf << x.to_s
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
def escape(buf, fn)
|
37
|
-
buf << Temple::Utils.escape_html(evaluate(fn))
|
38
|
-
end
|
39
|
-
|
40
|
-
def section(buf, fn1, fn2)
|
41
|
-
case x = evaluate(fn1)
|
42
|
-
when FalseClass, NilClass
|
43
|
-
nil
|
44
|
-
when Array, Range
|
45
|
-
x.each{|item|
|
46
|
-
render(fn2, item, buf)
|
47
|
-
}
|
48
|
-
when Proc
|
49
|
-
buf << x.call(lambda{ render(fn2) })
|
50
|
-
else
|
51
|
-
render(fn2, x, buf)
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
def inverted(buf, fn1, fn2)
|
56
|
-
case x = evaluate(fn1)
|
57
|
-
when FalseClass, NilClass
|
58
|
-
render(fn2, scope, buf)
|
59
|
-
when Array
|
60
|
-
render(fn2, scope, buf) if x.empty?
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
def comment(buf, fn)
|
65
|
-
end
|
66
|
-
|
67
|
-
def partial(buf, fn)
|
68
|
-
if x = Mustang.compile(evaluate(fn))
|
69
|
-
render(x, scope, buf)
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
end
|
74
|
-
include HighOrderFunctions
|
75
|
-
|
76
|
-
def evaluate(expr)
|
77
|
-
super
|
78
|
-
rescue
|
79
|
-
nil
|
80
|
-
end
|
81
|
-
|
82
|
-
tag '+', :plus
|
83
|
-
tag '$', :escape
|
84
|
-
tag '#', :section
|
85
|
-
tag '^', :inverted
|
86
|
-
tag '>', :partial
|
87
|
-
tag '!', [WLang::Dummy], :comment
|
88
|
-
|
89
|
-
end # class Mustang
|
90
|
-
end # module WLang
|
@@ -1,120 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
require 'wlang/mustang'
|
3
|
-
module WLang
|
4
|
-
describe Mustang do
|
5
|
-
|
6
|
-
def m(tpl, scope = {}, buffer = "")
|
7
|
-
Mustang.render(tpl, scope, buffer)
|
8
|
-
end
|
9
|
-
|
10
|
-
context '+{...} mimicing {{{ ... }}}' do
|
11
|
-
it "renders nothing on nil" do
|
12
|
-
m('Hello +{who}', :who => nil).should eq("Hello ")
|
13
|
-
end
|
14
|
-
it "renders nothing on unknown" do
|
15
|
-
m('Hello +{who}', {}).should eq("Hello ")
|
16
|
-
end
|
17
|
-
it "renders the variable if known" do
|
18
|
-
m('Hello +{who}', :who => "World").should eq("Hello World")
|
19
|
-
end
|
20
|
-
it "calls to_s on such variable" do
|
21
|
-
m('Hello +{who}', :who => 12).should eq("Hello 12")
|
22
|
-
end
|
23
|
-
it "does not escape html" do
|
24
|
-
m('Hello +{who}', :who => "<script>").should eq("Hello <script>")
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
context "${...} mimicing {{ ... }}" do
|
29
|
-
it "renders nothing on nil" do
|
30
|
-
m('Hello ${who}', :who => nil).should eq("Hello ")
|
31
|
-
end
|
32
|
-
it "renders nothing on unknown" do
|
33
|
-
m('Hello ${who}', {}).should eq("Hello ")
|
34
|
-
end
|
35
|
-
it "renders the variable if known" do
|
36
|
-
m('Hello ${who}', :who => "World").should eq("Hello World")
|
37
|
-
end
|
38
|
-
it "calls to_s on such variable" do
|
39
|
-
m('Hello ${who}', :who => 12).should eq("Hello 12")
|
40
|
-
end
|
41
|
-
it "does escape html" do
|
42
|
-
m('Hello ${who}', :who => "<script>").should eq("Hello <script>")
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
context '#{..1..}{..2..} mimicing {{#..1..}}..2..{{/..1..}} ' do
|
47
|
-
it 'skips the section on false' do
|
48
|
-
m('Hello #{present}{World}', :present => false).should eq("Hello ")
|
49
|
-
end
|
50
|
-
it 'skips the section on nil' do
|
51
|
-
m('Hello #{present}{World}', :present => nil).should eq("Hello ")
|
52
|
-
end
|
53
|
-
it 'skips the section on missing' do
|
54
|
-
m('Hello #{present}{World}').should eq("Hello ")
|
55
|
-
end
|
56
|
-
it 'skips the section on empty lists' do
|
57
|
-
m('Hello #{present}{World}', :present => []).should eq("Hello ")
|
58
|
-
end
|
59
|
-
it 'iterates on non-empty lists' do
|
60
|
-
repo = [{:name => "resque"},{:name => "hub"},{:name => "rip"}]
|
61
|
-
m('Hello #{repo}{<b>${name}</b>}', :repo => repo).should eq("Hello <b>resque</b><b>hub</b><b>rip</b>")
|
62
|
-
end
|
63
|
-
it 'iterates on ranges' do
|
64
|
-
m('Hello #{range}{.}', :range => 1..10).should eq("Hello ..........")
|
65
|
-
end
|
66
|
-
it 'passes the block to a lambda' do
|
67
|
-
wrapped = lambda{|fn| "<b>#{fn.call}</b>"}
|
68
|
-
scope = {:wrapped => wrapped, :name => "World"}
|
69
|
-
m('#{wrapped}{Hello ${name}}', scope).should eq("<b>Hello World</b>")
|
70
|
-
end
|
71
|
-
it 'use a Hash a a new scope' do
|
72
|
-
m('Hello #{person}{${name}}', :person => {:name => "World"}).should eq("Hello World")
|
73
|
-
end
|
74
|
-
it 'use a Struct a a new scope' do
|
75
|
-
person = Struct.new(:name).new("World")
|
76
|
-
m('Hello #{person}{${name}}', :person => person).should eq("Hello World")
|
77
|
-
end
|
78
|
-
it 'outputs frequently when iterating' do
|
79
|
-
m('#{range}{.}', {:range => 1..10}, []).should eq(Array.new(10, '.'))
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
|
-
context "^{..1..}{..2..} mimicing {{^..1..}}..2..{{/..1..}}" do
|
84
|
-
it 'renders the section on false' do
|
85
|
-
m('Hello ^{missing}{World}', :missing => false).should eq("Hello World")
|
86
|
-
end
|
87
|
-
it 'renders the section on nil' do
|
88
|
-
m('Hello ^{missing}{World}', :missing => nil).should eq("Hello World")
|
89
|
-
end
|
90
|
-
it 'renders the section on missing' do
|
91
|
-
m('Hello ^{missing}{World}').should eq("Hello World")
|
92
|
-
end
|
93
|
-
it 'renders the section on empty lists' do
|
94
|
-
m('Hello ^{missing}{World}', :missing => []).should eq("Hello World")
|
95
|
-
end
|
96
|
-
it 'does not iterate lists' do
|
97
|
-
repo = [{:name => "resque"},{:name => "hub"},{:name => "rip"}]
|
98
|
-
m('Hello ^{repo}{<b>${name}</b>}', :repo => repo).should eq("Hello ")
|
99
|
-
end
|
100
|
-
end
|
101
|
-
|
102
|
-
context "!{...} mimicing {{!...}}" do
|
103
|
-
it 'skips the section altogether' do
|
104
|
-
m('Hello !{this is a comment} world').should eq("Hello world")
|
105
|
-
end
|
106
|
-
end
|
107
|
-
|
108
|
-
context '>{...} mimicing {{>...}}' do
|
109
|
-
it 'renders the partial' do
|
110
|
-
scope = {:who => "<b>${name}</b>", :name => "World"}
|
111
|
-
m("Hello >{who}", scope).should eq("Hello <b>World</b>")
|
112
|
-
end
|
113
|
-
it 'supports a pre-compiled partial' do
|
114
|
-
scope = {:who => Mustang.compile("<b>${name}</b>"), :name => "World"}
|
115
|
-
m("Hello >{who}", scope).should eq("Hello <b>World</b>")
|
116
|
-
end
|
117
|
-
end
|
118
|
-
|
119
|
-
end # describe Mustang
|
120
|
-
end # module WLang
|
@@ -1,19 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
module WLang
|
3
|
-
describe Dialect::Dispatching do
|
4
|
-
include Dialect::Dispatching::ClassMethods
|
5
|
-
|
6
|
-
describe 'tag_dispatching_name' do
|
7
|
-
it "works with a single char" do
|
8
|
-
tag_dispatching_name("$").should eq(:_tag_36)
|
9
|
-
end
|
10
|
-
it "works with a multiple chars" do
|
11
|
-
tag_dispatching_name("!$").should eq(:_tag_33_36)
|
12
|
-
end
|
13
|
-
it "works with an array" do
|
14
|
-
tag_dispatching_name(['!', '$']).should eq(:_tag_33_36)
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
end # describe Dialect
|
19
|
-
end # module WLang
|
@@ -1,32 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
module WLang
|
3
|
-
describe Dialect::Tags do
|
4
|
-
|
5
|
-
describe 'tag' do
|
6
|
-
include Dialect::Tags::ClassMethods
|
7
|
-
|
8
|
-
def define_tag_method(*args)
|
9
|
-
args
|
10
|
-
end
|
11
|
-
|
12
|
-
it "works with a symbol" do
|
13
|
-
tag("$", :dollar).should eq(["$", nil, :dollar])
|
14
|
-
end
|
15
|
-
|
16
|
-
it "works with a single proc" do
|
17
|
-
proc = lambda{|buf,fn| }
|
18
|
-
tag("$", &proc).should eq(["$", nil, proc])
|
19
|
-
end
|
20
|
-
|
21
|
-
it "allows specifying dialects with a symbol" do
|
22
|
-
tag("$", [Foo], :dollar).should eq(["$", [Foo], :dollar])
|
23
|
-
end
|
24
|
-
|
25
|
-
it "allows specifying dialects with a proc" do
|
26
|
-
proc = lambda{|buf,fn| }
|
27
|
-
tag("$", [Foo], &proc).should eq(["$", [Foo], proc])
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
end # describe Dialect
|
32
|
-
end # module WLang
|