cf-rtex 2.1.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|