deface 0.3.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.markdown +50 -17
- data/deface.gemspec +2 -2
- data/lib/deface/parser.rb +40 -9
- data/spec/deface/parser_spec.rb +32 -15
- metadata +7 -7
data/README.markdown
CHANGED
@@ -3,25 +3,12 @@ Deface
|
|
3
3
|
|
4
4
|
Deface is a library that allows you to customize ERB views in a Rails application without editing the underlying view.
|
5
5
|
|
6
|
-
It allows you to easily target html & erb elements as the hooks for customization using
|
6
|
+
It allows you to easily target html & erb elements as the hooks for customization using CSS selectors as supported by Nokogiri.
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
becomes
|
13
|
-
|
14
|
-
<code erb-loud> some ruby code </code>
|
15
|
-
|
16
|
-
and
|
17
|
-
|
18
|
-
<% other ruby code %>
|
19
|
-
|
20
|
-
becomes
|
21
|
-
|
22
|
-
<code erb-silent> other ruby code </code>
|
8
|
+
Demo & Testing
|
9
|
+
---------------
|
10
|
+
You can play with Deface and see it's parsing in action at [deface.heroku.com](http://deface.heroku.com)
|
23
11
|
|
24
|
-
Deface overrides have full access to all variables accessible to the view being customized.
|
25
12
|
|
26
13
|
Deface::Override
|
27
14
|
=======
|
@@ -42,6 +29,10 @@ Action
|
|
42
29
|
|
43
30
|
* <tt>:insert_before</tt> - Inserts before all elements that match the supplied selector
|
44
31
|
|
32
|
+
* <tt>:insert_top</tt> - Inserts inside all elements that match the supplied selector, as the first child.
|
33
|
+
|
34
|
+
* <tt>:insert_bottom</tt> - Inserts inside all elements that match the supplied selector, as the last child.
|
35
|
+
|
45
36
|
Source
|
46
37
|
------
|
47
38
|
* <tt>:text</tt> - String containing markup
|
@@ -83,3 +74,45 @@ Removes any instance of `<%= helper_method %>` in the `posts/new.html.erb" templ
|
|
83
74
|
Deface::Override.new(:virtual_path => "posts/new",
|
84
75
|
:name => "example-4",
|
85
76
|
:remove => "code[erb-loud]:contains('helper_method')" )
|
77
|
+
|
78
|
+
|
79
|
+
Implementation
|
80
|
+
==============
|
81
|
+
|
82
|
+
Deface temporarily converts ERB files into a pseudo HTML markup that can be parsed and queired by Nokogiri, using the following approach:
|
83
|
+
|
84
|
+
<%= some ruby code %>
|
85
|
+
|
86
|
+
becomes
|
87
|
+
|
88
|
+
<code erb-loud> some ruby code </code>
|
89
|
+
|
90
|
+
and
|
91
|
+
|
92
|
+
<% other ruby code %>
|
93
|
+
|
94
|
+
becomes
|
95
|
+
|
96
|
+
<code erb-silent> other ruby code </code>
|
97
|
+
|
98
|
+
ERB that is contained inside a HTML tag definition is converted slightly differently to ensure a valid HTML document that Nokogiri can parse:
|
99
|
+
|
100
|
+
<p id="<%= dom_id @product %>" <%= "style='display:block';" %>>
|
101
|
+
|
102
|
+
becomes
|
103
|
+
|
104
|
+
<p data-erb-id="<%= dom_id @product %>" data-erb-0="<%= "style='display:block';" %>">
|
105
|
+
|
106
|
+
Deface overrides have full access to all variables accessible to the view being customized.
|
107
|
+
|
108
|
+
Caveats
|
109
|
+
======
|
110
|
+
|
111
|
+
Due to the use of the Nokogiri library for parsing HTML / view files you need to ensure that your layout views include doctype, html, head and body tags in a single file, as Nokogiri will create such elements if it detects any of these tags have been incorrectly nested.
|
112
|
+
|
113
|
+
Parsing will fail and result in invalid output if ERB blocks are responsible for closing a HTML tag what was opened normally, i.e. don't do this:
|
114
|
+
|
115
|
+
|
116
|
+
<div <%= ">" %>
|
117
|
+
|
118
|
+
|
data/deface.gemspec
CHANGED
@@ -5,7 +5,7 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{deface}
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.4.0"
|
9
9
|
|
10
10
|
s.authors = ["Brian Quinn"]
|
11
11
|
s.description = %q{Deface is a library that allows you to customize ERB views in a Rails application without editing the underlying view.}
|
@@ -15,7 +15,7 @@ Gem::Specification.new do |s|
|
|
15
15
|
]
|
16
16
|
s.files = `git ls-files`.split("\n")
|
17
17
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
-
s.homepage = %q{http://github.com/
|
18
|
+
s.homepage = %q{http://github.com/railsdog/deface}
|
19
19
|
s.rdoc_options = ["--charset=UTF-8"]
|
20
20
|
s.require_paths = ["lib"]
|
21
21
|
s.summary = %q{Deface is a library that allows you to customize ERB views in Rails}
|
data/lib/deface/parser.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
require 'nokogiri'
|
2
|
-
require 'erubis'
|
3
2
|
require 'cgi'
|
4
3
|
|
5
4
|
module Deface
|
@@ -7,6 +6,35 @@ module Deface
|
|
7
6
|
# converts erb to markup
|
8
7
|
#
|
9
8
|
def self.erb_markup!(source)
|
9
|
+
|
10
|
+
#all opening html tags that contain <% %> blocks
|
11
|
+
source.scan(/<\w+[^<>]+(?:<%.*?%>[^<>]*)+/m).each do |line|
|
12
|
+
|
13
|
+
#regexs to catch <% %> inside attributes id="<% something %>" - with double, single or no quotes
|
14
|
+
erb_attrs_regexs = [/([\w-]+)(\s?=\s?)(")([^"]*<%.*?%>[^"]*)/m,
|
15
|
+
/([\w-]+)(\s?=\s?)(')([^']*<%.*?%>[^']*)'/m,
|
16
|
+
/([\w-]+)(\s?=\s?)()(<%.*?%>)(?:\s|>|\z)/m]
|
17
|
+
|
18
|
+
replace_line = erb_attrs_regexs.inject(line.clone) do |replace_line, regex|
|
19
|
+
|
20
|
+
replace_line = line.scan(regex).inject(replace_line) do |replace_line, match|
|
21
|
+
replace_line.sub("#{match[0]}#{match[1]}#{match[2]}#{match[3]}#{match[2]}") { |m| m = " data-erb-#{match[0]}=\"#{CGI.escapeHTML(match[3])}\"" }
|
22
|
+
end
|
23
|
+
|
24
|
+
replace_line
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
i = -1
|
29
|
+
#catch all <% %> inside tags id <p <%= test %>> , not inside attrs
|
30
|
+
replace_line.scan(/(<%.*?%>)/m).each do |match|
|
31
|
+
replace_line.sub!(match[0]) { |m| m = " data-erb-#{i += 1}=\"#{CGI.escapeHTML(match[0])}\"" }
|
32
|
+
end
|
33
|
+
|
34
|
+
source.sub!(line) { |m| m = replace_line }
|
35
|
+
end
|
36
|
+
|
37
|
+
#replaces all <% %> not inside opening html tags
|
10
38
|
replacements = [ {"<%=" => "<code erb-loud>"},
|
11
39
|
{"<%" => "<code erb-silent>"},
|
12
40
|
{"%>" => "</code>"} ]
|
@@ -14,7 +42,7 @@ module Deface
|
|
14
42
|
replacements.each{ |h| h.each { |replace, with| source.gsub! replace, with } }
|
15
43
|
|
16
44
|
source.scan(/(<code.*?>)((?:(?!<\/code>)[\s\S])*)(<\/code>)/).each do |match|
|
17
|
-
source.
|
45
|
+
source.sub!("#{match[0]}#{match[1]}#{match[2]}") { |m| m = "#{match[0]}#{CGI.escapeHTML(match[1])}#{match[2]}" }
|
18
46
|
end
|
19
47
|
|
20
48
|
source
|
@@ -25,18 +53,21 @@ module Deface
|
|
25
53
|
def self.undo_erb_markup!(source)
|
26
54
|
replacements = [ {"<code erb-silent>" => '<%'},
|
27
55
|
{"<code erb-loud>" => '<%='},
|
28
|
-
{"</code>" => '%>'}
|
29
|
-
{/(<|<)code(\s|%20)erb-silent(>|>)/ => '<%'},
|
30
|
-
{/(<|<)code(\s|%20)erb-loud(>|>)/ => '<%='},
|
31
|
-
{/(<|<)\/code(>|>)/ => '%>'} ]
|
56
|
+
{"</code>" => '%>'}]
|
32
57
|
|
33
58
|
replacements.each{ |h| h.each { |replace, with| source.gsub! replace, with } }
|
34
59
|
|
60
|
+
source.scan(/data-erb-(\d+)+=(['"])(.*?)\2/m).each do |match|
|
61
|
+
source.gsub!("data-erb-#{match[0]}=#{match[1]}#{match[2]}#{match[1]}") { |m| m = CGI.unescapeHTML(match[2]) }
|
62
|
+
end
|
63
|
+
|
64
|
+
source.scan(/data-erb-([\w-]+)+=(["'])(.*?)\2/m).each do |match|
|
65
|
+
source.gsub!("data-erb-#{match[0]}=#{match[1]}#{match[2]}#{match[1]}") { |m| "#{match[0]}=#{match[1]}#{CGI.unescapeHTML(match[2])}#{match[1]}" }
|
66
|
+
end
|
67
|
+
|
35
68
|
#un-escape changes from Nokogiri and erb-markup!
|
36
69
|
source.scan(/(<%.*?)((?:(?!%>)[\s\S])*)(%>)/).each do |match|
|
37
|
-
|
38
|
-
escaped = CGI.unescapeHTML CGI.unescapeHTML(escaped)
|
39
|
-
source.gsub!("#{match[0]}#{match[1]}#{match[2]}", "#{match[0]}#{escaped}#{match[2]}")
|
70
|
+
source.gsub!("#{match[0]}#{match[1]}#{match[2]}") { |m| m = "#{match[0]}#{ CGI.unescapeHTML match[1] }#{match[2]}" }
|
40
71
|
end
|
41
72
|
|
42
73
|
source
|
data/spec/deface/parser_spec.rb
CHANGED
@@ -37,12 +37,34 @@ module Deface
|
|
37
37
|
Deface::Parser.convert("<%= method_name %>").to_s.should == "<code erb-loud> method_name </code>"
|
38
38
|
end
|
39
39
|
|
40
|
-
it "should convert
|
41
|
-
Deface::Parser.convert("<p
|
40
|
+
it "should convert first <% ... %> inside html tag" do
|
41
|
+
Deface::Parser.convert("<p <% method_name %>></p>").to_s.should == "<p data-erb-0=\"<% method_name %>\"></p>"
|
42
42
|
end
|
43
43
|
|
44
|
-
it "should convert
|
45
|
-
Deface::Parser.convert(
|
44
|
+
it "should convert second <% ... %> inside html tag" do
|
45
|
+
Deface::Parser.convert("<p <% method_name %> <% x = y %>></p>").to_s.should == "<p data-erb-0=\"<% method_name %>\" data-erb-1=\"<% x = y %>\"></p>"
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should convert <% ... %> inside double quoted attr value" do
|
49
|
+
Deface::Parser.convert("<p id=\"<% method_name %>\"></p>").to_s.should == "<p data-erb-id=\"<% method_name %>\"></p>"
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should convert <% ... %> inside single quoted attr value" do
|
53
|
+
Deface::Parser.convert("<p id='<% method_name %>'></p>").to_s.should == "<p data-erb-id=\"<% method_name %>\"></p>"
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should convert <% ... %> inside non-quoted attr value" do
|
57
|
+
Deface::Parser.convert("<p id=<% method_name %>></p>").to_s.should == "<p data-erb-id=\"<% method_name %>\"></p>"
|
58
|
+
Deface::Parser.convert("<p id=<% method_name %> alt=\"test\"></p>").to_s.should == "<p data-erb-id=\"<% method_name %>\" alt=\"test\"></p>"
|
59
|
+
end
|
60
|
+
|
61
|
+
it "should convert multiple <% ... %> inside html tag" do
|
62
|
+
Deface::Parser.convert(%q{<p <%= method_name %> alt="<% x = 'y' +
|
63
|
+
\"2\" %>" title='<% method_name %>' <%= other_method %></p>}).to_s.should == "<p data-erb-0=\"<%= method_name %>\" data-erb-alt=\"<% x = 'y' + \n \\"2\\" %>\" data-erb-title=\"<% method_name %>\" data-erb-1=\"<%= other_method %>\"></p>"
|
64
|
+
end
|
65
|
+
|
66
|
+
it "should convert <%= ... %> including href attribute" do
|
67
|
+
Deface::Parser.convert(%(<a href="<%= x 'y' + "z" %>">A Link</a>)).to_s.should == "<a data-erb-href=\"<%= x 'y' + "z" %>\">A Link</a>"
|
46
68
|
end
|
47
69
|
|
48
70
|
it "should escape contents code tags" do
|
@@ -59,21 +81,16 @@ module Deface
|
|
59
81
|
Deface::Parser.undo_erb_markup!("<code erb-loud> method_name </code>").should == "<%= method_name %>"
|
60
82
|
end
|
61
83
|
|
62
|
-
it "should revert
|
63
|
-
Deface::Parser.undo_erb_markup!("<p
|
64
|
-
end
|
65
|
-
|
66
|
-
it "should revert nested <code erb-silent> including href attribute" do
|
67
|
-
Deface::Parser.undo_erb_markup!("<a href=\"<code%20erb-silent>%20method_name%20</code>\">A Link</a>").should == "<a href=\"<% method_name %>\">A Link</a>"
|
84
|
+
it "should revert data-erb-x attrs inside html tag" do
|
85
|
+
Deface::Parser.undo_erb_markup!("<p data-erb-0=\"<% method_name %>\" data-erb-1=\"<% x = y %>\"></p>").should == "<p <% method_name %> <% x = y %>></p>"
|
68
86
|
end
|
69
87
|
|
70
|
-
it "should revert
|
71
|
-
Deface::Parser.undo_erb_markup!("<p id=\"<
|
88
|
+
it "should revert data-erb-id attr inside html tag" do
|
89
|
+
Deface::Parser.undo_erb_markup!("<p data-erb-id=\"<% method_name > 1 %>\"></p>").should == "<p id=\"<% method_name > 1 %>\"></p>"
|
72
90
|
end
|
73
91
|
|
74
|
-
it "should revert
|
75
|
-
Deface::Parser.undo_erb_markup!("<a href=\"<
|
76
|
-
Deface::Parser.undo_erb_markup!("<a href=\"<code%20erb-loud>%20x%20'y'%20+%20%22z%22%20</code>\">A Link</a>").should == %(<a href="<%= x 'y' + "z" %>">A Link</a>)
|
92
|
+
it "should revert data-erb-href attr inside html tag" do
|
93
|
+
Deface::Parser.undo_erb_markup!("<a data-erb-href=\"<%= x 'y' + "z" %>\">A Link</a>").should == %(<a href="<%= x 'y' + \"z\" %>">A Link</a>)
|
77
94
|
end
|
78
95
|
|
79
96
|
it "should unescape contents of code tags" do
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: deface
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
5
|
-
prerelease:
|
4
|
+
hash: 15
|
5
|
+
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
8
|
+
- 4
|
9
9
|
- 0
|
10
|
-
version: 0.
|
10
|
+
version: 0.4.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Brian Quinn
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-
|
18
|
+
date: 2011-05-24 00:00:00 +01:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -80,7 +80,7 @@ files:
|
|
80
80
|
- spec/deface/template_spec.rb
|
81
81
|
- spec/spec_helper.rb
|
82
82
|
has_rdoc: true
|
83
|
-
homepage: http://github.com/
|
83
|
+
homepage: http://github.com/railsdog/deface
|
84
84
|
licenses: []
|
85
85
|
|
86
86
|
post_install_message:
|
@@ -109,7 +109,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
109
109
|
requirements: []
|
110
110
|
|
111
111
|
rubyforge_project:
|
112
|
-
rubygems_version: 1.
|
112
|
+
rubygems_version: 1.3.7
|
113
113
|
signing_key:
|
114
114
|
specification_version: 3
|
115
115
|
summary: Deface is a library that allows you to customize ERB views in Rails
|