cf-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.
- checksums.yaml +7 -0
- data/README.rdoc +53 -0
- data/Rakefile +22 -0
- data/lib/rtex/document.rb +172 -0
- data/lib/rtex/escaping.rb +33 -0
- data/lib/rtex/helpers.rb +22 -0
- data/lib/rtex/railtie.rb +19 -0
- data/lib/rtex/tempdir.rb +52 -0
- data/lib/rtex/template_handler.rb +71 -0
- data/lib/rtex/version.rb +77 -0
- data/lib/rtex.rb +7 -0
- data/test/document_test.rb +86 -0
- data/test/filter_test.rb +24 -0
- data/test/fixtures/first.tex +50 -0
- data/test/fixtures/first.tex.erb +48 -0
- data/test/fixtures/fragment.tex.erb +1 -0
- data/test/fixtures/text.textile +4 -0
- data/test/tempdir_test.rb +67 -0
- data/test/test_helper.rb +26 -0
- metadata +110 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 2cbc2f55ee737e1a2975f05d000d78a88b833c02334346a3d3231117b0df84f6
|
4
|
+
data.tar.gz: 9317e517b43d544033e96fd0fa8d6df79229584f9b88cf165257165f33057c25
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 000efdd44938b7280c5a07ff1a0a2729d9b654a7a03447aceb6aa3c5f91b1674edf35a0368ea6b8f778d9d854a7e032ad2c0fd47bc78a3dedd6415985fd8b942
|
7
|
+
data.tar.gz: d43b5912f6888dced779a3ce1ee6d8cee6f78dd5b834955e8aeccebb95b36b5e5dae273fd449c2e662f83ef1d6453fcd56b79c0a470b17911094acffdbdc5dd3
|
data/README.rdoc
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
== Changes from the original
|
2
|
+
* Upgraded for rails 3/4 integration, removed merb and standalone support
|
3
|
+
* Optionaly setting a password on generated PDFs using the pdf-toolkit gem
|
4
|
+
* Writes last generated intermediate latex document to tmp/last_document.latex in development mode
|
5
|
+
* Considers all latex escaped text html_safe
|
6
|
+
* latex_simple_format method added so that new lines can be rendered properly in latex.
|
7
|
+
|
8
|
+
= RTeX: TeX/PDF Generation for Ruby
|
9
|
+
|
10
|
+
Project homepage (FAQ, manual, documentation, contact info): http://rtex.rubyforge.org
|
11
|
+
|
12
|
+
Original source repository at: http://github.com/bruce/rtex
|
13
|
+
|
14
|
+
== Dependencies
|
15
|
+
|
16
|
+
* pdflatex executable, available in modern teTeX distributions
|
17
|
+
* Requires Rails >= 2.0.1 if used as a plugin.
|
18
|
+
|
19
|
+
== Usage
|
20
|
+
|
21
|
+
For use as a standalone executable, see `rtex --help'
|
22
|
+
|
23
|
+
For use as a Rails plugin, see README_RAILS.rdoc
|
24
|
+
|
25
|
+
== More Information
|
26
|
+
|
27
|
+
Additional help may be available at the project homepage,
|
28
|
+
http://rtex.rubyforge.org
|
29
|
+
|
30
|
+
== License
|
31
|
+
|
32
|
+
(The MIT License)
|
33
|
+
|
34
|
+
Copyright (c) 2006-2008 Bruce Williams, Wiebe Cazemier
|
35
|
+
|
36
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
37
|
+
a copy of this software and associated documentation files (the
|
38
|
+
'Software'), to deal in the Software without restriction, including
|
39
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
40
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
41
|
+
permit persons to whom the Software is furnished to do so, subject to
|
42
|
+
the following conditions:
|
43
|
+
|
44
|
+
The above copyright notice and this permission notice shall be
|
45
|
+
included in all copies or substantial portions of the Software.
|
46
|
+
|
47
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
48
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
49
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
50
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
51
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
52
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
53
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
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 = 'Aaron Pederson'
|
9
|
+
p.email = 'aaron.pederson@castingnetworks.com'
|
10
|
+
p.project = 'cf-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
|
@@ -0,0 +1,172 @@
|
|
1
|
+
require 'erb'
|
2
|
+
require 'ostruct'
|
3
|
+
require 'tmpdir'
|
4
|
+
|
5
|
+
module RTeX
|
6
|
+
|
7
|
+
class Document
|
8
|
+
|
9
|
+
extend Escaping
|
10
|
+
|
11
|
+
class FilterError < ::StandardError; end
|
12
|
+
class GenerationError < ::StandardError; end
|
13
|
+
class ExecutableNotFoundError < ::StandardError; end
|
14
|
+
|
15
|
+
# Default options
|
16
|
+
# [+:preprocess+] Are we preprocessing? Default is +false+
|
17
|
+
# [+:preprocessor+] Executable to use during preprocessing (generating TOCs, etc). Default is +latex+
|
18
|
+
# [+:shell_redirect+] Option redirection for shell output (eg, +"> /dev/null 2>&1"+ ). Default is +nil+.
|
19
|
+
# [+:tmpdir+] Location of temporary directory (default: +Dir.tmpdir+)
|
20
|
+
def self.options
|
21
|
+
@options ||= {
|
22
|
+
:preprocessor => 'latex',
|
23
|
+
:preprocess => false,
|
24
|
+
:processor => 'pdflatex',
|
25
|
+
#
|
26
|
+
:shell_redirect => nil,
|
27
|
+
# Temporary Directory
|
28
|
+
:tempdir => Dir.tmpdir
|
29
|
+
}
|
30
|
+
end
|
31
|
+
|
32
|
+
def initialize(content, options={})
|
33
|
+
@options = self.class.options.merge(options)
|
34
|
+
if @options[:processed]
|
35
|
+
@source = content
|
36
|
+
else
|
37
|
+
@erb = ERB.new(content)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# Get the source for the entire
|
42
|
+
def source(binding=nil) #:nodoc:
|
43
|
+
@source ||= wrap_in_layout do
|
44
|
+
filter @erb.result(binding)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# Process through defined filter
|
49
|
+
def filter(text) #:nodoc:
|
50
|
+
return text unless @options[:filter]
|
51
|
+
if (process = RTeX.filters[@options[:filter]])
|
52
|
+
process[text]
|
53
|
+
else
|
54
|
+
raise FilterError, "No `#{@options[:filter]}' filter"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# Wrap content in optional layout
|
59
|
+
def wrap_in_layout #:nodoc:
|
60
|
+
if @options[:layout]
|
61
|
+
ERB.new(@options[:layout]).result(binding)
|
62
|
+
else
|
63
|
+
yield
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
# Generate PDF from
|
68
|
+
# call-seq:
|
69
|
+
# to_pdf # => PDF in a String
|
70
|
+
# to_pdf { |filename| ... }
|
71
|
+
def to_pdf(binding=nil, &file_handler)
|
72
|
+
process_pdf_from(source(binding), &file_handler)
|
73
|
+
end
|
74
|
+
|
75
|
+
def processor #:nodoc:
|
76
|
+
@processor ||= check_path_for @options[:processor]
|
77
|
+
end
|
78
|
+
|
79
|
+
def preprocessor #:nodoc:
|
80
|
+
@preprocessor ||= check_path_for @options[:preprocessor]
|
81
|
+
end
|
82
|
+
|
83
|
+
def system_path #:nodoc:
|
84
|
+
ENV['PATH']
|
85
|
+
end
|
86
|
+
|
87
|
+
#######
|
88
|
+
private
|
89
|
+
#######
|
90
|
+
|
91
|
+
# Verify existence of executable in search path
|
92
|
+
def check_path_for(command)
|
93
|
+
unless FileTest.executable?(command) || system_path.split(":").any?{ |path| FileTest.executable?(File.join(path, command))}
|
94
|
+
raise ExecutableNotFoundError, command
|
95
|
+
end
|
96
|
+
command
|
97
|
+
end
|
98
|
+
|
99
|
+
# Basic processing
|
100
|
+
def process_pdf_from(input, &file_handler)
|
101
|
+
Tempdir.open(@options[:tempdir]) do |tempdir|
|
102
|
+
prepare input
|
103
|
+
if generating?
|
104
|
+
preprocess! if preprocessing?
|
105
|
+
process!
|
106
|
+
verify!
|
107
|
+
end
|
108
|
+
if file_handler
|
109
|
+
yield full_path_in(tempdir.path)
|
110
|
+
else
|
111
|
+
result_as_string
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def process!
|
117
|
+
unless `#{processor} --interaction=nonstopmode '#{source_file}' #{@options[:shell_redirect]}`
|
118
|
+
raise GenerationError, "Could not generate PDF using #{processor}"
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
def preprocess!
|
123
|
+
unless `#{preprocessor} --interaction=nonstopmode '#{source_file}' #{@options[:shell_redirect]}`
|
124
|
+
raise GenerationError, "Could not preprocess using #{preprocessor}"
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
def preprocessing?
|
129
|
+
@options[:preprocess]
|
130
|
+
end
|
131
|
+
|
132
|
+
def source_file
|
133
|
+
@source_file ||= file(:tex)
|
134
|
+
end
|
135
|
+
|
136
|
+
def log_file
|
137
|
+
@log_file ||= file(:log)
|
138
|
+
end
|
139
|
+
|
140
|
+
def result_file
|
141
|
+
@result_file ||= file(@options[:tex] ? :tex : :pdf)
|
142
|
+
end
|
143
|
+
|
144
|
+
def file(extension)
|
145
|
+
"document.#{extension}"
|
146
|
+
end
|
147
|
+
|
148
|
+
def generating?
|
149
|
+
!@options[:tex]
|
150
|
+
end
|
151
|
+
|
152
|
+
def verify!
|
153
|
+
unless File.exists?(result_file)
|
154
|
+
raise GenerationError, "Could not find result PDF #{result_file} after generation.\nCheck #{File.expand_path(log_file)}"
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
def prepare(input)
|
159
|
+
File.open(source_file, 'wb') { |f| f.puts input }
|
160
|
+
end
|
161
|
+
|
162
|
+
def result_as_string
|
163
|
+
File.open(result_file, 'rb') { |f| f.read }
|
164
|
+
end
|
165
|
+
|
166
|
+
def full_path_in(directory)
|
167
|
+
File.expand_path(File.join(directory, result_file))
|
168
|
+
end
|
169
|
+
|
170
|
+
end
|
171
|
+
|
172
|
+
end
|
@@ -0,0 +1,33 @@
|
|
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.html_safe
|
10
|
+
end
|
11
|
+
|
12
|
+
def simple_format(text)
|
13
|
+
text=escape(text)
|
14
|
+
text.gsub(/([\n])/, '\newline{}').html_safe
|
15
|
+
end
|
16
|
+
|
17
|
+
# List of replacements
|
18
|
+
def replacements
|
19
|
+
@replacements ||= [
|
20
|
+
[/([{}])/, '\\\\\1'],
|
21
|
+
[/\\/, '\textbackslash{}'],
|
22
|
+
[/\^/, '\textasciicircum{}'],
|
23
|
+
[/~/, '\textasciitilde{}'],
|
24
|
+
[/\|/, '\textbar{}'],
|
25
|
+
[/\</, '\textless{}'],
|
26
|
+
[/\>/, '\textgreater{}'],
|
27
|
+
[/([_$&%#])/, '\\\\\1']
|
28
|
+
]
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
data/lib/rtex/helpers.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
module RTeX
|
2
|
+
module Helpers
|
3
|
+
def latex_escape(*args)
|
4
|
+
# Since Rails' I18n implementation aliases l() to localize(), LaTeX
|
5
|
+
# escaping should only be done if RTeX is doing the rendering.
|
6
|
+
# Otherwise, control should be be passed to localize().
|
7
|
+
if Thread.current[:_rendering_rtex]
|
8
|
+
RTeX::Document.escape(*args)
|
9
|
+
else
|
10
|
+
localize(*args)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def latex_simple_format(*args)
|
15
|
+
RTeX::Document.simple_format(*args)
|
16
|
+
end
|
17
|
+
|
18
|
+
alias :l :latex_escape
|
19
|
+
alias :sf :latex_simple_format
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
data/lib/rtex/railtie.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
module RTeX
|
2
|
+
class Railtie < Rails::Railtie
|
3
|
+
initializer "rtex.add_template_handler" do
|
4
|
+
ActionView::Template.register_template_handler("rtex",
|
5
|
+
RTeX::TemplateHandler)
|
6
|
+
end
|
7
|
+
initializer "rtex.add_controller_methods" do
|
8
|
+
ActionController::Base.send(:include, RTeX::ControllerMethods)
|
9
|
+
end
|
10
|
+
initializer "rtex.add_helper_methods" do
|
11
|
+
ActionView::Base.send(:include, RTeX::Helpers)
|
12
|
+
end
|
13
|
+
initializer "rtex.set_tempdir" do
|
14
|
+
ActiveSupport.on_load(:action_controller) do
|
15
|
+
Document.options[:tempdir] = Rails.root.join("tmp")
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/lib/rtex/tempdir.rb
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
|
3
|
+
module RTeX
|
4
|
+
|
5
|
+
class Tempdir #:nodoc:
|
6
|
+
|
7
|
+
def self.open(parent_path=RTeX::Document.options[:tempdir])
|
8
|
+
tempdir = new(parent_path)
|
9
|
+
FileUtils.mkdir_p tempdir.path
|
10
|
+
result = Dir.chdir(tempdir.path) do
|
11
|
+
yield tempdir
|
12
|
+
end
|
13
|
+
# We don't remove the temporary directory when exceptions occur,
|
14
|
+
# so that the source of the exception can be dubbed (logfile kept)
|
15
|
+
tempdir.remove!
|
16
|
+
result
|
17
|
+
end
|
18
|
+
|
19
|
+
def initialize(parent_path, basename='rtex')
|
20
|
+
@parent_path = parent_path
|
21
|
+
@basename = basename
|
22
|
+
@removed = false
|
23
|
+
end
|
24
|
+
|
25
|
+
def path
|
26
|
+
@path ||= File.expand_path(File.join(@parent_path, 'rtex', "#{@basename}-#{uuid}"))
|
27
|
+
end
|
28
|
+
|
29
|
+
def remove!
|
30
|
+
return false if @removed
|
31
|
+
FileUtils.rm_rf path
|
32
|
+
@removed = true
|
33
|
+
end
|
34
|
+
|
35
|
+
#######
|
36
|
+
private
|
37
|
+
#######
|
38
|
+
|
39
|
+
# Try using uuidgen, but if that doesn't work drop down to
|
40
|
+
# a poor-man's UUID; timestamp, thread & object hashes
|
41
|
+
# Note: I don't want to add any dependencies (so no UUID library)
|
42
|
+
def uuid
|
43
|
+
if (result = `uuidgen`.strip rescue nil).empty?
|
44
|
+
"#{Time.now.to_i}-#{Thread.current.hash}-#{hash}"
|
45
|
+
else
|
46
|
+
result
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
|
2
|
+
module RTeX
|
3
|
+
|
4
|
+
class TemplateHandler < ActionView::Template::Handlers::ERB
|
5
|
+
def call(template)
|
6
|
+
super.sub(/^(?!#)/m, "Thread.current[:_rendering_rtex] = true;\n")
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
module ControllerMethods
|
11
|
+
def self.included(base)
|
12
|
+
base.alias_method_chain :render, :rtex
|
13
|
+
end
|
14
|
+
|
15
|
+
def render_with_rtex(options = nil, *args, &block)
|
16
|
+
# pp args
|
17
|
+
orig = render_without_rtex(options, *args, &block)
|
18
|
+
# CF HACK
|
19
|
+
|
20
|
+
File.open(Rails.root.join("tmp","last_document.latex"), "w"){|f| f.puts orig.to_s.force_encoding('UTF-8')} if Rails.env.development?
|
21
|
+
|
22
|
+
# old:
|
23
|
+
# File.open(Rails.root.join("tmp","last_document.latex"), "w"){|f| f.puts orig} if Rails.env.development?
|
24
|
+
|
25
|
+
# END CF HACK
|
26
|
+
if Thread.current[:_rendering_rtex] == true
|
27
|
+
Thread.current[:_rendering_rtex] = false
|
28
|
+
options = {} if options.class != Hash
|
29
|
+
Document.new(orig, options.merge(:processed => true)).to_pdf do |f|
|
30
|
+
serve_file = Tempfile.new('rtex-pdf')
|
31
|
+
|
32
|
+
if options[:user_pw].present? && options[:owner_pw].present?
|
33
|
+
pdf_path = File.dirname(f)
|
34
|
+
pdf_name = File.basename(f, '.pdf')
|
35
|
+
encrypted_filename = File.join(pdf_path, "#{pdf_name}_encrypted.pdf")
|
36
|
+
owner_pw = options[:owner_pw].is_a?(Proc)? options[:owner_pw].call : options[:owner_pw]
|
37
|
+
user_pw = options[:user_pw].is_a?(Proc)? options[:user_pw].call : options[:user_pw]
|
38
|
+
|
39
|
+
pdftk_commands = [
|
40
|
+
f,
|
41
|
+
'output', encrypted_filename,
|
42
|
+
'owner_pw', owner_pw,
|
43
|
+
'user_pw', user_pw
|
44
|
+
]
|
45
|
+
|
46
|
+
unless options[:disallow_printing]
|
47
|
+
pdftk_commands << 'allow'
|
48
|
+
pdftk_commands << 'printing'
|
49
|
+
end
|
50
|
+
|
51
|
+
PDF::Toolkit.pdftk(*pdftk_commands)
|
52
|
+
f = encrypted_filename
|
53
|
+
end
|
54
|
+
|
55
|
+
FileUtils.mv f, serve_file.path
|
56
|
+
send_file serve_file.path,
|
57
|
+
:disposition => (options[:disposition] rescue nil) || 'inline',
|
58
|
+
:url_based_filename => true,
|
59
|
+
:filename => (options[:filename] rescue nil),
|
60
|
+
:type => "application/pdf",
|
61
|
+
:length => File.size(serve_file.path),
|
62
|
+
:stream => false
|
63
|
+
serve_file.close
|
64
|
+
end
|
65
|
+
end
|
66
|
+
orig
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
data/lib/rtex/version.rb
ADDED
@@ -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/lib/rtex.rb
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
require File.dirname(__FILE__) << '/test_helper'
|
2
|
+
|
3
|
+
class DocumentTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
context "Document Generation" do
|
6
|
+
|
7
|
+
setup do
|
8
|
+
change_tmpdir_for_testing
|
9
|
+
end
|
10
|
+
|
11
|
+
should "have a to_pdf method" do
|
12
|
+
assert document(:first).respond_to?(:to_pdf)
|
13
|
+
end
|
14
|
+
|
15
|
+
context "when escaping" do
|
16
|
+
setup do
|
17
|
+
@obj = Object.new
|
18
|
+
def @obj.to_s
|
19
|
+
'\~'
|
20
|
+
end
|
21
|
+
@escaped = '\textbackslash{}\textasciitilde{}'
|
22
|
+
end
|
23
|
+
should "escape character" do
|
24
|
+
assert_equal @escaped, RTeX::Document.escape(@obj.to_s)
|
25
|
+
end
|
26
|
+
should "convert argument to string before attempting escape" do
|
27
|
+
assert_equal @escaped, RTeX::Document.escape(@obj)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
should "use a to_pdf block to move a file to a relative path" do
|
32
|
+
begin
|
33
|
+
path = File.expand_path(File.dirname(__FILE__) << '/tmp/this_is_relative_to_pwd.pdf')
|
34
|
+
document(:first).to_pdf do |filename|
|
35
|
+
assert_nothing_raised do
|
36
|
+
FileUtils.move filename, path
|
37
|
+
end
|
38
|
+
assert File.exists?(path)
|
39
|
+
end
|
40
|
+
ensure
|
41
|
+
FileUtils.rm path rescue nil
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
should "generate PDF and return as a string" do
|
46
|
+
@author = 'Foo'
|
47
|
+
assert_equal '%PDF', document(:first).to_pdf(binding)[0, 4]
|
48
|
+
end
|
49
|
+
|
50
|
+
should "generate TeX source and return as a string with debug option" do
|
51
|
+
@author = 'Foo'
|
52
|
+
assert_not_equal '%PDF', document(:first, :tex => true).to_pdf(binding)[0, 4]
|
53
|
+
end
|
54
|
+
|
55
|
+
should "generate PDF and give access to file directly" do
|
56
|
+
@author = 'Foo'
|
57
|
+
data_read = nil
|
58
|
+
invocation_result = document(:first).to_pdf(binding) do |filename|
|
59
|
+
data_read = File.open(filename, 'rb') { |f| f.read }
|
60
|
+
:not_the_file_contents
|
61
|
+
end
|
62
|
+
assert_equal '%PDF', data_read[0, 4]
|
63
|
+
assert_equal :not_the_file_contents, invocation_result
|
64
|
+
end
|
65
|
+
|
66
|
+
should "generate TeX source and give access to file directly" do
|
67
|
+
@author = 'Foo'
|
68
|
+
data_read = nil
|
69
|
+
invocation_result = document(:first, :tex => true).to_pdf(binding) do |filename|
|
70
|
+
data_read = File.open(filename, 'rb') { |f| f.read }
|
71
|
+
:not_the_file_contents
|
72
|
+
end
|
73
|
+
assert_not_equal '%PDF', data_read[0, 4]
|
74
|
+
assert_equal :not_the_file_contents, invocation_result
|
75
|
+
end
|
76
|
+
|
77
|
+
should "wrap in a layout using `yield'" do
|
78
|
+
doc = document(:fragment, :layout => 'testing_layout[<%= yield %>]')
|
79
|
+
@name = 'ERB'
|
80
|
+
source = doc.source(binding)
|
81
|
+
assert source =~ /^testing_layout.*?ERB, Fragmented/
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
data/test/filter_test.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
require File.dirname(__FILE__) << '/test_helper'
|
2
|
+
|
3
|
+
class FilterTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
context "Filtering Documents" do
|
6
|
+
|
7
|
+
should "filter through textile" do
|
8
|
+
doc = document('text.textile', :filter => 'textile')
|
9
|
+
source = doc.source(binding)
|
10
|
+
assert source.include?('\item')
|
11
|
+
end
|
12
|
+
|
13
|
+
should "not affect layouts" do
|
14
|
+
doc = document('text.textile',
|
15
|
+
:filter => 'textile',
|
16
|
+
:layout => "* layout\n* is\n<%= yield %>")
|
17
|
+
source = doc.source(binding)
|
18
|
+
assert source.include?("* layout"), "filtered layout"
|
19
|
+
assert source.include?('\item'), "didn't filter content"
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
% This percent indicates a comment.
|
2
|
+
% This is a very simple latex article that introduces the way
|
3
|
+
% equations are typeset. Do this in linux:
|
4
|
+
%
|
5
|
+
% latex first.tex
|
6
|
+
% latex first.tex
|
7
|
+
% xdvi first.dvi
|
8
|
+
% dvips -o first.ps first.dvi
|
9
|
+
% gv first.ps
|
10
|
+
% lpr first.ps
|
11
|
+
% pdflatex first.tex
|
12
|
+
% acroread first.pdf
|
13
|
+
\documentclass[12pt]{article}
|
14
|
+
\title{First \LaTeX}
|
15
|
+
\author{Joe Student}
|
16
|
+
\date{\today}
|
17
|
+
|
18
|
+
\begin{document}
|
19
|
+
|
20
|
+
\maketitle
|
21
|
+
|
22
|
+
\abstract{This is a very simple example of using \LaTeX\ for typesetting.
|
23
|
+
The procedure for typesetting equations is introduced.}
|
24
|
+
\begin{sdsd}
|
25
|
+
\end{bar}
|
26
|
+
|
27
|
+
\section{A few equations}
|
28
|
+
Equations can be typeset inline like so: $\vec{F}=m\vec{a}$ .
|
29
|
+
Equations can also be separated form the text: $$ \vec{F}=m\vec{a} \ . $$
|
30
|
+
Notice the punctuation, the ``.'', had to be included with the equation.
|
31
|
+
Equations can also have a number assigned and a label attached,
|
32
|
+
as in the following:
|
33
|
+
\begin{equation}
|
34
|
+
\frac{D\vec{\omega}}{Dt} =
|
35
|
+
( \vec{\omega} + \vec{\Omega}) \cdot \nabla \vec{U}
|
36
|
+
+ \frac{1}{\rho^2} \nabla \rho \times \nabla p
|
37
|
+
+ \nu \nabla^2 \vec{\omega}
|
38
|
+
\label{vorteq}
|
39
|
+
\end{equation}
|
40
|
+
The vorticity equation (\ref{vorteq}) is referenced by label,
|
41
|
+
not by number. The numbers may change as the document grows and
|
42
|
+
more equations are added.
|
43
|
+
|
44
|
+
New paragraphs are indicated with a blank line in the source code.
|
45
|
+
|
46
|
+
\section{The End}
|
47
|
+
|
48
|
+
Further examples of \LaTeX\ can be found at {\tt it.metr.ou.edu}
|
49
|
+
|
50
|
+
\end{document}
|
@@ -0,0 +1,48 @@
|
|
1
|
+
% This percent indicates a comment.
|
2
|
+
% This is a very simple latex article that introduces the way
|
3
|
+
% equations are typeset. Do this in linux:
|
4
|
+
%
|
5
|
+
% latex first.tex
|
6
|
+
% latex first.tex
|
7
|
+
% xdvi first.dvi
|
8
|
+
% dvips -o first.ps first.dvi
|
9
|
+
% gv first.ps
|
10
|
+
% lpr first.ps
|
11
|
+
% pdflatex first.tex
|
12
|
+
% acroread first.pdf
|
13
|
+
\documentclass[12pt]{article}
|
14
|
+
\title{First \LaTeX}
|
15
|
+
\author{<%= @author %>}
|
16
|
+
\date{\today}
|
17
|
+
|
18
|
+
\begin{document}
|
19
|
+
|
20
|
+
\maketitle
|
21
|
+
|
22
|
+
\abstract{This is a very simple example of using \LaTeX\ for typesetting.
|
23
|
+
The procedure for typesetting equations is introduced.}
|
24
|
+
|
25
|
+
\section{A few equations}
|
26
|
+
Equations can be typeset inline like so: $\vec{F}=m\vec{a}$ .
|
27
|
+
Equations can also be separated form the text: $$ \vec{F}=m\vec{a} \ . $$
|
28
|
+
Notice the punctuation, the ``.'', had to be included with the equation.
|
29
|
+
Equations can also have a number assigned and a label attached,
|
30
|
+
as in the following:
|
31
|
+
\begin{equation}
|
32
|
+
\frac{D\vec{\omega}}{Dt} =
|
33
|
+
( \vec{\omega} + \vec{\Omega}) \cdot \nabla \vec{U}
|
34
|
+
+ \frac{1}{\rho^2} \nabla \rho \times \nabla p
|
35
|
+
+ \nu \nabla^2 \vec{\omega}
|
36
|
+
\label{vorteq}
|
37
|
+
\end{equation}
|
38
|
+
The vorticity equation (\ref{vorteq}) is referenced by label,
|
39
|
+
not by number. The numbers may change as the document grows and
|
40
|
+
more equations are added.
|
41
|
+
|
42
|
+
New paragraphs are indicated with a blank line in the source code.
|
43
|
+
|
44
|
+
\section{The End}
|
45
|
+
|
46
|
+
Further examples of \LaTeX\ can be found at {\tt it.metr.ou.edu}
|
47
|
+
|
48
|
+
\end{document}
|
@@ -0,0 +1 @@
|
|
1
|
+
\par <%= @name %>, Fragmented
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require File.dirname(__FILE__) << '/test_helper'
|
2
|
+
|
3
|
+
class TempdirTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
context "Creating a temporary directory" do
|
6
|
+
|
7
|
+
setup do
|
8
|
+
change_tmpdir_for_testing
|
9
|
+
end
|
10
|
+
|
11
|
+
should "change directory" do
|
12
|
+
old_location = Dir.pwd
|
13
|
+
block_location = nil
|
14
|
+
RTeX::Tempdir.open do
|
15
|
+
assert_not_equal old_location, Dir.pwd
|
16
|
+
block_location = Dir.pwd
|
17
|
+
end
|
18
|
+
assert_equal old_location, Dir.pwd
|
19
|
+
assert !File.exists?(block_location)
|
20
|
+
end
|
21
|
+
|
22
|
+
should "use a 'rtex' name prefix" do
|
23
|
+
RTeX::Tempdir.open do
|
24
|
+
assert_equal 'rtex-', File.basename(Dir.pwd)[0,5]
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
should "remove the directory after use if no exception occurs by default" do
|
29
|
+
path = nil
|
30
|
+
RTeX::Tempdir.open do
|
31
|
+
path = Dir.pwd
|
32
|
+
assert File.exists?(path)
|
33
|
+
end
|
34
|
+
assert !File.exists?(path)
|
35
|
+
end
|
36
|
+
|
37
|
+
should "return the result of the last statement if automatically removing the directory" do
|
38
|
+
result = RTeX::Tempdir.open do
|
39
|
+
:last
|
40
|
+
end
|
41
|
+
assert_equal :last, :last
|
42
|
+
end
|
43
|
+
|
44
|
+
should "return the result of the last statment if not automatically removing the directory" do
|
45
|
+
tempdir = nil # to capture value
|
46
|
+
result = RTeX::Tempdir.open do |tempdir|
|
47
|
+
:last
|
48
|
+
end
|
49
|
+
tempdir.remove!
|
50
|
+
assert_equal :last, :last
|
51
|
+
end
|
52
|
+
|
53
|
+
should "not remove the directory after use if an exception occurs" do
|
54
|
+
path = nil
|
55
|
+
assert_raises RuntimeError do
|
56
|
+
RTeX::Tempdir.open do
|
57
|
+
path = Dir.pwd
|
58
|
+
assert File.directory?(path)
|
59
|
+
raise "Test exception!"
|
60
|
+
end
|
61
|
+
end
|
62
|
+
assert File.directory?(path)
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
begin
|
5
|
+
require 'shoulda'
|
6
|
+
require 'flexmock/test_unit'
|
7
|
+
rescue LoadError
|
8
|
+
abort "the `Shoulda' and `flexmock' gems are required for testing"
|
9
|
+
end
|
10
|
+
|
11
|
+
require File.dirname(__FILE__) << '/../lib/rtex'
|
12
|
+
|
13
|
+
class Test::Unit::TestCase
|
14
|
+
|
15
|
+
def change_tmpdir_for_testing
|
16
|
+
flexmock(Dir).should_receive(:tmpdir).and_return(File.dirname(__FILE__) << '/tmp')
|
17
|
+
end
|
18
|
+
|
19
|
+
def document(name, options={})
|
20
|
+
name = name.kind_of?(Symbol) ? "#{name}.tex.erb" : name
|
21
|
+
template = File.read(File.dirname(__FILE__) << "/fixtures/#{name}")
|
22
|
+
RTeX::Document.new(template, options)
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
metadata
ADDED
@@ -0,0 +1,110 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: cf-rtex
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 2.1.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Aaron Pederson
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2022-07-05 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rails
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 3.1.0
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 3.1.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: pdf-toolkit
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: sqlite3
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
description: Description of Rtex.
|
56
|
+
email:
|
57
|
+
- aaron.pederson@castingnetworks.com
|
58
|
+
executables: []
|
59
|
+
extensions: []
|
60
|
+
extra_rdoc_files: []
|
61
|
+
files:
|
62
|
+
- README.rdoc
|
63
|
+
- Rakefile
|
64
|
+
- lib/rtex.rb
|
65
|
+
- lib/rtex/document.rb
|
66
|
+
- lib/rtex/escaping.rb
|
67
|
+
- lib/rtex/helpers.rb
|
68
|
+
- lib/rtex/railtie.rb
|
69
|
+
- lib/rtex/tempdir.rb
|
70
|
+
- lib/rtex/template_handler.rb
|
71
|
+
- lib/rtex/version.rb
|
72
|
+
- test/document_test.rb
|
73
|
+
- test/filter_test.rb
|
74
|
+
- test/fixtures/first.tex
|
75
|
+
- test/fixtures/first.tex.erb
|
76
|
+
- test/fixtures/fragment.tex.erb
|
77
|
+
- test/fixtures/text.textile
|
78
|
+
- test/tempdir_test.rb
|
79
|
+
- test/test_helper.rb
|
80
|
+
homepage: https://github.com/casting-frontier/cf-rtex
|
81
|
+
licenses: []
|
82
|
+
metadata: {}
|
83
|
+
post_install_message:
|
84
|
+
rdoc_options: []
|
85
|
+
require_paths:
|
86
|
+
- lib
|
87
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
88
|
+
requirements:
|
89
|
+
- - ">="
|
90
|
+
- !ruby/object:Gem::Version
|
91
|
+
version: '0'
|
92
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
requirements: []
|
98
|
+
rubygems_version: 3.3.11
|
99
|
+
signing_key:
|
100
|
+
specification_version: 4
|
101
|
+
summary: Summary of Rtex.
|
102
|
+
test_files:
|
103
|
+
- test/document_test.rb
|
104
|
+
- test/filter_test.rb
|
105
|
+
- test/fixtures/first.tex
|
106
|
+
- test/fixtures/first.tex.erb
|
107
|
+
- test/fixtures/fragment.tex.erb
|
108
|
+
- test/fixtures/text.textile
|
109
|
+
- test/tempdir_test.rb
|
110
|
+
- test/test_helper.rb
|