texzip 0.1.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.
- data/History.txt +13 -0
- data/README.md +63 -0
- data/Rakefile +27 -0
- data/bin/texzip +62 -0
- data/lib/texzip/Project.rb +478 -0
- data/lib/texzip.rb +60 -0
- data/spec/dummy/bib1.bib +39 -0
- data/spec/dummy/bib2.bib +31 -0
- data/spec/dummy/chapter1.tex +2 -0
- data/spec/dummy/chapter2.tex +2 -0
- data/spec/dummy/chapter3/chapter3-bad.tex +4 -0
- data/spec/dummy/chapter3/chapter3.1.tex +3 -0
- data/spec/dummy/chapter3/chapter3.2.tex +3 -0
- data/spec/dummy/chapter3/chapter3.tex +3 -0
- data/spec/dummy/chapter4.tex +2 -0
- data/spec/dummy/root-file.tex +19 -0
- data/spec/dummy/root-file2.tex +19 -0
- data/spec/dummy/root-file3.tex +19 -0
- data/spec/spec_helper.rb +15 -0
- data/spec/texzip_spec.rb +56 -0
- data/version.txt +1 -0
- metadata +146 -0
data/History.txt
ADDED
data/README.md
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
texzip
|
2
|
+
======
|
3
|
+
|
4
|
+
A small tool to collect images and BibTeX references from tex-files
|
5
|
+
and repack them in a new directory with a new clean BibTeX file.
|
6
|
+
|
7
|
+
Features
|
8
|
+
--------
|
9
|
+
|
10
|
+
* collects images included with \includegraphics
|
11
|
+
* collects BibTeX files included with \bibliography
|
12
|
+
* handles special images generated by xfig .pspdftex
|
13
|
+
* creates compressed archives containing the repacked project
|
14
|
+
|
15
|
+
Examples
|
16
|
+
--------
|
17
|
+
|
18
|
+
texpack -o result -i Images -a mytex.tgz mainfile.tex
|
19
|
+
|
20
|
+
Requirements
|
21
|
+
------------
|
22
|
+
|
23
|
+
* trollop ~> 1.16
|
24
|
+
* bibtex-ruby >= 1.2.1, < 2.0
|
25
|
+
* ffi-libarchive < 2.0
|
26
|
+
* ffi-inliner < 2.0 (through ffi-libarchive)
|
27
|
+
* highline ~> 1.0
|
28
|
+
|
29
|
+
Install
|
30
|
+
-------
|
31
|
+
|
32
|
+
* gem install texpack
|
33
|
+
|
34
|
+
Author
|
35
|
+
------
|
36
|
+
|
37
|
+
Original author: Frank Fischer
|
38
|
+
|
39
|
+
License
|
40
|
+
-------
|
41
|
+
|
42
|
+
(The MIT License)
|
43
|
+
|
44
|
+
Copyright (c) 2011 Frank Fischer
|
45
|
+
|
46
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
47
|
+
a copy of this software and associated documentation files (the
|
48
|
+
'Software'), to deal in the Software without restriction, including
|
49
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
50
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
51
|
+
permit persons to whom the Software is furnished to do so, subject to
|
52
|
+
the following conditions:
|
53
|
+
|
54
|
+
The above copyright notice and this permission notice shall be
|
55
|
+
included in all copies or substantial portions of the Software.
|
56
|
+
|
57
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
58
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
59
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
60
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
61
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
62
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
63
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
|
2
|
+
begin
|
3
|
+
require 'bones'
|
4
|
+
rescue LoadError
|
5
|
+
abort '### Please install the "bones" gem ###'
|
6
|
+
end
|
7
|
+
|
8
|
+
#task :default => 'test:run'
|
9
|
+
#task 'gem:release' => 'test:run'
|
10
|
+
|
11
|
+
files = `darcs show files`.split("\n").
|
12
|
+
select{|f| File.file?(f)}.
|
13
|
+
map{|f| f.gsub(/^\.\//, '')} - %w(.boring .bnsignore)
|
14
|
+
|
15
|
+
Bones {
|
16
|
+
name 'texzip'
|
17
|
+
authors 'Frank Fischer'
|
18
|
+
email 'frank.fischer@mathematik.tu-chemnitz.de'
|
19
|
+
url 'http://darcsden.com/lyro/texzip'
|
20
|
+
depend_on 'bibtex-ruby', ['>= 1.2.1', '< 2.0']
|
21
|
+
depend_on 'trollop', '~> 1.16'
|
22
|
+
depend_on 'ffi-libarchive', '>= 0.1.2', '< 2.0'
|
23
|
+
depend_on 'ffi-inliner', '>= 0.2.4', '< 2.0'
|
24
|
+
depend_on 'highline', '~> 1.0'
|
25
|
+
gem.files files
|
26
|
+
}
|
27
|
+
|
data/bin/texzip
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require File.expand_path(File.join(File.dirname(__FILE__),
|
4
|
+
%w[.. lib texzip]))
|
5
|
+
|
6
|
+
# Put your code here
|
7
|
+
|
8
|
+
require 'trollop'
|
9
|
+
|
10
|
+
opts = Trollop::options do
|
11
|
+
banner <<-EOS
|
12
|
+
TeXzip bundles your TeX project in a single archive or directory with all
|
13
|
+
included tex-, sty-, cls-files, pictures and (used) BibTeX-references.
|
14
|
+
|
15
|
+
Usage:
|
16
|
+
|
17
|
+
#{File.basename(__FILE__)} [options] <master-tex-file>
|
18
|
+
|
19
|
+
where [options] are:
|
20
|
+
EOS
|
21
|
+
opt :bib, "Output BibTeX file", :default => "bibliography.bib"
|
22
|
+
opt :output, "Output directory where the modified files should saved", :type => String
|
23
|
+
opt :images, "Subdirectory where the images should be stored", :default => "img"
|
24
|
+
opt :archive, "Archive to be created", :type => String
|
25
|
+
opt :force, "Force overwriting of files", :default => false
|
26
|
+
version "#{File.basename(__FILE__)} #{TeXzip::VERSION} (c) 2011 Frank Fischer"
|
27
|
+
end
|
28
|
+
|
29
|
+
if ARGV.empty?
|
30
|
+
STDERR.puts "Error: No master TeX-file given."
|
31
|
+
STDERR.puts "Try --help for help."
|
32
|
+
exit -1
|
33
|
+
end
|
34
|
+
|
35
|
+
unless opts[:archive] or opts[:output]
|
36
|
+
STDERR.puts "Error: --output or --archive must be given."
|
37
|
+
STDERR.puts "Try --help for help."
|
38
|
+
exit -1
|
39
|
+
end
|
40
|
+
|
41
|
+
begin
|
42
|
+
texproject = TeXzip::Project.new ARGV.shift
|
43
|
+
texproject.modify_files(opts[:output] || Dir.getwd, opts[:images], opts[:bib])
|
44
|
+
|
45
|
+
texproject.overwrite_all = opts[:force]
|
46
|
+
|
47
|
+
if opts[:output]
|
48
|
+
texproject.write_files
|
49
|
+
end
|
50
|
+
|
51
|
+
if opts[:archive]
|
52
|
+
texproject.write_archive opts[:archive]
|
53
|
+
end
|
54
|
+
rescue TeXzip::Error => e
|
55
|
+
STDERR.puts "Error: #{e}"
|
56
|
+
exit -1
|
57
|
+
rescue TeXzip::Project::Quit
|
58
|
+
puts "Aborted."
|
59
|
+
end
|
60
|
+
|
61
|
+
|
62
|
+
|
@@ -0,0 +1,478 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
require 'set'
|
3
|
+
require 'fileutils'
|
4
|
+
require 'bibtex'
|
5
|
+
require 'ffi-libarchive'
|
6
|
+
require 'highline'
|
7
|
+
|
8
|
+
class TeXzip::Error < Exception; end
|
9
|
+
|
10
|
+
class TeXzip::Project < HighLine
|
11
|
+
|
12
|
+
PACKAGE_EXTENSIONS = %w(.sty .cls)
|
13
|
+
IMAGE_EXTENSIONS = %w(.jpg .pdf .eps .pstex)
|
14
|
+
TEXIMAGE_EXTENSIONS = %w(.pspdftex .pdf_t .pstex_t)
|
15
|
+
|
16
|
+
class Quit < Exception; end
|
17
|
+
|
18
|
+
attr_accessor :overwrite_all
|
19
|
+
|
20
|
+
class FilePath
|
21
|
+
def initialize(root_dir, file)
|
22
|
+
@root_dir = Pathname.new(root_dir).expand_path
|
23
|
+
@file = Pathname.new(file)
|
24
|
+
@file = @root_dir.join(file).expand_path.relative_path_from(@root_dir)
|
25
|
+
end
|
26
|
+
|
27
|
+
def set_output_directory dir
|
28
|
+
@out_dir = Pathname.new(dir).expand_path
|
29
|
+
end
|
30
|
+
|
31
|
+
def file
|
32
|
+
@file
|
33
|
+
end
|
34
|
+
|
35
|
+
def output_path
|
36
|
+
@out_dir.join(@file).expand_path
|
37
|
+
end
|
38
|
+
|
39
|
+
def path
|
40
|
+
@root_dir.join(@file).expand_path
|
41
|
+
end
|
42
|
+
|
43
|
+
def extname
|
44
|
+
@file.extname
|
45
|
+
end
|
46
|
+
|
47
|
+
def hash
|
48
|
+
path.to_s.hash
|
49
|
+
end
|
50
|
+
|
51
|
+
def eql?(file_path)
|
52
|
+
path.to_s.eql? file_path.path.to_s
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def initialize( master_file )
|
57
|
+
super()
|
58
|
+
@tex_master_file = Pathname.new(master_file).expand_path
|
59
|
+
|
60
|
+
# All possible include-paths for TeX
|
61
|
+
@tex_dirs = [@tex_master_file.dirname]
|
62
|
+
@tex_dirs.concat((ENV["TEXINPUTS"] || "").split(':').map{|d| Pathname.new(d)})
|
63
|
+
@tex_dirs.map! &:expand_path
|
64
|
+
@tex_dirs.uniq!
|
65
|
+
|
66
|
+
@overwrite_all = false
|
67
|
+
|
68
|
+
parse_files
|
69
|
+
end
|
70
|
+
|
71
|
+
def parse_files
|
72
|
+
# The hash of all files, including the whole text.
|
73
|
+
@tex_files = {}
|
74
|
+
@image_files = Set.new
|
75
|
+
@bib_files = Set.new
|
76
|
+
@cites = Set.new
|
77
|
+
|
78
|
+
# Read all files recursively
|
79
|
+
unparsed_files = [@tex_master_file]
|
80
|
+
until unparsed_files.empty?
|
81
|
+
fname = unparsed_files.pop
|
82
|
+
file = find_file( fname )
|
83
|
+
if file.nil? then
|
84
|
+
if PACKAGE_EXTENSIONS.include? File.extname(fname)
|
85
|
+
next
|
86
|
+
else
|
87
|
+
raise TeXzip::Error, "Can't find file: #{fname}"
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
unless @tex_files.has_key? file
|
92
|
+
included_files = parse_file file
|
93
|
+
unparsed_files.concat included_files
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
unless @bib_files.empty?
|
98
|
+
@bib = BibTeX::Bibliography.new
|
99
|
+
@bib_files.each do |bib_file|
|
100
|
+
bib = BibTeX.open(bib_file.path)
|
101
|
+
bib.replace_strings
|
102
|
+
@bib.add(bib.to_a)
|
103
|
+
end
|
104
|
+
else
|
105
|
+
@bib = nil
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
# Returns the master-file's path.
|
110
|
+
def master_file
|
111
|
+
@tex_master_file
|
112
|
+
end
|
113
|
+
|
114
|
+
# Returns a list of included tex and sty files.
|
115
|
+
# @return [Array<Pathname>] Included tex files.
|
116
|
+
def tex_files
|
117
|
+
@tex_files.keys
|
118
|
+
end
|
119
|
+
|
120
|
+
# Returns a list of included image-files.
|
121
|
+
# @return [Array<Pathname>] Included image files.
|
122
|
+
def image_files
|
123
|
+
@image_files.to_a
|
124
|
+
end
|
125
|
+
|
126
|
+
# Returns a list of included BibTeX-files.
|
127
|
+
# @return [Array<Pathname>] Included BibTeX files.
|
128
|
+
def bib_files
|
129
|
+
@bib_files.to_a
|
130
|
+
end
|
131
|
+
|
132
|
+
# Returns a list of citations.
|
133
|
+
# @return [Array<String>] Citations.
|
134
|
+
def cites
|
135
|
+
@cites.to_a
|
136
|
+
end
|
137
|
+
|
138
|
+
# Returns the full path for a certain file.
|
139
|
+
#
|
140
|
+
# The file is searched in the current directory as well as all
|
141
|
+
# directories given by the environment variable +TEXINPUTS+
|
142
|
+
#
|
143
|
+
# @param [String] file The (relative) path of the file.
|
144
|
+
# @param [Array<String>] extensions The (possible) file extensions.
|
145
|
+
# @return [Pathname,nil] The path to the file if exist.
|
146
|
+
def find_file( file, extensions = [] )
|
147
|
+
extensions.unshift "" # the empty extension
|
148
|
+
extensions.uniq!
|
149
|
+
|
150
|
+
@tex_dirs.each do |d|
|
151
|
+
extensions.each do |ext|
|
152
|
+
file_path = d.join(file + ext).expand_path
|
153
|
+
if File.file? file_path
|
154
|
+
return FilePath.new(d, file + ext)
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
return nil
|
159
|
+
end
|
160
|
+
|
161
|
+
# Returns the full paths for all variants of a certain file.
|
162
|
+
#
|
163
|
+
# The files are searched in the current directory as well as all
|
164
|
+
# directories given by the environment variable +TEXINPUTS+
|
165
|
+
#
|
166
|
+
# @param [String] file The base file-name.
|
167
|
+
# @param [Array<String>] extensions The possible file-extensions.
|
168
|
+
# @return [Array<Pathname>] All found files.
|
169
|
+
def find_files( file, extensions )
|
170
|
+
extensions.uniq!
|
171
|
+
|
172
|
+
files = []
|
173
|
+
|
174
|
+
extensions.each do |ext|
|
175
|
+
@tex_dirs.each do |d|
|
176
|
+
file_path = d.join(file + ext).expand_path
|
177
|
+
if file_path.file?
|
178
|
+
files << FilePath.new(d, file + ext)
|
179
|
+
break
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
files
|
185
|
+
end
|
186
|
+
|
187
|
+
# Load and parse a single tex-file.
|
188
|
+
#
|
189
|
+
# The file is parsed for commands including images, BibTeX-files
|
190
|
+
# and citations. The command along with the command's argument is
|
191
|
+
# passed to the block. The block is assumed to return a list of
|
192
|
+
# further tex-files to be parsed.
|
193
|
+
#
|
194
|
+
# @param [Pathname,String] file_name The name of the TeX-file to parse
|
195
|
+
# @return [Array<String>] A list of included TeX-files.
|
196
|
+
def parse_file file_name, &block
|
197
|
+
text = nil
|
198
|
+
File.open(file_name.path, "rb") do |f|
|
199
|
+
text = f.read
|
200
|
+
end
|
201
|
+
@tex_files[file_name] = text
|
202
|
+
|
203
|
+
block = method(:handle_command) unless block
|
204
|
+
|
205
|
+
included_files = []
|
206
|
+
text.each_line do |line|
|
207
|
+
comment_match = line.match /(?:\\)*%/
|
208
|
+
if comment_match and (comment_match.end(0) - comment_match.begin(0)).odd?
|
209
|
+
line = line[0...comment_match.end(0)]
|
210
|
+
end
|
211
|
+
line.scan(/\\(documentclass|usepackage|include|input|includegraphics|bibliography|cite)(?:\[[^\]]+\])?\{([^}]+)\}/) do |cmd, arg|
|
212
|
+
new_files = block.call cmd, arg
|
213
|
+
included_files.concat new_files if new_files
|
214
|
+
end
|
215
|
+
end
|
216
|
+
included_files
|
217
|
+
end
|
218
|
+
|
219
|
+
# Handles parsed commands.
|
220
|
+
def handle_command command, argument
|
221
|
+
case command
|
222
|
+
when "includegraphics"
|
223
|
+
add_image argument
|
224
|
+
when "bibliography"
|
225
|
+
argument.split(',').uniq.each{|f| add_bib f.strip}
|
226
|
+
when "usepackage"
|
227
|
+
return [argument + ".sty"]
|
228
|
+
when "documentclass"
|
229
|
+
return [argument + ".cls"]
|
230
|
+
when "cite"
|
231
|
+
@cites.merge argument.split(',').map(&:strip)
|
232
|
+
else
|
233
|
+
ext = File.extname(argument)
|
234
|
+
if TEXIMAGE_EXTENSIONS.include?(ext)
|
235
|
+
file = find_file(argument)
|
236
|
+
unless file
|
237
|
+
puts "WARNING: Can't find tex-image file #{argument}"
|
238
|
+
return nil
|
239
|
+
end
|
240
|
+
dir = File.dirname(argument)
|
241
|
+
parse_file file do |command, arg|
|
242
|
+
if command == "includegraphics"
|
243
|
+
add_image File.join(dir, arg)
|
244
|
+
else
|
245
|
+
raise TeXzip::Error, "Unexpected command '\\#{command}' in tex-image file: \\#{argument}"
|
246
|
+
end
|
247
|
+
nil
|
248
|
+
end
|
249
|
+
elsif ext != ".tex"
|
250
|
+
argument += ".tex"
|
251
|
+
end
|
252
|
+
return [argument]
|
253
|
+
end
|
254
|
+
return nil
|
255
|
+
end
|
256
|
+
|
257
|
+
# Adds an image to the list of included images.
|
258
|
+
# @param [String] image_file_name The path of the image-file
|
259
|
+
def add_image image_file_name
|
260
|
+
ext = File.extname(image_file_name)
|
261
|
+
if ext == ""
|
262
|
+
image_files = find_files( image_file_name, IMAGE_EXTENSIONS )
|
263
|
+
else
|
264
|
+
image_files = [find_file( image_file_name )].compact
|
265
|
+
end
|
266
|
+
|
267
|
+
if image_files.empty?
|
268
|
+
puts "WARNING: Can't find included image #{image_file_name}"
|
269
|
+
else
|
270
|
+
@image_files.merge image_files
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
# Adds a BibTeX-file to the list of included BibTeX-files.
|
275
|
+
# @param [String] image_file_name The path of the BibTeX-file.
|
276
|
+
def add_bib bib_file_name
|
277
|
+
bib_file = find_file( bib_file_name, [".bib"] )
|
278
|
+
|
279
|
+
if bib_file.nil?
|
280
|
+
puts "WARNING: Can't find included BibTeX file #{bib_file_name}"
|
281
|
+
else
|
282
|
+
@bib_files.add bib_file
|
283
|
+
end
|
284
|
+
end
|
285
|
+
|
286
|
+
def modify_files outdir, image_dir, bibtex_file
|
287
|
+
@output_directory = Pathname.new(outdir).expand_path
|
288
|
+
@output_image_directory = @output_directory.join(Pathname.new(image_dir)).expand_path
|
289
|
+
@output_bibtex = @output_directory.join(Pathname.new(bibtex_file)).expand_path
|
290
|
+
@modified_files = {}
|
291
|
+
|
292
|
+
@tex_files.each_key do |file|
|
293
|
+
if TEXIMAGE_EXTENSIONS.include? file.extname
|
294
|
+
file.set_output_directory @output_image_directory
|
295
|
+
else
|
296
|
+
file.set_output_directory @output_directory
|
297
|
+
end
|
298
|
+
end
|
299
|
+
@tex_files.each_pair do |file, text|
|
300
|
+
@modified_files[file] = update_file file, text
|
301
|
+
end
|
302
|
+
|
303
|
+
@image_files.each do |file|
|
304
|
+
file.set_output_directory @output_image_directory
|
305
|
+
end
|
306
|
+
|
307
|
+
filter_bibtex
|
308
|
+
end
|
309
|
+
|
310
|
+
def update_file tex_file, text
|
311
|
+
ext = tex_file.path.extname
|
312
|
+
|
313
|
+
new_text = ""
|
314
|
+
text.each_line do |line|
|
315
|
+
comment_match = line.match /(?:\\)*%/
|
316
|
+
if comment_match and (comment_match.end(0) - comment_match.begin(0)).odd?
|
317
|
+
comment = line[comment_match.end(0) .. -1]
|
318
|
+
line = line[0...comment_match.end(0)]
|
319
|
+
else
|
320
|
+
comment = ""
|
321
|
+
end
|
322
|
+
new_line = line.gsub(/(\\(include|input|includegraphics|bibliography)(?:\[[^\]]+\])?)\{([^}]+)\}/) { |m|
|
323
|
+
start = $1
|
324
|
+
cmd = $2
|
325
|
+
file = $3
|
326
|
+
if cmd == "includegraphics"
|
327
|
+
if TEXIMAGE_EXTENSIONS.include? ext
|
328
|
+
file = File.join(tex_file.file.dirname, file)
|
329
|
+
end
|
330
|
+
new_file = @output_image_directory.join(Pathname.new(file)).relative_path_from(@output_directory)
|
331
|
+
elsif cmd == "bibliography"
|
332
|
+
new_file = @output_bibtex.basename.to_s.gsub(/\.bib$/, '')
|
333
|
+
else
|
334
|
+
if TEXIMAGE_EXTENSIONS.include? File.extname(file)
|
335
|
+
new_file = @output_image_directory.join(Pathname.new(file)).relative_path_from(@output_directory)
|
336
|
+
else
|
337
|
+
new_file = @output_directory.join(Pathname.new(file)).relative_path_from(@output_directory)
|
338
|
+
end
|
339
|
+
end
|
340
|
+
"#{start}{#{new_file}}"
|
341
|
+
}
|
342
|
+
new_text.concat new_line
|
343
|
+
new_text.concat comment
|
344
|
+
end
|
345
|
+
|
346
|
+
return new_text
|
347
|
+
end
|
348
|
+
|
349
|
+
def filter_bibtex
|
350
|
+
if @bib
|
351
|
+
cites = @cites.to_a
|
352
|
+
seen_cites = cites.to_set
|
353
|
+
until cites.empty?
|
354
|
+
cite = cites.pop
|
355
|
+
entry = @bib[cite]
|
356
|
+
if entry
|
357
|
+
crossref = entry["crossref"]
|
358
|
+
if crossref
|
359
|
+
crossref.split(',').map(&:strip).each do |ref|
|
360
|
+
if seen_cites.add? ref
|
361
|
+
cites << ref
|
362
|
+
seen_cites << ref
|
363
|
+
end
|
364
|
+
end
|
365
|
+
end
|
366
|
+
else
|
367
|
+
puts "WARNING: Can't find BibTeX-entry #{cite}"
|
368
|
+
end
|
369
|
+
end
|
370
|
+
|
371
|
+
@bib = BibTeX::Bibliography.new( @bib.to_a.select{|entry| seen_cites.include? entry.key} )
|
372
|
+
end
|
373
|
+
end
|
374
|
+
|
375
|
+
def write_files( force = false )
|
376
|
+
cwd = Pathname.getwd.expand_path
|
377
|
+
write_data do |path, data|
|
378
|
+
puts "Write file #{path.relative_path_from(cwd)}"
|
379
|
+
FileUtils.mkdir_p path.dirname unless path.dirname.exist?
|
380
|
+
if data.kind_of? Pathname
|
381
|
+
FileUtils.copy data, path
|
382
|
+
else
|
383
|
+
File.open(path, "wb") do |f|
|
384
|
+
f.write data
|
385
|
+
end
|
386
|
+
end
|
387
|
+
end
|
388
|
+
end
|
389
|
+
|
390
|
+
def write_archive( archive_file, force = false )
|
391
|
+
archive_file = Pathname.new(archive_file).expand_path
|
392
|
+
return unless ask_overwrite(archive_file)
|
393
|
+
|
394
|
+
compression = case File.basename(archive_file.to_s)
|
395
|
+
when /\.tgz$/, /\.tar\.gz$/
|
396
|
+
:gzip
|
397
|
+
when /\.tbz2$/, /\.tar\.bz2$/
|
398
|
+
:bzip2
|
399
|
+
when /\.txz$/, /\.tar\.xz$/
|
400
|
+
:xz
|
401
|
+
when /\.tlzma$/, /\.tar\.lzma$/
|
402
|
+
:lzma
|
403
|
+
when /\.tZ$/, /\.tar\.Z$/
|
404
|
+
:Z
|
405
|
+
when /\.tar$/
|
406
|
+
:none
|
407
|
+
else
|
408
|
+
raise TeXzip::Error, "Can't derive archive-type from file name #{archive_file}"
|
409
|
+
end
|
410
|
+
|
411
|
+
puts "Write archive #{archive_file.relative_path_from(Pathname.getwd)}"
|
412
|
+
Archive.write_open_filename archive_file.to_s, compression, :tar do |ar|
|
413
|
+
write_data true do |path, data|
|
414
|
+
ar.add_entry do |e|
|
415
|
+
e.pathname = path.relative_path_from(@output_directory).to_s
|
416
|
+
if data.kind_of? Pathname
|
417
|
+
e.copy_stat(data.to_s)
|
418
|
+
File.open(data, "rb", &:read)
|
419
|
+
else
|
420
|
+
e.mode = 0644
|
421
|
+
e.atime = Time.now
|
422
|
+
e.mtime = Time.now
|
423
|
+
e.filetype = :file
|
424
|
+
data
|
425
|
+
end
|
426
|
+
end
|
427
|
+
end
|
428
|
+
end
|
429
|
+
end
|
430
|
+
|
431
|
+
def write_data( force = false, &block )
|
432
|
+
raise ArgumentError, "Block required" unless block
|
433
|
+
|
434
|
+
overwrite_all = force
|
435
|
+
commands = []
|
436
|
+
|
437
|
+
@modified_files.each_pair do |file, text|
|
438
|
+
if force or ask_overwrite(file.output_path)
|
439
|
+
commands << [file.output_path, text]
|
440
|
+
end
|
441
|
+
end
|
442
|
+
|
443
|
+
@image_files.each do |file|
|
444
|
+
if force or ask_overwrite(file.output_path)
|
445
|
+
commands << [file.output_path, file.path]
|
446
|
+
end
|
447
|
+
end
|
448
|
+
|
449
|
+
if @bib and (force or ask_overwrite(@output_bibtex))
|
450
|
+
commands << [@output_bibtex, @bib.to_s]
|
451
|
+
end
|
452
|
+
|
453
|
+
commands.each do |path, data|
|
454
|
+
block.call path, data
|
455
|
+
end
|
456
|
+
end
|
457
|
+
|
458
|
+
def ask_overwrite file
|
459
|
+
if !@overwrite_all and File.exist?(file)
|
460
|
+
ask("File #{file.relative_path_from(Pathname.getwd)} exists. Overwrite? [Ynaq]") do |q|
|
461
|
+
q.character = true
|
462
|
+
q.validate = /[ynaq\r ]/
|
463
|
+
q.case = :down
|
464
|
+
q.overwrite = false
|
465
|
+
q.answer_type = lambda{ |c|
|
466
|
+
case c
|
467
|
+
when "q"; raise Quit
|
468
|
+
when "y"; true
|
469
|
+
when "n"; false
|
470
|
+
when "a"; @overwrite_all = true; true
|
471
|
+
end
|
472
|
+
}
|
473
|
+
end
|
474
|
+
else
|
475
|
+
true
|
476
|
+
end
|
477
|
+
end
|
478
|
+
end
|
data/lib/texzip.rb
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
|
2
|
+
module TeXzip
|
3
|
+
|
4
|
+
# :stopdoc:
|
5
|
+
LIBPATH = ::File.expand_path(::File.dirname(__FILE__)) + ::File::SEPARATOR
|
6
|
+
PATH = ::File.dirname(LIBPATH) + ::File::SEPARATOR
|
7
|
+
VERSION = ::File.read(PATH + 'version.txt').strip
|
8
|
+
# :startdoc:
|
9
|
+
|
10
|
+
# Returns the library path for the module. If any arguments are given,
|
11
|
+
# they will be joined to the end of the libray path using
|
12
|
+
# <tt>File.join</tt>.
|
13
|
+
#
|
14
|
+
def self.libpath( *args )
|
15
|
+
rv = args.empty? ? LIBPATH : ::File.join(LIBPATH, args.flatten)
|
16
|
+
if block_given?
|
17
|
+
begin
|
18
|
+
$LOAD_PATH.unshift LIBPATH
|
19
|
+
rv = yield
|
20
|
+
ensure
|
21
|
+
$LOAD_PATH.shift
|
22
|
+
end
|
23
|
+
end
|
24
|
+
return rv
|
25
|
+
end
|
26
|
+
|
27
|
+
# Returns the lpath for the module. If any arguments are given,
|
28
|
+
# they will be joined to the end of the path using
|
29
|
+
# <tt>File.join</tt>.
|
30
|
+
#
|
31
|
+
def self.path( *args )
|
32
|
+
rv = args.empty? ? PATH : ::File.join(PATH, args.flatten)
|
33
|
+
if block_given?
|
34
|
+
begin
|
35
|
+
$LOAD_PATH.unshift PATH
|
36
|
+
rv = yield
|
37
|
+
ensure
|
38
|
+
$LOAD_PATH.shift
|
39
|
+
end
|
40
|
+
end
|
41
|
+
return rv
|
42
|
+
end
|
43
|
+
|
44
|
+
# Utility method used to require all files ending in .rb that lie in the
|
45
|
+
# directory below this file that has the same name as the filename passed
|
46
|
+
# in. Optionally, a specific _directory_ name can be passed in such that
|
47
|
+
# the _filename_ does not have to be equivalent to the directory.
|
48
|
+
#
|
49
|
+
def self.require_all_libs_relative_to( fname, dir = nil )
|
50
|
+
dir ||= ::File.basename(fname, '.*')
|
51
|
+
search_me = ::File.expand_path(
|
52
|
+
::File.join(::File.dirname(fname), dir, '**', '*.rb'))
|
53
|
+
|
54
|
+
Dir.glob(search_me).sort.each {|rb| require rb}
|
55
|
+
end
|
56
|
+
|
57
|
+
end # module TeXzip
|
58
|
+
|
59
|
+
TeXzip.require_all_libs_relative_to(__FILE__)
|
60
|
+
|
data/spec/dummy/bib1.bib
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
@Article{cite1,
|
2
|
+
author = {Alice},
|
3
|
+
title = {Alice's idea},
|
4
|
+
journal = {Film am Sonntag},
|
5
|
+
year = {2010},
|
6
|
+
}
|
7
|
+
|
8
|
+
|
9
|
+
@Article{cite2,
|
10
|
+
author = {Bob},
|
11
|
+
title = {Bob's idea},
|
12
|
+
journal = {Widerhall},
|
13
|
+
year = {2009},
|
14
|
+
}
|
15
|
+
|
16
|
+
|
17
|
+
@Article{cite2,
|
18
|
+
author = {Bob},
|
19
|
+
title = {Bob's idea},
|
20
|
+
journal = {Widerhall},
|
21
|
+
year = {2009},
|
22
|
+
}
|
23
|
+
|
24
|
+
|
25
|
+
@Article{cite2,
|
26
|
+
author = {Bob},
|
27
|
+
title = {Bob's idea},
|
28
|
+
journal = {Widerhall},
|
29
|
+
year = {2009},
|
30
|
+
}
|
31
|
+
|
32
|
+
|
33
|
+
@Article{cite3,
|
34
|
+
author = {Alice and Bob},
|
35
|
+
title = {We two},
|
36
|
+
journal = {Brennpunkt},
|
37
|
+
year = {2008},
|
38
|
+
}
|
39
|
+
|
data/spec/dummy/bib2.bib
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
|
2
|
+
@Article{cite3,
|
3
|
+
author = {Alice and Bob},
|
4
|
+
title = {We two},
|
5
|
+
journal = {Brennpunkt},
|
6
|
+
year = {2008},
|
7
|
+
}
|
8
|
+
|
9
|
+
|
10
|
+
@Article{cite3,
|
11
|
+
author = {Alice and Bob},
|
12
|
+
title = {We two},
|
13
|
+
journal = {Brennpunkt},
|
14
|
+
year = {2008},
|
15
|
+
}
|
16
|
+
|
17
|
+
|
18
|
+
@Article{cite3,
|
19
|
+
author = {Alice and Bob},
|
20
|
+
title = {We two},
|
21
|
+
journal = {Brennpunkt},
|
22
|
+
year = {2008},
|
23
|
+
}
|
24
|
+
|
25
|
+
|
26
|
+
@Article{cite42,
|
27
|
+
author = {Udo},
|
28
|
+
title = {Ugh?},
|
29
|
+
journal = {Apes' world},
|
30
|
+
year = {2008},
|
31
|
+
}
|
@@ -0,0 +1,19 @@
|
|
1
|
+
\documentclass{scrartcl}
|
2
|
+
|
3
|
+
\begin{document}
|
4
|
+
|
5
|
+
|
6
|
+
\input{chapter1}
|
7
|
+
\input{chapter2.tex}
|
8
|
+
\include{chapter3/chapter3}
|
9
|
+
\include{chapter4.tex}
|
10
|
+
|
11
|
+
\cite{cite1}
|
12
|
+
\cite{cite5, cite2}
|
13
|
+
\cite{cite3,
|
14
|
+
cite4}
|
15
|
+
\cite{cite5, cite2}
|
16
|
+
|
17
|
+
\bibliography{bib1, bib2, bib1}
|
18
|
+
|
19
|
+
\end{document}
|
@@ -0,0 +1,19 @@
|
|
1
|
+
\documentclass{scrartcl}
|
2
|
+
|
3
|
+
\begin{document}
|
4
|
+
|
5
|
+
|
6
|
+
\input{chapter1}
|
7
|
+
\input{chapter2.tex}
|
8
|
+
\include{chapter3-bad}
|
9
|
+
\include{chapter4.tex}
|
10
|
+
|
11
|
+
\cite{cite1}
|
12
|
+
\cite{cite5, cite2}
|
13
|
+
\cite{cite3,
|
14
|
+
cite4}
|
15
|
+
\cite{cite5, cite2}
|
16
|
+
|
17
|
+
\bibliography{bib1, bib2}
|
18
|
+
|
19
|
+
\end{document}
|
@@ -0,0 +1,19 @@
|
|
1
|
+
\documentclass{scrartcl}
|
2
|
+
|
3
|
+
\begin{document}
|
4
|
+
|
5
|
+
|
6
|
+
\input{chapter1}
|
7
|
+
\input{chapter2.tex}
|
8
|
+
\include{chapter3}
|
9
|
+
\include{chapter4.tex}
|
10
|
+
|
11
|
+
\cite{cite1}
|
12
|
+
\cite{cite5, cite2}
|
13
|
+
\cite{cite3,
|
14
|
+
cite4}
|
15
|
+
\cite{cite5, cite2}
|
16
|
+
|
17
|
+
\bibliography{bib1, bib2, bib2, bib3}
|
18
|
+
|
19
|
+
\end{document}
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
|
2
|
+
require File.expand_path(
|
3
|
+
File.join(File.dirname(__FILE__), %w[.. lib texzip]))
|
4
|
+
|
5
|
+
RSpec::Runner.configure do |config|
|
6
|
+
# == Mock Framework
|
7
|
+
#
|
8
|
+
# RSpec uses it's own mocking framework by default. If you prefer to
|
9
|
+
# use mocha, flexmock or RR, uncomment the appropriate line:
|
10
|
+
#
|
11
|
+
# config.mock_with :mocha
|
12
|
+
# config.mock_with :flexmock
|
13
|
+
# config.mock_with :rr
|
14
|
+
end
|
15
|
+
|
data/spec/texzip_spec.rb
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
|
2
|
+
require File.join(File.dirname(__FILE__), %w[spec_helper])
|
3
|
+
|
4
|
+
require 'texzip'
|
5
|
+
require 'tempfile'
|
6
|
+
|
7
|
+
def init_env
|
8
|
+
Dir.chdir(File.dirname(__FILE__))
|
9
|
+
end
|
10
|
+
|
11
|
+
describe TeXzip, "on creation" do
|
12
|
+
before do
|
13
|
+
init_env
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should fail if the file does not exist" do
|
17
|
+
lambda { TeXzip::Project.new(File.join("dummy", "nofile.tex")) }.should raise_error
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should not fail if the file exists" do
|
21
|
+
lambda { TeXzip::Project.new(File.join("dummy", "root-file.tex")) }.should_not raise_error
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
|
26
|
+
describe TeXzip, "after creation" do
|
27
|
+
before do
|
28
|
+
init_env
|
29
|
+
@tex_file = TeXzip::Project.new("dummy/root-file.tex")
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should return its correct path" do
|
33
|
+
@tex_file.master_file.should == Pathname.new("dummy/root-file.tex").expand_path
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should return a list of included sub-files" do
|
37
|
+
@tex_file.tex_files.sort.should == %w( dummy/root-file.tex
|
38
|
+
dummy/chapter1.tex
|
39
|
+
dummy/chapter2.tex
|
40
|
+
dummy/chapter3.tex
|
41
|
+
dummy/chapter3.1.tex
|
42
|
+
dummy/chapter3.2.tex
|
43
|
+
dummy/chapter4.tex ).map{|p| Pathname.new(p).expand_path}.sort
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should return a list of used bibtex files" do
|
47
|
+
@tex_file.bib_files.sort.should == %w( dummy/bib1.bib dummy/bib2.bib ).
|
48
|
+
map{|p| Pathname.new(p).expand_path}.sort
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should return a list of used citations" do
|
52
|
+
@tex_file.cites.sort.should == %w( cite1 cite2 cite3 cite4 cite5 ).sort
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
|
data/version.txt
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.3
|
metadata
ADDED
@@ -0,0 +1,146 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: texzip
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease:
|
5
|
+
version: 0.1.3
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Frank Fischer
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2011-04-12 00:00:00 Z
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: bibtex-ruby
|
17
|
+
prerelease: false
|
18
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
19
|
+
none: false
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 1.2.1
|
24
|
+
- - <
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: "2.0"
|
27
|
+
type: :runtime
|
28
|
+
version_requirements: *id001
|
29
|
+
- !ruby/object:Gem::Dependency
|
30
|
+
name: trollop
|
31
|
+
prerelease: false
|
32
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ~>
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: "1.16"
|
38
|
+
type: :runtime
|
39
|
+
version_requirements: *id002
|
40
|
+
- !ruby/object:Gem::Dependency
|
41
|
+
name: ffi-libarchive
|
42
|
+
prerelease: false
|
43
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
44
|
+
none: false
|
45
|
+
requirements:
|
46
|
+
- - ">="
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: 0.1.2
|
49
|
+
type: :runtime
|
50
|
+
version_requirements: *id003
|
51
|
+
- !ruby/object:Gem::Dependency
|
52
|
+
name: ffi-inliner
|
53
|
+
prerelease: false
|
54
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
55
|
+
none: false
|
56
|
+
requirements:
|
57
|
+
- - ">="
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: 0.2.4
|
60
|
+
type: :runtime
|
61
|
+
version_requirements: *id004
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: highline
|
64
|
+
prerelease: false
|
65
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
66
|
+
none: false
|
67
|
+
requirements:
|
68
|
+
- - ~>
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: "1.0"
|
71
|
+
type: :runtime
|
72
|
+
version_requirements: *id005
|
73
|
+
- !ruby/object:Gem::Dependency
|
74
|
+
name: bones
|
75
|
+
prerelease: false
|
76
|
+
requirement: &id006 !ruby/object:Gem::Requirement
|
77
|
+
none: false
|
78
|
+
requirements:
|
79
|
+
- - ">="
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: 3.6.5
|
82
|
+
type: :development
|
83
|
+
version_requirements: *id006
|
84
|
+
description: |-
|
85
|
+
A small tool to collect images and BibTeX references from tex-files
|
86
|
+
and repack them in a new directory with a new clean BibTeX file.
|
87
|
+
email: frank.fischer@mathematik.tu-chemnitz.de
|
88
|
+
executables:
|
89
|
+
- texzip
|
90
|
+
extensions: []
|
91
|
+
|
92
|
+
extra_rdoc_files:
|
93
|
+
- History.txt
|
94
|
+
- bin/texzip
|
95
|
+
files:
|
96
|
+
- History.txt
|
97
|
+
- README.md
|
98
|
+
- Rakefile
|
99
|
+
- version.txt
|
100
|
+
- bin/texzip
|
101
|
+
- lib/texzip.rb
|
102
|
+
- lib/texzip/Project.rb
|
103
|
+
- spec/spec_helper.rb
|
104
|
+
- spec/texzip_spec.rb
|
105
|
+
- spec/dummy/bib1.bib
|
106
|
+
- spec/dummy/bib2.bib
|
107
|
+
- spec/dummy/chapter1.tex
|
108
|
+
- spec/dummy/chapter2.tex
|
109
|
+
- spec/dummy/chapter4.tex
|
110
|
+
- spec/dummy/root-file.tex
|
111
|
+
- spec/dummy/root-file2.tex
|
112
|
+
- spec/dummy/root-file3.tex
|
113
|
+
- spec/dummy/chapter3/chapter3-bad.tex
|
114
|
+
- spec/dummy/chapter3/chapter3.1.tex
|
115
|
+
- spec/dummy/chapter3/chapter3.2.tex
|
116
|
+
- spec/dummy/chapter3/chapter3.tex
|
117
|
+
homepage: http://darcsden.com/lyro/texzip
|
118
|
+
licenses: []
|
119
|
+
|
120
|
+
post_install_message:
|
121
|
+
rdoc_options:
|
122
|
+
- --main
|
123
|
+
- README.md
|
124
|
+
require_paths:
|
125
|
+
- lib
|
126
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
127
|
+
none: false
|
128
|
+
requirements:
|
129
|
+
- - ">="
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: "0"
|
132
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
133
|
+
none: false
|
134
|
+
requirements:
|
135
|
+
- - ">="
|
136
|
+
- !ruby/object:Gem::Version
|
137
|
+
version: "0"
|
138
|
+
requirements: []
|
139
|
+
|
140
|
+
rubyforge_project: texzip
|
141
|
+
rubygems_version: 1.7.2
|
142
|
+
signing_key:
|
143
|
+
specification_version: 3
|
144
|
+
summary: A small tool to collect images and BibTeX references from tex-files and repack them in a new directory with a new clean BibTeX file.
|
145
|
+
test_files: []
|
146
|
+
|