goldendocx 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (152) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +2 -0
  3. data/.rubocop.yml +47 -0
  4. data/CHANGELOG.md +43 -0
  5. data/Gemfile +6 -0
  6. data/Gemfile.lock +101 -0
  7. data/README.md +76 -0
  8. data/Rakefile +10 -0
  9. data/coverage/.last_run.json +5 -0
  10. data/demo/charts/create_bar_chart.rb +30 -0
  11. data/demo/charts/create_column_chart.rb +29 -0
  12. data/demo/charts/create_doughnut_chart.rb +28 -0
  13. data/demo/charts/create_line_chart.rb +41 -0
  14. data/demo/images/append_image.rb +21 -0
  15. data/demo/images/append_styled_image.rb +14 -0
  16. data/demo/tables/create_embed_image_table.rb +42 -0
  17. data/demo/tables/create_plain_table.rb +22 -0
  18. data/demo/tables/create_styled_table.rb +36 -0
  19. data/demo/templates/bg.png +0 -0
  20. data/demo/templates/blankDocument.docx +0 -0
  21. data/demo/templates/image_base64 +1 -0
  22. data/demo/templates/styles/reportLabel +19 -0
  23. data/demo/templates/styles/reportSubTitle +20 -0
  24. data/demo/templates/styles/reportTable +27 -0
  25. data/demo/templates/styles/reportTitle +19 -0
  26. data/demo/texts/append_plain_text.rb +13 -0
  27. data/demo/texts/append_styled_text.rb +23 -0
  28. data/lib/goldendocx/charts/category_axis.rb +20 -0
  29. data/lib/goldendocx/charts/properties/auto_title_deleted_property.rb +16 -0
  30. data/lib/goldendocx/charts/properties/axis_property.rb +16 -0
  31. data/lib/goldendocx/charts/properties/bar_chart_property.rb +28 -0
  32. data/lib/goldendocx/charts/properties/chart_property.rb +16 -0
  33. data/lib/goldendocx/charts/properties/column_chart_property.rb +28 -0
  34. data/lib/goldendocx/charts/properties/cross_axis_property.rb +16 -0
  35. data/lib/goldendocx/charts/properties/data_lables_property.rb +16 -0
  36. data/lib/goldendocx/charts/properties/direction_property.rb +16 -0
  37. data/lib/goldendocx/charts/properties/doughnut_chart_property.rb +17 -0
  38. data/lib/goldendocx/charts/properties/grouping_property.rb +16 -0
  39. data/lib/goldendocx/charts/properties/hole_property.rb +16 -0
  40. data/lib/goldendocx/charts/properties/index_property.rb +16 -0
  41. data/lib/goldendocx/charts/properties/label_hidden_property.rb +16 -0
  42. data/lib/goldendocx/charts/properties/layout_property.rb +14 -0
  43. data/lib/goldendocx/charts/properties/line_chart_property.rb +24 -0
  44. data/lib/goldendocx/charts/properties/marker_property.rb +16 -0
  45. data/lib/goldendocx/charts/properties/number_list_property.rb +17 -0
  46. data/lib/goldendocx/charts/properties/order_property.rb +16 -0
  47. data/lib/goldendocx/charts/properties/plot_area_property.rb +23 -0
  48. data/lib/goldendocx/charts/properties/point_count_property.rb +16 -0
  49. data/lib/goldendocx/charts/properties/point_property.rb +18 -0
  50. data/lib/goldendocx/charts/properties/rounded_corner_property.rb +16 -0
  51. data/lib/goldendocx/charts/properties/series_category_property.rb +16 -0
  52. data/lib/goldendocx/charts/properties/series_text_property.rb +16 -0
  53. data/lib/goldendocx/charts/properties/series_value_property.rb +16 -0
  54. data/lib/goldendocx/charts/properties/smooth_property.rb +14 -0
  55. data/lib/goldendocx/charts/properties/string_list_property.rb +17 -0
  56. data/lib/goldendocx/charts/properties/symbol_property.rb +16 -0
  57. data/lib/goldendocx/charts/properties/text_value_property.rb +16 -0
  58. data/lib/goldendocx/charts/properties.rb +12 -0
  59. data/lib/goldendocx/charts/reference.rb +16 -0
  60. data/lib/goldendocx/charts/series.rb +57 -0
  61. data/lib/goldendocx/charts/value_axis.rb +20 -0
  62. data/lib/goldendocx/charts.rb +26 -0
  63. data/lib/goldendocx/components/bar_chart.rb +17 -0
  64. data/lib/goldendocx/components/chart.rb +55 -0
  65. data/lib/goldendocx/components/column_chart.rb +17 -0
  66. data/lib/goldendocx/components/doughnut_chart.rb +17 -0
  67. data/lib/goldendocx/components/image.rb +77 -0
  68. data/lib/goldendocx/components/line_chart.rb +17 -0
  69. data/lib/goldendocx/components/paragraph.rb +23 -0
  70. data/lib/goldendocx/components/properties/align_property.rb +16 -0
  71. data/lib/goldendocx/components/properties/bold_property.rb +16 -0
  72. data/lib/goldendocx/components/properties/color_property.rb +16 -0
  73. data/lib/goldendocx/components/properties/drawing.rb +16 -0
  74. data/lib/goldendocx/components/properties/extents_property.rb +17 -0
  75. data/lib/goldendocx/components/properties/graphic_data_property.rb +17 -0
  76. data/lib/goldendocx/components/properties/graphic_frame_locks_property.rb +18 -0
  77. data/lib/goldendocx/components/properties/graphic_frame_property.rb +16 -0
  78. data/lib/goldendocx/components/properties/graphic_property.rb +16 -0
  79. data/lib/goldendocx/components/properties/inline.rb +20 -0
  80. data/lib/goldendocx/components/properties/non_visual_property.rb +17 -0
  81. data/lib/goldendocx/components/properties/padding_property.rb +19 -0
  82. data/lib/goldendocx/components/properties/property.rb +17 -0
  83. data/lib/goldendocx/components/properties/run.rb +20 -0
  84. data/lib/goldendocx/components/properties/run_property.rb +17 -0
  85. data/lib/goldendocx/components/properties/style_property.rb +16 -0
  86. data/lib/goldendocx/components/properties/textual.rb +16 -0
  87. data/lib/goldendocx/components/properties.rb +12 -0
  88. data/lib/goldendocx/components/table.rb +44 -0
  89. data/lib/goldendocx/components/text.rb +35 -0
  90. data/lib/goldendocx/components.rb +16 -0
  91. data/lib/goldendocx/configuration.rb +18 -0
  92. data/lib/goldendocx/content_types/default.rb +22 -0
  93. data/lib/goldendocx/content_types/override.rb +22 -0
  94. data/lib/goldendocx/document.rb +51 -0
  95. data/lib/goldendocx/documents/body.rb +90 -0
  96. data/lib/goldendocx/documents/document.rb +29 -0
  97. data/lib/goldendocx/documents/element.rb +23 -0
  98. data/lib/goldendocx/documents/relationship.rb +17 -0
  99. data/lib/goldendocx/documents/relationships.rb +39 -0
  100. data/lib/goldendocx/documents/style.rb +21 -0
  101. data/lib/goldendocx/documents/styles.rb +74 -0
  102. data/lib/goldendocx/documents/unparsed_style.rb +17 -0
  103. data/lib/goldendocx/documents.rb +10 -0
  104. data/lib/goldendocx/docx.rb +108 -0
  105. data/lib/goldendocx/element.rb +192 -0
  106. data/lib/goldendocx/images/picture.rb +41 -0
  107. data/lib/goldendocx/images/properties/blip_property.rb +16 -0
  108. data/lib/goldendocx/images/properties/drawing_property.rb +14 -0
  109. data/lib/goldendocx/images/properties/extents_property.rb +17 -0
  110. data/lib/goldendocx/images/properties/fill_rectangle_property.rb +14 -0
  111. data/lib/goldendocx/images/properties/image_data_property.rb +17 -0
  112. data/lib/goldendocx/images/properties/non_visual_drawing_property.rb +17 -0
  113. data/lib/goldendocx/images/properties/non_visual_picture_property.rb +17 -0
  114. data/lib/goldendocx/images/properties/picture_fill_property.rb +17 -0
  115. data/lib/goldendocx/images/properties/picture_shape_property.rb +16 -0
  116. data/lib/goldendocx/images/properties/shape_property.rb +30 -0
  117. data/lib/goldendocx/images/properties/stretch_property.rb +17 -0
  118. data/lib/goldendocx/images/properties/transform_property.rb +16 -0
  119. data/lib/goldendocx/images/properties.rb +12 -0
  120. data/lib/goldendocx/images/shape.rb +32 -0
  121. data/lib/goldendocx/images.rb +12 -0
  122. data/lib/goldendocx/parts/content_types.rb +63 -0
  123. data/lib/goldendocx/parts/documents.rb +103 -0
  124. data/lib/goldendocx/parts/media.rb +43 -0
  125. data/lib/goldendocx/parts.rb +10 -0
  126. data/lib/goldendocx/tables/cell.rb +33 -0
  127. data/lib/goldendocx/tables/header_cell.rb +16 -0
  128. data/lib/goldendocx/tables/header_row.rb +14 -0
  129. data/lib/goldendocx/tables/image_cell.rb +23 -0
  130. data/lib/goldendocx/tables/properties/cell_property.rb +19 -0
  131. data/lib/goldendocx/tables/properties/cell_width_property.rb +17 -0
  132. data/lib/goldendocx/tables/properties/grid_column_property.rb +16 -0
  133. data/lib/goldendocx/tables/properties/grid_property.rb +16 -0
  134. data/lib/goldendocx/tables/properties/grid_span_property.rb +16 -0
  135. data/lib/goldendocx/tables/properties/header_row_property.rb +14 -0
  136. data/lib/goldendocx/tables/properties/property.rb +17 -0
  137. data/lib/goldendocx/tables/properties/row_height_property.rb +17 -0
  138. data/lib/goldendocx/tables/properties/row_property.rb +16 -0
  139. data/lib/goldendocx/tables/properties/shading_property.rb +18 -0
  140. data/lib/goldendocx/tables/properties/style_property.rb +16 -0
  141. data/lib/goldendocx/tables/properties/vertical_align_property.rb +16 -0
  142. data/lib/goldendocx/tables/properties/width_property.rb +17 -0
  143. data/lib/goldendocx/tables/properties.rb +12 -0
  144. data/lib/goldendocx/tables/row.rb +28 -0
  145. data/lib/goldendocx/tables.rb +19 -0
  146. data/lib/goldendocx/units.rb +11 -0
  147. data/lib/goldendocx/version.rb +5 -0
  148. data/lib/goldendocx/xml_serializers/nokogiri.rb +66 -0
  149. data/lib/goldendocx/xml_serializers/ox.rb +63 -0
  150. data/lib/goldendocx.rb +72 -0
  151. data/sig/goldendocx.rbs +4 -0
  152. 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,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Goldendocx
4
+ module Documents
5
+ class UnparsedStyle
6
+ attr_reader :node
7
+
8
+ def initialize(node)
9
+ @node = node
10
+ end
11
+
12
+ def to_element(**_context)
13
+ @node
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Goldendocx
4
+ module Documents
5
+ end
6
+ end
7
+
8
+ Dir.glob(File.join(File.dirname(__FILE__), 'documents', '*.rb').to_s).sort.each do |file|
9
+ require file
10
+ 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,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Goldendocx
4
+ module Images
5
+ module Properties
6
+ class DrawingProperty
7
+ include Goldendocx::Element
8
+
9
+ namespace :pic
10
+ tag :cNvPicPr
11
+ end
12
+ end
13
+ end
14
+ 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,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Goldendocx
4
+ module Images
5
+ module Properties
6
+ class FillRectangleProperty
7
+ include Goldendocx::Element
8
+
9
+ namespace :a
10
+ tag :fillRect
11
+ end
12
+ end
13
+ end
14
+ 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