escape 0.0.1

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 ADDED
@@ -0,0 +1,20 @@
1
+ = __
2
+
3
+ [<b>Home page</b>:] http://__.rubyforge.org/
4
+ [<b>Project site</b>:] http://rubyforge.org/projects/__
5
+ [<b>Wiki</b>:] http://wiki.qualitysmith.com/__
6
+ [<b>Author</b>:] Your name
7
+ [<b>Copyright</b>:] 2007 QualitySmith, Inc.
8
+ [<b>License</b>:] {GNU General Public License}[http://www.gnu.org/copyleft/gpl.html]
9
+
10
+ == Introduction
11
+
12
+ ...
13
+
14
+ == Installation
15
+
16
+ ...
17
+
18
+ == Usage
19
+
20
+ ...
@@ -0,0 +1,631 @@
1
+ module RDoc
2
+ module Page
3
+
4
+ FONTS = "\"Bitstream Vera Sans\", Verdana, Arial, Helvetica, sans-serif"
5
+
6
+ STYLE = <<CSS
7
+ a {
8
+ color: #00F;
9
+ text-decoration: none;
10
+ }
11
+
12
+ a:hover {
13
+ color: #77F;
14
+ text-decoration: underline;
15
+ }
16
+
17
+ body, td, p {
18
+ font-family: %fonts%;
19
+ background: #FFF;
20
+ color: #000;
21
+ margin: 0px;
22
+ font-size: small;
23
+ }
24
+
25
+ #content {
26
+ margin: 2em;
27
+ }
28
+
29
+ #description p {
30
+ margin-bottom: 0.5em;
31
+ }
32
+
33
+ .sectiontitle {
34
+ margin-top: 1em;
35
+ margin-bottom: 1em;
36
+ padding: 0.5em;
37
+ padding-left: 2em;
38
+ background: #005;
39
+ color: #FFF;
40
+ font-weight: bold;
41
+ border: 1px dotted black;
42
+ }
43
+
44
+ .attr-rw {
45
+ padding-left: 1em;
46
+ padding-right: 1em;
47
+ text-align: center;
48
+ color: #055;
49
+ }
50
+
51
+ .attr-name {
52
+ font-weight: bold;
53
+ }
54
+
55
+ .attr-desc {
56
+ }
57
+
58
+ .attr-value {
59
+ font-family: monospace;
60
+ }
61
+
62
+ .file-title-prefix {
63
+ font-size: large;
64
+ }
65
+
66
+ .file-title {
67
+ font-size: large;
68
+ font-weight: bold;
69
+ background: #005;
70
+ color: #FFF;
71
+ }
72
+
73
+ .banner {
74
+ background: #005;
75
+ color: #FFF;
76
+ border: 1px solid black;
77
+ padding: 1em;
78
+ }
79
+
80
+ .banner td {
81
+ background: transparent;
82
+ color: #FFF;
83
+ }
84
+
85
+ h1 a, h2 a, .sectiontitle a, .banner a {
86
+ color: #FF0;
87
+ }
88
+
89
+ h1 a:hover, h2 a:hover, .sectiontitle a:hover, .banner a:hover {
90
+ color: #FF7;
91
+ }
92
+
93
+ .dyn-source {
94
+ display: none;
95
+ background: #FFE;
96
+ color: #000;
97
+ border: 1px dotted black;
98
+ margin: 0.5em 2em 0.5em 2em;
99
+ padding: 0.5em;
100
+ }
101
+
102
+ .dyn-source .cmt {
103
+ color: #00F;
104
+ font-style: italic;
105
+ }
106
+
107
+ .dyn-source .kw {
108
+ color: #070;
109
+ font-weight: bold;
110
+ }
111
+
112
+ .method {
113
+ margin-left: 1em;
114
+ margin-right: 1em;
115
+ margin-bottom: 1em;
116
+ }
117
+
118
+ .description pre {
119
+ padding: 0.5em;
120
+ border: 1px dotted black;
121
+ background: #FFE;
122
+ }
123
+
124
+ .method .title {
125
+ font-family: monospace;
126
+ font-size: large;
127
+ border-bottom: 1px dashed black;
128
+ margin-bottom: 0.3em;
129
+ padding-bottom: 0.1em;
130
+ }
131
+
132
+ .method .description, .method .sourcecode {
133
+ margin-left: 1em;
134
+ }
135
+
136
+ .description p, .sourcecode p {
137
+ margin-bottom: 0.5em;
138
+ }
139
+
140
+ .method .sourcecode p.source-link {
141
+ text-indent: 0em;
142
+ margin-top: 0.5em;
143
+ }
144
+
145
+ .method .aka {
146
+ margin-top: 0.3em;
147
+ margin-left: 1em;
148
+ font-style: italic;
149
+ text-indent: 2em;
150
+ }
151
+
152
+ h1 {
153
+ padding: 1em;
154
+ border: 1px solid black;
155
+ font-size: x-large;
156
+ font-weight: bold;
157
+ color: #FFF;
158
+ background: #007;
159
+ }
160
+
161
+ h2 {
162
+ padding: 0.5em 1em 0.5em 1em;
163
+ border: 1px solid black;
164
+ font-size: large;
165
+ font-weight: bold;
166
+ color: #FFF;
167
+ background: #009;
168
+ }
169
+
170
+ h3, h4, h5, h6 {
171
+ padding: 0.2em 1em 0.2em 1em;
172
+ border: 1px dashed black;
173
+ color: #000;
174
+ background: #AAF;
175
+ }
176
+
177
+ .sourcecode > pre {
178
+ padding: 0.5em;
179
+ border: 1px dotted black;
180
+ background: #FFE;
181
+ }
182
+
183
+ CSS
184
+
185
+ XHTML_PREAMBLE = %{<?xml version="1.0" encoding="%charset%"?>
186
+ <!DOCTYPE html
187
+ PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
188
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
189
+ }
190
+
191
+ HEADER = XHTML_PREAMBLE + <<ENDHEADER
192
+ <html>
193
+ <head>
194
+ <title>%title%</title>
195
+ <meta http-equiv="Content-Type" content="text/html; charset=%charset%" />
196
+ <link rel="stylesheet" href="%style_url%" type="text/css" media="screen" />
197
+
198
+ <script language="JavaScript" type="text/javascript">
199
+ // <![CDATA[
200
+
201
+ function toggleSource( id )
202
+ {
203
+ var elem
204
+ var link
205
+
206
+ if( document.getElementById )
207
+ {
208
+ elem = document.getElementById( id )
209
+ link = document.getElementById( "l_" + id )
210
+ }
211
+ else if ( document.all )
212
+ {
213
+ elem = eval( "document.all." + id )
214
+ link = eval( "document.all.l_" + id )
215
+ }
216
+ else
217
+ return false;
218
+
219
+ if( elem.style.display == "block" )
220
+ {
221
+ elem.style.display = "none"
222
+ link.innerHTML = "show source"
223
+ }
224
+ else
225
+ {
226
+ elem.style.display = "block"
227
+ link.innerHTML = "hide source"
228
+ }
229
+ }
230
+
231
+ function openCode( url )
232
+ {
233
+ window.open( url, "SOURCE_CODE", "width=400,height=400,scrollbars=yes" )
234
+ }
235
+ // ]]>
236
+ </script>
237
+ </head>
238
+
239
+ <body>
240
+ ENDHEADER
241
+
242
+ FILE_PAGE = <<HTML
243
+ <table border='0' cellpadding='0' cellspacing='0' width="100%" class='banner'>
244
+ <tr><td>
245
+ <table width="100%" border='0' cellpadding='0' cellspacing='0'><tr>
246
+ <td class="file-title" colspan="2"><span class="file-title-prefix">File</span><br />%short_name%</td>
247
+ <td align="right">
248
+ <table border='0' cellspacing="0" cellpadding="2">
249
+ <tr>
250
+ <td>Path:</td>
251
+ <td>%full_path%
252
+ IF:cvsurl
253
+ &nbsp;(<a href="%cvsurl%">CVS</a>)
254
+ ENDIF:cvsurl
255
+ </td>
256
+ </tr>
257
+ <tr>
258
+ <td>Modified:</td>
259
+ <td>%dtm_modified%</td>
260
+ </tr>
261
+ </table>
262
+ </td></tr>
263
+ </table>
264
+ </td></tr>
265
+ </table><br>
266
+ HTML
267
+
268
+ ###################################################################
269
+
270
+ CLASS_PAGE = <<HTML
271
+ <table width="100%" border='0' cellpadding='0' cellspacing='0' class='banner'><tr>
272
+ <td class="file-title"><span class="file-title-prefix">%classmod%</span><br />%full_name%</td>
273
+ <td align="right">
274
+ <table cellspacing=0 cellpadding=2>
275
+ <tr valign="top">
276
+ <td>In:</td>
277
+ <td>
278
+ START:infiles
279
+ HREF:full_path_url:full_path:
280
+ IF:cvsurl
281
+ &nbsp;(<a href="%cvsurl%">CVS</a>)
282
+ ENDIF:cvsurl
283
+ END:infiles
284
+ </td>
285
+ </tr>
286
+ IF:parent
287
+ <tr>
288
+ <td>Parent:</td>
289
+ <td>
290
+ IF:par_url
291
+ <a href="%par_url%">
292
+ ENDIF:par_url
293
+ %parent%
294
+ IF:par_url
295
+ </a>
296
+ ENDIF:par_url
297
+ </td>
298
+ </tr>
299
+ ENDIF:parent
300
+ </table>
301
+ </td>
302
+ </tr>
303
+ </table>
304
+ HTML
305
+
306
+ ###################################################################
307
+
308
+ METHOD_LIST = <<HTML
309
+ <div id="content">
310
+ IF:diagram
311
+ <table cellpadding='0' cellspacing='0' border='0' width="100%"><tr><td align="center">
312
+ %diagram%
313
+ </td></tr></table>
314
+ ENDIF:diagram
315
+
316
+ IF:description
317
+ <div class="description">%description%</div>
318
+ ENDIF:description
319
+
320
+ IF:requires
321
+ <div class="sectiontitle">Required Files</div>
322
+ <ul>
323
+ START:requires
324
+ <li>HREF:aref:name:</li>
325
+ END:requires
326
+ </ul>
327
+ ENDIF:requires
328
+
329
+ IF:toc
330
+ <div class="sectiontitle">Contents</div>
331
+ <ul>
332
+ START:toc
333
+ <li><a href="#%href%">%secname%</a></li>
334
+ END:toc
335
+ </ul>
336
+ ENDIF:toc
337
+
338
+ IF:methods
339
+ <div class="sectiontitle">Methods</div>
340
+ <ul>
341
+ START:methods
342
+ <li>HREF:aref:name:</li>
343
+ END:methods
344
+ </ul>
345
+ ENDIF:methods
346
+
347
+ IF:includes
348
+ <div class="sectiontitle">Included Modules</div>
349
+ <ul>
350
+ START:includes
351
+ <li>HREF:aref:name:</li>
352
+ END:includes
353
+ </ul>
354
+ ENDIF:includes
355
+
356
+ START:sections
357
+ IF:sectitle
358
+ <div class="sectiontitle"><a name="%secsequence%">%sectitle%</a></div>
359
+ IF:seccomment
360
+ <div class="description">
361
+ %seccomment%
362
+ </div>
363
+ ENDIF:seccomment
364
+ ENDIF:sectitle
365
+
366
+ IF:classlist
367
+ <div class="sectiontitle">Classes and Modules</div>
368
+ %classlist%
369
+ ENDIF:classlist
370
+
371
+ IF:constants
372
+ <div class="sectiontitle">Constants</div>
373
+ <table border='0' cellpadding='5'>
374
+ START:constants
375
+ <tr valign='top'>
376
+ <td class="attr-name">%name%</td>
377
+ <td>=</td>
378
+ <td class="attr-value">%value%</td>
379
+ </tr>
380
+ IF:desc
381
+ <tr valign='top'>
382
+ <td>&nbsp;</td>
383
+ <td colspan="2" class="attr-desc">%desc%</td>
384
+ </tr>
385
+ ENDIF:desc
386
+ END:constants
387
+ </table>
388
+ ENDIF:constants
389
+
390
+ IF:attributes
391
+ <div class="sectiontitle">Attributes</div>
392
+ <table border='0' cellpadding='5'>
393
+ START:attributes
394
+ <tr valign='top'>
395
+ <td class='attr-rw'>
396
+ IF:rw
397
+ [%rw%]
398
+ ENDIF:rw
399
+ </td>
400
+ <td class='attr-name'>%name%</td>
401
+ <td class='attr-desc'>%a_desc%</td>
402
+ </tr>
403
+ END:attributes
404
+ </table>
405
+ ENDIF:attributes
406
+
407
+ IF:method_list
408
+ START:method_list
409
+ IF:methods
410
+ <div class="sectiontitle">%type% %category% methods</div>
411
+ START:methods
412
+ <div class="method">
413
+ <div class="title">
414
+ IF:callseq
415
+ <a name="%aref%"></a><b>%callseq%</b>
416
+ ENDIF:callseq
417
+ IFNOT:callseq
418
+ <a name="%aref%"></a><b>%name%</b>%params%
419
+ ENDIF:callseq
420
+ IF:codeurl
421
+ [ <a href="javascript:openCode('%codeurl%')">source</a> ]
422
+ ENDIF:codeurl
423
+ </div>
424
+ IF:m_desc
425
+ <div class="description">
426
+ %m_desc%
427
+ </div>
428
+ ENDIF:m_desc
429
+ IF:aka
430
+ <div class="aka">
431
+ This method is also aliased as
432
+ START:aka
433
+ <a href="%aref%">%name%</a>
434
+ END:aka
435
+ </div>
436
+ ENDIF:aka
437
+ IF:sourcecode
438
+ <div class="sourcecode">
439
+ <p class="source-link">[ <a href="javascript:toggleSource('%aref%_source')" id="l_%aref%_source">show source</a> ]</p>
440
+ <div id="%aref%_source" class="dyn-source">
441
+ <pre>
442
+ %sourcecode%
443
+ </pre>
444
+ </div>
445
+ </div>
446
+ ENDIF:sourcecode
447
+ </div>
448
+ END:methods
449
+ ENDIF:methods
450
+ END:method_list
451
+ ENDIF:method_list
452
+ END:sections
453
+ </div>
454
+ HTML
455
+
456
+ FOOTER = <<ENDFOOTER
457
+ </body>
458
+ </html>
459
+ ENDFOOTER
460
+
461
+ BODY = HEADER + <<ENDBODY
462
+ !INCLUDE! <!-- banner header -->
463
+
464
+ <div id="bodyContent">
465
+ #{METHOD_LIST}
466
+ </div>
467
+
468
+ #{FOOTER}
469
+ ENDBODY
470
+
471
+ ########################## Source code ##########################
472
+
473
+ SRC_PAGE = XHTML_PREAMBLE + <<HTML
474
+ <html>
475
+ <head><title>%title%</title>
476
+ <meta http-equiv="Content-Type" content="text/html; charset=%charset%">
477
+ <style>
478
+ .ruby-comment { color: green; font-style: italic }
479
+ .ruby-constant { color: #4433aa; font-weight: bold; }
480
+ .ruby-identifier { color: #222222; }
481
+ .ruby-ivar { color: #2233dd; }
482
+ .ruby-keyword { color: #3333FF; font-weight: bold }
483
+ .ruby-node { color: #777777; }
484
+ .ruby-operator { color: #111111; }
485
+ .ruby-regexp { color: #662222; }
486
+ .ruby-value { color: #662222; font-style: italic }
487
+ .kw { color: #3333FF; font-weight: bold }
488
+ .cmt { color: green; font-style: italic }
489
+ .str { color: #662222; font-style: italic }
490
+ .re { color: #662222; }
491
+ </style>
492
+ </head>
493
+ <body bgcolor="white">
494
+ <pre>%code%</pre>
495
+ </body>
496
+ </html>
497
+ HTML
498
+
499
+ ########################## Index ################################
500
+
501
+ FR_INDEX_BODY = <<HTML
502
+ !INCLUDE!
503
+ HTML
504
+
505
+ FILE_INDEX = XHTML_PREAMBLE + <<HTML
506
+ <html>
507
+ <head>
508
+ <meta http-equiv="Content-Type" content="text/html; charset=%charset%">
509
+ <style>
510
+ <!--
511
+ body {
512
+ background-color: #EEE;
513
+ font-family: #{FONTS};
514
+ color: #000;
515
+ margin: 0px;
516
+ }
517
+ .banner {
518
+ background: #005;
519
+ color: #FFF;
520
+ padding: 0.2em;
521
+ font-size: small;
522
+ font-weight: bold;
523
+ text-align: center;
524
+ }
525
+ .entries {
526
+ margin: 0.25em 1em 0 1em;
527
+ font-size: x-small;
528
+ }
529
+ a {
530
+ display: block;
531
+ color: #00F;
532
+ text-decoration: none;
533
+ white-space: nowrap;
534
+ }
535
+ a:hover {
536
+ color: #77F;
537
+ text-decoration: underline;
538
+ }
539
+ input#link_search {
540
+ color: #a00;
541
+ }
542
+ input#link_search.default {
543
+ color: #888;
544
+ }
545
+ -->
546
+ </style>
547
+ <script type="text/javascript" language="javascript">
548
+ function init_frame_select() {
549
+ var opts = document.getElementById('frame_select').options;
550
+ for (i = 0; i < opts.length; i++) {
551
+ opts[i].selected = (location.href.indexOf(opts[i].value) != -1);
552
+ }
553
+ }
554
+ function do_link_search() {
555
+ var search_box = document.getElementById('link_search');
556
+ if (search_box.value == search_box.defaultValue) return;
557
+ var links = document.getElementById('entries').getElementsByTagName('a');
558
+ search = new RegExp(search_box.value, 'i');
559
+ for (i = 0; i < links.length; i++) {
560
+ links[i].style.display = search.exec(links[i].innerHTML) ? 'block' : 'none';
561
+ }
562
+ }
563
+ function clear_link_search() {
564
+ var search_box = document.getElementById('link_search');
565
+ if (search_box.value == search_box.defaultValue) search_box.value = '';
566
+ search_box.className = '';
567
+ }
568
+ function reset_link_search() {
569
+ var search_box = document.getElementById('link_search');
570
+ if (search_box.value == '') search_box.value = search_box.defaultValue;
571
+ search_box.className = 'default';
572
+ }
573
+ </script>
574
+ <base target="docwin">
575
+ </head>
576
+ <body onload="init_frame_select(); reset_link_search();">
577
+ <select id="frame_select" onchange="location.href=this.value" style="width: 100%;">
578
+ <option value="fr_class_index.html">Classes</option>
579
+ <option value="fr_file_index.html">Files</option>
580
+ <option value="fr_method_index.html">Methods</option>
581
+ </select>
582
+ <input id="link_search" class="default" type="text" onkeyup="do_link_search()" onfocus="clear_link_search()" onblur="reset_link_search()" style="width: 100%;" value="type search here..." />
583
+ <div class="banner">%list_title%</div>
584
+ <div class="entries" id="entries">
585
+ START:entries
586
+ <a href="%href%">%name%</a>
587
+ END:entries
588
+ </div>
589
+ </body></html>
590
+ HTML
591
+
592
+ CLASS_INDEX = FILE_INDEX
593
+ METHOD_INDEX = FILE_INDEX
594
+
595
+ INDEX = XHTML_PREAMBLE + <<HTML
596
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
597
+ <head>
598
+ <title>%title%</title>
599
+ <meta http-equiv="Content-Type" content="text/html; charset=%charset%">
600
+ </head>
601
+
602
+ <frameset cols="200, *">
603
+ <frame src="fr_class_index.html" name="framewin" />
604
+ <frame src="%initial_page%" name="docwin" />
605
+ </frameset>
606
+
607
+ <frameset cols="200,*">
608
+ <frame src="fr_class_index.html" name="framewin" />
609
+ IF:inline_source
610
+ <frame src="%initial_page%" name="docwin">
611
+ ENDIF:inline_source
612
+ IFNOT:inline_source
613
+ <frameset rows="80%,20%">
614
+ <frame src="%initial_page%" name="docwin">
615
+ <frame src="blank.html" name="source">
616
+ </frameset>
617
+ ENDIF:inline_source
618
+ <noframes>
619
+ <body bgcolor="white">
620
+ Click <a href="html/index.html">here</a> for a non-frames
621
+ version of this page.
622
+ </body>
623
+ </noframes>
624
+ </frameset>
625
+
626
+ </html>
627
+ HTML
628
+
629
+ end
630
+ end
631
+
@@ -0,0 +1,247 @@
1
+ # escape.rb - escape/unescape library for several formats
2
+ #
3
+ # Copyright (C) 2006,2007 Tanaka Akira <akr@fsij.org>
4
+ #
5
+ # Redistribution and use in source and binary forms, with or without
6
+ # modification, are permitted provided that the following conditions are met:
7
+ #
8
+ # 1. Redistributions of source code must retain the above copyright notice, this
9
+ # list of conditions and the following disclaimer.
10
+ # 2. Redistributions in binary form must reproduce the above copyright notice,
11
+ # this list of conditions and the following disclaimer in the documentation
12
+ # and/or other materials provided with the distribution.
13
+ # 3. The name of the author may not be used to endorse or promote products
14
+ # derived from this software without specific prior written permission.
15
+ #
16
+ # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17
+ # WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18
+ # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19
+ # EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20
+ # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
21
+ # OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
24
+ # IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
25
+ # OF SUCH DAMAGE.
26
+
27
+ # Escape module provides several escape functions.
28
+ # * URI
29
+ # * HTML
30
+ # * shell command
31
+ module Escape
32
+ module_function
33
+
34
+ # Escape.shell_command composes
35
+ # a sequence of words to
36
+ # a single shell command line.
37
+ # All shell meta characters are quoted and
38
+ # the words are concatenated with interleaving space.
39
+ #
40
+ # Escape.shell_command(["ls", "/"]) #=> "ls /"
41
+ # Escape.shell_command(["echo", "*"]) #=> "echo '*'"
42
+ #
43
+ # Note that system(*command) and
44
+ # system(Escape.shell_command(command)) is roughly same.
45
+ # There are two exception as follows.
46
+ # * The first is that the later may invokes /bin/sh.
47
+ # * The second is an interpretation of an array with only one element:
48
+ # the element is parsed by the shell with the former but
49
+ # it is recognized as single word with the later.
50
+ # For example, system(*["echo foo"]) invokes echo command with an argument "foo".
51
+ # But system(Escape.shell_command(["echo foo"])) invokes "echo foo" command without arguments (and it probably fails).
52
+ def shell_command(command)
53
+ command.map {|word| shell_single_word(word) }.join(' ')
54
+ end
55
+
56
+ # Escape.shell_single_word quotes shell meta characters.
57
+ #
58
+ # The result string is always single shell word, even if
59
+ # the argument is "".
60
+ # Escape.shell_single_word("") returns "''".
61
+ #
62
+ # Escape.shell_single_word("") #=> "''"
63
+ # Escape.shell_single_word("foo") #=> "foo"
64
+ # Escape.shell_single_word("*") #=> "'*'"
65
+ def shell_single_word(str)
66
+ if str.empty?
67
+ "''"
68
+ elsif %r{\A[0-9A-Za-z+,./:=@_-]+\z} =~ str
69
+ str
70
+ else
71
+ result = ''
72
+ str.scan(/('+)|[^']+/) {
73
+ if $1
74
+ result << %q{\'} * $1.length
75
+ else
76
+ result << "'#{$&}'"
77
+ end
78
+ }
79
+ result
80
+ end
81
+ end
82
+
83
+ # Escape.uri_segment escapes URI segment using percent-encoding.
84
+ #
85
+ # Escape.uri_segment("a/b") #=> "a%2Fb"
86
+ #
87
+ # The segment is "/"-splitted element after authority before query in URI, as follows.
88
+ #
89
+ # scheme://authority/segment1/segment2/.../segmentN?query#fragment
90
+ #
91
+ # See RFC 3986 for details of URI.
92
+ def uri_segment(str)
93
+ # pchar - pct-encoded = unreserved / sub-delims / ":" / "@"
94
+ # unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
95
+ # sub-delims = "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / ";" / "="
96
+ str.gsub(%r{[^A-Za-z0-9\-._~!$&'()*+,;=:@]}n) {
97
+ '%' + $&.unpack("H2")[0].upcase
98
+ }
99
+ end
100
+
101
+ # Escape.uri_path escapes URI path using percent-encoding.
102
+ # The given path should be a sequence of (non-escaped) segments separated by "/".
103
+ # The segments cannot contains "/".
104
+ #
105
+ # Escape.uri_path("a/b/c") #=> "a/b/c"
106
+ # Escape.uri_path("a?b/c?d/e?f") #=> "a%3Fb/c%3Fd/e%3Ff"
107
+ #
108
+ # The path is the part after authority before query in URI, as follows.
109
+ #
110
+ # scheme://authority/path#fragment
111
+ #
112
+ # See RFC 3986 for details of URI.
113
+ #
114
+ # Note that this function is not appropriate to convert OS path to URI.
115
+ def uri_path(str)
116
+ str.gsub(%r{[^/]+}n) { uri_segment($&) }
117
+ end
118
+
119
+ # :stopdoc:
120
+ def html_form_fast(pairs, sep=';')
121
+ pairs.map {|k, v|
122
+ # query-chars - pct-encoded - x-www-form-urlencoded-delimiters =
123
+ # unreserved / "!" / "$" / "'" / "(" / ")" / "*" / "," / ":" / "@" / "/" / "?"
124
+ # query-char - pct-encoded = unreserved / sub-delims / ":" / "@" / "/" / "?"
125
+ # query-char = pchar / "/" / "?" = unreserved / pct-encoded / sub-delims / ":" / "@" / "/" / "?"
126
+ # unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
127
+ # sub-delims = "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / ";" / "="
128
+ # x-www-form-urlencoded-delimiters = "&" / "+" / ";" / "="
129
+ k = k.gsub(%r{[^0-9A-Za-z\-\._~:/?@!\$'()*,]}n) {
130
+ '%' + $&.unpack("H2")[0].upcase
131
+ }
132
+ v = v.gsub(%r{[^0-9A-Za-z\-\._~:/?@!\$'()*,]}n) {
133
+ '%' + $&.unpack("H2")[0].upcase
134
+ }
135
+ "#{k}=#{v}"
136
+ }.join(sep)
137
+ end
138
+ # :startdoc:
139
+
140
+ # Escape.html_form composes HTML form key-value pairs as a x-www-form-urlencoded encoded string.
141
+ #
142
+ # Escape.html_form takes an array of pair of strings or
143
+ # an hash from string to string.
144
+ #
145
+ # Escape.html_form([["a","b"], ["c","d"]]) #=> "a=b&c=d"
146
+ # Escape.html_form({"a"=>"b", "c"=>"d"}) #=> "a=b&c=d"
147
+ #
148
+ # In the array form, it is possible to use same key more than once.
149
+ # (It is required for a HTML form which contains
150
+ # checkboxes and select element with multiple attribute.)
151
+ #
152
+ # Escape.html_form([["k","1"], ["k","2"]]) #=> "k=1&k=2"
153
+ #
154
+ # If the strings contains characters which must be escaped in x-www-form-urlencoded,
155
+ # they are escaped using %-encoding.
156
+ #
157
+ # Escape.html_form([["k=","&;="]]) #=> "k%3D=%26%3B%3D"
158
+ #
159
+ # The separator can be specified by the optional second argument.
160
+ #
161
+ # Escape.html_form([["a","b"], ["c","d"]], ";") #=> "a=b;c=d"
162
+ #
163
+ # See HTML 4.01 for details.
164
+ def html_form(pairs, sep='&')
165
+ r = ''
166
+ first = true
167
+ pairs.each {|k, v|
168
+ # query-chars - pct-encoded - x-www-form-urlencoded-delimiters =
169
+ # unreserved / "!" / "$" / "'" / "(" / ")" / "*" / "," / ":" / "@" / "/" / "?"
170
+ # query-char - pct-encoded = unreserved / sub-delims / ":" / "@" / "/" / "?"
171
+ # query-char = pchar / "/" / "?" = unreserved / pct-encoded / sub-delims / ":" / "@" / "/" / "?"
172
+ # unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
173
+ # sub-delims = "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / ";" / "="
174
+ # x-www-form-urlencoded-delimiters = "&" / "+" / ";" / "="
175
+ r << sep if !first
176
+ first = false
177
+ k.each_byte {|byte|
178
+ ch = byte.chr
179
+ if %r{[^0-9A-Za-z\-\._~:/?@!\$'()*,]}n =~ ch
180
+ r << "%" << ch.unpack("H2")[0].upcase
181
+ else
182
+ r << ch
183
+ end
184
+ }
185
+ r << '='
186
+ v.each_byte {|byte|
187
+ ch = byte.chr
188
+ if %r{[^0-9A-Za-z\-\._~:/?@!\$'()*,]}n =~ ch
189
+ r << "%" << ch.unpack("H2")[0].upcase
190
+ else
191
+ r << ch
192
+ end
193
+ }
194
+ }
195
+ r
196
+ end
197
+
198
+ # :stopdoc:
199
+ HTML_TEXT_ESCAPE_HASH = {
200
+ '&' => '&amp;',
201
+ '<' => '&lt;',
202
+ '>' => '&gt;',
203
+ }
204
+ # :startdoc:
205
+
206
+ # Escape.html_text escapes a string appropriate for HTML text using character references.
207
+ #
208
+ # It escapes 3 characters:
209
+ # * '&' to '&amp;'
210
+ # * '<' to '&lt;'
211
+ # * '>' to '&gt;'
212
+ #
213
+ # Escape.html_text("abc") #=> "abc"
214
+ # Escape.html_text("a & b < c > d") #=> "a &amp; b &lt; c &gt; d"
215
+ #
216
+ # This function is not appropriate for escaping HTML element attribute
217
+ # because quotes are not escaped.
218
+ def html_text(str)
219
+ str.gsub(/[&<>]/) {|ch| HTML_TEXT_ESCAPE_HASH[ch] }
220
+ end
221
+
222
+ # :stopdoc:
223
+ HTML_ATTR_ESCAPE_HASH = {
224
+ '&' => '&amp;',
225
+ '<' => '&lt;',
226
+ '>' => '&gt;',
227
+ '"' => '&quot;',
228
+ }
229
+ # :startdoc:
230
+
231
+ # Escape.html_attr encodes a string as a double-quoted HTML attribute using character references.
232
+ #
233
+ # Escape.html_attr("abc") #=> "\"abc\""
234
+ # Escape.html_attr("a&b") #=> "\"a&amp;b\""
235
+ # Escape.html_attr("ab&<>\"c") #=> "\"ab&amp;&lt;&gt;&quot;c\""
236
+ # Escape.html_attr("a'c") #=> "\"a'c\""
237
+ #
238
+ # It escapes 4 characters:
239
+ # * '&' to '&amp;'
240
+ # * '<' to '&lt;'
241
+ # * '>' to '&gt;'
242
+ # * '"' to '&quot;'
243
+ #
244
+ def html_attr(str)
245
+ '"' + str.gsub(/[&<>"]/) {|ch| HTML_ATTR_ESCAPE_HASH[ch] } + '"'
246
+ end
247
+ end
@@ -0,0 +1,213 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'rake/rdoctask'
4
+
5
+ # *Audience*: World, QualitySmith
6
+
7
+ module SharedTasks
8
+ #---------------------------------------------------------------------------------------------------------------------------------
9
+ # Tests
10
+
11
+ # Lets you very concisely create a test task using some common default options. A block may be provided if you want to set additional options.
12
+ # *Example*:
13
+ # SharedTasks.normal_test_task
14
+ # *Audience*: World
15
+ def self.normal_test_task()
16
+ module_eval do
17
+ desc 'Run tests'
18
+ Rake::TestTask.new(:test) do |task|
19
+ task.libs << 'lib'
20
+ task.pattern = 'test/**/*_test.rb'
21
+ task.verbose = true
22
+ # To do: autorequire color library? Could do something like this once we switch to gem dependencies...
23
+ #task.ruby_opts << "-r /home/tyler/code/gemables/test_extensions/lib/test_helper.rb"
24
+ yield task if block_given?
25
+ end
26
+ end
27
+ end
28
+ #---------------------------------------------------------------------------------------------------------------------------------
29
+ # Documentation
30
+
31
+ # Generates an RDoc task for you with common options enabled, including a nicer template than the default.
32
+ # Pass it a block if you need to customize it.
33
+ # Example:
34
+ # SharedTasks.rdoc_task do |rdoc|
35
+ # rdoc.title = Project::PrettyName
36
+ # end
37
+ # *Audience*: World
38
+ def self.rdoc_task(&block)
39
+ module_eval do
40
+ #-------------------------------------------------------------------------------------------
41
+ desc 'Generate RDoc'
42
+ Rake::RDocTask.new(:rdoc) do |rdoc|
43
+ rdoc.rdoc_dir = 'doc'
44
+ rdoc.options <<
45
+ '--line-numbers' << # Include line numbers in the source code
46
+ '--inline-source' << # Causes "Show source" link to display source inline rather than as a popup
47
+ '--all' << # Include private methods
48
+ '--diagram' << # Include diagrams showing modules and classes.
49
+ '--accessor' << 'mattr_accessor' << # So that attributes defined with mattr_accessor will be listed
50
+ '--extension' << 'rake=rb' # Treat .rake files as files that contain Ruby code
51
+ rdoc.template = './doc_include/template/qualitysmith.rb'
52
+ rdoc.rdoc_files.include(
53
+ 'Readme',
54
+ 'lib/**/*.rb'
55
+ )
56
+ yield rdoc
57
+ end
58
+ end
59
+ end
60
+
61
+ # Put images and stuff under doc_include and you can refer to them with links such as Screenshot[link:include/screenshot1.png]
62
+ task :doc_include do
63
+ mkdir 'doc' rescue nil
64
+ cp_r 'doc_include', target = 'doc/include'
65
+
66
+ # Remove those pesky .svn directories
67
+ require 'find'
68
+ require 'fileutils'
69
+ Find.find(target) do |path|
70
+ if File.basename(path) == '.svn'
71
+ FileUtils.remove_dir(path, true)
72
+ Find.prune
73
+ end
74
+ end
75
+ end
76
+
77
+ # Well, I'd rather make :doc_includes a "postrequisite" for :rdoc, but unfortunately Rake doesn't seem to provide a way to specify postrequisites.
78
+ # and :clobber_rdoc (lib/rake/rdoctask.rb) does a rm_r rdoc_dir so anything we do to the directory *before* :rdoc will get wiped out.
79
+ # So... we are left with making :doc_include a prerequisite for the publishing tasks. Unless you have a better idea??
80
+ task :publish_rdoc_local => :rerdoc
81
+ task :publish_rdoc_local => :doc_include
82
+
83
+
84
+ #---------------------------------------------------------------------------------------------------------------------------------
85
+ # Packaging (creating a new version/release)
86
+
87
+ require 'rake/gempackagetask'
88
+
89
+ def release_notes; "doc_include/ReleaseNotes-#{Project::Version}"; end
90
+
91
+ def self.package_task(specification, &block)
92
+ module_eval do
93
+ Rake::GemPackageTask.new(specification) do |package|
94
+ package.need_zip = true
95
+ package.need_tar = true
96
+ end
97
+ end
98
+ end
99
+
100
+ def self.inc_version(file)
101
+ module_eval do
102
+ desc "Increment version number and create release notes"
103
+ task :inc_version do
104
+ # This will be easier once we change to a YAML-based ProjectInfo file...
105
+ require 'facets/core/file/self/open_as_string'
106
+ new_version = Project::Version
107
+ File.open_as_string(file) do |contents|
108
+ contents.gsub!(/(Version *=.*?)(\d+\.\d+\.\d+)(.*)$/) do
109
+ before, version, after = $1, $2, $3
110
+ version = version.split('.')
111
+ new_version = version[0] + '.' + version[1] + '.' + (version[2].to_i+1).to_s
112
+ new_text = before + new_version + after
113
+ puts new_text
114
+ new_text
115
+ end
116
+ end
117
+ Project.const_set(:Version, new_version)
118
+
119
+ system(%(vim #{release_notes}))
120
+ sh %(svn add #{release_notes})
121
+ puts "When you're ready to commit, you can use this:"
122
+ puts "svn ci -F #{release_notes}"
123
+ end
124
+ end
125
+ end
126
+
127
+ desc "Test installing the gem locally"
128
+ # Use rake clean to force rebuilding of gem. Otherwise it may see that it has already built a gem file with that name and just try to reinstall the one we've already got.
129
+ task :gem_install => [:clean, :gem] do
130
+ # :todo:
131
+ # This should give a loud warning and require confirmation if this version already installed.
132
+ # Ask if they want to increment the version number instead (default). It doesn't cost anything to just increment the version number,
133
+ # and it's bad practice to use the same version number for two versions that are actually *different*.
134
+ # It would be okay to reinstall (--force) the current version if one is just testing something *prior* to official release.
135
+ # But once a version is released, it should never be changed. So I guess rather than checking if this version is installed locally,
136
+ # we should check some flag that we keep in ProjectVersion containing the last version number that has been published and refuse to
137
+ # rebuild a gem version that has already been released...
138
+ sh %{sudo gem install --force pkg/#{Project::Name}-#{Project::Version}.gem }
139
+ end
140
+
141
+ desc "Remove generated directories."
142
+ task :clean do
143
+ sh %(rm -rf doc/ pkg/)
144
+ end
145
+
146
+
147
+ #---------------------------------------------------------------------------------------------------------------------------------
148
+ # Publishing
149
+
150
+ require 'rake/contrib/sshpublisher'
151
+
152
+ def self.publish_task()
153
+ module_eval do
154
+ desc "Upload RDoc to RubyForge"
155
+ task :publish_rdoc => [:publish_rdoc_local] do
156
+ Rake::SshDirPublisher.new("#{ENV['RUBYFORGE_USER']}@rubyforge.org", "/var/www/gforge-projects/#{Project::RubyForgeName}", "doc").upload
157
+ end
158
+
159
+ # This can be invoked from the command line:
160
+ # rake release RUBYFORGE_USER=myuser \
161
+ # RUBYFORGE_PASSWORD=mypassword
162
+ task :verify_user do
163
+ raise "RUBYFORGE_USER environment variable not set!" unless ENV['RUBYFORGE_USER']
164
+ end
165
+ task :verify_password do
166
+ raise "RUBYFORGE_PASSWORD environment variable not set!" unless ENV['RUBYFORGE_PASSWORD']
167
+ end
168
+
169
+ desc "Publish package files on RubyForge."
170
+ task :publish_packages => [:verify_user, :verify_password, :package] do
171
+ require 'meta_project'
172
+ require 'rake/contrib/xforge'
173
+ release_files = FileList[
174
+ "pkg/#{Project::Name}-#{Project::Version}.gem",
175
+ "pkg/#{Project::Name}-#{Project::Version}.tgz",
176
+ "pkg/#{Project::Name}-#{Project::Version}.zip"
177
+ ]
178
+
179
+ Rake::XForge::Release.new(MetaProject::Project::XForge::RubyForge.new(Project::RubyForgeName)) do |release|
180
+ release.user_name = ENV['RUBYFORGE_USER']
181
+ release.password = ENV['RUBYFORGE_PASSWORD']
182
+ release.files = release_files.to_a
183
+ release.package_name = "#{Project::Name}"
184
+ release.release_name = "#{Project::Name} #{Project::Version}"
185
+ release.release_changes = ''
186
+ release.release_notes = File.read(release_notes) # Probably want to put them somewhere else, but for now...
187
+ end
188
+ end
189
+ end
190
+ end
191
+
192
+ # *Audience*: Qualitysmith
193
+ desc "Upload RDoc to rdoc.QualitySmith.com"
194
+ task :publish_rdoc_local do
195
+ sh %{ssh commodore mkdir -p /var/www/html/rdoc/#{Project::Name} }
196
+ sh %{ssh commodore sudo chown :users -R /var/www/html/rdoc/#{Project::Name} }
197
+ sh %{ssh commodore sudo chmod g+w -R /var/www/html/rdoc/#{Project::Name} }
198
+ Rake::SshDirPublisher.new("#{ENV['USER']}@commodore", "/var/www/html/rdoc/#{Project::Name}", "doc").upload
199
+ end
200
+
201
+
202
+ #---------------------------------------------------------------------------------------------------------------------------------
203
+ # Announcing
204
+
205
+ task :commits_since_last_release do
206
+ # Look at last release number/revision
207
+ # Display log messages for all revisions since then
208
+ # Can use it to write the release notes for you
209
+ end
210
+
211
+ end # SharedTasks
212
+
213
+ include SharedTasks
metadata ADDED
@@ -0,0 +1,53 @@
1
+ --- !ruby/object:Gem::Specification
2
+ rubygems_version: 0.9.2
3
+ specification_version: 1
4
+ name: escape
5
+ version: !ruby/object:Gem::Version
6
+ version: 0.0.1
7
+ date: 2007-04-26 00:00:00 -07:00
8
+ summary: ...
9
+ require_paths:
10
+ - .
11
+ email:
12
+ homepage: http://rdoc.qualitysmith.com/escape
13
+ rubyforge_project: escape
14
+ description: ...
15
+ autorequire:
16
+ default_executable:
17
+ bindir: bin
18
+ has_rdoc: true
19
+ required_ruby_version: !ruby/object:Gem::Version::Requirement
20
+ requirements:
21
+ - - ">"
22
+ - !ruby/object:Gem::Version
23
+ version: 0.0.0
24
+ version:
25
+ platform: ruby
26
+ signing_key:
27
+ cert_chain:
28
+ post_install_message:
29
+ authors:
30
+ - ...
31
+ files:
32
+ - escape.rb
33
+ - tasks/shared/shared_tasks.rb
34
+ - doc_include/template/qualitysmith.rb
35
+ - Readme
36
+ test_files: []
37
+
38
+ rdoc_options:
39
+ - --title
40
+ - escape
41
+ - --main
42
+ - Readme
43
+ - --line-numbers
44
+ extra_rdoc_files:
45
+ - Readme
46
+ executables: []
47
+
48
+ extensions: []
49
+
50
+ requirements: []
51
+
52
+ dependencies: []
53
+