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
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
|