goldendocx 0.2.2 → 0.3.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 (84) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +1 -1
  3. data/.ruby-version +1 -0
  4. data/CHANGELOG.md +8 -2
  5. data/Gemfile.lock +3 -1
  6. data/README.md +10 -2
  7. data/Rakefile +14 -3
  8. data/demo/tables/create_embed_image_table.rb +3 -3
  9. data/demo/templates/generate_codes.rb +10 -0
  10. data/demo/templates/xml_to_class.rb +97 -0
  11. data/demo/texts/append_plain_text.rb +1 -1
  12. data/demo/texts/append_styled_text.rb +1 -2
  13. data/demo/texts/create_text.rb +14 -0
  14. data/lib/extensions/active_support_extensions.rb +16 -0
  15. data/lib/extensions/nokogiri_extensions.rb +41 -0
  16. data/lib/extensions/ox_extensions.rb +35 -0
  17. data/lib/extensions/xml_serialize_extensions.rb +45 -0
  18. data/lib/goldendocx/charts/properties.rb +1 -1
  19. data/lib/goldendocx/charts/series.rb +2 -2
  20. data/lib/goldendocx/charts.rb +1 -1
  21. data/lib/goldendocx/components/bar_chart.rb +2 -2
  22. data/lib/goldendocx/components/chart.rb +6 -6
  23. data/lib/goldendocx/components/column_chart.rb +2 -2
  24. data/lib/goldendocx/components/doughnut_chart.rb +2 -2
  25. data/lib/goldendocx/components/line_chart.rb +2 -2
  26. data/lib/goldendocx/components/properties/font_property.rb +19 -0
  27. data/lib/goldendocx/components/properties/language_property.rb +18 -0
  28. data/lib/goldendocx/components/properties/run_property.rb +2 -0
  29. data/lib/goldendocx/components/properties.rb +1 -1
  30. data/lib/goldendocx/components/table.rb +2 -2
  31. data/lib/goldendocx/components.rb +1 -1
  32. data/lib/goldendocx/content_types/default.rb +2 -6
  33. data/lib/goldendocx/content_types/override.rb +2 -6
  34. data/lib/goldendocx/document.rb +9 -28
  35. data/lib/goldendocx/documents/body.rb +23 -14
  36. data/lib/goldendocx/documents/document.rb +2 -4
  37. data/lib/goldendocx/documents/latent_styles.rb +12 -0
  38. data/lib/goldendocx/documents/properties/default_style_property.rb +17 -0
  39. data/lib/goldendocx/documents/properties/page_margin_property.rb +37 -0
  40. data/lib/goldendocx/documents/properties/page_size_property.rb +17 -0
  41. data/lib/goldendocx/documents/properties/paragraph_default_style_property.rb +16 -0
  42. data/lib/goldendocx/documents/properties/run_default_style_property.rb +22 -0
  43. data/lib/goldendocx/documents/properties/section_property.rb +17 -0
  44. data/lib/goldendocx/documents/properties/style_name_property.rb +16 -0
  45. data/lib/goldendocx/documents/properties.rb +12 -0
  46. data/lib/goldendocx/documents/settings.rb +23 -0
  47. data/lib/goldendocx/documents/style.rb +10 -10
  48. data/lib/goldendocx/documents/styles.rb +9 -33
  49. data/lib/goldendocx/documents.rb +1 -1
  50. data/lib/goldendocx/docx.rb +55 -12
  51. data/lib/goldendocx/element.rb +33 -140
  52. data/lib/goldendocx/has_associations.rb +54 -0
  53. data/lib/goldendocx/has_attributes.rb +67 -0
  54. data/lib/goldendocx/has_children.rb +116 -0
  55. data/lib/goldendocx/images/picture.rb +1 -1
  56. data/lib/goldendocx/images/properties.rb +1 -1
  57. data/lib/goldendocx/images.rb +1 -1
  58. data/lib/goldendocx/{documents → models}/relationship.rb +1 -1
  59. data/lib/goldendocx/models/relationships.rb +31 -0
  60. data/lib/goldendocx/models.rb +10 -0
  61. data/lib/goldendocx/parts/app.rb +46 -0
  62. data/lib/goldendocx/parts/content_types.rb +16 -30
  63. data/lib/goldendocx/parts/core.rb +46 -0
  64. data/lib/goldendocx/parts/documents.rb +27 -14
  65. data/lib/goldendocx/parts/media.rb +1 -1
  66. data/lib/goldendocx/parts/properties/created_at_property.rb +17 -0
  67. data/lib/goldendocx/parts/properties/creator_property.rb +16 -0
  68. data/lib/goldendocx/parts/properties/revision_property.rb +16 -0
  69. data/lib/goldendocx/parts/properties/updated_at_property.rb +17 -0
  70. data/lib/goldendocx/parts/properties/updater_property.rb +16 -0
  71. data/lib/goldendocx/parts/properties.rb +12 -0
  72. data/lib/goldendocx/parts.rb +1 -1
  73. data/lib/goldendocx/tables/header_cell.rb +1 -1
  74. data/lib/goldendocx/tables/properties.rb +1 -1
  75. data/lib/goldendocx/tables/row.rb +1 -1
  76. data/lib/goldendocx/tables.rb +1 -1
  77. data/lib/goldendocx/version.rb +1 -1
  78. data/lib/goldendocx/xml_serializers/nokogiri.rb +32 -24
  79. data/lib/goldendocx/xml_serializers/ox.rb +15 -25
  80. data/lib/goldendocx.rb +14 -2
  81. metadata +54 -9
  82. data/lib/goldendocx/documents/element.rb +0 -23
  83. data/lib/goldendocx/documents/relationships.rb +0 -39
  84. 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
- def initialize(part_name, content_type)
13
- @part_name = part_name
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
@@ -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
- def self.included(base)
7
- base.include(Goldendocx::Element)
8
- base.extend(ClassMethods)
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
- module ClassMethods
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(root_tag, concerned_namespaces, ignorable_namespaces) do |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, :properties, :charts
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(root_tag) do |xml|
43
+ Goldendocx.xml_serializer.build_element(tag_name) do |xml|
35
44
  components.each { |component| xml << component }
36
- xml << properties if properties
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: text, **options.slice(:align, :color, :bold))
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: relationship_id, width: options[:width], height: options[:height])
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: relationship_id, width: options[:width], height: options[:height])
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,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Goldendocx
4
+ module Documents
5
+ class LatentStyles
6
+ include Goldendocx::Element
7
+
8
+ namespace :w
9
+ tag :latentStyles
10
+ end
11
+ end
12
+ end
@@ -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,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Goldendocx
4
+ module Documents
5
+ module Properties
6
+ end
7
+ end
8
+ end
9
+
10
+ Dir.glob(File.join(File.dirname(__FILE__), 'properties', '*.rb').to_s).each do |file|
11
+ require file
12
+ 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
- attr_reader :node, :id, :type, :name
6
+ include Goldendocx::Element
7
7
 
8
- def initialize(node)
9
- @node = node
10
- @id = node['w:styleId']
11
- @type = node['w:type']
12
- @name = node.public_send(:'w:name')['w:val']
13
- @default = node['w:default']
14
- end
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 to_element(**_context)
17
- @node
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
- attr_reader :styles, :doc_defaults, :latent_styles
16
-
17
- def initialize
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
- # FIXME: Not a good implementation for Nokogiri compatibility
64
- raise NotImplementedError unless Goldendocx.config.xml_serializer == :ox
65
-
66
- style_id = (@styles.size + 1).to_s
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
@@ -5,6 +5,6 @@ module Goldendocx
5
5
  end
6
6
  end
7
7
 
8
- Dir.glob(File.join(File.dirname(__FILE__), 'documents', '*.rb').to_s).sort.each do |file|
8
+ Dir.glob(File.join(File.dirname(__FILE__), 'documents', '*.rb').to_s).each do |file|
9
9
  require file
10
10
  end
@@ -1,32 +1,54 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'goldendocx/units'
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
- attr_reader :unstructured_entries, :documents, :content_types
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::Body::XML_PATH,
19
- Goldendocx::Documents::Relationships::XML_PATH,
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
- def initialize(file_path)
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
- @content_types = Goldendocx::Parts::ContentTypes.read_from(docx_file)
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.put_next_entry Goldendocx::Parts::ContentTypes::XML_PATH
83
- zos.write content_types.to_document_xml
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) }