erb_latex 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 85a04610d1b87c2b98b9b9c12236031c2a205018
4
+ data.tar.gz: f6f80ea5b96e39d6f8d1cc0abd0da6fe1c700410
5
+ SHA512:
6
+ metadata.gz: b325e8f90702b6a105623667c00d707f9f905512c3687e637c28fd4d4074ba8691781b0d068e2405576b35d647b1dbae6920e6d17e6d993f40284c28f6485c7d
7
+ data.tar.gz: 873c768effa755f69585530350414b1529741ea6232a052c5269c08ee4cd045c360be2f5df3d4d2a1a8f5504e650f3272f00aac320deae88f1d131f61adebb7a
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in erb_latex.gemspec
4
+ gemspec
data/Guardfile ADDED
@@ -0,0 +1,10 @@
1
+ notification :growl
2
+
3
+ guard :minitest, :all_on_start => true do
4
+ watch(%r{^test/test_helper\.rb}) { 'test' }
5
+
6
+ watch(%r{^test/.+_test\.rb})
7
+ watch(%r{^test/fixtures/(.+)s\.tex}) { |m| "test/erb_latex_test.rb" }
8
+
9
+ watch(%r{^lib/erb_latex/(.+)\.rb}) { |m| "test/erb_latex_test.rb" }
10
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Nathan Stitt
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,119 @@
1
+ # ERB LaTeX
2
+
3
+ Applies ERB template processing to a LaTeX file and compiles it to a PDF.
4
+
5
+ Supports layouts, partials, and string escaping.
6
+
7
+ Also supplies a Guard task to watch for modifications and auto-building files.
8
+
9
+ ## Use Case
10
+
11
+ [Argosity](http://argosity.com/) uses this for several different projects
12
+
13
+ * [Nathan](http://nathan.stitt.org/) originally used a bare-bones of this to generate his resume.
14
+ * [Stockor](http://stockor.org/), our open-source ERP platform. It's used for building all the form that output as PDF.
15
+ * Generating proposals for client projects.
16
+
17
+ ## Api Docs
18
+
19
+ Are hosted at [nathan.stitt.org/code/erb-latex/](http://nathan.stitt.org/code/erb-latex/)
20
+
21
+ ## Installation
22
+
23
+ Add this line to your application's Gemfile:
24
+
25
+ gem 'erb_latex'
26
+
27
+ And then execute:
28
+
29
+ $ bundle
30
+
31
+ Or install it yourself as:
32
+
33
+ $ gem install erb_latex
34
+
35
+ ## Usage
36
+
37
+ Given a LaTeX layout template: ``layout.tex``
38
+
39
+ ```latex
40
+ \documentclass[12pt]{article}
41
+ \usepackage{background}
42
+ \usepackage{lettrine}
43
+ \makeatletter
44
+ \AddEverypageHook{
45
+ \SetBgContents{
46
+ \includegraphics[width=\paperwidth]{argosity-background-wave.png}
47
+ }
48
+ \SetBgPosition{current page.south}
49
+ \SetBgAnchor{above}
50
+ \SetBgAngle{0}
51
+ \SetBgScale{1}
52
+ \SetBgVshift{-2mm}
53
+ \SetBgOpacity{0.3}
54
+ \bg@material}
55
+ \makeatother
56
+ \begin{document}
57
+ <%= yield %>
58
+ \end{document}
59
+ ```
60
+
61
+ and a simple LaTeX body: ``body.tex``
62
+
63
+ ```latex
64
+ \lettrine[lines=2]{T}{hank} you for your your consideration.
65
+ Please let us know if we can help you any further at all and don't forget to fill out the speakers notes.
66
+
67
+ <%=q message %>
68
+
69
+ Thank you,
70
+ <%=q author %>
71
+ ```
72
+ The following will convert it to a pdf
73
+
74
+ ```ruby
75
+ require "erb_latex"
76
+
77
+ tmpl = ErbLatex::Template.new( 'body.tex', {
78
+ :layout=>'layout.tex',
79
+ :data=>{
80
+ :author=>"Nathan",
81
+ :messge = "Please call our department at 555-5555"
82
+ }
83
+ })
84
+ tmpl.to_file('thank-you.pdf')
85
+ ```
86
+ ## Guard plugin
87
+
88
+ ERB LaTeX also includes a plugin for [Guard](https://github.com/guard/guard) to automatically
89
+ generate a PDF from a LaTeX file whenever the LaTeX file is modified.
90
+
91
+ This is useful for shortening the build/review/modify cycle when developing a complex layout.
92
+
93
+ A Guardfile such as this would compile all *.tex files in a directory
94
+
95
+ ```ruby
96
+ require 'erb_latex/guard'
97
+
98
+ guard :erb_latex do
99
+ watch(%r{.tex$})
100
+ end
101
+ ```
102
+
103
+ While the one below would compile the hypothetical body.tex file above
104
+
105
+ ```ruby
106
+ require 'erb_latex/guard'
107
+
108
+ guard :erb_latex, :layout=>'proposal.tex', :data=>{:author=>'Nathan Stitt', :message=>'Buy low, Sell High!'} do
109
+ watch 'body.tex'
110
+ end
111
+ ```
112
+
113
+ ## Contributing
114
+
115
+ 1. Fork it ( http://github.com/nathanstitt/erb_latex/fork )
116
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
117
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
118
+ 4. Push to the branch (`git push origin my-new-feature`)
119
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,28 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ require 'bundler/setup'
4
+ require "bundler/gem_tasks"
5
+ require 'rake/testtask'
6
+ require 'yard'
7
+ require 'guard'
8
+
9
+ Rake::TestTask.new do |t|
10
+ t.libs << 'test'
11
+ t.pattern = "test/*_test.rb"
12
+ end
13
+
14
+ YARD::Rake::YardocTask.new do |t|
15
+ t.files = ['lib/**/*.rb']
16
+ t.options = [
17
+ "--title=ERB LaTeX",
18
+ "--markup=markdown",
19
+ "--template-path=yard_ext/templates",
20
+ "--readme=README.md"
21
+ ]
22
+ end
23
+
24
+ desc "Deploy docs to web server"
25
+ task :docs do
26
+ Rake::Task["yard"].invoke
27
+ system( "rsync", "doc/", "-avz", "--delete", "nathan.stitt.org:~/docs/erb-latex")
28
+ end
data/erb_latex.gemspec ADDED
@@ -0,0 +1,27 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'erb_latex/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "erb_latex"
8
+ spec.version = ErbLatex::VERSION
9
+ spec.authors = ["Nathan Stitt"]
10
+ spec.email = ["nathan@stitt.org"]
11
+ spec.summary = %q{Applies ERB template processing to a Latex file and compiles it to a PDF}
12
+ spec.description = %q{Applies ERB template processing to a Latex file and compiles it to a PDF. Supports layouts, partials, and string escaping. Also supplies a Guard task to watch for modifications and auto-building files.}
13
+ spec.homepage = "http://nathan.stitt.org/code/erb-latex/"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.5"
22
+ spec.add_development_dependency "rake", "~> 10"
23
+ spec.add_development_dependency "growl", "~> 1.0" # sorry Linux. Anyone have suggestions on how to do this multi-platform?
24
+ spec.add_development_dependency "yard", "~> 0.8"
25
+ spec.add_development_dependency "guard", "~> 2.0"
26
+ spec.add_development_dependency "guard-minitest", "~> 2.2"
27
+ end
data/lib/erb_latex.rb ADDED
@@ -0,0 +1,17 @@
1
+ require "erb_latex/version"
2
+ require "erb_latex/errors"
3
+ require "erb_latex/context"
4
+ require "erb_latex/stringio"
5
+ require "erb_latex/template"
6
+ module ErbLatex
7
+
8
+
9
+
10
+ def self.xelatex_binary
11
+ defined?(@@xelatex_binary) ? @@xelatex_binary : "xelatex"
12
+ end
13
+
14
+ def self.xelatex_binary=(bin)
15
+ @@xelatex_binary = bin
16
+ end
17
+ end
@@ -0,0 +1,61 @@
1
+ module ErbLatex
2
+
3
+ # Is the execution context for ERB evaluation
4
+ #
5
+ class Context
6
+
7
+ # List of characters that need to be escaped
8
+ # and their escaped values
9
+ ESCAPE = {
10
+ "#"=>"\\#",
11
+ "$"=>"\\$",
12
+ "%"=>"\\%",
13
+ "&"=>"\\&",
14
+ "~"=>"\\~{}",
15
+ "_"=>"\\_",
16
+ "^"=>"\\^{}",
17
+ "\\"=>"\\textbackslash{}",
18
+ "{"=>"\\{",
19
+ "}"=>"\\}"
20
+ }
21
+
22
+ # create new Context
23
+ # @param directory [String] directory to use as a base for finding partials
24
+ # @param data [Hash]
25
+ def initialize( directory, data )
26
+ @directory = directory
27
+ @data = data
28
+ data.each{ |k,v| instance_variable_set( '@'+k.to_s, v ) }
29
+ end
30
+
31
+ # include another latex file into the current template
32
+ def partial( template, data={} )
33
+ view_file = @directory.join( template )
34
+ if view_file.exist?
35
+ context = Context.new( @directory, data )
36
+ ERB.new( view_file.read, 0, '-' ).result( context.getBinding )
37
+ else
38
+ "missing partial: #{template}"
39
+ end
40
+ end
41
+
42
+ # convert newline characters into latex '\\newline'
43
+ def break_lines( txt )
44
+ q(txt.to_s).gsub("\n",'\\newline ')
45
+ end
46
+
47
+ # return a reference to the instance's scope or 'binding'
48
+ def getBinding
49
+ return binding()
50
+ end
51
+
52
+ # escape using latex escaping rules
53
+ # @param text string to escape
54
+ # @return [String] text after {ESCAPE} characters are replaced
55
+ def q(text)
56
+ text.to_s.gsub( /([\^\%~\\\\#\$%&_\{\}])/ ) { |s| ESCAPE[s] }
57
+ end
58
+
59
+ end
60
+
61
+ end
@@ -0,0 +1,17 @@
1
+ module ErbLatex
2
+
3
+ # Encapsolates an error that occurs while processing a latex template
4
+ class LatexError < RuntimeError
5
+
6
+ # @attribute [r] log
7
+ # @return the log from the xelatex run
8
+ attr_reader :log
9
+
10
+ def initialize( msg, log )
11
+ super(msg)
12
+ @log = log
13
+ end
14
+
15
+ end
16
+
17
+ end
@@ -0,0 +1,58 @@
1
+ require 'guard'
2
+ require 'guard/plugin'
3
+ require 'erb_latex'
4
+ require 'erb_latex/guard_runner'
5
+
6
+ module Guard
7
+
8
+
9
+ # The ErbLatex guard that gets notifications about the following
10
+ # Guard events: `start`, `run_all` and `run_on_modifications`.
11
+ class ErbLatex < Plugin
12
+
13
+ DEFAULT_OPTIONS = {
14
+ :layout => false,
15
+ :data => {},
16
+ :all_on_start => true,
17
+ :hide_success => false
18
+ }
19
+
20
+ # Initialize Guard::ErbLates
21
+ #
22
+ # @param [Hash] options the options for the Guard
23
+ # @option options [String] :layout, the layout to apply to latex files
24
+ # @option options [String] :data, for use during the ERB processing
25
+ # @option options [Boolean] :all_on_start process all latex files on start
26
+ # @option options [Boolean] :hide_success hide success message notification, unless the previous run failed
27
+ def initialize( options = {} )
28
+ super( DEFAULT_OPTIONS.merge(options) )
29
+ end
30
+
31
+ # Gets called once when Guard starts.
32
+ #
33
+ # @raise [:task_has_failed] when stop has failed
34
+ #
35
+ def start
36
+ run_all if options[:all_on_start]
37
+ end
38
+
39
+ # Gets called when all files should be regenerated.
40
+ #
41
+ # @raise [:task_has_failed] when stop has failed
42
+ #
43
+ def run_all
44
+ run_on_modifications( Watcher.match_files(self, Dir.glob('**{,/*/**}/*.{tex,erb.tex,tex.erb}')) )
45
+ end
46
+
47
+ # Gets called when watched paths and files have changes.
48
+ #
49
+ # @param [Array<String>] paths the changed paths and files
50
+ # @raise [:task_has_failed] when stop has failed
51
+ #
52
+ def run_on_modifications(paths)
53
+ throw :task_has_failed unless ::ErbLatex::GuardRunner.run( paths, watchers, options )
54
+ end
55
+
56
+ end
57
+
58
+ end
@@ -0,0 +1,83 @@
1
+ require 'erb_latex'
2
+
3
+ module ErbLatex
4
+ module GuardRunner
5
+ class << self
6
+
7
+ attr_accessor :last_run_failed
8
+
9
+ # The ErbLatex runner handles the ErbLatex compilation,
10
+ # creates the output pdf file, writes the result
11
+ # to the console and triggers optional system notifications.
12
+ #
13
+ # @param [Array<String>] files the spec files or directories
14
+ # @param [Array<Guard::Watcher>] watchers the Guard watchers in the block
15
+ # @param [Hash] options the options for the execution
16
+ # @option options [String] :layout, the layout to apply to latex files
17
+ # @option options [String] :data, for use during the ERB processing
18
+ # @return [Array<Array<String>, Boolean>] the result for the compilation run
19
+ #
20
+ def run(files, watchers, options = { })
21
+ ::Guard::UI.info('Compiling ' + files.join(', '), :reset=>true )
22
+ changed_files, errors = compile_files(files, watchers, options)
23
+ notify_result(changed_files, errors, options)
24
+ return errors.empty?
25
+ end
26
+
27
+
28
+ private
29
+
30
+ # Compiles all ErbLatex files and writes the PDF files.
31
+ #
32
+ # @param [Array<String>] files the files to compile
33
+ # @param [Array<Guard::Watcher>] watchers the Guard watchers in the block
34
+ # @param [Hash] options the options for the execution
35
+ # @return [Array<Array<String>, Array<String>] the result for the compilation run
36
+ #
37
+ def compile_files(files, watchers, options)
38
+ errors = []
39
+ changed_files = []
40
+
41
+ files.each do |file|
42
+ begin
43
+ pdf = ErbLatex::Template.new( file, options ).to_file
44
+ changed_files << pdf
45
+ rescue LatexError => e
46
+ error_message = file + ': ' + e.message.to_s
47
+ errors << error_message
48
+ ::Guard::UI.error(color(error_message, ';31'), options)
49
+ end
50
+ end
51
+ [changed_files.flatten.compact, errors]
52
+ end
53
+
54
+ # Writes console and system notifications about the result of the compilation.
55
+ #
56
+ # @param [Array<String>] changed_files the changed JavaScript files
57
+ # @param [Array<String>] errors the error messages
58
+ # @param [Hash] options the options for the execution
59
+ # @option options [Boolean] :hide_success hide success message notification
60
+ # @option options [Boolean] :noop do not generate an output file
61
+ #
62
+ def notify_result(changed_files, errors, options = { })
63
+ if !errors.empty?
64
+ self.last_run_failed = true
65
+ ::Guard::Notifier.notify(errors.join("\n"), :title => 'ErbLatex results', :image => :failed, :priority => 2)
66
+ elsif !options[:hide_success] || last_run_failed
67
+ self.last_run_failed = false
68
+ message = "Successfully #{ options[:noop] ? 'verified' : 'generated' } #{ changed_files.join(', ') }"
69
+ ::Guard::UI.info(color( "#{Time.now.strftime('%r')} #{message}", ';32'), options)
70
+ ::Guard::Notifier.notify(message, :title => 'ErbLatex results')
71
+ end
72
+ end
73
+
74
+ # Print a info message to the console.
75
+ # @param [String] text the text to colorize
76
+ # @param [String] color_code the color code
77
+ def color(text, color_code)
78
+ ::Guard::UI.send(:color_enabled?) ? "\e[0#{ color_code }m#{ text }\e[0m" : text
79
+ end
80
+
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,34 @@
1
+ module ErbLatex
2
+
3
+ # An ErbLatex::StringIO extends Ruby's StringIO
4
+ # with a path and file name
5
+ # This allows it to be used in situations where a
6
+ # File is expected
7
+ class StringIO < ::StringIO
8
+
9
+ # @attribute [rw] filepath
10
+ # @return [String] complete *virtual* path for the data
11
+ attr_accessor :filepath
12
+
13
+ def initialize( name='' )
14
+ @filepath = name
15
+ super('')
16
+ self.set_encoding( Encoding.find("UTF-8") )
17
+ end
18
+
19
+ # define original_filename for clients that
20
+ # depend on it, i.e. carrierwave
21
+ def original_filename
22
+ File.basename(filepath)
23
+ end
24
+
25
+ # reset filepath
26
+ # @param name [String] new value for filepath
27
+ # @return self
28
+ def rename( name )
29
+ @filepath = name
30
+ self
31
+ end
32
+ end
33
+
34
+ end
@@ -0,0 +1,150 @@
1
+ require "tmpdir"
2
+ require "open3"
3
+ require "erb"
4
+ require 'pathname'
5
+ require 'fileutils'
6
+
7
+ module ErbLatex
8
+
9
+ # A template is an latex file that contains embedded ERB code
10
+ # It can optionally have a layout be rendered to either a file
11
+ # or StringIO instance
12
+ # @example for a hypothetical Rails controller
13
+ # tmpl = ErbLatex::Template.new( 'article.tex',
14
+ # :layout => 'layout.tex'
15
+ # :data => { :sentence=>"hello, this is doge" }
16
+ # )
17
+ # render :pdf => tmpl.to_stringio.read
18
+ #
19
+ class Template
20
+
21
+ # @attribute [r] log
22
+ # @return [String] the log from the last xelatex run
23
+ # @attribute [r] pass_count
24
+ # @return [Fixnum] how many passes it took to compile the tex into a PDF
25
+ attr_reader :log, :pass_count
26
+ # @attribute [rw] layout
27
+ # @return [String] path to a file to use for layout
28
+ attr_accessor :layout
29
+
30
+ # create a new Template
31
+ # @param view_file [String] path to the latex template
32
+ # @option options [String] :layout path to a latex template that calls yield
33
+ # @option options [Hash] :data an instance variable will be created in the view for each key/value pair
34
+ def initialize( view_file, options={} )
35
+ @data = options[:data] || {}
36
+ @layout = options[:layout]
37
+ @view = Pathname.new( view_file )
38
+ @log = ''
39
+ end
40
+
41
+ # Sets the data to be used for the template
42
+ # @param hash [Hash] data to set for the template
43
+ # An instance variable will be created for the template
44
+ # for each key in the hash with it's value set accordingly
45
+ def data=( hash )
46
+ @data = hash
47
+ end
48
+
49
+ # @return [String] the suggested filename for this template.
50
+ # It removes the extension from the name and replaces it with '.pdf'
51
+ def suggested_filename
52
+ @view.basename.to_s.gsub(/\..*$/, '.pdf')
53
+ end
54
+
55
+ # Save the PDF to the file
56
+ # @param file [String,IO] if file is a String, the PDF is moved to the path indicated (most efficient).
57
+ # Otherwise, file is considered an instance of IO, and write is called on it with the PDF contents
58
+ # @return [String,IO] the file
59
+ def to_file( file = suggested_filename )
60
+ execute do | contents |
61
+ if file.is_a?(String)
62
+ FileUtils.mv contents, file
63
+ else
64
+ file.write contents.read
65
+ pdf.rewind
66
+ end
67
+ end
68
+ file
69
+ end
70
+
71
+ # @return [StringIO] containing the the PDF
72
+ def to_stringio
73
+ to_file( ::ErbLatex::StringIO.new(suggested_filename) ).rewind
74
+ end
75
+
76
+ # Compile the Latex template into a PDF file
77
+ # @yield [Pathname] complete path to the PDF file
78
+ # @raise [LatexError] if the xelatex process does not complete successfully
79
+ def execute
80
+ latex = compile_latex
81
+ Dir.mktmpdir do | dir |
82
+ @pass_count = 0
83
+ @log = ''
84
+ success = false
85
+ while log_suggests_rerunning? && @pass_count < 5
86
+ @pass_count += 1
87
+ success = execute_xelatex(latex,dir)
88
+ end
89
+ pdf_file = Pathname.new(dir).join( "output.pdf" )
90
+ if success && pdf_file.exist?
91
+ yield pdf_file
92
+ else
93
+ errors = @log.scan(/\*\!\s(.*?)\n\s*\n/m).map{|e| e.first.gsub(/\n/,'') }.join("; ")
94
+ raise LatexError.new( errors.empty? ? "xelatex compile error" : errors, @log )
95
+ end
96
+ end
97
+ end
98
+
99
+ # @return [Pathname] layout file
100
+ def layout_file
101
+ Pathname.new( layout )
102
+ end
103
+
104
+ # Runs the ERB pre-process on the latex file
105
+ # @return [String] latex with ERB substitutions performed
106
+ # @raise [LatexError] if the xelatex process does not complete successfully
107
+ def compile_latex
108
+ begin
109
+ context = ErbLatex::Context.new( @view.dirname, @data )
110
+ content = ERB.new( @view.read, 0, '-' ).result( context.getBinding )
111
+ if layout
112
+ ERB.new( layout_file.read, nil, '-' ).result( context.getBinding{
113
+ content
114
+ })
115
+ else
116
+ content
117
+ end
118
+ rescue RuntimeError,LocalJumpError=>e
119
+ raise LatexError.new( "ERB compile raised #{e.class} on #{@view}", e.backtrace )
120
+ end
121
+ end
122
+
123
+ private
124
+
125
+ # @return [Boolean] True if the log is empty(not ran yet), or contains the string "Rerun"
126
+ def log_suggests_rerunning?
127
+ @log.empty? || !! ( @log =~ /Rerun/ )
128
+ end
129
+
130
+ # Execute xelatex on the file.
131
+ # @param latex [String] contents of the template after running ERB on it
132
+ # @param dir [String] path to the temporary working directory
133
+ def execute_xelatex( latex, dir )
134
+ success = false
135
+ @log = ''
136
+ Open3.popen2e( ErbLatex.xelatex_binary,
137
+ "--no-shell-escape", "-shell-restricted",
138
+ "-jobname=output", "-output-directory=#{dir}",
139
+ ) do |stdin, output, wait_thr|
140
+ stdin.write latex
141
+ stdin.close
142
+ @log = output.read.strip
143
+ success = ( 0 == wait_thr.value )
144
+ end
145
+ success
146
+ end
147
+
148
+ end
149
+
150
+ end
@@ -0,0 +1,5 @@
1
+ module ErbLatex
2
+
3
+ VERSION = "0.0.1"
4
+
5
+ end
@@ -0,0 +1,45 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'helper'
3
+
4
+ class ErbLatexTest < MiniTest::Test
5
+
6
+
7
+ def test_document
8
+ tmpl = ErbLatex::Template.new( document(:valid) )
9
+ tmpl.to_file tmp_output_file
10
+ assert_match "This is a very simple file", text_output
11
+ end
12
+
13
+ def test_errors
14
+ tmpl = ErbLatex::Template.new( document(:with_error) )
15
+ assert_raises(ErbLatex::LatexError) do
16
+ tmpl.to_stringio
17
+ end
18
+ end
19
+
20
+ def test_layout
21
+ tmpl = ErbLatex::Template.new( document(:body),
22
+ :layout => document(:layout),
23
+ :data => { :sentence=>"hello, this is doge" }
24
+ )
25
+ tmpl.to_file tmp_output_file
26
+ assert_match "hello, this is doge", text_output
27
+ end
28
+
29
+ def test_multiple_runs
30
+ tmpl = ErbLatex::Template.new( document(:multi_page) )
31
+ tmpl.to_file tmp_output_file
32
+ assert_equal 2, tmpl.pass_count
33
+ text = text_output
34
+ assert_match "Page 1 of 3", text
35
+ assert_match "Page 2 of 3", text
36
+ assert_match "Page 3 of 3", text
37
+ end
38
+
39
+ def test_partials
40
+ tmpl = ErbLatex::Template.new( document(:with_partial) )
41
+ tmpl.to_file tmp_output_file
42
+ assert_match "a test ’ of a partial", text_output
43
+ end
44
+
45
+ end
@@ -0,0 +1 @@
1
+ <%= @sentence %>
@@ -0,0 +1,4 @@
1
+ \documentclass[12pt]{article}
2
+ \begin{document}
3
+ <%= yield %>
4
+ \end{document}
@@ -0,0 +1,16 @@
1
+ \documentclass[oneside,12pt]{memoir}
2
+ \usepackage{xltxtra}
3
+ \usepackage{lastpage}
4
+ \usepackage[T1]{fontenc}
5
+ \makepagestyle{plain}
6
+ \makeoddfoot{plain}{}{}{Page \thepage\ of \pageref{LastPage}}
7
+ \makeevenfoot{plain}{}{}{Page \thepage\ of \pageref{LastPage}}
8
+ \begin{document}
9
+ \pagestyle{plain}
10
+ Page 1
11
+ \newpage
12
+ Page 2
13
+ \newpage
14
+ Page 3
15
+ \newpage
16
+ \end{document}
@@ -0,0 +1 @@
1
+ <%=q @sentence %>
@@ -0,0 +1,34 @@
1
+ \documentclass[12pt]{article}
2
+ \begin{document}
3
+
4
+ This is a very simple file, though it does include some mathematical
5
+ symbols, $\beta, x$ and $y$, and some equations,
6
+ \begin{equation}
7
+ \frac{1}{2} + \frac{1}{5} = \frac{7}{10}.
8
+ \end{equation}
9
+
10
+ The equations are automatically numbered:
11
+ \begin{equation}
12
+ 1 + 1 = 2 \Rightarrow E = m c^2.
13
+ \end{equation}
14
+
15
+ \LaTeX\ can handle complicated mathematical expressions.
16
+ \begin{equation}
17
+ \int_0^\infty \cos (k t) e^{-s t} d t = \frac{s}{s^2 + k^2}
18
+ \end{equation}
19
+ if $s > 0$.
20
+ \begin{equation}
21
+ e^z = \sum_{n=0}^\infty \frac{ z^n}{n!} .
22
+ \end{equation}
23
+
24
+ Leave a blank line in your file when you want a new paragraph.
25
+ \LaTeX\ will automatically
26
+ arrange your text
27
+ into tidy lines of
28
+ even length, even
29
+ if the
30
+ original text in the .tex file is a mess.
31
+
32
+ \sffamily\textregistered\textcopyright <%= @person %>
33
+
34
+ \end{document}
@@ -0,0 +1 @@
1
+ This document is in no way a valid LaTex Document
@@ -0,0 +1,4 @@
1
+ \documentclass[12pt]{article}
2
+ \begin{document}
3
+ <%= partial 'partial.tex.erb', :sentence=>"a test ' of a partial" %>
4
+ \end{document}
data/test/helper.rb ADDED
@@ -0,0 +1,32 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ begin
4
+ Bundler.setup(:default, :development)
5
+ rescue Bundler::BundlerError => e
6
+ $stderr.puts e.message
7
+ $stderr.puts "Run `bundle install` to install missing gems"
8
+ exit e.status_code
9
+ end
10
+
11
+ #require 'test/unit'
12
+
13
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
14
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
15
+ require 'erb_latex'
16
+
17
+ class MiniTest::Test
18
+
19
+ def document( name )
20
+ File.expand_path(File.join(File.dirname(__FILE__), "fixtures/#{name}.tex.erb"))
21
+ end
22
+
23
+ def tmp_output_file
24
+ File.expand_path( File.join( File.dirname(__FILE__), "tmp/output.pdf") )
25
+ end
26
+
27
+
28
+ def text_output
29
+ `pdftotext #{tmp_output_file} -`
30
+ end
31
+
32
+ end
@@ -0,0 +1 @@
1
+ [<a href="https://github.com/nathanstitt/code/erb_latex/tree/master/<%= object.file %><% if object.line %>#L<%= object.line %><% end %>">github</a>]
@@ -0,0 +1,3 @@
1
+ def source
2
+ super + erb(:github_link)
3
+ end
metadata ADDED
@@ -0,0 +1,166 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: erb_latex
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Nathan Stitt
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-03-05 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.5'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.5'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10'
41
+ - !ruby/object:Gem::Dependency
42
+ name: growl
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: yard
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '0.8'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '0.8'
69
+ - !ruby/object:Gem::Dependency
70
+ name: guard
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '2.0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '2.0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: guard-minitest
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '2.2'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '2.2'
97
+ description: Applies ERB template processing to a Latex file and compiles it to a
98
+ PDF. Supports layouts, partials, and string escaping. Also supplies a Guard task
99
+ to watch for modifications and auto-building files.
100
+ email:
101
+ - nathan@stitt.org
102
+ executables: []
103
+ extensions: []
104
+ extra_rdoc_files: []
105
+ files:
106
+ - ".gitignore"
107
+ - Gemfile
108
+ - Guardfile
109
+ - LICENSE.txt
110
+ - README.md
111
+ - Rakefile
112
+ - erb_latex.gemspec
113
+ - lib/erb_latex.rb
114
+ - lib/erb_latex/context.rb
115
+ - lib/erb_latex/errors.rb
116
+ - lib/erb_latex/guard.rb
117
+ - lib/erb_latex/guard_runner.rb
118
+ - lib/erb_latex/stringio.rb
119
+ - lib/erb_latex/template.rb
120
+ - lib/erb_latex/version.rb
121
+ - test/erb_latex_test.rb
122
+ - test/fixtures/body.tex.erb
123
+ - test/fixtures/layout.tex.erb
124
+ - test/fixtures/multi_page.tex.erb
125
+ - test/fixtures/partial.tex.erb
126
+ - test/fixtures/valid.tex.erb
127
+ - test/fixtures/with_error.tex.erb
128
+ - test/fixtures/with_partial.tex.erb
129
+ - test/helper.rb
130
+ - yard_ext/templates/default/method_details/html/github_link.erb
131
+ - yard_ext/templates/default/method_details/setup.rb
132
+ homepage: http://nathan.stitt.org/code/erb-latex/
133
+ licenses:
134
+ - MIT
135
+ metadata: {}
136
+ post_install_message:
137
+ rdoc_options: []
138
+ require_paths:
139
+ - lib
140
+ required_ruby_version: !ruby/object:Gem::Requirement
141
+ requirements:
142
+ - - ">="
143
+ - !ruby/object:Gem::Version
144
+ version: '0'
145
+ required_rubygems_version: !ruby/object:Gem::Requirement
146
+ requirements:
147
+ - - ">="
148
+ - !ruby/object:Gem::Version
149
+ version: '0'
150
+ requirements: []
151
+ rubyforge_project:
152
+ rubygems_version: 2.2.1
153
+ signing_key:
154
+ specification_version: 4
155
+ summary: Applies ERB template processing to a Latex file and compiles it to a PDF
156
+ test_files:
157
+ - test/erb_latex_test.rb
158
+ - test/fixtures/body.tex.erb
159
+ - test/fixtures/layout.tex.erb
160
+ - test/fixtures/multi_page.tex.erb
161
+ - test/fixtures/partial.tex.erb
162
+ - test/fixtures/valid.tex.erb
163
+ - test/fixtures/with_error.tex.erb
164
+ - test/fixtures/with_partial.tex.erb
165
+ - test/helper.rb
166
+ has_rdoc: