xhtml_report_generator 3.0.3 → 3.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 78b6c79e8a4be4c2bd9c2b5a824550c47ccc02b3
4
- data.tar.gz: a96047a216f7a553d6de6f9f48fca64c4d7790b6
3
+ metadata.gz: a3544c56a29c66abcc6c6ba3fb11ddc204b3198a
4
+ data.tar.gz: aeb8c4b728b729c3d88e428297dc5f13f5871ecf
5
5
  SHA512:
6
- metadata.gz: 94f0ece8702ec1534ccec2c13670f937c0ed41a389164bcf36e36ac9fc40cafc29777ec5b2fe167798161dc998d1d0a756f0c35e2530706d63fd36a545ae14a6
7
- data.tar.gz: ea980d45095e57bcda650ff70bf4a1b87628b441ce48bdba7a63ee46bb885dacf6eac1f67b1c7b78feddb143be870acb3555c9cf973d7f4732c4be8f6f2e0c0e
6
+ metadata.gz: 102f3476494f50f9d96d5a735fe33ae4714d74a70f422b47c0930c613b891d724b23e5ec59624a9361cc21f3e2982bf626bea5c15d772470fc1421760802aa58
7
+ data.tar.gz: f926db10047c34ddd95eaeb1a9eb7c0f0378cbfec795bc3999e4d8ce28478f813dd4284c7a4e41e97e8e15eb926aa3998eab84c0c3a15cbd96c6b9d2e12080aa
data/README.md CHANGED
@@ -48,9 +48,73 @@ By default "custom.rb" is loaded through instance eval, see
48
48
  [XhtmlReportGenerator/Generator](http://www.rubydoc.info/gems/xhtml_report_generator/XhtmlReportGenerator/Generator)
49
49
  for the documentation of available methods.
50
50
 
51
+ Advanced example1: custom tables including pictures or links
52
+ ----------------------------------
53
+ [Code] (../master/test/test.rb#L166-L233)
54
+
55
+ ```ruby
56
+ require 'xhtml_report_generator'
57
+ gen1 = XhtmlReportGenerator::Generator.new
58
+ gen1.create_layout("Custom Table")
59
+ gen1.heading("h1") {"custom styling"}
60
+ table_data = [
61
+ (0..9).collect{|i| i},
62
+ (10..19).collect{|i| i},
63
+ (20..29).collect{|i| i},
64
+ (30..39).collect{|i| i},
65
+ ]
66
+ table_opts = {
67
+ :headers => 3,
68
+ :data_is_xhtml => false,
69
+ :special => [
70
+ { # highlight all numbers from 0-13 green, only 11-13 should be green since the others are part of heading
71
+ condition: Proc.new { |e| (0 <= e.to_i) && (e.to_i <= 13) }, # a proc
72
+ attributes: {"style" => "background: #00FF00;"},
73
+ },
74
+ { # font-color the area if number contains a 3
75
+ row_index: 2..3,
76
+ col_index: 3..7,
77
+ condition: Proc.new { |e| e.to_s.match(/3/) }, # a proc
78
+ attributes: {"style" => "color: red;"},
79
+ },
80
+ { # red border around row 2-3 col with title 8
81
+ row_title: /[23]/,
82
+ col_title: "8",
83
+ condition: Proc.new { |e| true }, # a proc
84
+ attributes: {"style" => "border: 2px solid red;"},
85
+ },
86
+ { # black border around cell bottom right
87
+ row_index: 2,
88
+ col_index: 9,
89
+ condition: Proc.new { |e| true }, # a proc
90
+ attributes: {"style" => "border: 2px solid black;"},
91
+ },
92
+ ]
93
+ }
94
+ gen1.custom_table(table_data, table_opts)
95
+ gen1.heading("h1") {"Table Layout"}
96
+ table_opts = {
97
+ :headers => 0,
98
+ :data_is_xhtml => true,
99
+ }
51
100
 
101
+ a = gen1.get_code_html() {" blub\nblab\n\t\tblib"}
102
+ b = gen1.get_image_html("path/to/test.png", {"width" => "55", "height"=> "20", "alt" => "some_interesting_text"})
103
+ c = gen1.get_content_html() {" leading-whitespace removed"}
104
+ d = gen1.get_link_html("https://rubygems.org/gems/xhtml_report_generator/") {"download the gem"}
52
105
 
53
- Advanced example: including some graphs to your reports
106
+ table_data = [
107
+ [a, d],
108
+ [c, b]
109
+ ]
110
+ gen1.custom_table(table_data, table_opts)
111
+
112
+ gen1.write("path/to/CustomTable.xhtml")
113
+ ```
114
+ [Preview](https://cdn.rawgit.com/lumean/xhtml-report-generator/master/test/CustomTableReference.xhtml)
115
+
116
+
117
+ Advanced example2: including some graphs to your reports
54
118
  ----------------------------------
55
119
  Due to the xml nature it is also easy to insert SVG graphs / pictures. Check out the svg-graph gem
56
120
 
@@ -82,16 +146,8 @@ graph = SVG::Graph::Line.new({
82
146
  graph.add_data({:data => data_sales_02, :title => 'Sales2002'})
83
147
  graph.add_data({:data => data_sales_03, :title => 'Sales2003'})
84
148
 
85
- # we can't add the entire xml document since multiple xml declarations are invalid
86
- # so we add only the svg part
87
- doc = REXML::Document.new(graph.burn())
88
- svg = doc.elements["//svg"]
89
- out = ''
90
- f = REXML::Formatters::Pretty.new(0)
91
- f.compact = true
92
- f.write(svg, out)
93
-
94
- gen1.html(out)
149
+ # add the svg to the report
150
+ gen1.html(graph.burn_svg_only())
95
151
  gen1.write("graph.xhtml")
96
152
 
97
153
  ```
@@ -131,8 +187,6 @@ As a start you can copy the [custom.rb](../master/lib/xhtml_report_generator/cus
131
187
  default naming.
132
188
 
133
189
 
134
-
135
-
136
190
  Changes from version 2.x to 3.x
137
191
  -------------------------------
138
192
  The options for the initialize method "XhtmlReportGenerator::Generator.new" changed.
@@ -98,8 +98,33 @@ module Custom
98
98
  return out
99
99
  end
100
100
 
101
+ # @param elem [REXML::Element]
102
+ # @return [String]
103
+ def element_to_string(elem)
104
+ f = REXML::Formatters::Transitive.new(0) # use Transitive to preserve source formatting (e.g. <pre> tags)
105
+ out = ""
106
+ f.write(elem, out)
107
+ return out
108
+ end
109
+
110
+ # @see #code
111
+ # Instead of adding content to the report, this method returns the produced html code as a string.
112
+ # This can be used to insert code into #custom_table (with the option data_is_xhtml: true)
113
+ # @return [String] the code including <pre> tags as a string
114
+ def get_code_html(attrs={}, &block)
115
+ temp = REXML::Element.new("pre")
116
+ temp.add_attributes(attrs)
117
+ raise "Block argument is mandatory" unless block_given?
118
+ text = encoding_fixer(block.call())
119
+ temp.add_text(text)
120
+ element_to_string(temp)
121
+ end
122
+
101
123
  # Appends a <pre> node after the @current node
102
- # @param attrs [Hash] attributes for the <pre> element
124
+ # @param attrs [Hash] attributes for the <pre> element. The following classes can be passed as attributes and are predefined with a different
125
+ # background for your convenience !{"class" => "code0"} (light-blue), !{"class" => "code1"} (red-brown),
126
+ # !{"class" => "code2"} (light-green), !{"class" => "code3"} (light-yellow). You may also specify your own background
127
+ # as follows: !{"style" => "background: #FF00FF;"}.
103
128
  # @yieldreturn [String] the text to be added to the <pre> element
104
129
  # @return [REXML::Element] the Element which was just added
105
130
  def code(attrs={}, &block)
@@ -113,6 +138,19 @@ module Custom
113
138
  return @current
114
139
  end
115
140
 
141
+ # @see #content
142
+ # Instead of adding content to the report, this method returns the produced html code as a string.
143
+ # This can be used to insert code into #custom_table (with the option data_is_xhtml: true)
144
+ # @return [String] the code including <pre> tags as a string
145
+ def get_content_html(attrs={}, &block)
146
+ temp = REXML::Element.new("p")
147
+ temp.add_attributes(attrs)
148
+ raise "Block argument is mandatory" unless block_given?
149
+ text = encoding_fixer(block.call())
150
+ temp.add_text(text)
151
+ element_to_string(temp)
152
+ end
153
+
116
154
  # Appends a <p> node after the @current node
117
155
  # @param attrs [Hash] attributes for the <p> element
118
156
  # @yieldreturn [String] the text to be added to the <p> element
@@ -143,6 +181,20 @@ module Custom
143
181
  return @current
144
182
  end
145
183
 
184
+ # @see #link
185
+ # Instead of adding content to the report, this method returns the produced html code as a string.
186
+ # This can be used to insert code into #custom_table (with the option data_is_xhtml: true)
187
+ # @return [String] the code including <pre> tags as a string
188
+ def get_link_html(href, attrs={}, &block)
189
+ temp = REXML::Element.new("a")
190
+ attrs.merge!({"href" => href})
191
+ temp.add_attributes(attrs)
192
+ raise "Block argument is mandatory" unless block_given?
193
+ text = encoding_fixer(block.call())
194
+ temp.add_text(text)
195
+ element_to_string(temp)
196
+ end
197
+
146
198
  # Appends a <a href = > node after the @current nodes
147
199
  # @param href [String] this is the
148
200
  # @param attrs [Hash] attributes for the <a> element
@@ -160,6 +212,22 @@ module Custom
160
212
  return @current
161
213
  end
162
214
 
215
+ # @see #image
216
+ # Instead of adding content to the report, this method returns the produced html code as a string.
217
+ # This can be used to insert code into #custom_table (with the option data_is_xhtml: true)
218
+ # @return [String] the code including <pre> tags as a string
219
+ def get_image_html(path, attributes = {})
220
+ # read image as binary and do a base64 encoding
221
+ binary_data = Base64.strict_encode64(IO.binread(path))
222
+ type = File.extname(path).gsub('.', '')
223
+ # create the element
224
+ temp = REXML::Element.new("img")
225
+ # add the picture
226
+ temp.add_attribute("src","data:image/#{type};base64,#{binary_data}")
227
+ temp.add_attributes(attributes)
228
+ element_to_string(temp)
229
+ end
230
+
163
231
  # @param path [String] absolute or relative path to the image that should be inserted into the report
164
232
  # @param attributes [Hash] attributes for the <img> element, any valid html attributes can be specified
165
233
  # you may specify attributes such "alt", "height", "width"
@@ -187,7 +255,7 @@ module Custom
187
255
  # highlight_captures then puts a <span> </span> tag around all captures of the regex
188
256
  # NOTE: nested captures are not supported and don't make sense in this context!!
189
257
  # @param regex [Regexp] a regular expression that will be matched
190
- # @param color [String] at this point one of "y", "r", "g", "b" (yellow, red, green, blue) is supported
258
+ # @param color [String] either one of "y", "r", "g", "b" (yellow, red, green, blue) or a valid html color code (e.g. "#80BFFF")
191
259
  # @param el [REXML::Element] the Element (scope) which will be searched for pattern matches, by default the last inserted element will be scanned
192
260
  # @return [Fixnum] the number of highlighted captures
193
261
  def highlight_captures(regex, color="y", el = @current)
@@ -214,7 +282,14 @@ module Custom
214
282
  array
215
283
  }
216
284
  num_matches += positions.length
217
- replace_text_with_elements(el, i, "span", {"class" => color}, positions)
285
+ if ["y","r","g","b"].include?(color)
286
+ attr = {"class" => color}
287
+ elsif color.match(/^#[A-Fa-f0-9]{6}$/)
288
+ attr = {"style" => "background: #{color};"}
289
+ else
290
+ raise "invalid color: #{color}"
291
+ end
292
+ replace_text_with_elements(el, i, "span", attr, positions)
218
293
  else
219
294
  # for non-text nodes we recurse into it and finally reattach to our parent to preserve ordering
220
295
  num_matches += highlight_captures(regex, color, i)
@@ -231,7 +306,7 @@ module Custom
231
306
  # or match newlines explicitly.
232
307
  # highlight then puts a <span> </span> tag around all matches of regex
233
308
  # @param regex [Regexp] a regular expression that will be matched
234
- # @param color [String] at this point one of "y", "r", "g", "b" (yellow, red, green, blue) is supported
309
+ # @param color [String] either one of "y", "r", "g", "b" (yellow, red, green, blue) or a valid html color code (e.g. "#80BFFF")
235
310
  # @param el [REXML::Element] the Element (scope) which will be searched for pattern matches
236
311
  # @return [Fixnum] the number of highlighted captures
237
312
  def highlight(regex, color="y", el = @current)
@@ -254,7 +329,14 @@ module Custom
254
329
  Regexp.last_match.end(0)-Regexp.last_match.begin(0)]
255
330
  }
256
331
  num_matches += positions.length
257
- replace_text_with_elements(el, i, "span", {"class" => color}, positions)
332
+ if ["y","r","g","b"].include?(color)
333
+ attr = {"class" => color}
334
+ elsif color.match(/^#[A-Fa-f0-9]{6}$/)
335
+ attr = {"style" => "background: #{color};"}
336
+ else
337
+ raise "invalid color: #{color}"
338
+ end
339
+ replace_text_with_elements(el, i, "span", attr, positions)
258
340
  else
259
341
  # for non-text nodes we recurse into it and finally reattach to our parent to preserve ordering
260
342
  # puts "recurse"
@@ -272,23 +354,119 @@ module Custom
272
354
  # is equivalent to the bitwise AND of the two least significant bits with 1, 2 or 3
273
355
  # @return [REXML::Element] the Element which was just added
274
356
  def table(table_data, headers=0, table_attrs={}, tr_attrs={}, th_attrs={}, td_attrs={})
275
-
357
+ opts = {
358
+ headers: headers,
359
+ data_is_xhtml: false,
360
+ table_attrs: table_attrs,
361
+ th_attrs: th_attrs,
362
+ tr_attrs: tr_attrs,
363
+ td_attrs: td_attrs,
364
+ }
365
+ custom_table(table_data, opts)
366
+ end
367
+
368
+ # creates a html table from two dimensional array of the form Array [row] [col]
369
+ # @param table_data [Array<Array>] of the form Array [row] [col] containing all data, the '.to_s' method will be called on each element,
370
+ # @option opts [Number] :headers either of 0, 1, 2, 3. Where 0 is no headers (<th>) at all, 1 is only the first row,
371
+ # 2 is only the first column and 3 is both, first row and first column as <th> elements. Every other number
372
+ # is equivalent to the bitwise AND of the two least significant bits with 1, 2 or 3
373
+ # @option opts [Boolean] :data_is_xhtml defaults to false, if true table_data is inserted as xhtml without any sanitation or escaping.
374
+ # This way a table can be used for custom layouts.
375
+ # @option opts [Hash] :table_attrs html attributes for the <table> tag
376
+ # @option opts [Hash] :th_attrs html attributes for the <th> tag
377
+ # @option opts [Hash] :tr_attrs html attributes for the <tr> tag
378
+ # @option opts [Hash] :td_attrs html attributes for the <td> tag
379
+ # @option opts [Array<Hash>] :special Array of hashes for custom attributes on specific cells (<td> only) of the table
380
+ # @example Example of the :special attributes
381
+ # opts[:special] = [
382
+ # {
383
+ # col_title: 'rx_DroppedFrameCount', # string or regexp or nil # if neither title nor index are present, the condition is evaluated for all <td> cells
384
+ # col_index: 5..7, # Fixnum, Range or nil # index has precedence over title
385
+ # row_title: 'D_0_BE_iMix', # string or regexp or nil
386
+ # row_index: 6, # Fixnum, Range or nil
387
+ # condition: Proc.new { |e| Integer(e) != 0 }, # a proc
388
+ # attributes: {"style" => "background-color: #DB7093;"},
389
+ # },
390
+ # ]
391
+ # @return [REXML::Element] the Element which was just added
392
+ def custom_table(table_data, opts = {})
393
+ defaults = {
394
+ headers: 0,
395
+ data_is_xhtml: false,
396
+ table_attrs: {},
397
+ th_attrs: {},
398
+ tr_attrs: {},
399
+ td_attrs: {},
400
+ special: [],
401
+ }
402
+ o = defaults.merge(opts)
403
+
276
404
  temp = REXML::Element.new("table")
277
- temp.add_attributes(table_attrs)
405
+ temp.add_attributes(o[:table_attrs])
406
+ row_titles = table_data.collect{|row| row[0].to_s}
407
+ col_titles = table_data[0].collect{|title| title.to_s}
278
408
 
279
- for i in 0..table_data.length-1 do
280
- row = temp.add_element("tr", tr_attrs)
281
- for j in 0..table_data[i].length-1 do
282
- if (i == 0 && (0x1 & headers)==0x1)
283
- col = row.add_element("th", th_attrs)
284
- elsif (j == 0 && (0x2 & headers)==0x2)
285
- col = row.add_element("th", th_attrs)
286
- elsif ((i == 0 || j ==0) && (0x3 & headers)==0x3)
287
- col = row.add_element("th", th_attrs)
409
+ for i in 0..table_data.length-1 do # row
410
+ row = temp.add_element("tr", o[:tr_attrs])
411
+ for j in 0..table_data[i].length-1 do # column
412
+ if (i == 0 && (0x1 & o[:headers])==0x1)
413
+ col = row.add_element("th", o[:th_attrs])
414
+ elsif (j == 0 && (0x2 & o[:headers])==0x2)
415
+ col = row.add_element("th", o[:th_attrs])
416
+ elsif ((i == 0 || j ==0) && (0x3 & o[:headers])==0x3)
417
+ col = row.add_element("th", o[:th_attrs])
288
418
  else
289
- col = row.add_element("td", td_attrs)
419
+ _td_attrs = o[:td_attrs].clone
420
+
421
+ o[:special].each do |h|
422
+ # check if the current cell is a candidate for special
423
+ if !h[:col_index].nil?
424
+ if h[:col_index].is_a?(Range)
425
+ next if (!h[:col_index].include?(j)) # skip if not in range
426
+ elsif h[:col_index].is_a?(Integer)
427
+ next if (h[:col_index] != j) # skip if not at index
428
+ end
429
+ elsif !h[:col_title].nil?
430
+ next if !col_titles[j].match(h[:col_title])
431
+ end
432
+ # check if the current cell is a candidate for special
433
+ if !h[:row_index].nil?
434
+ if h[:row_index].is_a?(Range)
435
+ next if (!h[:row_index].include?(i)) # skip if not in range
436
+ elsif h[:row_index].is_a?(Integer)
437
+ next if (h[:row_index] != i) # skip if not at index
438
+ end
439
+ elsif !h[:row_title].nil?
440
+ next if !row_titles[i].match(h[:row_title])
441
+ end
442
+
443
+ # here we are a candidate for special, so we check if we meet the condition
444
+ if h[:condition].call(table_data[i][j])
445
+ h[:attributes].each { |attr, val|
446
+ if !_td_attrs[attr].nil?
447
+ # assume the existing attribute is a string (other types don't make much sense for html)
448
+ _td_attrs[attr] << val
449
+ else
450
+ # create the attribute if it is not already there
451
+ _td_attrs[attr] = val
452
+ end
453
+ }
454
+ end
455
+ end
456
+
457
+ col = row.add_element("td", _td_attrs)
458
+ end
459
+ if o[:data_is_xhtml]
460
+ # we need to create a new document with a pseudo root because having multiple nodes at top
461
+ # level is not valid xml
462
+ doc = REXML::Document.new("<root>" + table_data[i][j].to_s + "</root>")
463
+ # then we move all children of root to the actual div middle element and insert after current
464
+ for elem in doc.root.to_a do
465
+ col.add_element(elem) # add the td element
466
+ end
467
+ else
468
+ col.add_text(table_data[i][j].to_s)
290
469
  end
291
- col.add_text(table_data[i][j].to_s)
292
470
  end
293
471
  end
294
472
 
@@ -296,6 +474,7 @@ module Custom
296
474
  @current = temp
297
475
  return @current
298
476
  end
477
+
299
478
 
300
479
  # Appends a new heading element to body, and sets current to this new heading
301
480
  # @param tag_type [String] specifiy "h1", "h2", "h3" for the heading, defaults to "h1"
@@ -1,5 +1,5 @@
1
1
  module XhtmlReportGenerator
2
- VERSION = '3.0.3'
2
+ VERSION = '3.1.0'
3
3
  end
4
4
 
5
5
  # puts XhtmlReportGenerator::VERSION
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: xhtml_report_generator
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.3
4
+ version: 3.1.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: 2016-09-01 00:00:00.000000000 Z
11
+ date: 2016-09-30 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: "The generator can be used to create html or xhtml files. It comes with
14
14
  many utility functions.\n \nThe javascript to render the table of contents, the
@@ -51,10 +51,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
51
51
  version: '0'
52
52
  requirements: []
53
53
  rubyforge_project:
54
- rubygems_version: 2.6.2
54
+ rubygems_version: 2.4.5.1
55
55
  signing_key:
56
56
  specification_version: 4
57
57
  summary: A simple html or xhtml generator or logger to create human readable reports
58
58
  and logs
59
59
  test_files: []
60
- has_rdoc: