texzip 0.1.6 → 0.1.7

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.
Files changed (4) hide show
  1. data/History.txt +3 -0
  2. data/lib/texzip/Project.rb +518 -512
  3. data/version.txt +1 -1
  4. metadata +1 -1
data/History.txt CHANGED
@@ -1,3 +1,6 @@
1
+ == 0.1.7 / 2012-10-25
2
+ * fix plain image path substitution in tex-files
3
+
1
4
  == 0.1.6 / 2012-10-25
2
5
  * add .png extension for images
3
6
  * add -p parameter for storing images without nested subdirectories
@@ -8,516 +8,522 @@ class TeXzip::Error < Exception; end
8
8
 
9
9
  class TeXzip::Project < HighLine
10
10
 
11
- PACKAGE_EXTENSIONS = %w(.sty .cls)
12
- IMAGE_EXTENSIONS = %w(.png .jpg .pdf .eps .pstex)
13
- TEXIMAGE_EXTENSIONS = %w(.pspdftex .pdf_t .pstex_t)
14
-
15
- class Quit < Exception; end
16
-
17
- attr_accessor :overwrite_all
18
-
19
- class FilePath
20
- def initialize(root_dir, file)
21
- @root_dir = Pathname.new(root_dir).expand_path
22
- @file = Pathname.new(file)
23
- @file = @root_dir.join(file).expand_path.relative_path_from(@root_dir)
24
- @out_file = @file
25
- end
26
-
27
- def set_output_directory dir
28
- @out_dir = Pathname.new(dir).expand_path
29
- end
30
-
31
- def set_plain_output_directory dir
32
- set_output_directory dir
33
- @out_file = @file.basename
34
- end
35
-
36
- def file
37
- @file
38
- end
39
-
40
- def out_file= file
41
- @out_file = Pathname.new(file)
42
- end
43
-
44
- def output_path
45
- @out_dir.join(@out_file).expand_path
46
- end
47
-
48
- def path
49
- @root_dir.join(@file).expand_path
50
- end
51
-
52
- def extname
53
- @file.extname
54
- end
55
-
56
- def hash
57
- path.to_s.hash
58
- end
59
-
60
- def eql?(file_path)
61
- path.to_s.eql? file_path.path.to_s
62
- end
63
- end
64
-
65
- def initialize( master_file )
66
- super()
67
- @tex_master_file = Pathname.new(master_file).expand_path
68
-
69
- # All possible include-paths for TeX
70
- @tex_dirs = [@tex_master_file.dirname]
71
- @tex_dirs.concat((ENV["TEXINPUTS"] || "").split(':').map{|d| Pathname.new(d)})
72
- @tex_dirs.map! &:expand_path
73
- @tex_dirs.uniq!
74
-
75
- @overwrite_all = false
76
-
77
- parse_files
78
- end
79
-
80
- def parse_files
81
- # The hash of all files, including the whole text.
82
- @tex_files = {}
83
- @image_files = Set.new
84
- @bib_files = Set.new
85
- @cites = Set.new
86
-
87
- # Read all files recursively
88
- unparsed_files = [@tex_master_file]
89
- until unparsed_files.empty?
90
- fname = unparsed_files.pop
91
- file = find_file( fname )
92
- if file.nil? then
93
- if PACKAGE_EXTENSIONS.include? File.extname(fname)
94
- next
95
- else
96
- raise TeXzip::Error, "Can't find file: #{fname}"
97
- end
98
- end
99
-
100
- unless @tex_files.has_key? file
101
- included_files = parse_file file
102
- unparsed_files.concat included_files
103
- end
104
- end
105
-
106
- unless @bib_files.empty?
107
- @bib = BibTeX::Bibliography.new
108
- @bib_files.each do |bib_file|
109
- bib = BibTeX.open(bib_file.path)
110
- bib.replace_strings
111
- @bib.add(bib.data)
112
- end
113
- else
114
- @bib = nil
115
- end
116
- end
117
-
118
- # Returns the master-file's path.
119
- def master_file
120
- @tex_master_file
121
- end
122
-
123
- # Returns a list of included tex and sty files.
124
- # @return [Array<Pathname>] Included tex files.
125
- def tex_files
126
- @tex_files.keys
127
- end
128
-
129
- # Returns a list of included image-files.
130
- # @return [Array<Pathname>] Included image files.
131
- def image_files
132
- @image_files.to_a
133
- end
134
-
135
- # Returns a list of included BibTeX-files.
136
- # @return [Array<Pathname>] Included BibTeX files.
137
- def bib_files
138
- @bib_files.to_a
139
- end
140
-
141
- # Returns a list of citations.
142
- # @return [Array<String>] Citations.
143
- def cites
144
- @cites.to_a
145
- end
146
-
147
- # Returns the full path for a certain file.
148
- #
149
- # The file is searched in the current directory as well as all
150
- # directories given by the environment variable +TEXINPUTS+
151
- #
152
- # @param [String] file The (relative) path of the file.
153
- # @param [Array<String>] extensions The (possible) file extensions.
154
- # @return [Pathname,nil] The path to the file if exist.
155
- def find_file( file, extensions = [] )
156
- extensions.unshift "" # the empty extension
157
- extensions.uniq!
158
-
159
- @tex_dirs.each do |d|
160
- extensions.each do |ext|
161
- file_path = d.join(file + ext).expand_path
162
- if File.file? file_path
163
- return FilePath.new(d, file + ext)
164
- end
165
- end
166
- end
167
- return nil
168
- end
169
-
170
- # Returns the full paths for all variants of a certain file.
171
- #
172
- # The files are searched in the current directory as well as all
173
- # directories given by the environment variable +TEXINPUTS+
174
- #
175
- # @param [String] file The base file-name.
176
- # @param [Array<String>] extensions The possible file-extensions.
177
- # @return [Array<Pathname>] All found files.
178
- def find_files( file, extensions )
179
- extensions.uniq!
180
-
181
- files = []
182
-
183
- extensions.each do |ext|
184
- @tex_dirs.each do |d|
185
- file_path = d.join(file + ext).expand_path
186
- if file_path.file?
187
- files << FilePath.new(d, file + ext)
188
- break
189
- end
190
- end
191
- end
192
-
193
- files
194
- end
195
-
196
- # Load and parse a single tex-file.
197
- #
198
- # The file is parsed for commands including images, BibTeX-files
199
- # and citations. The command along with the command's argument is
200
- # passed to the block. The block is assumed to return a list of
201
- # further tex-files to be parsed.
202
- #
203
- # @param [Pathname,String] file_name The name of the TeX-file to parse
204
- # @return [Array<String>] A list of included TeX-files.
205
- def parse_file file_name, &block
206
- text = nil
207
- File.open(file_name.path, "rb") do |f|
208
- text = f.read
209
- end
210
- @tex_files[file_name] = text
211
-
212
- block = method(:handle_command) unless block
213
-
214
- included_files = []
215
- text_without_comments = ""
216
- text.each_line do |line|
217
- comment_match = line.match /(?:\\)*%/
218
- if comment_match and (comment_match.end(0) - comment_match.begin(0)).odd?
219
- line = line[0...comment_match.end(0)]
220
- end
221
- text_without_comments.concat line
222
- end
223
-
224
- text_without_comments.scan(/\\(documentclass|usepackage|include|input|includegraphics|bibliography|cite)(?:\[[^\]]+\])?\{([^}]+)\}/) do |cmd, arg|
225
- new_files = block.call cmd, arg
226
- included_files.concat new_files if new_files
227
- end
228
- included_files
229
- end
230
-
231
- # Handles parsed commands.
232
- def handle_command command, argument
233
- case command
234
- when "includegraphics"
235
- add_image argument
236
- when "bibliography"
237
- argument.split(',').uniq.each{|f| add_bib f.strip}
238
- when "usepackage"
239
- return [argument + ".sty"]
240
- when "documentclass"
241
- return [argument + ".cls"]
242
- when "cite"
243
- @cites.merge argument.split(',').map(&:strip)
244
- else
245
- ext = File.extname(argument)
246
- if TEXIMAGE_EXTENSIONS.include?(ext)
247
- file = find_file(argument)
248
- unless file
249
- puts "WARNING: Can't find tex-image file #{argument}"
250
- return nil
251
- end
252
- dir = File.dirname(argument)
253
- parse_file file do |command, arg|
254
- if command == "includegraphics"
255
- add_image File.join(dir, arg)
256
- else
257
- raise TeXzip::Error, "Unexpected command '\\#{command}' in tex-image file: \\#{argument}"
258
- end
259
- nil
260
- end
261
- elsif ext != ".tex"
262
- argument += ".tex"
263
- end
264
- return [argument]
265
- end
266
- return nil
267
- end
268
-
269
- # Adds an image to the list of included images.
270
- # @param [String] image_file_name The path of the image-file
271
- def add_image image_file_name
272
- ext = File.extname(image_file_name)
273
- if ext == ""
274
- image_files = find_files( image_file_name, IMAGE_EXTENSIONS )
275
- else
276
- image_files = [find_file( image_file_name )].compact
277
- end
278
-
279
- if image_files.empty?
280
- puts "WARNING: Can't find included image #{image_file_name}"
281
- else
282
- @image_files.merge image_files
283
- end
284
- end
285
-
286
- # Adds a BibTeX-file to the list of included BibTeX-files.
287
- # @param [String] image_file_name The path of the BibTeX-file.
288
- def add_bib bib_file_name
289
- bib_file = find_file( bib_file_name, [".bib"] )
290
-
291
- if bib_file.nil?
292
- puts "WARNING: Can't find included BibTeX file #{bib_file_name}"
293
- else
294
- @bib_files.add bib_file
295
- end
296
- end
297
-
298
- def modify_files outdir, image_dir, plain_img, bibtex_file
299
- @output_directory = Pathname.new(outdir).expand_path
300
- @output_image_directory = @output_directory.join(Pathname.new(image_dir)).expand_path
301
- @output_bibtex = @output_directory.join(Pathname.new(bibtex_file)).expand_path
302
- @modified_files = {}
303
-
304
- plain_img_files = Hash.new{|h,k| h[k] = []}
305
-
306
- @tex_files.each_key do |file|
307
- if TEXIMAGE_EXTENSIONS.include? file.extname
308
- if plain_img
309
- file.set_plain_output_directory @output_image_directory
310
- plain_img_files[file.file.to_s] << file
311
- else
312
- file.set_output_directory @output_image_directory
313
- end
314
- else
315
- file.set_output_directory @output_directory
316
- end
317
- end
318
- @tex_files.each_pair do |file, text|
319
- @modified_files[file] = update_file file, text
320
- end
321
-
322
- @image_files.each do |file|
323
- if plain_img
324
- file.set_plain_output_directory @output_image_directory
325
- plain_img_files[file.file.to_s] << file
326
- else
327
- file.set_output_directory @output_image_directory
328
- end
329
- end
330
-
331
- # maybe rename some files
332
- plain_img_files.each_pair do |fname, files|
333
- ext = File.extname(fname)
334
- next if files.size <= 1
335
- cnt = 2
336
- files.each do |file|
337
- loop do
338
- new_fname = fname.basename.sub_ext("#{cnt}#{ext}")
339
- if plain_img_files.include?(new_fname.to_s)
340
- cnt += 1
341
- else
342
- file.out_file = new_fname
343
- break
344
- end
345
- end
346
- end
347
- end
348
-
349
- filter_bibtex
350
- end
351
-
352
- def update_file tex_file, text
353
- ext = tex_file.path.extname
354
-
355
- new_text = ""
356
- text.each_line do |line|
357
- comment_match = line.match /(?:\\)*%/
358
- if comment_match and (comment_match.end(0) - comment_match.begin(0)).odd?
359
- comment = line[comment_match.end(0) .. -1]
360
- line = line[0...comment_match.end(0)]
361
- else
362
- comment = ""
363
- end
364
- new_line = line.gsub(/(\\(include|input|includegraphics|bibliography)(?:\[[^\]]+\])?)\{([^}]+)\}/) { |m|
365
- start = $1
366
- cmd = $2
367
- file = $3
368
- if cmd == "includegraphics"
369
- if TEXIMAGE_EXTENSIONS.include? ext
370
- file = File.join(tex_file.file.dirname, file)
371
- end
372
- new_file = @output_image_directory.join(Pathname.new(file)).relative_path_from(@output_directory)
373
- elsif cmd == "bibliography"
374
- new_file = @output_bibtex.basename.to_s.gsub(/\.bib$/, '')
375
- else
376
- if TEXIMAGE_EXTENSIONS.include? File.extname(file)
377
- new_file = @output_image_directory.join(Pathname.new(file)).relative_path_from(@output_directory)
378
- else
379
- new_file = @output_directory.join(Pathname.new(file)).relative_path_from(@output_directory)
380
- end
381
- end
382
- "#{start}{#{new_file}}"
383
- }
384
- new_text.concat new_line
385
- new_text.concat comment
386
- end
387
-
388
- return new_text
389
- end
390
-
391
- def filter_bibtex
392
- if @bib
393
- cites = @cites.to_a.map{|c| c.to_s}
394
- seen_cites = cites.to_set
395
- until cites.empty?
396
- cite = cites.pop
397
- entries = @bib[cite]
398
- if entries.nil?
399
- puts "WARNING: Can't find BibTeX-entry #{cite}"
400
- else
401
- entries = [entries] unless entries.kind_of? Array
402
- entries.each do |entry|
403
- crossref = entry["crossref"]
404
- if crossref
405
- crossref.split(',').map(&:strip).each do |ref|
406
- ref = ref.to_s
407
- cites << ref if seen_cites.add? ref
408
- end
409
- end
410
- end
411
- end
412
- end
413
-
414
- @bib = BibTeX::Bibliography.new.add(@bib.data.select{|entry| seen_cites.include? entry.key.to_s})
415
- end
416
- end
417
-
418
- def write_files( force = false )
419
- cwd = Pathname.getwd.expand_path
420
- write_data do |path, data|
421
- puts "Write file #{path.relative_path_from(cwd)}"
422
- FileUtils.mkdir_p path.dirname unless path.dirname.exist?
423
- if data.kind_of? Pathname
424
- FileUtils.copy data, path
425
- else
426
- File.open(path, "wb") do |f|
427
- f.write data
428
- end
429
- end
430
- end
431
- end
432
-
433
- def write_archive( archive_file, force = false )
434
- require 'ffi-libarchive'
435
-
436
- archive_file = Pathname.new(archive_file).expand_path
437
- return unless ask_overwrite(archive_file)
438
-
439
- compression = case File.basename(archive_file.to_s)
440
- when /\.tgz$/, /\.tar\.gz$/
441
- :gzip
442
- when /\.tbz2$/, /\.tar\.bz2$/
443
- :bzip2
444
- when /\.txz$/, /\.tar\.xz$/
445
- :xz
446
- when /\.tlzma$/, /\.tar\.lzma$/
447
- :lzma
448
- when /\.tZ$/, /\.tar\.Z$/
449
- :Z
450
- when /\.tar$/
451
- :none
452
- else
453
- raise TeXzip::Error, "Can't derive archive-type from file name #{archive_file}"
454
- end
455
-
456
- puts "Write archive #{archive_file.relative_path_from(Pathname.getwd)}"
457
- Archive.write_open_filename archive_file.to_s, compression, :tar do |ar|
458
- write_data true do |path, data|
459
- ar.add_entry do |e|
460
- e.pathname = path.relative_path_from(@output_directory).to_s
461
- if data.kind_of? Pathname
462
- e.copy_stat(data.to_s)
463
- File.open(data, "rb", &:read)
464
- else
465
- e.mode = 0644
466
- e.atime = Time.now
467
- e.mtime = Time.now
468
- e.filetype = :file
469
- data
470
- end
471
- end
472
- end
473
- end
474
- end
475
-
476
- def write_data( force = false, &block )
477
- raise ArgumentError, "Block required" unless block
478
-
479
- overwrite_all = force
480
- commands = []
481
-
482
- @modified_files.each_pair do |file, text|
483
- if force or ask_overwrite(file.output_path)
484
- commands << [file.output_path, text]
485
- end
486
- end
487
-
488
- @image_files.each do |file|
489
- if force or ask_overwrite(file.output_path)
490
- commands << [file.output_path, file.path]
491
- end
492
- end
493
-
494
- if @bib and (force or ask_overwrite(@output_bibtex))
495
- commands << [@output_bibtex, @bib.to_s]
496
- end
497
-
498
- commands.each do |path, data|
499
- block.call path, data
500
- end
501
- end
502
-
503
- def ask_overwrite file
504
- if !@overwrite_all and File.exist?(file)
505
- ask("File #{file.relative_path_from(Pathname.getwd)} exists. Overwrite? [Ynaq]") do |q|
506
- q.character = true
507
- q.validate = /[ynaq\r ]/
508
- q.case = :down
509
- q.overwrite = false
510
- q.answer_type = lambda{ |c|
511
- case c
512
- when "q"; raise Quit
513
- when "y"; true
514
- when "n"; false
515
- when "a"; @overwrite_all = true; true
516
- end
517
- }
518
- end
519
- else
520
- true
521
- end
522
- end
11
+ PACKAGE_EXTENSIONS = %w(.sty .cls)
12
+ IMAGE_EXTENSIONS = %w(.png .jpg .pdf .eps .pstex)
13
+ TEXIMAGE_EXTENSIONS = %w(.pspdftex .pdf_t .pstex_t)
14
+
15
+ class Quit < Exception; end
16
+
17
+ attr_accessor :overwrite_all
18
+
19
+ class FilePath
20
+ def initialize(root_dir, file)
21
+ @root_dir = Pathname.new(root_dir).expand_path
22
+ @file = Pathname.new(file)
23
+ @file = @root_dir.join(file).expand_path.relative_path_from(@root_dir)
24
+ @out_file = @file
25
+ end
26
+
27
+ def set_output_directory dir
28
+ @out_dir = Pathname.new(dir).expand_path
29
+ end
30
+
31
+ def set_plain_output_directory dir
32
+ set_output_directory dir
33
+ @out_file = @file.basename
34
+ end
35
+
36
+ def file
37
+ @file
38
+ end
39
+
40
+ def out_file= file
41
+ @out_file = Pathname.new(file)
42
+ end
43
+
44
+ def output_path
45
+ @out_dir.join(@out_file).expand_path
46
+ end
47
+
48
+ def path
49
+ @root_dir.join(@file).expand_path
50
+ end
51
+
52
+ def extname
53
+ @file.extname
54
+ end
55
+
56
+ def hash
57
+ path.to_s.hash
58
+ end
59
+
60
+ def eql?(file_path)
61
+ path.to_s.eql? file_path.path.to_s
62
+ end
63
+ end
64
+
65
+ def initialize( master_file )
66
+ super()
67
+ @tex_master_file = Pathname.new(master_file).expand_path
68
+
69
+ # All possible include-paths for TeX
70
+ @tex_dirs = [@tex_master_file.dirname]
71
+ @tex_dirs.concat((ENV["TEXINPUTS"] || "").split(':').map{|d| Pathname.new(d)})
72
+ @tex_dirs.map! &:expand_path
73
+ @tex_dirs.uniq!
74
+
75
+ @overwrite_all = false
76
+
77
+ parse_files
78
+ end
79
+
80
+ def parse_files
81
+ # The hash of all files, including the whole text.
82
+ @tex_files = {}
83
+ @image_files = Set.new
84
+ @bib_files = Set.new
85
+ @cites = Set.new
86
+
87
+ # Read all files recursively
88
+ unparsed_files = [@tex_master_file]
89
+ until unparsed_files.empty?
90
+ fname = unparsed_files.pop
91
+ file = find_file( fname )
92
+ if file.nil? then
93
+ if PACKAGE_EXTENSIONS.include? File.extname(fname)
94
+ next
95
+ else
96
+ raise TeXzip::Error, "Can't find file: #{fname}"
97
+ end
98
+ end
99
+
100
+ unless @tex_files.has_key? file
101
+ included_files = parse_file file
102
+ unparsed_files.concat included_files
103
+ end
104
+ end
105
+
106
+ unless @bib_files.empty?
107
+ @bib = BibTeX::Bibliography.new
108
+ @bib_files.each do |bib_file|
109
+ bib = BibTeX.open(bib_file.path)
110
+ bib.replace_strings
111
+ @bib.add(bib.data)
112
+ end
113
+ else
114
+ @bib = nil
115
+ end
116
+ end
117
+
118
+ # Returns the master-file's path.
119
+ def master_file
120
+ @tex_master_file
121
+ end
122
+
123
+ # Returns a list of included tex and sty files.
124
+ # @return [Array<Pathname>] Included tex files.
125
+ def tex_files
126
+ @tex_files.keys
127
+ end
128
+
129
+ # Returns a list of included image-files.
130
+ # @return [Array<Pathname>] Included image files.
131
+ def image_files
132
+ @image_files.to_a
133
+ end
134
+
135
+ # Returns a list of included BibTeX-files.
136
+ # @return [Array<Pathname>] Included BibTeX files.
137
+ def bib_files
138
+ @bib_files.to_a
139
+ end
140
+
141
+ # Returns a list of citations.
142
+ # @return [Array<String>] Citations.
143
+ def cites
144
+ @cites.to_a
145
+ end
146
+
147
+ # Returns the full path for a certain file.
148
+ #
149
+ # The file is searched in the current directory as well as all
150
+ # directories given by the environment variable +TEXINPUTS+
151
+ #
152
+ # @param [String] file The (relative) path of the file.
153
+ # @param [Array<String>] extensions The (possible) file extensions.
154
+ # @return [Pathname,nil] The path to the file if exist.
155
+ def find_file( file, extensions = [] )
156
+ extensions.unshift "" # the empty extension
157
+ extensions.uniq!
158
+
159
+ @tex_dirs.each do |d|
160
+ extensions.each do |ext|
161
+ file_path = d.join(file + ext).expand_path
162
+ if File.file? file_path
163
+ return FilePath.new(d, file + ext)
164
+ end
165
+ end
166
+ end
167
+ return nil
168
+ end
169
+
170
+ # Returns the full paths for all variants of a certain file.
171
+ #
172
+ # The files are searched in the current directory as well as all
173
+ # directories given by the environment variable +TEXINPUTS+
174
+ #
175
+ # @param [String] file The base file-name.
176
+ # @param [Array<String>] extensions The possible file-extensions.
177
+ # @return [Array<Pathname>] All found files.
178
+ def find_files( file, extensions )
179
+ extensions.uniq!
180
+
181
+ files = []
182
+
183
+ extensions.each do |ext|
184
+ @tex_dirs.each do |d|
185
+ file_path = d.join(file + ext).expand_path
186
+ if file_path.file?
187
+ files << FilePath.new(d, file + ext)
188
+ break
189
+ end
190
+ end
191
+ end
192
+
193
+ files
194
+ end
195
+
196
+ # Load and parse a single tex-file.
197
+ #
198
+ # The file is parsed for commands including images, BibTeX-files
199
+ # and citations. The command along with the command's argument is
200
+ # passed to the block. The block is assumed to return a list of
201
+ # further tex-files to be parsed.
202
+ #
203
+ # @param [Pathname,String] file_name The name of the TeX-file to parse
204
+ # @return [Array<String>] A list of included TeX-files.
205
+ def parse_file file_name, &block
206
+ text = nil
207
+ File.open(file_name.path, "rb") do |f|
208
+ text = f.read
209
+ end
210
+ @tex_files[file_name] = text
211
+
212
+ block = method(:handle_command) unless block
213
+
214
+ included_files = []
215
+ text_without_comments = ""
216
+ text.each_line do |line|
217
+ comment_match = line.match /(?:\\)*%/
218
+ if comment_match and (comment_match.end(0) - comment_match.begin(0)).odd?
219
+ line = line[0...comment_match.end(0)]
220
+ end
221
+ text_without_comments.concat line
222
+ end
223
+
224
+ text_without_comments.scan(/\\(documentclass|usepackage|include|input|includegraphics|bibliography|cite)(?:\[[^\]]+\])?\{([^}]+)\}/) do |cmd, arg|
225
+ new_files = block.call cmd, arg
226
+ included_files.concat new_files if new_files
227
+ end
228
+ included_files
229
+ end
230
+
231
+ # Handles parsed commands.
232
+ def handle_command command, argument
233
+ case command
234
+ when "includegraphics"
235
+ add_image argument
236
+ when "bibliography"
237
+ argument.split(',').uniq.each{|f| add_bib f.strip}
238
+ when "usepackage"
239
+ return [argument + ".sty"]
240
+ when "documentclass"
241
+ return [argument + ".cls"]
242
+ when "cite"
243
+ @cites.merge argument.split(',').map(&:strip)
244
+ else
245
+ ext = File.extname(argument)
246
+ if TEXIMAGE_EXTENSIONS.include?(ext)
247
+ file = find_file(argument)
248
+ unless file
249
+ puts "WARNING: Can't find tex-image file #{argument}"
250
+ return nil
251
+ end
252
+ dir = File.dirname(argument)
253
+ parse_file file do |command, arg|
254
+ if command == "includegraphics"
255
+ add_image File.join(dir, arg)
256
+ else
257
+ raise TeXzip::Error, "Unexpected command '\\#{command}' in tex-image file: \\#{argument}"
258
+ end
259
+ nil
260
+ end
261
+ elsif ext != ".tex"
262
+ argument += ".tex"
263
+ end
264
+ return [argument]
265
+ end
266
+ return nil
267
+ end
268
+
269
+ # Adds an image to the list of included images.
270
+ # @param [String] image_file_name The path of the image-file
271
+ def add_image image_file_name
272
+ ext = File.extname(image_file_name)
273
+ if ext == ""
274
+ image_files = find_files( image_file_name, IMAGE_EXTENSIONS )
275
+ else
276
+ image_files = [find_file( image_file_name )].compact
277
+ end
278
+
279
+ if image_files.empty?
280
+ puts "WARNING: Can't find included image #{image_file_name}"
281
+ else
282
+ @image_files.merge image_files
283
+ end
284
+ end
285
+
286
+ # Adds a BibTeX-file to the list of included BibTeX-files.
287
+ # @param [String] image_file_name The path of the BibTeX-file.
288
+ def add_bib bib_file_name
289
+ bib_file = find_file( bib_file_name, [".bib"] )
290
+
291
+ if bib_file.nil?
292
+ puts "WARNING: Can't find included BibTeX file #{bib_file_name}"
293
+ else
294
+ @bib_files.add bib_file
295
+ end
296
+ end
297
+
298
+ def modify_files outdir, image_dir, plain_img, bibtex_file
299
+ @output_directory = Pathname.new(outdir).expand_path
300
+ @output_image_directory = @output_directory.join(Pathname.new(image_dir)).expand_path
301
+ @output_bibtex = @output_directory.join(Pathname.new(bibtex_file)).expand_path
302
+ @modified_files = {}
303
+
304
+ plain_img_files = Hash.new{|h,k| h[k] = []}
305
+
306
+ @tex_files.each_key do |file|
307
+ if TEXIMAGE_EXTENSIONS.include? file.extname
308
+ if plain_img
309
+ file.set_plain_output_directory @output_image_directory
310
+ plain_img_files[file.file.to_s] << file
311
+ else
312
+ file.set_output_directory @output_image_directory
313
+ end
314
+ else
315
+ file.set_output_directory @output_directory
316
+ end
317
+ end
318
+ @tex_files.each_pair do |file, text|
319
+ @modified_files[file] = update_file file, text, plain_img
320
+ end
321
+
322
+ @image_files.each do |file|
323
+ if plain_img
324
+ file.set_plain_output_directory @output_image_directory
325
+ plain_img_files[file.file.to_s] << file
326
+ else
327
+ file.set_output_directory @output_image_directory
328
+ end
329
+ end
330
+
331
+ # maybe rename some files
332
+ plain_img_files.each_pair do |fname, files|
333
+ ext = File.extname(fname)
334
+ next if files.size <= 1
335
+ # TODO: not supported when updating references
336
+ raise "Multiple images with the same name but different directories"
337
+ cnt = 2
338
+ files.each do |file|
339
+ loop do
340
+ new_fname = fname.basename.sub_ext("#{cnt}#{ext}")
341
+ if plain_img_files.include?(new_fname.to_s)
342
+ cnt += 1
343
+ else
344
+ file.out_file = new_fname
345
+ break
346
+ end
347
+ end
348
+ end
349
+ end
350
+
351
+ filter_bibtex
352
+ end
353
+
354
+ def update_file tex_file, text, plain
355
+ ext = tex_file.path.extname
356
+
357
+ new_text = ""
358
+ text.each_line do |line|
359
+ comment_match = line.match /(?:\\)*%/
360
+ if comment_match and (comment_match.end(0) - comment_match.begin(0)).odd?
361
+ comment = line[comment_match.end(0) .. -1]
362
+ line = line[0...comment_match.end(0)]
363
+ else
364
+ comment = ""
365
+ end
366
+ new_line = line.gsub(/(\\(include|input|includegraphics|bibliography)(?:\[[^\]]+\])?)\{([^}]+)\}/) { |m|
367
+ start = $1
368
+ cmd = $2
369
+ file = $3
370
+ if cmd == "includegraphics"
371
+ if TEXIMAGE_EXTENSIONS.include? ext
372
+ file = File.join(tex_file.file.dirname, file)
373
+ end
374
+ new_file = @output_image_directory.join(Pathname.new(file)).relative_path_from(@output_directory)
375
+ # TODO: this does not support multiple files with same name
376
+ new_file = @output_image_directory.join(new_file.basename).relative_path_from(@output_directory) if plain
377
+ elsif cmd == "bibliography"
378
+ new_file = @output_bibtex.basename.to_s.gsub(/\.bib$/, '')
379
+ else
380
+ if TEXIMAGE_EXTENSIONS.include? File.extname(file)
381
+ new_file = @output_image_directory.join(Pathname.new(file)).relative_path_from(@output_directory)
382
+ # TODO: this does not support multiple files with same name
383
+ new_file = @output_image_directory.join(new_file.basename).relative_path_from(@output_directory) if plain
384
+ else
385
+ new_file = @output_directory.join(Pathname.new(file)).relative_path_from(@output_directory)
386
+ end
387
+ end
388
+ "#{start}{#{new_file}}"
389
+ }
390
+ new_text.concat new_line
391
+ new_text.concat comment
392
+ end
393
+
394
+ return new_text
395
+ end
396
+
397
+ def filter_bibtex
398
+ if @bib
399
+ cites = @cites.to_a.map{|c| c.to_s}
400
+ seen_cites = cites.to_set
401
+ until cites.empty?
402
+ cite = cites.pop
403
+ entries = @bib[cite]
404
+ if entries.nil?
405
+ puts "WARNING: Can't find BibTeX-entry #{cite}"
406
+ else
407
+ entries = [entries] unless entries.kind_of? Array
408
+ entries.each do |entry|
409
+ crossref = entry["crossref"]
410
+ if crossref
411
+ crossref.split(',').map(&:strip).each do |ref|
412
+ ref = ref.to_s
413
+ cites << ref if seen_cites.add? ref
414
+ end
415
+ end
416
+ end
417
+ end
418
+ end
419
+
420
+ @bib = BibTeX::Bibliography.new.add(@bib.data.select{|entry| seen_cites.include? entry.key.to_s})
421
+ end
422
+ end
423
+
424
+ def write_files( force = false )
425
+ cwd = Pathname.getwd.expand_path
426
+ write_data do |path, data|
427
+ puts "Write file #{path.relative_path_from(cwd)}"
428
+ FileUtils.mkdir_p path.dirname unless path.dirname.exist?
429
+ if data.kind_of? Pathname
430
+ FileUtils.copy data, path
431
+ else
432
+ File.open(path, "wb") do |f|
433
+ f.write data
434
+ end
435
+ end
436
+ end
437
+ end
438
+
439
+ def write_archive( archive_file, force = false )
440
+ require 'ffi-libarchive'
441
+
442
+ archive_file = Pathname.new(archive_file).expand_path
443
+ return unless ask_overwrite(archive_file)
444
+
445
+ compression = case File.basename(archive_file.to_s)
446
+ when /\.tgz$/, /\.tar\.gz$/
447
+ :gzip
448
+ when /\.tbz2$/, /\.tar\.bz2$/
449
+ :bzip2
450
+ when /\.txz$/, /\.tar\.xz$/
451
+ :xz
452
+ when /\.tlzma$/, /\.tar\.lzma$/
453
+ :lzma
454
+ when /\.tZ$/, /\.tar\.Z$/
455
+ :Z
456
+ when /\.tar$/
457
+ :none
458
+ else
459
+ raise TeXzip::Error, "Can't derive archive-type from file name #{archive_file}"
460
+ end
461
+
462
+ puts "Write archive #{archive_file.relative_path_from(Pathname.getwd)}"
463
+ Archive.write_open_filename archive_file.to_s, compression, :tar do |ar|
464
+ write_data true do |path, data|
465
+ ar.add_entry do |e|
466
+ e.pathname = path.relative_path_from(@output_directory).to_s
467
+ if data.kind_of? Pathname
468
+ e.copy_stat(data.to_s)
469
+ File.open(data, "rb", &:read)
470
+ else
471
+ e.mode = 0644
472
+ e.atime = Time.now
473
+ e.mtime = Time.now
474
+ e.filetype = :file
475
+ data
476
+ end
477
+ end
478
+ end
479
+ end
480
+ end
481
+
482
+ def write_data( force = false, &block )
483
+ raise ArgumentError, "Block required" unless block
484
+
485
+ overwrite_all = force
486
+ commands = []
487
+
488
+ @modified_files.each_pair do |file, text|
489
+ if force or ask_overwrite(file.output_path)
490
+ commands << [file.output_path, text]
491
+ end
492
+ end
493
+
494
+ @image_files.each do |file|
495
+ if force or ask_overwrite(file.output_path)
496
+ commands << [file.output_path, file.path]
497
+ end
498
+ end
499
+
500
+ if @bib and (force or ask_overwrite(@output_bibtex))
501
+ commands << [@output_bibtex, @bib.to_s]
502
+ end
503
+
504
+ commands.each do |path, data|
505
+ block.call path, data
506
+ end
507
+ end
508
+
509
+ def ask_overwrite file
510
+ if !@overwrite_all and File.exist?(file)
511
+ ask("File #{file.relative_path_from(Pathname.getwd)} exists. Overwrite? [Ynaq]") do |q|
512
+ q.character = true
513
+ q.validate = /[ynaq\r ]/
514
+ q.case = :down
515
+ q.overwrite = false
516
+ q.answer_type = lambda{ |c|
517
+ case c
518
+ when "q"; raise Quit
519
+ when "y"; true
520
+ when "n"; false
521
+ when "a"; @overwrite_all = true; true
522
+ end
523
+ }
524
+ end
525
+ else
526
+ true
527
+ end
528
+ end
523
529
  end
data/version.txt CHANGED
@@ -1 +1 @@
1
- 0.1.6
1
+ 0.1.7
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: texzip
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.1.6
5
+ version: 0.1.7
6
6
  platform: ruby
7
7
  authors:
8
8
  - Frank Fischer