goldendocx 0.2.2 → 0.2.3

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 (61) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +4 -0
  3. data/CHANGELOG.md +8 -2
  4. data/Gemfile.lock +3 -1
  5. data/README.md +10 -2
  6. data/Rakefile +14 -3
  7. data/demo/templates/generate_codes.rb +10 -0
  8. data/demo/templates/xml_to_class.rb +91 -0
  9. data/demo/texts/append_plain_text.rb +1 -1
  10. data/demo/texts/append_styled_text.rb +1 -2
  11. data/demo/texts/create_text.rb +14 -0
  12. data/lib/extensions/active_support_extensions.rb +16 -0
  13. data/lib/extensions/nokogiri_extensions.rb +41 -0
  14. data/lib/extensions/ox_extensions.rb +35 -0
  15. data/lib/extensions/xml_serialize_extensions.rb +45 -0
  16. data/lib/goldendocx/components/properties/font_property.rb +19 -0
  17. data/lib/goldendocx/components/properties/language_property.rb +18 -0
  18. data/lib/goldendocx/components/properties/run_property.rb +2 -0
  19. data/lib/goldendocx/content_types/default.rb +2 -6
  20. data/lib/goldendocx/content_types/override.rb +2 -6
  21. data/lib/goldendocx/document.rb +9 -28
  22. data/lib/goldendocx/documents/body.rb +20 -11
  23. data/lib/goldendocx/documents/document.rb +2 -4
  24. data/lib/goldendocx/documents/latent_styles.rb +12 -0
  25. data/lib/goldendocx/documents/properties/default_style_property.rb +17 -0
  26. data/lib/goldendocx/documents/properties/page_margin_property.rb +37 -0
  27. data/lib/goldendocx/documents/properties/page_size_property.rb +17 -0
  28. data/lib/goldendocx/documents/properties/paragraph_default_style_property.rb +16 -0
  29. data/lib/goldendocx/documents/properties/run_default_style_property.rb +22 -0
  30. data/lib/goldendocx/documents/properties/section_property.rb +17 -0
  31. data/lib/goldendocx/documents/properties/style_name_property.rb +16 -0
  32. data/lib/goldendocx/documents/properties.rb +12 -0
  33. data/lib/goldendocx/documents/settings.rb +23 -0
  34. data/lib/goldendocx/documents/style.rb +10 -10
  35. data/lib/goldendocx/documents/styles.rb +9 -33
  36. data/lib/goldendocx/docx.rb +55 -12
  37. data/lib/goldendocx/element.rb +33 -140
  38. data/lib/goldendocx/has_associations.rb +52 -0
  39. data/lib/goldendocx/has_attributes.rb +67 -0
  40. data/lib/goldendocx/has_children.rb +116 -0
  41. data/lib/goldendocx/{documents → models}/relationship.rb +1 -1
  42. data/lib/goldendocx/{documents → models}/relationships.rb +4 -12
  43. data/lib/goldendocx/models.rb +10 -0
  44. data/lib/goldendocx/parts/app.rb +46 -0
  45. data/lib/goldendocx/parts/content_types.rb +16 -30
  46. data/lib/goldendocx/parts/core.rb +46 -0
  47. data/lib/goldendocx/parts/documents.rb +26 -13
  48. data/lib/goldendocx/parts/properties/created_at_property.rb +17 -0
  49. data/lib/goldendocx/parts/properties/creator_property.rb +16 -0
  50. data/lib/goldendocx/parts/properties/revision_property.rb +16 -0
  51. data/lib/goldendocx/parts/properties/updated_at_property.rb +17 -0
  52. data/lib/goldendocx/parts/properties/updater_property.rb +16 -0
  53. data/lib/goldendocx/parts/properties.rb +12 -0
  54. data/lib/goldendocx/tables/row.rb +1 -1
  55. data/lib/goldendocx/version.rb +1 -1
  56. data/lib/goldendocx/xml_serializers/nokogiri.rb +30 -22
  57. data/lib/goldendocx/xml_serializers/ox.rb +10 -20
  58. data/lib/goldendocx.rb +14 -2
  59. metadata +51 -7
  60. data/lib/goldendocx/documents/element.rb +0 -23
  61. data/lib/goldendocx/documents/unparsed_style.rb +0 -17
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f1603ab8a5538d27e48b351b381f8859c92fb9e42169df8cbcc6104545803c2b
4
- data.tar.gz: 9bc30497d4a1f96da15f8190d9edb42857f2ec6876550ebb47415f3ed5e67caa
3
+ metadata.gz: ec01d96d925886ed23aa79de96bfcc71fd8c0cb0c151239c7696536095b7c8c4
4
+ data.tar.gz: e72d2a380906b12216d2e29ef2cb4ec94e9036860d9d5000a60313f8a95a8350
5
5
  SHA512:
6
- metadata.gz: b826c86f0013b2af7af58b047cdb5340cc912913ca78b0198ab9b506a8614a173b2d1a53f42d928da6f277f21a6312895175687a49e79e2cf63658acace1ef4a
7
- data.tar.gz: cb4198c911418e3579df98019d87709a009aed9bd595b2889602e595a32d53b2a333561cd8d43dde67f40a55b1ebd6552e0921a184308417f4ce8270a215cd0f
6
+ metadata.gz: c53baede5b94336cbf2b3461183d3301114842d3bea12957655f86118d9fa9050f7f78ab2ed072720bcd0f43c126b61a8ea59cdf78b28cb7fd3282f676937860
7
+ data.tar.gz: 576eca3f0caedb097062afb1952ee05ac39786848498cc9de1ac55359a25131320fd2d93a0df3e75ab992419b98bef1a4831e7d4bbb2e34a0fcbe540d69fa29b
data/.rubocop.yml CHANGED
@@ -6,6 +6,10 @@ AllCops:
6
6
  NewCops: enable
7
7
  TargetRubyVersion: 2.7
8
8
  SuggestExtensions: false
9
+ Exclude:
10
+ - 'tmp/**/*'
11
+ - 'demo/templates/xml_to_class.rb'
12
+
9
13
 
10
14
  Metrics/AbcSize:
11
15
  CountRepeatedAttributes: false
data/CHANGELOG.md CHANGED
@@ -30,7 +30,7 @@ Mostly refactoring
30
30
  - Introduce `ActiveSupport` to make coding easier
31
31
  - Clean irrelevant demos
32
32
 
33
- ## [0.2.2] - 2023-03-31(WIP)
33
+ ## [0.2.2] - 2023-03-31
34
34
 
35
35
  ### Features
36
36
 
@@ -40,4 +40,10 @@ Mostly refactoring
40
40
  ### Fixes
41
41
 
42
42
  - Fix create charts issues
43
- - Fix Nokogiri XML serializer compatible issues
43
+ - Fix Nokogiri XML serializer compatible issues
44
+
45
+ ## [0.2.3] - 2023-04-07
46
+
47
+ ### Features
48
+
49
+ - Support create new MS Word docx file without template
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- goldendocx (0.2.2)
4
+ goldendocx (0.2.3)
5
5
  activesupport (~> 7.0)
6
6
  nokogiri (~> 1.14)
7
7
  ox (~> 2.14)
@@ -78,6 +78,7 @@ GEM
78
78
  simplecov-html (0.12.3)
79
79
  simplecov-lcov (0.8.0)
80
80
  simplecov_json_formatter (0.1.4)
81
+ timecop (0.9.6)
81
82
  tzinfo (2.0.6)
82
83
  concurrent-ruby (~> 1.0)
83
84
  unicode-display_width (2.2.0)
@@ -96,6 +97,7 @@ DEPENDENCIES
96
97
  rubocop-rspec (~> 2.19)
97
98
  simplecov (~> 0.22.0)
98
99
  simplecov-lcov (~> 0.8.0)
100
+ timecop (~> 0.9.6)
99
101
 
100
102
  BUNDLED WITH
101
103
  2.3.23
data/README.md CHANGED
@@ -1,5 +1,8 @@
1
1
  # The Ruby API for Microsoft Word
2
2
 
3
+ [![Gem Version](https://badge.fury.io/rb/goldendocx.svg)](https://badge.fury.io/rb/goldendocx)
4
+ [![Coverage Status](https://coveralls.io/repos/github/SheldonLeo/goldendocx/badge.svg)](https://coveralls.io/github/SheldonLeo/goldendocx)
5
+
3
6
  Ruby APIs for manipulating Microsoft Word based upon OOXML standards.
4
7
 
5
8
  ## Installation
@@ -23,6 +26,7 @@ If bundler is not being used to manage dependencies, install the gem by executin
23
26
  Support both `ox` and `nokogiri` as XML serializer, and `ox` as default.
24
27
 
25
28
  You can customize with configuration
29
+
26
30
  ```ruby
27
31
  Goldendocx.configure do |config|
28
32
  config.xml_serializer = :nokogiri
@@ -30,9 +34,13 @@ end
30
34
  ```
31
35
 
32
36
  ### Compose MS Word
33
- - Read MS Word file and write to another path
37
+
38
+ - Create new MS Word file or read exists file and write to another path
34
39
  ```ruby
40
+ docx = Goldendocx::Docx.new
35
41
  docx = Goldendocx::Docx.new(docx_file_path)
42
+ docx.read_from(docx_file_path)
43
+
36
44
  docx.write_to(new_file_path)
37
45
  ```
38
46
  - Create texts to MS Word
@@ -71,6 +79,6 @@ end
71
79
  values = [13, 12, 9, 9, 8, 7, 7, 6, 5, 3]
72
80
  chart.add_series('地域分布详情数据', categories, values)
73
81
  ```
74
-
82
+
75
83
  More demos view at [Demos](demo/)
76
84
 
data/Rakefile CHANGED
@@ -4,7 +4,18 @@ require 'bundler/gem_tasks'
4
4
  require 'rspec/core/rake_task'
5
5
  require 'rubocop/rake_task'
6
6
 
7
- RSpec::Core::RakeTask.new(:spec)
8
- RuboCop::RakeTask.new
7
+ RSpec::Core::RakeTask.new(:ox_compatible_spec) do |task|
8
+ ENV['XML_SERIALIZER'] = 'ox'
9
+ task.failure_message = 'Failed with ox xml serializer compatible'
10
+ end
9
11
 
10
- task default: %i[rubocop spec]
12
+ RSpec::Core::RakeTask.new(:nokogiri_compatible_spec) do |task|
13
+ ENV['XML_SERIALIZER'] = 'nokogiri'
14
+ task.failure_message = 'Failed with nokogiri xml serializer compatible'
15
+ end
16
+
17
+ RuboCop::RakeTask.new(:rubocop) do |task|
18
+ task.options = ['-P']
19
+ end
20
+
21
+ task default: %i[rubocop ox_compatible_spec nokogiri_compatible_spec]
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'ox'
4
+ require_relative 'xml_to_class'
5
+
6
+ xml_fragment = File.read("#{Dir.pwd}/demo/templates/styles/reportTitle")
7
+ root_class = XmlToClass.new.parse(Ox.parse(xml_fragment))
8
+
9
+ root_class.write_rb('goldendocx/styles')
10
+ root_class.write_spec('goldendocx/styles')
@@ -0,0 +1,91 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'ox'
4
+ require 'fileutils'
5
+ require 'active_support/core_ext/string/inflections'
6
+
7
+ class XmlToClass
8
+ def parse(node)
9
+ @node = node
10
+ @namespace, @tag = parse_tag(@node.name)
11
+ @class_name = "#{@tag}Property".classify
12
+ parse_attributes
13
+ parse_children
14
+ self
15
+ end
16
+
17
+ def write_rb(dir)
18
+ dir_to_write = "#{Dir.pwd}/lib/#{dir}"
19
+ FileUtils.mkdir_p(dir_to_write)
20
+
21
+ File.open("#{dir_to_write}/#{@tag}.rb", 'w') do |f|
22
+ f.puts '# frozen_string_literal: true'
23
+ f.puts ''
24
+ f.puts "class Goldendocx::#{@class_name}"
25
+ f.puts ' include Goldendocx::Element'
26
+ f.puts ''
27
+ f.puts " namespace :#{@namespace}" if @namespace
28
+ f.puts " tag :#{@tag}"
29
+ f.puts ''
30
+ @attributes.each do |name, opt|
31
+ options = opt.map { |k, v| "#{k}: :#{v}" }.join(',')
32
+ f.puts " attribute :#{name.underscore}, #{options}"
33
+ end
34
+ f.puts ''
35
+ @children.group_by(&:to_s).each do |name, values|
36
+ method = values.size > 1 ? :embeds_many : :embeds_one
37
+ _, class_name = parse_tag(name)
38
+ f.puts " #{method} :#{class_name.underscore}, class_name: 'Goldendocx::#{class_name.classify}Property'"
39
+ end
40
+ f.puts 'end'
41
+ end
42
+
43
+ @subclasses.each { |c| c.write_rb("#{dir}/#{@tag}") }
44
+ end
45
+
46
+ def write_spec(dir)
47
+ dir_to_write = "#{Dir.pwd}/spec/#{dir}"
48
+ FileUtils.mkdir_p(dir_to_write)
49
+
50
+ File.open("#{dir_to_write}/#{@tag}_spec.rb", 'w') do |f|
51
+ f.puts '# frozen_string_literal: true'
52
+ f.puts ''
53
+ f.puts "describe Goldendocx::#{@class_name} do"
54
+ f.puts ' let(:property) { described_class.new }'
55
+ f.puts ''
56
+ f.puts " specify 'builds default #{@tag} property xml' do "
57
+ f.puts " expect(property.to_xml).to eq('<#{@namespace}:#{@tag}/>')"
58
+ f.puts ' end'
59
+ f.puts ''
60
+ f.puts " specify 'builds customized #{@tag} property xml' do"
61
+ f.puts ' property.attribute = :value '
62
+ f.puts " expect(property.to_xml).to eq('<#{@namespace}:#{@tag}/>') "
63
+ f.puts ' end '
64
+ f.puts 'end'
65
+ end
66
+
67
+ @subclasses.each { |c| c.write_spec("#{dir}/#{@tag}") }
68
+ end
69
+
70
+ def parse_tag(string)
71
+ string = string.to_s
72
+ string.include?(':') ? string.split(':') : [nil, string]
73
+ end
74
+
75
+ def parse_attributes
76
+ @attributes ||= {}
77
+ @node.attributes.each_key do |name|
78
+ ns, tg = parse_tag(name)
79
+ @attributes[tg] = { alias_name: tg, namespace: ns }.compact
80
+ end
81
+ end
82
+
83
+ def parse_children
84
+ @children = []
85
+ @subclasses = []
86
+ @node.nodes.each do |node|
87
+ @children << node.name.to_s
88
+ @subclasses << XmlToClass.new.parse(node)
89
+ end
90
+ end
91
+ end
@@ -3,7 +3,7 @@
3
3
  $LOAD_PATH.push "#{Dir.pwd}/lib"
4
4
  require 'goldendocx'
5
5
 
6
- docx = Goldendocx::Docx.new("#{Dir.pwd}/demo/templates/blankDocument.docx")
6
+ docx = Goldendocx::Docx.new.read_from("#{Dir.pwd}/demo/templates/blankDocument.docx")
7
7
 
8
8
  docx.create_text('Hello World!')
9
9
 
@@ -2,8 +2,7 @@
2
2
 
3
3
  $LOAD_PATH.push "#{Dir.pwd}/lib"
4
4
  require 'goldendocx'
5
-
6
- docx = Goldendocx::Docx.new("#{Dir.pwd}/demo/templates/blankDocument.docx")
5
+ docx = Goldendocx::Docx.new.read_from("#{Dir.pwd}/demo/templates/blankDocument.docx")
7
6
 
8
7
  # Register styles because default document without any style
9
8
  docx.add_style(File.read("#{Dir.pwd}/demo/templates/styles/reportTitle"))
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ $LOAD_PATH.push "#{Dir.pwd}/lib"
4
+ require 'goldendocx'
5
+
6
+ docx = Goldendocx::Docx.new
7
+
8
+ docx.create_text('Hello World!')
9
+ docx.create_text('Hello World!', align: :center, color: 'FF8533', bold: true)
10
+
11
+ filename = 'plainTextDocument.docx'
12
+ system "rm -f ~/Desktop/#{filename}" # -f so that we don't have an error if the file doesn't exist
13
+ docx.write_to File.expand_path("~/Desktop/#{filename}")
14
+ exec "open ~/Desktop/#{filename}"
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_support/concern'
4
+ require 'active_support/core_ext/array/access'
5
+ require 'active_support/core_ext/class/attribute'
6
+ require 'active_support/core_ext/class/subclasses'
7
+ require 'active_support/core_ext/hash/indifferent_access'
8
+ require 'active_support/core_ext/string/inflections'
9
+ require 'active_support/core_ext/string/conversions'
10
+
11
+ ActiveSupport::Inflector.inflections do |inflect|
12
+ inflect.uncountable 'extents', 'image_data', 'data', 'defaults', 'latentStyles'
13
+ inflect.irregular 'axis', 'axes'
14
+
15
+ inflect.uncountable 'values' # TODO: Find better names
16
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'nokogiri'
4
+
5
+ # FIXME: Temporarily here to provider syntactic sugar
6
+ module Nokogiri
7
+ module XML
8
+ class Document
9
+ def tag_name
10
+ root.tag_name
11
+ end
12
+ end
13
+
14
+ class Node
15
+ def <<(node_or_tags)
16
+ # FIXME: Add this line to transform element implicitly
17
+ node_or_tags = node_or_tags.public_send(:to_element, parent: self) if node_or_tags.respond_to?(:to_element)
18
+
19
+ add_child(node_or_tags)
20
+ self
21
+ end
22
+
23
+ def adapt?(klass)
24
+ adaptable_classes = [String, Integer, Time]
25
+ is_a?(Nokogiri::XML::Text) && adaptable_classes.include?(klass)
26
+ end
27
+
28
+ def tag_name
29
+ [namespace&.prefix, name].compact.join(':')
30
+ end
31
+
32
+ def unparsed_children
33
+ @unparsed_children ||= children.dup
34
+ end
35
+
36
+ def attributes_hash
37
+ attribute_nodes.reject { |node| node.tag_name == 'mc:Ignorable' }.to_h { |node| [node.tag_name, node.value] }
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'ox'
4
+
5
+ module Ox
6
+ class Document
7
+ def root
8
+ children.first
9
+ end
10
+ end
11
+
12
+ class Element
13
+ def <<(node)
14
+ # FIXME: Add this line to transform element implicitly
15
+ node = node.public_send(:to_element) if node.respond_to?(:to_element)
16
+
17
+ raise 'argument to << must be a String or Ox::Node.' unless node.is_a?(String) || node.is_a?(Node)
18
+
19
+ @nodes = [] if !instance_variable_defined?(:@nodes) || @nodes.nil?
20
+ @nodes << node
21
+ self
22
+ end
23
+
24
+ alias children nodes
25
+ alias tag_name name
26
+
27
+ def unparsed_children
28
+ @unparsed_children ||= children.dup
29
+ end
30
+
31
+ def attributes_hash
32
+ attributes.with_indifferent_access.reject { |k, _| k.to_s.start_with?('xmlns') || k.to_s == 'mc:Ignorable' }
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ class String
4
+ class << self
5
+ def adapt?(xml_node)
6
+ xml_node.is_a?(String) || xml_node.adapt?(String)
7
+ end
8
+
9
+ def read_from(xml_node)
10
+ xml_node.to_s
11
+ end
12
+ end
13
+ end
14
+
15
+ class Time
16
+ class << self
17
+ def adapt?(xml_node)
18
+ xml_node.is_a?(String) || xml_node.adapt?(Time)
19
+ end
20
+
21
+ def read_from(xml_node)
22
+ xml_node.to_s.to_time
23
+ end
24
+ end
25
+
26
+ def to_element(**_context)
27
+ strftime('%Y-%m-%dT%H:%M:%SZ')
28
+ end
29
+ end
30
+
31
+ class Integer
32
+ class << self
33
+ def adapt?(xml_node)
34
+ xml_node.is_a?(String) || xml_node.adapt?(Integer)
35
+ end
36
+
37
+ def read_from(xml_node)
38
+ xml_node.to_s.to_i
39
+ end
40
+ end
41
+
42
+ def to_element(**_context)
43
+ to_s
44
+ end
45
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Goldendocx
4
+ module Components
5
+ module Properties
6
+ class FontProperty
7
+ include Goldendocx::Element
8
+
9
+ namespace :w
10
+ tag :rFonts
11
+
12
+ attribute :ascii, namespace: :w, default: 'Times New Roman'
13
+ attribute :east_asia, alias_name: :eastAsia, namespace: :w, default: '宋体'
14
+ attribute :high_ansi, alias_name: :hAnsi, namespace: :w, default: 'Times New Roman'
15
+ attribute :complex, alias_name: :cs, namespace: :w, default: 'Times New Roman'
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Goldendocx
4
+ module Components
5
+ module Properties
6
+ class LanguageProperty
7
+ include Goldendocx::Element
8
+
9
+ namespace :w
10
+ tag :lang
11
+
12
+ attribute :complex, alias_name: :bidi, namespace: :w, default: 'ar-SA'
13
+ attribute :east_asia, alias_name: :eastAsia, namespace: :w, default: 'zh-CN'
14
+ attribute :latin, alias_name: :val, namespace: :w, default: 'en-US'
15
+ end
16
+ end
17
+ end
18
+ end
@@ -11,6 +11,8 @@ module Goldendocx
11
11
 
12
12
  embeds_one :color, class_name: 'Goldendocx::Components::Properties::ColorProperty', auto_build: false
13
13
  embeds_one :bold, class_name: 'Goldendocx::Components::Properties::BoldProperty', auto_build: false
14
+ embeds_one :language, class_name: 'Goldendocx::Components::Properties::LanguageProperty', auto_build: false
15
+ embeds_one :font, class_name: 'Goldendocx::Components::Properties::FontProperty', auto_build: false
14
16
  end
15
17
  end
16
18
  end
@@ -6,13 +6,9 @@ module Goldendocx
6
6
  include Goldendocx::Element
7
7
 
8
8
  tag :Default
9
- attribute :extension, alias_name: :Extension, readonly: true
10
- attribute :content_type, alias_name: :ContentType, readonly: true
11
9
 
12
- def initialize(extension, content_type)
13
- @extension = extension
14
- @content_type = content_type
15
- end
10
+ attribute :extension, alias_name: :Extension
11
+ attribute :content_type, alias_name: :ContentType
16
12
 
17
13
  def ==(other)
18
14
  extension == other.extension && content_type == other.content_type
@@ -6,13 +6,9 @@ module Goldendocx
6
6
  include Goldendocx::Element
7
7
 
8
8
  tag :Override
9
- attribute :part_name, alias_name: :PartName, readonly: true
10
- attribute :content_type, alias_name: :ContentType, readonly: true
11
9
 
12
- def initialize(part_name, content_type)
13
- @part_name = part_name
14
- @content_type = content_type
15
- end
10
+ attribute :part_name, alias_name: :PartName
11
+ attribute :content_type, alias_name: :ContentType
16
12
 
17
13
  def ==(other)
18
14
  part_name == other.part_name && content_type == other.content_type
@@ -3,49 +3,30 @@
3
3
  # Just to mark a element as a root document node
4
4
  module Goldendocx
5
5
  module Document
6
- def self.included(base)
7
- base.include(Goldendocx::Element)
8
- base.extend(ClassMethods)
6
+ extend ActiveSupport::Concern
7
+ include Goldendocx::Element
8
+
9
+ included do
10
+ class_attribute :concerned_namespaces, default: []
11
+ class_attribute :ignorable_namespaces, default: []
9
12
  end
10
13
 
11
- module ClassMethods
14
+ class_methods do
12
15
  def concern_namespaces(*namespaces)
13
16
  namespaces.each do |namespace|
14
17
  concerned_namespaces << namespace unless concerned_namespaces.include?(namespace)
15
18
  end
16
19
  end
17
20
 
18
- def concerned_namespaces
19
- @concerned_namespaces ||= []
20
- end
21
-
22
21
  def ignore_namespaces(*namespaces)
23
22
  namespaces.each do |namespace|
24
23
  ignorable_namespaces << namespace.to_sym unless ignorable_namespaces.include?(namespace)
25
24
  end
26
25
  end
27
-
28
- def ignorable_namespaces
29
- @ignorable_namespaces ||= []
30
- end
31
- end
32
-
33
- def concerned_namespaces
34
- self.class.concerning_ancestors.flat_map(&:concerned_namespaces)
35
- end
36
-
37
- def ignorable_namespaces
38
- self.class.concerning_ancestors.flat_map(&:ignorable_namespaces)
39
26
  end
40
27
 
41
- def to_document_xml
42
- Goldendocx.xml_serializer.build_document_xml(root_tag, concerned_namespaces, ignorable_namespaces) do |xml|
43
- attributes.each { |name, value| xml[name] = value }
44
-
45
- yield(xml) if block_given?
46
-
47
- children.each { |child| xml << child }
48
- end
28
+ def to_document_xml(&block)
29
+ Goldendocx.xml_serializer.build_document_xml(tag_name, concerned_namespaces, ignorable_namespaces) { |xml| build_element(xml, &block) }
49
30
  end
50
31
  end
51
32
  end
@@ -7,33 +7,42 @@ module Goldendocx
7
7
 
8
8
  XML_PATH = 'word/document.xml'
9
9
 
10
- attr_reader :components, :properties, :charts
10
+ attr_reader :components, :charts
11
11
 
12
12
  namespace :w
13
13
  tag :body
14
14
 
15
+ # TODO: Try to distinguish these paragraphs
15
16
  embeds_many :texts, class_name: 'Goldendocx::Components::Text'
16
17
  embeds_many :images, class_name: 'Goldendocx::Components::Image'
18
+
17
19
  embeds_many :tables, class_name: 'Goldendocx::Components::Table'
18
20
 
21
+ embeds_one :section_property, class_name: 'Goldendocx::Documents::Properties::SectionProperty', auto_build: true
22
+
23
+ class << self
24
+ def read_from(xml_node)
25
+ document = super(xml_node)
26
+
27
+ component_tags = %w[w:p w:tbl]
28
+ xml_node.children.map do |node|
29
+ document.components << node if component_tags.include?(node.tag_name)
30
+ end
31
+
32
+ document
33
+ end
34
+ end
35
+
19
36
  def initialize
20
37
  @components = []
21
38
  @charts = []
22
39
  end
23
40
 
24
- def read_from(docx_file)
25
- Goldendocx.xml_serializer.parse(docx_file.read(XML_PATH), %w[w:document w:body *]).map do |node|
26
- element = Goldendocx::Documents::Element.new(node)
27
- @components << element if element.component?
28
- @properties = element if element.properties?
29
- end
30
- end
31
-
32
41
  # FIXME: Override for children not in correctly order
33
42
  def to_element(**_context)
34
- Goldendocx.xml_serializer.build_element(root_tag) do |xml|
43
+ Goldendocx.xml_serializer.build_element(tag_name) do |xml|
35
44
  components.each { |component| xml << component }
36
- xml << properties if properties
45
+ xml << section_property if section_property
37
46
 
38
47
  yield(xml) if block_given?
39
48
  end
@@ -5,7 +5,9 @@ module Goldendocx
5
5
  class Document
6
6
  include Goldendocx::Document
7
7
 
8
+ TYPE = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument'
8
9
  XML_PATH = 'word/document.xml'
10
+ CONTENT_TYPE = 'application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml'
9
11
 
10
12
  namespace :w
11
13
  tag :document
@@ -16,10 +18,6 @@ module Goldendocx
16
18
 
17
19
  embeds_one :body, class_name: 'Goldendocx::Documents::Body', auto_build: true
18
20
 
19
- def read_from(docx_file)
20
- body.read_from(docx_file)
21
- end
22
-
23
21
  def write_to(zos)
24
22
  zos.put_next_entry XML_PATH
25
23
  zos.write to_document_xml
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Goldendocx
4
+ module Documents
5
+ class LatentStyles
6
+ include Goldendocx::Element
7
+
8
+ namespace :w
9
+ tag :latentStyles
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Goldendocx
4
+ module Documents
5
+ module Properties
6
+ class DefaultStyleProperty
7
+ include Goldendocx::Element
8
+
9
+ namespace :w
10
+ tag :docDefaults
11
+
12
+ embeds_one :run_default, class_name: 'Goldendocx::Documents::Properties::RunDefaultStyleProperty', auto_build: true
13
+ embeds_one :paragraph_default, class_name: 'Goldendocx::Documents::Properties::ParagraphDefaultStyleProperty', auto_build: true
14
+ end
15
+ end
16
+ end
17
+ end