livetext 0.9.14 → 0.9.15
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/lib/cmdargs.rb +93 -0
- data/lib/formatline.rb +56 -83
- data/lib/helpers.rb +142 -4
- data/lib/livetext.rb +11 -141
- data/lib/parser/file.rb +8 -0
- data/lib/parser/mixin.rb +28 -15
- data/lib/parser/set.rb +35 -26
- data/lib/parser/string.rb +19 -4
- data/lib/processor.rb +1 -4
- data/lib/standard.rb +56 -96
- data/plugin/bookish.rb +26 -22
- data/plugin/calibre.rb +1 -1
- data/plugin/livemagick.rb +10 -10
- data/plugin/markdown.rb +13 -11
- data/plugin/pyggish.rb +94 -84
- data/plugin/tutorial.rb +10 -5
- data/test/all.rb +0 -1
- data/test/snapshots/OMIT.txt +7 -8
- data/test/snapshots/clusion.txt +35 -0
- data/test/snapshots/error_inc_line_num/actual-error.txt +14 -0
- data/test/snapshots/error_inc_line_num/actual-output.txt +7 -0
- data/test/snapshots/error_inc_line_num/match-error.txt +1 -1
- data/test/snapshots/error_inc_line_num/out-sdiff.txt +14 -0
- data/test/snapshots/error_invalid_name/actual-error.txt +10 -0
- data/test/snapshots/error_invalid_name/actual-output.txt +0 -0
- data/test/snapshots/error_invalid_name/match-error.txt +1 -1
- data/test/snapshots/error_invalid_name/out-sdiff.txt +6 -0
- data/test/snapshots/error_line_num/match-error.txt +1 -1
- data/test/snapshots/error_mismatched_end/match-error.txt +1 -1
- data/test/snapshots/error_missing_end/actual-error.txt +10 -0
- data/test/snapshots/error_missing_end/actual-output.txt +0 -0
- data/test/snapshots/error_missing_end/match-error.txt +1 -1
- data/test/snapshots/error_missing_end/out-sdiff.txt +6 -0
- data/test/snapshots/error_no_such_copy/actual-error.txt +10 -0
- data/test/snapshots/error_no_such_copy/actual-output.txt +0 -0
- data/test/snapshots/error_no_such_copy/match-error.txt +1 -1
- data/test/snapshots/error_no_such_copy/out-sdiff.txt +5 -0
- data/test/snapshots/error_no_such_copy/source.lt3 +0 -1
- data/test/snapshots/error_no_such_inc/actual-error.txt +10 -0
- data/test/snapshots/error_no_such_inc/actual-output.txt +0 -0
- data/test/snapshots/error_no_such_inc/match-error.txt +1 -1
- data/test/snapshots/error_no_such_inc/out-sdiff.txt +6 -0
- data/test/snapshots/error_no_such_mixin/actual-error.txt +37 -0
- data/test/snapshots/error_no_such_mixin/actual-output.txt +0 -0
- data/test/snapshots/error_no_such_mixin/out-sdiff.txt +6 -0
- data/test/snapshots/simple_import/actual-error.txt +8 -0
- data/test/snapshots/simple_import/actual-output.txt +3 -0
- data/test/snapshots/simple_import/err-sdiff.txt +9 -0
- data/test/snapshots/simple_import/expected-error.txt +0 -0
- data/test/snapshots/simple_import/expected-output.txt +7 -0
- data/test/snapshots/simple_import/out-sdiff.txt +9 -0
- data/test/snapshots/simple_import/simple_import.rb +5 -0
- data/test/snapshots/simple_import/source.lt3 +7 -0
- data/test/snapshots/simple_include/source.lt3 +0 -1
- data/test/snapshots.rb +3 -2
- data/test/unit/all.rb +1 -0
- data/test/unit/formatline.rb +650 -0
- data/test/unit/parser/importable.rb +1 -1
- data/test/unit/parser/mixin.rb +1 -1
- data/test/unit/parser/set.rb +19 -12
- data/test/unit/parser/string.rb +14 -14
- metadata +32 -5
- data/test/formatting-tests.rb +0 -35
- data/test/formatting.rb +0 -103
- data/test/snapshots/formatting-tests.txt +0 -124
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a8d345a0f52ce0d7c62f40f8798793faf5136f8ce72cde8576a0284220c08082
|
4
|
+
data.tar.gz: 4e037527c3abd873c9cf8ca49685d99c68fffab9630a67c1193e898e961c4d48
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5b2957b2fe57d0abeff6029c63e310b7d26d653e1e7848c4026d2c16f43e6c37f6c9bf2fb63f2dfcd4e719cc82113cf549413362da43c14ac12312cafad1a744
|
7
|
+
data.tar.gz: 696a9ff22bff7caae99534e1a9431e9914e9137be4212674598c2ee66a58c11bd37c56bc90c52dd0d0cae3450f8905081202fbdc08f05a6164abd2de2dc5e7ce
|
data/lib/cmdargs.rb
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
require_relative 'livetext'
|
2
|
+
|
3
|
+
=begin
|
4
|
+
Weird concepts to understand here...
|
5
|
+
|
6
|
+
1. A Livetext dot-command (flush left) usually looks like:
|
7
|
+
.foobar
|
8
|
+
2. A dot-command (left-indented) usually looks like:
|
9
|
+
$.foobar
|
10
|
+
3. More generally, it may have any number of parameters (0, 1, ...)
|
11
|
+
.redirect somefile.txt append
|
12
|
+
4. Variables and functions *can* appear (rare in practice??)
|
13
|
+
.redirect somefile$my_suffix $$my_mode
|
14
|
+
5. A trailing # comment may appear
|
15
|
+
a. Stripped... saved in #raw ? #data ? #comment ? elsewhere?
|
16
|
+
b. NOT the "dot" as a comment!
|
17
|
+
6. .foobar # This here is a comment
|
18
|
+
7. #data accessor returns all data on the .foo line...
|
19
|
+
a. ...After the initial space
|
20
|
+
b. ...Including spaces
|
21
|
+
c. Including comment??
|
22
|
+
d. .foo This is o n l y a test.
|
23
|
+
# #data returns: "This is o n l y a test."
|
24
|
+
e. What about formatting???
|
25
|
+
f. What about: comments? variables? functions?
|
26
|
+
|
27
|
+
7. Some commands have NO body while others have an OPTIONAL or REQUIRED body
|
28
|
+
a. Assume .cmd1 definition forbids a body (then a body is an error)
|
29
|
+
.cmd1 # may NOT have a body
|
30
|
+
b. Assume .cmd2 definition PERMITS a body
|
31
|
+
.cmd2 # may or MAY NOT have body/.end
|
32
|
+
c. Assume .cmd3 definition PERMITS a body
|
33
|
+
.cmd3 # REQUIRES a body/.end
|
34
|
+
. stuff...
|
35
|
+
.end
|
36
|
+
8. Inside a body:
|
37
|
+
8a. Leading dot has no special meaning (though the associated method may parse it!)
|
38
|
+
8b. BUG? Currently leading dot is a comment INSIDE a body?
|
39
|
+
8a. No leading char is special (though the associated method may parse it!)
|
40
|
+
8a. No trailing #-comments (though the associated method may parse it!)
|
41
|
+
8c. ?? We should or shouldn't look for variables/functions? or make it an option?
|
42
|
+
8d. .end may naturally not be used (but see .raw where it may)
|
43
|
+
9. the args accessor is a simple array of strings
|
44
|
+
|
45
|
+
|
46
|
+
=end
|
47
|
+
|
48
|
+
class Livetext::CmdData
|
49
|
+
|
50
|
+
attr_reader :data, :args, :nargs, :arity, :comment, :raw # , ...?
|
51
|
+
|
52
|
+
def initialize(data, body: false, arity: :N) # FIXME maybe just add **options ??
|
53
|
+
# arity: (num) fixed number 0 or more
|
54
|
+
# :N arbitrary number
|
55
|
+
# n1..n2 range
|
56
|
+
# body: true => this command has a body + .end
|
57
|
+
# how raw is raw?
|
58
|
+
# remove comment - always/sometimes/never?
|
59
|
+
# var_func_parse - always/sometimes/never?
|
60
|
+
# var_func_parse inside body??
|
61
|
+
@data = data.dup # comment? vars? funcs?
|
62
|
+
@raw = data.dup # comment? vars? funcs?
|
63
|
+
@args = data.split # simple array
|
64
|
+
@nargs = nargs # not really "needed"
|
65
|
+
check_num_args(nargs)
|
66
|
+
|
67
|
+
# @varfunc = _var_func_parse(data.dup)
|
68
|
+
end
|
69
|
+
|
70
|
+
def check_num_args(num)
|
71
|
+
num_range = /(\d{0,2})(\.\.)(\d{0,2})/
|
72
|
+
min, max = 0, 9999
|
73
|
+
md = num_range.match(@nargs).to_a
|
74
|
+
bad_args = nil
|
75
|
+
case
|
76
|
+
when @nargs == ":N" # arbitrary
|
77
|
+
# max already set
|
78
|
+
when md[2] == ".." # range: 4..6 1.. ..4
|
79
|
+
vmin, vmax = md.values_at(1, 2)
|
80
|
+
min = Integer(vmin) unless vmin.empty?
|
81
|
+
max = Integer(vmax) unless vmax.empty?
|
82
|
+
min, max = Integer(min), Integer(max)
|
83
|
+
when %r[^\d+$] =~ num
|
84
|
+
min = max = Integer(num) # can raise error
|
85
|
+
else
|
86
|
+
raise "Invalid value or range '#{num.inspect}'"
|
87
|
+
end
|
88
|
+
|
89
|
+
bad_args = @args.size.between?(min, max)
|
90
|
+
raise "Expected #{num} args but found #{@args.size}!" if bad_args
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
data/lib/formatline.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# Class FormatLine handles the parsing of comments, dot commands, and
|
2
2
|
# simple formatting characters.
|
3
3
|
|
4
|
-
class FormatLine
|
4
|
+
class FormatLine < StringParser
|
5
5
|
SimpleFormats = {}
|
6
6
|
SimpleFormats[:b] = %w[<b> </b>]
|
7
7
|
SimpleFormats[:i] = %w[<i> </i>]
|
@@ -24,20 +24,11 @@ class FormatLine
|
|
24
24
|
|
25
25
|
Syms = { "*" => :b, "_" => :i, "`" => :t, "~" => :s }
|
26
26
|
|
27
|
-
def terminate?(terminators, ch)
|
28
|
-
if terminators.is_a? Regexp
|
29
|
-
terminators === ch
|
30
|
-
else
|
31
|
-
terminators.include?(ch)
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
27
|
attr_reader :out
|
36
28
|
attr_reader :tokenlist
|
37
29
|
|
38
30
|
def initialize(line)
|
39
|
-
|
40
|
-
@i = -1
|
31
|
+
super
|
41
32
|
@token = Null.dup
|
42
33
|
@tokenlist = []
|
43
34
|
end
|
@@ -45,26 +36,27 @@ class FormatLine
|
|
45
36
|
def self.parse!(line)
|
46
37
|
return nil if line.nil?
|
47
38
|
x = self.new(line.chomp)
|
48
|
-
t = x.tokenize
|
39
|
+
t = x.tokenize
|
40
|
+
# TTY.puts "tokens = \n#{t.inspect}\n "
|
49
41
|
x.evaluate
|
50
42
|
end
|
51
43
|
|
52
|
-
def tokenize
|
53
|
-
|
44
|
+
def tokenize
|
45
|
+
# add grab
|
54
46
|
loop do
|
55
|
-
case
|
56
|
-
when Escape; grab; add
|
47
|
+
case peek
|
48
|
+
when Escape; grab; add peek; grab; add peek
|
57
49
|
when "$"
|
58
50
|
dollar
|
59
51
|
when "*", "_", "`", "~"
|
60
|
-
marker
|
61
|
-
add
|
52
|
+
marker peek
|
53
|
+
add peek
|
62
54
|
when LF
|
63
55
|
break if @i >= line.size - 1
|
64
56
|
when nil
|
65
57
|
break
|
66
58
|
else
|
67
|
-
add
|
59
|
+
add peek
|
68
60
|
end
|
69
61
|
grab
|
70
62
|
end
|
@@ -72,24 +64,33 @@ class FormatLine
|
|
72
64
|
@tokenlist
|
73
65
|
end
|
74
66
|
|
67
|
+
def terminate?(terminators, ch)
|
68
|
+
if terminators.is_a? Regexp
|
69
|
+
terminators === ch
|
70
|
+
else
|
71
|
+
terminators.include?(ch)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
75
|
def self.var_func_parse(str)
|
76
76
|
return nil if str.nil?
|
77
77
|
x = self.new(str.chomp)
|
78
|
-
x.
|
79
|
-
loop do
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
break
|
86
|
-
else
|
87
|
-
x.add x.curr
|
88
|
-
end
|
89
|
-
x.grab
|
78
|
+
char = x.peek
|
79
|
+
loop do
|
80
|
+
char = x.grab
|
81
|
+
break if char == LF || char == nil
|
82
|
+
x.handle_escaping if char == Escape
|
83
|
+
x.dollar if char == "$"
|
84
|
+
x.add char
|
90
85
|
end
|
91
86
|
x.add_token(:str)
|
92
|
-
x.evaluate
|
87
|
+
result = x.evaluate
|
88
|
+
result
|
89
|
+
end
|
90
|
+
|
91
|
+
def handle_escaping
|
92
|
+
grab
|
93
|
+
add grab
|
93
94
|
end
|
94
95
|
|
95
96
|
def embed(sym, str)
|
@@ -130,27 +131,6 @@ class FormatLine
|
|
130
131
|
@out
|
131
132
|
end
|
132
133
|
|
133
|
-
def curr
|
134
|
-
@line[@i]
|
135
|
-
end
|
136
|
-
|
137
|
-
def prev
|
138
|
-
return nil if @i <= 0
|
139
|
-
@line[@i-1]
|
140
|
-
end
|
141
|
-
|
142
|
-
def next!
|
143
|
-
@line[@i+1]
|
144
|
-
end
|
145
|
-
|
146
|
-
def grab
|
147
|
-
@line[@i+=1]
|
148
|
-
end
|
149
|
-
|
150
|
-
def ungrab
|
151
|
-
@line[@i-=1]
|
152
|
-
end
|
153
|
-
|
154
134
|
def grab_colon_param
|
155
135
|
grab # grab :
|
156
136
|
param = ""
|
@@ -187,7 +167,7 @@ class FormatLine
|
|
187
167
|
end
|
188
168
|
end
|
189
169
|
|
190
|
-
add
|
170
|
+
add peek
|
191
171
|
grab
|
192
172
|
param = nil if param.empty?
|
193
173
|
param
|
@@ -207,8 +187,8 @@ class FormatLine
|
|
207
187
|
str = Null.dup
|
208
188
|
grab
|
209
189
|
loop do
|
210
|
-
break if
|
211
|
-
str <<
|
190
|
+
break if eos?
|
191
|
+
str << peek
|
212
192
|
break if terminate?(NoAlpha, next!)
|
213
193
|
grab
|
214
194
|
end
|
@@ -219,8 +199,8 @@ class FormatLine
|
|
219
199
|
str = Null.dup
|
220
200
|
grab
|
221
201
|
loop do
|
222
|
-
break if
|
223
|
-
str <<
|
202
|
+
break if eos? # peek.nil?
|
203
|
+
str << peek
|
224
204
|
break if terminate?(NoAlphaDot, next!)
|
225
205
|
grab
|
226
206
|
end
|
@@ -229,7 +209,7 @@ class FormatLine
|
|
229
209
|
|
230
210
|
def dollar
|
231
211
|
grab
|
232
|
-
case
|
212
|
+
case peek
|
233
213
|
when LF; add "$"; add_token :str
|
234
214
|
when " "; add "$ "; add_token :str
|
235
215
|
when nil; add "$"; add_token :str
|
@@ -237,10 +217,10 @@ class FormatLine
|
|
237
217
|
# when "."; dollar_dot
|
238
218
|
when /[A-Za-z]/
|
239
219
|
add_token :str
|
240
|
-
var =
|
220
|
+
var = peek + grab_alpha_dot
|
241
221
|
add_token(:var, var)
|
242
222
|
else
|
243
|
-
add "$" +
|
223
|
+
add "$" + peek
|
244
224
|
add_token(:string)
|
245
225
|
end
|
246
226
|
end
|
@@ -258,7 +238,7 @@ class FormatLine
|
|
258
238
|
when "["; param = grab_func_param; add_token(:brackets, param)
|
259
239
|
end
|
260
240
|
else
|
261
|
-
grab; add_token :str, "$$" +
|
241
|
+
grab; add_token :str, "$$" + peek; return
|
262
242
|
end
|
263
243
|
end
|
264
244
|
|
@@ -275,7 +255,7 @@ class FormatLine
|
|
275
255
|
end
|
276
256
|
|
277
257
|
grab
|
278
|
-
case
|
258
|
+
case peek
|
279
259
|
when Space
|
280
260
|
add char + " "
|
281
261
|
add_token :str
|
@@ -286,7 +266,7 @@ class FormatLine
|
|
286
266
|
when char; double_marker(char)
|
287
267
|
when LBrack; long_marker(char)
|
288
268
|
else
|
289
|
-
str =
|
269
|
+
str = peek + collect!(sym, Blank)
|
290
270
|
add str
|
291
271
|
add_token sym, str
|
292
272
|
grab
|
@@ -319,21 +299,19 @@ class FormatLine
|
|
319
299
|
str = Null.dup # next is not " ","*","["
|
320
300
|
grab # ZZZ
|
321
301
|
loop do
|
322
|
-
if
|
323
|
-
str << grab # ch = escaped char
|
302
|
+
if peek == Escape
|
324
303
|
grab
|
304
|
+
str << grab
|
325
305
|
next
|
326
306
|
end
|
327
|
-
if terminate?(terminators,
|
307
|
+
if terminate?(terminators, peek)
|
328
308
|
break
|
329
309
|
end
|
330
|
-
|
331
|
-
str << curr # not a terminator
|
310
|
+
str << peek # not a terminator
|
332
311
|
grab
|
333
|
-
# STDERR.puts "After grab, curr is #{curr.inspect}"
|
334
312
|
end
|
335
313
|
|
336
|
-
if
|
314
|
+
if peek == "]" # skip right bracket
|
337
315
|
grab
|
338
316
|
end
|
339
317
|
add str
|
@@ -344,8 +322,8 @@ class FormatLine
|
|
344
322
|
end
|
345
323
|
|
346
324
|
def escaped
|
347
|
-
ch = grab
|
348
325
|
grab
|
326
|
+
ch = grab
|
349
327
|
ch
|
350
328
|
end
|
351
329
|
|
@@ -356,15 +334,15 @@ class FormatLine
|
|
356
334
|
grab # ZZZ
|
357
335
|
loop do
|
358
336
|
case
|
359
|
-
when
|
337
|
+
when peek.nil?
|
360
338
|
return str
|
361
|
-
when
|
339
|
+
when peek == Escape
|
362
340
|
str << escaped
|
363
341
|
next
|
364
|
-
when terminate?(terminators,
|
342
|
+
when terminate?(terminators, peek)
|
365
343
|
break
|
366
344
|
else
|
367
|
-
str <<
|
345
|
+
str << peek # not a terminator
|
368
346
|
end
|
369
347
|
grab
|
370
348
|
end
|
@@ -376,17 +354,14 @@ class FormatLine
|
|
376
354
|
STDERR.puts "=== str = #{str.inspect}"
|
377
355
|
end
|
378
356
|
|
379
|
-
############
|
380
|
-
|
381
|
-
### From FormatLine:
|
382
|
-
|
383
357
|
def funcall(name, param)
|
358
|
+
err = "[Error evaluating $$#{name}(#{param})]"
|
384
359
|
result =
|
385
360
|
if self.respond_to?("func_" + name.to_s)
|
386
361
|
self.send("func_" + name.to_s, param)
|
387
362
|
else
|
388
363
|
fobj = ::Livetext::Functions.new
|
389
|
-
fobj.send(name, param)
|
364
|
+
fobj.send(name, param) rescue err
|
390
365
|
end
|
391
366
|
result
|
392
367
|
end
|
@@ -396,8 +371,6 @@ class FormatLine
|
|
396
371
|
result
|
397
372
|
end
|
398
373
|
|
399
|
-
#####
|
400
|
-
|
401
374
|
def embedded?
|
402
375
|
! (['"', "'", " ", nil].include? prev)
|
403
376
|
end
|
data/lib/helpers.rb
CHANGED
@@ -1,10 +1,86 @@
|
|
1
1
|
|
2
2
|
module Helpers
|
3
3
|
|
4
|
+
Space = " "
|
5
|
+
Sigil = "." # Can't change yet
|
6
|
+
|
7
|
+
def self.rx(str, space=nil)
|
8
|
+
Regexp.compile("^" + Regexp.escape(str) + "#{space}")
|
9
|
+
end
|
10
|
+
|
11
|
+
Comment = rx(Sigil, Space)
|
12
|
+
Dotcmd = rx(Sigil)
|
13
|
+
Ddotcmd = /^ *\$\.[A-Za-z]/
|
14
|
+
|
15
|
+
## FIXME process_file[!] should call process[_text]
|
16
|
+
|
17
|
+
def process_file(fname, btrace=false)
|
18
|
+
setfile(fname)
|
19
|
+
text = File.readlines(fname)
|
20
|
+
enum = text.each
|
21
|
+
@backtrace = btrace
|
22
|
+
@main.source(enum, fname, 0)
|
23
|
+
line = nil
|
24
|
+
loop do
|
25
|
+
line = @main.nextline
|
26
|
+
break if line.nil?
|
27
|
+
process_line(line)
|
28
|
+
end
|
29
|
+
val = @main.finalize if @main.respond_to? :finalize
|
30
|
+
@body
|
31
|
+
end
|
32
|
+
|
33
|
+
def process_line(line) # FIXME inefficient?
|
34
|
+
nomarkup = true
|
35
|
+
case line # must apply these in order
|
36
|
+
when Comment
|
37
|
+
handle_scomment(line)
|
38
|
+
when Dotcmd
|
39
|
+
handle_dotcmd(line)
|
40
|
+
when Ddotcmd
|
41
|
+
indent = line.index("$") + 1
|
42
|
+
@indentation.push(indent)
|
43
|
+
line.sub!(/^ *\$/, "")
|
44
|
+
handle_dotcmd(line)
|
45
|
+
indentation.pop
|
46
|
+
else
|
47
|
+
@main._passthru(line)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def handle_dotcmd(line, indent = 0)
|
52
|
+
indent = @indentation.last # top of stack
|
53
|
+
line = line.sub(/# .*$/, "")
|
54
|
+
name = get_name(line).to_sym
|
55
|
+
result = nil
|
56
|
+
case
|
57
|
+
when name == :end # special case
|
58
|
+
puts @body
|
59
|
+
raise EndWithoutOpening()
|
60
|
+
when @main.respond_to?(name)
|
61
|
+
result = @main.send(name)
|
62
|
+
else
|
63
|
+
puts @body # earlier correct output, not flushed yet
|
64
|
+
raise "Name '#{name}' is unknown"
|
65
|
+
return
|
66
|
+
end
|
67
|
+
result
|
68
|
+
end
|
69
|
+
|
70
|
+
def handle_scomment(line)
|
71
|
+
end
|
72
|
+
|
73
|
+
def get_name(line)
|
74
|
+
name, data = line.split(" ", 2)
|
75
|
+
name = name[1..-1] # chop off sigil
|
76
|
+
name = "dot_" + name if %w[include def].include?(name)
|
77
|
+
@main.data = data
|
78
|
+
@main.check_disallowed(name)
|
79
|
+
name
|
80
|
+
end
|
81
|
+
|
4
82
|
def check_disallowed(name)
|
5
|
-
|
6
|
-
# FIXME use custom exception
|
7
|
-
raise DisallowedName, name if _disallowed?(name)
|
83
|
+
raise DisallowedName(name) if disallowed?(name)
|
8
84
|
end
|
9
85
|
|
10
86
|
def check_file_exists(file)
|
@@ -14,7 +90,7 @@ module Helpers
|
|
14
90
|
def set_variables(pairs)
|
15
91
|
pairs.each do |pair|
|
16
92
|
var, value = *pair
|
17
|
-
@parent.
|
93
|
+
@parent.setvar(var, value)
|
18
94
|
end
|
19
95
|
end
|
20
96
|
|
@@ -22,4 +98,66 @@ module Helpers
|
|
22
98
|
File.read(fname)
|
23
99
|
end
|
24
100
|
|
101
|
+
def search_upward(file)
|
102
|
+
value = nil
|
103
|
+
return file if File.exist?(file)
|
104
|
+
|
105
|
+
count = 1
|
106
|
+
loop do
|
107
|
+
front = "../" * count
|
108
|
+
count += 1
|
109
|
+
here = Pathname.new(front).expand_path.dirname.to_s
|
110
|
+
break if here == "/"
|
111
|
+
path = front + file
|
112
|
+
value = path if File.exist?(path)
|
113
|
+
break if value
|
114
|
+
end
|
115
|
+
STDERR.puts "Cannot find #{file.inspect} from #{Dir.pwd}" unless value
|
116
|
+
return value
|
117
|
+
rescue
|
118
|
+
STDERR.puts "Can't find #{file.inspect} from #{Dir.pwd}"
|
119
|
+
return nil
|
120
|
+
end
|
121
|
+
|
122
|
+
def include_file(file)
|
123
|
+
@_args = [file]
|
124
|
+
dot_include
|
125
|
+
end
|
126
|
+
|
127
|
+
def onoff(arg) # helper
|
128
|
+
arg ||= "on"
|
129
|
+
raise ExpectedOnOff unless String === arg
|
130
|
+
case arg.downcase
|
131
|
+
when "on"
|
132
|
+
return true
|
133
|
+
when "off"
|
134
|
+
return false
|
135
|
+
else
|
136
|
+
raise ExpectedOnOff
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
def setvar(var, val)
|
141
|
+
str, sym = var.to_s, var.to_sym
|
142
|
+
Livetext::Vars[str] = val
|
143
|
+
Livetext::Vars[sym] = val
|
144
|
+
@_vars[str] = val
|
145
|
+
@_vars[sym] = val
|
146
|
+
end
|
147
|
+
|
148
|
+
def setfile(file)
|
149
|
+
if file
|
150
|
+
setvar(:File, file)
|
151
|
+
dir = File.dirname(File.expand_path(file))
|
152
|
+
setvar(:FileDir, dir)
|
153
|
+
else
|
154
|
+
setvar(:File, "[no file]")
|
155
|
+
setvar(:FileDir, "[no dir]")
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
def setfile!(file) # FIXME why does this variant exist?
|
160
|
+
setvar(:File, file)
|
161
|
+
end
|
162
|
+
|
25
163
|
end
|