erb_latex 0.0.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.
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: