nagoro 2009.05
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.
- 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
|