goldendocx 0.2.2 → 0.2.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +4 -0
- data/CHANGELOG.md +8 -2
- data/Gemfile.lock +3 -1
- data/README.md +10 -2
- data/Rakefile +14 -3
- data/demo/templates/generate_codes.rb +10 -0
- data/demo/templates/xml_to_class.rb +91 -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/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/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 +20 -11
- 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/docx.rb +55 -12
- data/lib/goldendocx/element.rb +33 -140
- data/lib/goldendocx/has_associations.rb +52 -0
- data/lib/goldendocx/has_attributes.rb +67 -0
- data/lib/goldendocx/has_children.rb +116 -0
- data/lib/goldendocx/{documents → models}/relationship.rb +1 -1
- data/lib/goldendocx/{documents → models}/relationships.rb +4 -12
- 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 +26 -13
- 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/tables/row.rb +1 -1
- data/lib/goldendocx/version.rb +1 -1
- data/lib/goldendocx/xml_serializers/nokogiri.rb +30 -22
- data/lib/goldendocx/xml_serializers/ox.rb +10 -20
- data/lib/goldendocx.rb +14 -2
- metadata +51 -7
- data/lib/goldendocx/documents/element.rb +0 -23
- data/lib/goldendocx/documents/unparsed_style.rb +0 -17
@@ -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/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) }
|
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, &block)
|
68
|
+
Goldendocx.xml_serializer.build_element(tag_name, **context) { |xml| build_element(xml, &block) }
|
165
69
|
end
|
166
70
|
|
167
|
-
def
|
168
|
-
|
169
|
-
send(name)
|
170
|
-
end.concat(siblings).compact
|
71
|
+
def to_xml(&block)
|
72
|
+
Goldendocx.xml_serializer.build_xml(tag_name) { |xml| build_element(xml, &block) }
|
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,52 @@
|
|
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
|
+
class_methods do
|
15
|
+
def relationships_at(xml_path)
|
16
|
+
self.relationships_xml_path = xml_path
|
17
|
+
end
|
18
|
+
|
19
|
+
def associate(name, class_name:, isolate: false)
|
20
|
+
named = name.to_s
|
21
|
+
associations[named] = { class_name: class_name, isolate: isolate }
|
22
|
+
|
23
|
+
define_method named do
|
24
|
+
return instance_variable_get("@#{name}") if instance_variable_defined?("@#{name}")
|
25
|
+
|
26
|
+
new_instance = class_name.constantize.new
|
27
|
+
instance_variable_set("@#{name}", new_instance)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def read_associations(docx_file)
|
33
|
+
associations.each do |association, options|
|
34
|
+
association_class = options[:class_name].constantize
|
35
|
+
association_document_xml = docx_file.read(association_class::XML_PATH)
|
36
|
+
instance_variable_set("@#{association}", association_class.parse(association_document_xml))
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def read_relationships(docx_file)
|
41
|
+
@relationships = Goldendocx::Models::Relationships.parse(docx_file.read(relationships_xml_path))
|
42
|
+
end
|
43
|
+
|
44
|
+
def write_relationships(zos)
|
45
|
+
relationships.write_to(zos, relationships_xml_path)
|
46
|
+
end
|
47
|
+
|
48
|
+
def relationships
|
49
|
+
@relationships ||= Goldendocx::Models::Relationships.new
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|