rd2odt 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.
Files changed (70) hide show
  1. data/FUTURE +63 -0
  2. data/LICENSE +21 -0
  3. data/NEWS +42 -0
  4. data/README +78 -0
  5. data/Rakefile +51 -0
  6. data/bin/rd2odt +4 -0
  7. data/doc/sample/body-text.rd +5 -0
  8. data/doc/sample/enum-list-over-headline-multi-level.rd +10 -0
  9. data/doc/sample/enum-list-over-headline.rd +9 -0
  10. data/doc/sample/enum-list-over-item-list-multi-level-2.rd +9 -0
  11. data/doc/sample/enum-list-over-item-list-multi-level.rd +8 -0
  12. data/doc/sample/enum-list-over-item-list.rd +7 -0
  13. data/doc/sample/headline.rd +60 -0
  14. data/doc/sample/include-file-figure.odt +0 -0
  15. data/doc/sample/include-file-ole-object.odt +0 -0
  16. data/doc/sample/include-file-original-styled-text.odt +0 -0
  17. data/doc/sample/include-file-shape.odt +0 -0
  18. data/doc/sample/include-file-simple-styled-text.odt +0 -0
  19. data/doc/sample/include-file-simple-text.odt +0 -0
  20. data/doc/sample/include-file-table.odt +0 -0
  21. data/doc/sample/include.rd +21 -0
  22. data/doc/sample/list.rd +22 -0
  23. data/doc/sample/multi-paragraph.rd +12 -0
  24. data/doc/sample/page-break.odt +0 -0
  25. data/doc/sample/verbatim.rd +8 -0
  26. data/doc/sample.rd.ja +75 -0
  27. data/doc/sample.rd.ja.ott +0 -0
  28. data/doc/sample.rd.ja.pdf +0 -0
  29. data/doc/specification.ja.rd +35 -0
  30. data/lib/rd2odt/rdtool/NOTICE.rd2odt +8 -0
  31. data/lib/rd2odt/rdtool/README.rd +50 -0
  32. data/lib/rd2odt/rdtool/README.rd.ja +53 -0
  33. data/lib/rd2odt/rdtool/rd/block-element.rb +114 -0
  34. data/lib/rd2odt/rdtool/rd/complex-list-item.rb +65 -0
  35. data/lib/rd2odt/rdtool/rd/desclist.rb +55 -0
  36. data/lib/rd2odt/rdtool/rd/document-struct.rb +46 -0
  37. data/lib/rd2odt/rdtool/rd/element.rb +160 -0
  38. data/lib/rd2odt/rdtool/rd/filter.rb +255 -0
  39. data/lib/rd2odt/rdtool/rd/inline-element.rb +233 -0
  40. data/lib/rd2odt/rdtool/rd/labeled-element.rb +14 -0
  41. data/lib/rd2odt/rdtool/rd/list.rb +57 -0
  42. data/lib/rd2odt/rdtool/rd/loose-struct.rb +11 -0
  43. data/lib/rd2odt/rdtool/rd/methodlist.rb +57 -0
  44. data/lib/rd2odt/rdtool/rd/output-format-visitor.rb +28 -0
  45. data/lib/rd2odt/rdtool/rd/package.rb +4 -0
  46. data/lib/rd2odt/rdtool/rd/parser-util.rb +14 -0
  47. data/lib/rd2odt/rdtool/rd/rbl-file.rb +69 -0
  48. data/lib/rd2odt/rdtool/rd/rbl-suite.rb +37 -0
  49. data/lib/rd2odt/rdtool/rd/rd-struct.rb +86 -0
  50. data/lib/rd2odt/rdtool/rd/rd2html-lib.rb +490 -0
  51. data/lib/rd2odt/rdtool/rd/rd2html-opt.rb +67 -0
  52. data/lib/rd2odt/rdtool/rd/rd2man-lib.rb +241 -0
  53. data/lib/rd2odt/rdtool/rd/rd2rdo-lib.rb +19 -0
  54. data/lib/rd2odt/rdtool/rd/rd2rmi-lib.rb +32 -0
  55. data/lib/rd2odt/rdtool/rd/rdblockparser.tab.rb +1050 -0
  56. data/lib/rd2odt/rdtool/rd/rdfmt.rb +15 -0
  57. data/lib/rd2odt/rdtool/rd/rdinlineparser.tab.rb +1243 -0
  58. data/lib/rd2odt/rdtool/rd/rdvisitor.rb +214 -0
  59. data/lib/rd2odt/rdtool/rd/reference-resolver.rb +114 -0
  60. data/lib/rd2odt/rdtool/rd/search-file.rb +14 -0
  61. data/lib/rd2odt/rdtool/rd/tree.rb +103 -0
  62. data/lib/rd2odt/rdtool/rd/version.rb +39 -0
  63. data/lib/rd2odt/rdtool/rd/visitor.rb +86 -0
  64. data/lib/rd2odt.rb +603 -0
  65. data/rd2odt.gemspec +108 -0
  66. data/setup.rb +1585 -0
  67. data/test/functional/rd2odt-spec.rb +733 -0
  68. data/test/test-helper.rb +93 -0
  69. data/test/unit/rd2odt-spec.rb +831 -0
  70. metadata +122 -0
data/lib/rd2odt.rb ADDED
@@ -0,0 +1,603 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ require "pp"
4
+ require "optparse"
5
+ require "find"
6
+ require "tmpdir"
7
+ require "cgi"
8
+ require "rexml/document"
9
+ begin
10
+ require "rd/rdvisitor"
11
+ require "rd/rdfmt"
12
+ require "zip/zip"
13
+ rescue LoadError
14
+ require "rubygems"
15
+ require "rd/rdvisitor"
16
+ require "rd/rdfmt"
17
+ require "zip/zip"
18
+ end
19
+
20
+ module RD2ODT
21
+ @@options = {
22
+ :backtrace => false,
23
+ :template => nil,
24
+ }
25
+ OPTION_PARSER = OptionParser.new
26
+ OPTION_PARSER.banner = "Usage: #{OPTION_PARSER.program_name} [options] input-file-path.rd [output-file-path.odt]"
27
+ OPTION_PARSER.on("--backtrace", "print backtrace") do
28
+ @@options[:backtrace] = true
29
+ end
30
+ OPTION_PARSER.on("--template=TEMPLATE", "specify template filename") do |arg|
31
+ @@options[:template] = arg
32
+ end
33
+
34
+ def options
35
+ return @@options
36
+ end
37
+ module_function :options
38
+
39
+ def parse_option(argv)
40
+ begin
41
+ OPTION_PARSER.parse!(argv)
42
+ rescue OptionParser::ParseError => e
43
+ raise ProgramOptionParseError, e
44
+ end
45
+
46
+ @@input_path = argv.shift
47
+ if @@input_path.nil?
48
+ raise ProgramOptionError, "no input file path."
49
+ end
50
+
51
+ @@output_path =
52
+ argv.shift ||
53
+ (@@input_path == "-" ? "output.odt" : @@input_path + ".odt")
54
+
55
+ if options[:template].nil?
56
+ options[:template] = @@input_path + ".ott"
57
+ end
58
+ @@input_path
59
+ end
60
+ module_function :parse_option
61
+
62
+ def main(argv)
63
+ parse_option(argv)
64
+
65
+ include_paths = [
66
+ File.dirname(@@input_path),
67
+ File.dirname(@@output_path),
68
+ ]
69
+
70
+ puts("input_path: " + @@input_path.inspect) if $DEBUG
71
+ puts("output_path: " + @@output_path.inspect) if $DEBUG
72
+ puts("options: " + options.inspect) if $DEBUG
73
+ puts("include_paths: " + include_paths.inspect) if $DEBUG
74
+
75
+ input_lines = treat_input(File.readlines(@@input_path))
76
+ tree = RD::RDTree.new(input_lines, include_paths, nil)
77
+ tree.parse
78
+ visitor = RD2ODTVisitor.new
79
+ doc = visitor.visit(tree)
80
+ create_odt(visitor, doc, @@output_path, options[:template])
81
+ rescue Error => e
82
+ e.process
83
+ end
84
+ module_function :main
85
+
86
+ def self.treat_input(lines)
87
+ result = lines.dup
88
+
89
+ if lines.grep(/^=begin\b/).empty? &&
90
+ lines.grep(/^=end\b/).empty?
91
+ result.unshift("=begin\n")
92
+
93
+ if !(/\n\z/ === result[-1])
94
+ result[-1] = result[-1] + "\n"
95
+ end
96
+ result.push("=end\n")
97
+ end
98
+
99
+ return result
100
+ end
101
+
102
+ def self.create_odt(visitor, doc, output_path, template_path)
103
+ current_path = Dir.pwd
104
+ output_absolute_path = File.expand_path(output_path)
105
+ template_absolute_path = File.expand_path(template_path)
106
+ Dir.mktmpdir do |tmpdir|
107
+ Dir.chdir(tmpdir) do
108
+ unzip(template_absolute_path)
109
+ open("styles.xml", "r+") do |f|
110
+ operate_styles_xml(f, visitor.additional_styles)
111
+ end
112
+ open("content.xml", "w") do |f|
113
+ f.puts('<?xml version="1.0" encoding="UTF-8"?>')
114
+ f.puts
115
+ f.puts(ah_to_xml(doc))
116
+ end
117
+ # todo: test
118
+ # todo: extract only inner_object.href for more optimizing.
119
+ visitor.inner_objects.each do |inner_object|
120
+ Dir.mktmpdir do |dir|
121
+ Dir.chdir(dir) do
122
+ unzip(File.join(current_path, inner_object.path))
123
+ from = inner_object.href
124
+ to = File.join(tmpdir, inner_object.fixed_href)
125
+ FileUtils.mkdir_p(File.dirname(to))
126
+ FileUtils.mv(from, to)
127
+ end
128
+ end
129
+ end
130
+ zip(output_absolute_path)
131
+ end
132
+ end
133
+ end
134
+
135
+ # very lazy formatter
136
+ def self.ah_to_xml(o)
137
+ return __send__("ah_to_xml_by_" + o.class.name.downcase, o)
138
+ end
139
+
140
+ def self.ah_to_xml_by_array(ary)
141
+ if ary.first.is_a?(Array) ||
142
+ ary.first.is_a?(Symbol) && /<.*>/ === ary.first.to_s
143
+ # This case is:
144
+ # [[:tag], [:tag]]
145
+ # |
146
+ # v
147
+ # <tag></tag>
148
+ # <tag></tag>
149
+ return ary.map { |item|
150
+ ah_to_xml(item)
151
+ }.join("\n")
152
+ end
153
+
154
+ ary = ary.dup
155
+ result = "<"
156
+
157
+ tag_name = ah_to_xml(ary.shift)
158
+ result << tag_name
159
+
160
+ if Hash === ary.first
161
+ h = ary.shift
162
+ result << ah_to_xml_by_hash(h)
163
+ end
164
+
165
+ if ary.empty?
166
+ result << " />"
167
+ return result
168
+ end
169
+
170
+ result << ">"
171
+
172
+ ary.each do |item|
173
+ case item
174
+ when Array
175
+ result << "\n"
176
+ result << ah_to_xml_by_array(item).gsub(/^/, " ")
177
+ result << "\n"
178
+ else
179
+ result << ah_to_xml(item)
180
+ end
181
+ end
182
+
183
+ result << "</" + tag_name + ">"
184
+
185
+ return result
186
+ end
187
+
188
+ def self.ah_to_xml_by_symbol(symbol)
189
+ return symbol.to_s.gsub("__", ":").gsub("_", "-")
190
+ end
191
+
192
+ def self.ah_to_xml_by_hash(h)
193
+ return h.keys.sort_by { |item|
194
+ item.to_s
195
+ }.map { |key|
196
+ converted_key = ah_to_xml_by_symbol(key)
197
+
198
+ value = h[key]
199
+ converted_value = ah_to_xml_by_string(value)
200
+
201
+ " " + converted_key + "=" + '"' + converted_value + '"'
202
+ }.join
203
+ end
204
+
205
+ def self.ah_to_xml_by_string(s)
206
+ return CGI.escapeHTML(s.to_s)
207
+ end
208
+
209
+ def self.operate_styles_xml(io, additional_styles)
210
+ parser = REXML::Document.new(io.read)
211
+ office_styles = parser.elements["/office:document-styles/office:styles"]
212
+ additional_styles.each do |element|
213
+ office_styles.add_element(element)
214
+ end
215
+
216
+ io.rewind
217
+ io.truncate(0)
218
+ io.write(parser.to_s)
219
+ end
220
+
221
+ # create zip file by current directory.
222
+ def self.zip(output_path)
223
+ # if !system("zip", "-9qr", output_path, ".")
224
+ # raise "zip failure: #{output_path.inspect}"
225
+ # end
226
+ FileUtils.rm_f(output_path)
227
+ Zip::ZipFile.open(output_path, Zip::ZipFile::CREATE) do |zip_file|
228
+ Find.find(".") do |path_orig|
229
+ path = path_orig.sub(/\A\.\//, "") # remove "./"
230
+ if File.file?(path)
231
+ zip_file.get_output_stream(path) do |f|
232
+ f.write(File.read(path))
233
+ end
234
+ elsif File.directory?(path)
235
+ zip_file.mkdir(path)
236
+ end
237
+ end
238
+ end
239
+ end
240
+
241
+ # unzip to current directory.
242
+ def self.unzip(input_path)
243
+ # if !system("unzip", "-q", input_path)
244
+ # raise "unzip failure: #{input_path.inspect}"
245
+ # end
246
+ Zip::ZipFile.foreach(input_path) do |zip_entry|
247
+ path = zip_entry.name
248
+ if zip_entry.directory?
249
+ FileUtils.mkdir_p(path)
250
+ elsif zip_entry.file?
251
+ FileUtils.mkdir_p(File.dirname(path))
252
+ zip_entry.get_input_stream do |input|
253
+ open(path, "w") do |output|
254
+ output.write(input.read)
255
+ end
256
+ end
257
+ end
258
+ end
259
+ end
260
+
261
+ class RD2ODTVisitor < RD::RDVisitor
262
+ attr_accessor :continue_numbering_headline
263
+
264
+ # for content.xml#/office:document-content/office:automatic-styles
265
+ attr_accessor :automatic_styles
266
+
267
+ # for styles.xml#/office:document-styles/office:styles
268
+ attr_accessor :additional_styles
269
+
270
+ attr_accessor :number_of_include_files
271
+
272
+ # included OLE objects
273
+ attr_accessor :inner_objects
274
+
275
+ def initialize(*args)
276
+ super
277
+
278
+ self.number_of_include_files = 0
279
+ self.additional_styles = []
280
+ self.automatic_styles = []
281
+ self.inner_objects = []
282
+ end
283
+
284
+ def apply_to_DocumentElement(element, sub_content)
285
+ result =
286
+ [:office__document_content,
287
+ {
288
+ :xmlns__office =>
289
+ "urn:oasis:names:tc:opendocument:xmlns:office:1.0",
290
+ :xmlns__style => "urn:oasis:names:tc:opendocument:xmlns:style:1.0",
291
+ :xmlns__text => "urn:oasis:names:tc:opendocument:xmlns:text:1.0",
292
+ :xmlns__table => "urn:oasis:names:tc:opendocument:xmlns:table:1.0",
293
+ :xmlns__draw => "urn:oasis:names:tc:opendocument:xmlns:drawing:1.0",
294
+ :xmlns__fo =>
295
+ "urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0",
296
+ :xmlns__xlink => "http://www.w3.org/1999/xlink",
297
+ :xmlns__dc => "http://purl.org/dc/elements/1.1/",
298
+ :xmlns__meta => "urn:oasis:names:tc:opendocument:xmlns:meta:1.0",
299
+ :xmlns__number =>
300
+ "urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0",
301
+ :xmlns__svg =>
302
+ "urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0",
303
+ :xmlns__chart => "urn:oasis:names:tc:opendocument:xmlns:chart:1.0",
304
+ :xmlns__dr3d => "urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0",
305
+ :xmlns__math => "http://www.w3.org/1998/Math/MathML",
306
+ :xmlns__form => "urn:oasis:names:tc:opendocument:xmlns:form:1.0",
307
+ :xmlns__script =>
308
+ "urn:oasis:names:tc:opendocument:xmlns:script:1.0",
309
+ :xmlns__ooo => "http://openoffice.org/2004/office",
310
+ :xmlns__ooow => "http://openoffice.org/2004/writer",
311
+ :xmlns__oooc => "http://openoffice.org/2004/calc",
312
+ :xmlns__dom => "http://www.w3.org/2001/xml-events",
313
+ :xmlns__xforms => "http://www.w3.org/2002/xforms",
314
+ :xmlns__xsd => "http://www.w3.org/2001/XMLSchema",
315
+ :xmlns__xsi => "http://www.w3.org/2001/XMLSchema-instance",
316
+ :xmlns__field =>
317
+ "urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:field:1.0",
318
+ :office__version => "1.1",
319
+ },
320
+ [:office__scripts],
321
+ [:office__font_face_decls,
322
+ [:style__font_face,
323
+ {
324
+ :style__name => "さざなみ明朝",
325
+ :svg__font_family => "さざなみ明朝",
326
+ :style__font_family_generic => "roman",
327
+ :style__font_pitch => "variable",
328
+ }],
329
+ [:style__font_face,
330
+ {
331
+ :style__name => "IPAゴシック",
332
+ :svg__font_family => "IPAゴシック",
333
+ :style__font_family_generic => "swiss",
334
+ :style__font_pitch => "variable",
335
+ }],
336
+ [:style__font_face,
337
+ {
338
+ :style__name => "IPAゴシック1",
339
+ :svg__font_family => "IPAゴシック",
340
+ :style__font_family_generic => "system",
341
+ :style__font_pitch => "variable",
342
+ }],
343
+ ], # :office__font_face_decls
344
+ [:office__automatic_styles,
345
+ *self.automatic_styles.map { |element|
346
+ element.to_s.to_sym
347
+ }],
348
+ [:office__body,
349
+ [:office__text,
350
+ [:text__sequence_decls,
351
+ [:text__sequence_decl,
352
+ {
353
+ :text__display_outline_level => "0",
354
+ :text__name => "Illustration",
355
+ }],
356
+ [:text__sequence_decl,
357
+ {
358
+ :text__display_outline_level => "0",
359
+ :text__name => "Table",
360
+ }],
361
+ [:text__sequence_decl,
362
+ {
363
+ :text__display_outline_level => "0",
364
+ :text__name => "Text",
365
+ }],
366
+ [:text__sequence_decl,
367
+ {
368
+ :text__display_outline_level => "0",
369
+ :text__name => "Drawing",
370
+ }],
371
+ ], # :text__sequence_decls
372
+ *sub_content
373
+ ], # :office__text
374
+ ], # :office__body
375
+ ] # :office__document_content
376
+ return result
377
+ end
378
+
379
+ def apply_to_TextBlock(element, sub_contents)
380
+ return [:text__p,
381
+ {:text__style_name => "Text_20_body"},
382
+ *sub_contents
383
+ ]
384
+ end
385
+
386
+ def apply_to_StringElement(element)
387
+ return element.content.gsub(/[\r\n]+/m, "")
388
+ end
389
+
390
+ def create_headline_result(title, original_level, current_level)
391
+ if current_level.zero?
392
+ return [:text__p,
393
+ {:text__style_name => "Heading_20_#{original_level}"},
394
+ *title
395
+ ]
396
+ else
397
+ return [:text__list,
398
+ {:text__continue_numbering => "true"},
399
+ [:text__list_item,
400
+ create_headline_result(title, original_level,
401
+ current_level - 1)
402
+ ],
403
+ ]
404
+ end
405
+ end
406
+ private :create_headline_result
407
+
408
+ def apply_to_Headline(element, title)
409
+ level = element.level
410
+ result = create_headline_result(title, level, level)
411
+ result[1][:text__style_name] = "Numbering_20_2"
412
+ if level == 1 && !continue_numbering_headline
413
+ result[1].delete(:text__continue_numbering)
414
+ end
415
+ self.continue_numbering_headline = true
416
+ return result
417
+ end
418
+
419
+ def apply_to_EnumList(element, items)
420
+ return apply_to_list(items,
421
+ :text__style_name => "Numbering_20_1",
422
+ :text__continue_numbering => "false")
423
+ end
424
+
425
+ def apply_to_ItemList(element, items)
426
+ return apply_to_list(items, :text__style_name => "List_20_1")
427
+ end
428
+
429
+ def apply_to_list(items, attributes)
430
+ return [:text__list, attributes, *items]
431
+ end
432
+ private :apply_to_list
433
+
434
+ def apply_to_EnumListItem(element, sub_contents)
435
+ return apply_to_list_item(sub_contents)
436
+ end
437
+
438
+ def apply_to_ItemListItem(element, sub_contents)
439
+ return apply_to_list_item(sub_contents)
440
+ end
441
+
442
+ def apply_to_list_item(sub_contents)
443
+ return [:text__list_item, *sub_contents]
444
+ end
445
+ private :apply_to_list_item
446
+
447
+ def apply_to_Verbatim(element)
448
+ lines = element.content.map { |line|
449
+ escape_text(line.chomp)
450
+ }
451
+ return [:text__p,
452
+ {:text__style_name=>"Preformatted_20_Text"},
453
+ lines.join("<text:line-break />").to_sym,
454
+ ]
455
+ end
456
+
457
+ def escape_text(text)
458
+ return CGI.escapeHTML(text).gsub(/ {2,}/) {
459
+ num_space_chars = Regexp.last_match.to_s.length
460
+ %Q'<text:s text:c="#{num_space_chars}" />'
461
+ }.gsub("\t", "<text:tab />")
462
+ end
463
+ private :escape_text
464
+
465
+ DO_NOT_INCLUDE_TAG_NAMES = ["office:forms", "text:sequence-decls"]
466
+
467
+ def apply_to_Include(element)
468
+ self.number_of_include_files += 1
469
+ name_prefix = create_name_prefix
470
+ path = search_file(element.tree.include_paths, element.filename)
471
+
472
+ append_children = []
473
+ content_xml = read_file_in_zip(path, "content.xml")
474
+ parser = REXML::Document.new(content_xml)
475
+ office_text =
476
+ parser.elements["/office:document-content/office:body/office:text"]
477
+ apply_prefix_to_xlink_href(path, office_text, name_prefix) # todo: test
478
+ [
479
+ "text:style-name",
480
+ "table:style-name",
481
+ "table:name",
482
+ "draw:style-name",
483
+ ].each do |attribute_key|
484
+ apply_prefix_to_all_of_style_name(office_text, attribute_key,
485
+ name_prefix)
486
+ end
487
+ office_text.each_element do |child|
488
+ # may use XPath.
489
+ next if DO_NOT_INCLUDE_TAG_NAMES.include?(child.expanded_name)
490
+ append_children << child.to_s.to_sym
491
+ end
492
+
493
+ office_automatic_styles =
494
+ parser.elements["/office:document-content/office:automatic-styles"]
495
+ apply_prefix_to_all_of_style_name(office_automatic_styles,
496
+ "style:name", name_prefix)
497
+ office_automatic_styles.each_element do |child|
498
+ self.automatic_styles << child.deep_clone
499
+ end
500
+
501
+ styles_xml = read_file_in_zip(path, "styles.xml")
502
+ parser = REXML::Document.new(styles_xml)
503
+ office_styles = parser.elements["/office:document-styles/office:styles"]
504
+ [
505
+ "style:name",
506
+ "style:parent-style-name",
507
+ "style:display-name",
508
+ ].each do |attribute_key|
509
+ apply_prefix_to_all_of_style_name(office_styles, attribute_key,
510
+ name_prefix)
511
+ end
512
+ office_styles.elements.each("style:style") do |element|
513
+ self.additional_styles << element
514
+ end
515
+
516
+ return append_children
517
+ end
518
+
519
+ def search_file(include_paths, filename)
520
+ include_paths.each do |d|
521
+ path = File.join(d, filename)
522
+ return path if File.exist?(path)
523
+ end
524
+ raise "file not found: #{filename.inspect}, #{include_paths.inspect}"
525
+ end
526
+ private :search_file
527
+
528
+ def read_file_in_zip(zip_path, path_in_zip)
529
+ # return `unzip -c #{zip_path} #{path_in_zip}`
530
+ Zip::ZipFile.open(zip_path) do |zip_file|
531
+ return zip_file.read(path_in_zip)
532
+ end
533
+ end
534
+ private :read_file_in_zip
535
+
536
+ def create_name_prefix
537
+ t = Time.now
538
+ return sprintf("rd2odt:%d:%06d:%d:",
539
+ t.tv_sec, t.tv_usec, number_of_include_files)
540
+ end
541
+ private :create_name_prefix
542
+
543
+ def apply_prefix_to_all_of_style_name(start_element, attribute_key,
544
+ name_prefix)
545
+ start_element.elements.each("//*[@#{attribute_key}]") do |element|
546
+ element.attributes[attribute_key] =
547
+ name_prefix + element.attributes[attribute_key]
548
+ end
549
+ end
550
+ private :apply_prefix_to_all_of_style_name
551
+
552
+ # todo: test
553
+ def apply_prefix_to_xlink_href(path, office_text, name_prefix)
554
+ # <draw:object> and <draw:image>
555
+ office_text.elements.each("//*[@xlink:href]") do |element|
556
+ href = element.attributes["xlink:href"]
557
+ fixed_href = File.join(File.dirname(href),
558
+ name_prefix + File.basename(href))
559
+ element.attributes["xlink:href"] = fixed_href
560
+ self.inner_objects << InnerObject.new(path, href, fixed_href)
561
+ end
562
+ end
563
+ private :apply_prefix_to_xlink_href
564
+ end
565
+
566
+ InnerObject = Struct.new(:path, :href, :fixed_href)
567
+
568
+ class Error < StandardError
569
+ def process
570
+ if RD2ODT.options[:backtrace]
571
+ STDERR.puts("backtrace:")
572
+ STDERR.puts(backtrace.map { |l|
573
+ " " + l
574
+ })
575
+ end
576
+ STDERR.puts(message)
577
+ exit(1)
578
+ end
579
+ end
580
+
581
+ class ProgramOptionError < Error
582
+ ADDITIONAL_MESSAGE = [RD2ODT::OPTION_PARSER.banner,
583
+ "use #{RD2ODT::OPTION_PARSER.program_name} --help for more help."]
584
+
585
+ def message
586
+ return [super, "", *ADDITIONAL_MESSAGE]
587
+ end
588
+ end
589
+
590
+ class ProgramOptionParseError < ProgramOptionError
591
+ def initialize(e)
592
+ @e = e
593
+ end
594
+
595
+ def message
596
+ return [@e.message, "", *ADDITIONAL_MESSAGE]
597
+ end
598
+
599
+ def backtrace
600
+ return @e.backtrace
601
+ end
602
+ end
603
+ end
data/rd2odt.gemspec ADDED
@@ -0,0 +1,108 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = "rd2odt"
3
+ s.version = "0.1.0"
4
+
5
+ s.authors = "Yuya.Nishida."
6
+ s.email = "yuyaAT@ATj96DOT.DOTorg"
7
+
8
+ s.rubyforge_project = s.name
9
+ s.homepage = "http://rubyforge.org/projects/#{s.name}/"
10
+ s.platform = Gem::Platform::RUBY
11
+ s.required_ruby_version = ">= 1.8.7"
12
+ s.rubygems_version = ">= 1.3.0"
13
+ s.requirements << "rubyzip"
14
+ s.require_paths = ["lib", "lib/rd2odt/rdtool"]
15
+ # s.autorequire = "rake"
16
+ # s.has_rdoc = true
17
+ # s.extra_rdoc_files = ["README"]
18
+ s.executable = "rd2odt"
19
+
20
+ s.summary = "RD(Ruby Document) to OpenDocument converter."
21
+ s.description = <<EOF
22
+ #{s.summary}
23
+ EOF
24
+
25
+ s.files = ["bin/rd2odt",
26
+
27
+ # "lib/**/*.rb",
28
+ "lib/rd2odt.rb",
29
+ "lib/rd2odt/rdtool/NOTICE.rd2odt",
30
+ "lib/rd2odt/rdtool/README.rd",
31
+ "lib/rd2odt/rdtool/README.rd.ja",
32
+ "lib/rd2odt/rdtool/rd/block-element.rb",
33
+ "lib/rd2odt/rdtool/rd/complex-list-item.rb",
34
+ "lib/rd2odt/rdtool/rd/desclist.rb",
35
+ "lib/rd2odt/rdtool/rd/document-struct.rb",
36
+ "lib/rd2odt/rdtool/rd/element.rb",
37
+ "lib/rd2odt/rdtool/rd/filter.rb",
38
+ "lib/rd2odt/rdtool/rd/inline-element.rb",
39
+ "lib/rd2odt/rdtool/rd/labeled-element.rb",
40
+ "lib/rd2odt/rdtool/rd/list.rb",
41
+ "lib/rd2odt/rdtool/rd/loose-struct.rb",
42
+ "lib/rd2odt/rdtool/rd/methodlist.rb",
43
+ "lib/rd2odt/rdtool/rd/output-format-visitor.rb",
44
+ "lib/rd2odt/rdtool/rd/package.rb",
45
+ "lib/rd2odt/rdtool/rd/parser-util.rb",
46
+ "lib/rd2odt/rdtool/rd/rbl-file.rb",
47
+ "lib/rd2odt/rdtool/rd/rbl-suite.rb",
48
+ "lib/rd2odt/rdtool/rd/rd-struct.rb",
49
+ "lib/rd2odt/rdtool/rd/rd2html-lib.rb",
50
+ "lib/rd2odt/rdtool/rd/rd2html-opt.rb",
51
+ "lib/rd2odt/rdtool/rd/rd2man-lib.rb",
52
+ "lib/rd2odt/rdtool/rd/rd2rdo-lib.rb",
53
+ "lib/rd2odt/rdtool/rd/rd2rmi-lib.rb",
54
+ "lib/rd2odt/rdtool/rd/rdblockparser.tab.rb",
55
+ "lib/rd2odt/rdtool/rd/rdfmt.rb",
56
+ "lib/rd2odt/rdtool/rd/rdinlineparser.tab.rb",
57
+ "lib/rd2odt/rdtool/rd/rdvisitor.rb",
58
+ "lib/rd2odt/rdtool/rd/reference-resolver.rb",
59
+ "lib/rd2odt/rdtool/rd/search-file.rb",
60
+ "lib/rd2odt/rdtool/rd/tree.rb",
61
+ "lib/rd2odt/rdtool/rd/version.rb",
62
+ "lib/rd2odt/rdtool/rd/visitor.rb",
63
+
64
+ # "doc/**/[a-z]*.rd*",
65
+ "doc/sample.rd.ja",
66
+ "doc/sample.rd.ja.ott",
67
+ "doc/sample.rd.ja.pdf",
68
+ "doc/sample/body-text.rd",
69
+ "doc/sample/enum-list-over-headline-multi-level.rd",
70
+ "doc/sample/enum-list-over-headline.rd",
71
+ "doc/sample/enum-list-over-item-list-multi-level-2.rd",
72
+ "doc/sample/enum-list-over-item-list-multi-level.rd",
73
+ "doc/sample/enum-list-over-item-list.rd",
74
+ "doc/sample/headline.rd",
75
+ "doc/sample/include.rd",
76
+ "doc/sample/list.rd",
77
+ "doc/sample/multi-paragraph.rd",
78
+ "doc/sample/verbatim.rd",
79
+ "doc/specification.ja.rd",
80
+
81
+ # "doc/**/*.odt"
82
+ "doc/sample/include-file-figure.odt",
83
+ "doc/sample/include-file-ole-object.odt",
84
+ "doc/sample/include-file-original-styled-text.odt",
85
+ "doc/sample/include-file-shape.odt",
86
+ "doc/sample/include-file-simple-styled-text.odt",
87
+ "doc/sample/include-file-simple-text.odt",
88
+ "doc/sample/include-file-table.odt",
89
+ "doc/sample/page-break.odt",
90
+
91
+ # "test/**/*.rb",
92
+ "test/functional/rd2odt-spec.rb",
93
+ "test/test-helper.rb",
94
+ "test/unit/rd2odt-spec.rb",
95
+ "rd2odt.gemspec",
96
+ "Rakefile",
97
+ "README",
98
+ "FUTURE",
99
+ "NEWS",
100
+ "LICENSE",
101
+ "setup.rb"]
102
+ end
103
+
104
+ # Editor settings
105
+ # - Emacs -
106
+ # local variables:
107
+ # mode: Ruby
108
+ # end: