goldendocx 0.2.2 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +1 -1
- data/.ruby-version +1 -0
- data/CHANGELOG.md +8 -2
- data/Gemfile.lock +3 -1
- data/README.md +10 -2
- data/Rakefile +14 -3
- data/demo/tables/create_embed_image_table.rb +3 -3
- data/demo/templates/generate_codes.rb +10 -0
- data/demo/templates/xml_to_class.rb +97 -0
- data/demo/texts/append_plain_text.rb +1 -1
- data/demo/texts/append_styled_text.rb +1 -2
- data/demo/texts/create_text.rb +14 -0
- data/lib/extensions/active_support_extensions.rb +16 -0
- data/lib/extensions/nokogiri_extensions.rb +41 -0
- data/lib/extensions/ox_extensions.rb +35 -0
- data/lib/extensions/xml_serialize_extensions.rb +45 -0
- data/lib/goldendocx/charts/properties.rb +1 -1
- data/lib/goldendocx/charts/series.rb +2 -2
- data/lib/goldendocx/charts.rb +1 -1
- data/lib/goldendocx/components/bar_chart.rb +2 -2
- data/lib/goldendocx/components/chart.rb +6 -6
- data/lib/goldendocx/components/column_chart.rb +2 -2
- data/lib/goldendocx/components/doughnut_chart.rb +2 -2
- data/lib/goldendocx/components/line_chart.rb +2 -2
- data/lib/goldendocx/components/properties/font_property.rb +19 -0
- data/lib/goldendocx/components/properties/language_property.rb +18 -0
- data/lib/goldendocx/components/properties/run_property.rb +2 -0
- data/lib/goldendocx/components/properties.rb +1 -1
- data/lib/goldendocx/components/table.rb +2 -2
- data/lib/goldendocx/components.rb +1 -1
- data/lib/goldendocx/content_types/default.rb +2 -6
- data/lib/goldendocx/content_types/override.rb +2 -6
- data/lib/goldendocx/document.rb +9 -28
- data/lib/goldendocx/documents/body.rb +23 -14
- data/lib/goldendocx/documents/document.rb +2 -4
- data/lib/goldendocx/documents/latent_styles.rb +12 -0
- data/lib/goldendocx/documents/properties/default_style_property.rb +17 -0
- data/lib/goldendocx/documents/properties/page_margin_property.rb +37 -0
- data/lib/goldendocx/documents/properties/page_size_property.rb +17 -0
- data/lib/goldendocx/documents/properties/paragraph_default_style_property.rb +16 -0
- data/lib/goldendocx/documents/properties/run_default_style_property.rb +22 -0
- data/lib/goldendocx/documents/properties/section_property.rb +17 -0
- data/lib/goldendocx/documents/properties/style_name_property.rb +16 -0
- data/lib/goldendocx/documents/properties.rb +12 -0
- data/lib/goldendocx/documents/settings.rb +23 -0
- data/lib/goldendocx/documents/style.rb +10 -10
- data/lib/goldendocx/documents/styles.rb +9 -33
- data/lib/goldendocx/documents.rb +1 -1
- data/lib/goldendocx/docx.rb +55 -12
- data/lib/goldendocx/element.rb +33 -140
- data/lib/goldendocx/has_associations.rb +54 -0
- data/lib/goldendocx/has_attributes.rb +67 -0
- data/lib/goldendocx/has_children.rb +116 -0
- data/lib/goldendocx/images/picture.rb +1 -1
- data/lib/goldendocx/images/properties.rb +1 -1
- data/lib/goldendocx/images.rb +1 -1
- data/lib/goldendocx/{documents → models}/relationship.rb +1 -1
- data/lib/goldendocx/models/relationships.rb +31 -0
- data/lib/goldendocx/models.rb +10 -0
- data/lib/goldendocx/parts/app.rb +46 -0
- data/lib/goldendocx/parts/content_types.rb +16 -30
- data/lib/goldendocx/parts/core.rb +46 -0
- data/lib/goldendocx/parts/documents.rb +27 -14
- data/lib/goldendocx/parts/media.rb +1 -1
- data/lib/goldendocx/parts/properties/created_at_property.rb +17 -0
- data/lib/goldendocx/parts/properties/creator_property.rb +16 -0
- data/lib/goldendocx/parts/properties/revision_property.rb +16 -0
- data/lib/goldendocx/parts/properties/updated_at_property.rb +17 -0
- data/lib/goldendocx/parts/properties/updater_property.rb +16 -0
- data/lib/goldendocx/parts/properties.rb +12 -0
- data/lib/goldendocx/parts.rb +1 -1
- data/lib/goldendocx/tables/header_cell.rb +1 -1
- data/lib/goldendocx/tables/properties.rb +1 -1
- data/lib/goldendocx/tables/row.rb +1 -1
- data/lib/goldendocx/tables.rb +1 -1
- data/lib/goldendocx/version.rb +1 -1
- data/lib/goldendocx/xml_serializers/nokogiri.rb +32 -24
- data/lib/goldendocx/xml_serializers/ox.rb +15 -25
- data/lib/goldendocx.rb +14 -2
- metadata +54 -9
- data/lib/goldendocx/documents/element.rb +0 -23
- data/lib/goldendocx/documents/relationships.rb +0 -39
- data/lib/goldendocx/documents/unparsed_style.rb +0 -17
@@ -6,13 +6,9 @@ module Goldendocx
|
|
6
6
|
include Goldendocx::Element
|
7
7
|
|
8
8
|
tag :Override
|
9
|
-
attribute :part_name, alias_name: :PartName, readonly: true
|
10
|
-
attribute :content_type, alias_name: :ContentType, readonly: true
|
11
9
|
|
12
|
-
|
13
|
-
|
14
|
-
@content_type = content_type
|
15
|
-
end
|
10
|
+
attribute :part_name, alias_name: :PartName
|
11
|
+
attribute :content_type, alias_name: :ContentType
|
16
12
|
|
17
13
|
def ==(other)
|
18
14
|
part_name == other.part_name && content_type == other.content_type
|
data/lib/goldendocx/document.rb
CHANGED
@@ -3,49 +3,30 @@
|
|
3
3
|
# Just to mark a element as a root document node
|
4
4
|
module Goldendocx
|
5
5
|
module Document
|
6
|
-
|
7
|
-
|
8
|
-
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
include Goldendocx::Element
|
8
|
+
|
9
|
+
included do
|
10
|
+
class_attribute :concerned_namespaces, default: []
|
11
|
+
class_attribute :ignorable_namespaces, default: []
|
9
12
|
end
|
10
13
|
|
11
|
-
|
14
|
+
class_methods do
|
12
15
|
def concern_namespaces(*namespaces)
|
13
16
|
namespaces.each do |namespace|
|
14
17
|
concerned_namespaces << namespace unless concerned_namespaces.include?(namespace)
|
15
18
|
end
|
16
19
|
end
|
17
20
|
|
18
|
-
def concerned_namespaces
|
19
|
-
@concerned_namespaces ||= []
|
20
|
-
end
|
21
|
-
|
22
21
|
def ignore_namespaces(*namespaces)
|
23
22
|
namespaces.each do |namespace|
|
24
23
|
ignorable_namespaces << namespace.to_sym unless ignorable_namespaces.include?(namespace)
|
25
24
|
end
|
26
25
|
end
|
27
|
-
|
28
|
-
def ignorable_namespaces
|
29
|
-
@ignorable_namespaces ||= []
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
def concerned_namespaces
|
34
|
-
self.class.concerning_ancestors.flat_map(&:concerned_namespaces)
|
35
|
-
end
|
36
|
-
|
37
|
-
def ignorable_namespaces
|
38
|
-
self.class.concerning_ancestors.flat_map(&:ignorable_namespaces)
|
39
26
|
end
|
40
27
|
|
41
|
-
def to_document_xml
|
42
|
-
Goldendocx.xml_serializer.build_document_xml(
|
43
|
-
attributes.each { |name, value| xml[name] = value }
|
44
|
-
|
45
|
-
yield(xml) if block_given?
|
46
|
-
|
47
|
-
children.each { |child| xml << child }
|
48
|
-
end
|
28
|
+
def to_document_xml(&)
|
29
|
+
Goldendocx.xml_serializer.build_document_xml(tag_name, concerned_namespaces, ignorable_namespaces) { |xml| build_element(xml, &) }
|
49
30
|
end
|
50
31
|
end
|
51
32
|
end
|
@@ -7,40 +7,49 @@ module Goldendocx
|
|
7
7
|
|
8
8
|
XML_PATH = 'word/document.xml'
|
9
9
|
|
10
|
-
attr_reader :components, :
|
10
|
+
attr_reader :components, :charts
|
11
11
|
|
12
12
|
namespace :w
|
13
13
|
tag :body
|
14
14
|
|
15
|
+
# TODO: Try to distinguish these paragraphs
|
15
16
|
embeds_many :texts, class_name: 'Goldendocx::Components::Text'
|
16
17
|
embeds_many :images, class_name: 'Goldendocx::Components::Image'
|
18
|
+
|
17
19
|
embeds_many :tables, class_name: 'Goldendocx::Components::Table'
|
18
20
|
|
21
|
+
embeds_one :section_property, class_name: 'Goldendocx::Documents::Properties::SectionProperty', auto_build: true
|
22
|
+
|
23
|
+
class << self
|
24
|
+
def read_from(xml_node)
|
25
|
+
document = super(xml_node)
|
26
|
+
|
27
|
+
component_tags = %w[w:p w:tbl]
|
28
|
+
xml_node.children.map do |node|
|
29
|
+
document.components << node if component_tags.include?(node.tag_name)
|
30
|
+
end
|
31
|
+
|
32
|
+
document
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
19
36
|
def initialize
|
20
37
|
@components = []
|
21
38
|
@charts = []
|
22
39
|
end
|
23
40
|
|
24
|
-
def read_from(docx_file)
|
25
|
-
Goldendocx.xml_serializer.parse(docx_file.read(XML_PATH), %w[w:document w:body *]).map do |node|
|
26
|
-
element = Goldendocx::Documents::Element.new(node)
|
27
|
-
@components << element if element.component?
|
28
|
-
@properties = element if element.properties?
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
41
|
# FIXME: Override for children not in correctly order
|
33
42
|
def to_element(**_context)
|
34
|
-
Goldendocx.xml_serializer.build_element(
|
43
|
+
Goldendocx.xml_serializer.build_element(tag_name) do |xml|
|
35
44
|
components.each { |component| xml << component }
|
36
|
-
xml <<
|
45
|
+
xml << section_property if section_property
|
37
46
|
|
38
47
|
yield(xml) if block_given?
|
39
48
|
end
|
40
49
|
end
|
41
50
|
|
42
51
|
def create_text(text, options = {})
|
43
|
-
text = build_text(text
|
52
|
+
text = build_text(text:, **options.slice(:align, :color, :bold))
|
44
53
|
|
45
54
|
components << text
|
46
55
|
|
@@ -57,7 +66,7 @@ module Goldendocx
|
|
57
66
|
end
|
58
67
|
|
59
68
|
def create_image(relationship_id, options)
|
60
|
-
image = build_image(relationship_id
|
69
|
+
image = build_image(relationship_id:, width: options[:width], height: options[:height])
|
61
70
|
|
62
71
|
components << image
|
63
72
|
|
@@ -65,7 +74,7 @@ module Goldendocx
|
|
65
74
|
end
|
66
75
|
|
67
76
|
def create_embed_image(relationship_id, options)
|
68
|
-
Goldendocx::Components::Image.new(relationship_id
|
77
|
+
Goldendocx::Components::Image.new(relationship_id:, width: options[:width], height: options[:height])
|
69
78
|
end
|
70
79
|
|
71
80
|
def ensure_chart_type(chart_type)
|
@@ -5,7 +5,9 @@ module Goldendocx
|
|
5
5
|
class Document
|
6
6
|
include Goldendocx::Document
|
7
7
|
|
8
|
+
TYPE = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument'
|
8
9
|
XML_PATH = 'word/document.xml'
|
10
|
+
CONTENT_TYPE = 'application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml'
|
9
11
|
|
10
12
|
namespace :w
|
11
13
|
tag :document
|
@@ -16,10 +18,6 @@ module Goldendocx
|
|
16
18
|
|
17
19
|
embeds_one :body, class_name: 'Goldendocx::Documents::Body', auto_build: true
|
18
20
|
|
19
|
-
def read_from(docx_file)
|
20
|
-
body.read_from(docx_file)
|
21
|
-
end
|
22
|
-
|
23
21
|
def write_to(zos)
|
24
22
|
zos.put_next_entry XML_PATH
|
25
23
|
zos.write to_document_xml
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Goldendocx
|
4
|
+
module Documents
|
5
|
+
module Properties
|
6
|
+
class DefaultStyleProperty
|
7
|
+
include Goldendocx::Element
|
8
|
+
|
9
|
+
namespace :w
|
10
|
+
tag :docDefaults
|
11
|
+
|
12
|
+
embeds_one :run_default, class_name: 'Goldendocx::Documents::Properties::RunDefaultStyleProperty', auto_build: true
|
13
|
+
embeds_one :paragraph_default, class_name: 'Goldendocx::Documents::Properties::ParagraphDefaultStyleProperty', auto_build: true
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Goldendocx
|
4
|
+
module Documents
|
5
|
+
module Properties
|
6
|
+
class PageMarginProperty
|
7
|
+
include Goldendocx::Element
|
8
|
+
|
9
|
+
namespace :w
|
10
|
+
tag :pgMar
|
11
|
+
|
12
|
+
attribute :top, namespace: :w, default: 1440
|
13
|
+
attribute :bottom, namespace: :w, default: 1440
|
14
|
+
attribute :left, namespace: :w, default: 1800
|
15
|
+
attribute :right, namespace: :w, default: 1800
|
16
|
+
attribute :header, namespace: :w, default: 851
|
17
|
+
attribute :footer, namespace: :w, default: 992
|
18
|
+
attribute :gutter, namespace: :w, default: 0
|
19
|
+
|
20
|
+
# Follow html margin style setting
|
21
|
+
def margin=(*args)
|
22
|
+
args = Array(*args)
|
23
|
+
raise StandardError("wrong number of arguments (given #{args.length}, expected 1..4)") unless (1..4).cover?(args.length)
|
24
|
+
|
25
|
+
margins =
|
26
|
+
case args.length
|
27
|
+
when 1 then [args.first] * 4
|
28
|
+
when 2 then [args.first, args.last, args.first, args.last]
|
29
|
+
when 3 then [args.first, args.second, args.last, args.second]
|
30
|
+
else args
|
31
|
+
end
|
32
|
+
assign_attributes(**%i[top right bottom left].zip(margins).to_h)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Goldendocx
|
4
|
+
module Documents
|
5
|
+
module Properties
|
6
|
+
class PageSizeProperty
|
7
|
+
include Goldendocx::Element
|
8
|
+
|
9
|
+
namespace :w
|
10
|
+
tag :pgSz
|
11
|
+
|
12
|
+
attribute :width, alias_name: :w, namespace: :w, default: 11906
|
13
|
+
attribute :height, alias_name: :h, namespace: :w, default: 16838
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Goldendocx
|
4
|
+
module Documents
|
5
|
+
module Properties
|
6
|
+
class ParagraphDefaultStyleProperty
|
7
|
+
include Goldendocx::Element
|
8
|
+
|
9
|
+
namespace :w
|
10
|
+
tag :pPrDefault
|
11
|
+
|
12
|
+
embeds_one :property, class_name: 'Goldendocx::Components::Properties::Property'
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Goldendocx
|
4
|
+
module Documents
|
5
|
+
module Properties
|
6
|
+
class RunDefaultStyleProperty
|
7
|
+
include Goldendocx::Element
|
8
|
+
|
9
|
+
namespace :w
|
10
|
+
tag :rPrDefault
|
11
|
+
|
12
|
+
embeds_one :property, class_name: 'Goldendocx::Components::Properties::RunProperty'
|
13
|
+
|
14
|
+
def initialize
|
15
|
+
build_property
|
16
|
+
property.build_language
|
17
|
+
property.build_font
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Goldendocx
|
4
|
+
module Documents
|
5
|
+
module Properties
|
6
|
+
class SectionProperty
|
7
|
+
include Goldendocx::Element
|
8
|
+
|
9
|
+
namespace :w
|
10
|
+
tag :sectPr
|
11
|
+
|
12
|
+
embeds_one :size, class_name: 'Goldendocx::Documents::Properties::PageSizeProperty', auto_build: true
|
13
|
+
embeds_one :margin, class_name: 'Goldendocx::Documents::Properties::PageMarginProperty', auto_build: true
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Goldendocx
|
4
|
+
module Documents
|
5
|
+
module Properties
|
6
|
+
class StyleNameProperty
|
7
|
+
include Goldendocx::Element
|
8
|
+
|
9
|
+
namespace :w
|
10
|
+
tag :name
|
11
|
+
|
12
|
+
attribute :name, alias_name: :val, namespace: :w
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Goldendocx
|
4
|
+
module Documents
|
5
|
+
class Settings
|
6
|
+
include Goldendocx::Document
|
7
|
+
|
8
|
+
XML_PATH = 'word/settings.xml'
|
9
|
+
TYPE = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/settings'
|
10
|
+
CONTENT_TYPE = 'application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml'
|
11
|
+
|
12
|
+
namespace :w
|
13
|
+
tag :settings
|
14
|
+
concern_namespaces :mc, :o, :r, :m, :v, :w10, :w, :w14, :w15, :w16cid, :w16se, :sl
|
15
|
+
ignore_namespaces :w14, :w15, :w16se, :w16cid
|
16
|
+
|
17
|
+
def write_to(zos)
|
18
|
+
zos.put_next_entry XML_PATH
|
19
|
+
zos.write to_document_xml
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -3,18 +3,18 @@
|
|
3
3
|
module Goldendocx
|
4
4
|
module Documents
|
5
5
|
class Style
|
6
|
-
|
6
|
+
include Goldendocx::Element
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
8
|
+
namespace :w
|
9
|
+
tag :style
|
10
|
+
|
11
|
+
attribute :id, alias_name: :styleId, namespace: :w
|
12
|
+
attribute :type, namespace: :w
|
13
|
+
|
14
|
+
embeds_one :style_name, class_name: 'Goldendocx::Documents::Properties::StyleNameProperty', auto_build: true
|
15
15
|
|
16
|
-
def
|
17
|
-
|
16
|
+
def name
|
17
|
+
style_name.name
|
18
18
|
end
|
19
19
|
end
|
20
20
|
end
|
@@ -6,42 +6,22 @@ module Goldendocx
|
|
6
6
|
include Goldendocx::Document
|
7
7
|
|
8
8
|
XML_PATH = 'word/styles.xml'
|
9
|
+
TYPE = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles'
|
10
|
+
CONTENT_TYPE = 'application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml'
|
9
11
|
|
10
12
|
tag :styles
|
11
13
|
namespace :w
|
12
14
|
concern_namespaces :mc, :r, :w, :w14, :w15
|
13
15
|
ignore_namespaces :w14, :w15
|
14
16
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
@styles = []
|
19
|
-
end
|
17
|
+
embeds_one :defaults, class_name: 'Goldendocx::Documents::Properties::DefaultStyleProperty', auto_build: true
|
18
|
+
embeds_one :latentStyles, class_name: 'Goldendocx::Documents::LatentStyles'
|
19
|
+
embeds_many :styles, class_name: 'Goldendocx::Documents::Style'
|
20
20
|
|
21
21
|
def size
|
22
22
|
styles.size
|
23
23
|
end
|
24
24
|
|
25
|
-
def read_from(docx_file)
|
26
|
-
@styles = Goldendocx.xml_serializer.parse(docx_file.read(XML_PATH), %w[w:styles w:style]).map do |node|
|
27
|
-
Goldendocx::Documents::Style.new(node)
|
28
|
-
end
|
29
|
-
@doc_defaults = Goldendocx.xml_serializer.parse(docx_file.read(XML_PATH), %w[w:styles w:docDefaults]).map do |node|
|
30
|
-
Goldendocx::Documents::UnparsedStyle.new(node)
|
31
|
-
end
|
32
|
-
@latent_styles = Goldendocx.xml_serializer.parse(docx_file.read(XML_PATH), %w[w:styles w:latentStyles]).map do |node|
|
33
|
-
Goldendocx::Documents::UnparsedStyle.new(node)
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
def to_document_xml
|
38
|
-
super do |xml|
|
39
|
-
@doc_defaults&.each { |element| xml << element }
|
40
|
-
@latent_styles&.each { |element| xml << element }
|
41
|
-
styles.each { |style| xml << style }
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
25
|
def write_to(zos)
|
46
26
|
zos.put_next_entry XML_PATH
|
47
27
|
zos.write to_document_xml
|
@@ -60,14 +40,10 @@ module Goldendocx
|
|
60
40
|
end
|
61
41
|
|
62
42
|
def add_style(fragment)
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
style = Goldendocx.xml_serializer.parse(fragment)
|
68
|
-
style['w:styleId'] = style_id if style['w:styleId'].nil? || style['w:styleId'].empty?
|
69
|
-
@styles << Goldendocx::Documents::Style.new(style)
|
70
|
-
style_id
|
43
|
+
style = Goldendocx::Documents::Style.parse(fragment)
|
44
|
+
style.id = (styles.size + 1).to_s # Rearrange id to prevent duplicates
|
45
|
+
styles << style
|
46
|
+
style.id
|
71
47
|
end
|
72
48
|
end
|
73
49
|
end
|
data/lib/goldendocx/documents.rb
CHANGED
data/lib/goldendocx/docx.rb
CHANGED
@@ -1,32 +1,54 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'goldendocx/
|
4
|
-
require 'goldendocx/element'
|
5
|
-
require 'goldendocx/document'
|
6
|
-
|
3
|
+
require 'goldendocx/models'
|
7
4
|
require 'goldendocx/components'
|
8
5
|
require 'goldendocx/documents'
|
9
6
|
require 'goldendocx/parts'
|
10
7
|
|
11
8
|
module Goldendocx
|
12
9
|
class Docx
|
13
|
-
|
10
|
+
include Goldendocx::HasAssociations
|
11
|
+
|
12
|
+
attr_reader :unstructured_entries, :documents
|
13
|
+
|
14
|
+
RELATIONSHIPS_XML_PATH = '_rels/.rels'
|
14
15
|
|
15
16
|
STRUCTURED_ENTRIES = [
|
17
|
+
RELATIONSHIPS_XML_PATH,
|
18
|
+
|
16
19
|
Goldendocx::Parts::ContentTypes::XML_PATH,
|
20
|
+
Goldendocx::Parts::App::XML_PATH,
|
21
|
+
Goldendocx::Parts::Core::XML_PATH,
|
22
|
+
|
23
|
+
Goldendocx::Parts::Documents::RELATIONSHIPS_XML_PATH,
|
17
24
|
|
18
|
-
Goldendocx::Documents::
|
19
|
-
Goldendocx::Documents::
|
25
|
+
Goldendocx::Documents::Document::XML_PATH,
|
26
|
+
Goldendocx::Documents::Settings::XML_PATH,
|
20
27
|
Goldendocx::Documents::Styles::XML_PATH
|
21
28
|
].freeze
|
22
29
|
|
23
|
-
|
30
|
+
relationships_at RELATIONSHIPS_XML_PATH
|
31
|
+
associate :app, class_name: 'Goldendocx::Parts::App'
|
32
|
+
associate :core, class_name: 'Goldendocx::Parts::Core'
|
33
|
+
associate :content_types, class_name: 'Goldendocx::Parts::ContentTypes', isolate: true
|
34
|
+
|
35
|
+
def initialize(file_path = nil)
|
36
|
+
file_path.present? ? read_from(file_path) : build_default
|
37
|
+
end
|
38
|
+
|
39
|
+
def read_from(file_path)
|
24
40
|
docx_file = Zip::File.new(file_path)
|
41
|
+
|
42
|
+
read_relationships(docx_file)
|
43
|
+
read_associations(docx_file)
|
44
|
+
|
25
45
|
@documents = Goldendocx::Parts::Documents.read_from(docx_file)
|
26
|
-
|
46
|
+
|
27
47
|
@unstructured_entries = docx_file.entries.filter_map do |entry|
|
28
48
|
UnStructuredEntry.new(entry) unless STRUCTURED_ENTRIES.include?(entry.name)
|
29
49
|
end
|
50
|
+
|
51
|
+
self
|
30
52
|
end
|
31
53
|
|
32
54
|
def write_to(new_path)
|
@@ -65,6 +87,25 @@ module Goldendocx
|
|
65
87
|
|
66
88
|
private
|
67
89
|
|
90
|
+
def build_default
|
91
|
+
associations.each do |association, options|
|
92
|
+
association_class = options.class_name.constantize
|
93
|
+
instance_variable_set("@#{association}", association_class.new)
|
94
|
+
add_relationship association_class::TYPE, association_class::XML_PATH unless options.isolate
|
95
|
+
end
|
96
|
+
|
97
|
+
content_types.add_override "/#{Goldendocx::Parts::App::XML_PATH}", Goldendocx::Parts::App::CONTENT_TYPE
|
98
|
+
content_types.add_override "/#{Goldendocx::Parts::Core::XML_PATH}", Goldendocx::Parts::Core::CONTENT_TYPE
|
99
|
+
content_types.add_override "/#{Goldendocx::Documents::Styles::XML_PATH}", Goldendocx::Documents::Styles::CONTENT_TYPE
|
100
|
+
content_types.add_override "/#{Goldendocx::Documents::Settings::XML_PATH}", Goldendocx::Documents::Settings::CONTENT_TYPE
|
101
|
+
|
102
|
+
@documents = Goldendocx::Parts::Documents.new
|
103
|
+
add_relationship Goldendocx::Documents::Document::TYPE, Goldendocx::Documents::Document::XML_PATH
|
104
|
+
content_types.add_override "/#{Goldendocx::Documents::Document::XML_PATH}", Goldendocx::Documents::Document::CONTENT_TYPE
|
105
|
+
|
106
|
+
@unstructured_entries = []
|
107
|
+
end
|
108
|
+
|
68
109
|
def ensure_image_content_type!(_image_data)
|
69
110
|
extension = 'png'
|
70
111
|
content_type = 'image/png'
|
@@ -79,10 +120,12 @@ module Goldendocx
|
|
79
120
|
|
80
121
|
def to_stream
|
81
122
|
Zip::OutputStream.write_buffer do |zos|
|
82
|
-
zos
|
83
|
-
|
123
|
+
write_relationships(zos)
|
124
|
+
|
125
|
+
associations.each_key do |association|
|
126
|
+
send(association).write_to(zos)
|
127
|
+
end
|
84
128
|
|
85
|
-
zos.put_next_entry Goldendocx::Parts::Documents::XML_PATH
|
86
129
|
documents.write_stream(zos)
|
87
130
|
|
88
131
|
@unstructured_entries.each { |unstructured_entry| unstructured_entry.write_to(zos) }
|