erector 0.2.42 → 0.2.61

Sign up to get free protection for your applications and to get access to all the features.
data/README.txt CHANGED
@@ -136,10 +136,10 @@ Here are the basics:
136
136
 
137
137
  TODO: document more obscure features like capture, Table, :class => ['one', 'two']
138
138
 
139
- === Using erector from Ruby on Rails
139
+ === Using Erector from Ruby on Rails
140
140
 
141
- Your views are just ruby classes. Your controller instantiates the
142
- relevant view and calls render. For example:
141
+ Your views are just ruby classes. Your controller instantiates the relevant view and calls render.
142
+ For example:
143
143
 
144
144
  app/controllers/welcome_controller.rb:
145
145
 
@@ -169,6 +169,40 @@ app/views/welcome/show.rb:
169
169
 
170
170
  end
171
171
 
172
+ For Rails to find these .rb files during render, you must first either copy the erector source to
173
+ vendor/plugins/erector, or add `require 'erector'` to config/environment.rb. You also should delete (or rename)
174
+ any other view files with the same base name that might be getting in the way.
175
+
176
+ === Erect
177
+
178
+ To make Rails integration as smooth as possible, we've written a little tool that will help you
179
+ erect your existing Rails app. The "erect" tool will convert HTML or HTML/ERB into an Erector class.
180
+ It ships as part of the Erector gem, so to try it out, install the gem, then run
181
+
182
+ erect app/views/foos/*.html.erb
183
+
184
+ or just
185
+
186
+ erect app/views
187
+
188
+ and then delete the original files when you're satisfied.
189
+
190
+ Here's a little command-line howto for erecting a scaffold Rails app:
191
+
192
+ rails foo
193
+ cd foo
194
+ script/generate scaffold post title:string body:text published:boolean
195
+
196
+ erect app/views/posts/*.erb
197
+
198
+ mate app/views/posts
199
+ sleep 30 # this should be enough time for you to stop drooling
200
+ rm app/views/posts/*.erb
201
+ (echo ""; echo "require 'erector'") >> config/environment.rb
202
+ rake db:migrate
203
+ script/server
204
+ open http://localhost:3000/posts
205
+
172
206
  === Layout Inheritance
173
207
 
174
208
  Erector replaces the typical Rails layout mechanism with a more natural construct, the use of inheritance. Want a common
@@ -211,6 +245,8 @@ method, you can pass a block to Erector::Widget.new. For example:
211
245
  end
212
246
  html.to_s #=> <p>Hello, world!</p>
213
247
 
248
+ This lets you define mini-widgets on the fly.
249
+
214
250
  == DEVELOPER NOTES
215
251
 
216
252
  * Check out project from rubyforge:
@@ -219,7 +255,7 @@ method, you can pass a block to Erector::Widget.new. For example:
219
255
 
220
256
  * Install gems:
221
257
 
222
- sudo gem install rake rails rspec rubyforge hpricot
258
+ sudo gem install rake rails rspec rubyforge hpricot treetop
223
259
 
224
260
  * Run specs:
225
261
 
@@ -241,6 +277,6 @@ method, you can pass a block to Erector::Widget.new. For example:
241
277
  * We will not be shy about incrementing version numbers -- if we end up going to version 0.943.67454 then so be it.
242
278
  * Developers should attempt to add lines in History.txt to reflect their checkins. These should reflect feature-level changes, not just one line per checkin. The top section of History.txt is used as the Release Notes by the "rake publish" task and will appear on the RubyForge file page.
243
279
  * Someone making a release must fill in the version number in History.txt as well as in Rakefile. Note that "rake release" requires a "VERSION=1.2.3" parameter to confirm you're releasing the version you intend.
244
- * As soon as a release is made and published, the publisher should go into History.txt and make a new section. Since we won't yet know what the next version will be called, the new section will be noted by a single "==" at the top of the file.
280
+ * As soon as a release is made and published, the publisher should go into History.txt and make a new section. Since we won't yet know what the next version will be called, the new section will be noted by a single "===" at the top of the file.
245
281
 
246
282
 
@@ -0,0 +1,31 @@
1
+ #!/usr/bin/env ruby
2
+ dir = File.expand_path(File.dirname(__FILE__))
3
+ $LOAD_PATH.unshift("#{dir}/../lib")
4
+ require "erector"
5
+ require "erector/erected" # pull this out so we don't recreate the grammar every time
6
+ require "rake"
7
+
8
+ # todo:
9
+ # --add_to_svn
10
+ # --delete_original
11
+
12
+ files = FileList.new
13
+ ARGV.each do |file|
14
+ if File.directory?(file)
15
+ files.add(FileList["#{file}/**/*.rhtml", "#{file}/**/*.html", "#{file}/**/*.html.erb"])
16
+ else
17
+ files.add(file)
18
+ end
19
+ end
20
+
21
+ files.each do |file|
22
+ print "Erecting #{file}... "
23
+ begin
24
+ e = Erector::Erected.new(file)
25
+ e.convert
26
+ puts " --> #{e.filename}"
27
+ rescue => e
28
+ puts e
29
+ puts
30
+ end
31
+ end
@@ -0,0 +1,63 @@
1
+ require 'rubygems'
2
+ require 'treetop'
3
+ dir = File.dirname(__FILE__)
4
+ require "#{dir}/indenting"
5
+ Treetop.load "#{dir}/../../lib/erector/rhtml"
6
+
7
+ module Erector
8
+ class Erected
9
+ def initialize(in_file)
10
+ @in_file = in_file
11
+ end
12
+
13
+ def filename
14
+ dir + basename + ".rb"
15
+ end
16
+
17
+ def classname
18
+ base = classize(basename)
19
+ parent = File.dirname(@in_file)
20
+ grandparent = File.dirname(parent)
21
+ if File.basename(grandparent) == "views"
22
+ base = "Views::" + classize(File.basename(parent)) + "::" + base
23
+ end
24
+ base
25
+ end
26
+
27
+ def text
28
+ File.read(@in_file)
29
+ end
30
+
31
+ def convert
32
+ parser = RhtmlParser.new
33
+ parsed = parser.parse(File.read(@in_file))
34
+ if parsed.nil?
35
+ raise "Could not parse #{@in_file}\n" +
36
+ parser.failure_reason
37
+ else
38
+ File.open(filename, "w") do |f|
39
+ f.puts("class #{classname} < Erector::Widget")
40
+ f.puts(" def render")
41
+ f.puts(parsed.set_indent(2).convert)
42
+ f.puts(" end")
43
+ f.puts("end")
44
+ end
45
+ end
46
+ end
47
+
48
+ protected
49
+
50
+ def basename
51
+ @in_file.split("/").last.gsub(/\..*$/, '')
52
+ end
53
+
54
+ def dir
55
+ x = File.dirname(@in_file)
56
+ return (x == ".") ? "" : "#{x}/"
57
+ end
58
+
59
+ def classize(filename)
60
+ filename.split("_").map{|part| part.capitalize}.join
61
+ end
62
+ end
63
+ end
@@ -1,5 +1,6 @@
1
1
  module Erector
2
2
  module Helpers
3
+
3
4
  [
4
5
  :image_tag,
5
6
  :javascript_include_tag,
@@ -23,6 +24,18 @@ module Erector
23
24
  end
24
25
  end
25
26
 
27
+ def error_messages_for(*args)
28
+ fake_erbout do
29
+ helpers.error_messages_for(*args)
30
+ end
31
+ end
32
+
33
+ def form_for(*args, &block)
34
+ fake_erbout do
35
+ helpers.form_for(*args, &block)
36
+ end
37
+ end
38
+
26
39
  def javascript_include_merged(key)
27
40
  helpers.javascript_include_merged(key)
28
41
  end
@@ -0,0 +1,36 @@
1
+ require 'rubygems'
2
+ require 'treetop'
3
+
4
+ module Erector
5
+ class Indenting < Treetop::Runtime::SyntaxNode
6
+ @@indent = 0
7
+
8
+ def set_indent(x)
9
+ @@indent = x
10
+ self
11
+ end
12
+
13
+ def indent
14
+ [0, @@indent].max
15
+ end
16
+
17
+ def indented(s)
18
+ " " * indent + s + "\n"
19
+ end
20
+
21
+ def line(s)
22
+ indented(s)
23
+ end
24
+
25
+ def line_in(s)
26
+ s = indented(s)
27
+ @@indent += 1
28
+ s
29
+ end
30
+
31
+ def line_out(s)
32
+ @@indent -= 1
33
+ indented(s)
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,143 @@
1
+ grammar Rhtml
2
+
3
+ rule doc
4
+ space node space x:doc? <Erector::Indenting> {
5
+ def convert
6
+ if x.empty?
7
+ node.convert
8
+ else
9
+ node.convert + x.convert
10
+ end
11
+ end
12
+ }
13
+ end
14
+
15
+ rule node
16
+ hprintlet / printlet / scriptlet / doctype / self_closing_tag / closetag / opentag / text
17
+ end
18
+
19
+ rule scriptlet
20
+ '<%' space code space '%>' <Erector::Indenting> {
21
+ def convert
22
+ text = code.text_value.strip
23
+ if text =~ /\bdo( |.*|)?$/
24
+ line_in text
25
+ elsif text == "end"
26
+ line_out text
27
+ else
28
+ line text
29
+ end
30
+ end
31
+ }
32
+ end
33
+
34
+ rule printlet
35
+ '<%=' space code space '%>' <Erector::Indenting> {
36
+ def convert
37
+ line "rawtext #{code.convert}"
38
+ end
39
+ }
40
+ end
41
+
42
+ rule hprintlet
43
+ '<%=' space 'h' ' '+ code space '%>' <Erector::Indenting> {
44
+ def convert
45
+ line "text #{code.convert}"
46
+ end
47
+ }
48
+ end
49
+
50
+ rule code
51
+ (('%' !'>') / [^%])* <Erector::Indenting> {
52
+ def convert
53
+ code = text_value.strip
54
+ # matches a word, followed by either a word, a string, or a symbol
55
+ code.gsub(/(\w+) ([\w:"'].*)$/, '\1(\2)')
56
+ end
57
+ }
58
+ end
59
+
60
+ rule doctype
61
+ '<!DOCTYPE' [^>]* '>' <Erector::Indenting> {
62
+ def convert
63
+ line "rawtext '#{text_value}'"
64
+ end
65
+ }
66
+ end
67
+
68
+ rule tagname
69
+ [A-Za-z0-9_:-]+
70
+ end
71
+
72
+ rule self_closing_tag
73
+ '<' tag_name:tagname attrs:attributes? space '/>' <Erector::Indenting> {
74
+ def convert
75
+ line "#{tag_name.text_value}#{attrs.blank? ? "" : attrs.convert}"
76
+ end
77
+ }
78
+ end
79
+
80
+ rule opentag
81
+ '<' tag_name:tagname attrs:attributes? space '>' <Erector::Indenting> {
82
+ def convert
83
+ line_in "#{tag_name.text_value}#{attrs.blank? ? "" : attrs.convert} do"
84
+ end
85
+ }
86
+ end
87
+
88
+ rule closetag
89
+ '</' tag_name:tagname '>' <Erector::Indenting> {
90
+ def convert
91
+ line_out "end"
92
+ end
93
+ }
94
+ end
95
+
96
+ rule text
97
+ (([<>] !(tagname / [/%!])) / [^<>])+ <Erector::Indenting> {
98
+ def convert
99
+ stripped = text_value.strip
100
+ if stripped.blank?
101
+ ""
102
+ else
103
+ line "text '#{text_value.strip.html_unescape}'"
104
+ end
105
+ end
106
+ }
107
+ end
108
+
109
+ rule attributes
110
+ first:attribute rest:attributes* {
111
+ def convert
112
+ " " + first.convert +
113
+ if rest.blank?
114
+ ""
115
+ else
116
+ ",#{rest.elements.first.convert}" # this is hacky -- is there a better way?
117
+ end
118
+ end
119
+ }
120
+ end
121
+
122
+ rule attribute
123
+ space n:(tagname) space '=' space v:quoted space {
124
+ def convert
125
+ attr_name = (n.text_value =~ /[-:]/) ? "'#{n.text_value}'" : ":#{n.text_value}"
126
+ "#{attr_name} => '#{v.value.html_unescape.escape_single_quotes}'"
127
+ end
128
+ }
129
+ end
130
+
131
+ rule quoted
132
+ (('"' val:([^"]*) '"') / ('\'' val:([^']*) '\'')) {
133
+ def value
134
+ val.text_value
135
+ end
136
+ }
137
+ end
138
+
139
+ rule space
140
+ ' '*
141
+ end
142
+
143
+ end
@@ -1,3 +1,5 @@
1
+ require 'cgi'
2
+
1
3
  module Erector
2
4
  class Widget
3
5
  class << self
@@ -22,7 +24,8 @@ module Erector
22
24
  end
23
25
  end
24
26
 
25
- include ActionController::UrlWriter, Helpers
27
+ include ActionController::UrlWriter
28
+ include Helpers
26
29
  attr_reader :helpers
27
30
  attr_reader :assigns
28
31
  attr_reader :doc
@@ -190,8 +193,8 @@ module Erector
190
193
  @__to_s = @doc.to_s
191
194
  end
192
195
 
193
- def html_escape()
194
- return to_s()
196
+ def html_escape
197
+ return to_s
195
198
  end
196
199
 
197
200
  alias_method :inspect, :to_s
@@ -232,7 +235,7 @@ module Erector
232
235
  raise "Cannot nest fake_erbout" if instance_methods.include?('concat_without_erector')
233
236
  alias_method :concat_without_erector, :concat
234
237
  define_method :concat do |some_text, binding|
235
- widget.text widget.raw(some_text)
238
+ widget.rawtext(some_text)
236
239
  end
237
240
  end
238
241
  yield
@@ -253,6 +256,15 @@ end
253
256
 
254
257
  class Object
255
258
  def html_escape
256
- return CGI.escapeHTML(to_s())
259
+ return CGI.escapeHTML(to_s)
260
+ end
261
+
262
+ def html_unescape
263
+ CGI.unescapeHTML(to_s)
264
+ end
265
+
266
+ # OMGWTF
267
+ def escape_single_quotes
268
+ self.gsub(/[']/, '\\\\\'')
257
269
  end
258
270
  end
@@ -0,0 +1,83 @@
1
+ dir = File.dirname(__FILE__)
2
+ require "#{dir}/../spec_helper"
3
+ require "#{dir}/../../lib/erector/erected"
4
+ require 'tempfile'
5
+
6
+ module Erector
7
+ describe Erected do
8
+
9
+ it "picks the right file name" do
10
+ Erected.new("foo.html.erb").filename.should == "foo.rb"
11
+ Erected.new("foo.html").filename.should == "foo.rb"
12
+ Erected.new("foo.bar.html").filename.should == "foo.rb"
13
+ Erected.new("foo_bar.html.erb").filename.should == "foo_bar.rb"
14
+ Erected.new("stuff/foo_bar.html.erb").filename.should == "stuff/foo_bar.rb"
15
+ end
16
+
17
+ it "picks a nice class name" do
18
+ Erected.new("foo.html.erb").classname.should == "Foo"
19
+ Erected.new("foo.html").classname.should == "Foo"
20
+ Erected.new("foo.bar.html").classname.should == "Foo"
21
+ Erected.new("foo_bar.html.erb").classname.should == "FooBar"
22
+ Erected.new("stuff/foo_bar.html.erb").classname.should == "FooBar"
23
+ end
24
+
25
+ it "picks an even nicer class name if it's in a views dir" do
26
+ Erected.new("app/views/stuff/foo_bar.html.erb").classname.should == "Views::Stuff::FooBar"
27
+ Erected.new("views/stuff/foo_bar.html.erb").classname.should == "Views::Stuff::FooBar"
28
+ end
29
+
30
+ def convert(dir, input, output)
31
+ dir = Dir.tmpdir + "/#{Time.now.to_i}" + "/#{dir}"
32
+
33
+ FileUtils.mkdir_p(dir)
34
+ html = "#{dir}/dummy.html"
35
+ rb = "#{dir}/dummy.rb"
36
+
37
+ File.open(html, "w") do |f|
38
+ f.puts(input)
39
+ end
40
+
41
+ @e = Erected.new(html)
42
+ @e.convert
43
+
44
+ File.read(rb).should == output
45
+ end
46
+
47
+ it "converts a normal file" do
48
+ convert(".",
49
+ "<div>hello</div>",
50
+ "class Dummy < Erector::Widget\n" +
51
+ " def render\n" +
52
+ " div do\n" +
53
+ " text 'hello'\n" +
54
+ " end\n" +
55
+ " end\n" +
56
+ "end\n"
57
+ )
58
+ end
59
+
60
+ it "converts a views file" do
61
+ convert("app/views/foos",
62
+ "<div>hello</div>",
63
+ "class Views::Foos::Dummy < Erector::Widget\n" +
64
+ " def render\n" +
65
+ " div do\n" +
66
+ " text 'hello'\n" +
67
+ " end\n" +
68
+ " end\n" +
69
+ "end\n"
70
+ )
71
+ end
72
+
73
+ # todo: figure out if there is any such thing as unparsable HTML anymore
74
+ # it "raises an exception if given unparsable HTML" do
75
+ # begin
76
+ # convert(".", "<", "")
77
+ # rescue => e
78
+ # e.to_s.should include("Could not parse")
79
+ # end
80
+ # end
81
+
82
+ end
83
+ end
@@ -0,0 +1,304 @@
1
+ dir = File.dirname(__FILE__)
2
+ require "#{dir}/../spec_helper"
3
+
4
+ # require 'test/unit'
5
+ require 'rubygems'
6
+ require 'treetop'
7
+ require "erector/erected" # pull this out so we don't recreate the grammar every time
8
+
9
+ module ParserTestHelper
10
+ def assert_evals_to_self(input)
11
+ assert_evals_to(input, input)
12
+ end
13
+
14
+ def parse(input)
15
+ result = @parser.parse(input)
16
+ if result
17
+ result.set_indent(0) if result.respond_to? :set_indent
18
+ else
19
+ puts @parser.failure_reason
20
+ puts @parser.terminal_failures.join("\n")
21
+ result.should_not be_nil
22
+ end
23
+ result
24
+ end
25
+ end
26
+
27
+ describe RhtmlParser do
28
+ include ParserTestHelper
29
+
30
+ before :each do
31
+ @parser = RhtmlParser.new
32
+ end
33
+
34
+ it "converts text" do
35
+ parse("hello").convert.should == "text 'hello'\n"
36
+ parse("hello maude!").convert.should == "text 'hello maude!'\n"
37
+ parse(" hello ").convert.should == "text 'hello'\n"
38
+ end
39
+
40
+ it "unescapes HTML entities in text" do
41
+ parse("&lt;").convert.should == "text '<'\n"
42
+ parse("5 &gt; 2").convert.should == "text '5 > 2'\n"
43
+ end
44
+
45
+ it "converts self-closing tags" do
46
+ parse("<br/>").convert.should == "br\n"
47
+ parse("<br />").convert.should == "br\n"
48
+ end
49
+
50
+ it "converts open tag" do
51
+ parse("<div>").convert.should == "div do\n"
52
+ parse("<h1>").convert.should == "h1 do\n"
53
+ end
54
+
55
+ it "converts close tag" do
56
+ parse("</div>").convert.should == "end\n"
57
+ parse("</h1>").convert.should == "end\n"
58
+ end
59
+
60
+ it "converts two nested divs" do
61
+ parse("<div><div></div></div>").convert.should ==
62
+ "div do\n" +
63
+ " div do\n" +
64
+ " end\n" +
65
+ "end\n"
66
+ end
67
+
68
+ it "converts two nested divs with whitespace" do
69
+ parse("<div> <div> </div> </div>").convert.should ==
70
+ "div do\n" +
71
+ " div do\n" +
72
+ " end\n" +
73
+ "end\n"
74
+ end
75
+
76
+ it "converts no open, text, and no close tag" do
77
+ parse("hello</div>").convert.should == "text 'hello'\nend\n"
78
+ end
79
+
80
+ it "converts open, text, and no close tag" do
81
+ parse("<div>hello").convert.should == "div do\n text 'hello'\n"
82
+ end
83
+
84
+ it "converts open, text, close" do
85
+ parse("<div>hello</div>").convert.should == "div do\n text 'hello'\nend\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 "deals with HTML entities in text" do
176
+ parse("&lt;").convert.should == "text '<'\n"
177
+ end
178
+
179
+ it "deals with a naked less-than or greater-than sign inside text" do
180
+ parse("if x > 2 or x< 5 then").convert.should == "text 'if x > 2 or x< 5 then'\n"
181
+ end
182
+
183
+ it "wraps printlets in parens if necessary, to avoid warning: parenthesize argument(s) for future version" do
184
+ parse("<%= h \"mom\" %>").convert.should == "text \"mom\"\n"
185
+ parse("<%= h hi \"mom\" %>").convert.should == "text hi(\"mom\")\n"
186
+
187
+ parse("<%= \"mom\" %>").convert.should == "rawtext \"mom\"\n"
188
+ parse("<%= hi \"mom\" %>").convert.should == "rawtext hi(\"mom\")\n"
189
+
190
+ parse("<%= link_to blah %>").convert.should == "rawtext link_to(blah)\n"
191
+ parse("<%= link_to blah blah %>").convert.should == "rawtext link_to(blah blah)\n"
192
+ parse("<%= link_to blah(blah) %>").convert.should == "rawtext link_to(blah(blah))\n"
193
+
194
+ parse("<%= link_to(blah) %>").convert.should == "rawtext link_to(blah)\n"
195
+ end
196
+
197
+ it "won't parenthesize expressions" do
198
+ parse("<%= h foo / bar %>").convert.should == "text foo / bar\n"
199
+ end
200
+
201
+ it "parses quoted strings" do
202
+ @parser.root = :quoted
203
+ parse("'foo'").value.should == "foo"
204
+ parse("\"foo\"").value.should == "foo"
205
+ end
206
+
207
+ it "converts attributes in isolation" do
208
+ @parser.root = :attribute
209
+ parse("a='foo'").convert.should == ":a => 'foo'"
210
+ parse("a=\"foo\"").convert.should == ":a => 'foo'"
211
+ end
212
+
213
+ it "parses a set of attributes" do
214
+ @parser.root = :attributes
215
+ parse("a='foo' b='bar'").convert.should == " :a => 'foo', :b => 'bar'"
216
+ end
217
+
218
+ it "works with namespaced attributes" do
219
+ @parser.root = :attribute
220
+ parse('xml:lang="en"').convert.should == "'xml:lang' => 'en'"
221
+ end
222
+
223
+ it "deals with HTML entities in attribute values" do
224
+ @parser.root = :attribute
225
+ parse("foo='b<r'").convert.should == ":foo => 'b<r'"
226
+ parse("foo='b&lt;r'").convert.should == ":foo => 'b<r'"
227
+ end
228
+
229
+ it "converts DOCTYPEs" do
230
+ html = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
231
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">'
232
+ parse(html).convert.should == "rawtext '#{html}'\n"
233
+ end
234
+
235
+ ## More functional-type specs below here
236
+
237
+ it "ignores spaces, tabs and newlines" do
238
+ parse(" <div>\t\n" + "\thello !" + "\n\t</div>").convert.should ==
239
+ "div do\n" +
240
+ " text 'hello !'\n" +
241
+ "end\n"
242
+ end
243
+
244
+ it "parses some scaffolding" do
245
+ parse("""<p>
246
+ <b>Name:</b>
247
+ <%=h @foo.name %>
248
+ </p>""").convert.should ==
249
+ "p do\n" +
250
+ " b do\n" +
251
+ " text 'Name:'\n" +
252
+ " end\n" +
253
+ " text @foo.name\n" +
254
+ "end\n"
255
+ end
256
+
257
+ it "parses edit.erb.html" do
258
+ parse("""<h1>Editing foo</h1>
259
+
260
+ <%= error_messages_for :foo %>
261
+
262
+ <% form_for(@foo) do |f| %>
263
+ <p>
264
+ <b>Name</b><br />
265
+ <%= f.text_field :name %>
266
+ </p>
267
+
268
+ <p>
269
+ <b>Age</b><br />
270
+ <%= f.text_field :age %>
271
+ </p>
272
+
273
+ <p>
274
+ <%= f.submit \"Update\" %>
275
+ </p>
276
+ <% end %>
277
+
278
+ <%= link_to 'Show', @foo %> |
279
+ <%= link_to 'Back', foos_path %>
280
+ """)
281
+ end
282
+
283
+ it "parses show.html.erb" do
284
+ parse("""<p>
285
+ <b>Name:</b>
286
+ <%=h @foo.name %>
287
+ </p>
288
+
289
+ <p>
290
+ <b>Age:</b>
291
+ <%=h @foo.age %>
292
+ </p>
293
+
294
+
295
+ <%= link_to 'Edit', edit_foo_path(@foo) %> |
296
+ <%= link_to 'Back', foos_path %>
297
+ """)
298
+ end
299
+
300
+ it "does meta" do
301
+ parse('<meta http-equiv="content-type" content="text/html;charset=UTF-8" />').convert.should ==
302
+ "meta 'http-equiv' => 'content-type', :content => 'text/html;charset=UTF-8'\n"
303
+ end
304
+ end
metadata CHANGED
@@ -1,17 +1,35 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: erector
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.42
5
- platform: ""
4
+ version: 0.2.61
5
+ platform: ruby
6
6
  authors:
7
7
  - Pivotal Labs
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2008-04-11 00:00:00 -07:00
12
+ date: 2008-04-18 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: treetop
17
+ version_requirement:
18
+ version_requirements: !ruby/object:Gem::Requirement
19
+ requirements:
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 1.2.3
23
+ version:
24
+ - !ruby/object:Gem::Dependency
25
+ name: rake
26
+ version_requirement:
27
+ version_requirements: !ruby/object:Gem::Requirement
28
+ requirements:
29
+ - - ">="
30
+ - !ruby/object:Gem::Version
31
+ version: "0"
32
+ version:
15
33
  - !ruby/object:Gem::Dependency
16
34
  name: hoe
17
35
  version_requirement:
@@ -24,37 +42,42 @@ dependencies:
24
42
  description: Erector is a Builder-like view framework, inspired by Markaby but overcoming some of its flaws. In Erector all views are objects, not template files, which allows the full power of object-oriented programming (inheritance, modular decomposition, encapsulation) in views.
25
43
  email:
26
44
  - alex@pivotallabs.com
27
- executables: []
28
-
45
+ executables:
46
+ - erect
29
47
  extensions: []
30
48
 
31
49
  extra_rdoc_files:
32
50
  - README.txt
33
51
  files:
34
- - spec/erect
52
+ - spec/convert
53
+ - spec/convert/erected_spec.rb
54
+ - spec/convert/rhtml_parser_spec.rb
35
55
  - spec/erector
36
- - spec/spec_helper.rb
37
- - spec/spec_suite.rb
38
- - spec/view_caching.rb
39
- - spec/erect/erect_spec.rb
40
56
  - spec/erector/extensions
57
+ - spec/erector/extensions/render_widget_spec.rb
41
58
  - spec/erector/widget_spec.rb
42
59
  - spec/erector/widgets
43
- - spec/erector/extensions/render_widget_spec.rb
44
60
  - spec/erector/widgets/table_spec.rb
61
+ - spec/spec_helper.rb
62
+ - spec/spec_suite.rb
63
+ - spec/view_caching.rb
45
64
  - lib/erector
46
- - lib/erector.rb
65
+ - lib/erector/erected.rb
47
66
  - lib/erector/extensions
67
+ - lib/erector/extensions/action_controller.rb
68
+ - lib/erector/extensions/action_view_template_handler.rb
69
+ - lib/erector/extensions/object.rb
48
70
  - lib/erector/helpers.rb
49
71
  - lib/erector/html_parts.rb
72
+ - lib/erector/indenting.rb
73
+ - lib/erector/rhtml.treetop
50
74
  - lib/erector/widget.rb
51
75
  - lib/erector/widgets
52
- - lib/erector/widgets.rb
53
- - lib/erector/extensions/action_controller.rb
54
- - lib/erector/extensions/action_view_template_handler.rb
55
- - lib/erector/extensions/object.rb
56
76
  - lib/erector/widgets/table.rb
77
+ - lib/erector/widgets.rb
78
+ - lib/erector.rb
57
79
  - README.txt
80
+ - bin/erect
58
81
  has_rdoc: true
59
82
  homepage: http://erector.rubyforge.org
60
83
  post_install_message:
@@ -78,7 +101,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
78
101
  requirements: []
79
102
 
80
103
  rubyforge_project: erector
81
- rubygems_version: 0.9.5
104
+ rubygems_version: 1.0.1
82
105
  signing_key:
83
106
  specification_version: 2
84
107
  summary: Erector is a Builder-like view framework, inspired by Markaby but overcoming some of its flaws
@@ -1,7 +0,0 @@
1
- dir = File.dirname(__FILE__)
2
- require "#{dir}/spec_helper"
3
-
4
- context "" do
5
- specify "" do
6
- end
7
- end