documatic 0.0.2 → 0.1.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.
data/README CHANGED
@@ -5,6 +5,8 @@ is a template-driven formatter that can be used to produce attractive
5
5
  printable documents such as database reports, invoices, letters, faxes
6
6
  and more.
7
7
 
8
+ As of version 0.1.0, Documatic supports OpenDocument text and
9
+ spreadsheet formats.
8
10
 
9
11
  == Installation
10
12
 
@@ -21,12 +23,27 @@ Documatic is a Ruport extension, so it is loaded like this:
21
23
  require 'ruport'
22
24
  require 'ruport/extensions'
23
25
 
24
- Documatic will then be available as a formatter for your Ruport tables, groups and groupings:
26
+ Documatic will then be available as a formatter for your Ruport
27
+ tables, groups and groupings. Rendering using an OpenDocument text
28
+ template is done like this:
25
29
 
26
- data.to_odt_template(:template => 'path/filename.odt',
27
- :output => 'output-path/filename.odt')
30
+ data.to_odt_template(:template_file => 'path/filename.odt',
31
+ :output_file => 'output-path/filename.odt')
28
32
 
29
- The wiki has more documentation and examples, plus a simple tutorial.
33
+ Rendering using an OpenDocument spreadsheet is done like this:
34
+
35
+ data.to_ods_template(:template_file => 'path/filename.ods',
36
+ :output_file => 'output-path/filename.ods')
37
+
38
+ Documatic creates the output path if required.
39
+
40
+ The wiki (see below) has more documentation and examples, plus simple
41
+ tutorials to illustrate how text and spreadsheet rendering works.
42
+
43
+
44
+ == Version
45
+
46
+ 0.1.0, released 02-SEP-2007.
30
47
 
31
48
 
32
49
  == Licence
@@ -51,7 +68,7 @@ http://stonecode.svnrepository.com/svn/documatic.
51
68
 
52
69
  The Rubyforge project page for Documatic is at
53
70
  http://rubyforge.org/projects/documatic. The Documatic rubygem is
54
- distributed from here.
71
+ distributed from there.
55
72
 
56
73
  For any other enquiries please contact Dave Nelson (urbanus at 240gl
57
74
  dot org).
data/lib/documatic.rb CHANGED
@@ -1,17 +1,18 @@
1
1
  require 'documatic/open_document_text/helper'
2
2
  require 'documatic/open_document_text/template'
3
+ require 'documatic/open_document_spreadsheet/template'
4
+ require 'documatic/open_document_spreadsheet/helper'
3
5
  require 'documatic/component'
4
6
  require 'documatic/open_document_text/partial'
5
7
 
6
-
7
8
  # The module "Documatic" is the namespace for the other modules and
8
9
  # classes in this project. It also contains some convenience methods.
9
10
  module Documatic
10
11
  class << self
11
12
 
12
13
  # Short-cut method for including a helper in
13
- # OpenDocumentText::Template.
14
- def text_helper(helper_module)
14
+ # Documatic::Component (the ERb processor).
15
+ def add_helper(helper_module)
15
16
  Documatic::Component.class_eval do
16
17
  include helper_module
17
18
  end
@@ -4,10 +4,13 @@ module Documatic
4
4
  class Component
5
5
  include ERB::Util
6
6
  include Documatic::OpenDocumentText::Helper
7
+ include Documatic::OpenDocumentSpreadsheet::Helper
7
8
 
8
9
  attr_accessor :erb
10
+ attr_accessor :erb_text
9
11
 
10
12
  def initialize(erb_text)
13
+ @erb_text = erb_text
11
14
  @erb = ERB.new(erb_text)
12
15
  end
13
16
 
@@ -22,7 +25,17 @@ module Documatic
22
25
  context = binding
23
26
  end
24
27
 
25
- @xml = nil ; @text = self.erb.result(context)
28
+ begin
29
+ @xml = nil ; @text = self.erb.result(context)
30
+ rescue
31
+ lines = self.erb_text.split /\n/
32
+ counter = 1
33
+ lines.each do |line|
34
+ puts "#{counter}:\t#{line}"
35
+ counter += 1
36
+ end
37
+ raise
38
+ end
26
39
  end
27
40
 
28
41
  # Returns a REXML::Document constructed from the text of this
@@ -4,24 +4,26 @@ require 'ruport'
4
4
  module Documatic::Formatter
5
5
 
6
6
  class OpenDocumentText < Ruport::Formatter
7
- PROCESSOR = Documatic::OpenDocumentText::Template
7
+ class << self
8
+ attr_accessor :processor
9
+ end
10
+
11
+ self.processor = Documatic::OpenDocumentText::Template
8
12
  renders :odt_template, :for => [ Ruport::Renderer::Table, Ruport::Renderer::Group,
9
13
  Ruport::Renderer::Grouping ]
10
14
 
11
15
  def build
12
- PROCESSOR.process_template(:data => data, :options => options)
16
+ self.class.processor.process_template(:data => data, :options => options)
13
17
  end
14
18
  alias_method :build_table_body, :build # for Ruport::Renderer::Table
15
19
  alias_method :build_group_body, :build # for Ruport::Renderer::Group
16
20
  alias_method :build_grouping_body, :build # for Ruport::Renderer::Grouping
17
-
18
21
  end
19
22
 
20
- # Coming soon
21
- # class OpenDocumentSpreadsheet < OpenDocumentText
22
- # PROCESSOR = Documatic::OpenDocumentSpreadsheet::Template
23
- # renders :ods_template, :for => [ Ruport::Renderer::Table, Ruport::Renderer::Group,
24
- # Ruport::Renderer::Grouping ]
25
- # end
26
-
27
- end
23
+ class OpenDocumentSpreadsheet < OpenDocumentText
24
+ self.processor = Documatic::OpenDocumentSpreadsheet::Template
25
+ renders :ods_template, :for => [ Ruport::Renderer::Table, Ruport::Renderer::Group,
26
+ Ruport::Renderer::Grouping ]
27
+ end
28
+
29
+ end # module Documatic::Formatter
@@ -0,0 +1,84 @@
1
+ require 'erb'
2
+ require 'date'
3
+ require 'time'
4
+
5
+ module Documatic
6
+ module OpenDocumentSpreadsheet
7
+ module Helper
8
+ include ERB::Util
9
+
10
+ # Map of OOCalc's visible types (selectable in the UI) to what's
11
+ # stored internally as the office:value-type attribute of a
12
+ # cell.
13
+ TYPES = {
14
+ 'Number' => 'float',
15
+ 'Percent' => 'percentage',
16
+ 'Currency' => 'currency',
17
+ 'Date' => 'date',
18
+ 'Time' => 'time',
19
+ 'Scientific' => 'float',
20
+ 'Fraction' => 'string',
21
+ 'Boolean' => 'boolean',
22
+ 'Text' => 'string',
23
+ }
24
+
25
+
26
+ # Renders a complete cell element with options to control the
27
+ # type, style, formula, row and column spans, and other cell
28
+ # attributes. See the wiki for full details.
29
+ def cell(value, opts = nil)
30
+ opts ||= Hash.new
31
+ opts[:type] ||= (case value.class.to_s
32
+ when 'Fixnum' then 'Number'
33
+ when 'Float' then 'Number'
34
+ when 'DateTime' then 'Date'
35
+ when 'Date' then 'Date'
36
+ when 'Time' then 'Time'
37
+ when 'TrueClass' then 'Boolean'
38
+ when 'FalseClass' then 'Boolean'
39
+ else 'Text'
40
+ end )
41
+ # Setting the :currency option forces the type to 'Currency'
42
+ if opts.has_key?(:currency)
43
+ opts[:type] = 'Currency'
44
+ end
45
+
46
+ # START OUTPUT
47
+ output = '<table:table-cell'
48
+ # Add style if specified
49
+ opts.has_key?(:style) &&
50
+ output << " table:style-name=\"#{opts[:style]}\""
51
+ # Add formula if specified
52
+ opts.has_key?(:formula) &&
53
+ output << " table:formula=\"#{opts[:formula]}\""
54
+ # Add the value-type attribute for the type
55
+ output << " office:value-type=\"#{TYPES[opts[:type]]}\""
56
+ # Add row and column spans if specified
57
+ opts.has_key?(:colspan) &&
58
+ output << " table:number-columns-spanned=\"#{opts[:colspan]}\""
59
+ opts.has_key?(:rowspan) &&
60
+ output << " table:number-rows-spanned=\"#{opts[:rowspan]}\""
61
+ # The rest of the output depends on the type
62
+ case opts[:type]
63
+ when 'Number', 'Percent', 'Scientific'
64
+ output << " office:value=\"#{ERB::Util.h(value)}\">"
65
+ when 'Currency'
66
+ output << " office:currency=\"#{ERB::Util.h(opts[:currency])}\""
67
+ output << " office:value=\"#{ERB::Util.h(value)}\">"
68
+ when 'Date'
69
+ output << " office:date-value=\"#{value.strftime("%Y-%m-%dT%H:%M:%S")}\">"
70
+ when 'Time'
71
+ output << " office:time-value=\"#{value.strftime("PT%HH%MM%SS")}\">"
72
+ when 'Boolean'
73
+ output << " office:boolean-value=\"#{value.to_s}\">"
74
+ else # text or fraction
75
+ output << "><text:p>#{ERB::Util.h(value)}</text:p>"
76
+ end
77
+ output << "</table:table-cell>"
78
+
79
+ return output
80
+ end
81
+
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,258 @@
1
+ require 'rexml/document'
2
+ require 'rexml/text'
3
+ require 'rexml/attribute'
4
+ require 'zip/zip'
5
+ require 'erb'
6
+ require 'fileutils'
7
+
8
+ module Documatic::OpenDocumentSpreadsheet
9
+ class Template
10
+ include ERB::Util
11
+
12
+ attr_accessor :content
13
+ attr_accessor :styles
14
+ attr_accessor :jar
15
+ # The raw contents of 'content.xml'.
16
+ attr_accessor :content_raw
17
+ # Compiled text, to be written to 'content.erb'
18
+ attr_accessor :content_erb
19
+
20
+ # RE_STYLES match positions
21
+ STYLE_NAME = 1
22
+ STYLE_TYPE = 2
23
+
24
+ # RE_ERB match positions
25
+ ROW_START = 1
26
+ TYPE = 2
27
+ ERB_CODE = 3
28
+ ROW_END = 4
29
+
30
+ class << self
31
+
32
+ # Includes the number and text helpers from Rails' ActionPack.
33
+ # Requires that the Rails gems be installed.
34
+ def include_rails_helpers
35
+ require 'action_pack'
36
+ require 'action_controller'
37
+ require 'action_view'
38
+
39
+ require 'action_view/helpers/number_helper'
40
+ require 'action_view/helpers/text_helper'
41
+
42
+ self.class_eval do
43
+ include ActionView::Helpers::NumberHelper
44
+ include ActionView::Helpers::TextHelper
45
+ end
46
+
47
+ end
48
+
49
+ def process_template(args, &block)
50
+ if args[:options] && args[:options].template_file && args[:options].output_file
51
+ output_dir = File.dirname(args[:options].output_file)
52
+ File.directory?(output_dir) || FileUtils.mkdir_p(output_dir)
53
+ FileUtils.cp(args[:options].template_file, args[:options].output_file)
54
+ template = self.new(args[:options].output_file)
55
+ template.process :data => args[:data], :options => args[:options]
56
+ template.save
57
+ if block
58
+ block.call(template)
59
+ template.save
60
+ end
61
+ template.close
62
+ else
63
+ raise ArgumentError, 'Need to specify both :template_file and :output_file in options'
64
+ end
65
+ end
66
+
67
+ end # class << self
68
+
69
+ def initialize(filename)
70
+ @filename = filename
71
+ @jar = Zip::ZipFile.open(@filename)
72
+ return true
73
+ end
74
+
75
+ def process(local_assigns = {})
76
+ # Compile this template, if not compiled already.
77
+ self.jar.find_entry('documatic/master') || self.compile
78
+ # Process the main (body) content.
79
+ @content = Documatic::Component.new( self.jar.read('documatic/master/content.erb') )
80
+ @content.process(local_assigns)
81
+ @content.merge_partial_styles
82
+ end
83
+
84
+ def save
85
+ # Gather all the styles from the partials, add them to the master's styles.
86
+ # Put the body into the document.
87
+ self.jar.get_output_stream('content.xml') do |f|
88
+ f.write self.content.to_s
89
+ end
90
+ end
91
+
92
+ def close
93
+ self.jar.close
94
+ end
95
+
96
+ def compile
97
+ # Read the raw files
98
+ @content_raw = regularise_styles( self.jar.read('content.xml') )
99
+ @content_erb = self.erbify(@content_raw)
100
+
101
+ # Create 'documatic/master/' in zip file
102
+ self.jar.find_entry('documatic/master') || self.jar.mkdir('documatic/master')
103
+
104
+ self.jar.get_output_stream('documatic/master/content.erb') do |f|
105
+ f.write @content_erb
106
+ end
107
+ end
108
+
109
+
110
+ protected
111
+
112
+ # Change OpenDocument line breaks and tabs in the ERb code to regular characters.
113
+ def unnormalize(code)
114
+ code = code.gsub(/<text:line-break\/>/, "\n")
115
+ code = code.gsub(/<text:tab\/>/, "\t")
116
+ return REXML::Text.unnormalize(code)
117
+ end
118
+
119
+ # Massage OpenDocument XML into ERb. (This is the heart of the compiler.)
120
+ def erbify(code)
121
+ # First gather all the ERb-related derived styles
122
+ remaining = code
123
+ styles = {'Ruby_20_Code' => 'Code', 'Ruby_20_Value' => 'Value', 'Ruby_20_Literal' => 'Literal'}
124
+ re_styles = /<style:style style:name="([^"]+)" style:parent-style-name="Ruby_20_(Code|Value|Literal)" style:family="table-cell">/
125
+
126
+ while remaining.length > 0
127
+ md = re_styles.match remaining
128
+ if md
129
+ styles[md[STYLE_NAME]] = md[STYLE_TYPE]
130
+ remaining = md.post_match
131
+ else
132
+ remaining = ""
133
+ end
134
+ end
135
+
136
+ remaining = code
137
+ result = String.new
138
+
139
+ # Then make a RE that includes the ERb-related styles.
140
+ # Match positions:
141
+ #
142
+ # 1. ROW_START Begin table row ?
143
+ # 2. TYPE ERb text style type
144
+ # 3. ERB_CODE ERb code
145
+ # 4. ROW_END End table row (empty cells then end of row) ?
146
+ #
147
+ # "?": optional, might not occur every time
148
+ re_erb = /(<table:table-row[^>]*>)?<table:table-cell [^>]*table:style-name="(#{styles.keys.join '|'})"[^>]*><text:p>([^<]*)<\/text:p><\/table:table-cell>(((<table:covered-table-cell[^\/>]*\/>)|(<table:table-cell[^\/>]*\/>))*<\/table:table-row>)?/
149
+
150
+ # The text one:
151
+ # re_erb = /(<table:table-row[^>]*>)?<table:table-cell [^>]+>)?(<text:list-item>)?(<text:p [^>]+>)?(<\/text:span>)?<text:span text:style-name="(#{styles.keys.join '|'})">(([^<]*|<text:line-break\/>|<text:tab\/>)+)<\/text:span>(<text:span [^>]+>)?(<\/text:p>)?(<\/text:list-item>)?(<\/table:table-cell>(<table:covered-table-cell\/>)*<\/table:table-row>)?/
152
+
153
+ # Then search for all text using those styles
154
+ while remaining.length > 0
155
+
156
+ md = re_erb.match remaining
157
+
158
+ if md
159
+
160
+ result += md.pre_match
161
+
162
+ match_code = false
163
+ match_row = false
164
+
165
+ if styles[md[TYPE]] == 'Code'
166
+ match_code = true
167
+ delim_start = '<% ' ; delim_end = ' %>'
168
+ if md[ROW_START] and md[ROW_END]
169
+ match_row = true
170
+ end
171
+ else # style is Value or Literal
172
+ if styles[md[TYPE]] == 'Literal'
173
+ delim_start = '<%= ' ; delim_end = ' %>'
174
+ else
175
+ delim_start = '<table:table-cell table:style-name="Default" office:value-type="string"><text:p><%= ERB::Util.h('
176
+ delim_end = ') %></text:p></table:table-cell>'
177
+ end
178
+ end
179
+
180
+ if md[ROW_START] and not match_row
181
+ result += md[ROW_START]
182
+ end
183
+
184
+ result += "#{delim_start}#{self.unnormalize md[ERB_CODE]}#{delim_end}"
185
+
186
+ if md[ROW_END] and not match_row
187
+ result += md[ROW_END]
188
+ end
189
+
190
+ remaining = md.post_match
191
+
192
+ else # no further matches
193
+ result += remaining
194
+ remaining = ""
195
+ end
196
+ end
197
+
198
+ return result
199
+ end
200
+
201
+
202
+ # OOo has a queer way of storing style information for cells. In
203
+ # some cases it is in the cell's attribute "table:style-name", but
204
+ # the default style for cells is also stored in the columns
205
+ # section at the beginning of each sheet. So there's no way of
206
+ # knowing in advance whether a cell will have its style specified
207
+ # or whether it has to be implied from the column definitions.
208
+
209
+ # This method regularises the cell styles: it takes the style
210
+ # definitions from each sheet's column definitions and applies
211
+ # them to any cells where the style is not specified. The result
212
+ # is a still-valid XML document but with explicit styles on each
213
+ # cell. This makes the document easier to compile.
214
+
215
+ def regularise_styles(content_raw)
216
+ doc = REXML::Document.new(content_raw)
217
+
218
+ # Get the default column types from all the sheets (tables) in the workbook
219
+ num_tables = doc.root.elements.to_a('//office:body/*/table:table').length
220
+ (1 .. num_tables).to_a.each do |tnum|
221
+ col_types = []
222
+ cols = doc.root.elements.to_a("//table:table[#{tnum}]/table:table-column")
223
+ cols.each do |col|
224
+ (0 ... (col.attributes['table:number-columns-repeated'] || 1).to_i).to_a.each do
225
+ col_types << col.attributes['table:default-cell-style-name']
226
+ end
227
+ end # each column
228
+
229
+ # Get the number of rows for each table
230
+ num_rows = doc.root.elements.to_a("//table:table[#{tnum}]/table:table-row").length
231
+
232
+ # Go through each row and process its cells
233
+ (1 .. num_rows).to_a.each do |rnum|
234
+ # The cells are both <table:table-cell> and <table:covered-table-cell>
235
+ cells = doc.root.elements.to_a(<<-END
236
+ //table:table[#{tnum}]/table:table-row[#{rnum}]/(table:table-cell | table:covered-table-cell)
237
+ END
238
+ )
239
+ # Keep track of the column number, for formatting purposes (c.f. col_types)
240
+ col_num = 0
241
+ cells.each do |cell|
242
+ # Only need to explicitly format the <table:table-cell>s
243
+ if cell.name == 'table-cell'
244
+ cell.attributes['table:style-name'] ||= col_types[col_num]
245
+ end
246
+ # Advance the column number, based on the columns spanned by the cell
247
+ col_num += (cell.attributes['table:number-columns-repeated'] || 1).to_i
248
+ end
249
+
250
+ end # each row
251
+ end # each table
252
+
253
+ return doc.to_s
254
+ end
255
+
256
+
257
+ end
258
+ end
@@ -29,7 +29,18 @@ module Documatic
29
29
  %Q(<text:span text:style-name="#{stylename}">#{ERB::Util.h(content)}</text:span>)
30
30
  end
31
31
 
32
-
32
+ # Turns an array of strings into a single, escaped string with
33
+ # OpenDocument line breaks (<text:line-break/>), omitting any
34
+ # blank lines. Perfect for address blocks etc.
35
+ def line_break(lines)
36
+ lines_esc = lines.collect do |line|
37
+ ERB::Util.h(line)
38
+ end
39
+ return (lines_esc.find_all do |line|
40
+ line && line.to_s.length > 0
41
+ end).join('<text:line-break/>')
42
+ end
43
+
33
44
  # Inserts a partial into the document at the chosen position.
34
45
  # This helper should be invoked from within "Ruby Block" because
35
46
  # it inserts unescaped block-level material in the current
@@ -77,7 +77,7 @@ module Documatic::OpenDocumentText
77
77
  body_text = doc.root.elements['office:body/office:text']
78
78
  body_text.elements.delete('text:sequence-decls')
79
79
  body_text.elements.delete('office:forms')
80
- @content_erb = self.erbify( (body_text.elements.to_a.collect do |e| e.to_s ; end ).join )
80
+ @content_erb = self.erbify( (body_text.elements.to_a.collect do |e| e.to_s ; end ).join("\n") )
81
81
  self.jar.get_output_stream('documatic/partial/content.erb') do |f|
82
82
  f.write @content_erb
83
83
  end
@@ -1,4 +1,5 @@
1
- require 'rexml/text'
1
+ #require 'rexml/text'
2
+ require 'rexml/document'
2
3
  require 'rexml/attribute'
3
4
  require 'zip/zip'
4
5
  require 'erb'
@@ -39,7 +40,7 @@ module Documatic::OpenDocumentText
39
40
 
40
41
  SPAN_END = 4
41
42
  SPAN_START = 8
42
-
43
+
43
44
  # Match types:
44
45
  TABLE_ROW = 1
45
46
  PARAGRAPH = 2
@@ -67,11 +68,11 @@ module Documatic::OpenDocumentText
67
68
  end
68
69
 
69
70
  def process_template(args, &block)
70
- if args[:options] && args[:options].template && args[:options].output
71
- output_dir = File.dirname(args[:options].output)
71
+ if args[:options] && args[:options].template_file && args[:options].output_file
72
+ output_dir = File.dirname(args[:options].output_file)
72
73
  File.directory?(output_dir) || FileUtils.mkdir_p(output_dir)
73
- FileUtils.cp(args[:options].template, args[:options].output)
74
- template = self.new(args[:options].output)
74
+ FileUtils.cp(args[:options].template_file, args[:options].output_file)
75
+ template = self.new(args[:options].output_file)
75
76
  template.process :data => args[:data], :options => args[:options]
76
77
  template.save
77
78
  if block
@@ -80,7 +81,7 @@ module Documatic::OpenDocumentText
80
81
  end
81
82
  template.close
82
83
  else
83
- raise ArgumentError, 'Need to specify both :template and :output in options'
84
+ raise ArgumentError, 'Need to specify both :template_file and :output_file in options'
84
85
  end
85
86
  end
86
87
 
@@ -125,8 +126,8 @@ module Documatic::OpenDocumentText
125
126
 
126
127
  def compile
127
128
  # Read the raw files
128
- @content_raw = self.jar.read('content.xml')
129
- @styles_raw = self.jar.read('styles.xml')
129
+ @content_raw = pretty_xml('content.xml')
130
+ @styles_raw = pretty_xml('styles.xml')
130
131
 
131
132
  @content_erb = self.erbify(@content_raw)
132
133
  @styles_erb = self.erbify(@styles_raw)
@@ -145,10 +146,20 @@ module Documatic::OpenDocumentText
145
146
 
146
147
  protected
147
148
 
149
+ def pretty_xml(filename)
150
+ # Pretty print the XML source
151
+ xml_doc = REXML::Document.new(self.jar.read(filename))
152
+ xml_text = String.new
153
+ # xml_doc.write(xml_text, Documatic.debug ? 0 : -1)
154
+ xml_doc.write(xml_text, 0)
155
+ return xml_text
156
+ end
157
+
148
158
  # Change OpenDocument line breaks and tabs in the ERb code to regular characters.
149
159
  def unnormalize(code)
150
160
  code = code.gsub(/<text:line-break\/>/, "\n")
151
161
  code = code.gsub(/<text:tab\/>/, "\t")
162
+ code = code.gsub(/<text:s(\/|(\s[^>]*))>/, " ")
152
163
  return REXML::Text.unnormalize(code)
153
164
  end
154
165
 
@@ -158,8 +169,8 @@ module Documatic::OpenDocumentText
158
169
  remaining = code
159
170
  styles = {'Ruby_20_Code' => 'Code', 'Ruby_20_Value' => 'Value',
160
171
  'Ruby_20_Block' => 'Block', 'Ruby_20_Literal' => 'Literal'}
161
- re_styles = /<style:style style:name="([^"]+)" style:family="text" style:parent-style-name="Ruby_20_(Code|Value|Block|Literal)">/
162
-
172
+ re_styles = /<style:style style:name="([^"]+)"[^>]* style:parent-style-name="Ruby_20_(Code|Value|Block|Literal)"[^>]*>/
173
+
163
174
  while remaining.length > 0
164
175
  md = re_styles.match remaining
165
176
  if md
@@ -180,6 +191,7 @@ module Documatic::OpenDocumentText
180
191
  # 2. ITEM_START Begin list item ?
181
192
  # 3. PARA_START Begin paragraph ?
182
193
  # 4. SPAN_END Another text span ends immediately before ERb ?
194
+ # --5. SPACE (possible leading space)
183
195
  # 5. TYPE ERb text style type
184
196
  # 6. ERB_CODE ERb code
185
197
  # 7. (ERb inner brackets)
@@ -189,7 +201,8 @@ module Documatic::OpenDocumentText
189
201
  # 11. ROW_END End table row (incl. covered rows) ?
190
202
  #
191
203
  # "?": optional, might not occur every time
192
- re_erb = /(<table:table-row[^>]*><table:table-cell [^>]+>)?(<text:list-item>)?(<text:p [^>]+>)?(<\/text:span>)?<text:span text:style-name="(#{styles.keys.join '|'})">(([^<]*|<text:line-break\/>|<text:tab\/>)+)<\/text:span>(<text:span [^>]+>)?(<\/text:p>)?(<\/text:list-item>)?(<\/table:table-cell>(<table:covered-table-cell\/>)*<\/table:table-row>)?/
204
+ # re_erb = /(<table:table-row[^>]*>\s*<table:table-cell [^>]+>\s*)?(\s*<text:list-item>\s*)?\s*(<text:p [^>]+>\s*)?(<\/text:span>)?<text:span text:style-name="(#{styles.keys.join '|'})">(([^<]*|<text:line-break\/>|<text:tab\/>)+)<\/text:span>(<text:span [^>]+>)?(\s*<\/text:p>\s*)?(<\/text:list-item>\s*)?(<\/table:table-cell>\s*(<table:covered-table-cell\/>\s*)*<\/table:table-row>)?/
205
+ re_erb = /(<table:table-row[^>]*>\s*<table:table-cell [^>]+>\s*)?(<text:list-item>\s*)?(<text:p [^>]+>\s*)?(<\/text:span>\s*)?<text:span text:style-name="(#{styles.keys.join '|'})">(([^<]*|<text:line-break\/>|<text:tab\/>)+)<\/text:span>(<text:span [^>]+>)?(\s*<\/text:p>)?(\s*<\/text:list-item>)?(\s*<\/table:table-cell>(\s*<table:covered-table-cell\/>)*\s*<\/table:table-row>)?/
193
206
 
194
207
  # Then search for all text using those styles
195
208
  while remaining.length > 0
@@ -197,7 +210,6 @@ module Documatic::OpenDocumentText
197
210
  md = re_erb.match remaining
198
211
 
199
212
  if md
200
-
201
213
  result += md.pre_match
202
214
 
203
215
  match_code = false
@@ -253,6 +265,9 @@ module Documatic::OpenDocumentText
253
265
  result += md[SPAN_END]
254
266
  end
255
267
  else
268
+ #if md[SPACE]
269
+ # result += md[SPACE]
270
+ #end
256
271
  if md[SPAN_START] and not md[SPAN_END]
257
272
  result += md[SPAN_START]
258
273
  end
metadata CHANGED
@@ -1,10 +1,10 @@
1
1
  --- !ruby/object:Gem::Specification
2
- rubygems_version: 0.9.2
2
+ rubygems_version: 0.9.0
3
3
  specification_version: 1
4
4
  name: documatic
5
5
  version: !ruby/object:Gem::Version
6
- version: 0.0.2
7
- date: 2007-06-15 00:00:00 +10:00
6
+ version: 0.1.0
7
+ date: 2007-09-02 00:00:00 +10:00
8
8
  summary: Documatic is an OpenDocument extension for Ruby Reports (Ruport). It is a template-driven formatter that can be used to produce attractive printable documents such as database reports, invoices, letters, faxes and more.
9
9
  require_paths:
10
10
  - lib
@@ -29,17 +29,20 @@ post_install_message:
29
29
  authors: []
30
30
 
31
31
  files:
32
- - lib
33
- - lib/documatic
32
+ - lib/
34
33
  - lib/documatic.rb
34
+ - lib/documatic/
35
35
  - lib/documatic/component.rb
36
- - lib/documatic/open_document_text
36
+ - lib/documatic/formatter/
37
+ - lib/documatic/formatter/open_document.rb
38
+ - lib/documatic/init.rb
39
+ - lib/documatic/open_document_spreadsheet/
40
+ - lib/documatic/open_document_spreadsheet/helper.rb
41
+ - lib/documatic/open_document_spreadsheet/template.rb
42
+ - lib/documatic/open_document_text/
37
43
  - lib/documatic/open_document_text/helper.rb
38
44
  - lib/documatic/open_document_text/partial.rb
39
45
  - lib/documatic/open_document_text/template.rb
40
- - lib/documatic/formatter
41
- - lib/documatic/formatter/open_document.rb
42
- - lib/documatic/init.rb
43
46
  - tests
44
47
  - README
45
48
  test_files: []
@@ -73,7 +76,7 @@ dependencies:
73
76
  requirements:
74
77
  - - ">="
75
78
  - !ruby/object:Gem::Version
76
- version: "0.1"
79
+ version: 0.2.2
77
80
  version:
78
81
  - !ruby/object:Gem::Dependency
79
82
  name: ruport
@@ -82,5 +85,5 @@ dependencies:
82
85
  requirements:
83
86
  - - ">="
84
87
  - !ruby/object:Gem::Version
85
- version: 1.0.0
88
+ version: 1.2.0
86
89
  version: