docx_manipulator 0.0.4 → 0.0.5
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.
- data/docx_manipulator.gemspec +1 -0
- data/lib/docx_manipulator/content.rb +27 -0
- data/lib/docx_manipulator/relationships.rb +62 -0
- data/lib/docx_manipulator/version.rb +1 -1
- data/lib/docx_manipulator.rb +15 -60
- data/spec/docx_manipulator_spec.rb +60 -55
- metadata +15 -2
data/docx_manipulator.gemspec
CHANGED
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'nokogiri'
|
2
|
+
|
3
|
+
class DocxManipulator
|
4
|
+
class Content
|
5
|
+
def set(new_content, options = {})
|
6
|
+
@new_content = if new_content.kind_of?(File)
|
7
|
+
new_content.read
|
8
|
+
else
|
9
|
+
new_content
|
10
|
+
end
|
11
|
+
if options.include?(:xslt)
|
12
|
+
xslt = Nokogiri::XSLT.parse(options[:xslt])
|
13
|
+
data = Nokogiri::XML.parse(@new_content)
|
14
|
+
@new_content = xslt.transform(data).to_s
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def writes_to_files
|
19
|
+
['word/document.xml']
|
20
|
+
end
|
21
|
+
|
22
|
+
def process(output)
|
23
|
+
output.put_next_entry 'word/document.xml'
|
24
|
+
output.write @new_content
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'i18n'
|
2
|
+
require 'nokogiri'
|
3
|
+
|
4
|
+
class DocxManipulator
|
5
|
+
class Relationships
|
6
|
+
def initialize(source)
|
7
|
+
@relationships = read_relationships(source)
|
8
|
+
@images = []
|
9
|
+
@binary_images = {}
|
10
|
+
end
|
11
|
+
|
12
|
+
def read_relationships(path)
|
13
|
+
content = ''
|
14
|
+
Zip::ZipFile.open(path) do |file|
|
15
|
+
content = file.read('word/_rels/document.xml.rels')
|
16
|
+
end
|
17
|
+
Nokogiri::XML.parse(content)
|
18
|
+
end
|
19
|
+
private :read_relationships
|
20
|
+
|
21
|
+
def add_image(id, path)
|
22
|
+
@images << path
|
23
|
+
add_node(id, I18n.transliterate(File.basename(path)))
|
24
|
+
end
|
25
|
+
|
26
|
+
def add_binary_image(id, name, data)
|
27
|
+
name = I18n.transliterate(name)
|
28
|
+
@binary_images[name] = data
|
29
|
+
add_node(id, name)
|
30
|
+
end
|
31
|
+
|
32
|
+
def add_node(id, name)
|
33
|
+
image_node = Nokogiri::XML::Node.new('Relationship', @relationships)
|
34
|
+
image_node['Id'] = id
|
35
|
+
image_node['Type'] = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/image'
|
36
|
+
image_node['Target'] = "media/#{name}"
|
37
|
+
@relationships.root << image_node
|
38
|
+
end
|
39
|
+
private :add_node
|
40
|
+
|
41
|
+
def writes_to_files
|
42
|
+
['word/_rels/document.xml.rels']
|
43
|
+
end
|
44
|
+
|
45
|
+
def process(output)
|
46
|
+
output.put_next_entry 'word/_rels/document.xml.rels'
|
47
|
+
output.write @relationships.to_s
|
48
|
+
|
49
|
+
@images.each do |path|
|
50
|
+
output.put_next_entry "word/media/#{I18n.transliterate(File.basename(path))}"
|
51
|
+
File.open(path) do |file|
|
52
|
+
IO.copy_stream file, output
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
@binary_images.each do |name, data|
|
57
|
+
output.put_next_entry "word/media/#{I18n.transliterate(name)}"
|
58
|
+
output.write data
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
data/lib/docx_manipulator.rb
CHANGED
@@ -1,91 +1,46 @@
|
|
1
1
|
require 'docx_manipulator/version'
|
2
|
-
require '
|
2
|
+
require 'docx_manipulator/content'
|
3
|
+
require 'docx_manipulator/relationships'
|
4
|
+
|
3
5
|
require 'zip/zip'
|
4
6
|
|
5
7
|
class DocxManipulator
|
6
8
|
|
7
|
-
attr_reader :source, :target
|
9
|
+
attr_reader :source, :target
|
8
10
|
|
9
11
|
def initialize(source, target)
|
10
12
|
@source = source
|
11
13
|
@target = target
|
12
|
-
@new_relationships = source_relationships
|
13
|
-
@images = {}
|
14
|
-
@binary_images = {}
|
15
|
-
end
|
16
|
-
|
17
|
-
def source_content
|
18
|
-
content = ''
|
19
|
-
Zip::ZipFile.open(source) do |file|
|
20
|
-
content = file.read('word/document.xml')
|
21
|
-
end
|
22
|
-
content
|
23
|
-
end
|
24
14
|
|
25
|
-
|
26
|
-
|
27
|
-
Zip::ZipFile.open(source) do |file|
|
28
|
-
content = file.read('word/_rels/document.xml.rels')
|
29
|
-
end
|
30
|
-
Nokogiri::XML.parse(content)
|
15
|
+
@content = Content.new
|
16
|
+
@relationships = Relationships.new(source)
|
31
17
|
end
|
32
18
|
|
33
19
|
def content(new_content, options = {})
|
34
|
-
|
35
|
-
when File then new_content.read
|
36
|
-
else new_content
|
37
|
-
end
|
38
|
-
if options.include?(:xslt)
|
39
|
-
xslt = Nokogiri::XSLT.parse(options[:xslt])
|
40
|
-
data = Nokogiri::XML.parse(new_content_string)
|
41
|
-
@new_content = xslt.transform(data).to_s
|
42
|
-
else
|
43
|
-
@new_content = new_content_string
|
44
|
-
end
|
20
|
+
@content.set(new_content, options)
|
45
21
|
end
|
46
22
|
|
47
23
|
def add_image(id, path)
|
48
|
-
@
|
49
|
-
image_node = Nokogiri::XML::Node.new('Relationship', new_relationships)
|
50
|
-
image_node['Id'] = id
|
51
|
-
image_node['Type'] = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/image'
|
52
|
-
image_node['Target'] = "media/#{File.basename(path)}"
|
53
|
-
new_relationships.root << image_node
|
24
|
+
@relationships.add_image(id, path)
|
54
25
|
end
|
55
26
|
|
56
27
|
def add_binary_image(id, name, data)
|
57
|
-
@
|
58
|
-
image_node = Nokogiri::XML::Node.new('Relationship', new_relationships)
|
59
|
-
image_node['Id'] = id
|
60
|
-
image_node['Type'] = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/image'
|
61
|
-
image_node['Target'] = "media/#{name}"
|
62
|
-
new_relationships.root << image_node
|
28
|
+
@relationships.add_binary_image(id, name, data)
|
63
29
|
end
|
64
30
|
|
65
31
|
def process
|
32
|
+
files_to_be_written = @content.writes_to_files + @relationships.writes_to_files
|
33
|
+
|
66
34
|
Zip::ZipOutputStream.open(target) do |os|
|
67
35
|
Zip::ZipFile.foreach(source) do |entry|
|
68
|
-
|
69
|
-
|
70
|
-
os.write @new_content
|
71
|
-
elsif entry.name == 'word/_rels/document.xml.rels'
|
72
|
-
os.write new_relationships.to_s
|
73
|
-
elsif entry.file?
|
36
|
+
unless files_to_be_written.include?(entry.name)
|
37
|
+
os.put_next_entry entry.name
|
74
38
|
os.write entry.get_input_stream.read
|
75
39
|
end
|
76
40
|
end
|
77
41
|
|
78
|
-
@
|
79
|
-
|
80
|
-
File.open(path) do |file|
|
81
|
-
IO.copy_stream file, os
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
|
-
@binary_images.each do |name, data|
|
86
|
-
os.put_next_entry "word/media/#{name}"
|
87
|
-
os.write data
|
88
|
-
end
|
42
|
+
@content.process(os)
|
43
|
+
@relationships.process(os)
|
89
44
|
end
|
90
45
|
end
|
91
46
|
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
1
2
|
require 'docx_manipulator'
|
2
3
|
require 'zip/zip'
|
3
4
|
|
@@ -5,13 +6,24 @@ describe DocxManipulator do
|
|
5
6
|
|
6
7
|
subject { DocxManipulator.new('spec/files/movies.docx', 'spec/files/result.docx') }
|
7
8
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
after :each do
|
10
|
+
File.delete('spec/files/result.docx') if File.exist?('spec/files/result.docx')
|
11
|
+
end
|
12
|
+
|
13
|
+
it "generates the resulting document" do
|
14
|
+
subject.process
|
15
|
+
File.should exist('spec/files/result.docx')
|
12
16
|
end
|
13
17
|
|
14
|
-
|
18
|
+
context 'content' do
|
19
|
+
it "accepts a string" do
|
20
|
+
subject.content 'bla'
|
21
|
+
subject.process
|
22
|
+
Zip::ZipFile.open('spec/files/result.docx') do |file|
|
23
|
+
file.get_input_stream('word/document.xml').read.should == 'bla'
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
15
27
|
let(:xml_string) { <<-EOF
|
16
28
|
<?xml version="1.0" encoding="UTF-8"?>
|
17
29
|
<Movies>
|
@@ -31,82 +43,75 @@ EOF
|
|
31
43
|
|
32
44
|
it "transforms the data file with an xslt file" do
|
33
45
|
subject.content File.new('spec/files/data.xml'), :xslt => File.new('spec/files/document.xslt')
|
34
|
-
subject.
|
35
|
-
|
46
|
+
subject.process
|
47
|
+
Zip::ZipFile.open('spec/files/result.docx') do |file|
|
48
|
+
data = file.get_input_stream('word/document.xml').read
|
49
|
+
data.should =~ /<w:t>The Departed<\/w:t>/
|
50
|
+
data.should =~ /<w:t>The Pursuit of Happyness<\/w:t>/
|
51
|
+
end
|
36
52
|
end
|
37
53
|
|
38
54
|
it "transforms a string with an xslt file" do
|
39
55
|
subject.content xml_string, :xslt => File.new('spec/files/document.xslt')
|
40
|
-
subject.
|
41
|
-
|
56
|
+
subject.process
|
57
|
+
Zip::ZipFile.open('spec/files/result.docx') do |file|
|
58
|
+
data = file.get_input_stream('word/document.xml').read
|
59
|
+
data.should =~ /<w:t>The Departed<\/w:t>/
|
60
|
+
data.should =~ /<w:t>The Pursuit of Happyness<\/w:t>/
|
61
|
+
end
|
42
62
|
end
|
43
63
|
|
44
64
|
it "accepts a string" do
|
45
65
|
subject.content 'the new content'
|
46
|
-
subject.
|
66
|
+
subject.process
|
67
|
+
Zip::ZipFile.open('spec/files/result.docx') do |file|
|
68
|
+
data = file.get_input_stream('word/document.xml').read
|
69
|
+
data.should == 'the new content'
|
70
|
+
end
|
47
71
|
end
|
48
72
|
|
49
73
|
it "accepts a file as input" do
|
50
74
|
subject.content File.new('spec/files/content.txt')
|
51
|
-
subject.new_content.should == 'this is the new content of the document'
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
describe '#add_image' do
|
56
|
-
it 'adds an image to the relations file' do
|
57
|
-
subject.add_image 'rId9', 'path/to/image.jpg'
|
58
|
-
subject.new_relationships.to_s.should =~ /<Relationship Id="rId9" Type="http:\/\/schemas.openxmlformats.org\/officeDocument\/2006\/relationships\/image" Target="media\/image.jpg"\/>/
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
describe '#add_binary_image' do
|
63
|
-
let(:image) { File.new(File.join(File.dirname(__FILE__), 'files', 'duck.jpeg'), 'rb') }
|
64
|
-
it 'adds an image in binary format to the docx' do
|
65
|
-
data = image.read
|
66
|
-
subject.add_binary_image 'rId18', 'duck.jpeg', data
|
67
|
-
subject.new_relationships.to_s.should =~ /<Relationship Id="rId18" Type="http:\/\/schemas.openxmlformats.org\/officeDocument\/2006\/relationships\/image" Target="media\/duck.jpeg"\/>/
|
68
75
|
subject.process
|
69
|
-
|
70
76
|
Zip::ZipFile.open('spec/files/result.docx') do |file|
|
71
|
-
file.
|
77
|
+
data = file.get_input_stream('word/document.xml').read
|
78
|
+
data.should == 'this is the new content of the document'
|
72
79
|
end
|
73
80
|
end
|
74
81
|
end
|
75
82
|
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
end
|
80
|
-
|
81
|
-
it "generates the resulting document" do
|
83
|
+
context 'with an image' do
|
84
|
+
it 'adds an image' do
|
85
|
+
subject.add_image 'rId19', 'spec/files/duck.jpeg'
|
82
86
|
subject.process
|
83
|
-
|
87
|
+
Zip::ZipFile.open('spec/files/result.docx') do |file|
|
88
|
+
content = Nokogiri::XML.parse(file.get_input_stream('word/_rels/document.xml.rels').read)
|
89
|
+
content.xpath('//r:Relationship[@Id="rId19"]', 'r' => 'http://schemas.openxmlformats.org/package/2006/relationships').first['Target'].should == 'media/duck.jpeg'
|
90
|
+
file.find_entry('word/media/duck.jpeg').should_not be_nil
|
91
|
+
end
|
84
92
|
end
|
85
93
|
|
86
|
-
it
|
87
|
-
|
94
|
+
it 'adds an image as binary data' do
|
95
|
+
file = File.new(File.join(File.dirname(__FILE__), 'files', 'duck.jpeg'), 'rb')
|
96
|
+
data = file.read
|
97
|
+
subject.add_binary_image 'rId19', 'duck.jpeg', data
|
88
98
|
subject.process
|
89
99
|
Zip::ZipFile.open('spec/files/result.docx') do |file|
|
90
|
-
file.get_input_stream('word/document.xml').read
|
100
|
+
content = Nokogiri::XML.parse(file.get_input_stream('word/_rels/document.xml.rels').read)
|
101
|
+
content.xpath('//r:Relationship[@Id="rId19"]', 'r' => 'http://schemas.openxmlformats.org/package/2006/relationships').first['Target'].should == 'media/duck.jpeg'
|
102
|
+
file.read('word/media/duck.jpeg').should == data
|
91
103
|
end
|
92
104
|
end
|
93
105
|
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
it 'adds the image to the resulting file' do
|
105
|
-
subject.add_image 'rId19', 'spec/files/duck.jpeg'
|
106
|
-
subject.process
|
107
|
-
Zip::ZipFile.open('spec/files/result.docx') do |file|
|
108
|
-
file.find_entry('word/media/duck.jpeg').should_not be_nil
|
109
|
-
end
|
106
|
+
it 'transliterates the image name' do
|
107
|
+
file = File.new(File.join(File.dirname(__FILE__), 'files', 'duck.jpeg'), 'rb')
|
108
|
+
data = file.read
|
109
|
+
subject.add_binary_image 'rId19', 'dück.jpeg', data
|
110
|
+
subject.process
|
111
|
+
Zip::ZipFile.open('spec/files/result.docx') do |file|
|
112
|
+
content = Nokogiri::XML.parse(file.get_input_stream('word/_rels/document.xml.rels').read)
|
113
|
+
content.xpath('//r:Relationship[@Id="rId19"]', 'r' => 'http://schemas.openxmlformats.org/package/2006/relationships').first['Target'].should == 'media/duck.jpeg'
|
114
|
+
file.find_entry('word/media/duck.jpeg').should_not be_nil
|
110
115
|
end
|
111
116
|
end
|
112
117
|
end
|
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: docx_manipulator
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 0.0.
|
5
|
+
version: 0.0.5
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- "Michael St\xC3\xA4mpfli"
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2012-04-
|
13
|
+
date: 2012-04-19 00:00:00 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: rspec
|
@@ -45,6 +45,17 @@ dependencies:
|
|
45
45
|
version: "0"
|
46
46
|
type: :runtime
|
47
47
|
version_requirements: *id003
|
48
|
+
- !ruby/object:Gem::Dependency
|
49
|
+
name: i18n
|
50
|
+
prerelease: false
|
51
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
52
|
+
none: false
|
53
|
+
requirements:
|
54
|
+
- - ">="
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: "0"
|
57
|
+
type: :runtime
|
58
|
+
version_requirements: *id004
|
48
59
|
description: This Gem enables you to modify the contents of docx files.
|
49
60
|
email:
|
50
61
|
- michael.staempfli@gmail.com
|
@@ -62,6 +73,8 @@ files:
|
|
62
73
|
- Rakefile
|
63
74
|
- docx_manipulator.gemspec
|
64
75
|
- lib/docx_manipulator.rb
|
76
|
+
- lib/docx_manipulator/content.rb
|
77
|
+
- lib/docx_manipulator/relationships.rb
|
65
78
|
- lib/docx_manipulator/version.rb
|
66
79
|
- spec/docx_manipulator_spec.rb
|
67
80
|
- spec/files/content.txt
|