awhyte-rtex 2.1.2

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG ADDED
@@ -0,0 +1,48 @@
1
+ v2.1.0
2
+
3
+ Merge in rails-2.2.2 branch, modify to make sure Prawn isn't trampled and
4
+ 2.3.0 is supported.
5
+ Simplify tagging of templates for later processing (+ ensure it works
6
+ with compiled templates).
7
+ Update README_RAILS
8
+
9
+ v2.0.5
10
+
11
+ Fix issue with Echoe being ultra-sensitive on RubyGems versions (v2.0.4
12
+ was RubyGems 1.2 only, and 1.3 just came out)
13
+
14
+ v2.0.4
15
+
16
+ Support for TeX escaping (via l()) calling to_s on the argument.
17
+ This should handle nils.
18
+
19
+ v2.0.3
20
+
21
+ Rails 2.0 compat:
22
+ Fix issue with init.rb not requiring rails/init.rb
23
+
24
+ v1.99.0 2008-04-20
25
+
26
+ Released RTeX v1.99.0 as a Rubygem, with a standalone executable for PDF generation
27
+ and support for plugin installation from the executable.
28
+
29
+ This release requires Rails >= 2.0.1
30
+
31
+ Thanks to:
32
+ * Jonas Bähr for a patch with additional LaTeX escaping
33
+ * Fouad Mardini for a TemplateHandler patch
34
+
35
+ v1.0.0+
36
+
37
+ Added quite a few *long* overdue fixes & enhancements sent in by various people.
38
+
39
+ * Added latex escaping 'l' method (Thanks, Benjamin Quorning)
40
+ * Added support for @options_for_rtex hash for configuration:
41
+ * Added :tempdir option, and changed default temporary directory
42
+ (Thanks, Francesco Levorato)
43
+ * Added :preprocess option to support running through latex before pdflatex
44
+ (Thanks Charles Lesburg, Benjamin Quorning)
45
+ * Moved old @filename setting to :filename option in this hash
46
+
47
+ If you're using the same settings for @options_for_rtex often, you might want to
48
+ put your assignment in a before_filter (perhaps overriding :filename, etc in your actions).
data/Manifest ADDED
@@ -0,0 +1,25 @@
1
+ bin/rtex
2
+ CHANGELOG
3
+ init.rb
4
+ lib/rtex/document.rb
5
+ lib/rtex/escaping.rb
6
+ lib/rtex/framework/merb.rb
7
+ lib/rtex/framework/rails.rb
8
+ lib/rtex/tempdir.rb
9
+ lib/rtex/version.rb
10
+ lib/rtex.rb
11
+ Manifest
12
+ rails/init.rb
13
+ Rakefile
14
+ README.rdoc
15
+ README_RAILS.rdoc
16
+ test/document_test.rb
17
+ test/filter_test.rb
18
+ test/fixtures/first.tex
19
+ test/fixtures/first.tex.erb
20
+ test/fixtures/fragment.tex.erb
21
+ test/fixtures/text.textile
22
+ test/tempdir_test.rb
23
+ test/test_helper.rb
24
+ vendor/instiki/LICENSE
25
+ vendor/instiki/redcloth_for_tex.rb
data/README.rdoc ADDED
@@ -0,0 +1,46 @@
1
+ = RTeX: TeX/PDF Generation for Ruby
2
+
3
+ Project homepage (FAQ, manual, documentation, contact info): http://rtex.rubyforge.org
4
+
5
+ Source repository at: http://github.com/bruce/rtex
6
+
7
+ == Dependencies
8
+
9
+ * pdflatex executable, available in modern teTeX distributions
10
+ * Requires Rails >= 2.0.1 if used as a plugin.
11
+
12
+ == Usage
13
+
14
+ For use as a standalone executable, see `rtex --help'
15
+
16
+ For use as a Rails plugin, see README_RAILS.rdoc
17
+
18
+ == More Information
19
+
20
+ Additional help may be available at the project homepage,
21
+ http://rtex.rubyforge.org
22
+
23
+ == License
24
+
25
+ (The MIT License)
26
+
27
+ Copyright (c) 2006-2008 Bruce Williams, Wiebe Cazemier
28
+
29
+ Permission is hereby granted, free of charge, to any person obtaining
30
+ a copy of this software and associated documentation files (the
31
+ 'Software'), to deal in the Software without restriction, including
32
+ without limitation the rights to use, copy, modify, merge, publish,
33
+ distribute, sublicense, and/or sell copies of the Software, and to
34
+ permit persons to whom the Software is furnished to do so, subject to
35
+ the following conditions:
36
+
37
+ The above copyright notice and this permission notice shall be
38
+ included in all copies or substantial portions of the Software.
39
+
40
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
41
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
42
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
43
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
44
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
45
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
46
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README_RAILS.rdoc ADDED
@@ -0,0 +1,58 @@
1
+ = RTeX for Rails
2
+
3
+ == Installation
4
+
5
+ sudo gem install rtex
6
+
7
+ Rails 2.0.X, 2.1+ in vendor/plugins (not recommended):
8
+ rtex --install /path/to/rails/app
9
+
10
+ Or, as a Rails 2.1+ gem dependency, just add the following
11
+ to your config/environment.rb:
12
+ config.gem 'rtex'
13
+
14
+ == Dependencies
15
+
16
+ * Rails >= 2.0.1
17
+
18
+ == Usage
19
+
20
+ Create files pdf.rtex extensions (eg, index.pdf.rtex) using standard LaTeX markup.
21
+
22
+ * Layouts are supported, eg: application.pdf.rtex
23
+ * Partials are supported, eg: _item.pdf.rtex
24
+
25
+ === Example
26
+
27
+ With the following:
28
+
29
+ # In config/initializers/mime_types.rb (or environment.rb in older Rails)
30
+ Mime::Type.register "application/pdf", :pdf
31
+
32
+ # app/controllers/items_controller.rb
33
+ def index
34
+ @items = Item.find(:all)
35
+ respond_to do |format|
36
+ format.html # We support the normal HTML view as well
37
+ format.pdf
38
+ end
39
+ end
40
+
41
+ # app/views/items/index.pdf.rtex
42
+ \section*{Items}
43
+ \begin{itemize}
44
+ <%= render :partial => @items %>
45
+ \end{itemize}
46
+
47
+ # app/views/items/_item.pdf.rtex
48
+ \item <%=l item.name %> \\
49
+
50
+ # app/layouts/application.pdf.rtex
51
+ \documentclass[12pt]{article}
52
+ \begin{document}
53
+ <%= yield %>
54
+ \end{document}
55
+
56
+ If you hit /items.pdf, you end up with a nice PDF listing of items.
57
+
58
+ Obviously a simplistic example.
data/Rakefile ADDED
@@ -0,0 +1,22 @@
1
+ require 'rubygems'
2
+ require 'echoe'
3
+
4
+ require File.dirname(__FILE__) << "/lib/rtex/version"
5
+
6
+ Echoe.new 'rtex' do |p|
7
+ p.version = RTeX::Version::STRING
8
+ p.author = ['Bruce Williams', 'Wiebe Cazemier']
9
+ p.email = 'bruce@codefluency.com'
10
+ p.project = 'rtex'
11
+ p.summary = "LaTeX preprocessor for PDF generation; Rails plugin"
12
+ p.url = "http://rtex.rubyforge.org"
13
+ p.include_rakefile = true
14
+ p.development_dependencies = %w(Shoulda echoe)
15
+ p.rcov_options = '--exclude gems --exclude version.rb --sort coverage --text-summary --html -o coverage'
16
+ p.ignore_pattern = /^(pkg|doc|site)|\.svn|CVS|\.bzr|\.DS|\.git/
17
+ p.rubygems_version = nil
18
+ end
19
+
20
+ task :coverage do
21
+ system "open coverage/index.html" if PLATFORM['darwin']
22
+ end
data/bin/rtex ADDED
@@ -0,0 +1,82 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'optparse'
4
+ require 'fileutils'
5
+
6
+ require File.dirname(__FILE__) << '/../lib/rtex'
7
+
8
+ options = {}
9
+
10
+ opts = OptionParser.new do |opts|
11
+
12
+ opts.banner = [
13
+ "RTeX v#{RTeX::Version::STRING} (c) 2006-2007 Bruce Williams, Wiebe Cazemier",
14
+ "Usage: rtex [OPTION...] FILE...\n\n"
15
+ ].join("\n")
16
+
17
+ opts.on('-l LAYOUT', '--layout LAYOUT', 'Path to layout file (use <%= yield %>)') do |layout|
18
+ if File.exists?(layout)
19
+ options[:layout] = File.read(layout)
20
+ else
21
+ STDERR.puts "Layout file not found: #{layout}"
22
+ exit 1
23
+ end
24
+ end
25
+
26
+ opts.on('-o OUTFILE', '--output OUTFILE', "Output to file (defaults to STDOUT)") do |path|
27
+ options[:outfile] = path
28
+ end
29
+
30
+ filters = RTeX.filters.keys.map { |k| k.to_s }.sort.join(', ')
31
+ opts.on('-f FILTER', '--filter FILTER', "Filter input (supported: #{filters})", "(Wraps in a basic `article' document; use --layout to customize)") do |filter|
32
+ options[:filter] = filter
33
+ end
34
+
35
+ opts.on('--no-pdf', "Don't generate PDF (just output TeX)") do
36
+ options[:tex] = true
37
+ end
38
+
39
+ opts.on('-i PATH', '--install PATH', "Install as plugin into Rails app at PATH") do |path|
40
+ unless Dir[plugins = File.join(path, 'vendor/plugins')].any?
41
+ STDERR.puts "Could not find application at #{path}"
42
+ exit 1
43
+ end
44
+ plugin_path = File.join(plugins, 'rtex')
45
+ FileUtils.cp_r(File.dirname(__FILE__) << '/..', plugin_path)
46
+ %w(Rakefile Manifest.txt bin tasks).each do |prune|
47
+ FileUtils.rm_rf(File.join(plugin_path, prune)) rescue nil
48
+ end
49
+ STDERR.puts "Installed at #{plugin_path}"
50
+ exit
51
+ end
52
+
53
+ opts.on('-p PROCESSOR', '--processor PROCESSOR', "Specify the LaTeX processor (default: #{RTeX::Document.options[:processor]})") do |processor|
54
+ options[:processor] = processor
55
+ end
56
+
57
+ opts.on('-h', '--help', "Show this message\n")
58
+ opts.separator "With no FILEs, or when FILE is -, read from standard input."
59
+
60
+ opts.on_tail do
61
+ STDERR.puts opts
62
+ exit
63
+ end
64
+ end
65
+ opts.parse!(ARGV)
66
+
67
+ if options[:filter] && !options[:layout]
68
+ STDERR.puts "Warning: Using default `article' layout (see --help on '--layout')"
69
+ options[:layout] = RTeX.basic_layout
70
+ end
71
+
72
+ RTeX::Document.create(ARGF.read, options) do |document|
73
+ document.to_pdf do |filename|
74
+ begin
75
+ location = File.expand_path options[:outfile]
76
+ FileUtils.move filename, location
77
+ rescue
78
+ STDOUT.print File.read(filename)
79
+ end
80
+ end
81
+ end
82
+
data/init.rb ADDED
@@ -0,0 +1 @@
1
+ require File.dirname(__FILE__) << "/rails/init"
data/lib/rtex.rb ADDED
@@ -0,0 +1,37 @@
1
+ $:.unshift(File.dirname(__FILE__) << '/rtex')
2
+
3
+ require 'document'
4
+ require 'version'
5
+
6
+ module RTeX
7
+
8
+ # Load code to initialize RTeX for framework
9
+ def self.framework(name)
10
+ require File.dirname(__FILE__) << "/rtex/framework/#{name}"
11
+ framework = ::RTeX::Framework.const_get(name.to_s.capitalize)
12
+ framework.setup
13
+ end
14
+
15
+ def self.filters #:nodoc:
16
+ @filters ||= {}
17
+ end
18
+
19
+ def self.basic_layout #:nodoc:
20
+ "\\documentclass[12pt]{article}\n\\begin{document}\n<%= yield %>\n\\end{document}"
21
+ end
22
+
23
+ # Define a processing filter
24
+ # call-seq:
25
+ # filter(:name) { |text_to_transform| ... } # => result
26
+ def self.filter(name, &block)
27
+ filters[name.to_s] = block
28
+ end
29
+
30
+ filter :textile do |source|
31
+ require File.dirname(__FILE__) << '/../vendor/instiki/redcloth_for_tex'
32
+ RedClothForTex.new(source).to_tex
33
+ end
34
+
35
+ end
36
+
37
+
@@ -0,0 +1,245 @@
1
+ require 'erb'
2
+ require 'escaping'
3
+ require 'tempdir'
4
+
5
+ module RTeX
6
+ class Document
7
+ extend Escaping
8
+
9
+ class FilterError < ::StandardError; end
10
+ class GenerationError < ::StandardError; end
11
+ class ExecutableNotFoundError < ::StandardError; end
12
+
13
+ # Create a new +RTeX::Document+. A temporary directory will be created
14
+ # for the lifetime of the document, and then destroyed at the end of the block.
15
+ #
16
+ # RTeX::Document.create(source, :processor => "xelatex") do |document|
17
+ # puts "working in #{document.tempdir}"
18
+ #
19
+ # document.to_pdf do |filename|
20
+ # # process PDF file
21
+ # # ...
22
+ # end
23
+ # end
24
+ #
25
+ # Options passed to +#create+ are the same as those for +#new+.
26
+ #
27
+ # To specify which temporary directory should be created for processing the
28
+ # document, set +:tempdir+.
29
+ #
30
+ def self.create(content, options={})
31
+ Tempdir.open(options[:tempdir]) do |dir|
32
+ doc = Document.new(content, options.merge(:tempdir => dir))
33
+ yield doc
34
+ end
35
+ end
36
+
37
+ # Create a new +RTeX::Document+ in either the current directory (default)
38
+ # or a specified, pre-existing directory.
39
+ #
40
+ # The +content+ parameter should contain the document source.
41
+ #
42
+ # The +options+ hash may contain:
43
+ # [+:processor+] Executable with which to output the document
44
+ # (default: 'pdflatex')
45
+ # [+:preprocessor+] Executable to use during preprocessing (particularly
46
+ # for longer documents containing a table-of-contents or
47
+ # bibliography section (default: 'latex')
48
+ # [+:preprocess+] Either a boolean specifying whether to preprocess the
49
+ # input file(s), or an integer for the number of times to
50
+ # preprocess (default: false / 0)
51
+ # [+:tmpdir+] Location of temporary directory (default: +Dir.getwd+)
52
+ # [+:shell_redirect+] Option redirection for shell output,
53
+ # e.g. +"> /dev/null 2>&1"+ (default: +nil+).
54
+ #
55
+ def initialize(content, options={})
56
+ @options = self.class.options.merge(options)
57
+ if @options[:processed]
58
+ @source = content
59
+ else
60
+ @erb = ERB.new(content)
61
+ end
62
+ end
63
+
64
+ # Get the compiled source for the entire document
65
+ def source(binding=nil) #:nodoc:
66
+ @source ||= wrap_in_layout do
67
+ filter @erb.result(binding)
68
+ end
69
+ end
70
+
71
+ # Process through defined filter
72
+ def filter(text) #:nodoc:
73
+ return text unless @options[:filter]
74
+ if (process = RTeX.filters[@options[:filter]])
75
+ process[text]
76
+ else
77
+ raise FilterError, "No `#{@options[:filter]}' filter"
78
+ end
79
+ end
80
+
81
+ # Wrap content in optional layout
82
+ def wrap_in_layout #:nodoc:
83
+ if @options[:layout]
84
+ ERB.new(@options[:layout]).result(binding)
85
+ else
86
+ yield
87
+ end
88
+ end
89
+
90
+ # Generate PDF output:
91
+ #
92
+ # to_pdf # => PDF in a String
93
+ # to_pdf { |filename| ... }
94
+ #
95
+ def to_pdf(binding=nil, &file_handler)
96
+ process_pdf_from(source(binding), &file_handler)
97
+ end
98
+
99
+ def processor #:nodoc:
100
+ @processor ||= check_path_for @options[:processor]
101
+ end
102
+
103
+ def preprocessor #:nodoc:
104
+ @preprocessor ||= check_path_for @options[:preprocessor]
105
+ end
106
+
107
+ def system_path #:nodoc:
108
+ ENV['PATH']
109
+ end
110
+
111
+ def self.options #:nodoc:
112
+ @options ||= {
113
+ :preprocessor => 'latex',
114
+ :preprocess => false,
115
+ :processor => 'pdflatex',
116
+ :shell_redirect => nil,
117
+ :tex_inputs => nil,
118
+ :tempdir => Dir.getwd # Current directory unless otherwise set
119
+ }
120
+ end
121
+
122
+ private
123
+
124
+ # Verify existence of executable in search path
125
+ def check_path_for(command)
126
+ unless FileTest.executable?(command) || system_path.split(":").any?{ |path| FileTest.executable?(File.join(path, command))}
127
+ raise ExecutableNotFoundError, command
128
+ end
129
+ command
130
+ end
131
+
132
+ # Basic processing
133
+ #
134
+ # The general call sequence is:
135
+ # #to_pdf (from user) => #source (ruby compile) => #process_pdf_from => #prepare => #preprocess! => #process! => #verify! => return as string or output filename
136
+ #
137
+ def process_pdf_from(input, &file_handler)
138
+ prepare input
139
+ if generating?
140
+ preprocess_count.times { preprocess! }
141
+ process!
142
+ verify!
143
+ end
144
+ if file_handler
145
+ yield result_file
146
+ else
147
+ result_as_string
148
+ end
149
+ end
150
+
151
+ # Save the Ruby-compiled document source to a file
152
+ # It is then ready for LaTeX to compile it into a PDF
153
+ #
154
+ def prepare(input)
155
+ File.open(source_file, 'wb') { |f| f.puts input }
156
+ end
157
+
158
+ # Run LaTeX pre-processing step on the source file
159
+ def preprocess!
160
+ unless `#{environment_vars}#{preprocessor} --output-directory=#{tempdir} --interaction=nonstopmode '#{File.basename(source_file)}' #{@options[:shell_redirect]}`
161
+ raise GenerationError, "Could not preprocess using #{preprocessor}"
162
+ end
163
+ end
164
+
165
+ # Run LaTeX output generation step on the source file
166
+ def process!
167
+ unless `#{environment_vars}#{tex_inputs} #{processor} --output-directory=#{tempdir} --interaction=nonstopmode '#{File.basename(source_file)}' #{@options[:shell_redirect]}`
168
+ raise GenerationError, "Could not generate PDF using #{processor}"
169
+ end
170
+ end
171
+
172
+ # Check the output file has been generated correctly
173
+ def verify!
174
+ unless File.exists?(result_file)
175
+ raise GenerationError, "Could not find result PDF #{result_file} after generation.\nCheck #{log_file}"
176
+ end
177
+ end
178
+
179
+ # Load the output file and return its contents
180
+ def result_as_string
181
+ File.open(result_file, 'rb') { |f| f.read }
182
+ end
183
+
184
+ # Should we pre-process?
185
+ def preprocessing?
186
+ preprocess_count > 0
187
+ end
188
+
189
+ def preprocess_count
190
+ case @options[:preprocess]
191
+ when Numeric
192
+ @options[:preprocess].to_i
193
+ when true
194
+ 1
195
+ else
196
+ 0
197
+ end
198
+ end
199
+
200
+ # Compile list of extra directories to search for LaTeX packages, using
201
+ # the file or array of files held in the :tex_inputs option.
202
+ #
203
+ def tex_inputs
204
+ if inputs = @options[:tex_inputs]
205
+ inputs = [inputs].flatten.select { |i| File.exists? i }
206
+ "TEXINPUTS='#{inputs.join(':')}:'"
207
+ else
208
+ nil
209
+ end
210
+ end
211
+
212
+ # Produce a list of environment variables to prefix the process and
213
+ # preprocess commands.
214
+ #
215
+ def environment_vars
216
+ list = [tex_inputs].compact
217
+ list.empty? ? "" : list.join(" ") + " "
218
+ end
219
+
220
+ def source_file
221
+ @source_file ||= file(:tex)
222
+ end
223
+
224
+ def log_file
225
+ @log_file ||= file(:log)
226
+ end
227
+
228
+ def result_file
229
+ @result_file ||= file(@options[:tex] ? :tex : :pdf)
230
+ end
231
+
232
+ def tempdir
233
+ @options[:tempdir]
234
+ end
235
+
236
+ def file(extension)
237
+ File.join(tempdir.to_s, "document.#{extension}")
238
+ end
239
+
240
+ def generating?
241
+ !@options[:tex]
242
+ end
243
+
244
+ end
245
+ end