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
@@ -3,11 +3,17 @@ require 'wlang/html'
3
3
  module WLang
4
4
  describe Html, "?{...}" do
5
5
 
6
+ debug = Module.new{ def inspect; "lambda{ #{call.inspect} }"; end }
7
+
6
8
  def render(tpl, scope = {})
7
9
  Html.render(tpl, scope, "")
8
10
  end
9
11
 
10
- [true, "Something", []].each do |test|
12
+ [ true,
13
+ "Something",
14
+ [],
15
+ lambda{ true }.extend(debug)
16
+ ].each do |test|
11
17
  context "when #{test.inspect}" do
12
18
  it 'renders the then block' do
13
19
  render("?{test}{hello}", binding).should eq("hello")
@@ -18,7 +24,11 @@ module WLang
18
24
  end
19
25
  end
20
26
 
21
- [false, nil].each do |test|
27
+ [ false,
28
+ nil,
29
+ lambda{ false }.extend(debug),
30
+ lambda{ nil }.extend(debug)
31
+ ].each do |test|
22
32
  context "when #{test.inspect}" do
23
33
  it 'do not render the then block' do
24
34
  render("?{test}{hello}", binding).should eq("")
@@ -17,5 +17,9 @@ module WLang
17
17
  render('Hello #{scope}{${who}}', binding).should eq("Hello ")
18
18
  end
19
19
 
20
+ it 'allows undefined variables' do
21
+ render('Hello #{scope}{${who}}', binding).should eq("Hello ")
22
+ end
23
+
20
24
  end
21
- end
25
+ end
@@ -18,9 +18,7 @@ module WLang
18
18
  end
19
19
 
20
20
  it 'preserves spacing in the third block' do
21
- pending{
22
- render("*{numbers}{+{self}}{, }", binding).should eq("1, 2, 3")
23
- }
21
+ render("*{numbers}{+{self}}{, }", binding).should eq("1, 2, 3")
24
22
  end
25
23
 
26
24
  it 'renders nothing on empty collections' do
@@ -14,7 +14,8 @@ module WLang
14
14
  end
15
15
 
16
16
  let(:expected) do
17
- Path.dir/:examples/ex_file.basename.sub_ext(".txt")
17
+ from, to = root_folder, Path.dir
18
+ (to/(ex_file % from)).rm_ext
18
19
  end
19
20
 
20
21
  it 'is instantiated as expected with autospacing' do
@@ -1,7 +1,6 @@
1
1
  require 'spec_helper'
2
- require 'wlang/mustang'
3
2
  module WLang
4
- describe Mustang do
3
+ describe "Examples in README.md" do
5
4
 
6
5
  describe "The Highlighter example" do
7
6
 
@@ -52,5 +51,18 @@ module WLang
52
51
  end
53
52
  end
54
53
 
54
+ describe 'tilt integration' do
55
+ it 'works as announced' do
56
+ require 'tilt' # needed in your bundle, not a wlang dependency
57
+ require 'wlang/tilt' # load wlang integration specifycally
58
+
59
+ template = Tilt.new(hello_path.to_s) # suppose 'Hello ${who}!'
60
+ template.render(:who => "world").should eq('Hello world!')
61
+
62
+ template = Tilt.new(hello_path.to_s, :dialect => Highlighter)
63
+ template.render(:who => "world").should eq('Hello WORLD!')
64
+ end
65
+ end
66
+
55
67
  end
56
68
  end
@@ -0,0 +1,13 @@
1
+ require 'tilt'
2
+ require 'wlang/tilt'
3
+ describe 'WLang integration with tilt' do
4
+
5
+ it 'allows invoking tilt directly' do
6
+ Tilt.new(hello_path.to_s).render(:who => "world").should eq("Hello world!")
7
+ end
8
+
9
+ it 'allows specifying the dialect' do
10
+ Tilt.new(hello_path.to_s, :dialect => Upcasing).render.should eq("Hello WHO!")
11
+ end
12
+
13
+ end
@@ -24,7 +24,7 @@ module Helpers
24
24
  end
25
25
 
26
26
  def tpl_path(what)
27
- what = "#{what}.tpl" if what.is_a?(Symbol)
27
+ what = "#{what}.wlang" if what.is_a?(Symbol)
28
28
  fixtures_folder/:templates/what
29
29
  end
30
30
 
@@ -38,7 +38,7 @@ module Helpers
38
38
  end
39
39
 
40
40
  # Install helper methods for templates
41
- fixtures_folder.glob("templates/*.tpl").each do |f|
41
+ fixtures_folder.glob("templates/*.wlang").each do |f|
42
42
  name = f.basename.without_extension
43
43
  define_method(:"#{name}_path") do
44
44
  fixtures_folder/:templates/f.basename
@@ -59,5 +59,5 @@ include Helpers
59
59
  # Configure rspec
60
60
  RSpec.configure do |c|
61
61
  c.include Helpers
62
- c.filter_run_excluding :hash_ordering => true if RUBY_VERSION < "1.9"
62
+ c.filter_run_excluding :hash_ordering => (RUBY_VERSION < "1.9")
63
63
  end
@@ -12,7 +12,7 @@ module WLang
12
12
  tag('!$') do |buf,fn| buf << "!$" end
13
13
  tag('*') do |buf,fn1,fn2| end
14
14
  tag('%', [WLang::Dummy]) do |buf, fn| end
15
- }.factor
15
+ }.new
16
16
  }
17
17
 
18
18
  describe 'find_dispatching_method' do
@@ -0,0 +1,15 @@
1
+ require 'spec_helper'
2
+ module WLang
3
+ describe Compiler, 'to_ruby_proc' do
4
+
5
+ def to_ruby_proc(source)
6
+ Compiler.new(WLang::Dialect.new).to_ruby_proc(source)
7
+ end
8
+
9
+ it 'returns a proc even if no tag at all' do
10
+ source = "Hello world!"
11
+ to_ruby_proc(source).should be_a(Proc)
12
+ end
13
+
14
+ end # describe Compiler, 'to_ruby_proc'
15
+ end # module WLang
@@ -20,16 +20,6 @@ module WLang
20
20
  end
21
21
  end
22
22
 
23
- it 'supports a no-op' do
24
- t = compile(hello_tpl)
25
- compile(t).should eq(t)
26
- end
27
-
28
- it 'supports a proc' do
29
- proc = compile(hello_tpl).inner_proc
30
- compile(proc).should be_a(Template)
31
- end
32
-
33
23
  specify 'returned template is callable' do
34
24
  compile(hello_tpl).call.should eq("Hello WHO!")
35
25
  end
@@ -1,41 +1,49 @@
1
1
  require 'spec_helper'
2
2
  module WLang
3
- class Dialect
4
- describe Evaluation, "evaluate" do
5
- include Evaluation
3
+ describe Dialect, 'evaluate' do
6
4
 
7
- let(:struct){ Struct.new(:who) }
5
+ let(:struct){ Struct.new(:who) }
8
6
 
9
- it 'works with a hash' do
10
- with_scope({:who => "World"}) do
11
- evaluate("who").should eq("World")
12
- evaluate(:who).should eq("World")
13
- end
14
- end
7
+ let(:dialect){ Dialect.new }
8
+
9
+ def with_scope(*args, &bl)
10
+ dialect.with_scope(*args, &bl)
11
+ end
12
+
13
+ def evaluate(*args, &bl)
14
+ dialect.evaluate(*args, &bl)
15
+ end
15
16
 
16
- it 'works with a struct' do
17
- with_scope(struct.new("World")) do
18
- evaluate("who").should eq("World")
19
- evaluate(:who).should eq("World")
20
- end
17
+ it 'works with a hash' do
18
+ with_scope({:who => "World"}) do
19
+ evaluate("who").should eq("World")
20
+ evaluate(:who).should eq("World")
21
21
  end
22
+ end
22
23
 
23
- it 'uses the hash in priority' do
24
- with_scope({:keys => [1,2,3]}) do
25
- evaluate("keys").should eq([1,2,3])
26
- end
24
+ it 'works with a struct' do
25
+ with_scope(struct.new("World")) do
26
+ evaluate("who").should eq("World")
27
+ evaluate(:who).should eq("World")
27
28
  end
29
+ end
28
30
 
29
- it 'falls back to send' do
30
- with_scope({:who => "World"}) do
31
- evaluate("keys").should eq([:who])
32
- end
31
+ it 'uses the hash in priority' do
32
+ with_scope({:keys => [1,2,3]}) do
33
+ evaluate("keys").should eq([1,2,3])
33
34
  end
35
+ end
34
36
 
35
- it 'raises a NameError when not found' do
36
- lambda{ evaluate("who") }.should raise_error(NameError)
37
+ it 'falls back to send' do
38
+ with_scope({:who => "World"}) do
39
+ evaluate("keys").should eq([:who])
37
40
  end
41
+ end
42
+
43
+ it 'raises a NameError when not found' do
44
+ lambda{ evaluate("who") }.should raise_error(NameError)
45
+ end
46
+
47
+ end # describe Dialect, 'evaluate'
48
+ end # module WLang
38
49
 
39
- end # describe Evaluation, "evaluate"
40
- end # class Dialect
41
- end # module WLang
@@ -0,0 +1,61 @@
1
+ require 'spec_helper'
2
+ module WLang
3
+ describe Dialect, 'new' do
4
+
5
+ let(:base){ Dialect.default_options }
6
+ let(:template){ Template.new "blah" }
7
+
8
+ subject{ Dialect.new(*args) }
9
+
10
+ context 'with no arguments' do
11
+ let(:args){ [] }
12
+ it 'should have default options' do
13
+ subject.options.should eq(base)
14
+ end
15
+ it 'should not have a template' do
16
+ subject.template.should be_nil
17
+ end
18
+ end
19
+
20
+ context 'with only options' do
21
+ let(:args){ [{:foo => :bar}] }
22
+ it 'should have merged options' do
23
+ subject.options.should eq(base.merge(:foo => :bar))
24
+ end
25
+ it 'should not have a template' do
26
+ subject.template.should be_nil
27
+ end
28
+ end
29
+
30
+ context 'with only a template' do
31
+ let(:args){ [template] }
32
+ it 'should have default options' do
33
+ subject.options.should eq(base)
34
+ end
35
+ it 'should not have a template' do
36
+ subject.template.should eq(template)
37
+ end
38
+ end
39
+
40
+ context 'with options and a template' do
41
+ let(:args){ [{:foo => :bar}, template] }
42
+ it 'should have merged options' do
43
+ subject.options.should eq(base.merge(:foo => :bar))
44
+ end
45
+ it 'should not have a template' do
46
+ subject.template.should eq(template)
47
+ end
48
+ end
49
+
50
+ context 'with options and a template in reverse order' do
51
+ let(:args){ [template, {:foo => :bar}] }
52
+ it 'should have merged options' do
53
+ subject.options.should eq(base.merge(:foo => :bar))
54
+ end
55
+ it 'should not have a template' do
56
+ subject.template.should eq(template)
57
+ end
58
+ end
59
+
60
+ end # describe Dialect, 'new'
61
+ end # module WLang
@@ -0,0 +1,36 @@
1
+ require 'spec_helper'
2
+ module WLang
3
+ describe Dialect, 'tag' do
4
+
5
+ let(:dialect){ Class.new(Dialect) }
6
+
7
+ before do
8
+ def dialect.define_tag_method(*args)
9
+ args
10
+ end
11
+ end
12
+
13
+ def tag(*args, &bl)
14
+ dialect.tag(*args, &bl)
15
+ end
16
+
17
+ it "works with a symbol" do
18
+ tag("$", :dollar).should eq(["$", nil, :dollar])
19
+ end
20
+
21
+ it "works with a single proc" do
22
+ proc = lambda{|buf,fn| }
23
+ tag("$", &proc).should eq(["$", nil, proc])
24
+ end
25
+
26
+ it "allows specifying dialects with a symbol" do
27
+ tag("$", [Foo], :dollar).should eq(["$", [Foo], :dollar])
28
+ end
29
+
30
+ it "allows specifying dialects with a proc" do
31
+ proc = lambda{|buf,fn| }
32
+ tag("$", [Foo], &proc).should eq(["$", [Foo], proc])
33
+ end
34
+
35
+ end # describe Dialect
36
+ end # module WLang
@@ -0,0 +1,22 @@
1
+ require 'spec_helper'
2
+ module WLang
3
+ describe Dialect, 'tag_dispatching_name' do
4
+
5
+ def tag_dispatching_name(symbol)
6
+ Dialect.tag_dispatching_name(symbol)
7
+ end
8
+
9
+ it "works with a single char" do
10
+ tag_dispatching_name("$").should eq(:_tag_36)
11
+ end
12
+
13
+ it "works with a multiple chars" do
14
+ tag_dispatching_name("!$").should eq(:_tag_33_36)
15
+ end
16
+
17
+ it "works with an array" do
18
+ tag_dispatching_name(['!', '$']).should eq(:_tag_33_36)
19
+ end
20
+
21
+ end # describe Dialect
22
+ end # module WLang
@@ -1,18 +1,15 @@
1
1
  require 'spec_helper'
2
2
  module WLang
3
- class Dialect
4
- describe Evaluation, "with_scope" do
5
- include Evaluation
3
+ describe Dialect, 'with_scope' do
6
4
 
7
- let(:struct){ Struct.new(:who) }
5
+ let(:struct){ Struct.new(:who) }
8
6
 
9
- it 'returns the block value' do
10
- got = with_scope({:who => "World"}) do
11
- 12
12
- end
13
- got.should eq(12)
7
+ it 'returns the block value' do
8
+ got = Dialect.new.with_scope({:who => "World"}) do
9
+ 12
14
10
  end
11
+ got.should eq(12)
12
+ end
15
13
 
16
- end # describe Evaluation, "with_scope"
17
- end # class Dialect
14
+ end # describe Dialect, 'with_scope'
18
15
  end # module WLang
@@ -0,0 +1,29 @@
1
+ module WLang
2
+ describe Scope, '.chain' do
3
+
4
+ it 'returns Scope.root on empty chain' do
5
+ Scope.chain([]).should eq(Scope.root)
6
+ end
7
+
8
+ it 'returns a single scope on singleton' do
9
+ s = Scope.chain([{:who => "World"}])
10
+ s.should be_a(Scope::ObjectScope)
11
+ s.parent.should eq(Scope.root)
12
+ end
13
+
14
+ it 'uses the last scope as most specific' do
15
+ s = Scope.chain([{:who => "World"}, lambda{}])
16
+ s.should be_a(Scope::ProcScope)
17
+ s.parent.should be_a(Scope::ObjectScope)
18
+ s.parent.parent.should eq(Scope.root)
19
+ end
20
+
21
+ it 'strips nils' do
22
+ s = Scope.chain([nil, {:who => "World"}, nil, lambda{}, nil])
23
+ s.should be_a(Scope::ProcScope)
24
+ s.parent.should be_a(Scope::ObjectScope)
25
+ s.parent.parent.should eq(Scope.root)
26
+ end
27
+
28
+ end
29
+ end
@@ -6,8 +6,8 @@ module WLang
6
6
  Scope.coerce(binding).should be_a(Scope::BindingScope)
7
7
  end
8
8
 
9
- it 'recognizes Scopes' do
10
- Scope.coerce(Scope.root).should be_a(Scope::ProxyScope)
9
+ it 'recognizes Procs' do
10
+ Scope.coerce(lambda{}).should be_a(Scope::ProcScope)
11
11
  end
12
12
 
13
13
  it 'falls back to ObjectScope on Hash' do
@@ -18,5 +18,16 @@ module WLang
18
18
  Scope.coerce(12).should be_a(Scope::ObjectScope)
19
19
  end
20
20
 
21
+ it 'returns the Scope if nothing has to be done' do
22
+ Scope.coerce(Scope.root).should eq(Scope.root)
23
+ s = Scope.coerce({})
24
+ Scope.coerce(s).should eq(s)
25
+ end
26
+
27
+ it 'builds ProxyScope on Scopes' do
28
+ s = Scope.coerce({})
29
+ Scope.coerce(s, Scope.root).should be_a(Scope::ProxyScope)
30
+ end
31
+
21
32
  end # describe Scope
22
33
  end # module WLang