wlang 2.0.0.beta → 2.0.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.
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