awhyte-rtex 2.1.2

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.
@@ -0,0 +1,28 @@
1
+ module RTeX
2
+
3
+ module Escaping
4
+
5
+ # Escape text using +replacements+
6
+ def escape(text)
7
+ replacements.inject(text.to_s) do |corpus, (pattern, replacement)|
8
+ corpus.gsub(pattern, replacement)
9
+ end
10
+ end
11
+
12
+ # List of replacements
13
+ def replacements
14
+ @replacements ||= [
15
+ [/([{}])/, '\\\\\1'],
16
+ [/\\/, '\textbackslash{}'],
17
+ [/\^/, '\textasciicircum{}'],
18
+ [/~/, '\textasciitilde{}'],
19
+ [/\|/, '\textbar{}'],
20
+ [/\</, '\textless{}'],
21
+ [/\>/, '\textgreater{}'],
22
+ [/([_$&%#])/, '\\\\\1']
23
+ ]
24
+ end
25
+
26
+ end
27
+
28
+ end
@@ -0,0 +1,13 @@
1
+ module RTeX
2
+
3
+ module Framework #:nodoc:
4
+
5
+ module Merb #:nodoc:
6
+
7
+ # TODO
8
+
9
+ end
10
+
11
+ end
12
+
13
+ end
@@ -0,0 +1,209 @@
1
+ require 'tempfile'
2
+
3
+ module RTeX
4
+ module Framework #:nodoc:
5
+ module Rails #:nodoc:
6
+
7
+ def self.setup
8
+ RTeX::Document.options[:tempdir] = File.expand_path(File.join(RAILS_ROOT, 'tmp'))
9
+ if ActionView::Base.respond_to?(:register_template_handler)
10
+ ActionView::Base.register_template_handler(:rtex, TemplateHandler)
11
+ else
12
+ ActionView::Template.register_template_handler(:rtex, TemplateHandler)
13
+ end
14
+ ActionController::Base.send(:include, ControllerMethods)
15
+ ActionView::Base.send(:include, HelperMethods)
16
+ end
17
+
18
+
19
+ class TemplateHandler < ::ActionView::TemplateHandlers::ERB
20
+ # Due to significant changes in ActionView over the lifespan of Rails,
21
+ # tagging compiled templates to set a thread local variable flag seems
22
+ # to be the least brittle approach.
23
+ def compile(template)
24
+ # Insert assignment, but not before the #coding: line, if present
25
+ super.sub(/^(?!#)/m, "Thread.current[:_rendering_rtex] = true;\n")
26
+ end
27
+ end
28
+
29
+
30
+ module ControllerMethods
31
+
32
+ def self.included(base) #:nodoc:
33
+ base.alias_method_chain :render, :rtex
34
+ end
35
+
36
+ # Extends the base +ActionController#render+ method by checking whether
37
+ # the template is RTeX-capable and creating an RTeX::Document in that
38
+ # case.
39
+ #
40
+ # If you have view templates saved, for example, as "show.html.erb" and
41
+ # "show.pdf.rtex" in an ItemsController, one could write the controller
42
+ # action like this:
43
+ #
44
+ # def show
45
+ # # set up instance variables
46
+ # # ...
47
+ # respond_to do |format|
48
+ # format.html
49
+ # format.pdf { render :filename => "Item Information.pdf" }
50
+ # end
51
+ # end
52
+ #
53
+ # As well as the options available to a new RTeX::Document, the
54
+ # following may be supplied here:
55
+ #
56
+ # [+:disposition+] 'inline' (default) or 'attachment'
57
+ # [+:filename+] +nil+ (default) results in the final part of the
58
+ # request URL being used.
59
+ #
60
+ # To see the underlying LaTeX code that generated the PDF, create
61
+ # another view called "show.tex.rtex" which includes the single line
62
+ #
63
+ # <%= include_template_from "items/show.pdf.rtex" -%>
64
+ #
65
+ # and include the following in the controller action
66
+ #
67
+ # format.tex { render :filename => "item_information_source.tex" }
68
+ #
69
+ # This may be helpful during debugging or for saving pre-compiled parts
70
+ # of LaTeX documents for later processing into PDFs.
71
+ #
72
+ def render_with_rtex(options=nil, extra_options={}, &block)
73
+ if conditions_for_rtex(options)
74
+ render_rtex(default_template, options, extra_options, &block)
75
+ else
76
+ render_without_rtex(options, extra_options, &block)
77
+ end
78
+ end
79
+
80
+ private
81
+
82
+ def render_rtex(template, options={}, extra_options={}, &block)
83
+ RTeX::Tempdir.open do |dir|
84
+ # Make LaTeX temporary directory accessible to view
85
+ @rtex_dir = dir.to_s
86
+
87
+ # Render view into LaTeX document string
88
+ latex = render_without_rtex(options, extra_options, &block)
89
+
90
+ # HTTP response options
91
+ send_options = {
92
+ :disposition => (options.delete(:disposition) || 'inline'),
93
+ :url_based_filename => true,
94
+ :filename => (options.delete(:filename) || nil),
95
+ :type => template.mime_type.to_s }
96
+
97
+ # Document options
98
+ rtex_options = options.merge(:tempdir => dir).reverse_merge(
99
+ :processed => true,
100
+ :tex_inputs => File.join(RAILS_ROOT,'lib','latex') )
101
+
102
+ # Content type requested
103
+ content_type = template.content_type.to_sym
104
+
105
+ # Send appropriate data to client
106
+ case content_type
107
+ when :tex
108
+ send_data latex, send_options.merge(:length => latex.length)
109
+ when :pdf
110
+ pdf = RTeX::Document.new(latex, rtex_options).to_pdf
111
+ send_data pdf, send_options.merge(:length => pdf.length)
112
+ else
113
+ raise "RTeX: unknown content type requested: #{content_type}"
114
+ end
115
+ end
116
+ end
117
+
118
+ def conditions_for_rtex(options)
119
+ begin
120
+ # Do not override the +:text+ rendering, because send_data uses this
121
+ !options[:text] &&
122
+ # Check whether the default template is one managed by the
123
+ # RTeX::Framework::Rails::TemplateHandler
124
+ :rtex == default_template.extension.to_sym
125
+ rescue
126
+ false
127
+ end
128
+ end
129
+ end
130
+
131
+
132
+ module HelperMethods
133
+
134
+ # Make the supplied text safe for the LaTeX processor, in the same way
135
+ # that h() works for HTML documents.
136
+ #
137
+ def latex_escape(*args)
138
+ # Since Rails' I18n implementation aliases l() to localize(), LaTeX
139
+ # escaping should only be done if RTeX is doing the rendering.
140
+ # Otherwise, control should be be passed to localize().
141
+ if Thread.current[:_rendering_rtex]
142
+ RTeX::Document.escape(*args)
143
+ else
144
+ localize(*args)
145
+ end
146
+ end
147
+ alias :l :latex_escape
148
+
149
+ # Obtain the temporary directory RTeX is currently using
150
+ attr_reader :rtex_dir
151
+
152
+ # Copy the contents of another template into the current one, like
153
+ # rendering a partial but without have to add an underscore to the
154
+ # filename.
155
+ #
156
+ def include_template_from(from)
157
+ other_file = @template.view_paths.find_template(from).relative_path
158
+ render(:inline => File.read(other_file))
159
+ end
160
+
161
+ # Include an image file into the current LaTeX document.
162
+ #
163
+ # For example,
164
+ #
165
+ # \includegraphics{<%= graphics_file("some file.png") -%>}
166
+ #
167
+ # will copy "public/images/some file.png" to a the current RTeX
168
+ # temporary directory (with a LaTeX-safe filename) and reference it in
169
+ # the document like this:
170
+ #
171
+ # \includegraphics{/tmp/rtex/rtex-random-number/image-file.png}
172
+ #
173
+ def graphics_file(file, reference_original_file=false)
174
+ source = Pathname.new file
175
+ source = Pathname.new(ActionView::Helpers::ASSETS_DIR) + "images" + source unless source.absolute?
176
+
177
+ if reference_original_file
178
+ source.to_s
179
+ else
180
+ destination = Pathname.new(@rtex_dir) + latex_safe_filename(source.basename)
181
+ FileUtils.copy source, destination
182
+ destination.to_s
183
+ end
184
+ end
185
+
186
+ # Save the supplied image data to the RTeX temporary directory and
187
+ # return the filename for inclusion in the current document.
188
+ #
189
+ # \includegraphics{<%= graphics_data(object.to_png) -%>}
190
+ #
191
+ def graphics_data(data)
192
+ destination = Pathname.new(@rtex_dir) + latex_safe_filename(filename)
193
+ File.open(destination, "w") { |f| f.write data }
194
+ dst.to_s
195
+ end
196
+
197
+ private
198
+
199
+ def latex_safe_filename(input)
200
+ # Replace non-ASCII characters
201
+ input = ActiveSupport::Inflector.transliterate(input.to_s).to_s
202
+ # Replace non-LaTeX-friendly characters with a dash
203
+ input.gsub(/[^a-z0-9\-_\+\.]+/i, '-')
204
+ end
205
+
206
+ end
207
+ end
208
+ end
209
+ end
@@ -0,0 +1,107 @@
1
+ require 'fileutils'
2
+ require 'tmpdir'
3
+
4
+ module RTeX
5
+
6
+ # Utility class to manage the lifetime of a temporary directory in which
7
+ # LaTeX can do its processing
8
+ #
9
+ class Tempdir
10
+
11
+ # Create a new temporary directory, yield for processing, then remove it.
12
+ #
13
+ # RTeX::Tempdir.open do |tempdir|
14
+ # # Use newly created temporary directory
15
+ # # ...
16
+ # end
17
+ #
18
+ # When the block completes, the directory is removed.
19
+ #
20
+ # Arguments can be either an specific directory name,
21
+ #
22
+ # RTeX::Tempdir.open("/tmp/somewhere") do ...
23
+ #
24
+ # or options to assist the generation of a randomly named unique directory,
25
+ #
26
+ # RTeX::Tempdir.open(:parent_path => PARENT, :basename => BASENAME) do ...
27
+ #
28
+ # which would result in a new directory
29
+ # "[PARENT]/rtex/[BASENAME]-[random hash]/" being created.
30
+ #
31
+ # The default +:parent_path+ is +Dir.tmpdir", and +:basename+ 'rtex'.
32
+ #
33
+ def self.open(*args)
34
+ tempdir = new(*args)
35
+ tempdir.create!
36
+
37
+ # Yield the path and wait for the block to finish
38
+ result = yield tempdir
39
+
40
+ # We don't remove the temporary directory when exceptions occur,
41
+ # so that the source of the exception can be dubbed (logfile kept)
42
+ tempdir.remove!
43
+ result
44
+ end
45
+
46
+ # Manually control tempdir creation and removal. Accepts the same arguments
47
+ # as +RTeX::Tempdir.open+, but the user must call +#create!+ and +#remove!+
48
+ # themselves:
49
+ #
50
+ # tempdir = RTeX::Tempdir.new
51
+ # tempdir.create!
52
+ # # Use the temporary directory
53
+ # # ...
54
+ # tempdir.remove!
55
+ #
56
+ def initialize(*args)
57
+ options = args.last.is_a?(Hash) ? options.pop : {}
58
+ specific_path = args.first
59
+
60
+ if specific_path
61
+ @path = specific_path
62
+ else
63
+ @parent_path = options[:parent_path] || Dir.tmpdir
64
+ @basename = options[:basename] || 'rtex'
65
+ end
66
+ end
67
+
68
+ def create!
69
+ FileUtils.mkdir_p path
70
+ @removed = false
71
+ path
72
+ end
73
+
74
+ # Is the temporary directory present on the filesystem
75
+ def exists?
76
+ File.exists?(path)
77
+ end
78
+
79
+ # The filesystem location of the temporary directory
80
+ def path
81
+ @path ||= File.expand_path(File.join(@parent_path, 'rtex', "#{@basename}-#{self.class.uuid}"))
82
+ end
83
+
84
+ # Return the +#path+ for use in string expansion
85
+ alias :to_s :path
86
+
87
+ # Forcibly remove this temporary directory
88
+ def remove!
89
+ return false if @removed
90
+ FileUtils.rm_rf path
91
+ @removed = true
92
+ end
93
+
94
+ # Try using uuidgen, but if that doesn't work drop down to
95
+ # a poor-man's UUID; timestamp, thread & object hashes
96
+ # Note: I don't want to add any dependencies (so no UUID library)
97
+ #
98
+ def self.uuid
99
+ if (result = `uuidgen`.strip rescue nil).empty?
100
+ "#{Time.now.to_i}-#{Thread.current.hash}-#{hash}"
101
+ else
102
+ result
103
+ end
104
+ end
105
+
106
+ end
107
+ end
@@ -0,0 +1,77 @@
1
+ # (The MIT License)
2
+ #
3
+ # Copyright (c) 2008 Jamis Buck <jamis@37signals.com>,
4
+ # with modifications by Bruce Williams <bruce@codefluency.com>
5
+ #
6
+ # Permission is hereby granted, free of charge, to any person obtaining
7
+ # a copy of this software and associated documentation files (the
8
+ # 'Software'), to deal in the Software without restriction, including
9
+ # without limitation the rights to use, copy, modify, merge, publish,
10
+ # distribute, sublicense, and/or sell copies of the Software, and to
11
+ # permit persons to whom the Software is furnished to do so, subject to
12
+ # the following conditions:
13
+ #
14
+ # The above copyright notice and this permission notice shall be
15
+ # included in all copies or substantial portions of the Software.
16
+ #
17
+ # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
18
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20
+ # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
21
+ # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
22
+ # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
23
+ # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24
+ module RTeX
25
+
26
+
27
+ # A class for describing the current version of a library. The version
28
+ # consists of three parts: the +major+ number, the +minor+ number, and the
29
+ # +tiny+ (or +patch+) number.
30
+ class Version
31
+
32
+ # A convenience method for instantiating a new Version instance with the
33
+ # given +major+, +minor+, and +tiny+ components.
34
+ def self.[](major, minor, tiny)
35
+ new(major, minor, tiny)
36
+ end
37
+
38
+ attr_reader :major, :minor, :tiny
39
+
40
+ # Create a new Version object with the given components.
41
+ def initialize(major, minor, tiny)
42
+ @major, @minor, @tiny = major, minor, tiny
43
+ end
44
+
45
+ # Compare this version to the given +version+ object.
46
+ def <=>(version)
47
+ to_i <=> version.to_i
48
+ end
49
+
50
+ # Converts this version object to a string, where each of the three
51
+ # version components are joined by the '.' character. E.g., 2.0.0.
52
+ def to_s
53
+ @to_s ||= [@major, @minor, @tiny].join(".")
54
+ end
55
+
56
+ # Converts this version to a canonical integer that may be compared
57
+ # against other version objects.
58
+ def to_i
59
+ @to_i ||= @major * 1_000_000 + @minor * 1_000 + @tiny
60
+ end
61
+
62
+ def to_a
63
+ [@major, @minor, @tiny]
64
+ end
65
+
66
+ MAJOR = 2
67
+ MINOR = 1
68
+ TINY = 1
69
+
70
+ # The current version as a Version instance
71
+ CURRENT = new(MAJOR, MINOR, TINY)
72
+ # The current version as a String
73
+ STRING = CURRENT.to_s
74
+
75
+ end
76
+
77
+ end
data/rails/init.rb ADDED
@@ -0,0 +1,2 @@
1
+ require 'rtex'
2
+ RTeX.framework :rails
data/rtex.gemspec ADDED
@@ -0,0 +1,41 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{rtex}
5
+ s.version = "2.1.2"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Bruce Williams, Wiebe Cazemier"]
9
+ s.date = %q{2009-09-24}
10
+ s.default_executable = %q{rtex}
11
+ s.description = %q{LaTeX preprocessor for PDF generation; Rails plugin}
12
+ s.email = %q{bruce@codefluency.com}
13
+ s.executables = ["rtex"]
14
+ s.extra_rdoc_files = ["bin/rtex", "CHANGELOG", "lib/rtex/document.rb", "lib/rtex/escaping.rb", "lib/rtex/framework/merb.rb", "lib/rtex/framework/rails.rb", "lib/rtex/tempdir.rb", "lib/rtex/version.rb", "lib/rtex.rb", "README.rdoc", "README_RAILS.rdoc"]
15
+ s.files = ["bin/rtex", "CHANGELOG", "init.rb", "lib/rtex/document.rb", "lib/rtex/escaping.rb", "lib/rtex/framework/merb.rb", "lib/rtex/framework/rails.rb", "lib/rtex/tempdir.rb", "lib/rtex/version.rb", "lib/rtex.rb", "Manifest", "rails/init.rb", "Rakefile", "README.rdoc", "README_RAILS.rdoc", "test/document_test.rb", "test/filter_test.rb", "test/fixtures/first.tex", "test/fixtures/first.tex.erb", "test/fixtures/fragment.tex.erb", "test/fixtures/text.textile", "test/tempdir_test.rb", "test/test_helper.rb", "vendor/instiki/LICENSE", "vendor/instiki/redcloth_for_tex.rb", "rtex.gemspec"]
16
+ s.has_rdoc = true
17
+ s.homepage = %q{http://rtex.rubyforge.org}
18
+ s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Rtex", "--main", "README.rdoc"]
19
+ s.require_paths = ["lib"]
20
+ s.rubyforge_project = %q{rtex}
21
+ s.rubygems_version = %q{1.3.1}
22
+ s.summary = %q{LaTeX preprocessor for PDF generation; Rails plugin}
23
+ s.test_files = ["test/document_test.rb", "test/filter_test.rb", "test/tempdir_test.rb", "test/test_helper.rb"]
24
+
25
+ if s.respond_to? :specification_version then
26
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
27
+ s.specification_version = 2
28
+
29
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
30
+ s.add_development_dependency(%q<Shoulda>, [">= 0"])
31
+ s.add_development_dependency(%q<echoe>, [">= 0"])
32
+ else
33
+ s.add_dependency(%q<Shoulda>, [">= 0"])
34
+ s.add_dependency(%q<echoe>, [">= 0"])
35
+ end
36
+ else
37
+ s.add_dependency(%q<Shoulda>, [">= 0"])
38
+ s.add_dependency(%q<echoe>, [">= 0"])
39
+ end
40
+ end
41
+