macaw 0.0.1 → 0.0.40
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 +4 -4
- data/.gitignore +2 -16
- data/Gemfile +4 -0
- data/Gemfile.lock +27 -0
- data/LICENSE.txt +1 -1
- data/README.md +82 -0
- data/Rakefile +132 -0
- data/bin/macaw +308 -0
- data/lib/macaw.rb +2 -3
- data/lib/macaw/i18n/de.yml +171 -0
- data/lib/macaw/i18n/en.yml +157 -0
- data/lib/macaw/i18n/es.yml +159 -0
- data/lib/macaw/i18n/fr.yml +160 -0
- data/lib/macaw/i18n/it.yml +157 -0
- data/lib/macaw/i18n/pt-BR.yml +154 -0
- data/lib/macaw/i18n/pt.yml +155 -0
- data/lib/macaw/i18n/ru.yml +159 -0
- data/lib/macaw/i18n/tr.yml +148 -0
- data/lib/macaw/rules/animate.rb +26 -0
- data/lib/macaw/rules/biber.rb +8 -0
- data/lib/macaw/rules/bibtex.rb +8 -0
- data/lib/macaw/rules/clean.rb +10 -0
- data/lib/macaw/rules/dvipdfm.rb +9 -0
- data/lib/macaw/rules/dvipdfmx.rb +9 -0
- data/lib/macaw/rules/dvips.rb +9 -0
- data/lib/macaw/rules/dvipsps2pdf.rb +10 -0
- data/lib/macaw/rules/frontespizio.rb +14 -0
- data/lib/macaw/rules/indent.rb +36 -0
- data/lib/macaw/rules/latex.rb +17 -0
- data/lib/macaw/rules/lmkclean.rb +13 -0
- data/lib/macaw/rules/lualatex.rb +17 -0
- data/lib/macaw/rules/lualatexmk.rb +17 -0
- data/lib/macaw/rules/luatex.rb +17 -0
- data/lib/macaw/rules/make.rb +9 -0
- data/lib/macaw/rules/makeglossaries.rb +9 -0
- data/lib/macaw/rules/makeindex.rb +16 -0
- data/lib/macaw/rules/nomencl.rb +17 -0
- data/lib/macaw/rules/pdflatex.rb +17 -0
- data/lib/macaw/rules/pdflatexmk.rb +17 -0
- data/lib/macaw/rules/pdftex.rb +16 -0
- data/lib/macaw/rules/ps2pdf.rb +16 -0
- data/lib/macaw/rules/sketch.rb +14 -0
- data/lib/macaw/rules/songidx.rb +8 -0
- data/lib/macaw/rules/sumatrapdf.rb +10 -0
- data/lib/macaw/rules/tex.rb +9 -0
- data/lib/macaw/rules/texcount.rb +9 -0
- data/lib/macaw/rules/xdvipdfmx.rb +9 -0
- data/lib/macaw/rules/xelatex.rb +16 -0
- data/lib/macaw/rules/xelatexmk.rb +14 -0
- data/lib/macaw/rules/xetex.rb +15 -0
- data/lib/macaw/version.rb +2 -2
- data/macaw.gemspec +24 -17
- data/test/test_macaw.rb +8 -0
- metadata +133 -30
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 06dfef52346c5bafb0f0fc2ee6ffa2f95298cd1a
|
4
|
+
data.tar.gz: 1f11bf5f437fb1c5665385cad0d91541613716e9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6861e834380c57a5a354178c533ebfe9cdc084d765a5d063f5ac73c0c7e82c5476aae0e85f0788f1165f015ad72cb7c0d12527e0053ef3355762680d96a7a0a0
|
7
|
+
data.tar.gz: dd05f1a8f17e67eb2f2506010e5fce59688597fc63683c2d5d2589c8e21ab8c1d070f450fe1b04aa3178724b26bb1226cca6193c11ee76704730d6a9a3f19618
|
data/.gitignore
CHANGED
data/Gemfile
CHANGED
data/Gemfile.lock
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
macaw (0.0.40)
|
5
|
+
i18n
|
6
|
+
json_pure
|
7
|
+
os
|
8
|
+
require_all
|
9
|
+
|
10
|
+
GEM
|
11
|
+
remote: https://rubygems.org/
|
12
|
+
specs:
|
13
|
+
i18n (0.6.9)
|
14
|
+
java_properties (0.0.4)
|
15
|
+
json_pure (1.8.1)
|
16
|
+
os (0.9.6)
|
17
|
+
rake (10.3.2)
|
18
|
+
require_all (1.3.2)
|
19
|
+
|
20
|
+
PLATFORMS
|
21
|
+
ruby
|
22
|
+
|
23
|
+
DEPENDENCIES
|
24
|
+
bundler (~> 1.3)
|
25
|
+
java_properties
|
26
|
+
macaw!
|
27
|
+
rake
|
data/LICENSE.txt
CHANGED
data/README.md
CHANGED
@@ -1 +1,83 @@
|
|
1
1
|
# Macaw
|
2
|
+
|
3
|
+
Macaw is a Ruby Arara, a Ruby port of http://cereda.github.io/arara/. This is in many aspects very rough around the
|
4
|
+
edges at this moment as it was written in a weekend while I was busy doing other things. Ruby does rock.
|
5
|
+
|
6
|
+
## Installation
|
7
|
+
|
8
|
+
To install, make sure you have Ruby 1.9 or later installed, and then (on a command line, sorry) type
|
9
|
+
|
10
|
+
gem install macaw
|
11
|
+
|
12
|
+
To update Macaw, you type
|
13
|
+
|
14
|
+
gem update macaw
|
15
|
+
gem cleanup macaw
|
16
|
+
|
17
|
+
## Usage
|
18
|
+
|
19
|
+
In day-to-day use it will (should) behave exactly like Arara. It accepts the same command line parameters and reads the
|
20
|
+
same *standard* rules that are bundled with Arara; if you use only those, there's no need to change anything in your
|
21
|
+
LaTeX documents. Instead of
|
22
|
+
|
23
|
+
arara
|
24
|
+
|
25
|
+
you call
|
26
|
+
|
27
|
+
macaw
|
28
|
+
|
29
|
+
(or macaw.bat if you want to run it from a Windows IDE)
|
30
|
+
|
31
|
+
## Custom rules
|
32
|
+
|
33
|
+
Macaw doesn't use yaml for its rules; rules are Ruby scripts. Macaw will read your araraconfig.yaml to find the paths to
|
34
|
+
your custom rules; in that location, you can drop files that end in '.rb', which are structured like this:
|
35
|
+
|
36
|
+
class Macaw # this line is mandatory
|
37
|
+
# define your macaw rule here. The name after 'def' is the name of your rule,
|
38
|
+
# the options between parenthesis are the parameters your rule will accept.
|
39
|
+
# Optional parameters are marked using '=nil'.
|
40
|
+
#
|
41
|
+
# For those of you who know ruby, this looks familiar but behaves oddly;
|
42
|
+
# using anything else than 'nil' will likewise make the parameter optional,
|
43
|
+
# but you will *always* be passed 'nil' if the Arara rule in the tex file
|
44
|
+
# did not pass the parameters).
|
45
|
+
def zoterobib(collection, format=nil, port=nil, exportCharset=nil, exportNotes=nil, useJournalAbbreviation=nil)
|
46
|
+
# ||= assigns a value if it wasn't set; set your default values here
|
47
|
+
format ||= 'biblatex'
|
48
|
+
port ||= 23119
|
49
|
+
|
50
|
+
# this adds the optional parameters to the url
|
51
|
+
params = []
|
52
|
+
params << "&exportCharset=#{exportCharset}" if exportCharset
|
53
|
+
params << "&exportNotes=#{exportNotes}" if exportNotes
|
54
|
+
params << "&useJournalAbbreviation=#{useJournalAbbreviation}" if useJournalAbbreviation
|
55
|
+
|
56
|
+
# the ~ is a Macaw feature -- it will escape the path of the string after it to be
|
57
|
+
# safe to be passed on the command line. It will do the right thing depending on
|
58
|
+
# the platform it's being run on.
|
59
|
+
bib = ~"#{@base}.bib"
|
60
|
+
url = ~"http://localhost:#{port}/better-bibtex/collection?#{collection}.#{format}#{params}"
|
61
|
+
|
62
|
+
# Macaw.system executes the command, captures output, does logging, etc
|
63
|
+
Macaw.system "curl --connect-timeout 5 -z #{bib} -o #{bib} #{url}"
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
You are not required to use Macaw.system BTW; Arara is mainly focused on running shell programs, but since Macaw rules
|
68
|
+
are ruby scripts, they can do some things natively:
|
69
|
+
|
70
|
+
# Clean rule for arara
|
71
|
+
# author: Paulo Cereda
|
72
|
+
# requires arara 3.0+
|
73
|
+
class Macaw
|
74
|
+
def clean(files)
|
75
|
+
files.reject{|f| f.downcase == @file.downcase}.each{|f|
|
76
|
+
Macaw.log "removing #{f}"
|
77
|
+
File.unlink(f)
|
78
|
+
}
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
If you don't use Macaw.system, you can use *Macaw.log* to pass output to the logging system (which will be subject to
|
83
|
+
choices the user makes on the command line, or *Macaw.error* to show a fatal error message and halt the build.
|
data/Rakefile
CHANGED
@@ -1 +1,133 @@
|
|
1
1
|
require 'bundler/gem_tasks'
|
2
|
+
require 'fileutils'
|
3
|
+
require 'yaml'
|
4
|
+
require 'pp'
|
5
|
+
require 'java_properties'
|
6
|
+
|
7
|
+
task :default => :build
|
8
|
+
|
9
|
+
task :bump do
|
10
|
+
version = Macaw::VERSION.split('.').collect{|v| Integer(v)}
|
11
|
+
version[2] += 1
|
12
|
+
version = version.collect{|v| v.to_s}.join('.')
|
13
|
+
File.open('lib/macaw/version.rb', 'w'){|f| f.write("class Macaw\n VERSION = #{version.inspect}\nend\n") }
|
14
|
+
puts `git add lib/macaw/version.rb Gemfile.lock`
|
15
|
+
end
|
16
|
+
|
17
|
+
task :publish do
|
18
|
+
sh "git tag #{Macaw::VERSION}"
|
19
|
+
Dir['pkg/*.gem'].each{|f| File.unlink(f)}
|
20
|
+
Rake::Task["build"].invoke
|
21
|
+
sh "gem push #{Dir['pkg/*.gem'].join(' ')}"
|
22
|
+
sh "git push"
|
23
|
+
end
|
24
|
+
|
25
|
+
task :test do
|
26
|
+
sh "cp test/test.tex ."
|
27
|
+
sh "./bin/macaw -p -l"
|
28
|
+
sh "rm test.*"
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
class LanguageManager
|
33
|
+
class NoTranslation < StandardError; end
|
34
|
+
|
35
|
+
def initialize
|
36
|
+
@translations = {}
|
37
|
+
Dir['lib/macaw/i18n/*.yml'].each{|yml|
|
38
|
+
@translations[File.basename(yml, File.extname(yml))] = YAML.load_file(yml)
|
39
|
+
}
|
40
|
+
@en = @translations.delete('en')
|
41
|
+
@keys = keys(@en[@en.keys[0]])
|
42
|
+
end
|
43
|
+
|
44
|
+
def keys(h, prefix=[])
|
45
|
+
c = []
|
46
|
+
h.each_pair{|k, v|
|
47
|
+
if v.is_a?(Hash)
|
48
|
+
c += keys(v, prefix + [k])
|
49
|
+
else
|
50
|
+
c << prefix + [k]
|
51
|
+
end
|
52
|
+
}
|
53
|
+
c
|
54
|
+
end
|
55
|
+
|
56
|
+
def resolve(h, k)
|
57
|
+
raise NoTranslation if h.nil?
|
58
|
+
h = h[k.shift]
|
59
|
+
return h if k.empty?
|
60
|
+
return resolve(h, k)
|
61
|
+
end
|
62
|
+
|
63
|
+
def vars(s)
|
64
|
+
v = []
|
65
|
+
s.gsub(/%\{([^}]+)\}/){|k| v << k}
|
66
|
+
return v.sort
|
67
|
+
end
|
68
|
+
|
69
|
+
def port
|
70
|
+
Dir['arara/translations/*.input'].each{|prop|
|
71
|
+
lang = File.basename(prop, File.extname(prop)).gsub('_', '-').gsub(/^Messages-/, '')
|
72
|
+
lang = 'en' if lang == 'Messages'
|
73
|
+
next if lang == 'Messages.sample'
|
74
|
+
strings = JavaProperties::Properties.new(prop)
|
75
|
+
|
76
|
+
tr = {lang => {}}
|
77
|
+
strings.each{|key, value|
|
78
|
+
section, localkey = *key.to_s.split('_', 2)
|
79
|
+
section.downcase!
|
80
|
+
|
81
|
+
case key
|
82
|
+
when :Log_ProcessingFile, :Msg_NoDirectivesFound, :Error_FileDoesNotExist
|
83
|
+
value.gsub!('{0}', '%{file}')
|
84
|
+
when :Msg_SpecialThanks
|
85
|
+
value.gsub!(/Alan.*Kottwitz/i, '%{contributors}')
|
86
|
+
when :Error_InvalidLanguageConfigurationFile
|
87
|
+
value.gsub!('{0}', '%{languages}')
|
88
|
+
end
|
89
|
+
|
90
|
+
value.gsub!(/(\{[0-9]+\})/){"%#{$1}"}
|
91
|
+
value.gsub!('arara', 'macaw')
|
92
|
+
value.gsub!('Arara', 'Macaw')
|
93
|
+
value.gsub!("''", '"')
|
94
|
+
|
95
|
+
tr[lang][section] ||= {}
|
96
|
+
tr[lang][section][localkey] = value
|
97
|
+
}
|
98
|
+
tr[lang]['help']['Usage'] ||= 'Usage'
|
99
|
+
tr[lang]['help']['Progress'] ||= 'Print dots to mark progress'
|
100
|
+
File.open("lib/macaw/i18n/#{lang}.yml", 'w'){|f| f.write(tr.to_yaml)}
|
101
|
+
}
|
102
|
+
end
|
103
|
+
|
104
|
+
|
105
|
+
def test
|
106
|
+
@translations.values.each{|l|
|
107
|
+
@keys.each{|k|
|
108
|
+
ens = resolve(@en[@en.keys[0]], k.dup)
|
109
|
+
ls = nil
|
110
|
+
begin
|
111
|
+
ls = resolve(l[l.keys[0]], k.dup)
|
112
|
+
rescue NoTranslation
|
113
|
+
ls = nil
|
114
|
+
end
|
115
|
+
|
116
|
+
if ls.to_s == ''
|
117
|
+
puts "No translation: #{l.keys[0]}: #{k.join('.')}"
|
118
|
+
next
|
119
|
+
end
|
120
|
+
|
121
|
+
puts "Var mismatch: #{l.keys[0]}: #{k.join('.')}\n #{vars(ens).inspect}\n #{vars(ls).inspect}" if vars(ens) != vars(ls)
|
122
|
+
}
|
123
|
+
}
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
task :gettranslations do
|
128
|
+
LanguageManager.new.port
|
129
|
+
end
|
130
|
+
|
131
|
+
task :checktranslations do
|
132
|
+
LanguageManager.new.test
|
133
|
+
end
|
data/bin/macaw
ADDED
@@ -0,0 +1,308 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# encoding: UTF-8
|
3
|
+
|
4
|
+
require 'yaml'
|
5
|
+
require 'pp'
|
6
|
+
require_relative '../lib/macaw'
|
7
|
+
require_relative '../lib/macaw/version'
|
8
|
+
require 'json/pure'
|
9
|
+
require 'os'
|
10
|
+
require 'ostruct'
|
11
|
+
require 'shellwords'
|
12
|
+
require 'optparse'
|
13
|
+
require 'timeout'
|
14
|
+
require 'i18n'
|
15
|
+
require 'open3'
|
16
|
+
|
17
|
+
puts [
|
18
|
+
' __ __ ',
|
19
|
+
'| \/ | __ _ ___ __ ___ __',
|
20
|
+
'| |\/| |/ _` |/ __/ _` \ \ /\ / /',
|
21
|
+
'| | | | (_| | (_| (_| |\ V V / ',
|
22
|
+
'|_| |_|\__,_|\___\__,_| \_/\_/ ',
|
23
|
+
' ',
|
24
|
+
].join("\n")
|
25
|
+
|
26
|
+
CONTRIBUTORS = [
|
27
|
+
'Alan Munn',
|
28
|
+
'Andrew Stacey',
|
29
|
+
'Brent Longborough',
|
30
|
+
'Clemens Niederberger',
|
31
|
+
'David Carlisle',
|
32
|
+
'Enrico Gregorio',
|
33
|
+
'Francesco Endrici',
|
34
|
+
'Gonzalo Medina',
|
35
|
+
'Harish Kumar',
|
36
|
+
'?lhan Polat',
|
37
|
+
'Joseph Wright',
|
38
|
+
'Marco Daniel',
|
39
|
+
'Mikaδl Maunier',
|
40
|
+
'Patrick Gundlach',
|
41
|
+
'Rasmus Roulund',
|
42
|
+
'Sergey Ulyanov',
|
43
|
+
'Stefan Kottwitz'
|
44
|
+
].join(', ')
|
45
|
+
|
46
|
+
I18n.enforce_available_locales = true
|
47
|
+
I18n.load_path = Dir[File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib', 'macaw', 'i18n', '*.yml'))]
|
48
|
+
I18n.default_locale = :en
|
49
|
+
|
50
|
+
def options!
|
51
|
+
options = {}
|
52
|
+
[true, false].collect{|dryrun|
|
53
|
+
opts = OptionParser.new{|parser|
|
54
|
+
parser.banner = "#{I18n.t('help.Usage')}: macaw [options] FILE"
|
55
|
+
parser.separator ""
|
56
|
+
|
57
|
+
options[:language] = I18n.default_locale
|
58
|
+
parser.on('-L', '--language LANG', I18n.t('help.Language')){|lang|
|
59
|
+
begin
|
60
|
+
I18n.locale = lang.intern
|
61
|
+
options[:language] = lang.intern
|
62
|
+
rescue I18n::InvalidLocale
|
63
|
+
if !dryrun
|
64
|
+
puts I81n.t('error.InvalidLanguageConfigurationFile', languages: I18n.available_locales.collect{|l| l.to_s}.join(', '))
|
65
|
+
exit
|
66
|
+
end
|
67
|
+
end
|
68
|
+
}
|
69
|
+
|
70
|
+
parser.on('-p', '--progress', I18n.t('help.Progress')) {|v|
|
71
|
+
options[:progress] = v
|
72
|
+
}
|
73
|
+
parser.on('-l', '--log', I18n.t('help.Log')) {|v|
|
74
|
+
options[:log] = v
|
75
|
+
}
|
76
|
+
|
77
|
+
parser.on('-t', '--timeout MILLISECONDS', I18n.t('help.Timeout')){|timeout|
|
78
|
+
options[:timeout] = Float(timeout) / 1000
|
79
|
+
}
|
80
|
+
|
81
|
+
parser.on('-r', '--rules', 'Available rules') {|v|
|
82
|
+
options[:rules] = v
|
83
|
+
}
|
84
|
+
|
85
|
+
parser.on('-v', '--verbose', I18n.t('help.Verbose')) {|v|
|
86
|
+
options[:verbose] = v
|
87
|
+
}
|
88
|
+
|
89
|
+
parser.on_tail('-h', '--help', '--usage', I18n.t('help.Help')){
|
90
|
+
if !dryrun
|
91
|
+
puts parser.help
|
92
|
+
exit
|
93
|
+
end
|
94
|
+
}
|
95
|
+
|
96
|
+
parser.on_tail('-V', '--version', I18n.t('help.Version')){
|
97
|
+
if !dryrun
|
98
|
+
puts "macaw #{Macaw::VERSION} - #{I18n.t('header.Slogan')}\nCopyright (c) 2012, Paulo Roberto Massa Cereda\n"
|
99
|
+
puts I18n.t('header.AllRightsReserved')
|
100
|
+
puts "\n"
|
101
|
+
puts I18n.t('msg.SpecialThanks', :contributors => CONTRIBUTORS).gsub(/(.{1,#{60}})(?: +|$)\n?|(.{#{60}})/, "\\1\\2\n")
|
102
|
+
exit
|
103
|
+
end
|
104
|
+
}
|
105
|
+
}
|
106
|
+
if dryrun
|
107
|
+
opts.parse!(ARGV.dup)
|
108
|
+
else
|
109
|
+
opts.parse!
|
110
|
+
end
|
111
|
+
}
|
112
|
+
OpenStruct.new(options)
|
113
|
+
end
|
114
|
+
|
115
|
+
CONFIGFILE = [File.join(Dir.home, 'araraconfig.yaml'), File.join(Dir.home, '.araraconfig.yaml')].detect{|config| File.file?(config) }
|
116
|
+
CONFIG = CONFIGFILE ? YAML.load_file(CONFIGFILE) : {}
|
117
|
+
|
118
|
+
class String
|
119
|
+
def ~
|
120
|
+
if OS.windows?
|
121
|
+
return '"' + self.gsub('"', '""') + '"'
|
122
|
+
else
|
123
|
+
return self.shellescape
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
class JSON::Pure::Parser
|
129
|
+
IDENTIFIER = /[^:\s\\",{}\[\]]+/i
|
130
|
+
alias :parse_quoted_string :parse_string
|
131
|
+
|
132
|
+
def parse_string
|
133
|
+
if match?(IDENTIFIER)
|
134
|
+
str = scan(IDENTIFIER)
|
135
|
+
return true if str == 'yes'
|
136
|
+
return false if str == 'no'
|
137
|
+
return str
|
138
|
+
end
|
139
|
+
|
140
|
+
return parse_quoted_string
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
class Macaw
|
145
|
+
class CommandlineError < StandardError; end
|
146
|
+
|
147
|
+
@@log = nil
|
148
|
+
|
149
|
+
def initialize(tex)
|
150
|
+
@file = tex
|
151
|
+
@base = File.join(File.dirname(@file), File.basename(@file, File.extname(@file)))
|
152
|
+
end
|
153
|
+
attr_reader :file, :base
|
154
|
+
|
155
|
+
def halt
|
156
|
+
error 'Halted on user request'
|
157
|
+
end
|
158
|
+
|
159
|
+
ERRORMODES=[:exit, :throw, :ignore]
|
160
|
+
def self.error(msg, onfail=:exit)
|
161
|
+
throw "errormode can only be #{ERRORMODES.inspect}" unless ERRORMODES.include?(onfail)
|
162
|
+
case onfail
|
163
|
+
when :exit
|
164
|
+
@@log.close if @@log
|
165
|
+
puts "\n\n#{msg}"
|
166
|
+
exit 1
|
167
|
+
when :throw
|
168
|
+
raise CommandlineError, msg
|
169
|
+
else
|
170
|
+
puts msg
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
def self.options
|
175
|
+
@@options ||= options!
|
176
|
+
end
|
177
|
+
|
178
|
+
def self.run
|
179
|
+
@@options ||= options!
|
180
|
+
|
181
|
+
if @@options.rules
|
182
|
+
vars = Macaw.new('').instance_variables.collect{|v| v.to_s.sub(/^@/, '').intern}
|
183
|
+
w = 0
|
184
|
+
rules = {}
|
185
|
+
self.instance_methods(false).sort{|a, b| a.to_s <=> b.to_s }.each{|method|
|
186
|
+
next if vars.include?(method)
|
187
|
+
w = [w, method.to_s.length].max
|
188
|
+
rules[method.to_s] = self.instance_method(method).parameters.sort{|a, b|
|
189
|
+
a = a.collect{|v| v.to_s}
|
190
|
+
b = b.collect{|v| v.to_s}
|
191
|
+
if a[0] != b[0]
|
192
|
+
a[0] <=> b[0]
|
193
|
+
else
|
194
|
+
b[1] <=> a[1]
|
195
|
+
end
|
196
|
+
}.collect{|p| "#{p[1]}:#{p[0]}"}.join(', ')
|
197
|
+
}
|
198
|
+
rules.each_pair{|method, params|
|
199
|
+
if params.length == 0
|
200
|
+
puts method
|
201
|
+
else
|
202
|
+
puts "#{method.ljust(w, ' ')}: #{params}"
|
203
|
+
end
|
204
|
+
}
|
205
|
+
exit
|
206
|
+
end
|
207
|
+
|
208
|
+
|
209
|
+
if ARGV.size == 0 && Dir['*.tex'].size == 1
|
210
|
+
puts "No TeX file offered, defaulting to #{Dir['*.tex'][0]}"
|
211
|
+
ARGV.push(Dir['*.tex'][0])
|
212
|
+
end
|
213
|
+
error("No filename to process") if ARGV.size == 0
|
214
|
+
error("Expected exactly one filename to process #{ARGV.inspect}") if ARGV.size != 1
|
215
|
+
tex = File.file?(ARGV[0]) ? ARGV[0] : ARGV[0] + '.tex'
|
216
|
+
error(I18n.t('error.FileDoesNotExist', file: tex)) if !File.exists?(tex)
|
217
|
+
|
218
|
+
Macaw.load_rules
|
219
|
+
|
220
|
+
puts I18n.t('log.ProcessingFile', file: tex)
|
221
|
+
|
222
|
+
macaw = Macaw.new(tex)
|
223
|
+
@@log = File.open(macaw.base + '.log', 'w') if @@options.log
|
224
|
+
|
225
|
+
executed = 0
|
226
|
+
IO.readlines(tex).each_with_index{|line, lineno|
|
227
|
+
@@lineno = lineno + 1
|
228
|
+
|
229
|
+
next unless line =~ /^% arara: /
|
230
|
+
executed += 1
|
231
|
+
line.strip!
|
232
|
+
line.sub!(/^%\s+arara\s*:\s*/, '')
|
233
|
+
data = line.split(':', 2).collect{|v| v.strip}
|
234
|
+
|
235
|
+
cmd = data[0]
|
236
|
+
next if cmd == ''
|
237
|
+
|
238
|
+
params = {}
|
239
|
+
begin
|
240
|
+
params = JSON.parse(data[1]) if data[1]
|
241
|
+
rescue => e
|
242
|
+
error("cannot parse command #{line.inspect}: #{e}")
|
243
|
+
end
|
244
|
+
|
245
|
+
cmd = cmd.intern
|
246
|
+
|
247
|
+
error "no such rule #{cmd}" unless macaw.respond_to?(cmd)
|
248
|
+
|
249
|
+
accept = Macaw.instance_method(cmd).parameters
|
250
|
+
required = accept.collect{|k, v| k == :req ? v : nil}.compact
|
251
|
+
optional = accept.collect{|k, v| k != :req ? v : nil}.compact
|
252
|
+
|
253
|
+
missing = required - params.keys.collect{|k| k.intern}
|
254
|
+
error "#{line}: missing required parameter#{missing.size > 1 ? 's' : ''}: #{missing.inspect}" if missing.size > 0
|
255
|
+
|
256
|
+
unexpected = params.keys.collect{|k| k.intern} - (required + optional)
|
257
|
+
error "#{line}: unexpected parameter#{unexpected.size > 1 ? 's' : ''}: #{unexpected.inspect}" if unexpected.size > 0
|
258
|
+
|
259
|
+
puts "\n** #{line} **\n"
|
260
|
+
macaw.send(cmd, *accept.collect{|k, v| params[v.to_s]})
|
261
|
+
}
|
262
|
+
|
263
|
+
if executed == 0
|
264
|
+
puts I18n.t('log.NoDirectivesFound', file: tex)
|
265
|
+
else
|
266
|
+
puts I18n.t('log.Done')
|
267
|
+
end
|
268
|
+
end
|
269
|
+
|
270
|
+
def self.log(line, force=false)
|
271
|
+
if @@options.verbose || @@options.progress || force
|
272
|
+
print (options.progress && !force ? '.' : line)
|
273
|
+
STDOUT.flush
|
274
|
+
end
|
275
|
+
@@log.write(line) if @@log
|
276
|
+
end
|
277
|
+
|
278
|
+
def self.system(cmd, onfail=:exit)
|
279
|
+
throw "errormode can only be #{ERRORMODES.inspect}" unless ERRORMODES.include?(onfail)
|
280
|
+
|
281
|
+
cmd = cmd.compact.join(' ') if cmd.is_a?(Array)
|
282
|
+
log(cmd)
|
283
|
+
|
284
|
+
output = ''
|
285
|
+
begin
|
286
|
+
Timeout::timeout(@@options.timeout || 0) {
|
287
|
+
Open3.popen2e(cmd) do |stdin, stdout_err, wait_thr|
|
288
|
+
while line = stdout_err.gets
|
289
|
+
self.log(line)
|
290
|
+
output += line + "\n"
|
291
|
+
end
|
292
|
+
|
293
|
+
exit_status = wait_thr.value
|
294
|
+
error "cmd failed: #{cmd}", onfail unless exit_status.success?
|
295
|
+
end
|
296
|
+
}
|
297
|
+
rescue Timeout::Error
|
298
|
+
error "#{cmd}: timed out after #{@@options.timeout} seconds" if failonerror
|
299
|
+
end
|
300
|
+
return output
|
301
|
+
end
|
302
|
+
|
303
|
+
def self.load_rules
|
304
|
+
CONFIG['paths'].each{|path| require_all path} if CONFIG['paths']
|
305
|
+
end
|
306
|
+
end
|
307
|
+
|
308
|
+
Macaw.run
|