nagoro 2009.05
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +446 -0
- data/MANIFEST +51 -0
- data/README.markdown +189 -0
- data/Rakefile +29 -0
- data/bin/nagoro +83 -0
- data/doc/COPYING +56 -0
- data/doc/GPL +340 -0
- data/doc/LEGAL +2 -0
- data/example/element/Html.nage +8 -0
- data/example/hello.nag +3 -0
- data/example/morpher.nag +23 -0
- data/lib/nagoro.rb +22 -0
- data/lib/nagoro/binding.rb +8 -0
- data/lib/nagoro/element.rb +46 -0
- data/lib/nagoro/pipe.rb +12 -0
- data/lib/nagoro/pipe/base.rb +56 -0
- data/lib/nagoro/pipe/compile.rb +30 -0
- data/lib/nagoro/pipe/element.rb +70 -0
- data/lib/nagoro/pipe/include.rb +36 -0
- data/lib/nagoro/pipe/instruction.rb +64 -0
- data/lib/nagoro/pipe/localization.rb +60 -0
- data/lib/nagoro/pipe/morph.rb +95 -0
- data/lib/nagoro/pipe/tidy.rb +49 -0
- data/lib/nagoro/scanner.rb +97 -0
- data/lib/nagoro/template.rb +89 -0
- data/lib/nagoro/tidy.rb +49 -0
- data/lib/nagoro/version.rb +3 -0
- data/nagoro.gemspec +28 -0
- data/spec/core_extensions.rb +33 -0
- data/spec/example/hello.rb +13 -0
- data/spec/helper.rb +19 -0
- data/spec/nagoro/listener/base.rb +19 -0
- data/spec/nagoro/pipe/compile.rb +31 -0
- data/spec/nagoro/pipe/element.rb +46 -0
- data/spec/nagoro/pipe/include.rb +17 -0
- data/spec/nagoro/pipe/instruction.rb +32 -0
- data/spec/nagoro/pipe/morph.rb +47 -0
- data/spec/nagoro/pipe/tidy.rb +23 -0
- data/spec/nagoro/template.rb +105 -0
- data/spec/nagoro/template/full.nag +26 -0
- data/spec/nagoro/template/hello.nag +1 -0
- data/tasks/bacon.rake +49 -0
- data/tasks/changelog.rake +18 -0
- data/tasks/gem.rake +22 -0
- data/tasks/gem_installer.rake +76 -0
- data/tasks/grancher.rake +12 -0
- data/tasks/install_dependencies.rake +6 -0
- data/tasks/manifest.rake +4 -0
- data/tasks/rcov.rake +19 -0
- data/tasks/release.rake +52 -0
- data/tasks/reversion.rake +8 -0
- metadata +105 -0
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'spec/helper'
|
2
|
+
|
3
|
+
describe "example/hello.nag" do
|
4
|
+
behaves_like 'xpath'
|
5
|
+
|
6
|
+
Nagoro.file_element('Html', 'example/element/Html.nage')
|
7
|
+
|
8
|
+
should 'render Hello, World!' do
|
9
|
+
file = 'example/hello.nag'
|
10
|
+
doc = Nagoro.compile(file, :pipes => [:Element]).compiled
|
11
|
+
xpath(doc, '//title').first.text.should == 'Hello, World!'
|
12
|
+
end
|
13
|
+
end
|
data/spec/helper.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'lib/nagoro'
|
2
|
+
require 'spec/core_extensions'
|
3
|
+
|
4
|
+
require 'stringio'
|
5
|
+
require 'rexml/document'
|
6
|
+
require 'rexml/xpath'
|
7
|
+
require 'pp'
|
8
|
+
|
9
|
+
require 'rubygems'
|
10
|
+
require 'bacon'
|
11
|
+
|
12
|
+
Bacon.summary_on_exit
|
13
|
+
|
14
|
+
shared 'xpath' do
|
15
|
+
def xpath(string, path)
|
16
|
+
doc = REXML::Document.new(string)
|
17
|
+
REXML::XPath.match(doc, path)
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'spec/helper'
|
2
|
+
|
3
|
+
describe "Nagoro::Listener::Base" do
|
4
|
+
def base(string)
|
5
|
+
nagoro = Nagoro::Template[:Base]
|
6
|
+
nagoro.pipeline(string)
|
7
|
+
end
|
8
|
+
|
9
|
+
should 'not fail on backslash' do
|
10
|
+
base('#{}').should == '#{}'
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'should not stumble over HTML entities' do
|
14
|
+
%w[gt lt quot amp nbsp uuml].each do |entity|
|
15
|
+
str = "&#{entity};"
|
16
|
+
base(str).should == str
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'spec/helper'
|
2
|
+
|
3
|
+
describe "Nagoro::Pipe::Compile" do
|
4
|
+
def render(obj)
|
5
|
+
Nagoro::Template[Nagoro::Pipe::Compile].render(obj)
|
6
|
+
end
|
7
|
+
|
8
|
+
should 'compile normal string' do
|
9
|
+
render('Hello, World!').should == 'Hello, World!'
|
10
|
+
end
|
11
|
+
|
12
|
+
should 'compile ruby instructions' do
|
13
|
+
render('<?r a = 1 ?><?ro a ?>').should == '1'
|
14
|
+
render('<?r a = 1 ?><?ro a > 1 ?>').should == 'false'
|
15
|
+
render('<?r a = 1 ?><?ro a < 1 ?>').should == 'false'
|
16
|
+
end
|
17
|
+
|
18
|
+
should 'compile with compatiblity to Ezamar' do
|
19
|
+
render('<?r a = 1 ?>#{a}').should == '1'
|
20
|
+
render('<?r a = 1 ?>#{a > 1}').should == 'false'
|
21
|
+
render('<?r a = 1 ?>#{a < 1}').should == 'false'
|
22
|
+
end
|
23
|
+
|
24
|
+
should 'not fail on nested {} inside #{}' do
|
25
|
+
render('#{"Hello, {World}!"}').should == 'Hello, {World}!'
|
26
|
+
end
|
27
|
+
|
28
|
+
should 'not fail on > inside ruby instruction' do
|
29
|
+
render('#{{:hi => :there}[:hi]}').should == 'there'
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'spec/helper'
|
2
|
+
|
3
|
+
describe "Nagoro::Pipe::Element" do
|
4
|
+
behaves_like 'xpath'
|
5
|
+
|
6
|
+
def compile(obj)
|
7
|
+
Nagoro::Template[Nagoro::Pipe::Element].compile(obj).compiled
|
8
|
+
end
|
9
|
+
|
10
|
+
Nagoro.element('Page') do |content, attrs|
|
11
|
+
"(Page: #{content.dump})"
|
12
|
+
end
|
13
|
+
|
14
|
+
Nagoro.element('SideBar') do |content, attrs|
|
15
|
+
"(SideBar: #{content.dump})"
|
16
|
+
end
|
17
|
+
|
18
|
+
Nagoro.file_element('Html', 'example/element/Html.nage')
|
19
|
+
|
20
|
+
it 'should compile single element' do
|
21
|
+
compile('<Page />').
|
22
|
+
should == '(Page: "")'
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'should compile two elements' do
|
26
|
+
compile('<Page /><Page />').
|
27
|
+
should == '(Page: "")(Page: "")'
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'should compile nested elements' do
|
31
|
+
compile('<Page><Page /></Page>').
|
32
|
+
should == '(Page: "(Page: \\"\\")")'
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'should compile different nested elements' do
|
36
|
+
compile('<Page><SideBar /></Page>').
|
37
|
+
should == '(Page: "(SideBar: \\"\\")")'
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'should render file-elements' do
|
41
|
+
doc = compile(File.read('example/hello.nag'))
|
42
|
+
doc.should.not.be.empty
|
43
|
+
xpath(doc, '//title').first.text.should == 'Hello, World!'
|
44
|
+
xpath(doc, '//h1').first.text.should == 'Hello, World!'
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'spec/helper'
|
2
|
+
|
3
|
+
describe "Nagoro::Pipe::Include" do
|
4
|
+
def compile(obj)
|
5
|
+
Nagoro::Template[Nagoro::Pipe::Include].compile(obj).compiled
|
6
|
+
end
|
7
|
+
|
8
|
+
it 'should append included file with arguments src or href' do
|
9
|
+
path = __DIR__/'../template/hello.nag'
|
10
|
+
|
11
|
+
compile(%{<p id="text"><include src="#{path}" /></p>}).strip.
|
12
|
+
should == %{<p id="text">#{File.read(path).strip}</p>}
|
13
|
+
|
14
|
+
compile(%{<p id="text"><include href="#{path}" /></p>}).strip.
|
15
|
+
should == %{<p id="text">#{File.read(path).strip}</p>}
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'spec/helper'
|
2
|
+
|
3
|
+
describe "Nagoro::Pipe::Instruction" do
|
4
|
+
behaves_like 'xpath'
|
5
|
+
def compile(obj)
|
6
|
+
Nagoro::Template[Nagoro::Pipe::Instruction].compile(obj).compiled
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'should expand <?js code ?>' do
|
10
|
+
compile('<?js alert("Hello, World!"); ?>').
|
11
|
+
should == '<script type="text/javascript"> alert("Hello, World!"); </script>'
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'should expand <?js:src path?>' do
|
15
|
+
doc = compile('<?js:src /js/foo.js ?>')
|
16
|
+
scripts = xpath(doc, 'script[@type="text/javascript" @src="/js/foo.js"]')
|
17
|
+
scripts.size.should == 1
|
18
|
+
scripts.first.texts.should.be.empty
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'should expand <?css styles ?>' do
|
22
|
+
compile('<?css body{ color: #eee; } ?>').
|
23
|
+
should == '<style type="text/css"> body{ color: #eee; } </style>'
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'should expand <?css:src path ?>' do
|
27
|
+
doc = compile('<?css:src /css/foo.css ?>')
|
28
|
+
styles = xpath(doc, 'style[@type="text/css" @src="/css/foo.css"]')
|
29
|
+
styles.size.should == 1
|
30
|
+
styles.first.texts.should.be.empty
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'spec/helper'
|
2
|
+
|
3
|
+
describe "Nagoro::Pipe::Morph" do
|
4
|
+
def compile(obj)
|
5
|
+
Nagoro::Template[Nagoro::Pipe::Morph].compile(obj).compiled
|
6
|
+
end
|
7
|
+
|
8
|
+
it 'should morph single tag' do
|
9
|
+
compile('<a href="foo" if="1">bar</a>').
|
10
|
+
should == '<?r if 1 ?><a href="foo">bar</a><?r end ?>'
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'should morph multiple tags' do
|
14
|
+
compile('<div if="2"><p if="1"></p></div>').
|
15
|
+
should == '<?r if 2 ?><div><?r if 1 ?><p></p><?r end ?></div><?r end ?>'
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'should morph if' do
|
19
|
+
compile('<p if="1">x</p>').
|
20
|
+
should == '<?r if 1 ?><p>x</p><?r end ?>'
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'should morph unless' do
|
24
|
+
compile('<p unless="1">x</p>').
|
25
|
+
should == '<?r unless 1 ?><p>x</p><?r end ?>'
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'should morph foreach' do
|
29
|
+
compile('<p foreach="i in 1..10">#{i}</p>').
|
30
|
+
should == '<?r for i in 1..10 ?><p>#{i}</p><?r end ?>'
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'should morph each' do
|
34
|
+
compile('<p each="1..10">#{_e}</p>').
|
35
|
+
should == '<?r 1..10.each do |_e| ?><p>#{_e}</p><?r end ?>'
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'should morph times' do
|
39
|
+
compile('<p times="3">#{_t}</p>').
|
40
|
+
should == '<?r 3.times do |_t| ?><p>#{_t}</p><?r end ?>'
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'should morph filter' do
|
44
|
+
compile('<p filter="my_filter">x</p>').
|
45
|
+
should == '<?o my_filter(%<<p>x</p>>) ?>'
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'spec/helper'
|
2
|
+
require 'nagoro/pipe/tidy'
|
3
|
+
|
4
|
+
describe "Nagoro::Pipe::Tidy" do
|
5
|
+
def compile(obj)
|
6
|
+
Nagoro::Template[Nagoro::Pipe::Tidy].compile(obj).compiled
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'pipes the template through tidy' do
|
10
|
+
compile('<html></html>').strip.should ==
|
11
|
+
"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"
|
12
|
+
\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">
|
13
|
+
|
14
|
+
<html xmlns=\"http://www.w3.org/1999/xhtml\">
|
15
|
+
<head>
|
16
|
+
<title></title>
|
17
|
+
</head>
|
18
|
+
|
19
|
+
<body>
|
20
|
+
</body>
|
21
|
+
</html>"
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
require 'spec/helper'
|
2
|
+
|
3
|
+
describe "Nagoro" do
|
4
|
+
should '::compile from filename' do
|
5
|
+
file = __DIR__/'template/hello.nag'
|
6
|
+
template = Nagoro.compile(file)
|
7
|
+
template.compiled.should == "_out_ = []; _out_ << %Q`Hello, World!\n`; _out_.join"
|
8
|
+
end
|
9
|
+
|
10
|
+
should '::compile' do
|
11
|
+
string = 'Hello, World!'
|
12
|
+
template = Nagoro.compile(string)
|
13
|
+
template.compiled.should == '_out_ = []; _out_ << %Q`Hello, World!`; _out_.join'
|
14
|
+
end
|
15
|
+
|
16
|
+
should 'compile <?end ?> to <?r end ?>' do
|
17
|
+
string = '<?end ?>'
|
18
|
+
template = Nagoro.compile(string)
|
19
|
+
template.compiled.should == '_out_ = []; _out_ << %Q``;end; _out_ << %Q``; _out_.join'
|
20
|
+
end
|
21
|
+
|
22
|
+
should '::render from filename' do
|
23
|
+
file = __DIR__/'template/hello.nag'
|
24
|
+
rendered = Nagoro.render(file)
|
25
|
+
rendered.should == File.read(file).strip
|
26
|
+
end
|
27
|
+
|
28
|
+
should '::render' do
|
29
|
+
string = 'Hello, World!'
|
30
|
+
rendered = Nagoro.render(string)
|
31
|
+
rendered.should == string
|
32
|
+
end
|
33
|
+
|
34
|
+
should '::render from IO' do
|
35
|
+
io = StringIO.new('Hello, World!')
|
36
|
+
rendered = Nagoro.render(io)
|
37
|
+
rendered.should == 'Hello, World!'
|
38
|
+
end
|
39
|
+
|
40
|
+
should 'render a full featured template with binding' do
|
41
|
+
file = __DIR__/'template/full.nag'
|
42
|
+
@title = 'Full template'
|
43
|
+
|
44
|
+
template = Nagoro.render(file, :binding => binding)
|
45
|
+
|
46
|
+
template.should =~ %r~<!DOCTYPE html PUBLIC~
|
47
|
+
template.should =~ %r~<title>Full template</title>~
|
48
|
+
template.should =~ %r~<h1>Full template</h1>~
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe "Nagoro::Template" do
|
53
|
+
should 'set up with ::[]' do
|
54
|
+
template = Nagoro::Template[]
|
55
|
+
template.pipes.should == []
|
56
|
+
template = Nagoro::Template[*Nagoro::DEFAULT_PIPES]
|
57
|
+
template.pipes.size.should == Nagoro::DEFAULT_PIPES.size
|
58
|
+
end
|
59
|
+
|
60
|
+
should 'set up with ::new' do
|
61
|
+
template = Nagoro::Template.new(:pipes => [])
|
62
|
+
template.pipes.should.be.empty
|
63
|
+
template = Nagoro::Template.new(:pipes => Nagoro::DEFAULT_PIPES)
|
64
|
+
template.pipes.size.should == Nagoro::DEFAULT_PIPES.size
|
65
|
+
end
|
66
|
+
|
67
|
+
should 'not open/close empty tags' do
|
68
|
+
%w[ img hr br link meta ].each do |tag|
|
69
|
+
tag = "<#{tag} />"
|
70
|
+
Nagoro.render(tag).should == tag
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
should 'render and pass result to tidy via #tidy_result' do
|
75
|
+
template = Nagoro::Template.new
|
76
|
+
template.compile('<html></html>').tidy_result.should ==
|
77
|
+
"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"
|
78
|
+
\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">
|
79
|
+
|
80
|
+
<html xmlns=\"http://www.w3.org/1999/xhtml\">
|
81
|
+
<head>
|
82
|
+
<title></title>
|
83
|
+
</head>
|
84
|
+
|
85
|
+
<body>
|
86
|
+
</body>
|
87
|
+
</html>"
|
88
|
+
end
|
89
|
+
|
90
|
+
def noop(*args) end
|
91
|
+
|
92
|
+
it "doesn't get stuck when ruby contains double-quotes" do
|
93
|
+
tag = %q(<link href='#{ noop("some.thing") }' />)
|
94
|
+
Nagoro.render(tag, :binding => binding).should == "<link href='' />"
|
95
|
+
end
|
96
|
+
|
97
|
+
it "ignores comments" do
|
98
|
+
comment = '
|
99
|
+
<!--[if IE]>
|
100
|
+
<link rel="stylesheet" type="text/css" media="screen, projection" href="css/blueprint/ie.css">
|
101
|
+
<![endif]-->'.strip
|
102
|
+
|
103
|
+
Nagoro.render(comment).should == comment
|
104
|
+
end
|
105
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
<?xml version="1.0" ?>
|
2
|
+
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
|
3
|
+
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
|
4
|
+
<html xmlns="http://www.w3.org/1999/xhtml">
|
5
|
+
<head>
|
6
|
+
<title>#{@title}</title>
|
7
|
+
<meta http-equiv="Content-Script-Type" content="text/javascript" />
|
8
|
+
<meta http-equiv="Content-Style-Type" content="text/css" />
|
9
|
+
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
10
|
+
<meta http-equiv="expires" content="0" />
|
11
|
+
<meta name="description" content="Description for search engines" />
|
12
|
+
<meta name="generator" content="Nagoro #{Nagoro::VERSION}" />
|
13
|
+
<meta name="keywords" content="Nagoro, Your own keywords" />
|
14
|
+
<meta name="author" content="Max Mustermann" />
|
15
|
+
<style type="text/css">
|
16
|
+
body { margin: 2em; }
|
17
|
+
#content { margin-left: 2em; }
|
18
|
+
</style>
|
19
|
+
</head>
|
20
|
+
<body>
|
21
|
+
<h1>#{@title}</h1>
|
22
|
+
<div id="content">
|
23
|
+
#{@content}
|
24
|
+
</div>
|
25
|
+
</body>
|
26
|
+
</html>
|
@@ -0,0 +1 @@
|
|
1
|
+
Hello, World!
|
data/tasks/bacon.rake
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
desc 'Run all bacon specs with pretty output'
|
2
|
+
task :bacon => :install_dependencies do
|
3
|
+
require 'open3'
|
4
|
+
require 'scanf'
|
5
|
+
|
6
|
+
specs = PROJECT_SPECS
|
7
|
+
|
8
|
+
some_failed = false
|
9
|
+
total = specs.size
|
10
|
+
len = specs.map{|s| s.size }.sort.last
|
11
|
+
tt = ta = tf = te = 0
|
12
|
+
|
13
|
+
red, yellow, green = "\e[31m%s\e[0m", "\e[33m%s\e[0m", "\e[32m%s\e[0m"
|
14
|
+
left_format = "%4d/%d: %-#{len + 11}s"
|
15
|
+
spec_format = "%d specifications (%d requirements), %d failures, %d errors"
|
16
|
+
|
17
|
+
specs.each_with_index do |spec, idx|
|
18
|
+
print(left_format % [idx + 1, total, spec])
|
19
|
+
|
20
|
+
Open3.popen3(RUBY, spec) do |sin, sout, serr|
|
21
|
+
out = sout.read
|
22
|
+
err = serr.read
|
23
|
+
|
24
|
+
ran = false
|
25
|
+
|
26
|
+
out.each_line do |line|
|
27
|
+
tests, assertions, failures, errors = all = line.scanf(spec_format)
|
28
|
+
next unless all.any?
|
29
|
+
ran = true
|
30
|
+
tt += tests; ta += assertions; tf += failures; te += errors
|
31
|
+
|
32
|
+
if tests == 0 || failures + errors > 0
|
33
|
+
puts((red % spec_format) % all)
|
34
|
+
puts out
|
35
|
+
puts err
|
36
|
+
else
|
37
|
+
puts((green % "%6d passed") % tests)
|
38
|
+
end
|
39
|
+
|
40
|
+
break
|
41
|
+
end
|
42
|
+
|
43
|
+
puts(yellow % " skipped") unless ran
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
puts(spec_format % [tt, ta, tf, te])
|
48
|
+
exit 1 if some_failed
|
49
|
+
end
|