antex 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 9e8f4f3fd672813d3ad879df973fd7f322a74690
4
+ data.tar.gz: 84e7aa764ab967c2afc9423ce92b03a04e4d5e2e
5
+ SHA512:
6
+ metadata.gz: 586cb677c67b145dd111eaf9056d3bca2b4739c64be9cf7bf42336bcb75ed71f6bab884fd47932bbc79c10a70fa4a823c74f74b0622f12be73041ccd724439bc
7
+ data.tar.gz: 42335c58867725e0d1959e96b93a2b1a21a867f6943daeea39a39527ab4145c912fd1728d3e4038955224e191d3e7f20948222ec0158c381b94ed4a73c414d9c
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2017 Paolo Brasolin
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,10 @@
1
+ # antex
2
+
3
+ [![Build Status](https://travis-ci.org/paolobrasolin/antex.svg?branch=master)](https://travis-ci.org/paolobrasolin/antex)
4
+ [![Latest Release](https://img.shields.io/github/release/paolobrasolin/antex.svg)](https://github.com/paolobrasolin/antex)
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
6
+
7
+ [![Code Climate](https://codeclimate.com/github/paolobrasolin/antex/badges/gpa.svg)](https://codeclimate.com/github/paolobrasolin/antex)
8
+ [![Test Coverage](https://codeclimate.com/github/paolobrasolin/antex/badges/coverage.svg)](https://codeclimate.com/github/paolobrasolin/antex/coverage)
9
+ [![Inline docs](http://inch-ci.org/github/paolobrasolin/antex.svg?branch=master)](http://inch-ci.org/github/paolobrasolin/antex)
10
+ [![Issue Count](https://codeclimate.com/github/paolobrasolin/antex/badges/issue_count.svg)](https://codeclimate.com/github/paolobrasolin/antex)
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'antex/version'
4
+ require 'antex/error'
5
+
6
+ require 'antex/measurable'
7
+ require 'antex/tex_box'
8
+ require 'antex/svg_box'
9
+ require 'antex/set_box'
10
+
11
+ require 'antex/liquid_helpers'
12
+ require 'antex/job'
13
+ require 'antex/command'
@@ -0,0 +1,93 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'open3'
4
+
5
+ module Antex
6
+ # This class encapsulates the execution of a command line that needs
7
+ # some source files to produce some target files.
8
+ #
9
+ # Existence checks are performed on files:
10
+ # * if all targets exist before execution then it is skipped
11
+ # * all sources must exist before execution
12
+ # * all targets must exist after execution
13
+ #
14
+ # Details of the execution itself are given by
15
+ # the attributes {#stdout}, {#stderr} and {#status}.
16
+ class Command
17
+ class MissingSourceFiles < Error; end
18
+ class MissingTargetFiles < Error; end
19
+ class ExecutionFailed < Error; end
20
+
21
+ # @return [String, nil] the +stdout+ returned by the command line
22
+ attr_reader :stdout
23
+
24
+ # @return [String, nil] the +stderr+ returned by the command line
25
+ attr_reader :stderr
26
+
27
+ # @return [Process::Status, nil] the +status+ returned by the command line
28
+ attr_reader :status
29
+
30
+ # Initializes the command.
31
+ #
32
+ # @note A command with no targets will always skip
33
+ # since it needs to produce nothing!
34
+ #
35
+ # @param name [String] name of the command (just for error reporting)
36
+ # @param sources [Array] list of source files
37
+ # @param targets [Array] list of target files
38
+ # @param command_line [String] command line that will be executed
39
+ def initialize(name:, sources:, targets:, command_line:)
40
+ @name = name
41
+ @sources = sources
42
+ @targets = targets
43
+ @command_line = command_line
44
+ end
45
+
46
+ # Executes the command.
47
+ #
48
+ # @raise [MissingSourceFiles] when source files are missing
49
+ # @raise [ExecutionFailed] when command execution fails
50
+ # @raise [MissingTargetFiles] when command does not create target files
51
+ def run!
52
+ return if all_exist? @targets
53
+ check_source_files!
54
+ @stdout, @stderr, @status = Open3.capture3 @command_line
55
+ check_status!
56
+ check_target_files!
57
+ end
58
+
59
+ private
60
+
61
+ def all_exist?(files)
62
+ files.all?(&File.method(:exist?))
63
+ end
64
+
65
+ def missing(files)
66
+ files.reject(&File.method(:exist?))
67
+ end
68
+
69
+ def check_source_files!
70
+ raise MissingSourceFiles, <<~MISSING_SOURCE unless all_exist? @sources
71
+ Required source files #{missing @sources} for command #{@name} are missing.
72
+ MISSING_SOURCE
73
+ end
74
+
75
+ def check_status!
76
+ raise ExecutionFailed, <<~EXECUTION_FAILED unless @status.success?
77
+ Command #{@name} failed.
78
+ Command line: #{@command_line}
79
+ Status: #{@status}
80
+ Stdout:
81
+ #{@stdout}
82
+ Stderr:
83
+ #{@stderr}
84
+ EXECUTION_FAILED
85
+ end
86
+
87
+ def check_target_files!
88
+ raise MissingTargetFiles, <<~MISSING_TARGET unless all_exist? @targets
89
+ Expected target files #{missing @targets} were not produced by command #{@name}.
90
+ MISSING_TARGET
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,73 @@
1
+ template: |
2
+ \documentclass{article}
3
+ \pagestyle{empty}
4
+ {{ preamble }}
5
+ \newsavebox\snippet
6
+ \begin{lrbox}{\snippet}{{ prepend }}{{ snippet }}{{ append }}\end{lrbox}
7
+ \newwrite\file
8
+ \immediate\openout\file=\jobname.yml
9
+ \immediate\write\file{em: \the\dimexpr1em}
10
+ \immediate\write\file{ex: \the\dimexpr1ex}
11
+ \immediate\write\file{ht: \the\ht\snippet}
12
+ \immediate\write\file{dp: \the\dp\snippet}
13
+ \immediate\write\file{wd: \the\wd\snippet}
14
+ \closeout\file
15
+ \begin{document}\usebox{\snippet}\end{document}
16
+ preamble:
17
+ prepend:
18
+ append:
19
+ dirs:
20
+ work: .antex-cache
21
+ files:
22
+ tex: "{{ dir.work }}/{{ hash }}.tex"
23
+ dvi: "{{ dir.work }}/{{ hash }}.dvi"
24
+ yml: "{{ dir.work }}/{{ hash }}.yml"
25
+ tfm: "{{ dir.work }}/{{ hash }}.tfm.svg"
26
+ fit: "{{ dir.work }}/{{ hash }}.fit.svg"
27
+ svg: "{{ dir.work }}/{{ hash }}.svg"
28
+ pipeline:
29
+ - latexmk
30
+ - dvisvgm_tfm
31
+ - dvisvgm_fit
32
+ - rename
33
+ commands:
34
+ latexmk:
35
+ command:
36
+ - "latexmk"
37
+ - "-output-directory={{ dir.work }}"
38
+ - "{{ file.tex }}"
39
+ sources:
40
+ - "{{ file.tex }}"
41
+ targets:
42
+ - "{{ file.dvi }}"
43
+ - "{{ file.yml }}"
44
+ dvisvgm_tfm:
45
+ command:
46
+ - "dvisvgm"
47
+ - "--no-fonts"
48
+ - "{{ file.dvi }}"
49
+ - "--output={{ file.tfm }}"
50
+ sources:
51
+ - "{{ file.dvi }}"
52
+ targets:
53
+ - "{{ file.tfm }}"
54
+ dvisvgm_fit:
55
+ command:
56
+ - "dvisvgm"
57
+ - "--no-fonts"
58
+ - "--exact"
59
+ - "{{ file.dvi }}"
60
+ - "--output={{ file.fit }}"
61
+ sources:
62
+ - "{{ file.dvi }}"
63
+ targets:
64
+ - "{{ file.fit }}"
65
+ rename:
66
+ command:
67
+ - "cp"
68
+ - "{{ file.fit }}"
69
+ - "{{ file.svg }}"
70
+ sources:
71
+ - "{{ file.fit }}"
72
+ targets:
73
+ - "{{ file.svg }}"
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Antex
4
+ class Error < StandardError; end
5
+ end
@@ -0,0 +1,117 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Antex
4
+ # This class is the beating heart of {Antex}.
5
+ #
6
+ # The simplest usage of this gem involves three steps:
7
+ # # 1. Get a LaTeX snippet and initialize a job.
8
+ # job = Antex::Job.new snippet: "Hello, \TeX world!"
9
+ # # 2. Run the job!
10
+ # job.run!
11
+ # # 3. Do something neat with your new SVG file and its typesetting metrics.
12
+ # job.files(:svg) # => "./.antex-cache/eb64793dafe3bbd963dc663385a22096.svg"
13
+ # job.set_box.measures # => {:ex=>1, :wd=>17.03..., :mt=>-0.05..., ...}
14
+ #
15
+ # The {Antex::Job::DEFAULTS} are tuned to work with a basic
16
+ # +latexmk+/+dvisvgm+ pipeline.
17
+ # To get started with customization. you'll want to read the (not yet well
18
+ # documented) +YAML+ source loaded into the constant at the
19
+ # {https://github.com/paolobrasolin/antex/blob/master/lib/antex/defaults.yml
20
+ # github repo}.
21
+ class Job
22
+ include LiquidHelpers
23
+
24
+ # The configuration defaults for a +latexmk+/+dvisvgm+ pipeline.
25
+ DEFAULTS =
26
+ YAML.load_file(File.join(File.dirname(__FILE__), 'defaults.yml')).freeze
27
+
28
+ # @return [Hash] the initialization options
29
+ attr_reader :options
30
+
31
+ # @return [Hash] the dirs paths rendered from the options
32
+ attr_reader :dirs
33
+
34
+ # @return [Hash] the files paths rendered from the options
35
+ attr_reader :files
36
+
37
+ # @return [String] the unique hash identifying the job
38
+ attr_reader :hash
39
+
40
+ # @return [SetBox, nil] the {SetBox} calculated by the {#run!}
41
+ attr_reader :set_box
42
+
43
+ # @param snippet [String] +TeX+ code snippet to render
44
+ # @param options [Hash] job options
45
+ def initialize(snippet: '', options: Antex::Job::DEFAULTS)
46
+ @options = options
47
+ @snippet = snippet
48
+
49
+ prepare_code
50
+ prepare_hash
51
+ prepare_dirs
52
+ prepare_files
53
+ end
54
+
55
+ # Run the job, compile the +TeX+ snippet and calculate the {#set_box}.
56
+ def run!
57
+ create_dirs
58
+ write_code
59
+ run_pipeline!
60
+ load_set_box
61
+ end
62
+
63
+ private
64
+
65
+ def prepare_code
66
+ @code = liquid_render @options['template'],
67
+ 'preamble' => @options['preamble'],
68
+ 'append' => @options['append'],
69
+ 'prepend' => @options['prepend'],
70
+ 'snippet' => @snippet
71
+ end
72
+
73
+ def prepare_hash
74
+ @hash = Digest::MD5.hexdigest @code
75
+ end
76
+
77
+ def prepare_dirs
78
+ @dirs = liquid_render @options['dirs'],
79
+ 'hash' => @hash
80
+ end
81
+
82
+ def prepare_files
83
+ @files = liquid_render @options['files'],
84
+ 'hash' => @hash,
85
+ 'dir' => @dirs
86
+ end
87
+
88
+ def create_dirs
89
+ @dirs.each_value { |path| FileUtils.mkdir_p path }
90
+ end
91
+
92
+ def write_code
93
+ return if File.exist? @files['tex']
94
+ File.open(@files['tex'], 'w') { |io| io.write @code }
95
+ end
96
+
97
+ def run_pipeline!
98
+ context = { 'hash' => @hash, 'dir' => @dirs, 'file' => @files }
99
+ pipeline = liquid_render @options['pipeline'], context
100
+ commands = liquid_render @options['commands'], context
101
+
102
+ pipeline.each do |command_name|
103
+ options = { name: command_name,
104
+ sources: commands[command_name]['sources'],
105
+ targets: commands[command_name]['targets'],
106
+ command_line: commands[command_name]['command'].join(' ') }
107
+ Command.new(options).run!
108
+ end
109
+ end
110
+
111
+ def load_set_box
112
+ @set_box = SetBox.new.load yml: @files['yml'],
113
+ tfm: @files['tfm'],
114
+ fit: @files['fit']
115
+ end
116
+ end
117
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'liquid'
4
+
5
+ module Antex
6
+ # Exposes helper methods to simplify +Liquid+ templates rendering.
7
+ module LiquidHelpers
8
+ class UnknownClass < Error; end
9
+
10
+ # Recursively renders +Liquid+ template strings, possibly organized in
11
+ # nested arrays and hashes, using the given hash of contextual variables.
12
+ #
13
+ # @param object [String, Array, Hash] the object to render
14
+ # @param context_hash [Hash]
15
+ # the context hash accessible from the object strings
16
+ # @return [String] the rendered object
17
+ # @raise [UnknownClass] when given anything that's not renderable
18
+ def liquid_render(object, context_hash = {})
19
+ case object
20
+ when String
21
+ liquid_render_string object, context_hash
22
+ when Array
23
+ liquid_render_array object, context_hash
24
+ when Hash
25
+ liquid_render_hash object, context_hash
26
+ else
27
+ raise UnknownClass, "I don't know how to render a #{object.class}."
28
+ end
29
+ end
30
+
31
+ private
32
+
33
+ def liquid_render_string(string, context_hash = {})
34
+ Liquid::Template.parse(string).render(context_hash)
35
+ end
36
+
37
+ def liquid_render_array(array, context_hash = {})
38
+ array.map do |element|
39
+ liquid_render element, context_hash
40
+ end
41
+ end
42
+
43
+ def liquid_render_hash(hash, context_hash = {})
44
+ hash.map do |key, value|
45
+ [key, liquid_render(value, context_hash)]
46
+ end.to_h
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Antex
4
+ # Implements an easy to use container for storing measures
5
+ # and retrieving them performing unit conversions.
6
+ #
7
+ # Measures should be a hash with symbolic keys
8
+ # and numeric values with uniform units.
9
+ # mea = Measurable.new
10
+ # mea.measures = { km: 1, mi: 0.621 }
11
+ class Measurable
12
+ class InvalidUnit < Antex::Error; end
13
+
14
+ def initialize
15
+ @default_unit = nil
16
+ @measures = {}
17
+ end
18
+
19
+ # @return [Symbol] the default unit
20
+ attr_reader :default_unit
21
+
22
+ def default_unit=(unit)
23
+ raise InvalidUnit, "Unit #{unit} is undefined." unless @measures.key? unit
24
+ raise InvalidUnit, "Unit #{unit} is zero." if @measures[unit].zero?
25
+ @default_unit = unit
26
+ end
27
+
28
+ # @return [Hash] the stored measures
29
+ # @note When setting, the default unit will be set to +nil+.
30
+ attr_reader :measures
31
+
32
+ def measures=(**measures)
33
+ @default_unit = nil
34
+ @measures = measures
35
+ end
36
+
37
+ private
38
+
39
+ def calculate(metric, unit = @default_unit)
40
+ raise InvalidUnit, 'Default unit is not set.' if unit.nil?
41
+ raise InvalidUnit, "Unit #{unit} is undefined." unless @measures.key? unit
42
+ raise InvalidUnit, "Unit #{unit} is zero." if @measures[unit].zero?
43
+ @measures[metric].fdiv @measures[unit]
44
+ end
45
+
46
+ def respond_to_missing?(method_name, include_private = false)
47
+ (@measures.include? method_name) || super
48
+ end
49
+
50
+ # Once measures are set they can be accessed and converted.
51
+ # mea.km(:km) # => 1.0
52
+ # mea.km(:mi) # => 1.610...
53
+ # mea.mi(:mi) # => 1.0
54
+ # mea.mi(:km) # => 0.621
55
+ #
56
+ # You can set a default unit for quicker access.
57
+ # mea.default_unit = :mi
58
+ # mea.km # => 1.610...
59
+ # mea.mi # => 1.0
60
+ def method_missing(method_name, *arguments, &block)
61
+ return super unless @measures.include? method_name
62
+ send :calculate, method_name, *arguments, &block
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,81 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Antex
4
+ # Encapsulates calculations and results for perfectly typesetting
5
+ # the +SVG+ vectorial conversion of a +TeX+ box.
6
+ #
7
+ # Three files are required by {#load} for initialization:
8
+ # [+YAML+ file containing +TeX+ measures]
9
+ # We obtain this by using +TeX+ directly
10
+ # to measure the box and write to file.
11
+ # Required metrics are +ht+, +dp+ and +wd+ (naturally expressed in +pt+s).
12
+ # [+SVG+ picture fitting +tfm+ metrics]
13
+ # We obtain this by converting the +DVI+ rendition of the box
14
+ # to +SVG+ using {http://dvisvgm.bplaced.net/ +dvisvgm+}.
15
+ # [+SVG+ picture fitting the ink]
16
+ # We obtain this by converting the +DVI+ rendition of the box
17
+ # to +SVG+ using {http://dvisvgm.bplaced.net/ +dvisvgm+}
18
+ # with the +--exact+ flag.
19
+ #
20
+ # After the initialization the calculations are performed immediatly.
21
+ # Six metrics become available:
22
+ # * +mt+, +mr+, +ml+ and +ml+ (the margins, positive or negative)
23
+ # * +wd+ and +ht+ (width and height)
24
+ # * +ex+ (the default unit)
25
+ class SetBox < Measurable
26
+ class InvalidMeasure < Antex::Error; end
27
+
28
+ # @param yml [String] path of the +YAML+ file containing +TeX+ measures
29
+ # @param tfm [String] path of the +SVG+ picture fitting +tfm+ metrics
30
+ # @param fit [String] path of the +SVG+ picture fitting the ink
31
+ # @return [TexBox] returns +self+ after loading
32
+ def load(yml:, tfm:, fit:)
33
+ @tex = TexBox.new.load yml
34
+ @tfm = SVGBox.new.load tfm
35
+ @fit = SVGBox.new.load fit
36
+ @tex.default_unit = :ex
37
+ check_measures!
38
+ self.measures = compute_measures
39
+ self.default_unit = :ex
40
+ self
41
+ end
42
+
43
+ private
44
+
45
+ # Memorandum:
46
+ # .--> x ml fit.dx mr
47
+ # | |--|-------------|--|
48
+ # v y
49
+ # - ,-------------------. -
50
+ # mt | | TFM | |
51
+ # - | ,-------------. | | tfm.dy
52
+ # | | | FIT | | |
53
+ # | | | | | |
54
+ # fit.dy | | | | | | r ,-------. - tex.ht
55
+ # | | | | | | <---> | TEX | |
56
+ # | |- |- - - - - - -| -| | |- - - -| -
57
+ # - | `-------------' | | `-------' - tex.dp
58
+ # mb | | | | |-------|
59
+ # - `-------------------' - tex.wd
60
+ # |-------------------|
61
+ # tfm.dx
62
+ def compute_measures # rubocop:disable Metrics/AbcSize
63
+ ex_px = (@tex.ht + @tex.dp) / @tfm.dy # [ex/px]
64
+ {
65
+ ex: 1,
66
+ th: ex_px * @fit.dy,
67
+ wd: ex_px * @fit.dx,
68
+ ml: ex_px * (- @tfm.ox + @fit.ox),
69
+ mt: ex_px * (- @tfm.oy + @fit.oy),
70
+ mr: ex_px * (+ @tfm.ox - @fit.ox + @tfm.dx - @fit.dx),
71
+ mb: ex_px * (+ @tfm.oy - @fit.oy + @tfm.dy - @fit.dy) - @tex.dp
72
+ }
73
+ end
74
+
75
+ def check_measures!
76
+ raise InvalidMeasure, <<~INVALID_MEASURE if @tfm.dy.zero?
77
+ The given tfm SVG file has zero height.
78
+ INVALID_MEASURE
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'nokogiri'
4
+
5
+ module Antex
6
+ # Loads and manages measures for +SVG+ pictures.
7
+ class SVGBox < Measurable
8
+ # Loads an +SVG+ file and extracts the measures of its +viewBox+.
9
+ #
10
+ # @param filepath [String] the path of the SVG file to load
11
+ # @return [SVGBox] returns +self+ after loading
12
+ def load(filepath)
13
+ svg_ast = Nokogiri::XML.parse File.read(filepath)
14
+ view_box = svg_ast.css('svg').attribute('viewBox')
15
+ magnitudes = view_box.to_s.split(' ').map(&:to_f)
16
+ @measures = %i[ox oy dx dy].zip(magnitudes).to_h
17
+ @measures[:px] ||= 1.0
18
+ @default_unit = :px
19
+ self
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'yaml'
4
+
5
+ module Antex
6
+ # Loads and manages measures for +TeX+ boxes.
7
+ class TexBox < Measurable
8
+ # Loads a +YAML+ file containing +TeX+ measures.
9
+ #
10
+ # The expected input is a hash of named +pt+ lenghts.
11
+ # E.g.:
12
+ #
13
+ # pt: 1.0pt
14
+ # wd: 5.0pt
15
+ # ht: 8.0pt
16
+ # dp: 2.0pt
17
+ #
18
+ # @param filepath [String] the path of the YAML file to load
19
+ # @return [TexBox] returns +self+ after loading
20
+ def load(filepath)
21
+ yaml_hash = YAML.safe_load File.read(filepath)
22
+ units = yaml_hash.keys.map(&:to_sym)
23
+ magnitudes = yaml_hash.values.map { |value| value.chomp('pt').to_f }
24
+ @measures = units.zip(magnitudes).to_h
25
+ @measures[:pt] ||= 1.0
26
+ @default_unit = :pt
27
+ self
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Antex
4
+ VERSION = '0.1.1'
5
+ end
metadata ADDED
@@ -0,0 +1,169 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: antex
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ platform: ruby
6
+ authors:
7
+ - Paolo Brasolin
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-09-30 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: nokogiri
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1'
27
+ - !ruby/object:Gem::Dependency
28
+ name: liquid
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '4'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '4'
41
+ - !ruby/object:Gem::Dependency
42
+ name: guard
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '2.14'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '2.14'
55
+ - !ruby/object:Gem::Dependency
56
+ name: guard-rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '4.7'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '4.7'
69
+ - !ruby/object:Gem::Dependency
70
+ name: simplecov
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '0.15'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '0.15'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rspec
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '3.6'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '3.6'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rubocop
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '0.50'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '0.50'
111
+ - !ruby/object:Gem::Dependency
112
+ name: yard
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '0.9'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '0.9'
125
+ description: 'anTeX implements a universal TeX integration pipeline to easily embed
126
+ and render arbitrary code using any engine and dialect. '
127
+ email: paolo.brasolin@gmail.com
128
+ executables: []
129
+ extensions: []
130
+ extra_rdoc_files: []
131
+ files:
132
+ - LICENSE.txt
133
+ - README.md
134
+ - lib/antex.rb
135
+ - lib/antex/command.rb
136
+ - lib/antex/defaults.yml
137
+ - lib/antex/error.rb
138
+ - lib/antex/job.rb
139
+ - lib/antex/liquid_helpers.rb
140
+ - lib/antex/measurable.rb
141
+ - lib/antex/set_box.rb
142
+ - lib/antex/svg_box.rb
143
+ - lib/antex/tex_box.rb
144
+ - lib/antex/version.rb
145
+ homepage: https://github.com/paolobrasolin/antex
146
+ licenses:
147
+ - MIT
148
+ metadata: {}
149
+ post_install_message:
150
+ rdoc_options: []
151
+ require_paths:
152
+ - lib
153
+ required_ruby_version: !ruby/object:Gem::Requirement
154
+ requirements:
155
+ - - ">="
156
+ - !ruby/object:Gem::Version
157
+ version: '2.3'
158
+ required_rubygems_version: !ruby/object:Gem::Requirement
159
+ requirements:
160
+ - - ">="
161
+ - !ruby/object:Gem::Version
162
+ version: '0'
163
+ requirements: []
164
+ rubyforge_project:
165
+ rubygems_version: 2.6.13
166
+ signing_key:
167
+ specification_version: 4
168
+ summary: Universal TeX integrator
169
+ test_files: []