rodf 1.1.1 → 1.2.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/lib/rodf/document.rb CHANGED
@@ -1,20 +1,14 @@
1
- require 'zip'
2
-
3
- require_relative 'container'
4
- require_relative 'skeleton'
5
- require_relative 'style'
6
-
7
1
  module RODF
8
2
  class Document < Container
9
- contains :styles, :default_styles, :office_styles
10
-
11
3
  def self.file(ods_file_name, &contents)
12
4
  doc = new
5
+
13
6
  if contents.arity.zero?
14
7
  contents.call(doc)
15
8
  else
16
9
  doc.instance_exec(doc, &contents)
17
10
  end
11
+
18
12
  doc.write_to ods_file_name
19
13
  end
20
14
 
@@ -25,22 +19,109 @@ module RODF
25
19
  def bytes
26
20
  buffer = Zip::OutputStream::write_buffer do |zio|
27
21
  zio.put_next_entry('META-INF/manifest.xml')
22
+
28
23
  zio << self.class.skeleton.manifest(self.class.doc_type)
29
24
 
30
25
  zio.put_next_entry('styles.xml')
26
+
31
27
  zio << self.class.skeleton.styles
28
+
32
29
  zio << self.office_styles_xml unless self.office_styles.empty?
30
+
33
31
  zio << "</office:styles> </office:document-styles>"
34
32
 
35
33
  zio.put_next_entry('content.xml')
34
+
36
35
  zio << self.xml
37
36
  end
38
37
 
39
38
  buffer.set_encoding('ASCII-8BIT')
39
+
40
40
  buffer.rewind
41
+
41
42
  buffer.sysread
42
43
  end
43
- private
44
+
45
+ def styles
46
+ @styles ||= []
47
+ end
48
+
49
+ def style(*args, &block)
50
+ x = Style.new(*args, &block)
51
+
52
+ styles << x
53
+
54
+ return x
55
+ end
56
+
57
+ def styles_xml
58
+ styles.map(&:xml).join
59
+ end
60
+
61
+ def add_styles(*elements)
62
+ if elements.first.is_a?(Array)
63
+ elements = elements.first
64
+ end
65
+
66
+ elements.each do |element|
67
+ style(element)
68
+ end
69
+ end
70
+
71
+ def default_styles
72
+ @default_styles ||= []
73
+ end
74
+
75
+ def default_style(*args, &block)
76
+ x = DefaultStyle.new(*args, &block)
77
+
78
+ default_styles << x
79
+
80
+ return x
81
+ end
82
+
83
+ def default_styles_xml
84
+ default_styles.map(&:xml).join
85
+ end
86
+
87
+ def add_default_styles(*elements)
88
+ if elements.first.is_a?(Array)
89
+ elements = elements.first
90
+ end
91
+
92
+ elements.each do |element|
93
+ default_style(element)
94
+ end
95
+ end
96
+
97
+ def office_styles
98
+ @office_styles ||= []
99
+ end
100
+
101
+ def office_style(*args, &block)
102
+ x = OfficeStyle.new(*args, &block)
103
+
104
+ office_styles << x
105
+
106
+ return x
107
+ end
108
+
109
+ def office_styles_xml
110
+ office_styles.map(&:xml).join
111
+ end
112
+
113
+ def add_office_styles(*elements)
114
+ if elements.first.is_a?(Array)
115
+ elements = elements.first
116
+ end
117
+
118
+ elements.each do |element|
119
+ office_style(element)
120
+ end
121
+ end
122
+
123
+ private
124
+
44
125
  def self.skeleton
45
126
  @skeleton ||= Skeleton.new
46
127
  end
@@ -1,7 +1,3 @@
1
- require 'builder'
2
-
3
- require_relative 'paragraph_container'
4
-
5
1
  module RODF
6
2
  class Hyperlink < ParagraphContainer
7
3
  def initialize(first, second = {})
@@ -25,8 +21,11 @@ module RODF
25
21
  class ParagraphContainer < Container
26
22
  def link(*args)
27
23
  l = Hyperlink.new(*args)
24
+
28
25
  yield l if block_given?
26
+
29
27
  content_parts << l
28
+
30
29
  l
31
30
  end
32
31
  alias a link
@@ -1,5 +1,3 @@
1
- require 'builder'
2
-
3
1
  module RODF
4
2
  class MasterPage
5
3
  def initialize(name, opts = {})
@@ -7,8 +5,7 @@ module RODF
7
5
  end
8
6
 
9
7
  def xml
10
- Builder::XmlMarkup.new.tag! 'style:master-page',
11
- 'style:name' => @name, 'style:page-layout-name' => @layout
8
+ Builder::XmlMarkup.new.tag! 'style:master-page', 'style:name' => @name, 'style:page-layout-name' => @layout
12
9
  end
13
10
  end
14
11
  end
@@ -1,18 +1,37 @@
1
- require 'builder'
2
-
3
- require_relative 'container'
4
- require_relative 'property'
5
-
6
1
  module RODF
7
2
  class PageLayout < Container
8
- contains :properties
9
-
10
3
  def initialize(name)
11
4
  super
12
5
 
13
6
  @name = name
14
7
  end
15
8
 
9
+ def properties
10
+ @properties ||= []
11
+ end
12
+
13
+ def property(*args, &block)
14
+ x = Property.new(*args, &block)
15
+
16
+ properties << x
17
+
18
+ return x
19
+ end
20
+
21
+ def properties_xml
22
+ properties.map(&:xml).join
23
+ end
24
+
25
+ def add_properties(*elements)
26
+ if elements.first.is_a?(Array)
27
+ elements = elements.first
28
+ end
29
+
30
+ elements.each do |element|
31
+ property(element)
32
+ end
33
+ end
34
+
16
35
  def xml
17
36
  Builder::XmlMarkup.new.tag! 'style:page-layout', 'style:name' => @name do |b|
18
37
  b << properties_xml
@@ -1,14 +1,12 @@
1
- require 'builder'
2
-
3
- require_relative 'paragraph_container'
4
-
5
1
  module RODF
6
2
  class Paragraph < ParagraphContainer
7
3
  def initialize(fst = nil, snd = {})
8
4
  super
9
5
 
10
- first_is_hash = fst.instance_of? Hash
6
+ first_is_hash = fst.instance_of?(Hash)
7
+
11
8
  span(fst) unless first_is_hash
9
+
12
10
  @elem_attrs = make_element_attributes(first_is_hash ? fst : snd)
13
11
  end
14
12
 
@@ -18,7 +16,7 @@ module RODF
18
16
  end
19
17
  end
20
18
 
21
- private
19
+ private
22
20
 
23
21
  def make_element_attributes(opts)
24
22
  attrs = {}
@@ -1,7 +1,3 @@
1
- require 'builder'
2
-
3
- require_relative 'container'
4
-
5
1
  module RODF
6
2
  # Container for all kinds of paragraph content
7
3
  class ParagraphContainer < Container
@@ -12,5 +8,23 @@ module RODF
12
8
  def content_parts_xml
13
9
  content_parts.map {|p| p.xml}.join
14
10
  end
11
+
12
+ def span(*args)
13
+ s = Span.new(*args)
14
+
15
+ yield s if block_given?
16
+
17
+ content_parts << s
18
+
19
+ s
20
+ end
21
+
22
+ def <<(content)
23
+ span(content)
24
+ end
25
+
26
+ def method_missing(style, *args)
27
+ span(style, *args)
28
+ end
15
29
  end
16
30
  end
data/lib/rodf/property.rb CHANGED
@@ -1,66 +1,82 @@
1
- require 'builder'
2
-
3
1
  module RODF
4
2
  class Property
5
- PROPERTY_NAMES = {cell: 'table-cell-properties',
6
- text: 'text-properties',
7
- column: 'table-column-properties',
8
- row: 'table-row-properties',
9
- page_layout: 'page-layout-properties',
10
- header_footer: 'header-footer-properties',
11
- list_level: 'list-level-properties',
12
- conditional: 'map'}
3
+ PROPERTY_NAMES = {
4
+ cell: 'table-cell-properties',
5
+ text: 'text-properties',
6
+ column: 'table-column-properties',
7
+ row: 'table-row-properties',
8
+ page_layout: 'page-layout-properties',
9
+ header_footer: 'header-footer-properties',
10
+ list_level: 'list-level-properties',
11
+ conditional: 'map',
12
+ }
13
+
13
14
  TRANSLATED_SPECS = [:border_color, :border_style, :border_width]
14
15
 
15
- ATTRIBUTES_TO_NAMESPACES = [[
16
- ['column-width', 'rotation-angle', 'text-underline-type', 'tab-stop-distance',
17
- 'condition', 'apply-style-name', 'base-cell-address', 'row-height',
18
- 'country-asian', 'country-complex', 'font-charset', 'font-charset-asian',
19
- 'font-charset-complex', 'font-family-asian', 'font-family-complex', 'font-family-generic',
20
- 'font-family-generic-asian', 'font-family-generic-complex', 'font-name', 'font-name-asian',
21
- 'font-name-complex', 'font-pitch', 'font-pitch-asian', 'font-pitch-complex', 'font-relief',
22
- 'font-size-asian', 'font-size-complex', 'font-size-rel', 'font-size-rel-asian',
23
- 'font-size-rel-complex', 'font-style-asian', 'font-style-complex', 'font-style-name',
24
- 'font-style-name-asian', 'font-style-name-complex', 'font-weight-asian', 'font-weight-complex',
25
- 'language-asian', 'language-complex', 'letter-kerning', 'rfc-language-tag',
26
- 'rfc-language-tag-asian', 'rfc-language-tag-complex', 'script-asian', 'script-complex',
27
- 'script-type', 'text-blinking', 'text-combine', 'text-combine-end-char',
28
- 'text-combine-start-char', 'text-emphasize', 'text-line-through-color',
29
- 'text-line-through-mode', 'text-line-through-style', 'text-line-through-text',
30
- 'text-line-through-text-style', 'text-line-through-type', 'text-line-through-width',
31
- 'text-outline', 'text-overline-color', 'text-overline-mode', 'text-overline-style',
32
- 'text-overline-type', 'text-overline-width', 'text-position', 'text-rotation-angle',
33
- 'text-rotation-scale', 'text-scale', 'text-underline-color', 'text-underline-mode',
34
- 'text-underline-style', 'text-underline-width', 'use-window-font-color',
35
- 'border-line-width', 'border-line-width-bottom', 'border-line-width-left',
36
- 'border-line-width-right', 'border-line-width-top', 'cell-protect', 'decimal-places',
37
- 'diagonal-bl-tr', 'diagonal-bl-tr-widths', 'diagonal-tl-br', 'diagonal-tl-br-widths',
38
- 'direction', 'glyph-orientation-vertical', 'print-content', 'repeat-content',
39
- 'rotation-align', 'shadow', 'shrink-to-fit', 'text-align-source',
40
- 'vertical-align', 'writing-mode', 'min-row-height', 'use-optimal-row-height',
41
- 'rel-column-width', 'use-optimal-column-width', 'auto-text-indent', 'background-transparency',
42
- 'font-independent-line-spacing', 'join-border', 'justify-single-word', 'line-break',
43
- 'line-height-at-least', 'line-spacing', 'page-number', 'punctuation-wrap', 'register-true',
44
- 'snap-to-layout-grid', 'text-autospace',
45
- 'writing-mode-automatic',
46
- 'first-page-number', 'footnote-max-height', 'layout-grid-base-height', 'layout-grid-base-width',
47
- 'layout-grid-color', 'layout-grid-display', 'layout-grid-lines', 'layout-grid-mode',
48
- 'layout-grid-print', 'layout-grid-ruby-below', 'layout-grid-ruby-height', 'layout-grid-snap-to',
49
- 'layout-grid-standard-mode', 'num-format', 'num-letter-sync', 'num-prefix', 'num-suffix',
50
- 'paper-tray-name', 'print', 'print-orientation', 'print-page-order',
51
- 'register-truth-ref-style-name', 'scale-to', 'scale-to-pages', 'table-centering',
52
- 'dynamic-spacing',
53
- 'ruby-align', 'ruby-position',
54
- 'editable', 'protect',
55
- 'may-break-between-rows', 'rel-width', 'width',
56
- 'vertical-pos', 'vertical-rel'], 'style'],
57
- [['height', 'y'], 'svg'],
58
- [['dont-balance-text-columns', 'list-level-position-and-space-mode', 'min-label-distance',
59
- 'min-label-width', 'space-before'], 'text'],
60
- [['align', 'border-model', 'display'], 'table']]
16
+ ATTRIBUTES_TO_NAMESPACES = [
17
+ [
18
+ [
19
+ 'column-width', 'rotation-angle', 'text-underline-type', 'tab-stop-distance',
20
+ 'condition', 'apply-style-name', 'base-cell-address', 'row-height',
21
+ 'country-asian', 'country-complex', 'font-charset', 'font-charset-asian',
22
+ 'font-charset-complex', 'font-family-asian', 'font-family-complex', 'font-family-generic',
23
+ 'font-family-generic-asian', 'font-family-generic-complex', 'font-name', 'font-name-asian',
24
+ 'font-name-complex', 'font-pitch', 'font-pitch-asian', 'font-pitch-complex', 'font-relief',
25
+ 'font-size-asian', 'font-size-complex', 'font-size-rel', 'font-size-rel-asian',
26
+ 'font-size-rel-complex', 'font-style-asian', 'font-style-complex', 'font-style-name',
27
+ 'font-style-name-asian', 'font-style-name-complex', 'font-weight-asian', 'font-weight-complex',
28
+ 'language-asian', 'language-complex', 'letter-kerning', 'rfc-language-tag',
29
+ 'rfc-language-tag-asian', 'rfc-language-tag-complex', 'script-asian', 'script-complex',
30
+ 'script-type', 'text-blinking', 'text-combine', 'text-combine-end-char',
31
+ 'text-combine-start-char', 'text-emphasize', 'text-line-through-color',
32
+ 'text-line-through-mode', 'text-line-through-style', 'text-line-through-text',
33
+ 'text-line-through-text-style', 'text-line-through-type', 'text-line-through-width',
34
+ 'text-outline', 'text-overline-color', 'text-overline-mode', 'text-overline-style',
35
+ 'text-overline-type', 'text-overline-width', 'text-position', 'text-rotation-angle',
36
+ 'text-rotation-scale', 'text-scale', 'text-underline-color', 'text-underline-mode',
37
+ 'text-underline-style', 'text-underline-width', 'use-window-font-color',
38
+ 'border-line-width', 'border-line-width-bottom', 'border-line-width-left',
39
+ 'border-line-width-right', 'border-line-width-top', 'cell-protect', 'decimal-places',
40
+ 'diagonal-bl-tr', 'diagonal-bl-tr-widths', 'diagonal-tl-br', 'diagonal-tl-br-widths',
41
+ 'direction', 'glyph-orientation-vertical', 'print-content', 'repeat-content',
42
+ 'rotation-align', 'shadow', 'shrink-to-fit', 'text-align-source',
43
+ 'vertical-align', 'writing-mode', 'min-row-height', 'use-optimal-row-height',
44
+ 'rel-column-width', 'use-optimal-column-width', 'auto-text-indent', 'background-transparency',
45
+ 'font-independent-line-spacing', 'join-border', 'justify-single-word', 'line-break',
46
+ 'line-height-at-least', 'line-spacing', 'page-number', 'punctuation-wrap', 'register-true',
47
+ 'snap-to-layout-grid', 'text-autospace',
48
+ 'writing-mode-automatic',
49
+ 'first-page-number', 'footnote-max-height', 'layout-grid-base-height', 'layout-grid-base-width',
50
+ 'layout-grid-color', 'layout-grid-display', 'layout-grid-lines', 'layout-grid-mode',
51
+ 'layout-grid-print', 'layout-grid-ruby-below', 'layout-grid-ruby-height', 'layout-grid-snap-to',
52
+ 'layout-grid-standard-mode', 'num-format', 'num-letter-sync', 'num-prefix', 'num-suffix',
53
+ 'paper-tray-name', 'print', 'print-orientation', 'print-page-order',
54
+ 'register-truth-ref-style-name', 'scale-to', 'scale-to-pages', 'table-centering',
55
+ 'dynamic-spacing',
56
+ 'ruby-align', 'ruby-position',
57
+ 'editable', 'protect',
58
+ 'may-break-between-rows', 'rel-width', 'width',
59
+ 'vertical-pos', 'vertical-rel'
60
+ ],
61
+ 'style'
62
+ ],
63
+ [
64
+ ['height', 'y'],
65
+ 'svg'
66
+ ],
67
+ [
68
+ ['dont-balance-text-columns', 'list-level-position-and-space-mode', 'min-label-distance', 'min-label-width', 'space-before'],
69
+ 'text'
70
+ ],
71
+ [
72
+ ['align', 'border-model', 'display'],
73
+ 'table'
74
+ ]
75
+ ]
61
76
 
62
77
  def initialize(type, specs={})
63
78
  @name = 'style:' + (PROPERTY_NAMES[type] || "#{type}-properties")
79
+
64
80
  @specs = translate(specs).map { |k, v| [k.to_s, v] }
65
81
  end
66
82
 
@@ -68,25 +84,32 @@ module RODF
68
84
  specs = @specs.inject({}) do |acc, kv|
69
85
  acc.merge Property.lookup_namespace_for(kv.first) + ':' + kv.first => kv.last
70
86
  end
87
+
71
88
  Builder::XmlMarkup.new.tag! @name, specs
72
89
  end
73
90
 
74
- class << self
75
- def lookup_namespace_for(property_name)
76
- as = ATTRIBUTES_TO_NAMESPACES.select {|a| a[0].include? property_name}
77
- as.empty? ? 'fo' : as[0][1]
78
- end
91
+ def self.lookup_namespace_for(property_name)
92
+ as = ATTRIBUTES_TO_NAMESPACES.select {|a| a[0].include? property_name}
93
+
94
+ as.empty? ? 'fo' : as[0][1]
79
95
  end
80
- private
96
+
97
+ private
98
+
81
99
  def translate(specs)
82
100
  result = specs.clone
101
+
83
102
  tspecs = specs.select {|k, v| TRANSLATED_SPECS.include? k}
103
+
84
104
  tspecs.map {|k, v| result.delete k}
105
+
85
106
  tspecs = tspecs.inject({}) {|acc, e| acc.merge e.first => e.last}
107
+
86
108
  if tspecs[:border_width] && tspecs[:border_style] && tspecs[:border_color] then
87
109
  width = tspecs[:border_width].split
88
110
  style = tspecs[:border_style].split
89
111
  color = tspecs[:border_color].split
112
+
90
113
  if width.length == 1 && style.length == 1 && color.length == 1 then
91
114
  result[:border] = [width[0], style[0], color[0]].join(' ')
92
115
  else
@@ -96,13 +119,16 @@ module RODF
96
119
  result['border-left'] = cascading_join(width, style, color, 3, 1, 0)
97
120
  end
98
121
  end
122
+
99
123
  result
100
124
  end
101
125
 
102
126
  def cascading_join(width_parts, style_parts, color_parts, *prefs)
103
- [ cascade(width_parts, prefs),
127
+ [
128
+ cascade(width_parts, prefs),
104
129
  cascade(style_parts, prefs),
105
- cascade(color_parts, prefs)].join(' ')
130
+ cascade(color_parts, prefs),
131
+ ].join(' ')
106
132
  end
107
133
 
108
134
  def cascade(list, prefs)
data/lib/rodf/row.rb CHANGED
@@ -1,25 +1,54 @@
1
- require 'builder'
2
-
3
- require_relative 'container'
4
- require_relative 'cell'
5
-
6
1
  module RODF
7
2
  class Row < Container
8
- contains :cells
9
3
  attr_reader :number
10
4
  attr_writer :style
11
5
 
12
6
  def initialize(number=0, opts={})
13
7
  @number = number
14
- @style = opts[:style]
8
+
9
+ @elem_attrs = {}
10
+
11
+ @elem_attrs['table:style-name'] = opts[:style] unless opts[:style].nil?
12
+
13
+ if opts[:attributes]
14
+ @elem_attrs.merge!(opts[:attributes])
15
+ end
15
16
 
16
17
  super
17
18
  end
18
19
 
20
+ def cells
21
+ @cells ||= []
22
+ end
23
+
24
+ def cell(*args, &block)
25
+ x = Cell.new(*args, &block)
26
+
27
+ cells << x
28
+
29
+ return x
30
+ end
31
+
32
+ def cells_xml
33
+ cells.map(&:xml).join
34
+ end
35
+
36
+ def style=(style_name)
37
+ @elem_attrs['table:style-name'] = style_name
38
+ end
39
+
40
+ def add_cells(*elements)
41
+ if elements.first.is_a?(Array)
42
+ elements = elements.first
43
+ end
44
+
45
+ elements.each do |element|
46
+ cell(element)
47
+ end
48
+ end
49
+
19
50
  def xml
20
- elem_attrs = {}
21
- elem_attrs['table:style-name'] = @style unless @style.nil?
22
- Builder::XmlMarkup.new.tag! 'table:table-row', elem_attrs do |xml|
51
+ Builder::XmlMarkup.new.tag! 'table:table-row', @elem_attrs do |xml|
23
52
  xml << cells_xml
24
53
  end
25
54
  end
data/lib/rodf/skeleton.rb CHANGED
@@ -1,5 +1,3 @@
1
- require 'erb'
2
-
3
1
  module RODF
4
2
  class Skeleton
5
3
  def manifest(document_type)
@@ -9,7 +7,9 @@ module RODF
9
7
  def styles
10
8
  template('styles.pxml')
11
9
  end
12
- private
10
+
11
+ private
12
+
13
13
  def template(fname)
14
14
  File.open(File.dirname(__FILE__) + '/skeleton/' + fname).read
15
15
  end
data/lib/rodf/span.rb CHANGED
@@ -1,8 +1,3 @@
1
- require 'builder'
2
-
3
- require_relative 'compatibility'
4
- require_relative 'paragraph_container'
5
-
6
1
  module RODF
7
2
  class TextNode
8
3
  def initialize(content)
@@ -10,46 +5,41 @@ module RODF
10
5
  end
11
6
 
12
7
  def xml
13
- @content.to_s.to_xs
8
+ Builder::XChar.encode(@content.to_s)
14
9
  end
15
10
  end
16
11
 
17
12
  class Span < ParagraphContainer
18
- def initialize(first, second = nil)
19
- super
13
+ def initialize(first, second=nil, style: nil, &block)
14
+ super(first, second, &block)
20
15
 
21
16
  @style = nil
22
17
 
23
18
  if first.instance_of?(Symbol)
19
+ ### Legacy behaviour
20
+
24
21
  @style = first
25
- content_parts << TextNode.new(second) unless second.nil?
22
+
23
+ if !second.nil?
24
+ content_parts << TextNode.new(second)
25
+ end
26
26
  else
27
+ if style
28
+ @style = style
29
+ end
30
+
27
31
  content_parts << TextNode.new(first)
28
32
  end
29
33
  end
30
34
 
31
35
  def xml
32
- return content_parts_xml if @style.nil?
33
- Builder::XmlMarkup.new.text:span, 'text:style-name' => @style do |xml|
34
- xml << content_parts_xml
36
+ if @style.nil?
37
+ return content_parts_xml
35
38
  end
36
- end
37
- end
38
-
39
- class ParagraphContainer < Container
40
- def span(*args)
41
- s = Span.new(*args)
42
- yield s if block_given?
43
- content_parts << s
44
- s
45
- end
46
39
 
47
- def <<(content)
48
- span(content)
49
- end
50
-
51
- def method_missing(style, *args)
52
- span(style, *args)
40
+ Builder::XmlMarkup.new.text(:span, 'text:style-name' => @style) do |xml|
41
+ xml << content_parts_xml
42
+ end
53
43
  end
54
44
  end
55
45
  end