goldendocx 0.2.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.rspec +2 -0
- data/.rubocop.yml +47 -0
- data/CHANGELOG.md +43 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +101 -0
- data/README.md +76 -0
- data/Rakefile +10 -0
- data/coverage/.last_run.json +5 -0
- data/demo/charts/create_bar_chart.rb +30 -0
- data/demo/charts/create_column_chart.rb +29 -0
- data/demo/charts/create_doughnut_chart.rb +28 -0
- data/demo/charts/create_line_chart.rb +41 -0
- data/demo/images/append_image.rb +21 -0
- data/demo/images/append_styled_image.rb +14 -0
- data/demo/tables/create_embed_image_table.rb +42 -0
- data/demo/tables/create_plain_table.rb +22 -0
- data/demo/tables/create_styled_table.rb +36 -0
- data/demo/templates/bg.png +0 -0
- data/demo/templates/blankDocument.docx +0 -0
- data/demo/templates/image_base64 +1 -0
- data/demo/templates/styles/reportLabel +19 -0
- data/demo/templates/styles/reportSubTitle +20 -0
- data/demo/templates/styles/reportTable +27 -0
- data/demo/templates/styles/reportTitle +19 -0
- data/demo/texts/append_plain_text.rb +13 -0
- data/demo/texts/append_styled_text.rb +23 -0
- data/lib/goldendocx/charts/category_axis.rb +20 -0
- data/lib/goldendocx/charts/properties/auto_title_deleted_property.rb +16 -0
- data/lib/goldendocx/charts/properties/axis_property.rb +16 -0
- data/lib/goldendocx/charts/properties/bar_chart_property.rb +28 -0
- data/lib/goldendocx/charts/properties/chart_property.rb +16 -0
- data/lib/goldendocx/charts/properties/column_chart_property.rb +28 -0
- data/lib/goldendocx/charts/properties/cross_axis_property.rb +16 -0
- data/lib/goldendocx/charts/properties/data_lables_property.rb +16 -0
- data/lib/goldendocx/charts/properties/direction_property.rb +16 -0
- data/lib/goldendocx/charts/properties/doughnut_chart_property.rb +17 -0
- data/lib/goldendocx/charts/properties/grouping_property.rb +16 -0
- data/lib/goldendocx/charts/properties/hole_property.rb +16 -0
- data/lib/goldendocx/charts/properties/index_property.rb +16 -0
- data/lib/goldendocx/charts/properties/label_hidden_property.rb +16 -0
- data/lib/goldendocx/charts/properties/layout_property.rb +14 -0
- data/lib/goldendocx/charts/properties/line_chart_property.rb +24 -0
- data/lib/goldendocx/charts/properties/marker_property.rb +16 -0
- data/lib/goldendocx/charts/properties/number_list_property.rb +17 -0
- data/lib/goldendocx/charts/properties/order_property.rb +16 -0
- data/lib/goldendocx/charts/properties/plot_area_property.rb +23 -0
- data/lib/goldendocx/charts/properties/point_count_property.rb +16 -0
- data/lib/goldendocx/charts/properties/point_property.rb +18 -0
- data/lib/goldendocx/charts/properties/rounded_corner_property.rb +16 -0
- data/lib/goldendocx/charts/properties/series_category_property.rb +16 -0
- data/lib/goldendocx/charts/properties/series_text_property.rb +16 -0
- data/lib/goldendocx/charts/properties/series_value_property.rb +16 -0
- data/lib/goldendocx/charts/properties/smooth_property.rb +14 -0
- data/lib/goldendocx/charts/properties/string_list_property.rb +17 -0
- data/lib/goldendocx/charts/properties/symbol_property.rb +16 -0
- data/lib/goldendocx/charts/properties/text_value_property.rb +16 -0
- data/lib/goldendocx/charts/properties.rb +12 -0
- data/lib/goldendocx/charts/reference.rb +16 -0
- data/lib/goldendocx/charts/series.rb +57 -0
- data/lib/goldendocx/charts/value_axis.rb +20 -0
- data/lib/goldendocx/charts.rb +26 -0
- data/lib/goldendocx/components/bar_chart.rb +17 -0
- data/lib/goldendocx/components/chart.rb +55 -0
- data/lib/goldendocx/components/column_chart.rb +17 -0
- data/lib/goldendocx/components/doughnut_chart.rb +17 -0
- data/lib/goldendocx/components/image.rb +77 -0
- data/lib/goldendocx/components/line_chart.rb +17 -0
- data/lib/goldendocx/components/paragraph.rb +23 -0
- data/lib/goldendocx/components/properties/align_property.rb +16 -0
- data/lib/goldendocx/components/properties/bold_property.rb +16 -0
- data/lib/goldendocx/components/properties/color_property.rb +16 -0
- data/lib/goldendocx/components/properties/drawing.rb +16 -0
- data/lib/goldendocx/components/properties/extents_property.rb +17 -0
- data/lib/goldendocx/components/properties/graphic_data_property.rb +17 -0
- data/lib/goldendocx/components/properties/graphic_frame_locks_property.rb +18 -0
- data/lib/goldendocx/components/properties/graphic_frame_property.rb +16 -0
- data/lib/goldendocx/components/properties/graphic_property.rb +16 -0
- data/lib/goldendocx/components/properties/inline.rb +20 -0
- data/lib/goldendocx/components/properties/non_visual_property.rb +17 -0
- data/lib/goldendocx/components/properties/padding_property.rb +19 -0
- data/lib/goldendocx/components/properties/property.rb +17 -0
- data/lib/goldendocx/components/properties/run.rb +20 -0
- data/lib/goldendocx/components/properties/run_property.rb +17 -0
- data/lib/goldendocx/components/properties/style_property.rb +16 -0
- data/lib/goldendocx/components/properties/textual.rb +16 -0
- data/lib/goldendocx/components/properties.rb +12 -0
- data/lib/goldendocx/components/table.rb +44 -0
- data/lib/goldendocx/components/text.rb +35 -0
- data/lib/goldendocx/components.rb +16 -0
- data/lib/goldendocx/configuration.rb +18 -0
- data/lib/goldendocx/content_types/default.rb +22 -0
- data/lib/goldendocx/content_types/override.rb +22 -0
- data/lib/goldendocx/document.rb +51 -0
- data/lib/goldendocx/documents/body.rb +90 -0
- data/lib/goldendocx/documents/document.rb +29 -0
- data/lib/goldendocx/documents/element.rb +23 -0
- data/lib/goldendocx/documents/relationship.rb +17 -0
- data/lib/goldendocx/documents/relationships.rb +39 -0
- data/lib/goldendocx/documents/style.rb +21 -0
- data/lib/goldendocx/documents/styles.rb +74 -0
- data/lib/goldendocx/documents/unparsed_style.rb +17 -0
- data/lib/goldendocx/documents.rb +10 -0
- data/lib/goldendocx/docx.rb +108 -0
- data/lib/goldendocx/element.rb +192 -0
- data/lib/goldendocx/images/picture.rb +41 -0
- data/lib/goldendocx/images/properties/blip_property.rb +16 -0
- data/lib/goldendocx/images/properties/drawing_property.rb +14 -0
- data/lib/goldendocx/images/properties/extents_property.rb +17 -0
- data/lib/goldendocx/images/properties/fill_rectangle_property.rb +14 -0
- data/lib/goldendocx/images/properties/image_data_property.rb +17 -0
- data/lib/goldendocx/images/properties/non_visual_drawing_property.rb +17 -0
- data/lib/goldendocx/images/properties/non_visual_picture_property.rb +17 -0
- data/lib/goldendocx/images/properties/picture_fill_property.rb +17 -0
- data/lib/goldendocx/images/properties/picture_shape_property.rb +16 -0
- data/lib/goldendocx/images/properties/shape_property.rb +30 -0
- data/lib/goldendocx/images/properties/stretch_property.rb +17 -0
- data/lib/goldendocx/images/properties/transform_property.rb +16 -0
- data/lib/goldendocx/images/properties.rb +12 -0
- data/lib/goldendocx/images/shape.rb +32 -0
- data/lib/goldendocx/images.rb +12 -0
- data/lib/goldendocx/parts/content_types.rb +63 -0
- data/lib/goldendocx/parts/documents.rb +103 -0
- data/lib/goldendocx/parts/media.rb +43 -0
- data/lib/goldendocx/parts.rb +10 -0
- data/lib/goldendocx/tables/cell.rb +33 -0
- data/lib/goldendocx/tables/header_cell.rb +16 -0
- data/lib/goldendocx/tables/header_row.rb +14 -0
- data/lib/goldendocx/tables/image_cell.rb +23 -0
- data/lib/goldendocx/tables/properties/cell_property.rb +19 -0
- data/lib/goldendocx/tables/properties/cell_width_property.rb +17 -0
- data/lib/goldendocx/tables/properties/grid_column_property.rb +16 -0
- data/lib/goldendocx/tables/properties/grid_property.rb +16 -0
- data/lib/goldendocx/tables/properties/grid_span_property.rb +16 -0
- data/lib/goldendocx/tables/properties/header_row_property.rb +14 -0
- data/lib/goldendocx/tables/properties/property.rb +17 -0
- data/lib/goldendocx/tables/properties/row_height_property.rb +17 -0
- data/lib/goldendocx/tables/properties/row_property.rb +16 -0
- data/lib/goldendocx/tables/properties/shading_property.rb +18 -0
- data/lib/goldendocx/tables/properties/style_property.rb +16 -0
- data/lib/goldendocx/tables/properties/vertical_align_property.rb +16 -0
- data/lib/goldendocx/tables/properties/width_property.rb +17 -0
- data/lib/goldendocx/tables/properties.rb +12 -0
- data/lib/goldendocx/tables/row.rb +28 -0
- data/lib/goldendocx/tables.rb +19 -0
- data/lib/goldendocx/units.rb +11 -0
- data/lib/goldendocx/version.rb +5 -0
- data/lib/goldendocx/xml_serializers/nokogiri.rb +66 -0
- data/lib/goldendocx/xml_serializers/ox.rb +63 -0
- data/lib/goldendocx.rb +72 -0
- data/sig/goldendocx.rbs +4 -0
- metadata +347 -0
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Goldendocx
|
4
|
+
module Documents
|
5
|
+
class Relationship
|
6
|
+
include Goldendocx::Element
|
7
|
+
|
8
|
+
attr_reader :id, :type, :target
|
9
|
+
|
10
|
+
tag :Relationship
|
11
|
+
|
12
|
+
attribute :id, alias_name: :Id
|
13
|
+
attribute :type, alias_name: :Type
|
14
|
+
attribute :target, alias_name: :Target
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Goldendocx
|
4
|
+
module Documents
|
5
|
+
class Relationships
|
6
|
+
include Goldendocx::Document
|
7
|
+
|
8
|
+
XML_PATH = 'word/_rels/document.xml.rels'
|
9
|
+
NAMESPACE = 'http://schemas.openxmlformats.org/package/2006/relationships'
|
10
|
+
|
11
|
+
tag :Relationships
|
12
|
+
attribute :xmlns, default: NAMESPACE, readonly: true
|
13
|
+
|
14
|
+
embeds_many :relationships, class_name: 'Goldendocx::Documents::Relationship'
|
15
|
+
|
16
|
+
def size
|
17
|
+
relationships.size
|
18
|
+
end
|
19
|
+
|
20
|
+
def read_from(docx_file)
|
21
|
+
paths = %w[Relationships Relationship]
|
22
|
+
Goldendocx.xml_serializer.parse(docx_file.read(XML_PATH), paths).map do |node|
|
23
|
+
build_relationship(id: node[:Id], type: node[:Type], target: node[:Target])
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def write_to(zos)
|
28
|
+
zos.put_next_entry XML_PATH
|
29
|
+
zos.write to_document_xml
|
30
|
+
end
|
31
|
+
|
32
|
+
def add_relationship(type, target)
|
33
|
+
relationship_id = "rId#{relationships.size + 1}"
|
34
|
+
build_relationship(id: relationship_id, type: type, target: target)
|
35
|
+
relationship_id
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Goldendocx
|
4
|
+
module Documents
|
5
|
+
class Style
|
6
|
+
attr_reader :node, :id, :type, :name
|
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
|
15
|
+
|
16
|
+
def to_element(**_context)
|
17
|
+
@node
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Goldendocx
|
4
|
+
module Documents
|
5
|
+
class Styles
|
6
|
+
include Goldendocx::Document
|
7
|
+
|
8
|
+
XML_PATH = 'word/styles.xml'
|
9
|
+
|
10
|
+
tag :styles
|
11
|
+
namespace :w
|
12
|
+
concern_namespaces :mc, :r, :w, :w14, :w15
|
13
|
+
ignore_namespaces :w14, :w15
|
14
|
+
|
15
|
+
attr_reader :styles, :doc_defaults, :latent_styles
|
16
|
+
|
17
|
+
def initialize
|
18
|
+
@styles = []
|
19
|
+
end
|
20
|
+
|
21
|
+
def size
|
22
|
+
styles.size
|
23
|
+
end
|
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
|
+
def write_to(zos)
|
46
|
+
zos.put_next_entry XML_PATH
|
47
|
+
zos.write to_document_xml
|
48
|
+
end
|
49
|
+
|
50
|
+
def find_text_style(style_name)
|
51
|
+
return if style_name.nil?
|
52
|
+
|
53
|
+
styles.find { |s| s.type == 'paragraph' && s.name == style_name }
|
54
|
+
end
|
55
|
+
|
56
|
+
def find_table_style(style_name)
|
57
|
+
return if style_name.nil?
|
58
|
+
|
59
|
+
styles.find { |s| s.type == 'table' && s.name == style_name }
|
60
|
+
end
|
61
|
+
|
62
|
+
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
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'goldendocx/units'
|
4
|
+
require 'goldendocx/element'
|
5
|
+
require 'goldendocx/document'
|
6
|
+
|
7
|
+
require 'goldendocx/components'
|
8
|
+
require 'goldendocx/documents'
|
9
|
+
require 'goldendocx/parts'
|
10
|
+
|
11
|
+
module Goldendocx
|
12
|
+
class Docx
|
13
|
+
attr_reader :unstructured_entries, :documents, :content_types
|
14
|
+
|
15
|
+
STRUCTURED_ENTRIES = [
|
16
|
+
Goldendocx::Parts::ContentTypes::XML_PATH,
|
17
|
+
|
18
|
+
Goldendocx::Documents::Body::XML_PATH,
|
19
|
+
Goldendocx::Documents::Relationships::XML_PATH,
|
20
|
+
Goldendocx::Documents::Styles::XML_PATH
|
21
|
+
].freeze
|
22
|
+
|
23
|
+
def initialize(file_path)
|
24
|
+
docx_file = Zip::File.new(file_path)
|
25
|
+
@documents = Goldendocx::Parts::Documents.read_from(docx_file)
|
26
|
+
@content_types = Goldendocx::Parts::ContentTypes.read_from(docx_file)
|
27
|
+
@unstructured_entries = docx_file.entries.filter_map do |entry|
|
28
|
+
UnStructuredEntry.new(entry) unless STRUCTURED_ENTRIES.include?(entry.name)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def write_to(new_path)
|
33
|
+
File.binwrite(new_path, to_stream.string)
|
34
|
+
end
|
35
|
+
|
36
|
+
def create_text(text, options = {})
|
37
|
+
documents.create_text(text, options)
|
38
|
+
end
|
39
|
+
|
40
|
+
def create_table(options = {})
|
41
|
+
documents.create_table(options)
|
42
|
+
end
|
43
|
+
|
44
|
+
def create_image(image_data, options = {})
|
45
|
+
ensure_image_content_type!(image_data)
|
46
|
+
documents.create_image(image_data, options)
|
47
|
+
end
|
48
|
+
|
49
|
+
def create_embed_image(image_data, options = {})
|
50
|
+
ensure_image_content_type!(image_data)
|
51
|
+
documents.create_embed_image(image_data, options)
|
52
|
+
end
|
53
|
+
|
54
|
+
def add_style(style_path)
|
55
|
+
documents.add_style(style_path)
|
56
|
+
end
|
57
|
+
|
58
|
+
def create_chart(chart_type, width: nil, height: nil)
|
59
|
+
chart = documents.create_chart(
|
60
|
+
chart_type, width || Charts::DEFAULT_WIDTH, height || Charts::DEFAULT_HEIGHT
|
61
|
+
)
|
62
|
+
ensure_chart_content_type!(chart)
|
63
|
+
chart
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
67
|
+
|
68
|
+
def ensure_image_content_type!(_image_data)
|
69
|
+
extension = 'png'
|
70
|
+
content_type = 'image/png'
|
71
|
+
content_types.add_default(extension, content_type)
|
72
|
+
end
|
73
|
+
|
74
|
+
def ensure_chart_content_type!(chart)
|
75
|
+
content_types.add_override(
|
76
|
+
format(Charts::PART_NAME_PATTERN, id: chart.id), Charts::CONTENT_TYPE
|
77
|
+
)
|
78
|
+
end
|
79
|
+
|
80
|
+
def to_stream
|
81
|
+
Zip::OutputStream.write_buffer do |zos|
|
82
|
+
zos.put_next_entry Goldendocx::Parts::ContentTypes::XML_PATH
|
83
|
+
zos.write content_types.to_document_xml
|
84
|
+
|
85
|
+
zos.put_next_entry Goldendocx::Parts::Documents::XML_PATH
|
86
|
+
documents.write_stream(zos)
|
87
|
+
|
88
|
+
@unstructured_entries.each { |unstructured_entry| unstructured_entry.write_to(zos) }
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
# TODO: Remove this after all structured
|
93
|
+
class UnStructuredEntry
|
94
|
+
attr_reader :entry
|
95
|
+
|
96
|
+
def initialize(entry)
|
97
|
+
@entry = entry
|
98
|
+
end
|
99
|
+
|
100
|
+
def write_to(zos)
|
101
|
+
zos.put_next_entry entry.name
|
102
|
+
return if entry.directory?
|
103
|
+
|
104
|
+
zos.write entry.get_input_stream.read
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
@@ -0,0 +1,192 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'active_support/core_ext/string/inflections'
|
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
|
11
|
+
|
12
|
+
module Goldendocx
|
13
|
+
module Element
|
14
|
+
def self.included(base)
|
15
|
+
base.extend(ClassMethods)
|
16
|
+
end
|
17
|
+
|
18
|
+
module ClassMethods
|
19
|
+
def tag(*args)
|
20
|
+
@tag = args.first if args.any?
|
21
|
+
@tag
|
22
|
+
end
|
23
|
+
|
24
|
+
def namespace(*args)
|
25
|
+
@namespace = args.first if args.any?
|
26
|
+
@namespace
|
27
|
+
end
|
28
|
+
|
29
|
+
# alias_name: nil
|
30
|
+
# readonly: false
|
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
|
73
|
+
end
|
74
|
+
|
75
|
+
def create_children_setter(name)
|
76
|
+
options = children[name]
|
77
|
+
class_name = options[:class_name]
|
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
|
83
|
+
end
|
84
|
+
|
85
|
+
def create_children_builder(name)
|
86
|
+
options = children[name]
|
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
|
96
|
+
end
|
97
|
+
|
98
|
+
def embeds_one(name, class_name:, auto_build: false)
|
99
|
+
warning_naming_suggestion(name, name.to_s.singularize)
|
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
|
114
|
+
|
115
|
+
def children
|
116
|
+
@children ||= {}
|
117
|
+
end
|
118
|
+
|
119
|
+
def concerning_ancestors
|
120
|
+
ancestors.filter { |ancestor| ancestor.include?(Goldendocx::Element) }
|
121
|
+
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
|
+
end
|
144
|
+
|
145
|
+
def assign_attributes(**attributes)
|
146
|
+
attributes.each { |key, value| send("#{key}=", value) if respond_to?("#{key}=") }
|
147
|
+
end
|
148
|
+
|
149
|
+
def tag
|
150
|
+
self.class.concerning_ancestors.find { |ancestor| ancestor.tag.present? }&.tag
|
151
|
+
end
|
152
|
+
|
153
|
+
def namespace
|
154
|
+
self.class.concerning_ancestors.find { |ancestor| ancestor.namespace.present? }&.namespace
|
155
|
+
end
|
156
|
+
|
157
|
+
def root_tag
|
158
|
+
@root_tag ||= [namespace, tag].compact.join(':')
|
159
|
+
end
|
160
|
+
|
161
|
+
def siblings
|
162
|
+
return [] unless self.class.superclass.include?(Goldendocx::Element)
|
163
|
+
|
164
|
+
self.class.superclass.children.keys.flat_map { |name| send(name) }
|
165
|
+
end
|
166
|
+
|
167
|
+
def children
|
168
|
+
self.class.children.keys.flat_map do |name|
|
169
|
+
send(name)
|
170
|
+
end.concat(siblings).compact
|
171
|
+
end
|
172
|
+
|
173
|
+
def to_element(**context)
|
174
|
+
Goldendocx.xml_serializer.build_element(root_tag, **context) do |xml|
|
175
|
+
attributes.each { |name, value| xml[name] = value }
|
176
|
+
children.each { |child| xml << child }
|
177
|
+
|
178
|
+
yield(xml) if block_given?
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
def to_xml
|
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
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Goldendocx
|
4
|
+
module Images
|
5
|
+
class Picture
|
6
|
+
include Goldendocx::Element
|
7
|
+
|
8
|
+
namespace :pic
|
9
|
+
tag :pic
|
10
|
+
|
11
|
+
embeds_one :non_visual_picture, class_name: 'Goldendocx::Images::Properties::NonVisualPictureProperty', auto_build: true
|
12
|
+
embeds_one :drawing, class_name: 'Goldendocx::Images::Properties::DrawingProperty', auto_build: true
|
13
|
+
embeds_one :picture_fill, class_name: 'Goldendocx::Images::Properties::PictureFillProperty', auto_build: true
|
14
|
+
embeds_one :picture_shape, class_name: 'Goldendocx::Images::Properties::PictureShapeProperty', auto_build: true
|
15
|
+
|
16
|
+
def initialize(**attributes)
|
17
|
+
attributes.each do |name, value|
|
18
|
+
send("#{name}=", value) if respond_to?("#{name}=")
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def width=(width)
|
23
|
+
picture_shape.transform.extents.width = width if width
|
24
|
+
end
|
25
|
+
|
26
|
+
def height=(height)
|
27
|
+
picture_shape.transform.extents.height = height if height
|
28
|
+
end
|
29
|
+
|
30
|
+
def relationship_id=(relationship_id)
|
31
|
+
return unless relationship_id
|
32
|
+
|
33
|
+
non_visual_picture.non_visual_drawing.assign_attributes(
|
34
|
+
relationship_id: relationship_id,
|
35
|
+
name: "#{relationship_id}.png"
|
36
|
+
)
|
37
|
+
picture_fill.blip.relationship_id = relationship_id
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Goldendocx
|
4
|
+
module Images
|
5
|
+
module Properties
|
6
|
+
class BlipProperty
|
7
|
+
include Goldendocx::Element
|
8
|
+
|
9
|
+
namespace :a
|
10
|
+
tag :blip
|
11
|
+
|
12
|
+
attribute :relationship_id, alias_name: :embed, namespace: :r
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Goldendocx
|
4
|
+
module Images
|
5
|
+
module Properties
|
6
|
+
class ExtentsProperty
|
7
|
+
include Goldendocx::Element
|
8
|
+
|
9
|
+
namespace :a
|
10
|
+
tag :ext
|
11
|
+
|
12
|
+
attribute :width, alias_name: :cx
|
13
|
+
attribute :height, alias_name: :cy
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Goldendocx
|
4
|
+
module Images
|
5
|
+
module Properties
|
6
|
+
class ImageDataProperty
|
7
|
+
include Goldendocx::Element
|
8
|
+
|
9
|
+
namespace :v
|
10
|
+
tag :imagedata
|
11
|
+
|
12
|
+
attribute :relationship_id, alias_name: :id, namespace: :r
|
13
|
+
attribute :title, namespace: :o
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Goldendocx
|
4
|
+
module Images
|
5
|
+
module Properties
|
6
|
+
class NonVisualDrawingProperty
|
7
|
+
include Goldendocx::Element
|
8
|
+
|
9
|
+
namespace :pic
|
10
|
+
tag :cNvPr
|
11
|
+
|
12
|
+
attribute :relationship_id, alias_name: :id
|
13
|
+
attribute :name
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Goldendocx
|
4
|
+
module Images
|
5
|
+
module Properties
|
6
|
+
class NonVisualPictureProperty
|
7
|
+
include Goldendocx::Element
|
8
|
+
|
9
|
+
namespace :pic
|
10
|
+
tag :nvPicPr
|
11
|
+
|
12
|
+
embeds_one :non_visual_drawing, class_name: 'Goldendocx::Images::Properties::NonVisualDrawingProperty',
|
13
|
+
auto_build: true
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Goldendocx
|
4
|
+
module Images
|
5
|
+
module Properties
|
6
|
+
class PictureFillProperty
|
7
|
+
include Goldendocx::Element
|
8
|
+
|
9
|
+
namespace :pic
|
10
|
+
tag :blipFill
|
11
|
+
|
12
|
+
embeds_one :blip, class_name: 'Goldendocx::Images::Properties::BlipProperty', auto_build: true
|
13
|
+
embeds_one :stretch, class_name: 'Goldendocx::Images::Properties::StretchProperty', 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 Images
|
5
|
+
module Properties
|
6
|
+
class PictureShapeProperty
|
7
|
+
include Goldendocx::Element
|
8
|
+
|
9
|
+
namespace :pic
|
10
|
+
tag :spPr
|
11
|
+
|
12
|
+
embeds_one :transform, class_name: 'Goldendocx::Images::Properties::TransformProperty', auto_build: true
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|