html_namespacing 0.1.5
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.rdoc +406 -0
- data/ext/html_namespacing/extconf.rb +6 -0
- data/ext/html_namespacing/html_namespacing.c +482 -0
- data/ext/html_namespacing/html_namespacing.h +35 -0
- data/ext/html_namespacing/html_namespacing_ext.c +97 -0
- data/lib/html_namespacing.rb +5 -0
- data/lib/html_namespacing/plugin.rb +10 -0
- data/lib/html_namespacing/plugin/dom_scan_jquery.js +44 -0
- data/lib/html_namespacing/plugin/dom_scan_jquery.js.compressed +1 -0
- data/lib/html_namespacing/plugin/rails.rb +134 -0
- data/lib/html_namespacing/plugin/sass.rb +76 -0
- data/spec/c_extension_spec.rb +55 -0
- data/spec/spec_helper.rb +4 -0
- metadata +74 -0
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
#ifndef HTML_NAMESPACING_H
|
|
2
|
+
#define HTML_NAMESPACING_H
|
|
3
|
+
|
|
4
|
+
#ifdef __cplusplus
|
|
5
|
+
extern "C" {
|
|
6
|
+
#endif
|
|
7
|
+
|
|
8
|
+
typedef struct _HtmlNamespacingAllocationStrategy {
|
|
9
|
+
void *(*malloc)(size_t size);
|
|
10
|
+
void (*free)(void *ptr);
|
|
11
|
+
void *(*realloc)(void *ptr, size_t size);
|
|
12
|
+
} HtmlNamespacingAllocationStrategy;
|
|
13
|
+
|
|
14
|
+
int
|
|
15
|
+
add_namespace_to_html_with_length(
|
|
16
|
+
const char *html,
|
|
17
|
+
size_t html_len,
|
|
18
|
+
const char *ns,
|
|
19
|
+
char **ret,
|
|
20
|
+
size_t *ret_len);
|
|
21
|
+
|
|
22
|
+
int
|
|
23
|
+
add_namespace_to_html_with_length_and_allocation_strategy(
|
|
24
|
+
const char *html,
|
|
25
|
+
size_t html_len,
|
|
26
|
+
const char *ns,
|
|
27
|
+
char **ret,
|
|
28
|
+
size_t *ret_len,
|
|
29
|
+
HtmlNamespacingAllocationStrategy allocation_strategy);
|
|
30
|
+
|
|
31
|
+
#ifdef __cplusplus
|
|
32
|
+
}
|
|
33
|
+
#endif
|
|
34
|
+
|
|
35
|
+
#endif /* HTML_NAMESPACING_H */
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
#include <errno.h>
|
|
2
|
+
|
|
3
|
+
#include "ruby.h"
|
|
4
|
+
|
|
5
|
+
#include "html_namespacing.h"
|
|
6
|
+
|
|
7
|
+
#include <stdio.h>
|
|
8
|
+
|
|
9
|
+
VALUE rb_mHtmlNamespacing = Qnil;
|
|
10
|
+
|
|
11
|
+
static const HtmlNamespacingAllocationStrategy ALLOCATION_STRATEGY = {
|
|
12
|
+
(void *(*)(size_t)) ruby_xmalloc,
|
|
13
|
+
ruby_xfree,
|
|
14
|
+
(void *(*)(void *, size_t)) ruby_xrealloc
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
/*
|
|
18
|
+
* call-seq:
|
|
19
|
+
* HtmlNamespacing.add_namespace_to_html(html, ns) => String
|
|
20
|
+
*
|
|
21
|
+
* Returns new HTML string based on +html+ with the HTML class +ns+ to root
|
|
22
|
+
* elements.
|
|
23
|
+
*
|
|
24
|
+
* If +html+ is nil, returns +nil+.
|
|
25
|
+
*
|
|
26
|
+
* If +ns+ is nil, returns +html+.
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
VALUE
|
|
30
|
+
html_namespacing_add_namespace_to_html(
|
|
31
|
+
VALUE obj,
|
|
32
|
+
VALUE html,
|
|
33
|
+
VALUE ns)
|
|
34
|
+
{
|
|
35
|
+
/*
|
|
36
|
+
* It's almost tempting to manually allocate the RString object to save
|
|
37
|
+
* ourselves the stupid extra copy. (add_namespace_to_html_with_length()
|
|
38
|
+
* implicitly copies the string, and here we are copying it again because
|
|
39
|
+
* Ruby can't convert from a char* to an RString? How lame....)
|
|
40
|
+
*
|
|
41
|
+
* But for now, let's just do the extra copy (implicit in rb_str_new2) and
|
|
42
|
+
* be done with it.
|
|
43
|
+
*/
|
|
44
|
+
|
|
45
|
+
const char *html_ptr;
|
|
46
|
+
size_t html_len;
|
|
47
|
+
const char *ns_ptr;
|
|
48
|
+
char *ret_ptr;
|
|
49
|
+
size_t ret_len;
|
|
50
|
+
int rv;
|
|
51
|
+
VALUE ret;
|
|
52
|
+
|
|
53
|
+
if (TYPE(html) == T_NIL) {
|
|
54
|
+
return Qnil;
|
|
55
|
+
}
|
|
56
|
+
Check_Type(html, T_STRING);
|
|
57
|
+
|
|
58
|
+
if (TYPE(ns) == T_NIL) {
|
|
59
|
+
return html;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
Check_Type(ns, T_STRING);
|
|
63
|
+
|
|
64
|
+
html_ptr = RSTRING_PTR(html);
|
|
65
|
+
html_len = RSTRING_LEN(html);
|
|
66
|
+
|
|
67
|
+
ns_ptr = RSTRING_PTR(ns);
|
|
68
|
+
|
|
69
|
+
rv = add_namespace_to_html_with_length_and_allocation_strategy(
|
|
70
|
+
html_ptr,
|
|
71
|
+
html_len,
|
|
72
|
+
ns_ptr,
|
|
73
|
+
&ret_ptr,
|
|
74
|
+
&ret_len,
|
|
75
|
+
ALLOCATION_STRATEGY);
|
|
76
|
+
if (rv == EINVAL) {
|
|
77
|
+
rb_raise(rb_eArgError, "Badly-formed HTML: %s", html_ptr);
|
|
78
|
+
}
|
|
79
|
+
if (rv != 0) {
|
|
80
|
+
rb_raise(rb_eRuntimeError, "Unknown error in add_namespace_to_html");
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
ret = rb_str_new(ret_ptr, ret_len);
|
|
84
|
+
ruby_xfree(ret_ptr);
|
|
85
|
+
|
|
86
|
+
return ret;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/*
|
|
90
|
+
* Holds functions related to HTML namespacing.
|
|
91
|
+
*/
|
|
92
|
+
void
|
|
93
|
+
Init_html_namespacing_ext()
|
|
94
|
+
{
|
|
95
|
+
rb_mHtmlNamespacing = rb_define_module("HtmlNamespacing");
|
|
96
|
+
rb_define_module_function(rb_mHtmlNamespacing, "add_namespace_to_html", html_namespacing_add_namespace_to_html, 2);
|
|
97
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
jQuery(function($) {
|
|
2
|
+
function NS_from_node(root_node) {
|
|
3
|
+
var SPLIT_REGEX = /[ \t\n]+/,
|
|
4
|
+
ret = {},
|
|
5
|
+
node_stack = [root_node],
|
|
6
|
+
cur_node,
|
|
7
|
+
class_name_list,
|
|
8
|
+
class_names,
|
|
9
|
+
class_name,
|
|
10
|
+
i,
|
|
11
|
+
j,
|
|
12
|
+
children,
|
|
13
|
+
subnode;
|
|
14
|
+
|
|
15
|
+
while (node_stack.length) {
|
|
16
|
+
cur_node = node_stack.pop();
|
|
17
|
+
|
|
18
|
+
// Populate entry in $.NS
|
|
19
|
+
class_name_list = cur_node.className;
|
|
20
|
+
if (class_name_list) {
|
|
21
|
+
class_names = class_name_list.split(SPLIT_REGEX);
|
|
22
|
+
for (i = 0; i < class_names.length; i++) {
|
|
23
|
+
class_name = class_names[i];
|
|
24
|
+
if (!ret[class_name]) {
|
|
25
|
+
ret[class_name] = [cur_node];
|
|
26
|
+
} else {
|
|
27
|
+
ret[class_name].push(cur_node);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// "recurse" to the children, so they are handled in document order
|
|
33
|
+
children = cur_node.childNodes;
|
|
34
|
+
for (var j = children.length - 1; j >= 0; j--) {
|
|
35
|
+
subnode = children[j];
|
|
36
|
+
node_stack.push(subnode);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return ret;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
$.NS = NS_from_node(document.getElementsByTagName('body')[0]);
|
|
44
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
jQuery(function(b){function a(f){var c=/[ \t\n]+/,m={},o=[f],n,l,p,h,k,g,e,d;while(o.length){n=o.pop();l=n.className;if(l){p=l.split(c);for(k=0;k<p.length;k++){h=p[k];if(!m[h]){m[h]=[n]}else{m[h].push(n)}}}e=n.childNodes;for(var g=e.length-1;g>=0;g--){d=e[g];o.push(d)}}return m}b.NS=a(document.getElementsByTagName("body")[0])});
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
begin
|
|
2
|
+
require 'glob_fu'
|
|
3
|
+
rescue LoadError
|
|
4
|
+
require 'rubygems'
|
|
5
|
+
require 'glob_fu'
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
module HtmlNamespacing
|
|
9
|
+
module Plugin
|
|
10
|
+
module Rails
|
|
11
|
+
def self.install(options = {})
|
|
12
|
+
@options = options
|
|
13
|
+
install_rails_2_3(options)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Called by ActionView
|
|
17
|
+
def self.path_to_namespace(relative_path)
|
|
18
|
+
if func = @options[:path_to_namespace_callback]
|
|
19
|
+
func.call(relative_path)
|
|
20
|
+
else
|
|
21
|
+
HtmlNamespacing::Plugin.default_relative_path_to_namespace(relative_path)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def self.handle_exception(e, template, view)
|
|
26
|
+
if func = @options[:handle_exception_callback]
|
|
27
|
+
func.call(e, template, view)
|
|
28
|
+
else
|
|
29
|
+
raise(e)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def self.javascript_root
|
|
34
|
+
@options[:javascript_root] || RAILS_ROOT + '/app/javascripts/views'
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def self.javascript_optional_suffix
|
|
38
|
+
@options[:javascript_optional_suffix]
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def self.template_formats
|
|
42
|
+
@formats ||= Set.new(@options[:template_formats] || ['html'])
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
module Helpers
|
|
46
|
+
def html_namespacing_javascript_tag(framework, options = {})
|
|
47
|
+
files = html_namespacing_files(options[:format])
|
|
48
|
+
root = Pathname.new(::HtmlNamespacing::Plugin::Rails.javascript_root)
|
|
49
|
+
|
|
50
|
+
unless files.empty?
|
|
51
|
+
r = "<script type=\"text/javascript\"><!--//--><![CDATA[//><!--\n"
|
|
52
|
+
r << HtmlNamespaceJs[framework][:top]
|
|
53
|
+
r << "\n"
|
|
54
|
+
files.collect do |path|
|
|
55
|
+
relative_path = Pathname.new(path).relative_path_from(root)
|
|
56
|
+
r << html_namespacing_inline_js(framework, relative_path.to_s, path)
|
|
57
|
+
r << "\n"
|
|
58
|
+
end
|
|
59
|
+
r << "//--><!]]></script>"
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
private
|
|
64
|
+
|
|
65
|
+
HtmlNamespaceJs = {
|
|
66
|
+
:jquery => {
|
|
67
|
+
:top => File.open(File.join(File.dirname(__FILE__), 'dom_scan_jquery.js.compressed')) { |f| f.read },
|
|
68
|
+
:each => 'jQuery(function($){var NS=%s,$NS=function(){return $($.NS[NS]||[])};%s});'
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
def html_namespacing_files(format)
|
|
73
|
+
(Array === format ? format : [format]).inject([]) do |r, f|
|
|
74
|
+
r.concat(GlobFu.find(
|
|
75
|
+
html_namespacing_rendered_paths,
|
|
76
|
+
:suffix => 'js',
|
|
77
|
+
:extra_suffix => f && f.to_s,
|
|
78
|
+
:optional_suffix => ::HtmlNamespacing::Plugin::Rails.javascript_optional_suffix,
|
|
79
|
+
:root => ::HtmlNamespacing::Plugin::Rails.javascript_root
|
|
80
|
+
))
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def html_namespacing_inline_js(framework, relative_path, absolute_path)
|
|
85
|
+
namespace = ::HtmlNamespacing::Plugin::Rails.path_to_namespace(relative_path.sub(/\..*$/, ''))
|
|
86
|
+
content = File.open(absolute_path) { |f| f.read }
|
|
87
|
+
|
|
88
|
+
HtmlNamespaceJs[framework][:each] % [namespace.to_json, content]
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
private
|
|
93
|
+
|
|
94
|
+
def self.install_rails_2_3(options = {})
|
|
95
|
+
if options[:javascript]
|
|
96
|
+
::ActionView::Base.class_eval do
|
|
97
|
+
attr_writer(:html_namespacing_rendered_paths)
|
|
98
|
+
def html_namespacing_rendered_paths
|
|
99
|
+
@html_namespacing_rendered_paths ||= []
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
::ActionView::Template.class_eval do
|
|
105
|
+
def render_with_html_namespacing(view, local_assigns = {})
|
|
106
|
+
html = render_without_html_namespacing(view, local_assigns)
|
|
107
|
+
|
|
108
|
+
view.html_namespacing_rendered_paths << path_without_format_and_extension if view.respond_to?(:html_namespacing_rendered_paths)
|
|
109
|
+
|
|
110
|
+
if HtmlNamespacing::Plugin::Rails.template_formats.include?(format)
|
|
111
|
+
add_namespace_to_html(html, view)
|
|
112
|
+
else
|
|
113
|
+
html
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
alias_method_chain :render, :html_namespacing
|
|
117
|
+
|
|
118
|
+
private
|
|
119
|
+
|
|
120
|
+
def add_namespace_to_html(html, view)
|
|
121
|
+
HtmlNamespacing::add_namespace_to_html(html, html_namespace)
|
|
122
|
+
rescue ArgumentError => e
|
|
123
|
+
HtmlNamespacing::Plugin::Rails.handle_exception(e, self, view)
|
|
124
|
+
html # unless handle_exception() raised something
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def html_namespace
|
|
128
|
+
HtmlNamespacing::Plugin::Rails.path_to_namespace(path_without_format_and_extension)
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
end
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
module HtmlNamespacing
|
|
2
|
+
module Plugin
|
|
3
|
+
module Sass
|
|
4
|
+
def self.install(options = {})
|
|
5
|
+
options[:prefix] ||= 'views'
|
|
6
|
+
options[:callback] ||= lambda { |p| HtmlNamespacing::Plugin.default_relative_path_to_namespace(p) }
|
|
7
|
+
Sass_2_2.install(options)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
module Sass_2_2
|
|
11
|
+
def self.install(options = {})
|
|
12
|
+
self.allow_updating_partials
|
|
13
|
+
self.add_super_rule_to_tree_node(options)
|
|
14
|
+
self.try_to_enable_memoization
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
private
|
|
18
|
+
|
|
19
|
+
def self.allow_updating_partials
|
|
20
|
+
::Sass::Plugin.module_eval do
|
|
21
|
+
private
|
|
22
|
+
|
|
23
|
+
# Though a bit over-zealous, who *cares* if we render partial
|
|
24
|
+
# Sass files?
|
|
25
|
+
def forbid_update?(*args)
|
|
26
|
+
false
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def self.add_super_rule_to_tree_node(namespacing_options)
|
|
32
|
+
::Sass::Tree::RuleNode.class_eval do
|
|
33
|
+
def to_s_with_namespacing(tabs, super_rules = nil)
|
|
34
|
+
super_rules ||= namespacing_rules
|
|
35
|
+
to_s_without_namespacing(tabs, super_rules)
|
|
36
|
+
end
|
|
37
|
+
alias_method_chain(:to_s, :namespacing)
|
|
38
|
+
|
|
39
|
+
private
|
|
40
|
+
|
|
41
|
+
define_method(:namespacing_prefix) do
|
|
42
|
+
namespacing_options[:prefix]
|
|
43
|
+
end
|
|
44
|
+
define_method(:namespacing_callback) do
|
|
45
|
+
namespacing_options[:callback]
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def namespacing_regex
|
|
49
|
+
/^#{Regexp.quote(options[:css_location])}\/#{Regexp.quote(namespacing_prefix)}\/(.*)\.css$/
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def namespace
|
|
53
|
+
@namespace ||= if options[:css_filename] =~ namespacing_regex
|
|
54
|
+
namespacing_callback.call($1.split('.')[0])
|
|
55
|
+
end
|
|
56
|
+
@namespace
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def namespacing_rules
|
|
60
|
+
namespace && [ ".#{namespace}" ]
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def self.try_to_enable_memoization
|
|
66
|
+
::Sass::Tree::RuleNode.class_eval do
|
|
67
|
+
extend ActiveSupport::Memoizable
|
|
68
|
+
memoize :namespacing_rules
|
|
69
|
+
end
|
|
70
|
+
rescue NameError
|
|
71
|
+
# ActiveSupport isn't loaded
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
|
4
|
+
|
|
5
|
+
describe(HtmlNamespacing) do
|
|
6
|
+
private
|
|
7
|
+
|
|
8
|
+
def self.define_test(name, html, ns, expect)
|
|
9
|
+
it("should work with #{name}") do
|
|
10
|
+
f(html, ns).should == expect
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def self.define_failing_test(name, html)
|
|
15
|
+
it("should fail on #{name}") do
|
|
16
|
+
lambda { f(html, 'X') }.should raise_error(ArgumentError)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def f(html, ns)
|
|
21
|
+
HtmlNamespacing::add_namespace_to_html(html, ns)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
self.define_test('nil HTML', nil, 'X', nil)
|
|
25
|
+
self.define_test('nil namespace', '<div>hello</div>', nil, '<div>hello</div>')
|
|
26
|
+
self.define_test('nil everything', nil, nil, nil)
|
|
27
|
+
self.define_test('plain text', 'hello', 'X', 'hello')
|
|
28
|
+
self.define_test('regular tag', '<div>hello</div>', 'X', '<div class="X">hello</div>')
|
|
29
|
+
self.define_test('empty tag', '<div/>', 'X', '<div class="X"/>')
|
|
30
|
+
self.define_test('empty tag with " />"', '<div />', 'X', '<div class="X" />')
|
|
31
|
+
self.define_test('empty tag with " />" and class', '<div class="A" />', 'X', '<div class="A X" />')
|
|
32
|
+
self.define_test('nested tag', '<div><div>hello</div></div>', 'X', '<div class="X"><div>hello</div></div>')
|
|
33
|
+
self.define_test('two tags', '<div>hello</div><div>goodbye</div>', 'X', '<div class="X">hello</div><div class="X">goodbye</div>')
|
|
34
|
+
self.define_test('existing class= tag with double-quotes', '<div class="foo">bar</div>', 'baz', '<div class="foo baz">bar</div>')
|
|
35
|
+
self.define_test('existing class= tag with single-quotes', "<div class='foo'>bar</div>", 'baz', "<div class='foo baz'>bar</div>")
|
|
36
|
+
self.define_test('other attributes are ignored', '<div id="id" class="foo" style="display:none;">bar</div>', 'baz', '<div id="id" class="foo baz" style="display:none;">bar</div>')
|
|
37
|
+
self.define_test('works with utf-8', '<div class="𝞪">𝟂</div>', '𝞺', '<div class="𝞪 𝞺">𝟂</div>')
|
|
38
|
+
self.define_test('empty tag with existing class=', '<span class="foo"/>', 'bar', '<span class="foo bar"/>')
|
|
39
|
+
self.define_test('works with newlines in tag', "<div\n\nclass\n\n=\n\n'foo'\n\n>bar</div>", 'baz', "<div\n\nclass\n\n=\n\n'foo baz'\n\n>bar</div>")
|
|
40
|
+
self.define_test('works with "\'" within \'"\' attributes', '<div title="Adam\'s House" class="foo">bar</div>', 'baz', '<div title="Adam\'s House" class="foo baz">bar</div>')
|
|
41
|
+
self.define_test('ignores XML prolog', '<?xml version="1.0"?><div>foo</div>', 'X', '<?xml version="1.0"?><div class="X">foo</div>')
|
|
42
|
+
self.define_test('ignores DOCTYPE', '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><div>foo</div>', 'X', '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><div class="X">foo</div>')
|
|
43
|
+
self.define_test('ignores CDATA', '<![CDATA[ignore <div class="foo">]] </div>]]><div>foo</div>', 'X', '<![CDATA[ignore <div class="foo">]] </div>]]><div class="X">foo</div>')
|
|
44
|
+
self.define_test('ignores comments', '<!-- blah <div class="foo">foo</div> - <span/>--><div>foo</div>', 'X', '<!-- blah <div class="foo">foo</div> - <span/>--><div class="X">foo</div>')
|
|
45
|
+
self.define_test('detects CDATA end delimiter correctly', '<![CDATA[ ]>< ]]>', 'X', '<![CDATA[ ]>< ]]>')
|
|
46
|
+
self.define_test('detects comment end delimiter correctly', '<!-- ->< -->', 'X', '<!-- ->< -->')
|
|
47
|
+
|
|
48
|
+
[ 'html', 'head', 'base', 'meta', 'title', 'link', 'script', 'noscript', 'style' ].each do |tag|
|
|
49
|
+
self.define_test("ignores <#{tag}> tags", "<#{tag}>foo</#{tag}>", "X", "<#{tag}>foo</#{tag}>")
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
self.define_failing_test('unclosed tag', '<div>foo')
|
|
53
|
+
self.define_failing_test('closing tag', 'foo</div>')
|
|
54
|
+
self.define_failing_test('wrong attr syntax', '<div foo=bar>foo</div>')
|
|
55
|
+
end
|