rubyword 1.0.0 → 1.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 (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