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.
@@ -22,4 +22,5 @@ Gem::Specification.new do |s|
22
22
  s.add_development_dependency "rspec"
23
23
  s.add_dependency "rubyzip"
24
24
  s.add_dependency "nokogiri"
25
+ s.add_dependency 'i18n'
25
26
  end
@@ -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
@@ -1,3 +1,3 @@
1
1
  class DocxManipulator
2
- VERSION = "0.0.4"
2
+ VERSION = "0.0.5"
3
3
  end
@@ -1,91 +1,46 @@
1
1
  require 'docx_manipulator/version'
2
- require 'nokogiri'
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, :new_content, :new_relationships
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
- def source_relationships
26
- content = ''
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
- new_content_string = case new_content
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
- @images[id] = path
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
- @binary_images[name] = data
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
- os.put_next_entry entry.name
69
- if entry.name == 'word/document.xml'
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
- @images.each do |id, path|
79
- os.put_next_entry "word/media/#{File.basename(path)}"
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
- describe "#source_content" do
9
- it "returns the content of document.xml" do
10
- subject.source_content.should =~ /w:document/
11
- end
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
- describe "#content" do
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.new_content.should =~ /<w:t>The Departed<\/w:t>/
35
- subject.new_content.should =~ /<w:t>The Pursuit of Happyness<\/w:t>/
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.new_content.should =~ /<w:t>The Departed<\/w:t>/
41
- subject.new_content.should =~ /<w:t>The Pursuit of Happyness<\/w:t>/
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.new_content.should == 'the new content'
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.read('word/media/duck.jpeg').should == data
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
- describe "#process" do
77
- after :each do
78
- File.delete 'spec/files/result.docx'
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
- File.should exist('spec/files/result.docx')
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 "replaces the content of the document" do
87
- subject.content 'bla'
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.should == 'bla'
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
- context 'with an image' do
95
- it 'replaces the relations file' do
96
- subject.add_image 'rId19', 'spec/files/duck.jpeg'
97
- subject.process
98
- Zip::ZipFile.open('spec/files/result.docx') do |file|
99
- content = Nokogiri::XML.parse(file.get_input_stream('word/_rels/document.xml.rels').read)
100
- content.xpath('//r:Relationship[@Id="rId19"]', 'r' => 'http://schemas.openxmlformats.org/package/2006/relationships').first['Target'].should == 'media/duck.jpeg'
101
- end
102
- end
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.4
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-03 00:00:00 Z
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