xhtml_report_generator 2.1.1 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +66 -6
- data/lib/xhtml_report_generator.rb +54 -15
- data/lib/xhtml_report_generator/custom.rb +25 -6
- data/lib/xhtml_report_generator/toc.js +5 -5
- data/lib/xhtml_report_generator/version.rb +1 -1
- metadata +13 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3aa1ee1460f949608080993ab68e93eab9298561
|
4
|
+
data.tar.gz: 3ac67dd1dcde669790405a065295abdcc223d36d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d5499730f068d0597fe8ae3f7fba1e1af58257a7b2ae52c11993e1f3ca0062fc095d8f0e6c48919ccb1141602ed3a6d7b5019d2059747f04c14466c2ee0e1553
|
7
|
+
data.tar.gz: f92130285b5d241af4c17a10068c2c18a155a29cfca58ca6024c20da4b0e1c8dc1f80ba87e3d8dba21dacddb077310080b835ad6922e547a5f73e28544190092
|
data/README.md
CHANGED
@@ -1,15 +1,20 @@
|
|
1
|
-
|
1
|
+
xhtml_report_generator
|
2
2
|
======================
|
3
3
|
|
4
|
-
This project was written to provide an easy way to create valid xhtml documents.
|
4
|
+
This project was written to provide an easy way to create valid xhtml or html documents.
|
5
5
|
Usecases are the automatic creation of reports (e.g. program logs) with automatically created table of contents.
|
6
|
-
|
7
|
-
only written to disk on demand. Hence in case of crashes the data might be lost.
|
6
|
+
xhtml_report_generator is not a Logger replacement, since the complete document is always kept in memory and
|
7
|
+
only written to disk on demand. Hence in case of crashes the data might be lost if you didn't write before.
|
8
|
+
|
9
|
+
Ruby version
|
10
|
+
-----
|
11
|
+
This gem was mainly tested with ruby version 2.2.3. Except of the test_encoding_issues unit tests, all other tests are
|
12
|
+
also passing with 1.9.3. Probably there were issues in ruby itself for earlier versions.
|
8
13
|
|
9
14
|
|
10
15
|
Example usage
|
11
16
|
-------------
|
12
|
-
In the following you can find a quick start on how to use
|
17
|
+
In the following you can find a quick start on how to use xhtml_report_generator.
|
13
18
|
Basically the project is built in a way that lets you supply your own methods for everything.
|
14
19
|
By default "custom.rb" is loaded through instance eval, so you can check the corresponding documentation for available methods.
|
15
20
|
|
@@ -21,9 +26,11 @@ Basically starting from version 2 the syntax for each method of custom.rb is uni
|
|
21
26
|
def method({"attribute" => "value", "attribute2" => "value2"}) {contents}
|
22
27
|
|
23
28
|
in addition the method naming convention was changed from camelCase to underscore to comply more with ruby conventions.
|
29
|
+
|
30
|
+
See <a href=http://www.rubydoc.info/gems/xhtml_report_generator/Custom>http://www.rubydoc.info/gems/xhtml_report_generator/Custom</> for the documentation of available methods.
|
24
31
|
|
25
32
|
<pre>
|
26
|
-
require '
|
33
|
+
require 'xhtml_report_generator'
|
27
34
|
|
28
35
|
gen1 = XhtmlReportGenerator::Generator.new
|
29
36
|
gen1.create_layout("Title")
|
@@ -33,9 +40,62 @@ gen1.heading("h3") {"section"}
|
|
33
40
|
gen1.content({"class"=>"bold"}) {"content function: Hallo welt <br /> html test <span class=\"r\" >red span test</span>"}
|
34
41
|
gen1.html("<p class=\"italic\">html function: Hallo welt <br /> html test <span class=\"r\" >red span test</span></p>")
|
35
42
|
gen1.highlight(/Ha.*lt/)
|
43
|
+
gen1.link("https://rubygems.org/gems/xhtml_report_generator/") {"download the gem"}
|
44
|
+
# browser will parse this as html (based on file extension)
|
45
|
+
gen1.write("myreport.html")
|
46
|
+
# browser will parse this as xhtml (based on file extension)
|
47
|
+
gen1.write("myreport.xhtml")
|
48
|
+
</pre>
|
49
|
+
|
50
|
+
Adding some graphs to your reports
|
51
|
+
----------------------------------
|
52
|
+
Due to the xml nature it is also easy to insert SVG graphs / pictures. Check out the svg-graph gem
|
53
|
+
|
54
|
+
<pre>
|
55
|
+
require 'xhtml_report_generator'
|
56
|
+
require 'SVG/Graph/Line'
|
57
|
+
require 'REXML/document'
|
58
|
+
|
59
|
+
gen1 = XhtmlReportGenerator::Generator.new
|
60
|
+
gen1.create_layout("Graph example")
|
61
|
+
gen1.heading("h1") {"my graph"}
|
62
|
+
|
63
|
+
x_axis = %w(Jan Feb Mar);
|
64
|
+
data_sales_02 = [12, 45, 21]
|
65
|
+
data_sales_03 = [15, 30, 40]
|
66
|
+
|
67
|
+
graph = SVG::Graph::Line.new({
|
68
|
+
:height => 300,
|
69
|
+
:width => 500,
|
70
|
+
:show_graph_title => true,
|
71
|
+
:graph_title => 'Graph Title',
|
72
|
+
:show_x_title => true,
|
73
|
+
:x_title => 'Month',
|
74
|
+
:show_y_title => true,
|
75
|
+
#:y_title_text_direction => :bt,
|
76
|
+
:y_title => 'cash',
|
77
|
+
:fields => x_axis})
|
78
|
+
|
79
|
+
graph.add_data({:data => data_sales_02, :title => 'Sales2002'})
|
80
|
+
graph.add_data({:data => data_sales_03, :title => 'Sales2003'})
|
81
|
+
|
82
|
+
# we can't add the entire xml document since multiple xml declarations are invalid
|
83
|
+
# so we add only
|
84
|
+
doc = REXML::Document.new(graph.burn())
|
85
|
+
svg = doc.elements["//svg"]
|
86
|
+
out = ''
|
87
|
+
f = REXML::Formatters::Pretty.new(0)
|
88
|
+
f.compact = true
|
89
|
+
f.write(svg, out)
|
90
|
+
|
91
|
+
gen1.html(out)
|
92
|
+
gen1.write("graph.xhtml")
|
36
93
|
|
37
94
|
</pre>
|
38
95
|
|
96
|
+
|
97
|
+
|
98
|
+
|
39
99
|
Changes from version 1.x to 2.x
|
40
100
|
-------------------------------
|
41
101
|
To ease with migration here is a list with the changed function names, please also check the new synopsis
|
@@ -1,8 +1,6 @@
|
|
1
|
-
#
|
2
|
-
# logfile.section
|
3
|
-
# logfil.content("mein resultat")
|
4
|
-
# logfile.markup(regexstart, regex end, :yellow)
|
1
|
+
# encoding: utf-8
|
5
2
|
require 'rexml/document'
|
3
|
+
require 'rexml/formatters/transitive'
|
6
4
|
|
7
5
|
module XhtmlReportGenerator
|
8
6
|
|
@@ -29,36 +27,73 @@ module XhtmlReportGenerator
|
|
29
27
|
}
|
30
28
|
# either use the default files provided with the gem, or those provided by the caller
|
31
29
|
symbols = symbols.merge(opts)
|
30
|
+
custom_rb_path = symbols[:custom_rb]
|
32
31
|
for key in symbols.keys do
|
33
32
|
# read the contents into the symbols hash
|
34
33
|
symbols[key] = File.read(symbols[key])
|
35
34
|
end
|
36
35
|
# load the custom module and extend it, use instance_eval otherwise the module will affect
|
37
36
|
# all existing Generator classes
|
38
|
-
instance_eval
|
37
|
+
instance_eval(symbols[:custom_rb], custom_rb_path)
|
39
38
|
|
40
39
|
@document = Generator.create_xhtml_document("Title")
|
41
40
|
head = @document.elements["//head"]
|
41
|
+
|
42
|
+
head.add_element("meta", {"charset" => "utf-8"})
|
43
|
+
|
42
44
|
# insert the custom css, and javascript files
|
43
45
|
style = head.add_element("style", {"type" => "text/css"})
|
44
|
-
|
45
|
-
style.add_text(REXML::CData.new("\n"+symbols[:css].gsub(/\n/, "")+"\n"))
|
46
|
+
cdata(symbols[:css], style)
|
46
47
|
|
47
48
|
style = head.add_element("style", {"type" => "text/css", "media"=>"print"})
|
48
|
-
|
49
|
+
cdata(symbols[:css_print], style)
|
49
50
|
|
50
51
|
script = head.add_element("script", {"type" => "text/javascript"})
|
51
|
-
|
52
|
+
cdata(symbols[:jquery], script)
|
52
53
|
|
53
54
|
script = head.add_element("script", {"type" => "text/javascript"})
|
54
|
-
|
55
|
+
cdata(symbols[:toc], script)
|
56
|
+
end
|
57
|
+
|
58
|
+
# Surrounds CData tag with c-style comments to remain compatible with normal html.
|
59
|
+
# For plain xhtml documents this is not needed.
|
60
|
+
# Example /*<![CDATA[*/\n ...content ... \n/*]]>*/
|
61
|
+
# @param str [String] the string to be enclosed in cdata
|
62
|
+
# @param parent_element [REXML::Element] the element to which cdata should be added
|
63
|
+
# @return [String] CDATA enclosed in c-style comments /**/
|
64
|
+
def cdata(str, parent_element)
|
65
|
+
f = REXML::Formatters::Transitive.new(0) # use Transitive to preserve source formatting
|
66
|
+
# somehow there is a problem with CDATA, any text added after will automatically go into the CDATA
|
67
|
+
# so we have do add a dummy node after the CDATA and then add the text.
|
68
|
+
parent_element.add_text("/*")
|
69
|
+
parent_element.add(REXML::CData.new("*/\n"+str+"\n/*"))
|
70
|
+
parent_element.add(REXML::Comment.new("dummy comment to make c-style comments for cdata work"))
|
71
|
+
parent_element.add_text("*/")
|
72
|
+
end
|
73
|
+
|
74
|
+
# Check if the give string is a valid UTF-8 byte sequence. If it is not valid UTF-8, then
|
75
|
+
# all invalid bytes are replaced by "\u2e2e" (\xe2\xb8\xae) ('REVERSED QUESTION MARK') because the default
|
76
|
+
# replacement character "\uFFFD" ('QUESTION MARK IN DIAMOND BOX') is two slots wide and might
|
77
|
+
# destroy mono spaced formatting
|
78
|
+
# @param str [String] of any encoding
|
79
|
+
# @return [String] UTF-8 encoded valid string
|
80
|
+
def encoding_fixer(str)
|
81
|
+
#if !str.force_encoding('UTF-8').valid_encoding?
|
82
|
+
# str.encode!('UTF-8', 'ISO-8859-1', {:invalid => :replace, :undef => :replace, :xml => :text})
|
83
|
+
#end
|
84
|
+
tmp = str.force_encoding('UTF-8').encode('UTF-8',{:invalid => :replace, :undef => :replace, :replace => "\u2e2e"})
|
85
|
+
# replace all special control chars as well but keep newline and whitespace "\u2e2e"
|
86
|
+
tmp.force_encoding('binary').gsub!(/[\x00-\x07\x0C-\x1F]|\xef\xbf\xbe|\xef\xbf\xbf/n, "\xe2\xb8\xae".force_encoding('binary'))
|
87
|
+
return tmp.force_encoding('UTF-8')
|
55
88
|
end
|
56
89
|
|
57
90
|
# Creates a minimal valid xhtml document including header title and body elements
|
58
91
|
# @param title [String] Title in the header section
|
59
92
|
def self.create_xhtml_document(title)
|
60
|
-
|
61
|
-
|
93
|
+
# don't use version 1.1 - firefox has not yet a parser vor xml 1.1
|
94
|
+
# https://bugzilla.mozilla.org/show_bug.cgi?id=233154
|
95
|
+
header = '<?xml version="1.0" encoding="UTF-8"?>'
|
96
|
+
header << '<!DOCTYPE html>'
|
62
97
|
|
63
98
|
doc = REXML::Document.new(header)
|
64
99
|
html = doc.add_element("html", {"xmlns" => "http://www.w3.org/1999/xhtml"})
|
@@ -71,14 +106,18 @@ module XhtmlReportGenerator
|
|
71
106
|
end
|
72
107
|
|
73
108
|
# returns the string representation of the xml document
|
74
|
-
# @param indent [Number] indent for child elements. defaults to 0.
|
109
|
+
# @param indent [Number] indent for child elements. defaults to 0.
|
110
|
+
# Note: if you change the indet this might destroy formatting of <pre> sections
|
111
|
+
# @return [String] formatted xml document
|
75
112
|
def to_s(indent = 0)
|
76
113
|
output = ""
|
77
114
|
# note : transitive is needed to preserve newlines in <pre> tags
|
78
115
|
# note2: the hash options syntax is supported only from ruby version >= 2.0.0 we need the old style
|
79
116
|
# for compatibility with 1.9.3
|
80
|
-
|
81
|
-
|
117
|
+
# @document.write({:output=>output, :indent=>indent, :transitive=>true})
|
118
|
+
# change to Formatters since document.write is deprecated
|
119
|
+
f = REXML::Formatters::Transitive.new(indent)
|
120
|
+
f.write(@document, output)
|
82
121
|
return output
|
83
122
|
end
|
84
123
|
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# encoding: utf-8
|
1
2
|
require 'base64'
|
2
3
|
# The module name doesn't matter, just make sure at the end to 'extend' it
|
3
4
|
# because it will be 'eval'ed by the initialize method of the XhtmlReportGenerator::Generator class.
|
@@ -28,7 +29,7 @@ module Custom
|
|
28
29
|
div.add_text("Quick Links")
|
29
30
|
div.add_element("br");div.add_element("br")
|
30
31
|
end
|
31
|
-
|
32
|
+
|
32
33
|
@div_middle = @body.add_element("div", {"class" => "middle"})
|
33
34
|
@layout = true
|
34
35
|
end
|
@@ -85,7 +86,7 @@ module Custom
|
|
85
86
|
@div_middle.insert_after(@current, temp)
|
86
87
|
@current = temp
|
87
88
|
raise "Block argument is mandatory" unless block_given?
|
88
|
-
text = block.call()
|
89
|
+
text = encoding_fixer(block.call())
|
89
90
|
@current.add_text(text)
|
90
91
|
return @current
|
91
92
|
end
|
@@ -100,7 +101,7 @@ module Custom
|
|
100
101
|
@div_middle.insert_after(@current, temp)
|
101
102
|
@current = temp
|
102
103
|
raise "Block argument is mandatory" unless block_given?
|
103
|
-
text = block.call()
|
104
|
+
text = encoding_fixer(block.call())
|
104
105
|
@current.add_text(text)
|
105
106
|
return @current
|
106
107
|
end
|
@@ -109,7 +110,8 @@ module Custom
|
|
109
110
|
# @param text [String] valid xhtml code which is included into the document
|
110
111
|
# @return [REXML::Element] the Element which was just added
|
111
112
|
def html(text)
|
112
|
-
# we need to create a new document with a pseudo root
|
113
|
+
# we need to create a new document with a pseudo root becaus having multiple nodes at top
|
114
|
+
# level is not valid xml
|
113
115
|
doc = REXML::Document.new("<root>"+text+"</root>")
|
114
116
|
# then we move all children of root to the actual div middle element and insert after current
|
115
117
|
for i in doc.root.to_a do
|
@@ -119,6 +121,23 @@ module Custom
|
|
119
121
|
return @current
|
120
122
|
end
|
121
123
|
|
124
|
+
# Appends a <a href = > node after the @current nodes
|
125
|
+
# @param href [String] this is the
|
126
|
+
# @param attrs [Hash] attributes for the <a> element
|
127
|
+
# @yieldreturn [String] the text to be added to the <a> element
|
128
|
+
# @return [REXML::Element] the Element which was just added
|
129
|
+
def link(href, attrs={}, &block)
|
130
|
+
temp = REXML::Element.new("a")
|
131
|
+
attrs.merge!({"href" => href})
|
132
|
+
temp.add_attributes(attrs)
|
133
|
+
@div_middle.insert_after(@current, temp)
|
134
|
+
@current = temp
|
135
|
+
raise "Block argument is mandatory" unless block_given?
|
136
|
+
text = encoding_fixer(block.call())
|
137
|
+
@current.add_text(text)
|
138
|
+
return @current
|
139
|
+
end
|
140
|
+
|
122
141
|
# @param path [String] absolute or relative path to the image that should be inserted into the report
|
123
142
|
# @param attrs [Hash] attributes for the <img> element, any valid html attributes can be specified
|
124
143
|
# you may specify attributes such "alt", "height", "width"
|
@@ -270,7 +289,7 @@ module Custom
|
|
270
289
|
@div_middle.insert_after(@current, temp)
|
271
290
|
@current = temp
|
272
291
|
raise "Block argument is mandatory" unless block_given?
|
273
|
-
text = block.call()
|
292
|
+
text = encoding_fixer(block.call())
|
274
293
|
@current.text = text
|
275
294
|
return @current
|
276
295
|
end
|
@@ -297,7 +316,7 @@ module Custom
|
|
297
316
|
|
298
317
|
@current = temp
|
299
318
|
raise "Block argument is mandatory" unless block_given?
|
300
|
-
text = block.call()
|
319
|
+
text = encoding_fixer(block.call())
|
301
320
|
@current.text = text
|
302
321
|
return @current
|
303
322
|
end
|
@@ -1,5 +1,5 @@
|
|
1
|
-
$(document).ready(function(){$("td").each(function(b){b=$(this);null!==b.html().match(/^passed$/)?b.attr("style","background-color:#19D119;"):null!==b.html().match(/^failed$/)?b.attr("style","background-color:#FF4719;"):null!==b.html().match(/^check$/)&&b.attr("style","background-color:#FFFF00;")});$("[class=rtoconly],[class=bothtoc]").each(function(b){var a=$(this),c=a.attr("class");a.attr("id",c+b);$("#rtoc").append("<a href='#"+c+b+"'>"+a.html()+"</a> <br />\n")});h3index=h2index=h1index=0
|
2
|
-
$(this);void 0==a.attr("id")&&a.attr("id","title"+b);if("
|
3
|
-
0;if("
|
4
|
-
e=!1;else c=" - ",e=!0;b.html(c);if("0"==a[2]){var d=new RegExp("div_fold_"+a[1]+"_[1-9]\\d*_0");$("div").filter(function(){return this.id.match(d)}).each(function(){$(this).children('a[id^="a_fold"]').html(c);$(this).toggle(e)});d=new RegExp("div_fold_"+a[1]+"_\\d+_[1-9]\\d*");$("div").filter(function(){return this.id.match(d)}).each(function(){$(this).children('a[id^="a_fold"]').html(c)
|
5
|
-
$(this).toggle(e)}))})});
|
1
|
+
$(document).ready(function(){$("td").each(function(b){b=$(this);null!==b.html().match(/^passed$/i)?b.attr("style","background-color:#19D119;"):null!==b.html().match(/^failed$/i)?b.attr("style","background-color:#FF4719;"):null!==b.html().match(/^check$/i)&&b.attr("style","background-color:#FFFF00;")});$("[class=rtoconly],[class=bothtoc]").each(function(b){var a=$(this),c=a.attr("class");a.attr("id",c+b);$("#rtoc").append("<a href='#"+c+b+"'>"+a.html()+"</a> <br />\n")});h3index=h2index=h1index=0;
|
2
|
+
$("h1, h2, h3, a.h2, a.h1").each(function(b){var a=$(this);void 0==a.attr("id")&&a.attr("id","title"+b);if("H1"==a.prop("tagName").toUpperCase())h1index+=1,h3index=h2index=0,a.prepend(h1index+" "),$("#ltoc").append("<br />\n"),lasth1="#"+a.attr("id"),lasth1cont=a.html();else if("H2"==a.prop("tagName").toUpperCase())h2index+=1,h3index=0,a.prepend(h1index+"."+h2index+" "),lasth2="#"+a.attr("id"),lasth2cont=a.html();else if("H3"==a.prop("tagName").toUpperCase())h3index+=1,a.prepend(h1index+"."+h2index+
|
3
|
+
"."+h3index+" ");else{if("H1"==a.attr("class").toUpperCase())return a.attr("href",lasth1),a.html(lasth1cont),0;if("H2"==a.attr("class").toUpperCase())return a.attr("href",lasth2),a.html(lasth2cont),0}if("undefined"!=typeof a.attr("class")&&"RTOCONLY"==a.attr("class").toUpperCase())return 0;$("#ltoc").append("<div id='div_fold_"+h1index+"_"+h2index+"_"+h3index+"'><a id='a_fold_"+h1index+"_"+h2index+"_"+h3index+"' style='cursor:pointer'> - </a> <a id='link"+b+"' href='#"+a.attr("id")+"' >"+
|
4
|
+
a.html()+"</a> <br /> </div>\n");return 0});$('a[id^="a_fold"]').click(function(){var b=$(this),a=b.attr("id").match(/(\d+)_(\d+)_(\d+)/);if(b.html().match(/-/))var c=" + ",e=!1;else c=" - ",e=!0;b.html(c);if("0"==a[2]){var d=new RegExp("div_fold_"+a[1]+"_[1-9]\\d*_0");$("div").filter(function(){return this.id.match(d)}).each(function(){$(this).children('a[id^="a_fold"]').html(c);$(this).toggle(e)});d=new RegExp("div_fold_"+a[1]+"_\\d+_[1-9]\\d*");$("div").filter(function(){return this.id.match(d)}).each(function(){$(this).children('a[id^="a_fold"]').html(c);
|
5
|
+
$(this).toggle(e)})}else"0"==a[3]&&(d=new RegExp("div_fold_"+a[1]+"_"+a[2]+"_[1-9]\\d*"),$("div").filter(function(){return this.id.match(d)}).each(function(){$(this).children('a[id^="a_fold"]').html(c);$(this).toggle(e)}))})});
|
metadata
CHANGED
@@ -1,25 +1,27 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: xhtml_report_generator
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Manuel Widmer
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2016-01-29 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
|
-
description: "The generator can be used to create xhtml files. It comes with
|
14
|
-
|
13
|
+
description: "The generator can be used to create html or xhtml files. It comes with
|
14
|
+
many utility functions.\n== Example usage\n gen1 = XhtmlReportGenerator::Generator.new\n
|
15
15
|
\ gen1.create_layout(\"Title\")\n gen1.heading(\"h1\", {\"class\" => \"bothtoc\"})
|
16
16
|
{\"titel\"}\n gen1.heading(\"h2\") {\"subtitel\"}\n gen1.heading(\"h3\") {\"section\"}\n
|
17
|
-
\ gen1.content({\"class\"=>\"bold\"}) {\"content function: Hallo welt
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
17
|
+
\ gen1.content({\"class\"=>\"bold\"}) {\"content function: Hallo welt <br /> html
|
18
|
+
test <span class=\"r\" >red span test</span>\"}\n gen1.html(\"<p class=\"italic\">html
|
19
|
+
function: Hallo welt <br /> html test <span class=\"r\" >red span test<span></p>\")\n
|
20
|
+
\ gen1.highlight(/Ha.*lt/)\n \nThe javascript to render the table of contents,
|
21
|
+
the custom generator functions and style sheet all can be\nsupplied by your own,
|
22
|
+
if necessary. By default there are methods to insert tables, links, paragraphs,
|
23
|
+
preformatted text\nand arbitrary xhtml code. Due to the xml nature it is also easy
|
24
|
+
to insert SVG graphs / pictures.\n\n"
|
23
25
|
email: m-widmer@gmx.ch
|
24
26
|
executables: []
|
25
27
|
extensions: []
|
@@ -57,5 +59,5 @@ rubyforge_project:
|
|
57
59
|
rubygems_version: 2.4.5.1
|
58
60
|
signing_key:
|
59
61
|
specification_version: 4
|
60
|
-
summary: A simple
|
62
|
+
summary: A simple html or xhtml generator to create human readable support
|
61
63
|
test_files: []
|