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.
- 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
data/lib/goldendocx/element.rb
CHANGED
@@ -1,19 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require '
|
4
|
-
|
5
|
-
ActiveSupport::Inflector.inflections do |inflect|
|
6
|
-
inflect.uncountable 'extents', 'image_data', 'data'
|
7
|
-
inflect.irregular 'axis', 'axes'
|
8
|
-
|
9
|
-
inflect.uncountable 'values' # TODO: Find better names
|
10
|
-
end
|
3
|
+
require 'goldendocx/has_attributes'
|
4
|
+
require 'goldendocx/has_children'
|
11
5
|
|
12
6
|
module Goldendocx
|
13
7
|
module Element
|
14
|
-
|
15
|
-
|
16
|
-
|
8
|
+
extend ActiveSupport::Concern
|
9
|
+
include Goldendocx::HasAttributes
|
10
|
+
include Goldendocx::HasChildren
|
17
11
|
|
18
12
|
module ClassMethods
|
19
13
|
def tag(*args)
|
@@ -26,124 +20,36 @@ module Goldendocx
|
|
26
20
|
@namespace
|
27
21
|
end
|
28
22
|
|
29
|
-
|
30
|
-
|
31
|
-
# default: nil
|
32
|
-
# namespace: nil
|
33
|
-
# setter: nil
|
34
|
-
def attribute(name, **options)
|
35
|
-
named = name.to_s
|
36
|
-
attributes[named] = {
|
37
|
-
alias_name: options[:alias_name],
|
38
|
-
default: options[:default],
|
39
|
-
namespace: options[:namespace],
|
40
|
-
method: options[:method]
|
41
|
-
}.compact
|
42
|
-
|
43
|
-
readonly = options[:readonly] || false
|
44
|
-
if readonly
|
45
|
-
attr_reader named
|
46
|
-
elsif options[:method]
|
47
|
-
attr_writer named
|
48
|
-
else
|
49
|
-
attr_accessor named
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
def attributes
|
54
|
-
@attributes ||= {}
|
55
|
-
end
|
56
|
-
|
57
|
-
def create_children_getter(name)
|
58
|
-
options = children[name]
|
59
|
-
class_name = options[:class_name]
|
60
|
-
multiple = options[:multiple]
|
61
|
-
auto_build = options[:auto_build]
|
62
|
-
|
63
|
-
define_method name do
|
64
|
-
return instance_variable_get("@#{name}") if instance_variable_defined?("@#{name}")
|
65
|
-
|
66
|
-
default_value = if multiple
|
67
|
-
[]
|
68
|
-
else
|
69
|
-
auto_build ? Kernel.const_get(class_name).new : nil
|
70
|
-
end
|
71
|
-
instance_variable_set("@#{name}", default_value)
|
72
|
-
end
|
23
|
+
def tag_name
|
24
|
+
@tag_name ||= [namespace, tag].compact.join(':')
|
73
25
|
end
|
74
26
|
|
75
|
-
def
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
define_method "#{name}=" do |value|
|
80
|
-
value = value.to_s if value && class_name == 'String'
|
81
|
-
instance_variable_set("@#{name}", value)
|
82
|
-
end
|
27
|
+
def parse(xml_string)
|
28
|
+
root_node = Goldendocx.xml_serializer.parse(xml_string).root
|
29
|
+
read_from(root_node)
|
83
30
|
end
|
84
31
|
|
85
|
-
def
|
86
|
-
|
87
|
-
class_name = options[:class_name]
|
88
|
-
multiple = options[:multiple]
|
89
|
-
|
90
|
-
define_method "build_#{name.to_s.singularize}" do |**attributes|
|
91
|
-
child = Kernel.const_get(class_name).new
|
92
|
-
attributes.each { |key, value| child.send("#{key}=", value) if child.respond_to?("#{key}=") }
|
93
|
-
multiple ? send(name) << child : instance_variable_set("@#{name}", child)
|
94
|
-
child
|
95
|
-
end
|
32
|
+
def adapt?(xml_node)
|
33
|
+
tag_name == xml_node.tag_name
|
96
34
|
end
|
97
35
|
|
98
|
-
def
|
99
|
-
|
100
|
-
|
101
|
-
children[name] = { class_name: class_name, multiple: false, auto_build: auto_build }
|
102
|
-
create_children_getter(name)
|
103
|
-
create_children_setter(name)
|
104
|
-
create_children_builder(name)
|
105
|
-
end
|
106
|
-
|
107
|
-
def embeds_many(name, class_name:)
|
108
|
-
warning_naming_suggestion(name, name.to_s.pluralize)
|
109
|
-
|
110
|
-
children[name] = { class_name: class_name, multiple: true, auto_build: false }
|
111
|
-
create_children_getter(name)
|
112
|
-
create_children_builder(name)
|
113
|
-
end
|
36
|
+
def read_from(xml_node)
|
37
|
+
return unless adapt?(xml_node)
|
114
38
|
|
115
|
-
|
116
|
-
|
39
|
+
instance = new
|
40
|
+
instance.read_attributes(xml_node)
|
41
|
+
instance.read_children(xml_node)
|
42
|
+
instance
|
117
43
|
end
|
118
44
|
|
119
45
|
def concerning_ancestors
|
120
46
|
ancestors.filter { |ancestor| ancestor.include?(Goldendocx::Element) }
|
121
47
|
end
|
122
|
-
|
123
|
-
private
|
124
|
-
|
125
|
-
# :nocov:
|
126
|
-
def warning_naming_suggestion(name, suggestion_name)
|
127
|
-
return if suggestion_name == name.to_s
|
128
|
-
|
129
|
-
location = caller.find { |c| c.include?('goldendocx/') && !c.include?('goldendocx/element.rb') }
|
130
|
-
warn "warning: [embeds_one] `#{name}` better be singular `#{suggestion_name}` at #{location}"
|
131
|
-
end
|
132
|
-
# :nocov:
|
133
|
-
end
|
134
|
-
|
135
|
-
def attributes
|
136
|
-
self.class.attributes.each_with_object({}) do |(name, options), result|
|
137
|
-
value = public_send(options[:method] || name) || options[:default]
|
138
|
-
next if value.nil?
|
139
|
-
|
140
|
-
key = [options[:namespace], options[:alias_name] || name].compact.join(':')
|
141
|
-
result[key] = value
|
142
|
-
end
|
143
48
|
end
|
144
49
|
|
145
|
-
def
|
146
|
-
attributes
|
50
|
+
def initialize(attributes = nil)
|
51
|
+
attributes ||= {}
|
52
|
+
assign_attributes(**attributes)
|
147
53
|
end
|
148
54
|
|
149
55
|
def tag
|
@@ -154,39 +60,26 @@ module Goldendocx
|
|
154
60
|
self.class.concerning_ancestors.find { |ancestor| ancestor.namespace.present? }&.namespace
|
155
61
|
end
|
156
62
|
|
157
|
-
def
|
158
|
-
@
|
63
|
+
def tag_name
|
64
|
+
@tag_name ||= [namespace, tag].compact.join(':')
|
159
65
|
end
|
160
66
|
|
161
|
-
def
|
162
|
-
|
163
|
-
|
164
|
-
self.class.superclass.children.keys.flat_map { |name| send(name) }
|
67
|
+
def to_element(**context, &)
|
68
|
+
Goldendocx.xml_serializer.build_element(tag_name, **context) { |xml| build_element(xml, &) }
|
165
69
|
end
|
166
70
|
|
167
|
-
def
|
168
|
-
|
169
|
-
send(name)
|
170
|
-
end.concat(siblings).compact
|
71
|
+
def to_xml(&)
|
72
|
+
Goldendocx.xml_serializer.build_xml(tag_name) { |xml| build_element(xml, &) }
|
171
73
|
end
|
172
74
|
|
173
|
-
def
|
174
|
-
|
175
|
-
|
176
|
-
children.each { |child| xml << child }
|
75
|
+
def build_element(xml)
|
76
|
+
attributes.each { |name, value| xml[name] = value }
|
77
|
+
unparsed_attributes.each { |name, value| xml[name] = value }
|
177
78
|
|
178
|
-
|
179
|
-
|
180
|
-
end
|
79
|
+
children.each { |child| xml << child }
|
80
|
+
unparsed_children.each { |child| xml << child }
|
181
81
|
|
182
|
-
|
183
|
-
Goldendocx.xml_serializer.build_xml(root_tag) do |xml|
|
184
|
-
attributes.each { |name, value| xml[name] = value }
|
185
|
-
|
186
|
-
yield(xml) if block_given?
|
187
|
-
|
188
|
-
children.each { |child| xml << child }
|
189
|
-
end
|
82
|
+
yield(xml) if block_given?
|
190
83
|
end
|
191
84
|
end
|
192
85
|
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Goldendocx
|
4
|
+
module HasAssociations
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
included do
|
8
|
+
class_attribute :associations, default: {}
|
9
|
+
class_attribute :relationships_xml_path
|
10
|
+
|
11
|
+
delegate :add_relationship, to: :relationships
|
12
|
+
end
|
13
|
+
|
14
|
+
Options = Data.define(:class_name, :isolate)
|
15
|
+
|
16
|
+
class_methods do
|
17
|
+
def relationships_at(xml_path)
|
18
|
+
self.relationships_xml_path = xml_path
|
19
|
+
end
|
20
|
+
|
21
|
+
def associate(name, class_name:, isolate: false)
|
22
|
+
named = name.to_s
|
23
|
+
associations[named] = Options.new(class_name:, isolate:)
|
24
|
+
|
25
|
+
define_method named do
|
26
|
+
return instance_variable_get("@#{name}") if instance_variable_defined?("@#{name}")
|
27
|
+
|
28
|
+
new_instance = class_name.constantize.new
|
29
|
+
instance_variable_set("@#{name}", new_instance)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def read_associations(docx_file)
|
35
|
+
associations.each do |association, options|
|
36
|
+
association_class = options.class_name.constantize
|
37
|
+
association_document_xml = docx_file.read(association_class::XML_PATH)
|
38
|
+
instance_variable_set("@#{association}", association_class.parse(association_document_xml))
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def read_relationships(docx_file)
|
43
|
+
@relationships = Goldendocx::Models::Relationships.parse(docx_file.read(relationships_xml_path))
|
44
|
+
end
|
45
|
+
|
46
|
+
def write_relationships(zos)
|
47
|
+
relationships.write_to(zos, relationships_xml_path)
|
48
|
+
end
|
49
|
+
|
50
|
+
def relationships
|
51
|
+
@relationships ||= Goldendocx::Models::Relationships.new
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Goldendocx
|
4
|
+
module HasAttributes
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
included do
|
8
|
+
class_attribute :attributes, instance_accessor: false, default: {}
|
9
|
+
|
10
|
+
def unparsed_attributes
|
11
|
+
@unparsed_attributes ||= {}
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class_methods do
|
16
|
+
# alias_name: nil
|
17
|
+
# readonly: false
|
18
|
+
# default: nil
|
19
|
+
# namespace: nil
|
20
|
+
# setter: nil
|
21
|
+
def attribute(name, **options)
|
22
|
+
named = name.to_s
|
23
|
+
attributes[named] = {
|
24
|
+
alias_name: options[:alias_name],
|
25
|
+
default: options[:default],
|
26
|
+
namespace: options[:namespace],
|
27
|
+
method: options[:method]
|
28
|
+
}.compact
|
29
|
+
|
30
|
+
readonly = options[:readonly] || false
|
31
|
+
if readonly
|
32
|
+
attr_reader named
|
33
|
+
elsif options[:method]
|
34
|
+
attr_writer named
|
35
|
+
else
|
36
|
+
attr_accessor named
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def attributes
|
42
|
+
self.class.attributes.each_with_object({}) do |(name, options), result|
|
43
|
+
value = public_send(options[:method] || name) || options[:default]
|
44
|
+
next if value.nil?
|
45
|
+
|
46
|
+
key = [options[:namespace], options[:alias_name] || name].compact.join(':')
|
47
|
+
result[key] = value
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def read_attributes(node)
|
52
|
+
node_attributes = node.attributes_hash
|
53
|
+
|
54
|
+
attributes = self.class.attributes.each_with_object({}) do |(name, options), result|
|
55
|
+
attribute_tag = [options[:namespace], (options[:alias_name] || name)].compact.join(':')
|
56
|
+
result[name] = node_attributes.delete(attribute_tag)
|
57
|
+
end
|
58
|
+
assign_attributes(**attributes)
|
59
|
+
|
60
|
+
unparsed_attributes.update(node_attributes)
|
61
|
+
end
|
62
|
+
|
63
|
+
def assign_attributes(**attributes)
|
64
|
+
attributes.each { |key, value| send("#{key}=", value) if respond_to?("#{key}=") }
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'goldendocx/has_attributes'
|
4
|
+
|
5
|
+
module Goldendocx
|
6
|
+
module HasChildren
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
|
9
|
+
included do
|
10
|
+
class_attribute :children, instance_accessor: false, default: {}
|
11
|
+
|
12
|
+
def unparsed_children
|
13
|
+
@unparsed_children ||= []
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
module ClassMethods
|
18
|
+
def embeds_one(name, class_name:, auto_build: false)
|
19
|
+
warning_naming_suggestion(__method__, name, name.to_s.singularize)
|
20
|
+
|
21
|
+
options = { class_name:, multiple: false, auto_build: }
|
22
|
+
self.children = children.merge(name => options)
|
23
|
+
|
24
|
+
create_children_getter(name)
|
25
|
+
create_children_setter(name)
|
26
|
+
create_children_builder(name)
|
27
|
+
end
|
28
|
+
|
29
|
+
def embeds_many(name, class_name:, uniqueness: false)
|
30
|
+
warning_naming_suggestion(__method__, name, name.to_s.pluralize)
|
31
|
+
|
32
|
+
options = { class_name:, multiple: true, uniqueness: }
|
33
|
+
self.children = children.merge(name => options)
|
34
|
+
|
35
|
+
create_children_getter(name)
|
36
|
+
create_children_setter(name)
|
37
|
+
create_children_builder(name)
|
38
|
+
end
|
39
|
+
|
40
|
+
def default_value(name)
|
41
|
+
options = children[name]
|
42
|
+
return [] if options[:multiple]
|
43
|
+
|
44
|
+
options[:class_name].constantize.new if options[:auto_build]
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def create_children_getter(name)
|
50
|
+
define_method name do
|
51
|
+
return instance_variable_get("@#{name}") if instance_variable_defined?("@#{name}")
|
52
|
+
|
53
|
+
instance_variable_set("@#{name}", self.class.default_value(name))
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def create_children_setter(name)
|
58
|
+
define_method("#{name}=") { |value| instance_variable_set("@#{name}", value) }
|
59
|
+
end
|
60
|
+
|
61
|
+
def create_children_appender(name)
|
62
|
+
options = children[name]
|
63
|
+
|
64
|
+
define_method "append_#{name.to_s.singularize}" do |child|
|
65
|
+
return instance_variable_set("@#{name}", child) unless options[:multiple]
|
66
|
+
|
67
|
+
children = send(name)
|
68
|
+
children << child unless options[:uniqueness] && children.any?(child)
|
69
|
+
child
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def create_children_builder(name)
|
74
|
+
options = children[name]
|
75
|
+
create_children_appender(name)
|
76
|
+
|
77
|
+
define_method "build_#{name.to_s.singularize}" do |**attributes|
|
78
|
+
child = options[:class_name].constantize.new
|
79
|
+
attributes.each { |key, value| child.send("#{key}=", value) if child.respond_to?("#{key}=") }
|
80
|
+
send("append_#{name.to_s.singularize}", child)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
# :nocov:
|
85
|
+
def warning_naming_suggestion(method, name, suggestion_name)
|
86
|
+
return if suggestion_name == name.to_s
|
87
|
+
|
88
|
+
location = caller.find { |c| c.include?('goldendocx/') && !c.include?('goldendocx/element.rb') }
|
89
|
+
warn "warning: [#{method}] `#{name}` better be `#{suggestion_name}` at #{location}"
|
90
|
+
end
|
91
|
+
# :nocov:
|
92
|
+
end
|
93
|
+
|
94
|
+
def children
|
95
|
+
self.class.children.keys.flat_map { |name| send(name) }.compact
|
96
|
+
end
|
97
|
+
|
98
|
+
def read_children(xml_node)
|
99
|
+
xml_node.children.each do |child_node|
|
100
|
+
read_child(child_node)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def read_child(child_node)
|
105
|
+
name, options = self.class.children.find do |_, opts|
|
106
|
+
opts[:class_name].constantize.adapt?(child_node)
|
107
|
+
end
|
108
|
+
if name.present?
|
109
|
+
child = options[:class_name].constantize.read_from(child_node)
|
110
|
+
send("append_#{name.to_s.singularize}", child)
|
111
|
+
else
|
112
|
+
unparsed_children << child_node
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
@@ -31,7 +31,7 @@ module Goldendocx
|
|
31
31
|
return unless relationship_id
|
32
32
|
|
33
33
|
non_visual_picture.non_visual_drawing.assign_attributes(
|
34
|
-
relationship_id
|
34
|
+
relationship_id:,
|
35
35
|
name: "#{relationship_id}.png"
|
36
36
|
)
|
37
37
|
picture_fill.blip.relationship_id = relationship_id
|
data/lib/goldendocx/images.rb
CHANGED
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Goldendocx
|
4
|
+
module Models
|
5
|
+
class Relationships
|
6
|
+
include Goldendocx::Document
|
7
|
+
|
8
|
+
NAMESPACE = 'http://schemas.openxmlformats.org/package/2006/relationships'
|
9
|
+
|
10
|
+
tag :Relationships
|
11
|
+
attribute :xmlns, default: NAMESPACE, readonly: true
|
12
|
+
|
13
|
+
embeds_many :relationships, class_name: 'Goldendocx::Models::Relationship'
|
14
|
+
|
15
|
+
def size
|
16
|
+
relationships.size
|
17
|
+
end
|
18
|
+
|
19
|
+
def write_to(zos, xml_path)
|
20
|
+
zos.put_next_entry xml_path
|
21
|
+
zos.write to_document_xml
|
22
|
+
end
|
23
|
+
|
24
|
+
def add_relationship(type, target)
|
25
|
+
relationship_id = "rId#{relationships.size + 1}"
|
26
|
+
build_relationship(id: relationship_id, type:, target:)
|
27
|
+
relationship_id
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Goldendocx
|
4
|
+
module Parts
|
5
|
+
class App
|
6
|
+
include Goldendocx::Document
|
7
|
+
|
8
|
+
TYPE = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties'
|
9
|
+
XML_PATH = 'docProps/app.xml'
|
10
|
+
NAMESPACE = 'http://schemas.openxmlformats.org/officeDocument/2006/extended-properties'
|
11
|
+
CONTENT_TYPE = 'application/vnd.openxmlformats-officedocument.extended-properties+xml'
|
12
|
+
|
13
|
+
tag :Properties
|
14
|
+
attribute :xmlns, default: NAMESPACE, readonly: true
|
15
|
+
|
16
|
+
class << self
|
17
|
+
def read_from(app_document)
|
18
|
+
new_instance = new
|
19
|
+
|
20
|
+
app_document.children.map do |node|
|
21
|
+
new_instance.properties[node.name.to_sym] = node.text
|
22
|
+
end
|
23
|
+
|
24
|
+
new_instance
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def write_to(zos)
|
29
|
+
zos.put_next_entry XML_PATH
|
30
|
+
zos.write to_document_xml
|
31
|
+
end
|
32
|
+
|
33
|
+
def to_document_xml
|
34
|
+
super do |xml|
|
35
|
+
properties.each do |name, value|
|
36
|
+
xml << Goldendocx.xml_serializer.build_element(name).tap { |app| app << value }
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def properties
|
42
|
+
@properties ||= { Application: "Goldendocx_#{Goldendocx::VERSION}" }
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -11,52 +11,38 @@ module Goldendocx
|
|
11
11
|
XML_PATH = '[Content_Types].xml'
|
12
12
|
NAMESPACE = 'http://schemas.openxmlformats.org/package/2006/content-types'
|
13
13
|
|
14
|
-
|
14
|
+
REQUIRED_DEFAULTS = {
|
15
|
+
rels: 'application/vnd.openxmlformats-package.relationships+xml',
|
16
|
+
xml: 'application/xml'
|
17
|
+
}.with_indifferent_access.freeze
|
15
18
|
|
16
19
|
tag :Types
|
17
20
|
attribute :xmlns, default: NAMESPACE, readonly: true
|
18
21
|
|
19
|
-
|
20
|
-
|
21
|
-
content_types = Goldendocx::Parts::ContentTypes.new
|
22
|
-
content_types.read_defaults(docx_file)
|
23
|
-
content_types.read_overrides(docx_file)
|
24
|
-
content_types
|
25
|
-
end
|
26
|
-
end
|
22
|
+
embeds_many :defaults, class_name: 'Goldendocx::ContentTypes::Default', uniqueness: true
|
23
|
+
embeds_many :overrides, class_name: 'Goldendocx::ContentTypes::Override', uniqueness: true
|
27
24
|
|
28
25
|
def initialize
|
29
|
-
|
30
|
-
|
31
|
-
end
|
32
|
-
|
33
|
-
def read_defaults(docx_file)
|
34
|
-
@defaults = Goldendocx.xml_serializer.parse(docx_file.read(XML_PATH), %w[Types Default]).map do |node|
|
35
|
-
Goldendocx::ContentTypes::Default.new(node[:Extension], node[:ContentType])
|
26
|
+
REQUIRED_DEFAULTS.map do |extension, content_type|
|
27
|
+
build_defaults(extension:, content_type:)
|
36
28
|
end
|
37
29
|
end
|
38
30
|
|
39
|
-
def
|
40
|
-
|
41
|
-
|
42
|
-
end
|
31
|
+
def write_to(zos)
|
32
|
+
zos.put_next_entry XML_PATH
|
33
|
+
zos.write to_document_xml
|
43
34
|
end
|
44
35
|
|
45
36
|
def add_default(extension, content_type)
|
46
|
-
|
47
|
-
|
37
|
+
return if defaults.any? { |default| extension == default.extension && content_type == default.content_type }
|
38
|
+
|
39
|
+
build_defaults(extension:, content_type:)
|
48
40
|
end
|
49
41
|
|
50
42
|
def add_override(part_name, content_type)
|
51
|
-
|
52
|
-
overrides << new_override if overrides.none?(new_override)
|
53
|
-
end
|
43
|
+
return if overrides.any? { |override| part_name == override.part_name && content_type == override.content_type }
|
54
44
|
|
55
|
-
|
56
|
-
super do |xml|
|
57
|
-
defaults.each { |default| xml << default }
|
58
|
-
overrides.each { |override| xml << override }
|
59
|
-
end
|
45
|
+
build_override(part_name:, content_type:)
|
60
46
|
end
|
61
47
|
end
|
62
48
|
end
|