artex 2.1.1
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.
- data/CHANGELOG +3 -0
- data/Manifest +25 -0
- data/README.rdoc +46 -0
- data/Rakefile +22 -0
- data/artex.gemspec +37 -0
- data/init.rb +1 -0
- data/lib/artex.rb +31 -0
- data/lib/artex/document.rb +175 -0
- data/lib/artex/escaping.rb +28 -0
- data/lib/artex/framework/merb.rb +13 -0
- data/lib/artex/framework/rails.rb +28 -0
- data/lib/artex/pdf.rb +81 -0
- data/lib/artex/tempdir.rb +52 -0
- data/lib/artex/version.rb +77 -0
- data/rails/init.rb +1 -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 +25 -0
- data/vendor/instiki/LICENSE +3 -0
- data/vendor/instiki/redcloth_for_tex.rb +736 -0
- metadata +115 -0
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
|
3
|
+
module ArTeX
|
4
|
+
|
5
|
+
class Tempdir #:nodoc:
|
6
|
+
|
7
|
+
def self.open(parent_path=ArTeX::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='artex')
|
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, 'artex', "#{@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,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 ArTeX
|
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 @@
|
|
1
|
+
require 'artex'
|
@@ -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, ArTeX::Document.escape(@obj.to_s)
|
25
|
+
end
|
26
|
+
should "convert argument to string before attempting escape" do
|
27
|
+
assert_equal @escaped, ArTeX::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
|
+
ArTeX::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 'artex' name prefix" do
|
23
|
+
ArTeX::Tempdir.open do
|
24
|
+
assert_equal 'artex', 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
|
+
ArTeX::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 = ArTeX::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 = ArTeX::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
|
+
ArTeX::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,25 @@
|
|
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/artex'
|
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
|
+
ArTeX::Document.new(template, options)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|