odf 0.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.
- checksums.yaml +7 -0
- data/.gitignore +9 -0
- data/.rspec +2 -0
- data/.travis.yml +5 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +76 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/odf.rb +65 -0
- data/lib/odf/component/abstract.rb +23 -0
- data/lib/odf/component/content.rb +35 -0
- data/lib/odf/component/image_set.rb +42 -0
- data/lib/odf/component/manifest.rb +33 -0
- data/lib/odf/component/meta.rb +25 -0
- data/lib/odf/component/mime_type.rb +11 -0
- data/lib/odf/component/settings.rb +15 -0
- data/lib/odf/component/styles.rb +26 -0
- data/lib/odf/component/xml_component.rb +29 -0
- data/lib/odf/document/abstract.rb +67 -0
- data/lib/odf/document/presentation.rb +13 -0
- data/lib/odf/document/spreadsheet.rb +13 -0
- data/lib/odf/document/text.rb +17 -0
- data/lib/odf/element/abstract.rb +34 -0
- data/lib/odf/element/abstract_contenteable.rb +11 -0
- data/lib/odf/element/binary_data.rb +13 -0
- data/lib/odf/element/draw_frame.rb +50 -0
- data/lib/odf/element/draw_page.rb +15 -0
- data/lib/odf/element/draw_text_box.rb +38 -0
- data/lib/odf/element/heading.rb +18 -0
- data/lib/odf/element/image.rb +41 -0
- data/lib/odf/element/number.rb +14 -0
- data/lib/odf/element/paragraph.rb +14 -0
- data/lib/odf/element/table.rb +19 -0
- data/lib/odf/element/table_cell.rb +30 -0
- data/lib/odf/element/table_row.rb +16 -0
- data/lib/odf/element/text_list.rb +21 -0
- data/lib/odf/element/text_list_item.rb +29 -0
- data/lib/odf/utils/file.rb +45 -0
- data/lib/odf/utils/xml.rb +13 -0
- data/lib/odf/version.rb +3 -0
- data/odf.gemspec +32 -0
- data/templates/default_style.xml +2 -0
- metadata +185 -0
@@ -0,0 +1,29 @@
|
|
1
|
+
module Odf::Component
|
2
|
+
module XmlComponent
|
3
|
+
|
4
|
+
def self.included(base)
|
5
|
+
base.class_eval { attr_reader :xml }
|
6
|
+
end
|
7
|
+
|
8
|
+
def initialize(document)
|
9
|
+
super
|
10
|
+
initialize_xml
|
11
|
+
end
|
12
|
+
|
13
|
+
def content
|
14
|
+
wrap_xml
|
15
|
+
xml.to_xml
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
def initialize_xml
|
20
|
+
@xml = Odf::Utils::Xml.new
|
21
|
+
xml.encoding = "UTF-8"
|
22
|
+
end
|
23
|
+
|
24
|
+
def wrap_xml
|
25
|
+
true
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module Odf::Document
|
2
|
+
class Abstract
|
3
|
+
|
4
|
+
COMPONENTS = [:content, :manifest, :meta, :mime_type, :styles, :settings]
|
5
|
+
|
6
|
+
attr_reader *(COMPONENTS + [:image_set])
|
7
|
+
attr_writer :creator
|
8
|
+
|
9
|
+
alias :document :itself
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
@content = Odf::Component::Content.new(self)
|
13
|
+
@image_set = Odf::Component::ImageSet.new(self)
|
14
|
+
@manifest = Odf::Component::Manifest.new(self)
|
15
|
+
@meta = Odf::Component::Meta.new(self)
|
16
|
+
@mime_type = Odf::Component::MimeType.new(self)
|
17
|
+
@settings = Odf::Component::Settings.new(self)
|
18
|
+
@styles = Odf::Component::Styles.new(self)
|
19
|
+
end
|
20
|
+
|
21
|
+
# Returns the mime type of document.
|
22
|
+
# All subclasses of this abstract class
|
23
|
+
# should define the +MIME_TYPE+ constant.
|
24
|
+
def media_type
|
25
|
+
self.class::MIME_TYPE
|
26
|
+
end
|
27
|
+
|
28
|
+
# Returns the file extension for
|
29
|
+
# open document format.
|
30
|
+
def extension
|
31
|
+
self.class::EXTENSION
|
32
|
+
end
|
33
|
+
|
34
|
+
def wrapper
|
35
|
+
self.class::WRAPPER
|
36
|
+
end
|
37
|
+
|
38
|
+
# Returns the components of the document.
|
39
|
+
def components
|
40
|
+
COMPONENTS
|
41
|
+
end
|
42
|
+
|
43
|
+
# Returns the creator information.
|
44
|
+
def creator
|
45
|
+
@creator || Odf.creator
|
46
|
+
end
|
47
|
+
|
48
|
+
# Serialize the document to given path.
|
49
|
+
def serialize(file_name)
|
50
|
+
Odf::Utils::File.serialize(file_name, self) && true
|
51
|
+
end
|
52
|
+
|
53
|
+
# Returns the output stream.
|
54
|
+
def to_blob
|
55
|
+
Odf::Utils::File.output_stream(self)
|
56
|
+
end
|
57
|
+
|
58
|
+
def add_image(uri)
|
59
|
+
image_set << uri
|
60
|
+
end
|
61
|
+
|
62
|
+
def root
|
63
|
+
content.root
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Odf::Document
|
2
|
+
class Presentation < Abstract
|
3
|
+
|
4
|
+
MIME_TYPE = 'application/vnd.oasis.opendocument.presentation'.freeze
|
5
|
+
EXTENSION = 'odp'.freeze
|
6
|
+
WRAPPER = 'office:presentation'.freeze
|
7
|
+
|
8
|
+
def add_page(options = {})
|
9
|
+
Odf::Element::DrawPage.build(self, options)
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Odf::Document
|
2
|
+
class Spreadsheet < Abstract
|
3
|
+
|
4
|
+
MIME_TYPE = 'application/vnd.oasis.opendocument.spreadsheet'.freeze
|
5
|
+
EXTENSION = 'ods'.freeze
|
6
|
+
WRAPPER = 'office:spreadsheet'.freeze
|
7
|
+
|
8
|
+
def add_table(options = {})
|
9
|
+
Odf::Element::Table.build(self, options)
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Odf::Document
|
2
|
+
class Text < Abstract
|
3
|
+
|
4
|
+
MIME_TYPE = 'application/vnd.oasis.opendocument.text'.freeze
|
5
|
+
EXTENSION = 'odt'.freeze
|
6
|
+
WRAPPER = 'office:text'.freeze
|
7
|
+
|
8
|
+
def add_heading(text, options = {})
|
9
|
+
Odf::Element::Heading.build(self, text, options)
|
10
|
+
end
|
11
|
+
|
12
|
+
def add_paragraph(text, options = {})
|
13
|
+
Odf::Element::Paragraph.build(self, text, options)
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Odf::Element
|
2
|
+
class Abstract
|
3
|
+
|
4
|
+
attr_reader :parent, :root
|
5
|
+
|
6
|
+
def initialize(parent, options = {})
|
7
|
+
@parent = parent
|
8
|
+
@root = document.content.xml.create_element(xml_tag, fetch_options(options))
|
9
|
+
@parent.root.add_child(@root)
|
10
|
+
end
|
11
|
+
|
12
|
+
# Accessor for valid options of element
|
13
|
+
def valid_options
|
14
|
+
@valid_options ||= defined?(self.class::VALID_OPTIONS) ? self.class::VALID_OPTIONS : {}
|
15
|
+
end
|
16
|
+
|
17
|
+
def xml_tag
|
18
|
+
self.class::XML_TAG
|
19
|
+
end
|
20
|
+
|
21
|
+
def document
|
22
|
+
parent.document
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
def fetch_options(options)
|
27
|
+
options.reduce({}) do |ret, (k, v)|
|
28
|
+
option = valid_options.fetch(k, k)
|
29
|
+
ret.merge(option => v)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module Odf::Element
|
2
|
+
module AbstractContenteable
|
3
|
+
|
4
|
+
def initialize(parent, content, options = {})
|
5
|
+
@parent = parent
|
6
|
+
@root = document.content.xml.create_element(xml_tag, content, fetch_options(options))
|
7
|
+
@parent.root.add_child(@root)
|
8
|
+
end
|
9
|
+
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module Odf::Element
|
2
|
+
class DrawFrame < Abstract
|
3
|
+
|
4
|
+
VALID_OPTIONS = {
|
5
|
+
caption_id: 'draw:caption-id',
|
6
|
+
class_names: 'draw:class-names',
|
7
|
+
copy_of: 'draw:copy-of',
|
8
|
+
id: 'draw:id',
|
9
|
+
name: 'draw:name',
|
10
|
+
style_name: 'draw:style-name',
|
11
|
+
text_style_name: 'draw:text-style-name',
|
12
|
+
transform: 'draw:transform',
|
13
|
+
z_index: 'draw:z-index',
|
14
|
+
p_class: 'presentation:class',
|
15
|
+
p_class_names: 'presentation:class-names',
|
16
|
+
placeholder: 'presentation:placeholder',
|
17
|
+
p_style_name: 'presentation:style-name',
|
18
|
+
user_transformed: 'presentation:user-transformed',
|
19
|
+
rel_height: 'style:rel-height',
|
20
|
+
rel_width: 'style:rel-width',
|
21
|
+
height: 'svg:height',
|
22
|
+
width: 'svg:width',
|
23
|
+
x: 'svg:x',
|
24
|
+
y: 'svg:y',
|
25
|
+
end_cell_address: 'table:end-cell-address',
|
26
|
+
end_x: 'table:end-x',
|
27
|
+
end_y: 'table:end-y',
|
28
|
+
table_background: 'table:table-background',
|
29
|
+
anchor_page_number: 'table:anchor-page-number',
|
30
|
+
anchor_type: 'table:anchor-type',
|
31
|
+
xml_id: 'xml:id',
|
32
|
+
layer: 'draw:layer'
|
33
|
+
}
|
34
|
+
|
35
|
+
XML_TAG = 'draw:frame'.freeze
|
36
|
+
|
37
|
+
def self.build(parent, options = {})
|
38
|
+
new(parent, options)
|
39
|
+
end
|
40
|
+
|
41
|
+
def add_text_box(options = {})
|
42
|
+
Odf::Element::DrawTextBox.build(self, options)
|
43
|
+
end
|
44
|
+
|
45
|
+
def add_image(options = {})
|
46
|
+
Odf::Element::Image.build(self, options)
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Odf::Element
|
2
|
+
class DrawPage < Abstract
|
3
|
+
|
4
|
+
XML_TAG = 'draw:page'.freeze
|
5
|
+
|
6
|
+
def self.build(document, options = {})
|
7
|
+
new(document, options)
|
8
|
+
end
|
9
|
+
|
10
|
+
def add_frame(options = {})
|
11
|
+
Odf::Element::DrawFrame.build(self, options)
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Odf::Element
|
2
|
+
class DrawTextBox < Abstract
|
3
|
+
|
4
|
+
VALID_OPTIONS = {
|
5
|
+
next_name: 'draw:chain-next-name',
|
6
|
+
corner_radius: 'draw:corner-radius',
|
7
|
+
max_height: 'fo:max-height',
|
8
|
+
max_width: 'fo:max-width',
|
9
|
+
min_height: 'fo:min-height',
|
10
|
+
min_width: 'fo:min-width',
|
11
|
+
text_id: 'text:id',
|
12
|
+
xml_id: 'xml:id'
|
13
|
+
}
|
14
|
+
|
15
|
+
XML_TAG = 'draw:text-box'.freeze
|
16
|
+
|
17
|
+
def self.build(parent, options = {})
|
18
|
+
new(parent, options)
|
19
|
+
end
|
20
|
+
|
21
|
+
def add_frame(options = {})
|
22
|
+
Odf::Element::DrawFrame.build(self, options)
|
23
|
+
end
|
24
|
+
|
25
|
+
def add_heading(text, options = {})
|
26
|
+
Odf::Element::Heading.build(self, text, options)
|
27
|
+
end
|
28
|
+
|
29
|
+
def add_paragraph(text, options = {})
|
30
|
+
Odf::Element::Paragraph.build(self, text, options)
|
31
|
+
end
|
32
|
+
|
33
|
+
def add_text_list(options = {})
|
34
|
+
Odf::Element::TextList.build(self, options)
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Odf::Element
|
2
|
+
class Heading < Abstract
|
3
|
+
|
4
|
+
include AbstractContenteable
|
5
|
+
|
6
|
+
XML_TAG = 'text:h'.freeze
|
7
|
+
|
8
|
+
def self.build(parent, text, options = {})
|
9
|
+
new(parent, text, options)
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize(parent, content, options = {})
|
13
|
+
options = { level: 1 }.merge(options)
|
14
|
+
super(parent, content, options)
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Odf::Element
|
2
|
+
class Image < Abstract
|
3
|
+
|
4
|
+
VALID_OPTIONS = {
|
5
|
+
filter_name: 'draw:filter-name',
|
6
|
+
actuate: 'xlink:actuate',
|
7
|
+
href: 'xlink:href',
|
8
|
+
show: 'xlink:show',
|
9
|
+
type: 'xlink:type',
|
10
|
+
xml_id: 'xml:id'
|
11
|
+
}
|
12
|
+
|
13
|
+
XML_TAG = 'draw:image'.freeze
|
14
|
+
|
15
|
+
def self.build(parent, options = {})
|
16
|
+
new(parent, options)
|
17
|
+
end
|
18
|
+
|
19
|
+
def initialize(parent, options)
|
20
|
+
@parent = parent
|
21
|
+
|
22
|
+
# Save image under Pictures directory
|
23
|
+
if options.fetch(:save, true) && options[:href]
|
24
|
+
uri = save_image(options[:href])
|
25
|
+
options.merge!({ href: uri, show: 'embed' })
|
26
|
+
end
|
27
|
+
|
28
|
+
super(parent, options)
|
29
|
+
end
|
30
|
+
|
31
|
+
def add_paragraph(text, options = {})
|
32
|
+
Odf::Element::Paragraph.build(self, text, options)
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
def save_image(href)
|
37
|
+
document.add_image(href)
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Odf::Element
|
2
|
+
class Table < Abstract
|
3
|
+
|
4
|
+
VALID_OPTIONS = {
|
5
|
+
table_name: 'table:name'
|
6
|
+
}
|
7
|
+
|
8
|
+
XML_TAG = 'table:table'.freeze
|
9
|
+
|
10
|
+
def self.build(parent, options = {})
|
11
|
+
new(parent, options)
|
12
|
+
end
|
13
|
+
|
14
|
+
def add_table_row(options = {})
|
15
|
+
Odf::Element::TableRow.build(self, options)
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Odf::Element
|
2
|
+
class TableCell < Abstract
|
3
|
+
|
4
|
+
TYPE_MAP = {
|
5
|
+
Fixnum => 'float',
|
6
|
+
Float => 'float',
|
7
|
+
String => 'string'
|
8
|
+
}
|
9
|
+
|
10
|
+
VALID_OPTIONS = {}
|
11
|
+
XML_TAG = 'table:table-cell'.freeze
|
12
|
+
|
13
|
+
def self.build(parent, content, options = {})
|
14
|
+
type = options[:type] || infer_type(content)
|
15
|
+
self_opts = {
|
16
|
+
'office:value-type' => type,
|
17
|
+
'office:value' => content
|
18
|
+
}.merge(options)
|
19
|
+
this = new(parent, self_opts)
|
20
|
+
|
21
|
+
Odf::Element::Paragraph.build(this, content, options)
|
22
|
+
this
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.infer_type(content)
|
26
|
+
TYPE_MAP[content.class] || 'string'
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|