docx_manipulator 0.0.4 → 0.0.5

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