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.
Files changed (74) hide show
  1. data/Gemfile +2 -8
  2. data/Gemfile.lock +4 -8
  3. data/Manifest.txt +0 -2
  4. data/README.md +36 -7
  5. data/lib/wlang.rb +3 -0
  6. data/lib/wlang/command.rb +3 -11
  7. data/lib/wlang/compiler.rb +11 -20
  8. data/lib/wlang/compiler/autospacing.rb +4 -2
  9. data/lib/wlang/compiler/dialect_enforcer.rb +1 -1
  10. data/lib/wlang/compiler/to_ruby_code.rb +1 -1
  11. data/lib/wlang/dialect.rb +163 -23
  12. data/lib/wlang/html.rb +9 -8
  13. data/lib/wlang/loader.rb +2 -4
  14. data/lib/wlang/scope.rb +17 -8
  15. data/lib/wlang/scope/proc_scope.rb +18 -0
  16. data/lib/wlang/source.rb +56 -0
  17. data/lib/wlang/source/front_matter.rb +51 -0
  18. data/lib/wlang/template.rb +55 -17
  19. data/lib/wlang/tilt.rb +3 -0
  20. data/lib/wlang/tilt/wlang_template.rb +43 -0
  21. data/lib/wlang/version.rb +1 -2
  22. data/spec/fixtures/templates/{hello.tpl → hello.wlang} +0 -0
  23. data/spec/fixtures/templates/hello_with_data.wlang +4 -0
  24. data/spec/fixtures/templates/hello_with_explicit_locals.wlang +6 -0
  25. data/spec/fixtures/templates/hello_with_partials.wlang +7 -0
  26. data/spec/integration/examples/{1-basics.txt → 1-html-intro/1-basics.md} +1 -1
  27. data/spec/integration/examples/{2-imperative.txt → 1-html-intro/2-imperative.md} +1 -1
  28. data/spec/integration/examples/{3-partials.txt → 1-html-intro/3-partials.md} +0 -0
  29. data/spec/integration/examples/{4-recursion.txt → 1-html-intro/4-recursion.md} +1 -2
  30. data/spec/integration/examples/1-html-intro/5-polymorphism.md +17 -0
  31. data/spec/integration/html/test_caret.rb +15 -2
  32. data/spec/integration/html/test_question.rb +12 -2
  33. data/spec/integration/html/test_sharp.rb +5 -1
  34. data/spec/integration/html/test_star.rb +1 -3
  35. data/spec/integration/test_examples.rb +2 -1
  36. data/spec/integration/test_readme.rb +14 -2
  37. data/spec/integration/tilt/test_wlang_template.rb +13 -0
  38. data/spec/spec_helper.rb +3 -3
  39. data/spec/unit/compiler/test_dialect_enforcer.rb +1 -1
  40. data/spec/unit/compiler/test_to_ruby_proc.rb +15 -0
  41. data/spec/unit/dialect/test_compile.rb +0 -10
  42. data/spec/unit/dialect/test_evaluate.rb +36 -28
  43. data/spec/unit/dialect/test_new.rb +61 -0
  44. data/spec/unit/dialect/test_tag.rb +36 -0
  45. data/spec/unit/dialect/test_tag_dispatching_name.rb +22 -0
  46. data/spec/unit/dialect/test_with_scope.rb +8 -11
  47. data/spec/unit/scope/test_chain.rb +29 -0
  48. data/spec/unit/scope/test_coerce.rb +13 -2
  49. data/spec/unit/scope/test_proc_scope.rb +18 -0
  50. data/spec/unit/source/front_matter/test_locals.rb +39 -0
  51. data/spec/unit/source/front_matter/test_template_content.rb +22 -0
  52. data/spec/unit/source/test_locals.rb +12 -0
  53. data/spec/unit/source/test_path.rb +27 -0
  54. data/spec/unit/source/test_template_content.rb +37 -0
  55. data/spec/unit/source/test_with_front_matter.rb +19 -0
  56. data/spec/unit/template/test_call.rb +16 -0
  57. data/spec/unit/template/test_new.rb +20 -0
  58. data/spec/unit/template/test_path.rb +28 -0
  59. data/spec/unit/template/test_render.rb +44 -0
  60. data/spec/unit/template/test_to_ast.rb +12 -0
  61. data/spec/unit/template/test_to_ruby_code.rb +13 -0
  62. data/spec/unit/template/test_to_ruby_proc.rb +12 -0
  63. data/spec/unit/template/test_yaml_front_matter.rb +22 -0
  64. data/spec/unit/tilt/test_wlang_template.rb +65 -0
  65. data/wlang.gemspec +3 -5
  66. data/wlang.noespec +12 -17
  67. metadata +117 -85
  68. data/lib/wlang/dialect/dispatching.rb +0 -51
  69. data/lib/wlang/dialect/evaluation.rb +0 -30
  70. data/lib/wlang/dialect/tags.rb +0 -50
  71. data/lib/wlang/mustang.rb +0 -90
  72. data/spec/integration/test_mustang.rb +0 -120
  73. data/spec/unit/dialect/test_dispatching.rb +0 -19
  74. 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
@@ -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
@@ -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 &lt;script&gt;")
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