tiny_xml_builder 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ .raketasks
2
+ announcement.txt
3
+ coverage
4
+ doc
5
+ pkg
data/History.txt ADDED
@@ -0,0 +1,14 @@
1
+ == 0.0.3 / 2011-02-04
2
+ * 2 more enhancements
3
+ * Using the blankslate gem now for our blankslating needs (instead of embedding it);
4
+ * Tested and working against Ruby {1.8.7, 1.9.2} and JRuby {1.5.6}
5
+
6
+ == 0.0.2 / 2011-02-03
7
+
8
+ * 1 other major enhancement
9
+ * Finally ready for release :-)
10
+
11
+ == 0.0.1 / 2010-10-28
12
+
13
+ * 1 major enhancement
14
+ * Birthday!
data/README.asciidoc ADDED
@@ -0,0 +1,156 @@
1
+ Tiny XML Builder
2
+ ================
3
+ Alexandru Ungur <alexaandru@gmail.com>
4
+ :icons:
5
+ :toc:
6
+ :website: http://github.com/alexaandru/tiny_xml_builder
7
+
8
+ Description
9
+ -----------
10
+
11
+ A very simple XML builder class. +
12
+ I wanted something really simple that I could easily extend myself later on if I needed to. +
13
+ Ironically, in four years since I created and used TinyXml, I never needed to extend it :-)
14
+ I figured, it may as well work for others in that case, so here it is.
15
+
16
+ Acknowledgements
17
+ ----------------
18
+
19
+ A big thanks to Jim Weirich for his great advices on Ruby-talk. +
20
+ The BlankSlate "mechanism" he describes at: http://onestepback.org/index.cgi/Tech/Ruby/BlankSlate.rdoc
21
+ and which this library depends upon, is one of the first things I've learnt when started to play with Ruby DSLs.
22
+
23
+ Features/Problems
24
+ -----------------
25
+ - You cannot have XML elements named _\__id\___, _\__send___, _method_missing_, _instance_eval_ or _respond_to_ as those are NOT undefined (on purpose) by BlankSlate mechanism;
26
+ - There are other limitations related to ``implicit receiver'' calls, e.g.:
27
+
28
+ .Explicit receiver example
29
+ ---------------------------------------------
30
+ puts TinyXml::Builder.new.foo {|f| f.p 'bar'}
31
+ ---------------------------------------------
32
+
33
+ will output:
34
+
35
+ ------------
36
+ <foo>
37
+ <p>bar</p>
38
+ </foo>
39
+ ------------
40
+
41
+ while the following:
42
+
43
+ .Implicit receiver example
44
+ -----------------------------------------
45
+ puts TinyXml::Builder.new.foo { p 'bar' }
46
+ -----------------------------------------
47
+
48
+ will output:
49
+
50
+ ------
51
+ "bar"
52
+ <foo>
53
+ </foo>
54
+ ------
55
+
56
+ as "p" method exists in outer scope and does an entirely different thing than what (missing) methods of TinyXml do.
57
+
58
+ Synopsis
59
+ --------
60
+
61
+ .Example Usage
62
+ -----------------------------------------------------------------------------------------
63
+ builder = TinyXml::Builder.new
64
+ builder.html do |xhtml|
65
+ xhtml.head do |head|
66
+ head.title 'Hello World'
67
+ head.meta :name => :keywords, :content => 'hello, world'
68
+ head.meta :name => :description, :content => 'hello world sample usage for XML class'
69
+ end
70
+ xhtml.body do |body|
71
+ body.div :id => 'main' do |div_main|
72
+ div_main.h1 "Hello World"
73
+ div_main.p "Hello HTML world", "from XML"
74
+ end
75
+ end
76
+ end
77
+
78
+ puts builder
79
+ -----------------------------------------------------------------------------------------
80
+
81
+ .Alternate Example Usage
82
+ -----------------------------------------------------------------------------------------
83
+ puts TinyXml::Builder.new.html {
84
+ head {
85
+ title 'Hello World'
86
+ meta :name => :keywords, :content => 'hello, world'
87
+ meta :name => :description, :content => 'hello world sample usage for XML class'
88
+ }
89
+
90
+ body {
91
+ div(:id => 'main') { |div|
92
+ div.h1 "Hello World"
93
+ div.p "Hello HTML world", "from XML"
94
+ }
95
+ }
96
+ }
97
+ -----------------------------------------------------------------------------------------
98
+
99
+ both will output:
100
+
101
+ -----------------------------------------------------------------------------------------
102
+ <html>
103
+ <head>
104
+ <title>Hello World</title>
105
+ <meta name="keywords" content="hello, world" />
106
+ <meta name="description" content="hello world sample usage for XML class" />
107
+ </head>
108
+ <body>
109
+ <div id="main">
110
+ <h1>Hello World</h1>
111
+ <p>Hello HTML world</p>
112
+ <p>from XML</p>
113
+ </div>
114
+ </body>
115
+ </html>
116
+ -----------------------------------------------------------------------------------------
117
+
118
+ Requirements
119
+ ------------
120
+
121
+ NONE
122
+
123
+ Install
124
+ -------
125
+
126
+ *********************************
127
+ sudo gem install tiny_xml_builder
128
+ *********************************
129
+
130
+ License
131
+ -------
132
+
133
+ (The MIT License)
134
+
135
+ Copyright (c) 2010 Alexandru Ungur
136
+
137
+ Permission is hereby granted, free of charge, to any person obtaining
138
+ a copy of this software and associated documentation files (the
139
+ 'Software'), to deal in the Software without restriction, including
140
+ without limitation the rights to use, copy, modify, merge, publish,
141
+ distribute, sublicense, and/or sell copies of the Software, and to
142
+ permit persons to whom the Software is furnished to do so, subject to
143
+ the following conditions:
144
+
145
+ The above copyright notice and this permission notice shall be
146
+ included in all copies or substantial portions of the Software.
147
+
148
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
149
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
150
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
151
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
152
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
153
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
154
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
155
+
156
+ // vim: set syntax=asciidoc:
data/README.html ADDED
@@ -0,0 +1,682 @@
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
2
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
3
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
4
+ <head>
5
+ <meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
6
+ <meta name="generator" content="AsciiDoc 8.6.3" />
7
+ <title>Tiny XML Builder</title>
8
+ <style type="text/css">
9
+ /* Debug borders */
10
+ p, li, dt, dd, div, pre, h1, h2, h3, h4, h5, h6 {
11
+ /*
12
+ border: 1px solid red;
13
+ */
14
+ }
15
+
16
+ body {
17
+ margin: 1em 5% 1em 5%;
18
+ }
19
+
20
+ a {
21
+ color: blue;
22
+ text-decoration: underline;
23
+ }
24
+ a:visited {
25
+ color: fuchsia;
26
+ }
27
+
28
+ em {
29
+ font-style: italic;
30
+ color: navy;
31
+ }
32
+
33
+ strong {
34
+ font-weight: bold;
35
+ color: #083194;
36
+ }
37
+
38
+ tt {
39
+ color: navy;
40
+ }
41
+
42
+ h1, h2, h3, h4, h5, h6 {
43
+ color: #527bbd;
44
+ font-family: sans-serif;
45
+ margin-top: 1.2em;
46
+ margin-bottom: 0.5em;
47
+ line-height: 1.3;
48
+ }
49
+
50
+ h1, h2, h3 {
51
+ border-bottom: 2px solid silver;
52
+ }
53
+ h2 {
54
+ padding-top: 0.5em;
55
+ }
56
+ h3 {
57
+ float: left;
58
+ }
59
+ h3 + * {
60
+ clear: left;
61
+ }
62
+
63
+ div.sectionbody {
64
+ font-family: serif;
65
+ margin-left: 0;
66
+ }
67
+
68
+ hr {
69
+ border: 1px solid silver;
70
+ }
71
+
72
+ p {
73
+ margin-top: 0.5em;
74
+ margin-bottom: 0.5em;
75
+ }
76
+
77
+ ul, ol, li > p {
78
+ margin-top: 0;
79
+ }
80
+
81
+ pre {
82
+ padding: 0;
83
+ margin: 0;
84
+ }
85
+
86
+ span#author {
87
+ color: #527bbd;
88
+ font-family: sans-serif;
89
+ font-weight: bold;
90
+ font-size: 1.1em;
91
+ }
92
+ span#email {
93
+ }
94
+ span#revnumber, span#revdate, span#revremark {
95
+ font-family: sans-serif;
96
+ }
97
+
98
+ div#footer {
99
+ font-family: sans-serif;
100
+ font-size: small;
101
+ border-top: 2px solid silver;
102
+ padding-top: 0.5em;
103
+ margin-top: 4.0em;
104
+ }
105
+ div#footer-text {
106
+ float: left;
107
+ padding-bottom: 0.5em;
108
+ }
109
+ div#footer-badges {
110
+ float: right;
111
+ padding-bottom: 0.5em;
112
+ }
113
+
114
+ div#preamble {
115
+ margin-top: 1.5em;
116
+ margin-bottom: 1.5em;
117
+ }
118
+ div.tableblock, div.imageblock, div.exampleblock, div.verseblock,
119
+ div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock,
120
+ div.admonitionblock {
121
+ margin-top: 0.25em;
122
+ margin-bottom: 1.5em;
123
+ }
124
+ div.admonitionblock {
125
+ margin-top: 2.5em;
126
+ margin-bottom: 2.5em;
127
+ }
128
+
129
+ div.content { /* Block element content. */
130
+ padding: 0;
131
+ }
132
+
133
+ /* Block element titles. */
134
+ div.title, caption.title {
135
+ color: #527bbd;
136
+ font-family: sans-serif;
137
+ font-weight: bold;
138
+ text-align: left;
139
+ margin-top: 1.0em;
140
+ margin-bottom: 0.5em;
141
+ }
142
+ div.title + * {
143
+ margin-top: 0;
144
+ }
145
+
146
+ td div.title:first-child {
147
+ margin-top: 0.0em;
148
+ }
149
+ div.content div.title:first-child {
150
+ margin-top: 0.0em;
151
+ }
152
+ div.content + div.title {
153
+ margin-top: 0.0em;
154
+ }
155
+
156
+ div.sidebarblock > div.content {
157
+ background: #ffffee;
158
+ border: 1px solid silver;
159
+ padding: 0.5em;
160
+ }
161
+
162
+ div.listingblock > div.content {
163
+ border: 1px solid silver;
164
+ background: #f4f4f4;
165
+ padding: 0.5em;
166
+ }
167
+
168
+ div.quoteblock {
169
+ padding-left: 2.0em;
170
+ margin-right: 10%;
171
+ }
172
+ div.quoteblock > div.attribution {
173
+ padding-top: 0.5em;
174
+ text-align: right;
175
+ }
176
+
177
+ div.verseblock {
178
+ padding-left: 2.0em;
179
+ margin-right: 10%;
180
+ }
181
+ div.verseblock > div.content {
182
+ white-space: pre;
183
+ }
184
+ div.verseblock > div.attribution {
185
+ padding-top: 0.75em;
186
+ text-align: left;
187
+ }
188
+ /* DEPRECATED: Pre version 8.2.7 verse style literal block. */
189
+ div.verseblock + div.attribution {
190
+ text-align: left;
191
+ }
192
+
193
+ div.admonitionblock .icon {
194
+ vertical-align: top;
195
+ font-size: 1.1em;
196
+ font-weight: bold;
197
+ text-decoration: underline;
198
+ color: #527bbd;
199
+ padding-right: 0.5em;
200
+ }
201
+ div.admonitionblock td.content {
202
+ padding-left: 0.5em;
203
+ border-left: 2px solid silver;
204
+ }
205
+
206
+ div.exampleblock > div.content {
207
+ border-left: 2px solid silver;
208
+ padding: 0.5em;
209
+ }
210
+
211
+ div.imageblock div.content { padding-left: 0; }
212
+ span.image img { border-style: none; }
213
+ a.image:visited { color: white; }
214
+
215
+ dl {
216
+ margin-top: 0.8em;
217
+ margin-bottom: 0.8em;
218
+ }
219
+ dt {
220
+ margin-top: 0.5em;
221
+ margin-bottom: 0;
222
+ font-style: normal;
223
+ color: navy;
224
+ }
225
+ dd > *:first-child {
226
+ margin-top: 0.1em;
227
+ }
228
+
229
+ ul, ol {
230
+ list-style-position: outside;
231
+ }
232
+ ol.arabic {
233
+ list-style-type: decimal;
234
+ }
235
+ ol.loweralpha {
236
+ list-style-type: lower-alpha;
237
+ }
238
+ ol.upperalpha {
239
+ list-style-type: upper-alpha;
240
+ }
241
+ ol.lowerroman {
242
+ list-style-type: lower-roman;
243
+ }
244
+ ol.upperroman {
245
+ list-style-type: upper-roman;
246
+ }
247
+
248
+ div.compact ul, div.compact ol,
249
+ div.compact p, div.compact p,
250
+ div.compact div, div.compact div {
251
+ margin-top: 0.1em;
252
+ margin-bottom: 0.1em;
253
+ }
254
+
255
+ div.tableblock > table {
256
+ border: 3px solid #527bbd;
257
+ }
258
+ thead {
259
+ font-family: sans-serif;
260
+ font-weight: bold;
261
+ }
262
+ tfoot {
263
+ font-weight: bold;
264
+ }
265
+ td > div.verse {
266
+ white-space: pre;
267
+ }
268
+ p.table {
269
+ margin-top: 0;
270
+ }
271
+ /* Because the table frame attribute is overriden by CSS in most browsers. */
272
+ div.tableblock > table[frame="void"] {
273
+ border-style: none;
274
+ }
275
+ div.tableblock > table[frame="hsides"] {
276
+ border-left-style: none;
277
+ border-right-style: none;
278
+ }
279
+ div.tableblock > table[frame="vsides"] {
280
+ border-top-style: none;
281
+ border-bottom-style: none;
282
+ }
283
+
284
+
285
+ div.hdlist {
286
+ margin-top: 0.8em;
287
+ margin-bottom: 0.8em;
288
+ }
289
+ div.hdlist tr {
290
+ padding-bottom: 15px;
291
+ }
292
+ dt.hdlist1.strong, td.hdlist1.strong {
293
+ font-weight: bold;
294
+ }
295
+ td.hdlist1 {
296
+ vertical-align: top;
297
+ font-style: normal;
298
+ padding-right: 0.8em;
299
+ color: navy;
300
+ }
301
+ td.hdlist2 {
302
+ vertical-align: top;
303
+ }
304
+ div.hdlist.compact tr {
305
+ margin: 0;
306
+ padding-bottom: 0;
307
+ }
308
+
309
+ .comment {
310
+ background: yellow;
311
+ }
312
+
313
+ .footnote, .footnoteref {
314
+ font-size: 0.8em;
315
+ }
316
+
317
+ span.footnote, span.footnoteref {
318
+ vertical-align: super;
319
+ }
320
+
321
+ #footnotes {
322
+ margin: 20px 0 20px 0;
323
+ padding: 7px 0 0 0;
324
+ }
325
+
326
+ #footnotes div.footnote {
327
+ margin: 0 0 5px 0;
328
+ }
329
+
330
+ #footnotes hr {
331
+ border: none;
332
+ border-top: 1px solid silver;
333
+ height: 1px;
334
+ text-align: left;
335
+ margin-left: 0;
336
+ width: 20%;
337
+ min-width: 100px;
338
+ }
339
+
340
+
341
+ @media print {
342
+ div#footer-badges { display: none; }
343
+ }
344
+
345
+ div#toctitle {
346
+ color: #527bbd;
347
+ font-family: sans-serif;
348
+ font-size: 1.1em;
349
+ font-weight: bold;
350
+ margin-top: 1.0em;
351
+ margin-bottom: 0.1em;
352
+ }
353
+
354
+ div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 {
355
+ margin-top: 0;
356
+ margin-bottom: 0;
357
+ }
358
+ div.toclevel2 {
359
+ margin-left: 2em;
360
+ font-size: 0.9em;
361
+ }
362
+ div.toclevel3 {
363
+ margin-left: 4em;
364
+ font-size: 0.9em;
365
+ }
366
+ div.toclevel4 {
367
+ margin-left: 6em;
368
+ font-size: 0.9em;
369
+ }
370
+ </style>
371
+ <script type="text/javascript">
372
+ /*<![CDATA[*/
373
+ window.onload = function(){asciidoc.footnotes(); asciidoc.toc(2);}
374
+ var asciidoc = { // Namespace.
375
+
376
+ /////////////////////////////////////////////////////////////////////
377
+ // Table Of Contents generator
378
+ /////////////////////////////////////////////////////////////////////
379
+
380
+ /* Author: Mihai Bazon, September 2002
381
+ * http://students.infoiasi.ro/~mishoo
382
+ *
383
+ * Table Of Content generator
384
+ * Version: 0.4
385
+ *
386
+ * Feel free to use this script under the terms of the GNU General Public
387
+ * License, as long as you do not remove or alter this notice.
388
+ */
389
+
390
+ /* modified by Troy D. Hanson, September 2006. License: GPL */
391
+ /* modified by Stuart Rackham, 2006, 2009. License: GPL */
392
+
393
+ // toclevels = 1..4.
394
+ toc: function (toclevels) {
395
+
396
+ function getText(el) {
397
+ var text = "";
398
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
399
+ if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants.
400
+ text += i.data;
401
+ else if (i.firstChild != null)
402
+ text += getText(i);
403
+ }
404
+ return text;
405
+ }
406
+
407
+ function TocEntry(el, text, toclevel) {
408
+ this.element = el;
409
+ this.text = text;
410
+ this.toclevel = toclevel;
411
+ }
412
+
413
+ function tocEntries(el, toclevels) {
414
+ var result = new Array;
415
+ var re = new RegExp('[hH]([2-'+(toclevels+1)+'])');
416
+ // Function that scans the DOM tree for header elements (the DOM2
417
+ // nodeIterator API would be a better technique but not supported by all
418
+ // browsers).
419
+ var iterate = function (el) {
420
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
421
+ if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
422
+ var mo = re.exec(i.tagName);
423
+ if (mo)
424
+ result[result.length] = new TocEntry(i, getText(i), mo[1]-1);
425
+ iterate(i);
426
+ }
427
+ }
428
+ }
429
+ iterate(el);
430
+ return result;
431
+ }
432
+
433
+ var toc = document.getElementById("toc");
434
+ var entries = tocEntries(document.getElementById("content"), toclevels);
435
+ for (var i = 0; i < entries.length; ++i) {
436
+ var entry = entries[i];
437
+ if (entry.element.id == "")
438
+ entry.element.id = "_toc_" + i;
439
+ var a = document.createElement("a");
440
+ a.href = "#" + entry.element.id;
441
+ a.appendChild(document.createTextNode(entry.text));
442
+ var div = document.createElement("div");
443
+ div.appendChild(a);
444
+ div.className = "toclevel" + entry.toclevel;
445
+ toc.appendChild(div);
446
+ }
447
+ if (entries.length == 0)
448
+ toc.parentNode.removeChild(toc);
449
+ },
450
+
451
+
452
+ /////////////////////////////////////////////////////////////////////
453
+ // Footnotes generator
454
+ /////////////////////////////////////////////////////////////////////
455
+
456
+ /* Based on footnote generation code from:
457
+ * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html
458
+ */
459
+
460
+ footnotes: function () {
461
+ var cont = document.getElementById("content");
462
+ var noteholder = document.getElementById("footnotes");
463
+ var spans = cont.getElementsByTagName("span");
464
+ var refs = {};
465
+ var n = 0;
466
+ for (i=0; i<spans.length; i++) {
467
+ if (spans[i].className == "footnote") {
468
+ n++;
469
+ // Use [\s\S] in place of . so multi-line matches work.
470
+ // Because JavaScript has no s (dotall) regex flag.
471
+ note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1];
472
+ noteholder.innerHTML +=
473
+ "<div class='footnote' id='_footnote_" + n + "'>" +
474
+ "<a href='#_footnoteref_" + n + "' title='Return to text'>" +
475
+ n + "</a>. " + note + "</div>";
476
+ spans[i].innerHTML =
477
+ "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +
478
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
479
+ var id =spans[i].getAttribute("id");
480
+ if (id != null) refs["#"+id] = n;
481
+ }
482
+ }
483
+ if (n == 0)
484
+ noteholder.parentNode.removeChild(noteholder);
485
+ else {
486
+ // Process footnoterefs.
487
+ for (i=0; i<spans.length; i++) {
488
+ if (spans[i].className == "footnoteref") {
489
+ var href = spans[i].getElementsByTagName("a")[0].getAttribute("href");
490
+ href = href.match(/#.*/)[0]; // Because IE return full URL.
491
+ n = refs[href];
492
+ spans[i].innerHTML =
493
+ "[<a href='#_footnote_" + n +
494
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
495
+ }
496
+ }
497
+ }
498
+ }
499
+
500
+ }
501
+ /*]]>*/
502
+ </script>
503
+ </head>
504
+ <body class="article">
505
+ <div id="header">
506
+ <h1>Tiny XML Builder</h1>
507
+ <span id="author">Alexandru Ungur</span><br />
508
+ <span id="email"><tt>&lt;<a href="mailto:alexaandru@gmail.com">alexaandru@gmail.com</a>&gt;</tt></span><br />
509
+ <div id="toc">
510
+ <div id="toctitle">Table of Contents</div>
511
+ <noscript><p><b>JavaScript must be enabled in your browser to display the table of contents.</b></p></noscript>
512
+ </div>
513
+ </div>
514
+ <div id="content">
515
+ <div class="sect1">
516
+ <h2 id="_description">Description</h2>
517
+ <div class="sectionbody">
518
+ <div class="paragraph"><p>A very simple XML builder class.<br />
519
+ I wanted something really simple that I could easily extend myself later on if I needed to.<br />
520
+ Ironically, in four years since I created and used TinyXml, I never needed to extend it :-)
521
+ I figured, it may as well work for others in that case, so here it is.</p></div>
522
+ </div>
523
+ </div>
524
+ <div class="sect1">
525
+ <h2 id="_acknowledgements">Acknowledgements</h2>
526
+ <div class="sectionbody">
527
+ <div class="paragraph"><p>A big thanks to Jim Weirich for his great advices on Ruby-talk.<br />
528
+ The BlankSlate "mechanism" he describes at: <a href="http://onestepback.org/index.cgi/Tech/Ruby/BlankSlate.rdoc">http://onestepback.org/index.cgi/Tech/Ruby/BlankSlate.rdoc</a>
529
+ and which this library depends upon, is one of the first things I&#8217;ve learnt when started to play with Ruby DSLs.</p></div>
530
+ </div>
531
+ </div>
532
+ <div class="sect1">
533
+ <h2 id="_features_problems">Features/Problems</h2>
534
+ <div class="sectionbody">
535
+ <div class="ulist"><ul>
536
+ <li>
537
+ <p>
538
+ You cannot have XML elements named <em>__id__</em>, <em>__send__</em>, <em>method_missing</em>, <em>instance_eval</em> or <em>respond_to</em> as those are NOT undefined (on purpose) by BlankSlate mechanism;
539
+ </p>
540
+ </li>
541
+ <li>
542
+ <p>
543
+ There are other limitations related to &#8220;implicit receiver&#8221; calls, e.g.:
544
+ </p>
545
+ </li>
546
+ </ul></div>
547
+ <div class="listingblock">
548
+ <div class="title">Explicit receiver example</div>
549
+ <div class="content">
550
+ <pre><tt>puts TinyXml::Builder.new.foo {|f| f.p 'bar'}</tt></pre>
551
+ </div></div>
552
+ <div class="paragraph"><p>will output:</p></div>
553
+ <div class="listingblock">
554
+ <div class="content">
555
+ <pre><tt>&lt;foo&gt;
556
+ &lt;p&gt;bar&lt;/p&gt;
557
+ &lt;/foo&gt;</tt></pre>
558
+ </div></div>
559
+ <div class="paragraph"><p>while the following:</p></div>
560
+ <div class="listingblock">
561
+ <div class="title">Implicit receiver example</div>
562
+ <div class="content">
563
+ <pre><tt>puts TinyXml::Builder.new.foo { p 'bar' }</tt></pre>
564
+ </div></div>
565
+ <div class="paragraph"><p>will output:</p></div>
566
+ <div class="listingblock">
567
+ <div class="content">
568
+ <pre><tt>"bar"
569
+ &lt;foo&gt;
570
+ &lt;/foo&gt;</tt></pre>
571
+ </div></div>
572
+ <div class="paragraph"><p>as "p" method exists in outer scope and does an entirely different thing than what (missing) methods of TinyXml do.</p></div>
573
+ </div>
574
+ </div>
575
+ <div class="sect1">
576
+ <h2 id="_synopsis">Synopsis</h2>
577
+ <div class="sectionbody">
578
+ <div class="listingblock">
579
+ <div class="title">Example Usage</div>
580
+ <div class="content">
581
+ <pre><tt>builder = TinyXml::Builder.new
582
+ builder.html do |xhtml|
583
+ xhtml.head do |head|
584
+ head.title 'Hello World'
585
+ head.meta :name =&gt; :keywords, :content =&gt; 'hello, world'
586
+ head.meta :name =&gt; :description, :content =&gt; 'hello world sample usage for XML class'
587
+ end
588
+ xhtml.body do |body|
589
+ body.div :id =&gt; 'main' do |div_main|
590
+ div_main.h1 "Hello World"
591
+ div_main.p "Hello HTML world", "from XML"
592
+ end
593
+ end
594
+ end
595
+
596
+ puts builder</tt></pre>
597
+ </div></div>
598
+ <div class="listingblock">
599
+ <div class="title">Alternate Example Usage</div>
600
+ <div class="content">
601
+ <pre><tt>puts TinyXml::Builder.new.html {
602
+ head {
603
+ title 'Hello World'
604
+ meta :name =&gt; :keywords, :content =&gt; 'hello, world'
605
+ meta :name =&gt; :description, :content =&gt; 'hello world sample usage for XML class'
606
+ }
607
+
608
+ body {
609
+ div(:id =&gt; 'main') { |div|
610
+ div.h1 "Hello World"
611
+ div.p "Hello HTML world", "from XML"
612
+ }
613
+ }
614
+ }</tt></pre>
615
+ </div></div>
616
+ <div class="paragraph"><p>both will output:</p></div>
617
+ <div class="listingblock">
618
+ <div class="content">
619
+ <pre><tt>&lt;html&gt;
620
+ &lt;head&gt;
621
+ &lt;title&gt;Hello World&lt;/title&gt;
622
+ &lt;meta name="keywords" content="hello, world" /&gt;
623
+ &lt;meta name="description" content="hello world sample usage for XML class" /&gt;
624
+ &lt;/head&gt;
625
+ &lt;body&gt;
626
+ &lt;div id="main"&gt;
627
+ &lt;h1&gt;Hello World&lt;/h1&gt;
628
+ &lt;p&gt;Hello HTML world&lt;/p&gt;
629
+ &lt;p&gt;from XML&lt;/p&gt;
630
+ &lt;/div&gt;
631
+ &lt;/body&gt;
632
+ &lt;/html&gt;</tt></pre>
633
+ </div></div>
634
+ </div>
635
+ </div>
636
+ <div class="sect1">
637
+ <h2 id="_requirements">Requirements</h2>
638
+ <div class="sectionbody">
639
+ <div class="paragraph"><p>NONE</p></div>
640
+ </div>
641
+ </div>
642
+ <div class="sect1">
643
+ <h2 id="_install">Install</h2>
644
+ <div class="sectionbody">
645
+ <div class="sidebarblock">
646
+ <div class="content">
647
+ <div class="paragraph"><p>sudo gem install tiny_xml_builder</p></div>
648
+ </div></div>
649
+ </div>
650
+ </div>
651
+ <div class="sect1">
652
+ <h2 id="_license">License</h2>
653
+ <div class="sectionbody">
654
+ <div class="paragraph"><p>(The MIT License)</p></div>
655
+ <div class="paragraph"><p>Copyright (c) 2010 Alexandru Ungur</p></div>
656
+ <div class="paragraph"><p>Permission is hereby granted, free of charge, to any person obtaining
657
+ a copy of this software and associated documentation files (the
658
+ <em>Software</em>), to deal in the Software without restriction, including
659
+ without limitation the rights to use, copy, modify, merge, publish,
660
+ distribute, sublicense, and/or sell copies of the Software, and to
661
+ permit persons to whom the Software is furnished to do so, subject to
662
+ the following conditions:</p></div>
663
+ <div class="paragraph"><p>The above copyright notice and this permission notice shall be
664
+ included in all copies or substantial portions of the Software.</p></div>
665
+ <div class="paragraph"><p>THE SOFTWARE IS PROVIDED <em>AS IS</em>, WITHOUT WARRANTY OF ANY KIND,
666
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
667
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
668
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
669
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
670
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
671
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.</p></div>
672
+ </div>
673
+ </div>
674
+ </div>
675
+ <div id="footnotes"><hr /></div>
676
+ <div id="footer">
677
+ <div id="footer-text">
678
+ Last updated 2011-02-04 14:02:13 EET
679
+ </div>
680
+ </div>
681
+ </body>
682
+ </html>
data/Rakefile ADDED
@@ -0,0 +1,21 @@
1
+ begin
2
+ require 'bones'
3
+ rescue LoadError
4
+ abort '### Please install the "bones" gem ###'
5
+ end
6
+
7
+ task :default => 'test:run'
8
+ task 'gem:release' => 'test:run'
9
+
10
+ ver = `cat version.txt`.strip
11
+
12
+ Bones {
13
+ name 'tiny_xml_builder'
14
+ version ver
15
+ authors 'Alexandru Ungur'
16
+ email 'alexaandru@gmail.com'
17
+ url 'http://rubygems.com/gems/tiny_xml_builder'
18
+ readme_file 'README.asciidoc'
19
+ ignore_file '.gitignore'
20
+ depend_on 'blankslate'
21
+ }
@@ -0,0 +1,43 @@
1
+ require 'rubygems'
2
+ require 'blankslate'
3
+
4
+ module TinyXml
5
+ class Builder < BlankSlate
6
+ reveal :respond_to? unless RUBY_VERSION >= '1.9'
7
+ def initialize(opts = {}, &block)
8
+ @xml = []
9
+ @indent_level = opts[:indent_level] || opts['indent_level'] || 0
10
+ @indent_size = opts[:indent_size] || opts['indent_size'] || 2
11
+ block and instance_eval(&block)
12
+ end
13
+
14
+ def <<(xml)
15
+ @xml << xml.to_s
16
+ end
17
+
18
+ def to_s
19
+ @xml.join("\n")
20
+ end
21
+
22
+ def to_ary
23
+ [to_s]
24
+ end
25
+
26
+ def method_missing(tag, *args, &block)
27
+ indent = ' ' * @indent_level * @indent_size
28
+ attributes = args.last && args.last.is_a?(Hash) ? args.pop.inject(''){|acc,(k,v)| acc << " #{k}=\"#{v}\""} : ''
29
+ if block
30
+ @xml << "%s<%s%s>" % [indent, tag, attributes]
31
+ @indent_level += 1; instance_eval(&block); @indent_level -= 1
32
+ @xml << "%s</%s>" % [indent, tag]
33
+ elsif args.empty?
34
+ @xml << "%s<%s%s />" % [indent, tag, attributes]
35
+ else
36
+ args.map{|a| a && Array(a)}.flatten.each do |val|
37
+ @xml << "%s<%s%s>%s</%s>" % [indent, tag, attributes, val, tag]
38
+ end
39
+ end
40
+ self
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,71 @@
1
+ require 'test/unit'
2
+ require 'tiny_xml_builder'
3
+
4
+ class TinyXMLBuilderTest < Test::Unit::TestCase
5
+ def setup
6
+ @xml = TinyXml::Builder.new(:indent_size => (@indent_size = 4))
7
+ end
8
+
9
+ def test_passing_no_params
10
+ assert_equal '<zaza />', "#{@xml.zaza}"
11
+ end
12
+
13
+ def test_passing_a_nil_as_param
14
+ assert_equal '<zaza></zaza>', "#{@xml.zaza nil}"
15
+ end
16
+
17
+ def test_passing_one_param_that_is_a_hash
18
+ assert_equal '<zaza zuzu="zyzy" />', "#{@xml.zaza :zuzu => "zyzy"}"
19
+ end
20
+
21
+ def test_passing_one_simple_param
22
+ assert_equal '<zaza>123</zaza>', "#{@xml.zaza 123}"
23
+ end
24
+
25
+ def test_passing_an_enumerable
26
+ assert_equal "<zaza>1</zaza>\n<zaza>2</zaza>", "#{@xml.zaza 1..2}"
27
+ end
28
+
29
+ def test_passing_multiple_params
30
+ assert_equal "<zaza>1</zaza>\n<zaza>A</zaza>\n<zaza>Z</zaza>", "#{@xml.zaza 1, "A", :Z}"
31
+ end
32
+
33
+ def test_passing_a_simple_param_and_a_hash
34
+ assert_equal '<zaza zuzu="zumzum">123</zaza>', "#{@xml.zaza 123, :zuzu => "zumzum"}"
35
+ end
36
+
37
+ def test_passing_two_simple_params_and_a_hash
38
+ assert_equal %Q|<zaza zuzu="zumzum">123</zaza>\n<zaza zuzu="zumzum">456</zaza>|,
39
+ "#{@xml.zaza 123, 456, :zuzu => "zumzum"}"
40
+ end
41
+
42
+ def test_pushing_xml_directly
43
+ content = '<foo>bar</foo>'
44
+ @xml << content
45
+ assert_equal content, @xml.to_s
46
+ end
47
+
48
+ def test_passing_a_block
49
+ @xml.zuzu(:where => 'Hawaii') {
50
+ whatToDo {
51
+ swim "a lot"
52
+ justLayOnTheBeach
53
+ party { |p|
54
+ p.allNightLong "hoorayyyy", :must_do_this => true
55
+ }
56
+ }
57
+ }
58
+ expects = <<-EOS.strip
59
+ #{' ' * (0 * @indent_size)}<zuzu where="Hawaii">
60
+ #{' ' * (1 * @indent_size)}<whatToDo>
61
+ #{' ' * (2 * @indent_size)}<swim>a lot</swim>
62
+ #{' ' * (2 * @indent_size)}<justLayOnTheBeach />
63
+ #{' ' * (2 * @indent_size)}<party>
64
+ #{' ' * (3 * @indent_size)}<allNightLong must_do_this="true">hoorayyyy</allNightLong>
65
+ #{' ' * (2 * @indent_size)}</party>
66
+ #{' ' * (1 * @indent_size)}</whatToDo>
67
+ #{' ' * (0 * @indent_size)}</zuzu>
68
+ EOS
69
+ assert_equal expects, "#{@xml}"
70
+ end
71
+ end
data/version.txt ADDED
@@ -0,0 +1 @@
1
+ 0.0.3
metadata ADDED
@@ -0,0 +1,111 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: tiny_xml_builder
3
+ version: !ruby/object:Gem::Version
4
+ hash: 25
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 3
10
+ version: 0.0.3
11
+ platform: ruby
12
+ authors:
13
+ - Alexandru Ungur
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-02-10 00:00:00 +02:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: blankslate
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - "="
28
+ - !ruby/object:Gem::Version
29
+ hash: 105
30
+ segments:
31
+ - 2
32
+ - 1
33
+ - 2
34
+ - 3
35
+ version: 2.1.2.3
36
+ type: :runtime
37
+ version_requirements: *id001
38
+ - !ruby/object:Gem::Dependency
39
+ name: bones
40
+ prerelease: false
41
+ requirement: &id002 !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ hash: 27
47
+ segments:
48
+ - 3
49
+ - 6
50
+ - 2
51
+ version: 3.6.2
52
+ type: :development
53
+ version_requirements: *id002
54
+ description: |-
55
+ A very simple XML builder class. +
56
+ I wanted something really simple that I could easily extend myself later on if I needed to. +
57
+ Ironically, in four years since I created and used TinyXml, I never needed to extend it :-)
58
+ I figured, it may as well work for others in that case, so here it is.
59
+ email: alexaandru@gmail.com
60
+ executables: []
61
+
62
+ extensions: []
63
+
64
+ extra_rdoc_files:
65
+ - History.txt
66
+ files:
67
+ - .gitignore
68
+ - History.txt
69
+ - README.asciidoc
70
+ - README.html
71
+ - Rakefile
72
+ - lib/tiny_xml_builder.rb
73
+ - test/test_tiny_xml_builder.rb
74
+ - version.txt
75
+ has_rdoc: true
76
+ homepage: http://rubygems.com/gems/tiny_xml_builder
77
+ licenses: []
78
+
79
+ post_install_message:
80
+ rdoc_options:
81
+ - --main
82
+ - README.asciidoc
83
+ require_paths:
84
+ - lib
85
+ required_ruby_version: !ruby/object:Gem::Requirement
86
+ none: false
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ hash: 3
91
+ segments:
92
+ - 0
93
+ version: "0"
94
+ required_rubygems_version: !ruby/object:Gem::Requirement
95
+ none: false
96
+ requirements:
97
+ - - ">="
98
+ - !ruby/object:Gem::Version
99
+ hash: 3
100
+ segments:
101
+ - 0
102
+ version: "0"
103
+ requirements: []
104
+
105
+ rubyforge_project: tiny_xml_builder
106
+ rubygems_version: 1.3.7
107
+ signing_key:
108
+ specification_version: 3
109
+ summary: A very simple XML builder class.
110
+ test_files:
111
+ - test/test_tiny_xml_builder.rb