rd2odt 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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: