goldendocx 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
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