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
@@ -0,0 +1,18 @@
1
+ require 'spec_helper'
2
+ module WLang
3
+ class Scope
4
+ describe ProcScope do
5
+
6
+ it 'implements fetch through call.xxx' do
7
+ scope = Scope.coerce(lambda{ {:who => "World"} })
8
+ scope.fetch(:who).should eq("World")
9
+ end
10
+
11
+ it 'delegates fetch to its parent when not found' do
12
+ scope = Scope.coerce(lambda{ nil }, Scope.coerce({:who => "World"}))
13
+ scope.fetch(:who).should eq("World")
14
+ end
15
+
16
+ end # describe ProcScope
17
+ end # class Scope
18
+ end # module WLang
@@ -0,0 +1,39 @@
1
+ require 'spec_helper'
2
+ module WLang
3
+ class Source
4
+ describe FrontMatter, "locals" do
5
+
6
+ let(:template){ nil }
7
+
8
+ subject{ FrontMatter.new(source, template).locals }
9
+
10
+ context 'without front matter' do
11
+ let(:source){ "Hello world!" }
12
+ it{ should eq({}) }
13
+ end
14
+
15
+ describe 'with a front matter' do
16
+ let(:source){ "---\nlocals:\n x: 2\n---\nHello world!" }
17
+ specify 'it decode the YAML data' do
18
+ subject.should eq({"x" => 2})
19
+ end
20
+ end
21
+
22
+ describe 'with a front matter containing partials' do
23
+ let(:template){
24
+ tpl_class = Struct.new(:compiler)
25
+ tpl_class.new(Object.new.extend(Module.new{
26
+ def to_ruby_proc(tpl)
27
+ tpl.upcase
28
+ end
29
+ }))
30
+ }
31
+ let(:source){ "---\npartials:\n x: abc\n---\nHello world!" }
32
+ specify 'it should have correct locals' do
33
+ subject.should eq({"x" => 'ABC'})
34
+ end
35
+ end
36
+
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,22 @@
1
+ require 'spec_helper'
2
+ module WLang
3
+ class Source
4
+ describe FrontMatter, "template_content" do
5
+
6
+ subject{ FrontMatter.new(source).template_content }
7
+
8
+ context 'without front matter' do
9
+ let(:source){ "Hello world!" }
10
+ it{ should eq(source) }
11
+ end
12
+
13
+ describe 'with a front matter' do
14
+ let(:source){ "---\nlocals:\n x: 2\n---\nHello world!" }
15
+ specify 'it should not return the front matter itself' do
16
+ subject.should eq("Hello world!")
17
+ end
18
+ end
19
+
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,12 @@
1
+ require 'spec_helper'
2
+ module WLang
3
+ describe Source, 'locals' do
4
+
5
+ subject{ Source.new("Hello world").locals }
6
+
7
+ it 'is empty by default' do
8
+ subject.should eq({})
9
+ end
10
+
11
+ end
12
+ end
@@ -0,0 +1,27 @@
1
+ require 'spec_helper'
2
+ module WLang
3
+ describe Source, "path" do
4
+
5
+ subject{ Source.new(source).path }
6
+
7
+ context 'on a pure string' do
8
+ let(:source){ "Hello world!" }
9
+ it{ should be_nil }
10
+ end
11
+
12
+ context 'on a Path' do
13
+ let(:source){ Path.here }
14
+ it{ should eq(source.to_s) }
15
+ end
16
+
17
+ context 'on a File' do
18
+ let(:source){ File.open(Path.here.to_s) }
19
+ it{ should eq(__FILE__) }
20
+ end
21
+
22
+ it 'is aliased as to_path' do
23
+ Source.new(Path.here).to_path.should eq(__FILE__)
24
+ end
25
+
26
+ end
27
+ end
@@ -0,0 +1,37 @@
1
+ require 'spec_helper'
2
+ module WLang
3
+ describe Source, "template_content" do
4
+
5
+ subject{ Source.new(source).template_content }
6
+
7
+ context 'on a pure string' do
8
+ let(:source){ "Hello world!" }
9
+ it{ should eq(source) }
10
+ end
11
+
12
+ context 'on a Path' do
13
+ let(:source){ hello_path }
14
+ it{ should eq(hello_path.read) }
15
+ end
16
+
17
+ context 'on a File' do
18
+ let(:source){ File.open(Path.here.to_s) }
19
+ it{ should eq(File.read(__FILE__)) }
20
+ end
21
+
22
+ it 'also works on an IO' do
23
+ hello_io do |io|
24
+ Source.new(io).template_content.should eq(hello_path.read)
25
+ end
26
+ end
27
+
28
+ it 'is aliased as to_s' do
29
+ Source.new("raw text").to_s.should eq("raw text")
30
+ end
31
+
32
+ it 'is aliased as to_str' do
33
+ Source.new("raw text").to_str.should eq("raw text")
34
+ end
35
+
36
+ end
37
+ end
@@ -0,0 +1,19 @@
1
+ require 'spec_helper'
2
+ module WLang
3
+ describe Source, "template_content" do
4
+
5
+ let(:source){ Source.new("Hello world") }
6
+ subject{ source.with_front_matter(enabled) }
7
+
8
+ context 'when enabled' do
9
+ let(:enabled){ true }
10
+ it { should be_a(Source::FrontMatter) }
11
+ end
12
+
13
+ context 'when disabled' do
14
+ let(:enabled){ false }
15
+ it { should eq(source) }
16
+ end
17
+
18
+ end
19
+ end
@@ -0,0 +1,16 @@
1
+ require 'spec_helper'
2
+ module WLang
3
+ describe Template, 'call' do
4
+
5
+ let(:template){ Template.new("Hello ${who}!") }
6
+
7
+ it 'renders the template to a string by default' do
8
+ template.render(:who => "world").should eq("Hello world!")
9
+ end
10
+
11
+ it 'allows specifying a buffer' do
12
+ template.render({:who => "world"}, "Hey, ").should eq("Hey, Hello world!")
13
+ end
14
+
15
+ end
16
+ end
@@ -0,0 +1,20 @@
1
+ require 'spec_helper'
2
+ module WLang
3
+ describe Template, '.new' do
4
+
5
+ it 'returns a Template instance' do
6
+ Template.new("Hello ${who}!").should be_a(Template)
7
+ end
8
+
9
+ it 'allows specifying the dialect to use' do
10
+ t = Template.new("Hello ${who}!", :dialect => Upcasing)
11
+ t.dialect.should eq(Upcasing)
12
+ end
13
+
14
+ it 'uses WLang::Html as default dialect' do
15
+ t = Template.new("Hello ${who}!")
16
+ t.dialect.should eq(Html)
17
+ end
18
+
19
+ end
20
+ end
@@ -0,0 +1,28 @@
1
+ require 'spec_helper'
2
+ module WLang
3
+ describe Template, 'path' do
4
+
5
+ subject{ template.path }
6
+
7
+ context 'when a string and no option' do
8
+ let(:template){ Template.new("Hello ${who}!") }
9
+ it{ should be_nil }
10
+ end
11
+
12
+ context 'when a Path and no option' do
13
+ let(:template){ Template.new(Path.here) }
14
+ it{ should eq(__FILE__) }
15
+ end
16
+
17
+ context 'when a string and an option' do
18
+ let(:template){ Template.new("Hello ${who}!", :path => __FILE__) }
19
+ it{ should eq(__FILE__) }
20
+ end
21
+
22
+ context 'when a path an an option' do
23
+ let(:template){ Template.new(Path.here, :path => __FILE__) }
24
+ it{ should eq(__FILE__) }
25
+ end
26
+
27
+ end
28
+ end
@@ -0,0 +1,44 @@
1
+ require 'spec_helper'
2
+ module WLang
3
+ describe Template, 'render' do
4
+
5
+ def template
6
+ Template.new(source, options)
7
+ end
8
+
9
+ let(:options){ {} }
10
+
11
+ subject{ template.render }
12
+
13
+ context 'with a single source String and no options' do
14
+ let(:source){ "Hello world!" }
15
+ it{ should eq("Hello world!") }
16
+ end
17
+
18
+ context 'with a yaml front matter and default options' do
19
+ let(:source){ hello_with_data_path }
20
+ it{ should eq("Hello world!") }
21
+ end
22
+
23
+ context 'with a yaml front matter and front matter disabled' do
24
+ let(:source){ hello_with_data_path }
25
+ let(:options){ {:yaml_front_matter => false} }
26
+ it 'should fail' do
27
+ lambda{
28
+ subject
29
+ }.should raise_error(NameError)
30
+ end
31
+ end
32
+
33
+ context 'with explicit locals' do
34
+ let(:source){ hello_with_explicit_locals_path }
35
+ it{ should eq("Hello world and wlang!") }
36
+ end
37
+
38
+ context 'with partials' do
39
+ let(:source){ hello_with_partials_path }
40
+ it{ should eq("Hello world and wlang!") }
41
+ end
42
+
43
+ end
44
+ end
@@ -0,0 +1,12 @@
1
+ require 'spec_helper'
2
+ module WLang
3
+ describe Template, 'to_ast' do
4
+
5
+ let(:template){ Template.new("Hello ${who}!") }
6
+
7
+ it 'it returns an ast' do
8
+ template.to_ast.should be_a(Array)
9
+ end
10
+
11
+ end
12
+ end
@@ -0,0 +1,13 @@
1
+ require 'spec_helper'
2
+ module WLang
3
+ describe Template, 'to_ruby_code' do
4
+
5
+ let(:template){ Template.new("Hello ${who}!") }
6
+
7
+ it 'it returns some ruby code' do
8
+ expected = %q{Proc.new{|d1,b1| b1 << ("Hello "); d1._tag_36(b1, "who"); b1 << ("!") }}
9
+ template.to_ruby_code.should eq(expected)
10
+ end
11
+
12
+ end
13
+ end
@@ -0,0 +1,12 @@
1
+ require 'spec_helper'
2
+ module WLang
3
+ describe Template, 'to_ruby_proc' do
4
+
5
+ let(:template){ Template.new("Hello ${who}!") }
6
+
7
+ it 'returns a Proc instance' do
8
+ template.to_ruby_proc.should be_a(Proc)
9
+ end
10
+
11
+ end
12
+ end
@@ -0,0 +1,22 @@
1
+ require 'spec_helper'
2
+ module WLang
3
+ describe Template, 'yaml_front_matter?' do
4
+
5
+ before do
6
+ class Template; public :yaml_front_matter?; end
7
+ end
8
+
9
+ it 'is true by default' do
10
+ Template.new("Hello ${who}!").should be_yaml_front_matter
11
+ end
12
+
13
+ it 'is can be explicitely enabled' do
14
+ Template.new("Hello ${who}!", :yaml_front_matter => true).should be_yaml_front_matter
15
+ end
16
+
17
+ it 'is can be explicitely disabled' do
18
+ Template.new("Hello ${who}!", :yaml_front_matter => false).should_not be_yaml_front_matter
19
+ end
20
+
21
+ end
22
+ end
@@ -0,0 +1,65 @@
1
+ require 'tilt'
2
+ require 'wlang/tilt'
3
+ describe Tilt::WLangTemplate do
4
+
5
+ it 'is registered for .wlang files' do
6
+ Tilt.mappings['wlang'].should include(Tilt::WLangTemplate)
7
+ end
8
+
9
+ it 'supports basic rendering with no scope no locals' do
10
+ template = Tilt::WLangTemplate.new{ "Hello" }
11
+ template.render.should eq("Hello")
12
+ end
13
+
14
+ it 'supports a binding scope' do
15
+ template = Tilt::WLangTemplate.new{ "Hello ${who}" }
16
+ who = "world"
17
+ template.render(binding).should eq("Hello world")
18
+ end
19
+
20
+ it 'supports a Hash scope' do
21
+ template = Tilt::WLangTemplate.new{ "Hello ${who}" }
22
+ scope = {:who => "world"}
23
+ template.render(scope).should eq("Hello world")
24
+ end
25
+
26
+ it 'supports both a scope and locals' do
27
+ template = Tilt::WLangTemplate.new{ "Hello ${who} and ${who_else}" }
28
+ who = "world"
29
+ template.render(binding, :who_else => 'wlang').should eq("Hello world and wlang")
30
+ end
31
+
32
+ it 'supports being rendered multiple times' do
33
+ template = Tilt::WLangTemplate.new{ "Hello ${i}" }
34
+ 3.times{|i| template.render(binding).should eq("Hello #{i}") }
35
+ end
36
+
37
+ it 'supports passing a block for yielding' do
38
+ template = Tilt::WLangTemplate.new{ "Hello ${yield}" }
39
+ template.render{ "world" }.should eq('Hello world')
40
+ end
41
+
42
+ it 'supports expressions on yield' do
43
+ template = Tilt::WLangTemplate.new{ "Hello ${yield.upcase}" }
44
+ template.render{ "world" }.should eq('Hello WORLD')
45
+ end
46
+
47
+ it 'passes :path option to the underlying template' do
48
+ tpl = Tilt::WLangTemplate.new(hello_path.to_s)
49
+ tpl = tpl.send(:prepare)
50
+ tpl.should be_a(WLang::Template)
51
+ tpl.path.should eq(hello_path.to_s)
52
+ end
53
+
54
+ it 'supports passing a dialect as options' do
55
+ template = Tilt::WLangTemplate.new(:dialect => Upcasing){ "Hello ${who}" }
56
+ template.render.should eq("Hello WHO")
57
+ end
58
+
59
+ it 'supports options through inheritance' do
60
+ tpl_class = Tilt::WLangTemplate.with_options(:dialect => Upcasing)
61
+ template = tpl_class.new{ "Hello ${who}" }
62
+ template.render.should eq("Hello WHO")
63
+ end
64
+
65
+ end
@@ -27,7 +27,7 @@ Gem::Specification.new do |s|
27
27
  #
28
28
  # The description should be more detailed than the summary. For example,
29
29
  # you might wish to copy the entire README into the description.
30
- s.description = "WLang is a general-purpose *code generation*/*templating engine*. It's main aim is to help you generating\nweb pages, sql queries, ruby code (that is, generating code in general) without having to worry too much \nabout html entities encoding, sql back quoting, string escaping and the like. WLang proposes a generic \nengine that you can extend to fit your needs. It also proposes standard instantiations of this engine \nfor common tasks such as creating SQL queries, instantiating web pages, and so on."
30
+ s.description = "WLang is a general-purpose *code generation*/*templating engine*. It's main aim is to\nhelp you generating web pages, sql queries, ruby code (that is, generating text in\ngeneral) without having to worry too much about html entities encoding, sql back\nquoting, string escaping and the like. WLang proposes a generic engine that you can\neasily extend to fit your needs. It also proposes standard instantiations of this\nengine for common tasks such as rendering HTML web pages."
31
31
 
32
32
  # The URL of this gem home page (optional)
33
33
  s.homepage = "http://github.com/blambeau/wlang"
@@ -123,19 +123,17 @@ Gem::Specification.new do |s|
123
123
  # One call to add_development_dependency('gem_name', 'gem version requirement')
124
124
  # for each development dependency. These gems are required for developers
125
125
  #
126
- s.add_development_dependency("ruby-prof", "~> 0.11.2")
127
- s.add_development_dependency("mustache", "~> 0.99.4")
126
+ s.add_development_dependency("tilt", "~> 1.3")
128
127
  s.add_development_dependency("rake", "~> 0.9.2")
129
128
  s.add_development_dependency("bundler", "~> 1.0")
130
129
  s.add_development_dependency("rspec", "~> 2.10.0")
131
- s.add_development_dependency("epath", "~> 0.1.0")
132
130
  s.add_development_dependency("yard", "~> 0.8.1")
133
131
  s.add_development_dependency("bluecloth", "~> 2.2.0")
134
132
  s.add_dependency("citrus", "~> 2.4.1")
135
133
  s.add_dependency("temple", "~> 0.4.0")
136
- s.add_dependency("backports", "~> 2.6.1")
137
134
  s.add_dependency("quickl", "~> 0.4.3")
138
135
  s.add_dependency("awesome_print", "~> 1.0.2")
136
+ s.add_dependency("epath", ">= 0.2")
139
137
 
140
138
  # The version of ruby required by this gem
141
139
  #