Skip to content

Commit

Permalink
%s/code/erb/g
Browse files Browse the repository at this point in the history
This changes the ERB template parser to use `<erb>` rather than `<code>`
to designate code blocks in a template.

For example:

    <%= render template: 'foo/bar' %>

Used to parse as:

    <code erb-loud> render template: 'foo/bar' </code>

But not parses as:

    <erb erb-loud> render template: 'foo/bar' </erb>

This fixes a number of problems that result from using `<code>`:

* There may be </code> tags in the original ERB, which would be turned
  into `%>`
  (Fixes #101)

* Any <code> tags in the <head> of a document would be moved to the
  body, since <code> is a real HTML tag, and isn't allowed in the head.
  This happens in nokogiri under jRuby or libXML 2.9.0
  (Fixes #84, Fixes #100)

Unfortunately this breaks any existing deface selectors looking for
code, which are somewhat common. Selectors should be updated to cover
both code and erb:

    selector: "code:contains('my_method'), erb:contains('my_method')"
  • Loading branch information
jhawthorn committed Sep 3, 2013
1 parent 1110a13 commit 415422f
Show file tree
Hide file tree
Showing 6 changed files with 56 additions and 56 deletions.
10 changes: 5 additions & 5 deletions README.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ Removes any ERB block containing the string `helper_method` in the `posts/new.ht
```ruby
Deface::Override.new(:virtual_path => "posts/new",
:name => "example-4",
:remove => "code[erb-loud]:contains('helper_method')",
:remove => "erb[erb-loud]:contains('helper_method')",
:original => "<%= helper_method %>")
```

Expand All @@ -171,8 +171,8 @@ Remove an entire ERB if statement (and all it's contents) in the 'admin/products
```ruby
Deface::Override.new(:virtual_path => 'admin/products/index',
:name => "remove_if_statement",
:remove => "code[erb-silent]:contains('if @product.sold?')",
:closing_selector => "code[erb-silent]:contains('end')"
:remove => "erb[erb-silent]:contains('if @product.sold?')",
:closing_selector => "erb[erb-silent]:contains('end')"
```

### Scope
Expand Down Expand Up @@ -354,7 +354,7 @@ Deface temporarily converts ERB files into a pseudo HTML markup that can be pars
becomes:

```html
<code erb-loud> some ruby code </code>
<erb erb-loud> some ruby code </erb>
```

and
Expand All @@ -366,7 +366,7 @@ and
becomes:

```html
<code erb-silent> other ruby code </code>
<erb erb-silent> other ruby code </erb>
```

ERB that is contained inside a HTML tag definition is converted slightly differently to ensure a valid HTML document that Nokogiri can parse:
Expand Down
4 changes: 2 additions & 2 deletions lib/deface/actions/surround_action.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ def source_element
end

def original_placeholders
@original_placeholders ||= source_element.css("code:contains('render_original')")
@original_placeholders ||= source_element.css("erb:contains('render_original')")
raise(DefaceError, "The surround action couldn't find <%= render_original %> in your template") unless @original_placeholders.first
@original_placeholders
end
end
end
end
end
18 changes: 9 additions & 9 deletions lib/deface/parser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,13 @@ def self.erb_markup!(source)
end

#replaces all <% %> not inside opening html tags
replacements = [ {"<%=" => "<code erb-loud>"},
{"<%" => "<code erb-silent>"},
{"%>" => "</code>"} ]
replacements = [ {"<%=" => "<erb erb-loud>"},
{"<%" => "<erb erb-silent>"},
{"%>" => "</erb>"} ]

replacements.each{ |h| h.each { |replace, with| source.gsub! replace, with } }

source.scan(/(<code.*?>)((?:(?!<\/code>)[\s\S])*)(<\/code>)/).each do |match|
source.scan(/(<erb.*?>)((?:(?!<\/erb>)[\s\S])*)(<\/erb>)/).each do |match|
source.sub!("#{match[0]}#{match[1]}#{match[2]}") { |m| m = "#{match[0]}#{CGI.escapeHTML(match[1])}#{match[2]}" }
end

Expand All @@ -50,11 +50,11 @@ def self.erb_markup!(source)
# undoes ERB markup generated by Deface::Parser::ERB
#
def self.undo_erb_markup!(source)
replacements = [ {"<code erb-silent>" => '<%'},
{"<code erb-silent=\"\">" => '<%'},
{"<code erb-loud>" => '<%='},
{"<code erb-loud=\"\">" => '<%='},
{"</code>" => '%>'}]
replacements = [ {"<erb erb-silent>" => '<%'},
{"<erb erb-silent=\"\">" => '<%'},
{"<erb erb-loud>" => '<%='},
{"<erb erb-loud=\"\">" => '<%='},
{"</erb>" => '%>'}]

replacements.each{ |h| h.each { |replace, with| source.gsub! replace, with } }

Expand Down
4 changes: 2 additions & 2 deletions spec/deface/applicator_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ module Deface

describe "with a single :copy using :start and :end" do
before { Deface::Override.new(:virtual_path => "posts/index", :name => "Posts#index", :insert_before => "h1",
:copy => {:start => "code:contains('if true')", :end => "code:contains('end')"}) }
:copy => {:start => "erb:contains('if true')", :end => "erb:contains('end')"}) }
let(:source) { "<h1>World</h1><% if true %><p>True that!</p><% end %><p>Hello</p>" }


Expand All @@ -52,7 +52,7 @@ module Deface

describe "with a single :cut using :start and :end" do
before { Deface::Override.new(:virtual_path => "posts/index", :name => "Posts#index", :replace => "h1",
:cut => {:start => "code:contains('if true')", :end => "code:contains('end')"}) }
:cut => {:start => "erb:contains('if true')", :end => "erb:contains('end')"}) }
let(:source) { "<h1>World</h1><% if true %><p>True that!</p><% end %><p>Hello</p>" }


Expand Down
52 changes: 26 additions & 26 deletions spec/deface/override_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,9 @@ module Deface
@original.original_source.should be_an_instance_of Nokogiri::HTML::DocumentFragment

if RUBY_PLATFORM == 'java'
@original.original_source.to_s.should == "<p><code erb-loud=\"\"> something </code></p>"
@original.original_source.to_s.should == "<p><erb erb-loud=\"\"> something </erb></p>"
else
@original.original_source.to_s.should == "<p><code erb-loud> something </code></p>"
@original.original_source.to_s.should == "<p><erb erb-loud> something </erb></p>"
end
end
end
Expand All @@ -64,11 +64,11 @@ module Deface

it "should return true when input contains similar (ignoring whitespace)" do
if RUBY_PLATFORM == 'java'
@original.validate_original("<p><code erb-loud=\"\"> something </code></p>").should be_true
@original.validate_original("<p><code erb-loud=\"\">something\n</code> </p>").should be_true
@original.validate_original("<p><erb erb-loud=\"\"> something </erb></p>").should be_true
@original.validate_original("<p><erb erb-loud=\"\">something\n</erb> </p>").should be_true
else
@original.validate_original("<p><code erb-loud> something </code></p>").should be_true
@original.validate_original("<p><code erb-loud>something\n</code> </p>").should be_true
@original.validate_original("<p><erb erb-loud> something </erb></p>").should be_true
@original.validate_original("<p><erb erb-loud>something\n</erb> </p>").should be_true
end
end

Expand Down Expand Up @@ -117,11 +117,11 @@ module Deface

before(:each) do
@override = Deface::Override.new(:virtual_path => "posts/index", :name => "Posts#index", :replace => "h1",
:haml => %q{%strong{:class => "code", :id => "message"}= 'Hello, World!'})
:haml => %q{%strong{:class => "erb", :id => "message"}= 'Hello, World!'})
end

it "should return erb converted from haml as source" do
@override.source.should == "<strong class='code' id='message'><%= 'Hello, World!' %>\n</strong>\n"
@override.source.should == "<strong class='erb' id='message'><%= 'Hello, World!' %>\n</strong>\n"

@override.source_argument.should == :haml
end
Expand All @@ -131,11 +131,11 @@ module Deface

before(:each) do
@override = Deface::Override.new(:virtual_path => "posts/index", :name => "Posts#index", :replace => "h1",
:slim => %q{strong class="code" id="message"= 'Hello, World!'})
:slim => %q{strong class="erb" id="message"= 'Hello, World!'})
end

it "should return erb converted from slim as source" do
@override.source.should == "<strong class=\"code\" id=\"message\"><%= ::Temple::Utils.escape_html_safe(('Hello, World!')) %><%\n%></strong>"
@override.source.should == "<strong class=\"erb\" id=\"message\"><%= ::Temple::Utils.escape_html_safe(('Hello, World!')) %><%\n%></strong>"

@override.source_argument.should == :slim
end
Expand Down Expand Up @@ -189,9 +189,9 @@ module Deface
@override.source

if RUBY_PLATFORM == 'java'
parsed.to_s.gsub(/\n/,'').should == "<div><h1>Manage Posts</h1><code erb-loud=\"\"> some_method </code></div>"
parsed.to_s.gsub(/\n/,'').should == "<div><h1>Manage Posts</h1><erb erb-loud=\"\"> some_method </erb></div>"
else
parsed.to_s.gsub(/\n/,'').should == "<div><h1>Manage Posts</h1><code erb-loud> some_method </code></div>"
parsed.to_s.gsub(/\n/,'').should == "<div><h1>Manage Posts</h1><erb erb-loud> some_method </erb></div>"
end

@override.source_argument.should == :copy
Expand All @@ -202,7 +202,7 @@ module Deface
end

it "should return unescaped content for source document" do
@override = Deface::Override.new(:virtual_path => "posts/index", :name => "Posts#index", :insert_after => "h1", :copy => "code[erb-loud]:contains('some_method')")
@override = Deface::Override.new(:virtual_path => "posts/index", :name => "Posts#index", :insert_after => "h1", :copy => "erb[erb-loud]:contains('some_method')")
@override.stub(:parsed_document).and_return(parsed)
@override.source.should == "<%= some_method %>"
end
Expand All @@ -215,7 +215,7 @@ module Deface

before(:each) do
@override = Deface::Override.new(:virtual_path => "posts/index", :name => "Posts#index", :insert_after => "h1",
:copy => {:start => "code:contains('if true')", :end => "code:contains('end')"})
:copy => {:start => "erb:contains('if true')", :end => "erb:contains('end')"})

@override.stub(:parsed_document).and_return(parsed)
end
Expand All @@ -224,9 +224,9 @@ module Deface
@override.source

if RUBY_PLATFORM == 'java'
parsed.to_s.gsub(/\n/,'').should == "<h1>World</h1><code erb-silent=\"\"> if true </code><p>True that!</p><code erb-silent=\"\"> end </code><p>Hello</p>"
parsed.to_s.gsub(/\n/,'').should == "<h1>World</h1><erb erb-silent=\"\"> if true </erb><p>True that!</p><erb erb-silent=\"\"> end </erb><p>Hello</p>"
else
parsed.to_s.gsub(/\n/,'').should == "<h1>World</h1><code erb-silent> if true </code><p>True that!</p><code erb-silent> end </code><p>Hello</p>"
parsed.to_s.gsub(/\n/,'').should == "<h1>World</h1><erb erb-silent> if true </erb><p>True that!</p><erb erb-silent> end </erb><p>Hello</p>"
end

@override.source_argument.should == :copy
Expand All @@ -247,9 +247,9 @@ module Deface
it "should remove cut element from original parsed source" do
@override.source
if RUBY_PLATFORM == 'java'
parsed.to_s.gsub(/\n/,'').should == "<div><code erb-loud=\"\"> some_method </code></div>"
parsed.to_s.gsub(/\n/,'').should == "<div><erb erb-loud=\"\"> some_method </erb></div>"
else
parsed.to_s.gsub(/\n/,'').should == "<div><code erb-loud> some_method </code></div>"
parsed.to_s.gsub(/\n/,'').should == "<div><erb erb-loud> some_method </erb></div>"
end

@override.source_argument.should == :cut
Expand All @@ -260,7 +260,7 @@ module Deface
end

it "should return unescaped content for source document" do
@override = Deface::Override.new(:virtual_path => "posts/index", :name => "Posts#index", :insert_after => "h1", :cut => "code[erb-loud]:contains('some_method')")
@override = Deface::Override.new(:virtual_path => "posts/index", :name => "Posts#index", :insert_after => "h1", :cut => "erb[erb-loud]:contains('some_method')")
@override.stub(:parsed_document).and_return(parsed)
@override.source.should == "<%= some_method %>"
end
Expand All @@ -274,17 +274,17 @@ module Deface

before(:each) do
@override = Deface::Override.new(:virtual_path => "posts/index", :name => "Posts#index", :insert_after => "h1",
:cut => {:start => "code:contains('if true')", :end => "code:contains('end')"})
:cut => {:start => "erb:contains('if true')", :end => "erb:contains('end')"})

@override.stub(:parsed_document).and_return(parsed)
end

it "should remove cut element from original parsed source" do
@override.source
if RUBY_PLATFORM == 'java'
parsed.to_s.gsub(/\n/,'').should == "<h1>World</h1><code erb-loud=\"\"> hello </code>"
parsed.to_s.gsub(/\n/,'').should == "<h1>World</h1><erb erb-loud=\"\"> hello </erb>"
else
parsed.to_s.gsub(/\n/,'').should == "<h1>World</h1><code erb-loud> hello </code>"
parsed.to_s.gsub(/\n/,'').should == "<h1>World</h1><erb erb-loud> hello </erb>"
end

@override.source_argument.should == :cut
Expand Down Expand Up @@ -342,12 +342,12 @@ module Deface
@override.source_element.should be_an_instance_of Nokogiri::HTML::DocumentFragment

if RUBY_PLATFORM == 'java'
source = "<code erb-loud=\"\"> method :opt =&gt; 'x' &amp; 'y' </code>"
source = "<erb erb-loud=\"\"> method :opt =&gt; 'x' &amp; 'y' </erb>"
@override.source_element.to_s.should == source
#do it twice to ensure it doesn't change as it's destructive
@override.source_element.to_s.should == source
else
source = "<code erb-loud> method :opt =&gt; 'x' &amp; 'y' </code>"
source = "<erb erb-loud> method :opt =&gt; 'x' &amp; 'y' </erb>"
@override.source_element.to_s.should == source
#do it twice to ensure it doesn't change as it's destructive
@override.source_element.to_s.should == source
Expand Down Expand Up @@ -497,7 +497,7 @@ module Deface
Deface::Override.all.clear

@override = Deface::Override.new(:virtual_path => "posts/index", :name => "Posts#index", :replace => "h1", :text => "<h1>Argh!</h1>")
@second = Deface::Override.new(:virtual_path => "posts/index", :name => "second", :insert_after => "p", :text => "<pre>this is code?</pre>")
@second = Deface::Override.new(:virtual_path => "posts/index", :name => "second", :insert_after => "p", :text => "<pre>this is erb?</pre>")

@digest = Deface::Override.digest(:virtual_path => "posts/index")
end
Expand All @@ -513,7 +513,7 @@ module Deface
@override = Deface::Override.new(:virtual_path => "posts/index", :name => "Posts#index", :replace => "h1", :text => "<h1>Argh!</h1>")
Deface::Override.digest(:virtual_path => "posts/index").should == @digest

@second = Deface::Override.new(:virtual_path => "posts/index", :name => "2nd", :insert_after => "p", :text => "<pre>this is code?</pre>")
@second = Deface::Override.new(:virtual_path => "posts/index", :name => "2nd", :insert_after => "p", :text => "<pre>this is erb?</pre>")
Deface::Override.digest(:virtual_path => "posts/index").should_not == @digest
end

Expand Down
24 changes: 12 additions & 12 deletions spec/deface/parser_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -68,13 +68,13 @@ module Deface

it "should convert <% ... %>" do
tag = Deface::Parser.convert("<% method_name %>")
tag = tag.css('code').first
tag = tag.css('erb').first
tag.attributes['erb-silent'].value.should eq ''
end

it "should convert <%= ... %>" do
tag = Deface::Parser.convert("<%= method_name %>")
tag = tag.css('code').first
tag = tag.css('erb').first
tag.attributes['erb-loud'].value.should eq ''
end

Expand Down Expand Up @@ -129,22 +129,22 @@ module Deface
tag.text.should eq 'A Link'
end

it "should escape contents code tags" do
it "should escape contents erb tags" do
tag = Deface::Parser.convert("<% method_name :key => 'value' %>")
tag = tag.css('code').first
tag = tag.css('erb').first
tag.attributes.key?('erb-silent').should be_true
tag.text.should eq " method_name :key => 'value' "
end

it "should handle round brackets in code tags" do
it "should handle round brackets in erb tags" do
# commented out line below will fail as : adjacent to ( causes Nokogiri parser issue on jruby
tag = Deface::Parser.convert("<% method_name(:key => 'value') %>")
tag = tag.css('code').first
tag = tag.css('erb').first
tag.attributes.key?('erb-silent').should be_true
tag.text.should eq " method_name(:key => 'value') "

tag = Deface::Parser.convert("<% method_name( :key => 'value' ) %>")
tag = tag.css('code').first
tag = tag.css('erb').first
tag.attributes.key?('erb-silent').should be_true
tag.text.should eq " method_name( :key => 'value' ) "
end
Expand All @@ -169,12 +169,12 @@ module Deface
end

describe "#undo_erb_markup" do
it "should revert <code erb-silent>" do
Deface::Parser.undo_erb_markup!("<code erb-silent> method_name </code>").should == "<% method_name %>"
it "should revert <erb erb-silent>" do
Deface::Parser.undo_erb_markup!("<erb erb-silent> method_name </erb>").should == "<% method_name %>"
end

it "should revert <code erb-loud>" do
Deface::Parser.undo_erb_markup!("<code erb-loud> method_name </code>").should == "<%= method_name %>"
it "should revert <erb erb-loud>" do
Deface::Parser.undo_erb_markup!("<erb erb-loud> method_name </erb>").should == "<%= method_name %>"
end

it "should revert data-erb-x attrs inside html tag" do
Expand All @@ -195,7 +195,7 @@ module Deface
end
end

it "should unescape contents of code tags" do
it "should unescape contents of erb tags" do
Deface::Parser.undo_erb_markup!("<% method(:key =&gt; 'value' %>").should == "<% method(:key => 'value' %>"
Deface::Parser.undo_erb_markup!("<% method(:key =&gt; 'value'\n %>").should == "<% method(:key => 'value'\n %>"
end
Expand Down

1 comment on commit 415422f

@m3nd3s
Copy link

@m3nd3s m3nd3s commented on 415422f Sep 4, 2013

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice! Thank you!

Please sign in to comment.