deface 0.3.0 → 0.4.0
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.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
|