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.
- checksums.yaml +4 -4
- data/.rubocop.yml +4 -0
- data/CHANGELOG.md +8 -2
- data/Gemfile.lock +3 -1
- data/README.md +10 -2
- data/Rakefile +14 -3
- data/demo/templates/generate_codes.rb +10 -0
- data/demo/templates/xml_to_class.rb +91 -0
- data/demo/texts/append_plain_text.rb +1 -1
- data/demo/texts/append_styled_text.rb +1 -2
- data/demo/texts/create_text.rb +14 -0
- data/lib/extensions/active_support_extensions.rb +16 -0
- data/lib/extensions/nokogiri_extensions.rb +41 -0
- data/lib/extensions/ox_extensions.rb +35 -0
- data/lib/extensions/xml_serialize_extensions.rb +45 -0
- data/lib/goldendocx/components/properties/font_property.rb +19 -0
- data/lib/goldendocx/components/properties/language_property.rb +18 -0
- data/lib/goldendocx/components/properties/run_property.rb +2 -0
- data/lib/goldendocx/content_types/default.rb +2 -6
- data/lib/goldendocx/content_types/override.rb +2 -6
- data/lib/goldendocx/document.rb +9 -28
- data/lib/goldendocx/documents/body.rb +20 -11
- data/lib/goldendocx/documents/document.rb +2 -4
- data/lib/goldendocx/documents/latent_styles.rb +12 -0
- data/lib/goldendocx/documents/properties/default_style_property.rb +17 -0
- data/lib/goldendocx/documents/properties/page_margin_property.rb +37 -0
- data/lib/goldendocx/documents/properties/page_size_property.rb +17 -0
- data/lib/goldendocx/documents/properties/paragraph_default_style_property.rb +16 -0
- data/lib/goldendocx/documents/properties/run_default_style_property.rb +22 -0
- data/lib/goldendocx/documents/properties/section_property.rb +17 -0
- data/lib/goldendocx/documents/properties/style_name_property.rb +16 -0
- data/lib/goldendocx/documents/properties.rb +12 -0
- data/lib/goldendocx/documents/settings.rb +23 -0
- data/lib/goldendocx/documents/style.rb +10 -10
- data/lib/goldendocx/documents/styles.rb +9 -33
- data/lib/goldendocx/docx.rb +55 -12
- data/lib/goldendocx/element.rb +33 -140
- data/lib/goldendocx/has_associations.rb +52 -0
- data/lib/goldendocx/has_attributes.rb +67 -0
- data/lib/goldendocx/has_children.rb +116 -0
- data/lib/goldendocx/{documents → models}/relationship.rb +1 -1
- data/lib/goldendocx/{documents → models}/relationships.rb +4 -12
- data/lib/goldendocx/models.rb +10 -0
- data/lib/goldendocx/parts/app.rb +46 -0
- data/lib/goldendocx/parts/content_types.rb +16 -30
- data/lib/goldendocx/parts/core.rb +46 -0
- data/lib/goldendocx/parts/documents.rb +26 -13
- data/lib/goldendocx/parts/properties/created_at_property.rb +17 -0
- data/lib/goldendocx/parts/properties/creator_property.rb +16 -0
- data/lib/goldendocx/parts/properties/revision_property.rb +16 -0
- data/lib/goldendocx/parts/properties/updated_at_property.rb +17 -0
- data/lib/goldendocx/parts/properties/updater_property.rb +16 -0
- data/lib/goldendocx/parts/properties.rb +12 -0
- data/lib/goldendocx/tables/row.rb +1 -1
- data/lib/goldendocx/version.rb +1 -1
- data/lib/goldendocx/xml_serializers/nokogiri.rb +30 -22
- data/lib/goldendocx/xml_serializers/ox.rb +10 -20
- data/lib/goldendocx.rb +14 -2
- metadata +51 -7
- data/lib/goldendocx/documents/element.rb +0 -23
- data/lib/goldendocx/documents/unparsed_style.rb +0 -17
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ec01d96d925886ed23aa79de96bfcc71fd8c0cb0c151239c7696536095b7c8c4
|
4
|
+
data.tar.gz: e72d2a380906b12216d2e29ef2cb4ec94e9036860d9d5000a60313f8a95a8350
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c53baede5b94336cbf2b3461183d3301114842d3bea12957655f86118d9fa9050f7f78ab2ed072720bcd0f43c126b61a8ea59cdf78b28cb7fd3282f676937860
|
7
|
+
data.tar.gz: 576eca3f0caedb097062afb1952ee05ac39786848498cc9de1ac55359a25131320fd2d93a0df3e75ab992419b98bef1a4831e7d4bbb2e34a0fcbe540d69fa29b
|
data/.rubocop.yml
CHANGED
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
|
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.
|
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
|
+
[](https://badge.fury.io/rb/goldendocx)
|
4
|
+
[](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
|
-
|
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(:
|
8
|
-
|
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
|
-
|
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
|
@@ -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
|
-
|
13
|
-
|
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
|
-
|
13
|
-
|
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
|
data/lib/goldendocx/document.rb
CHANGED
@@ -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
|
-
|
7
|
-
|
8
|
-
|
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
|
-
|
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(
|
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, :
|
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(
|
43
|
+
Goldendocx.xml_serializer.build_element(tag_name) do |xml|
|
35
44
|
components.each { |component| xml << component }
|
36
|
-
xml <<
|
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,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
|