macaw 0.0.1 → 0.0.40
Sign up to get free protection for your applications and to get access to all the features.
- 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
|