fast_xs 0.2
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/CHANGELOG +8 -0
- data/COPYING +22 -0
- data/README +18 -0
- data/Rakefile +119 -0
- data/ext/fast_xs/extconf.rb +4 -0
- data/ext/fast_xs/fast_xs.c +279 -0
- data/lib/fast_xs_monkey_patcher.rb +32 -0
- data/test/test_cgi_class_overrides.rb +35 -0
- data/test/test_erb_util_module_overrides.rb +29 -0
- data/test/test_xml_escaping.rb +39 -0
- metadata +70 -0
data/CHANGELOG
ADDED
data/COPYING
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2007 Eric Wong <normalperson@yhbt.net>
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person
|
4
|
+
obtaining a copy of this software and associated documentation
|
5
|
+
files (the "Software"), to deal in the Software without
|
6
|
+
restriction, including without limitation the rights to use,
|
7
|
+
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
8
|
+
copies of the Software, and to permit persons to whom the
|
9
|
+
Software is furnished to do so, subject to the following
|
10
|
+
conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be
|
13
|
+
included in all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
17
|
+
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
19
|
+
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
20
|
+
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
21
|
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
22
|
+
OTHER DEALINGS IN THE SOFTWARE.
|
data/README
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
= fast_xs, a fast C extension for cleaning XML
|
2
|
+
|
3
|
+
== Overview
|
4
|
+
|
5
|
+
The original fast_xs method is based on the xchar code by Sam Ruby:
|
6
|
+
|
7
|
+
http://intertwingly.net/stories/2005/09/28/xchar.rb
|
8
|
+
http://intertwingly.net/blog/2005/09/28/XML-Cleansing
|
9
|
+
|
10
|
+
_why also packages a slightly modified version in the latest version
|
11
|
+
of Hpricot (not-yet-released) that also escapes '"' to """ (which
|
12
|
+
is optional).
|
13
|
+
|
14
|
+
This is an exact translation (to the best of my knowledge :) of Sam's
|
15
|
+
original implementation, so it does not escape """. The version
|
16
|
+
of XML::Builder packaged with Rails also uses Sam's version, and
|
17
|
+
XML::Builder as packaged in Rails 2.0 will be automatically use
|
18
|
+
fast_xs if available.
|
data/Rakefile
ADDED
@@ -0,0 +1,119 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/clean'
|
3
|
+
require 'rake/gempackagetask'
|
4
|
+
require 'rake/rdoctask'
|
5
|
+
require 'rake/testtask'
|
6
|
+
require 'hoe'
|
7
|
+
require 'fileutils'
|
8
|
+
include FileUtils
|
9
|
+
|
10
|
+
name = "fast_xs"
|
11
|
+
rev = `git describe 2>/dev/null`.chomp rescue nil
|
12
|
+
version = ENV['VERSION'] || "0.2" + (rev && rev.length > 0 ? "-#{rev}" : "")
|
13
|
+
pkg = "#{name}-#{version}"
|
14
|
+
bin = "*.{so,o}"
|
15
|
+
archlib = "lib/#{::Config::CONFIG['arch']}"
|
16
|
+
CLEAN.include ["ext/fast_xs/#{bin}", "lib/**/#{bin}",
|
17
|
+
'ext/fast_xs/Makefile', '**/.*.sw?', '*.gem', '.config']
|
18
|
+
rdoc_opts = ['--quiet', '--title', 'fast_xs notes', '--main', 'README',
|
19
|
+
'--inline-source']
|
20
|
+
pkg_files = %w(CHANGELOG COPYING README Rakefile) +
|
21
|
+
Dir.glob("{test,lib}/**/*.rb") +
|
22
|
+
Dir.glob("ext/**/*.{c,rb}")
|
23
|
+
|
24
|
+
|
25
|
+
spec = Gem::Specification.new do |s|
|
26
|
+
s.name = name
|
27
|
+
s.version = version
|
28
|
+
s.platform = Gem::Platform::RUBY
|
29
|
+
s.has_rdoc = true
|
30
|
+
s.rdoc_options += rdoc_opts
|
31
|
+
s.extra_rdoc_files = ["README", "CHANGELOG", "COPYING"]
|
32
|
+
s.summary = "escape faster!"
|
33
|
+
s.description = s.summary
|
34
|
+
s.author = "Eric Wong"
|
35
|
+
s.email = 'normalperson@yhbt.net'
|
36
|
+
s.homepage = 'http://bogonips.org/fast_xs/'
|
37
|
+
s.files = pkg_files
|
38
|
+
s.require_paths = [archlib, "lib"]
|
39
|
+
s.extensions = FileList["ext/**/extconf.rb"].to_a
|
40
|
+
end
|
41
|
+
|
42
|
+
hoe = Hoe.new(name, version) do |p|
|
43
|
+
p.author = spec.author
|
44
|
+
p.description = spec.description
|
45
|
+
p.email = spec.email
|
46
|
+
p.summary = spec.summary
|
47
|
+
p.url = spec.homepage
|
48
|
+
p.rubyforge_name = 'fast-xs'
|
49
|
+
end
|
50
|
+
|
51
|
+
desc "Does a full compile, test run"
|
52
|
+
task :default => [:compile, :test]
|
53
|
+
|
54
|
+
desc "Run all the tests"
|
55
|
+
Rake::TestTask.new do |t|
|
56
|
+
t.libs << "test" << archlib
|
57
|
+
t.test_files = FileList['test/test_*.rb']
|
58
|
+
t.verbose = true
|
59
|
+
end
|
60
|
+
|
61
|
+
Rake::RDocTask.new do |rdoc|
|
62
|
+
rdoc.rdoc_dir = 'doc/rdoc'
|
63
|
+
rdoc.options += rdoc_opts
|
64
|
+
rdoc.main = "README"
|
65
|
+
rdoc.rdoc_files.add ['README', 'CHANGELOG', 'COPYING' ]
|
66
|
+
end
|
67
|
+
|
68
|
+
Rake::GemPackageTask.new(spec) do |p|
|
69
|
+
p.need_tar = true
|
70
|
+
p.gem_spec = spec
|
71
|
+
end
|
72
|
+
|
73
|
+
['fast_xs'].each do |extension|
|
74
|
+
ext = "ext/#{extension}"
|
75
|
+
ext_so = "#{ext}/#{extension}.#{Config::CONFIG['DLEXT']}"
|
76
|
+
ext_files = FileList[
|
77
|
+
"#{ext}/*.c",
|
78
|
+
"#{ext}/*.h",
|
79
|
+
"#{ext}/*.rl",
|
80
|
+
"#{ext}/extconf.rb",
|
81
|
+
"#{ext}/Makefile",
|
82
|
+
"lib"
|
83
|
+
]
|
84
|
+
|
85
|
+
desc "Builds just the #{extension} extension"
|
86
|
+
task extension.to_sym => ["#{ext}/Makefile", ext_so ]
|
87
|
+
|
88
|
+
file "#{ext}/Makefile" => ["#{ext}/extconf.rb"] do
|
89
|
+
Dir.chdir(ext) do ruby "extconf.rb" end
|
90
|
+
end
|
91
|
+
|
92
|
+
file ext_so => ext_files do
|
93
|
+
Dir.chdir(ext) do sh('make') end
|
94
|
+
mkdir_p archlib
|
95
|
+
chmod 0644, ext_so
|
96
|
+
cp ext_so, archlib
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
task "lib" do
|
101
|
+
directory "lib"
|
102
|
+
end
|
103
|
+
|
104
|
+
desc "Compiles the Ruby extension"
|
105
|
+
task :compile => [:fast_xs] do
|
106
|
+
if Dir.glob(File.join(archlib,"fast_xs.*")).empty?
|
107
|
+
STDERR.puts 'Gem failed to build'
|
108
|
+
exit(1)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
task :install do
|
113
|
+
sh %{rake package}
|
114
|
+
sh %{sudo gem install pkg/#{name}-#{version}}
|
115
|
+
end
|
116
|
+
|
117
|
+
task :uninstall => [:clean] do
|
118
|
+
sh %{sudo gem uninstall #{name}}
|
119
|
+
end
|
@@ -0,0 +1,279 @@
|
|
1
|
+
#define VERSION "0.1"
|
2
|
+
|
3
|
+
#include <ruby.h>
|
4
|
+
#include <assert.h>
|
5
|
+
|
6
|
+
static ID unpack_id;
|
7
|
+
static VALUE U_fmt, C_fmt;
|
8
|
+
|
9
|
+
/* give GCC hints for better branch prediction
|
10
|
+
* (we layout branches so that ASCII characters are handled faster) */
|
11
|
+
#if defined(__GNUC__) && (__GNUC__ >= 3)
|
12
|
+
# define likely(x) __builtin_expect (!!(x), 1)
|
13
|
+
# define unlikely(x) __builtin_expect (!!(x), 0)
|
14
|
+
#else
|
15
|
+
# define unlikely(x) (x)
|
16
|
+
# define likely(x) (x)
|
17
|
+
#endif
|
18
|
+
|
19
|
+
/* pass-through certain characters for CP-1252 */
|
20
|
+
#define p(x) (x-128)
|
21
|
+
|
22
|
+
static const int cp_1252[] = {
|
23
|
+
8364, /* 128 => 8364, euro sign */
|
24
|
+
p(129), /* 129 => 129, pass-through */
|
25
|
+
8218, /* 130 => 8218, single low-9 quotation mark */
|
26
|
+
402, /* 131 => 402, latin small letter f with hook */
|
27
|
+
8222, /* 132 => 8222, double low-9 quotation mark */
|
28
|
+
8230, /* 133 => 8230, horizontal ellipsis */
|
29
|
+
8224, /* 134 => 8224, dagger */
|
30
|
+
8225, /* 135 => 8225, double dagger */
|
31
|
+
710, /* 136 => 710, modifier letter circumflex accent */
|
32
|
+
8240, /* 137 => 8240, per mille sign */
|
33
|
+
352, /* 138 => 352, latin capital letter s with caron */
|
34
|
+
8249, /* 139 => 8249, single left-pointing angle quotation mark */
|
35
|
+
338, /* 140 => 338, latin capital ligature oe */
|
36
|
+
p(141), /* 141 => 141, pass-through */
|
37
|
+
381, /* 142 => 381, latin capital letter z with caron */
|
38
|
+
p(143), /* 143 => 143, pass-through */
|
39
|
+
p(144), /* 144 => 144, pass-through */
|
40
|
+
8216, /* 145 => 8216, left single quotation mark */
|
41
|
+
8217, /* 146 => 8217, right single quotation mark */
|
42
|
+
8220, /* 147 => 8220, left double quotation mark */
|
43
|
+
8221, /* 148 => 8221, right double quotation mark */
|
44
|
+
8226, /* 149 => 8226, bullet */
|
45
|
+
8211, /* 150 => 8211, en dash */
|
46
|
+
8212, /* 151 => 8212, em dash */
|
47
|
+
732, /* 152 => 732, small tilde */
|
48
|
+
8482, /* 153 => 8482, trade mark sign */
|
49
|
+
353, /* 154 => 353, latin small letter s with caron */
|
50
|
+
8250, /* 155 => 8250, single right-pointing angle quotation mark */
|
51
|
+
339, /* 156 => 339, latin small ligature oe */
|
52
|
+
p(157), /* 157 => 157, pass-through */
|
53
|
+
382, /* 158 => 382, latin small letter z with caron */
|
54
|
+
376 /* 159 => 376} latin capital letter y with diaeresis */
|
55
|
+
};
|
56
|
+
|
57
|
+
#define VALID_VALUE(n) \
|
58
|
+
(n >= 0x20 && n <= 0xD7FF) || \
|
59
|
+
(n >= 0xE000 && n <= 0xFFFD) || \
|
60
|
+
(n >= 0x10000 && n <= 0x10FFFF)
|
61
|
+
|
62
|
+
#define CP_1252_ESCAPE(n) do { \
|
63
|
+
if (n >= 128 && n <= 159) \
|
64
|
+
n = cp_1252[n - 128]; \
|
65
|
+
} while(0)
|
66
|
+
|
67
|
+
static inline size_t bytes_for(int n)
|
68
|
+
{
|
69
|
+
if (n < 1000)
|
70
|
+
return sizeof("ϧ") - 1;
|
71
|
+
if (n < 10000)
|
72
|
+
return sizeof("✏") - 1;
|
73
|
+
if (n < 100000)
|
74
|
+
return sizeof("𘚟") - 1;
|
75
|
+
if (n < 1000000)
|
76
|
+
return sizeof("󴈿") - 1;
|
77
|
+
/* if (n < 10000000), we won't have cases above 0x10FFFF */
|
78
|
+
return sizeof("�") - 1;
|
79
|
+
}
|
80
|
+
|
81
|
+
static size_t escape(char *buf, int n)
|
82
|
+
{
|
83
|
+
|
84
|
+
#define return_const_len(x) do { \
|
85
|
+
memcpy(buf, x, sizeof(x) - 1); \
|
86
|
+
return (sizeof(x) - 1); \
|
87
|
+
} while (0)
|
88
|
+
|
89
|
+
/* handle ASCII first */
|
90
|
+
if (likely(n < 128)) {
|
91
|
+
if (likely(n >= 0x20 || n == '\t' || n == '\n' || n == '\r')) {
|
92
|
+
if (unlikely(n == '&'))
|
93
|
+
return_const_len("&");
|
94
|
+
if (unlikely(n == '<'))
|
95
|
+
return_const_len("<");
|
96
|
+
if (unlikely(n == '>'))
|
97
|
+
return_const_len(">");
|
98
|
+
buf[0] = (char)n;
|
99
|
+
return 1;
|
100
|
+
}
|
101
|
+
|
102
|
+
buf[0] = '*';
|
103
|
+
return 1;
|
104
|
+
}
|
105
|
+
|
106
|
+
#undef return_const_len
|
107
|
+
|
108
|
+
CP_1252_ESCAPE(n);
|
109
|
+
|
110
|
+
if (VALID_VALUE(n)) {
|
111
|
+
/* return snprintf(buf, sizeof(""), "&#%i;", n); */
|
112
|
+
extern const char ruby_digitmap[];
|
113
|
+
size_t rv = sizeof("&#;") - 1;
|
114
|
+
buf += bytes_for(n);
|
115
|
+
*--buf = ';';
|
116
|
+
do {
|
117
|
+
*--buf = ruby_digitmap[(int)(n % 10)];
|
118
|
+
++rv;
|
119
|
+
} while (n /= 10);
|
120
|
+
*--buf = '#';
|
121
|
+
*--buf = '&';
|
122
|
+
return rv;
|
123
|
+
}
|
124
|
+
buf[0] = '*';
|
125
|
+
return 1;
|
126
|
+
}
|
127
|
+
|
128
|
+
static long escaped_len(int n)
|
129
|
+
{
|
130
|
+
if (likely(n < 128)) {
|
131
|
+
if (unlikely(n == '&'))
|
132
|
+
return (sizeof("&") - 1);
|
133
|
+
if (unlikely(n == '>' || n == '<'))
|
134
|
+
return (sizeof(">") - 1);
|
135
|
+
return 1;
|
136
|
+
}
|
137
|
+
|
138
|
+
CP_1252_ESCAPE(n);
|
139
|
+
|
140
|
+
return VALID_VALUE(n) ? bytes_for(n) : 1;
|
141
|
+
}
|
142
|
+
|
143
|
+
static VALUE unpack_utf8(VALUE self)
|
144
|
+
{
|
145
|
+
return rb_funcall(self, unpack_id, 1, U_fmt);
|
146
|
+
}
|
147
|
+
|
148
|
+
static VALUE unpack_uchar(VALUE self)
|
149
|
+
{
|
150
|
+
return rb_funcall(self, unpack_id, 1, C_fmt);
|
151
|
+
}
|
152
|
+
|
153
|
+
static VALUE fast_xs(VALUE self)
|
154
|
+
{
|
155
|
+
long i;
|
156
|
+
struct RArray *array;
|
157
|
+
char *s, *c;
|
158
|
+
size_t s_len = 0;
|
159
|
+
VALUE *tmp;
|
160
|
+
|
161
|
+
array = RARRAY(rb_rescue(unpack_utf8, self, unpack_uchar, self));
|
162
|
+
|
163
|
+
for (tmp = array->ptr, i = array->len; --i >= 0; tmp++)
|
164
|
+
s_len += escaped_len(NUM2INT(*tmp));
|
165
|
+
|
166
|
+
c = s = alloca(s_len);
|
167
|
+
|
168
|
+
for (tmp = array->ptr, i = array->len; --i >= 0; tmp++)
|
169
|
+
c += escape(c, NUM2INT(*tmp));
|
170
|
+
|
171
|
+
return rb_str_new(s, s_len);
|
172
|
+
}
|
173
|
+
|
174
|
+
/*
|
175
|
+
* This is coding agnostic, and works on each byte, so some multibyte
|
176
|
+
* character sets may not be fully supported (but UTF-8 should be).
|
177
|
+
* This is meant to be 100% compatible with the
|
178
|
+
* ERB::Util::escape_html and CGI::escapeHTML methods
|
179
|
+
*/
|
180
|
+
static VALUE fast_xs_html(VALUE self)
|
181
|
+
{
|
182
|
+
struct RString *string = RSTRING(self);
|
183
|
+
long i;
|
184
|
+
char *s;
|
185
|
+
size_t new_len = 0;
|
186
|
+
char *new_str;
|
187
|
+
|
188
|
+
for (s = string->ptr, i = string->len; --i >= 0; ++s) {
|
189
|
+
if (unlikely(*s == '&'))
|
190
|
+
new_len += (sizeof("&") - 1);
|
191
|
+
else if (unlikely(*s == '<' || *s == '>'))
|
192
|
+
new_len += (sizeof(">") - 1);
|
193
|
+
else if (unlikely(*s == '"'))
|
194
|
+
new_len += (sizeof(""") - 1);
|
195
|
+
else
|
196
|
+
new_len += 1;
|
197
|
+
}
|
198
|
+
|
199
|
+
new_str = alloca(new_len);
|
200
|
+
|
201
|
+
#define append_const(buf, x) do { \
|
202
|
+
buf = memcpy(buf, x, sizeof(x) - 1) + sizeof(x) - 1; \
|
203
|
+
} while (0)
|
204
|
+
|
205
|
+
for (s = string->ptr, i = string->len; --i >= 0; ++s) {
|
206
|
+
if (unlikely(*s == '&'))
|
207
|
+
append_const(new_str, "&");
|
208
|
+
else if (unlikely(*s == '<'))
|
209
|
+
append_const(new_str, "<");
|
210
|
+
else if (unlikely(*s == '>'))
|
211
|
+
append_const(new_str, ">");
|
212
|
+
else if (unlikely(*s == '"'))
|
213
|
+
append_const(new_str, """);
|
214
|
+
else
|
215
|
+
*new_str++ = *s;
|
216
|
+
}
|
217
|
+
|
218
|
+
#undef append_const
|
219
|
+
|
220
|
+
return rb_str_new(new_str - new_len, new_len);
|
221
|
+
}
|
222
|
+
|
223
|
+
#define CGI_URI_OK(x) \
|
224
|
+
((x >= 'a' && x <= 'z') || \
|
225
|
+
(x >= 'A' && x <= 'Z') || \
|
226
|
+
(x >= '0' && x <= '9') || \
|
227
|
+
(x == '.' || x == '-' || x == '_'))
|
228
|
+
|
229
|
+
/*
|
230
|
+
* Compatible with CGI::escape(), this iterates through each byte, so
|
231
|
+
* multibyte character sets may not supported (but UTF-8 should be).
|
232
|
+
*/
|
233
|
+
static VALUE fast_xs_cgi(VALUE self)
|
234
|
+
{
|
235
|
+
struct RString *string = RSTRING(self);
|
236
|
+
long i;
|
237
|
+
char *s;
|
238
|
+
size_t new_len = 0;
|
239
|
+
char *new_str;
|
240
|
+
|
241
|
+
for (s = string->ptr, i = string->len; --i >= 0; ++s) {
|
242
|
+
if (likely(CGI_URI_OK(*s) || *s == ' '))
|
243
|
+
++new_len;
|
244
|
+
else /* we'll only get <= "%FF" here */
|
245
|
+
new_len += 3;
|
246
|
+
}
|
247
|
+
|
248
|
+
new_str = alloca(new_len);
|
249
|
+
|
250
|
+
for (s = string->ptr, i = string->len; --i >= 0; ++s) {
|
251
|
+
if (likely(CGI_URI_OK(*s)))
|
252
|
+
*new_str++ = *s;
|
253
|
+
else if (*s == ' ')
|
254
|
+
*new_str++ = '+';
|
255
|
+
else {
|
256
|
+
static const char cgi_digitmap[] = "0123456789ABCDEF";
|
257
|
+
new_str[2] = cgi_digitmap[(*s % 16)];
|
258
|
+
new_str[1] = cgi_digitmap[((*s/16) % 16)];
|
259
|
+
new_str[0] = '%';
|
260
|
+
new_str += 3;
|
261
|
+
}
|
262
|
+
}
|
263
|
+
return rb_str_new(new_str - new_len, new_len);
|
264
|
+
}
|
265
|
+
|
266
|
+
void Init_fast_xs(void)
|
267
|
+
{
|
268
|
+
assert(cp_1252[159 - 128] == 376); /* just in case I skipped a line */
|
269
|
+
|
270
|
+
unpack_id = rb_intern("unpack");
|
271
|
+
U_fmt = rb_str_new("U*", 2);
|
272
|
+
C_fmt = rb_str_new("C*", 2);
|
273
|
+
rb_global_variable(&U_fmt);
|
274
|
+
rb_global_variable(&C_fmt);
|
275
|
+
|
276
|
+
rb_define_method(rb_cString, "fast_xs", fast_xs, 0);
|
277
|
+
rb_define_method(rb_cString, "fast_xs_html", fast_xs_html, 0);
|
278
|
+
rb_define_method(rb_cString, "fast_xs_cgi", fast_xs_cgi, 0);
|
279
|
+
}
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'fast_xs'
|
2
|
+
|
3
|
+
if defined?(CGI)
|
4
|
+
|
5
|
+
class CGI
|
6
|
+
|
7
|
+
def CGI::escapeHTML(value)
|
8
|
+
value.to_s.fast_xs_html
|
9
|
+
end
|
10
|
+
|
11
|
+
def CGI::escape(value)
|
12
|
+
value.to_s.fast_xs_cgi
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
if defined?(ERB::Util)
|
20
|
+
|
21
|
+
module ERB::Util
|
22
|
+
|
23
|
+
def html_escape(value)
|
24
|
+
value.to_s.fast_xs_html
|
25
|
+
end
|
26
|
+
alias h html_escape
|
27
|
+
module_function :h
|
28
|
+
module_function :html_escape
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'cgi'
|
3
|
+
load 'fast_xs_monkey_patcher.rb'
|
4
|
+
|
5
|
+
class TestCgiClassOverrides < Test::Unit::TestCase
|
6
|
+
|
7
|
+
def test_escape_html_predefined
|
8
|
+
assert_equal '&', CGI::escapeHTML('&')
|
9
|
+
assert_equal '"', CGI::escapeHTML('"')
|
10
|
+
assert_equal '<', CGI::escapeHTML('<')
|
11
|
+
assert_equal '>', CGI::escapeHTML('>')
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_escape_html_normal
|
15
|
+
assert_equal 'hello world', CGI::escapeHTML('hello world')
|
16
|
+
assert_equal '', CGI::escapeHTML('')
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_escape_html_ignore
|
20
|
+
assert_equal "\x00", CGI::escapeHTML("\x00")
|
21
|
+
assert_equal "\x0C", CGI::escapeHTML("\x0C")
|
22
|
+
assert_equal "\xEF\xBF\xBF", CGI::escapeHTML("\xEF\xBF\xBF")
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_escape_cgi
|
26
|
+
assert_equal 'hello%3Dworld', CGI::escape('hello=world')
|
27
|
+
assert_equal '+', CGI::escape(' ')
|
28
|
+
assert_equal '%2B', CGI::escape('+')
|
29
|
+
assert_equal '%2C', CGI::escape(',')
|
30
|
+
assert_equal 'hello-world', CGI::escape('hello-world')
|
31
|
+
assert_equal 'H3LL0+W0RLD', CGI::escape('H3LL0 W0RLD')
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'erb'
|
2
|
+
require 'test/unit'
|
3
|
+
load 'fast_xs_monkey_patcher.rb'
|
4
|
+
|
5
|
+
class TestErbUtilModuleOverrides < Test::Unit::TestCase
|
6
|
+
|
7
|
+
include ERB::Util
|
8
|
+
|
9
|
+
def test_escape_html_predefined
|
10
|
+
assert_equal '&', html_escape('&')
|
11
|
+
assert_equal '"', html_escape('"')
|
12
|
+
assert_equal '<', html_escape('<')
|
13
|
+
assert_equal '>', html_escape('>')
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_escape_html_normal
|
17
|
+
assert_equal 'hello world', html_escape('hello world')
|
18
|
+
assert_equal '', html_escape('')
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_escape_html_ignore
|
22
|
+
assert_equal "\x00", html_escape("\x00")
|
23
|
+
assert_equal "\x0C", html_escape("\x0C")
|
24
|
+
assert_equal "\xEF\xBF\xBF", html_escape("\xEF\xBF\xBF")
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'fast_xs'
|
2
|
+
require 'test/unit'
|
3
|
+
|
4
|
+
# Based on Sam's original xchar.rb tests:
|
5
|
+
|
6
|
+
class TestXmlEscaping < Test::Unit::TestCase
|
7
|
+
|
8
|
+
def test_ascii
|
9
|
+
assert_equal 'abc', 'abc'.fast_xs
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_predefined
|
13
|
+
assert_equal '&', '&'.fast_xs # ampersand
|
14
|
+
assert_equal '<', '<'.fast_xs # left angle bracket
|
15
|
+
assert_equal '>', '>'.fast_xs # right angle bracket
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_invalid
|
19
|
+
assert_equal '*', "\x00".fast_xs # null
|
20
|
+
assert_equal '*', "\x0C".fast_xs # form feed
|
21
|
+
assert_equal '*', "\xEF\xBF\xBF".fast_xs # U+FFFF
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_iso_8859_1
|
25
|
+
assert_equal 'ç', "\xE7".fast_xs # small c cedilla
|
26
|
+
assert_equal '©', "\xA9".fast_xs # copyright symbol
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_win_1252
|
30
|
+
assert_equal '’', "\x92".fast_xs # smart quote
|
31
|
+
assert_equal '€', "\x80".fast_xs # euro
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_utf8
|
35
|
+
assert_equal '’', "\xE2\x80\x99".fast_xs # right single quote
|
36
|
+
assert_equal '©', "\xC2\xA9".fast_xs # copy
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
metadata
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
rubygems_version: 0.9.4.7
|
3
|
+
specification_version: 2
|
4
|
+
name: fast_xs
|
5
|
+
version: !ruby/object:Gem::Version
|
6
|
+
version: "0.2"
|
7
|
+
date: 2007-12-07 00:00:00 -08:00
|
8
|
+
summary: escape faster!
|
9
|
+
require_paths:
|
10
|
+
- lib/i486-linux
|
11
|
+
- lib
|
12
|
+
email: normalperson@yhbt.net
|
13
|
+
homepage: http://bogonips.org/fast_xs/
|
14
|
+
rubyforge_project:
|
15
|
+
description: escape faster!
|
16
|
+
autorequire:
|
17
|
+
default_executable:
|
18
|
+
bindir: bin
|
19
|
+
has_rdoc: true
|
20
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
21
|
+
requirements:
|
22
|
+
- - ">="
|
23
|
+
- !ruby/object:Gem::Version
|
24
|
+
version: "0"
|
25
|
+
version:
|
26
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
27
|
+
requirements:
|
28
|
+
- - ">="
|
29
|
+
- !ruby/object:Gem::Version
|
30
|
+
version: "0"
|
31
|
+
version:
|
32
|
+
platform: ruby
|
33
|
+
signing_key:
|
34
|
+
cert_chain: []
|
35
|
+
|
36
|
+
post_install_message:
|
37
|
+
authors:
|
38
|
+
- Eric Wong
|
39
|
+
files:
|
40
|
+
- CHANGELOG
|
41
|
+
- COPYING
|
42
|
+
- README
|
43
|
+
- Rakefile
|
44
|
+
- test/test_cgi_class_overrides.rb
|
45
|
+
- test/test_xml_escaping.rb
|
46
|
+
- test/test_erb_util_module_overrides.rb
|
47
|
+
- lib/fast_xs_monkey_patcher.rb
|
48
|
+
- ext/fast_xs/fast_xs.c
|
49
|
+
- ext/fast_xs/extconf.rb
|
50
|
+
test_files: []
|
51
|
+
|
52
|
+
rdoc_options:
|
53
|
+
- --quiet
|
54
|
+
- --title
|
55
|
+
- fast_xs notes
|
56
|
+
- --main
|
57
|
+
- README
|
58
|
+
- --inline-source
|
59
|
+
extra_rdoc_files:
|
60
|
+
- README
|
61
|
+
- CHANGELOG
|
62
|
+
- COPYING
|
63
|
+
executables: []
|
64
|
+
|
65
|
+
extensions:
|
66
|
+
- ext/fast_xs/extconf.rb
|
67
|
+
requirements: []
|
68
|
+
|
69
|
+
dependencies: []
|
70
|
+
|