erector 0.6.3 → 0.6.4
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/README.txt +10 -5
- data/VERSION.yml +1 -1
- data/bin/erector +3 -1
- data/lib/erector.rb +1 -0
- data/lib/erector/erect.rb +4 -2
- data/lib/erector/erected.rb +14 -4
- data/lib/erector/mixin.rb +7 -0
- data/lib/erector/rhtml.treetop +48 -11
- data/lib/erector/widget.rb +146 -113
- data/spec/erect/erect_rails_spec.rb +62 -0
- data/spec/erect/erect_spec.rb +165 -0
- data/spec/erect/erected_spec.rb +93 -0
- data/spec/erect/rhtml_parser_spec.rb +351 -0
- data/spec/erector/mixin_spec.rb +54 -0
- data/spec/erector/widget_spec.rb +38 -0
- metadata +8 -2
@@ -0,0 +1,62 @@
|
|
1
|
+
require File.expand_path("#{File.dirname(__FILE__)}/../spec_helper")
|
2
|
+
|
3
|
+
require "erector/rails"
|
4
|
+
|
5
|
+
# Note: this is *not* inside the rails_root since we're not testing
|
6
|
+
# Erector inside a rails app. We're testing that we can use the command-line
|
7
|
+
# converter tool on a newly generated scaffold app (like we brag about in the
|
8
|
+
# user guide).
|
9
|
+
#
|
10
|
+
module Erector
|
11
|
+
|
12
|
+
describe "the user running this spec" do
|
13
|
+
it "should have the correct Rails gem (version #{Erector::Rails::RAILS_VERSION}) installed" do
|
14
|
+
target_version = Gem::Version.new(Erector::Rails::RAILS_VERSION)
|
15
|
+
dep = Gem::Dependency.new "rails", target_version
|
16
|
+
specs = Gem.source_index.search dep
|
17
|
+
specs.size.should == 1
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe "Erect in a Rails app" do
|
22
|
+
|
23
|
+
def run(cmd)
|
24
|
+
puts cmd
|
25
|
+
stdout = `#{cmd}`
|
26
|
+
if $? != 0
|
27
|
+
raise "Command #{cmd} failed, returning '#{stdout}', current dir '#{Dir.getwd}'"
|
28
|
+
else
|
29
|
+
return stdout
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def run_rails(app_dir)
|
34
|
+
# To ensure we're working with the right version of Rails we use "gem 'rails', 1.2.3"
|
35
|
+
# in a "ruby -e" command line invocation of the rails executable to generate an
|
36
|
+
# app called explode.
|
37
|
+
#
|
38
|
+
puts "Generating fresh rails #{Erector::Rails::RAILS_VERSION} app"
|
39
|
+
run "ruby -e \"require 'rubygems'; gem 'rails', '#{Erector::Rails::RAILS_VERSION}'; load 'rails'\" #{app_dir}"
|
40
|
+
end
|
41
|
+
|
42
|
+
it "works like we say it does in the user guide" do
|
43
|
+
app_dir = Dir.tmpdir + "/#{Time.now.to_i}" + "/explode"
|
44
|
+
erector_bin = File.expand_path("#{File.dirname(__FILE__)}/../../bin")
|
45
|
+
|
46
|
+
FileUtils.mkdir_p(app_dir)
|
47
|
+
run_rails app_dir
|
48
|
+
FileUtils.cd(app_dir, :verbose => true) do
|
49
|
+
run "script/generate scaffold post title:string body:text published:boolean"
|
50
|
+
run "#{erector_bin}/erector app/views/posts"
|
51
|
+
FileUtils.rm_f("app/views/posts/*.erb")
|
52
|
+
run "(echo ''; echo \"require 'erector'\") >> config/environment.rb"
|
53
|
+
run "rake db:migrate"
|
54
|
+
# run "script/server" # todo: launch in background; use mechanize or something to crawl it; then kill it
|
55
|
+
# perhaps use open4?
|
56
|
+
# open http://localhost:3000/posts
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
@@ -0,0 +1,165 @@
|
|
1
|
+
require File.expand_path("#{File.dirname(__FILE__)}/../spec_helper")
|
2
|
+
|
3
|
+
require "erector/erect"
|
4
|
+
|
5
|
+
module Erector
|
6
|
+
describe Erect do
|
7
|
+
it "parses an empty command line" do
|
8
|
+
erect = Erect.new([])
|
9
|
+
erect.files.should == []
|
10
|
+
end
|
11
|
+
|
12
|
+
it "parses a command line with one filename on it" do
|
13
|
+
erect = Erect.new(["foo.html"])
|
14
|
+
erect.files.should == ["foo.html"]
|
15
|
+
end
|
16
|
+
|
17
|
+
it "parses a command line with several filenames on it" do
|
18
|
+
erect = Erect.new(["foo.html", "bar/baz.html"])
|
19
|
+
erect.files.should == ["foo.html", "bar/baz.html"]
|
20
|
+
end
|
21
|
+
|
22
|
+
it "is verbose by default, but quiet when told" do
|
23
|
+
Erect.new([]).verbose.should be_true
|
24
|
+
Erect.new(["-q"]).verbose.should be_false
|
25
|
+
end
|
26
|
+
|
27
|
+
it "parses a command line with several filenames and an option on it" do
|
28
|
+
erect = Erect.new(["-q", "foo.html", "bar/baz.html"])
|
29
|
+
erect.files.should == ["foo.html", "bar/baz.html"]
|
30
|
+
end
|
31
|
+
|
32
|
+
def capturing_output
|
33
|
+
output = StringIO.new
|
34
|
+
$stdout = output
|
35
|
+
yield
|
36
|
+
output.string
|
37
|
+
ensure
|
38
|
+
$stdout = STDOUT
|
39
|
+
end
|
40
|
+
|
41
|
+
it "exits immediately from help" do
|
42
|
+
output = capturing_output do
|
43
|
+
lambda {
|
44
|
+
erect = Erect.new(["-h"])
|
45
|
+
}.should raise_error(SystemExit)
|
46
|
+
end
|
47
|
+
output.should =~ /^Usage/
|
48
|
+
end
|
49
|
+
|
50
|
+
it "exits immediately from --version" do
|
51
|
+
output = capturing_output do
|
52
|
+
lambda {
|
53
|
+
erect = Erect.new(["--version"])
|
54
|
+
}.should raise_error(SystemExit)
|
55
|
+
end
|
56
|
+
output.should == Erector::VERSION + "\n"
|
57
|
+
end
|
58
|
+
|
59
|
+
it "changes to html output" do
|
60
|
+
erect = Erect.new(["--to-html"])
|
61
|
+
erect.mode.should == :to_html
|
62
|
+
end
|
63
|
+
|
64
|
+
it "changes to html output when passed a .rb file" do
|
65
|
+
pending do
|
66
|
+
erect = Erect.new(["foo.rb"])
|
67
|
+
erect.mode.should == :to_html
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
it "fails when given both .rb and .html files" do
|
72
|
+
pending do
|
73
|
+
lambda {
|
74
|
+
erect = Erect.new(["foo.rb", "bar.html"])
|
75
|
+
}.should raise_error
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
it "returns false when there's an error during run" do
|
80
|
+
capturing_output do
|
81
|
+
Erect.new(["MISSINGFILE"]).run.should == false
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
|
88
|
+
describe "Erect functionally" do
|
89
|
+
|
90
|
+
attr_reader :dir, :fred_html, :wilma_rhtml, :barney_html_erb, :fred_rb
|
91
|
+
|
92
|
+
def create(file, body="hi")
|
93
|
+
File.open(file, "w") do |f|
|
94
|
+
f.puts(body)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
before :all do
|
99
|
+
@dir = Dir.tmpdir + "/#{Time.now.to_i}" + "/explode"
|
100
|
+
@fred_html = "#{dir}/fred.html"
|
101
|
+
@wilma_rhtml = "#{dir}/wilma.rhtml"
|
102
|
+
@barney_html_erb = "#{dir}/barney.html.erb"
|
103
|
+
@fred_rb = "#{dir}/fred.rb"
|
104
|
+
|
105
|
+
FileUtils.mkdir_p(dir)
|
106
|
+
create(fred_html)
|
107
|
+
create(wilma_rhtml)
|
108
|
+
create(barney_html_erb)
|
109
|
+
create(fred_rb, "class Fred < Erector::Widget\ndef content\ndiv 'dino'\nend\nend")
|
110
|
+
end
|
111
|
+
|
112
|
+
it "explodes dirs into .html etc. files when in to-rb mode" do
|
113
|
+
erect = Erect.new(["--to-erector", dir])
|
114
|
+
erect.files.sort.should == [barney_html_erb, fred_html, wilma_rhtml]
|
115
|
+
end
|
116
|
+
|
117
|
+
it "explodes dirs into .rb files when in to-html mode" do
|
118
|
+
erect = Erect.new(["--to-html", dir])
|
119
|
+
erect.files.should == [fred_rb]
|
120
|
+
end
|
121
|
+
|
122
|
+
it "outputs .rb files in the same directory as the input .html files" do
|
123
|
+
erect = Erect.new(["--to-erector", "-q", fred_html])
|
124
|
+
erect.run
|
125
|
+
File.exist?(fred_rb).should be_true
|
126
|
+
File.read(fred_rb).should include("text 'hi'")
|
127
|
+
end
|
128
|
+
|
129
|
+
it "outputs .html files in the same directory as the input .rb files" do
|
130
|
+
betty_rb = "#{dir}/betty.rb"
|
131
|
+
betty_html = "#{dir}/betty.html"
|
132
|
+
create(betty_rb, "class Betty < Erector::Widget\ndef content\ndiv 'bam bam'\nend\nend")
|
133
|
+
|
134
|
+
erect = Erect.new(["--to-html", "-q", betty_rb])
|
135
|
+
erect.run
|
136
|
+
File.exist?(betty_html).should be_true
|
137
|
+
File.read(betty_html).should == "<div>bam bam</div>\n"
|
138
|
+
end
|
139
|
+
|
140
|
+
it "outputs .html files in the given directory" do
|
141
|
+
create(fred_rb, "class Fred < Erector::Widget\ndef content\ndiv 'dino'\nend\nend")
|
142
|
+
out_dir = "#{dir}/out"
|
143
|
+
out_file = "#{out_dir}/fred.html"
|
144
|
+
|
145
|
+
Erect.new([]).output_dir.should be_nil
|
146
|
+
erect = Erect.new(["--to-html", "-o", "#{out_dir}", "-q", fred_rb])
|
147
|
+
erect.output_dir.should == out_dir
|
148
|
+
erect.run
|
149
|
+
File.exist?(out_file).should be_true
|
150
|
+
File.read(out_file).should == "<div>dino</div>\n"
|
151
|
+
end
|
152
|
+
|
153
|
+
it "skips rendering classes that aren't widgets" do
|
154
|
+
mr_slate_rb = "#{dir}/mr_slate.rb"
|
155
|
+
mr_slate_html = "#{dir}/mr_slate.html"
|
156
|
+
create(mr_slate_rb, "class MrSlate\nend")
|
157
|
+
erect = Erect.new(["-q", "--to-html", mr_slate_rb])
|
158
|
+
erect.run
|
159
|
+
File.exist?(mr_slate_html).should be_false
|
160
|
+
end
|
161
|
+
|
162
|
+
# it "properly indents lines beginning with for, unless, etc."
|
163
|
+
end
|
164
|
+
|
165
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
require File.expand_path("#{File.dirname(__FILE__)}/../spec_helper")
|
2
|
+
|
3
|
+
require "erector/erect"
|
4
|
+
|
5
|
+
module Erector
|
6
|
+
describe Erected do
|
7
|
+
|
8
|
+
it "picks the right file name" do
|
9
|
+
Erected.new("foo.html.erb").filename.should == "foo.rb"
|
10
|
+
Erected.new("foo.html").filename.should == "foo.rb"
|
11
|
+
Erected.new("foo.bar.html").filename.should == "foo.rb"
|
12
|
+
Erected.new("foo_bar.html.erb").filename.should == "foo_bar.rb"
|
13
|
+
Erected.new("stuff/foo_bar.html.erb").filename.should == "stuff/foo_bar.rb"
|
14
|
+
end
|
15
|
+
|
16
|
+
it "picks a nice class name" do
|
17
|
+
Erected.new("foo.html.erb").classname.should == "Foo"
|
18
|
+
Erected.new("foo.html").classname.should == "Foo"
|
19
|
+
Erected.new("foo.bar.html").classname.should == "Foo"
|
20
|
+
Erected.new("foo_bar.html.erb").classname.should == "FooBar"
|
21
|
+
Erected.new("stuff/foo_bar.html.erb").classname.should == "FooBar"
|
22
|
+
end
|
23
|
+
|
24
|
+
it "picks an even nicer class name if it's in a views dir" do
|
25
|
+
Erected.new("app/views/stuff/foo_bar.html.erb").classname.should == "Views::Stuff::FooBar"
|
26
|
+
Erected.new("views/stuff/foo_bar.html.erb").classname.should == "Views::Stuff::FooBar"
|
27
|
+
end
|
28
|
+
|
29
|
+
it "uses Widget as the parent class" do
|
30
|
+
Erected.new("foo_bar.html").parent_class.should == "Erector::Widget"
|
31
|
+
Erected.new("foo_bar.html.erb").parent_class.should == "Erector::Widget"
|
32
|
+
Erected.new("stuff/foo_bar.html.erb").parent_class.should == "Erector::Widget"
|
33
|
+
end
|
34
|
+
|
35
|
+
it "uses RailsWidget as the parent class if it's in a views dir" do
|
36
|
+
Erected.new("app/views/stuff/foo_bar.html.erb").parent_class.should == "Erector::RailsWidget"
|
37
|
+
Erected.new("views/stuff/foo_bar.html.erb").parent_class.should == "Erector::RailsWidget"
|
38
|
+
end
|
39
|
+
|
40
|
+
def convert(dir, input, output)
|
41
|
+
dir = Dir.tmpdir + "/#{Time.now.to_i}" + "/#{dir}"
|
42
|
+
|
43
|
+
FileUtils.mkdir_p(dir)
|
44
|
+
html = "#{dir}/dummy.html"
|
45
|
+
rb = "#{dir}/dummy.rb"
|
46
|
+
|
47
|
+
File.open(html, "w") do |f|
|
48
|
+
f.puts(input)
|
49
|
+
end
|
50
|
+
|
51
|
+
@e = Erected.new(html)
|
52
|
+
@e.convert
|
53
|
+
|
54
|
+
File.read(rb).should == output
|
55
|
+
end
|
56
|
+
|
57
|
+
it "converts a normal file" do
|
58
|
+
convert(".",
|
59
|
+
"<div>hello</div>",
|
60
|
+
"class Dummy < Erector::Widget\n" +
|
61
|
+
" def content\n" +
|
62
|
+
" div do\n" +
|
63
|
+
" text 'hello'\n" +
|
64
|
+
" end\n" +
|
65
|
+
" end\n" +
|
66
|
+
"end\n"
|
67
|
+
)
|
68
|
+
end
|
69
|
+
|
70
|
+
it "converts a views file" do
|
71
|
+
convert("app/views/foos",
|
72
|
+
"<div>hello</div>",
|
73
|
+
"class Views::Foos::Dummy < Erector::RailsWidget\n" +
|
74
|
+
" def content\n" +
|
75
|
+
" div do\n" +
|
76
|
+
" text 'hello'\n" +
|
77
|
+
" end\n" +
|
78
|
+
" end\n" +
|
79
|
+
"end\n"
|
80
|
+
)
|
81
|
+
end
|
82
|
+
|
83
|
+
# todo: figure out if there is any such thing as unparsable HTML anymore
|
84
|
+
# it "raises an exception if given unparsable HTML" do
|
85
|
+
# begin
|
86
|
+
# convert(".", "<", "")
|
87
|
+
# rescue => e
|
88
|
+
# e.to_s.should include("Could not parse")
|
89
|
+
# end
|
90
|
+
# end
|
91
|
+
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,351 @@
|
|
1
|
+
require File.expand_path("#{File.dirname(__FILE__)}/../spec_helper")
|
2
|
+
|
3
|
+
require "erector/erect"
|
4
|
+
|
5
|
+
module ParserTestHelper
|
6
|
+
def assert_evals_to_self(input)
|
7
|
+
assert_evals_to(input, input)
|
8
|
+
end
|
9
|
+
|
10
|
+
def parse(input)
|
11
|
+
result = @parser.parse(input)
|
12
|
+
if result
|
13
|
+
result.set_indent(0) if result.respond_to? :set_indent
|
14
|
+
else
|
15
|
+
puts @parser.failure_reason
|
16
|
+
puts @parser.terminal_failures.join("\n")
|
17
|
+
result.should_not be_nil
|
18
|
+
end
|
19
|
+
result
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe RhtmlParser do
|
24
|
+
include ParserTestHelper
|
25
|
+
|
26
|
+
before :each do
|
27
|
+
@parser = RhtmlParser.new
|
28
|
+
end
|
29
|
+
|
30
|
+
it "converts text" do
|
31
|
+
parse("hello").convert.should == "text 'hello'\n"
|
32
|
+
parse("hello maude!").convert.should == "text 'hello maude!'\n"
|
33
|
+
parse(" hello ").convert.should == "text 'hello'\n"
|
34
|
+
end
|
35
|
+
|
36
|
+
it "unescapes HTML entities in text" do
|
37
|
+
parse("<").convert.should == "text '<'\n"
|
38
|
+
parse("5 > 2").convert.should == "text '5 > 2'\n"
|
39
|
+
end
|
40
|
+
|
41
|
+
it "converts self-closing tags" do
|
42
|
+
parse("<br/>").convert.should == "br\n"
|
43
|
+
parse("<br />").convert.should == "br\n"
|
44
|
+
end
|
45
|
+
|
46
|
+
it "converts open tag" do
|
47
|
+
parse("<div>").convert.should == "div do\n"
|
48
|
+
parse("<h1>").convert.should == "h1 do\n"
|
49
|
+
end
|
50
|
+
|
51
|
+
it "converts close tag" do
|
52
|
+
parse("</div>").convert.should == "end\n"
|
53
|
+
parse("</h1>").convert.should == "end\n"
|
54
|
+
end
|
55
|
+
|
56
|
+
it "converts two nested divs" do
|
57
|
+
parse("<div><div></div></div>").convert.should ==
|
58
|
+
"div do\n" +
|
59
|
+
" div do\n" +
|
60
|
+
" end\n" +
|
61
|
+
"end\n"
|
62
|
+
end
|
63
|
+
|
64
|
+
it "converts two nested divs with whitespace" do
|
65
|
+
parse("<div> <div> </div> </div>").convert.should ==
|
66
|
+
"div do\n" +
|
67
|
+
" div do\n" +
|
68
|
+
" end\n" +
|
69
|
+
"end\n"
|
70
|
+
end
|
71
|
+
|
72
|
+
it "converts no open, text, and no close tag" do
|
73
|
+
parse("hello</div>").convert.should == "text 'hello'\nend\n"
|
74
|
+
end
|
75
|
+
|
76
|
+
it "converts open, text, and no close tag" do
|
77
|
+
parse("<div>hello").convert.should == "div do\n text 'hello'\n"
|
78
|
+
end
|
79
|
+
|
80
|
+
it "converts open, text, close" do
|
81
|
+
parse("<div>hello</div>").convert.should == "div do\n text 'hello'\nend\n"
|
82
|
+
end
|
83
|
+
|
84
|
+
it "autocloses an img tag" do
|
85
|
+
parse("<img src='foo'>").convert.should == "img :src => 'foo'\n"
|
86
|
+
end
|
87
|
+
|
88
|
+
it "converts a scriptlet" do
|
89
|
+
parse("<% foo %>").convert.should == "foo\n"
|
90
|
+
end
|
91
|
+
|
92
|
+
it "converts open, text, scriptlet, text, close" do
|
93
|
+
parse("<div>hello <% 5.times do %> very <% end %> much</div>").convert.should ==
|
94
|
+
"div do\n" +
|
95
|
+
" text 'hello'\n" +
|
96
|
+
" 5.times do\n" +
|
97
|
+
" text 'very'\n" +
|
98
|
+
" end\n" +
|
99
|
+
" text 'much'\n" +
|
100
|
+
"end\n"
|
101
|
+
end
|
102
|
+
|
103
|
+
it "converts open, scriptlet, text, close" do
|
104
|
+
parse("<div><% 5.times do %> very <% end %> much</div>").convert.should ==
|
105
|
+
"div do\n" +
|
106
|
+
" 5.times do\n" +
|
107
|
+
" text 'very'\n" +
|
108
|
+
" end\n" +
|
109
|
+
" text 'much'\n" +
|
110
|
+
"end\n"
|
111
|
+
end
|
112
|
+
|
113
|
+
it "converts open, text, scriptlet, close" do
|
114
|
+
parse("<div>hello <% 5.times do %> very <% end %></div>").convert.should ==
|
115
|
+
"div do\n" +
|
116
|
+
" text 'hello'\n" +
|
117
|
+
" 5.times do\n" +
|
118
|
+
" text 'very'\n" +
|
119
|
+
" end\n" +
|
120
|
+
"end\n"
|
121
|
+
end
|
122
|
+
|
123
|
+
it "converts printlets into rawtext statements" do
|
124
|
+
parse("<%= 1+1 %>").convert.should == "rawtext 1+1\n"
|
125
|
+
parse("<%= link_to \"mom\" %>").convert.should == "rawtext link_to(\"mom\")\n"
|
126
|
+
end
|
127
|
+
|
128
|
+
it "converts h-printlets into text statements" do
|
129
|
+
parse("<%=h foo %>").convert.should == "text foo\n"
|
130
|
+
parse("<%= h \"mom\" %>").convert.should == "text \"mom\"\n"
|
131
|
+
end
|
132
|
+
|
133
|
+
it "allows naked percent signs inside scriptlets" do
|
134
|
+
parse("<% x = 10 % 5 %>").convert.should == "x = 10 % 5\n"
|
135
|
+
end
|
136
|
+
|
137
|
+
it "indents" do
|
138
|
+
i = Erector::Indenting.new(nil, nil)
|
139
|
+
i.line("foo").should == "foo\n"
|
140
|
+
i.line_in("bar").should == "bar\n"
|
141
|
+
i.line_in("baz").should == " baz\n"
|
142
|
+
i.line("baf").should == " baf\n"
|
143
|
+
i.line_out("end").should == " end\n"
|
144
|
+
i.line_out("end").should == "end\n"
|
145
|
+
end
|
146
|
+
|
147
|
+
it "indents extra when told to" do
|
148
|
+
parse("<div>hello</div>").set_indent(2).convert.should ==
|
149
|
+
" div do\n" +
|
150
|
+
" text 'hello'\n" +
|
151
|
+
" end\n"
|
152
|
+
end
|
153
|
+
|
154
|
+
it "indents scriptlets ending with do and end" do
|
155
|
+
parse("<% form_for :foo do |x,y| %><% 5.times do %>hello<% end %><% end %>bye").convert.should ==
|
156
|
+
"form_for :foo do |x,y|\n" +
|
157
|
+
" 5.times do\n" +
|
158
|
+
" text 'hello'\n" +
|
159
|
+
" end\n" +
|
160
|
+
"end\n" +
|
161
|
+
"text 'bye'\n"
|
162
|
+
end
|
163
|
+
|
164
|
+
it "converts HTML attributes" do
|
165
|
+
parse("<div id='foo'/>").convert.should == "div :id => 'foo'\n"
|
166
|
+
parse("<div id='foo' class='bar'/>").convert.should == "div :id => 'foo', :class => 'bar'\n"
|
167
|
+
parse("<div id='foo'>bar</div>").convert.should == "div :id => 'foo' do\n text 'bar'\nend\n"
|
168
|
+
end
|
169
|
+
|
170
|
+
it "escapes single quotes inside attribute values" do
|
171
|
+
@parser.root = :attribute
|
172
|
+
parse("a=\"don't worry\"").convert.should == ":a => 'don\\'t worry'"
|
173
|
+
end
|
174
|
+
|
175
|
+
it "escapes single quotes inside text strings" do
|
176
|
+
parse("isn't she lovely").convert.should == "text 'isn" + "\\" + "'t she lovely'\n"
|
177
|
+
end
|
178
|
+
|
179
|
+
it "allows newlines where whitespace is allowed" do
|
180
|
+
parse("<img src='foo' \nalt='bar' />").convert.should == "img :src => 'foo', :alt => 'bar'\n"
|
181
|
+
end
|
182
|
+
|
183
|
+
it "treats tab characters the same as spaces" do
|
184
|
+
parse("<div \t />").convert.should == "div\n"
|
185
|
+
end
|
186
|
+
|
187
|
+
it "deals with HTML entities in text" do
|
188
|
+
parse("<").convert.should == "text '<'\n"
|
189
|
+
end
|
190
|
+
|
191
|
+
it "deals with a naked less-than or greater-than sign inside text" do
|
192
|
+
parse("if x > 2 or x< 5 then").convert.should == "text 'if x > 2 or x< 5 then'\n"
|
193
|
+
end
|
194
|
+
|
195
|
+
it "wraps printlets in parens if necessary, to avoid warning: parenthesize argument(s) for future version" do
|
196
|
+
parse("<%= h \"mom\" %>").convert.should == "text \"mom\"\n"
|
197
|
+
parse("<%= h hi \"mom\" %>").convert.should == "text hi(\"mom\")\n"
|
198
|
+
|
199
|
+
parse("<%= \"mom\" %>").convert.should == "rawtext \"mom\"\n"
|
200
|
+
parse("<%= \"hi mom\" %>").convert.should == "rawtext \"hi mom\"\n"
|
201
|
+
parse("<%= hi \"mom\" %>").convert.should == "rawtext hi(\"mom\")\n"
|
202
|
+
|
203
|
+
parse("<%= link_to blah %>").convert.should == "rawtext link_to(blah)\n"
|
204
|
+
parse("<%= link_to blah blah %>").convert.should == "rawtext link_to(blah blah)\n"
|
205
|
+
parse("<%= link_to blah(blah) %>").convert.should == "rawtext link_to(blah(blah))\n"
|
206
|
+
|
207
|
+
parse("<%= link_to(blah) %>").convert.should == "rawtext link_to(blah)\n"
|
208
|
+
end
|
209
|
+
|
210
|
+
it "won't parenthesize expressions" do
|
211
|
+
parse("<%= h foo / bar %>").convert.should == "text foo / bar\n"
|
212
|
+
end
|
213
|
+
|
214
|
+
it "understands a varname" do
|
215
|
+
@parser.root = :varname
|
216
|
+
parse("head").text_value.should == "head"
|
217
|
+
end
|
218
|
+
|
219
|
+
it "converts yield printlet into a use of @content_for_layout, commented for your edification" do
|
220
|
+
parse("<%= yield %>").convert.should == "rawtext @content_for_layout # Note: you must define @content_for_layout elsewhere\n"
|
221
|
+
parse("<%= yield :head %>").convert.should == "rawtext @content_for_head # Note: you must define @content_for_head elsewhere\n"
|
222
|
+
parse("<%= \"yield\" %>").convert.should == "rawtext \"yield\"\n"
|
223
|
+
parse("<%= \"the yield is good\" %>").convert.should == "rawtext \"the yield is good\"\n"
|
224
|
+
end
|
225
|
+
|
226
|
+
it "parses quoted strings" do
|
227
|
+
@parser.root = :quoted
|
228
|
+
parse("'foo'").value.should == "foo"
|
229
|
+
parse("\"foo\"").value.should == "foo"
|
230
|
+
end
|
231
|
+
|
232
|
+
it "converts attributes in isolation" do
|
233
|
+
@parser.root = :attribute
|
234
|
+
parse("a='foo'").convert.should == ":a => 'foo'"
|
235
|
+
parse("a=\"foo\"").convert.should == ":a => 'foo'"
|
236
|
+
end
|
237
|
+
|
238
|
+
it "parses a set of attributes" do
|
239
|
+
@parser.root = :attributes
|
240
|
+
parse("a='foo' b='bar'").convert.should == " :a => 'foo', :b => 'bar'"
|
241
|
+
end
|
242
|
+
|
243
|
+
it "works with namespaced attributes" do
|
244
|
+
@parser.root = :attribute
|
245
|
+
parse('xml:lang="en"').convert.should == "'xml:lang' => 'en'"
|
246
|
+
end
|
247
|
+
|
248
|
+
it "deals with HTML entities in attribute values" do
|
249
|
+
@parser.root = :attribute
|
250
|
+
parse("foo='b<r'").convert.should == ":foo => 'b<r'"
|
251
|
+
parse("foo='b<r'").convert.should == ":foo => 'b<r'"
|
252
|
+
end
|
253
|
+
|
254
|
+
it "converts DOCTYPEs" do
|
255
|
+
html = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
256
|
+
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">'
|
257
|
+
parse(html).convert.should == "rawtext '#{html}'\n"
|
258
|
+
end
|
259
|
+
|
260
|
+
["<!--[if IE]>", "<![endif]-->", "<![if !IE]>", "<![endif]>", "<!--[if IE 5.5000]>", "<!--[if IE 6]>"].each do |html|
|
261
|
+
it "converts IE directive '#{html}'" do
|
262
|
+
parse(html).convert.should == "rawtext '#{html}'\n"
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
## More functional-type specs below here
|
267
|
+
|
268
|
+
it "ignores spaces, tabs and newlines" do
|
269
|
+
parse(" <div>\t\n" + "\thello !" + "\n\t</div>").convert.should ==
|
270
|
+
"div do\n" +
|
271
|
+
" text 'hello !'\n" +
|
272
|
+
"end\n"
|
273
|
+
end
|
274
|
+
|
275
|
+
it "parses some scaffolding" do
|
276
|
+
parse("<p>
|
277
|
+
<b>Name:</b>
|
278
|
+
<%=h @foo.name %>
|
279
|
+
</p>").convert.should ==
|
280
|
+
"p do\n" +
|
281
|
+
" b do\n" +
|
282
|
+
" text 'Name:'\n" +
|
283
|
+
" end\n" +
|
284
|
+
" text @foo.name\n" +
|
285
|
+
"end\n"
|
286
|
+
end
|
287
|
+
|
288
|
+
it "parses edit.erb.html" do
|
289
|
+
parse("<h1>Editing foo</h1>
|
290
|
+
|
291
|
+
<%= error_messages_for :foo %>
|
292
|
+
|
293
|
+
<% form_for(@foo) do |f| %>
|
294
|
+
<p>
|
295
|
+
<b>Name</b><br />
|
296
|
+
<%= f.text_field :name %>
|
297
|
+
</p>
|
298
|
+
|
299
|
+
<p>
|
300
|
+
<b>Age</b><br />
|
301
|
+
<%= f.text_field :age %>
|
302
|
+
</p>
|
303
|
+
|
304
|
+
<p>
|
305
|
+
<%= f.submit \"Update\" %>
|
306
|
+
</p>
|
307
|
+
<% end %>
|
308
|
+
|
309
|
+
<%= link_to 'Show', @foo %> |
|
310
|
+
<%= link_to 'Back', foos_path %>
|
311
|
+
")
|
312
|
+
end
|
313
|
+
|
314
|
+
it "parses show.html.erb" do
|
315
|
+
parse("<p>
|
316
|
+
<b>Name:</b>
|
317
|
+
<%=h @foo.name %>
|
318
|
+
</p>
|
319
|
+
|
320
|
+
<p>
|
321
|
+
<b>Age:</b>
|
322
|
+
<%=h @foo.age %>
|
323
|
+
</p>
|
324
|
+
|
325
|
+
|
326
|
+
<%= link_to 'Edit', edit_foo_path(@foo) %> |
|
327
|
+
<%= link_to 'Back', foos_path %>
|
328
|
+
")
|
329
|
+
end
|
330
|
+
|
331
|
+
it "does meta" do
|
332
|
+
parse('<meta http-equiv="content-type" content="text/html;charset=UTF-8" />').convert.should ==
|
333
|
+
"meta 'http-equiv' => 'content-type', :content => 'text/html;charset=UTF-8'\n"
|
334
|
+
end
|
335
|
+
|
336
|
+
it "parses JayTee's IE and DOCTYPE test file" do
|
337
|
+
parse <<-HTML
|
338
|
+
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
339
|
+
<html xmlns="http://www.w3.org/1999/xhtml">
|
340
|
+
<head>
|
341
|
+
<!--[if IE]><link href="custom.css" rel="stylesheet" type="text/css" /><![endif]-->
|
342
|
+
<!--[if IE]><link href="custom.css" rel="stylesheet" type="text/css" /><![endif]-->
|
343
|
+
<script language="javascript" type="text/javascript"> /* <![CDATA[ */
|
344
|
+
var myJavascriptCode = 1; /*]]>*/ </script>
|
345
|
+
</head>
|
346
|
+
<body>
|
347
|
+
</body>
|
348
|
+
</html>
|
349
|
+
HTML
|
350
|
+
end
|
351
|
+
end
|