rubyword 1.0.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -2
  3. data/CHANGELOG.md +44 -0
  4. data/README.cn.md +167 -0
  5. data/README.md +24 -3
  6. data/bin/run-example +11 -0
  7. data/doc/README.md +18 -1
  8. data/doc/doc-information.md +16 -0
  9. data/doc/footer.md +19 -0
  10. data/doc/header.md +11 -0
  11. data/doc/image.md +10 -0
  12. data/doc/link.md +10 -0
  13. data/doc/list.md +17 -0
  14. data/doc/paragraph.md +27 -0
  15. data/doc/table.md +21 -0
  16. data/doc/text.md +26 -1
  17. data/doc/title.md +14 -0
  18. data/doc/toc.md +11 -0
  19. data/example/doc_information.rb +13 -0
  20. data/example/footer.rb +5 -0
  21. data/example/header.rb +5 -0
  22. data/example/image.rb +7 -0
  23. data/example/link.rb +7 -0
  24. data/example/list.rb +11 -0
  25. data/example/paragraph.rb +17 -0
  26. data/example/result/.keep +0 -0
  27. data/example/result/doc-information.docx +0 -0
  28. data/example/result/footer.docx +0 -0
  29. data/example/result/header.docx +0 -0
  30. data/example/result/image.docx +0 -0
  31. data/example/result/link.docx +0 -0
  32. data/example/result/list.docx +0 -0
  33. data/example/result/paragraph.docx +0 -0
  34. data/example/result/table.docx +0 -0
  35. data/example/result/test.docx +0 -0
  36. data/example/result/text.docx +0 -0
  37. data/example/table.rb +18 -0
  38. data/example/test.rb +117 -0
  39. data/example/text.rb +9 -0
  40. data/example/toc.rb +24 -0
  41. data/lib/rubyword.rb +1 -0
  42. data/lib/rubyword/configuration.rb +1 -1
  43. data/lib/rubyword/document.rb +29 -41
  44. data/lib/rubyword/element/base.rb +12 -0
  45. data/lib/rubyword/element/link.rb +6 -5
  46. data/lib/rubyword/element/list.rb +4 -2
  47. data/lib/rubyword/element/paragraph.rb +38 -0
  48. data/lib/rubyword/element/section.rb +23 -10
  49. data/lib/rubyword/element/table.rb +60 -0
  50. data/lib/rubyword/element/text.rb +14 -79
  51. data/lib/rubyword/style.rb +4 -0
  52. data/lib/rubyword/version.rb +1 -1
  53. data/lib/rubyword/writer.rb +0 -4
  54. data/lib/rubyword/writer/part/document.rb +51 -44
  55. data/lib/rubyword/writer/part/footer.rb +1 -6
  56. data/lib/rubyword/writer/part/header.rb +2 -6
  57. data/lib/rubyword/writer/style/base.rb +0 -1
  58. data/lib/rubyword/writer/style/paragraph.rb +47 -0
  59. data/lib/rubyword/writer/style/section.rb +0 -1
  60. data/lib/rubyword/writer/style/word.rb +40 -0
  61. data/rubyword.gemspec +1 -2
  62. data/spec/rubyword/document_spec.rb +18 -3
  63. data/spec/rubyword/element/page_break_spec.rb +55 -0
  64. data/spec/rubyword/element/text_break_spec.rb +46 -0
  65. data/spec/rubyword/element/text_spec.rb +50 -0
  66. data/spec/spec_helper.rb +3 -30
  67. metadata +50 -20
  68. data/CHANGELOG.txt +0 -10
@@ -7,6 +7,18 @@ module Rubyword
7
7
  @rubyword = rubyword
8
8
  @section = section
9
9
  end
10
+
11
+ # filter html special char
12
+ def filter_text(text)
13
+ text = text.to_s
14
+ text.gsub('&', '&')
15
+ text.gsub('\'', ''')
16
+ text.gsub('"', '"')
17
+ text.gsub('<', '&lt;')
18
+ text.gsub('>', '&gt;')
19
+ text
20
+ end
21
+
10
22
  end
11
23
  end
12
24
  end
@@ -3,16 +3,17 @@ module Rubyword
3
3
  module Element
4
4
  class Link < Base
5
5
  attr_accessor :links
6
- def save(text, link, style)
6
+ def save(text, link, style=nil)
7
7
  @links ||= Queue.new
8
- return if text.nil?
8
+ return if text.nil?
9
+ text = filter_text(text)
9
10
  @rubyword.rels_documents << {
10
11
  Id: "rId#{@rubyword.init_rid}",
11
12
  Type: 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink',
12
13
  Target: link,
13
14
  TargetMode: 'External'
14
15
  }
15
- @links << { rId: @rubyword.init_rid, text: text, link: link }
16
+ @links << { rId: @rubyword.init_rid, text: text, link: link, style: style }
16
17
  @rubyword.init_rid = @rubyword.init_rid + 1
17
18
  end
18
19
 
@@ -20,10 +21,10 @@ module Rubyword
20
21
  @xml = xml
21
22
  link = self.links.pop
22
23
  @xml.send('w:p') {
24
+ Writer::Style::Paragraph.new(@section, @xml, @rubyword).write(link[:style])
23
25
  @xml.send('hyperlink', 'r:id' => "rId#{link[:rId]}", 'w:history' => '1') {
24
26
  @xml.send('w:r') {
25
- # TODO: add style
26
- @xml.send('w:rPr')
27
+ Writer::Style::Word.new(@section, @xml, @rubyword).write(link[:style])
27
28
  @xml.send('w:t', {'xml:space' => 'preserve'}, link[:text])
28
29
  }
29
30
  }
@@ -7,9 +7,11 @@ module Rubyword
7
7
  # write document and numbering
8
8
  def save(text, level, style)
9
9
  @lists ||= Queue.new
10
+ text = filter_text(text)
10
11
  @lists << {
11
12
  level: level.to_i - 1,
12
- text: text
13
+ text: text,
14
+ style: style
13
15
  }
14
16
  end
15
17
 
@@ -24,7 +26,7 @@ module Rubyword
24
26
  }
25
27
  }
26
28
  @xml.send('w:r') {
27
- @xml.send('w:rPr')
29
+ Writer::Style::Word.new(@section, @xml, @rubyword).write(list[:style])
28
30
  @xml.send('w:t', {'xml:space' => 'preserve'}, list[:text])
29
31
  }
30
32
  }
@@ -0,0 +1,38 @@
1
+ # -*- encoding : utf-8 -*-
2
+ module Rubyword
3
+ module Element
4
+ class Paragraph < Text
5
+ attr_accessor :paragraphs, :style
6
+ def initialize(rubyword, section=nil, style)
7
+ super(rubyword, section)
8
+ @style = style
9
+ end
10
+
11
+ def text(text, style=nil)
12
+ @paragraphs ||= []
13
+ text = filter_text(text)
14
+ @paragraphs << {
15
+ text: text,
16
+ style: style
17
+ }
18
+ end
19
+
20
+ def write(section=nil, xml=nil)
21
+ @xml = xml
22
+ @xml.send('w:p') {
23
+ @paragraphs.each do |p|
24
+ Writer::Style::Paragraph.new(@section, @xml, @rubyword).write(p[:style])
25
+ @xml.send('w:r') do
26
+ Writer::Style::Word.new(@section, @xml, @rubyword).write(p[:style])
27
+ @xml.send('w:t', {'xml:space' => 'preserve'}, p[:text])
28
+ end
29
+ end
30
+ }
31
+ end
32
+
33
+ def method_missing(name, *arg)
34
+ @section.send(name.to_sym, *arg)
35
+ end
36
+ end
37
+ end
38
+ end
@@ -1,4 +1,3 @@
1
- # -*- coding: utf-8 -*-
2
1
  require_relative 'base'
3
2
  require_relative 'text'
4
3
  require_relative 'link'
@@ -6,23 +5,37 @@ require_relative 'list'
6
5
  require_relative 'image'
7
6
  require_relative 'page_break'
8
7
  require_relative 'text_break'
8
+ require_relative 'paragraph'
9
+ require_relative 'table'
9
10
  module Rubyword
10
11
  module Element
11
12
  class Section
12
13
  attr_accessor :section_id, :style, :rubyword, :section_objects, :objects, :titles
14
+
13
15
  def initialize(section_count, style = nil, rubyword=nil)
14
16
  @section_id = section_count
15
17
  @style = style
16
18
  @rubyword = rubyword
17
19
  @section_objects = []
18
20
  @objects = []
21
+ @text_blocks = []
22
+ end
23
+
24
+ def p(style=nil, &block)
25
+ object ||= Paragraph.new(@rubyword, self, style)
26
+ return nil unless block_given?
27
+ object.instance_eval(&block)
28
+ @objects << object
19
29
  end
20
30
 
21
- def generate(&block)
22
- !block.nil? && block.arity < 1 ? instance_eval(&block) : block[self]
31
+ def table(style=nil, &block)
32
+ object ||= Table.new(@rubyword, self, style)
33
+ return nil unless block_given?
34
+ object.instance_eval(&block)
35
+ @objects << object
23
36
  end
24
37
 
25
- def text(text, style=nil)
38
+ def text(text, style=nil)
26
39
  object ||= Text.new(@rubyword, self)
27
40
  object.save(text, __callee__.to_s, style)
28
41
  @objects << object
@@ -38,18 +51,18 @@ module Rubyword
38
51
  @objects << object
39
52
  end
40
53
 
41
- def image(url)
42
- object ||= Image.new(@rubyword)
43
- object.save(url)
44
- @objects << object
45
- end
46
-
47
54
  def link(text, link, style=nil)
48
55
  object ||= Link.new(@rubyword)
49
56
  object.save(text, link, style)
50
57
  @objects << object
51
58
  end
52
59
 
60
+ def image(url)
61
+ object ||= Image.new(@rubyword)
62
+ object.save(url)
63
+ @objects << object
64
+ end
65
+
53
66
  def page_break(break_num=1)
54
67
  object ||= PageBreak.new(@rubyword)
55
68
  object.save(break_num)
@@ -0,0 +1,60 @@
1
+ # -*- encoding : utf-8 -*-
2
+ module Rubyword
3
+ module Element
4
+ class Table < Base
5
+ attr_accessor :trs
6
+ def initialize(rubyword, section=nil, style)
7
+ super(rubyword, section)
8
+ @style = style
9
+ @trs ||= []
10
+ end
11
+
12
+ def tr(style=nil, &block)
13
+ return unless block_given?
14
+ tr = Tr.new
15
+ tr.instance_eval(&block)
16
+ @trs << tr
17
+ end
18
+
19
+ def write(section=nil, xml=nil)
20
+ @xml = xml
21
+ @xml.send('w:tbl') {
22
+ @xml.send('w:tblGrid') {
23
+ @xml.send('w:gridCol', 'w:w' => '1750', 'w:type' => 'dxa')
24
+ @xml.send('w:gridCol', 'w:w' => '1750', 'w:type' => 'dxa')
25
+ @xml.send('w:gridCol', 'w:w' => '1750', 'w:type' => 'dxa')
26
+ }
27
+ @trs.each do |tr|
28
+ @xml.send('w:tr') {
29
+ @xml.send('w:trPr')
30
+ tr.texts.each do |text|
31
+ @xml.send('w:tc') {
32
+ @xml.send('w:tcPr') {
33
+ @xml.send('w:tcW', 'w:w'=>'1750', 'w:type' => 'dxa')
34
+ }
35
+ @xml.send('w:p') {
36
+ Writer::Style::Paragraph.new(@section, @xml, @rubyword).write(text[:style])
37
+ @xml.send('w:r') do
38
+ Writer::Style::Word.new(@section, @xml, @rubyword).write(text[:style])
39
+ @xml.send('w:t', {'xml:space' => 'preserve'}, text[:text])
40
+ end
41
+ }
42
+ }
43
+ end
44
+ }
45
+ end
46
+ }
47
+ end
48
+
49
+ end
50
+
51
+ class Tr
52
+ attr_accessor :texts
53
+ def th(text, style=nil)
54
+ @texts ||= []
55
+ @texts << { text: text, style: style }
56
+ end
57
+ end
58
+
59
+ end
60
+ end
@@ -1,31 +1,15 @@
1
- # -*- encoding : utf-8 -*-
2
1
  module Rubyword
3
2
  module Element
4
3
  class Text < Base
5
4
  attr_accessor :texts
6
-
5
+ # Toc indent size
7
6
  IndentSize = 200
8
- WordStyleList = {
9
- font_size: 'w:sz',
10
- color: 'w:color',
11
- underline: 'w:u',
12
- blod: 'w:b',
13
- all_caps: 'w:caps',
14
- italic: 'w:i',
15
- bgcolor: 'w:highlight'
16
- }.freeze
17
- ParagraphStyleList = {
18
- text_align: 'w:jc',
19
- spacing: 'w:spacing',
20
- indent_left: 'w:ind',
21
- indent_right: 'w:ind',
22
- indent_between: 'w:ind'
23
- }.freeze
24
-
25
- def save(text, type, style)
7
+
8
+ def save(text, type=nil, style=nil)
26
9
  @texts ||= Queue.new
27
10
  @section.titles ||= []
28
- return if text.nil?
11
+ return if text.nil? || type.nil?
12
+ text = filter_text(text)
29
13
  if type == 'text'
30
14
  text(text, style)
31
15
  else
@@ -34,21 +18,21 @@ module Rubyword
34
18
  end
35
19
 
36
20
  def text(text, style)
37
- @texts << { size: 'normal', text: text.to_s, style: style }
21
+ @texts << { size: 'normal', text: text, style: style }
38
22
  end
39
23
 
40
24
  (1..4).each do |num|
41
25
  define_method "title_#{num}" do |text, style|
42
26
  @rubyword.relation_rids << {rid: @rubyword.init_rid, type: "title_#{num}"}
43
- title_hs = {
27
+ title_info = {
44
28
  indent: (num - 1) * IndentSize,
45
29
  size: "title_#{num}",
46
30
  text: text.to_s,
47
31
  rid: @rubyword.init_rid,
48
32
  style: style
49
33
  }
50
- @section.titles << title_hs if (style && !style[:ignore_dir]) || style.nil?
51
- @texts << title_hs
34
+ @section.titles << title_info if (style && !style[:ignore_dir]) || style.nil?
35
+ @texts << title_info
52
36
  @rubyword.init_rid = @rubyword.init_rid + 1
53
37
  end
54
38
 
@@ -67,68 +51,19 @@ module Rubyword
67
51
  end
68
52
 
69
53
  def write(section=nil, xml=nil)
70
- @xml = xml
54
+ @xml, @section = xml, section
71
55
  text = self.texts.pop
56
+ return if text.to_s.empty?
72
57
  eval "write_#{text[:size]}(text)"
73
58
  end
74
59
 
75
60
  def write_normal(text)
76
- @xml.send('w:p') do
77
- write_paragraph_style(text[:style])
61
+ @xml.send('w:p') {
62
+ Writer::Style::Paragraph.new(@section, @xml, @rubyword).write(text[:style])
78
63
  @xml.send('w:r') do
79
- write_word_style(text[:style])
64
+ Writer::Style::Word.new(@section, @xml, @rubyword).write(text[:style])
80
65
  @xml.send('w:t', {'xml:space' => 'preserve'}, text[:text])
81
66
  end
82
- end
83
- end
84
-
85
- def write_word_style(style)
86
- if style.is_a?(Hash)
87
- @xml.send('w:rPr') {
88
- style.keys.each do |style_name|
89
- style_name = style_name.to_sym
90
- if WordStyleList.keys.include?(style_name)
91
- value =style[style_name]
92
- attribute = if !!value != value # not a bool type
93
- {'w:val' => value}
94
- else
95
- nil
96
- end
97
- doc_style = WordStyleList[style_name]
98
- @xml.send(doc_style, attribute)
99
- @xml.send('w:szCs', attribute) if style_name == :font_size
100
- end
101
- end
102
- }
103
- end
104
- end
105
-
106
- def write_paragraph_style(style)
107
- return unless style.is_a?(Hash)
108
- @xml.send('w:pPr') {
109
- style.keys.each do |style_name|
110
- style_name = style_name.to_sym
111
- next unless ParagraphStyleList.keys.include?(style_name)
112
- value =style[style_name]
113
- attribute = case style_name.to_s
114
- when 'spacing'
115
- {'w:after' => value}
116
- when 'indent_left'
117
- {'w:left' => value}
118
- when 'indent_right'
119
- {'w:right' => value}
120
- when 'indent_between'
121
- v = value.split '-'
122
- next unless v.is_a?(Array)
123
- { 'w:left' => v[0].to_i, 'w:right' => v[1].to_i }
124
- when !!value == value
125
- nil
126
- else
127
- {'w:val' => value}
128
- end
129
- doc_style = ParagraphStyleList[style_name]
130
- @xml.send(doc_style, attribute)
131
- end
132
67
  }
133
68
  end
134
69
 
@@ -0,0 +1,4 @@
1
+ require_relative 'writer/style/base'
2
+ require_relative 'writer/style/section'
3
+ require_relative "writer/style/paragraph"
4
+ require_relative "writer/style/word"
@@ -1,3 +1,3 @@
1
1
  module Rubyword
2
- VERSION = "1.0.0"
2
+ VERSION = "1.1.0"
3
3
  end
@@ -1,4 +1,3 @@
1
- # -*- encoding : utf-8 -*-
2
1
  require_relative "writer/part/base"
3
2
  require_relative "writer/part/toc"
4
3
  require_relative "writer/part/content_types"
@@ -16,9 +15,6 @@ require_relative "writer/part/theme"
16
15
  require_relative "writer/part/web_settings"
17
16
  require_relative "writer/part/footer"
18
17
  require_relative "writer/part/header"
19
- # style file
20
- require_relative 'writer/style/base'
21
- require_relative 'writer/style/section'
22
18
 
23
19
  module Rubyword
24
20
  module Writer
@@ -1,56 +1,63 @@
1
1
  # -*- encoding : utf-8 -*
2
2
  module Rubyword
3
3
  module Writer
4
- class Part::Document < Part::Base
5
- include ::Rubyword::Writer::Part::Toc
6
- DOCUMENT_ATTR = {
7
- 'xmlns:ve' => "http://schemas.openxmlformats.org/markup-compatibility/2006",
8
- 'xmlns:o' => "urn:schemas-microsoft-com:office:office",
9
- 'xmlns:r' => "http://schemas.openxmlformats.org/officeDocument/2006/relationships",
10
- 'xmlns:m' => "http://schemas.openxmlformats.org/officeDocument/2006/math",
11
- 'xmlns:v' => "urn:schemas-microsoft-com:vml",
12
- 'xmlns:wp' => "http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing",
13
- 'xmlns:w10' => "urn:schemas-microsoft-com:office:word",
14
- 'xmlns:w' => "http://schemas.openxmlformats.org/wordprocessingml/2006/main",
15
- 'xmlns:wne' => "http://schemas.microsoft.com/office/word/2006/wordml"
16
- }
4
+ module Part
5
+ class Document < Base
6
+ include Toc
7
+ DOCUMENT_ATTR = {
8
+ 'xmlns:ve' => "http://schemas.openxmlformats.org/markup-compatibility/2006",
9
+ 'xmlns:o' => "urn:schemas-microsoft-com:office:office",
10
+ 'xmlns:r' => "http://schemas.openxmlformats.org/officeDocument/2006/relationships",
11
+ 'xmlns:m' => "http://schemas.openxmlformats.org/officeDocument/2006/math",
12
+ 'xmlns:v' => "urn:schemas-microsoft-com:vml",
13
+ 'xmlns:wp' => "http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing",
14
+ 'xmlns:w10' => "urn:schemas-microsoft-com:office:word",
15
+ 'xmlns:w' => "http://schemas.openxmlformats.org/wordprocessingml/2006/main",
16
+ 'xmlns:wne' => "http://schemas.microsoft.com/office/word/2006/wordml"
17
+ }
17
18
 
18
- def write
19
- builder = Nokogiri::XML::Builder.new(:encoding => 'UTF-8') do |xml|
20
- xml.send('w:document', DOCUMENT_ATTR) {
21
- xml.send('w:body') {
22
- section_write(xml)
19
+ def write
20
+ builder = Nokogiri::XML::Builder.new(:encoding => 'UTF-8') do |xml|
21
+ xml.send('w:document', DOCUMENT_ATTR) {
22
+ xml.send('w:body') {
23
+ section_write(xml)
24
+ }
23
25
  }
24
- }
26
+ end
27
+ builder.to_xml
25
28
  end
26
- builder.to_xml
27
- end
28
29
 
29
- def section_write(xml)
30
- @object_blocks = []
31
- sections_count = @rubyword.sections.count
32
- current_section = 0
33
- # write TOC
34
- toc_block = write_toc(@rubyword, xml)
35
- @object_blocks.push(toc_block) if toc_block
36
- @rubyword.sections.each do |section|
37
- current_section = current_section + 1
38
- # 遍历输出各对象 object 信息
39
- section.objects.each{|object| @object_blocks << object.write(section, xml)}
40
- if current_section == sections_count
41
- @object_blocks << Style::Section.new(section, xml, @rubyword).write
42
- else
43
- p_block = xml.send('w:p') {
44
- xml.send('w:pPr') {
45
- @object_blocks << Style::Section.new(section, xml, @rubyword).write
46
- }
30
+ def section_write(xml)
31
+ @object_blocks = []
32
+ sections_count = @rubyword.sections.count
33
+ current_section = 0
34
+ # write TOC
35
+ write_toc(@rubyword, xml)
36
+ # To write all sections xml.
37
+ @rubyword.sections.each do |section|
38
+ current_section = current_section + 1
39
+ section.objects.each{|object|
40
+ # text should save in block
41
+ object.write(section, xml)
47
42
  }
48
- @object_blocks << p_block
43
+ # write in the last
44
+ if current_section == sections_count
45
+ Style::Section.new(section, xml, @rubyword).write
46
+ else
47
+ xml.send('w:p') {
48
+ xml.send('w:pPr') {
49
+ Style::Section.new(section, xml, @rubyword).write
50
+ }
51
+ }
52
+ end
53
+ end
54
+
55
+ if @rubyword.sections.empty?
56
+ Style::Section.new(section, xml, @rubyword).write
49
57
  end
50
58
  end
51
- @object_blocks
52
- end
53
-
54
- end # end of class
59
+
60
+ end # end of class
61
+ end
55
62
  end
56
63
  end