livetext 0.9.30 → 0.9.31
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/imports/bookish.rb +1 -1
- data/lib/livetext/expansion.rb +15 -13
- data/lib/livetext/formatter.rb +206 -87
- data/lib/livetext/helpers.rb +24 -13
- data/lib/livetext/standard.rb +62 -57
- data/lib/livetext/userapi.rb +13 -2
- data/lib/livetext/version.rb +1 -1
- data/plugin/bookish.rb +1 -1
- data/test/extra/README.txt +149 -0
- data/test/extra/bracketed.rb +121 -0
- data/test/extra/bracketed.txt +44 -0
- data/test/extra/double.rb +121 -0
- data/test/extra/double.txt +44 -0
- data/test/extra/functions.rb +148 -0
- data/test/extra/functions.txt +58 -0
- data/test/extra/single.rb +139 -0
- data/test/extra/single.txt +52 -0
- data/test/extra/testgen.rb +104 -0
- data/test/{snapshots/bootstrap_menu/expected-error.txt → extra/variables..rb} +0 -0
- data/test/extra/variables.rb +94 -0
- data/test/extra/variables.txt +35 -0
- data/test/snapshots/basic_formatting/expected-output.txt +2 -1
- data/test/snapshots/import_bookish/toc.tmp +0 -0
- data/test/snapshots/mixin_bookish/toc.tmp +0 -0
- data/test/snapshots/simple_vars/source.lt3 +1 -1
- data/test/snapshots/subset.txt +0 -2
- data/test/unit/all.rb +1 -2
- metadata +17 -9
- data/test/snapshots/bootstrap_menu/expected-output.txt +0 -4
- data/test/snapshots/bootstrap_menu/source.lt3 +0 -17
- data/test/snapshots/error_inc_line_num/README.txt +0 -20
- data/test/snapshots/error_invalid_name/foo +0 -5
- data/test/unit/lineparser.rb +0 -359
- data/test/unit/new_lineparser.rb +0 -359
data/lib/livetext/standard.rb
CHANGED
@@ -17,6 +17,8 @@ module Livetext::Standard
|
|
17
17
|
include HTMLHelper
|
18
18
|
include Livetext::Helpers
|
19
19
|
|
20
|
+
TTY = ::File.open("/dev/tty", "w")
|
21
|
+
|
20
22
|
SimpleFormats = # Move this?
|
21
23
|
{ b: %w[<b> </b>],
|
22
24
|
i: %w[<i> </i>],
|
@@ -25,18 +27,19 @@ module Livetext::Standard
|
|
25
27
|
|
26
28
|
attr_reader :data
|
27
29
|
|
28
|
-
|
29
|
-
# api.tty ">>>> in #{__FILE__}: api id = #{api.object_id}"
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
30
|
+
# def data=(val) # FIXME this is weird, let's remove it soonish and why are there two???
|
31
|
+
# # api.tty ">>>> in #{__FILE__}: api id = #{api.object_id}"
|
32
|
+
# val ||= ""
|
33
|
+
# val = val.chomp
|
34
|
+
# api.data = val
|
35
|
+
# api.args = format(val).split rescue []
|
36
|
+
# @mixins = []
|
37
|
+
# @imports = []
|
38
|
+
# end
|
36
39
|
|
37
40
|
# dumb name - bold, italic, teletype, striketrough
|
38
41
|
|
39
|
-
def bits
|
42
|
+
def bits # FIXME umm what is this?
|
40
43
|
b0, b1, i0, i1, t0, t1, s0, s1 = *api.args
|
41
44
|
SimpleFormats[:b] = [b0, b1]
|
42
45
|
SimpleFormats[:i] = [i0, i1]
|
@@ -51,29 +54,29 @@ module Livetext::Standard
|
|
51
54
|
# end
|
52
55
|
# end
|
53
56
|
|
54
|
-
def backtrace
|
57
|
+
def backtrace
|
55
58
|
@backtrace = onoff(api.args.first)
|
56
59
|
api.optional_blank_line
|
57
60
|
end
|
58
61
|
|
59
|
-
def comment
|
62
|
+
def comment
|
60
63
|
api.body
|
61
64
|
api.optional_blank_line
|
62
65
|
end
|
63
66
|
|
64
|
-
def shell
|
67
|
+
def shell
|
65
68
|
cmd = api.data
|
66
69
|
system(cmd)
|
67
70
|
api.optional_blank_line
|
68
71
|
end
|
69
72
|
|
70
|
-
def func
|
73
|
+
def func
|
71
74
|
funcname = api.args[0]
|
72
75
|
# check_disallowed(funcname) # should any be invalid?
|
73
76
|
funcname = funcname.gsub(/\./, "__")
|
74
77
|
func_def = <<~EOS
|
75
78
|
def #{funcname}(param)
|
76
|
-
#{api.body.to_a.join("\n")}
|
79
|
+
#{api.body(true).to_a.join("\n")}
|
77
80
|
end
|
78
81
|
EOS
|
79
82
|
api.optional_blank_line
|
@@ -81,21 +84,21 @@ module Livetext::Standard
|
|
81
84
|
return true
|
82
85
|
end
|
83
86
|
|
84
|
-
def h1
|
85
|
-
def h2
|
86
|
-
def h3
|
87
|
-
def h4
|
88
|
-
def h5
|
89
|
-
def h6
|
87
|
+
def h1; api.out wrapped(api.data, :h1); return true; end
|
88
|
+
def h2; api.out wrapped(api.data, :h2); return true; end
|
89
|
+
def h3; api.out wrapped(api.data, :h3); return true; end
|
90
|
+
def h4; api.out wrapped(api.data, :h4); return true; end
|
91
|
+
def h5; api.out wrapped(api.data, :h5); return true; end
|
92
|
+
def h6; api.out wrapped(api.data, :h6); return true; end
|
90
93
|
|
91
|
-
def list
|
94
|
+
def list
|
92
95
|
wrap :ul do
|
93
96
|
api.body {|line| api.out wrapped(line, :li) }
|
94
97
|
end
|
95
98
|
api.optional_blank_line
|
96
99
|
end
|
97
100
|
|
98
|
-
def list!
|
101
|
+
def list!
|
99
102
|
wrap(:ul) do
|
100
103
|
lines = api.body.each # enumerator
|
101
104
|
loop do
|
@@ -108,40 +111,40 @@ module Livetext::Standard
|
|
108
111
|
api.optional_blank_line
|
109
112
|
end
|
110
113
|
|
111
|
-
def shell!
|
114
|
+
def shell!
|
112
115
|
cmd = api.data
|
113
116
|
system(cmd)
|
114
117
|
api.optional_blank_line
|
115
118
|
end
|
116
119
|
|
117
|
-
def errout
|
120
|
+
def errout
|
118
121
|
::STDERR.puts api.data
|
119
122
|
api.optional_blank_line
|
120
123
|
end
|
121
124
|
|
122
|
-
def ttyout
|
125
|
+
def ttyout
|
123
126
|
TTY.puts api.data
|
124
127
|
api.optional_blank_line
|
125
128
|
end
|
126
129
|
|
127
|
-
def say
|
130
|
+
def say
|
128
131
|
str = api.format(api.data)
|
129
132
|
TTY.puts str
|
130
133
|
api.optional_blank_line
|
131
134
|
end
|
132
135
|
|
133
|
-
def banner
|
136
|
+
def banner
|
134
137
|
str = api.format(api.data)
|
135
138
|
num = str.length
|
136
139
|
decor = "-"*num + "\n"
|
137
140
|
puts decor + str + "\n" + decor
|
138
141
|
end
|
139
142
|
|
140
|
-
def quit
|
143
|
+
def quit
|
141
144
|
@output.close
|
142
145
|
end
|
143
146
|
|
144
|
-
def cleanup
|
147
|
+
def cleanup
|
145
148
|
api.args.each do |item|
|
146
149
|
cmd = ::File.directory?(item) ? "rm -f #{item}/*" : "rm #{item}"
|
147
150
|
system(cmd)
|
@@ -149,7 +152,7 @@ module Livetext::Standard
|
|
149
152
|
api.optional_blank_line
|
150
153
|
end
|
151
154
|
|
152
|
-
def dot_def
|
155
|
+
def dot_def
|
153
156
|
# api.tty "in #{__FILE__}: api id = #{api.inspect}"
|
154
157
|
name = api.args[0]
|
155
158
|
# api.tty :dd1
|
@@ -164,7 +167,7 @@ module Livetext::Standard
|
|
164
167
|
api.optional_blank_line
|
165
168
|
end
|
166
169
|
|
167
|
-
def set
|
170
|
+
def set
|
168
171
|
line = api.args.join(" ") # data.chomp
|
169
172
|
pairs = Livetext::ParseSet.new(line).parse
|
170
173
|
api.setvars(pairs)
|
@@ -173,7 +176,7 @@ module Livetext::Standard
|
|
173
176
|
|
174
177
|
# FIXME really these should be one method...
|
175
178
|
|
176
|
-
def variables!
|
179
|
+
def variables! # cwd, not FileDir - weird, fix later
|
177
180
|
prefix = api.args[0]
|
178
181
|
file = api.args[1]
|
179
182
|
prefix = nil if prefix == "-" # FIXME dumb hack
|
@@ -189,7 +192,7 @@ STDERR.puts "! pairs = #{pairs.inspect}"
|
|
189
192
|
api.optional_blank_line
|
190
193
|
end
|
191
194
|
|
192
|
-
def variables
|
195
|
+
def variables
|
193
196
|
prefix = api.args[0]
|
194
197
|
file = api.args[1]
|
195
198
|
prefix = nil if prefix == "-" # FIXME dumb hack
|
@@ -205,7 +208,7 @@ STDERR.puts "pairs = #{pairs.inspect}"
|
|
205
208
|
api.optional_blank_line
|
206
209
|
end
|
207
210
|
|
208
|
-
def heredoc
|
211
|
+
def heredoc
|
209
212
|
var = api.args[0]
|
210
213
|
text = api.body.join("\n")
|
211
214
|
rhs = ""
|
@@ -215,11 +218,11 @@ STDERR.puts "pairs = #{pairs.inspect}"
|
|
215
218
|
end
|
216
219
|
indent = @parent.indentation.last
|
217
220
|
indented = " " * indent
|
218
|
-
api.
|
221
|
+
api.setvar(var, rhs.chomp)
|
219
222
|
api.optional_blank_line
|
220
223
|
end
|
221
224
|
|
222
|
-
def seek
|
225
|
+
def seek # like include, but search upward as needed
|
223
226
|
file = api.args.first
|
224
227
|
file = search_upward(file)
|
225
228
|
check_file_exists(file)
|
@@ -227,14 +230,14 @@ STDERR.puts "pairs = #{pairs.inspect}"
|
|
227
230
|
api.optional_blank_line
|
228
231
|
end
|
229
232
|
|
230
|
-
def dot_include
|
231
|
-
file = api.format(api.args.first) # allows for variables
|
233
|
+
def dot_include # dot command
|
234
|
+
file = api.args.first # api.format(api.args.first) # allows for variables
|
232
235
|
check_file_exists(file)
|
233
236
|
@parent.process_file(file)
|
234
237
|
api.optional_blank_line
|
235
238
|
end
|
236
239
|
|
237
|
-
def inherit
|
240
|
+
def inherit
|
238
241
|
file = api.args.first
|
239
242
|
upper = "../#{file}"
|
240
243
|
got_upper, got_file = File.exist?(upper), File.exist?(file)
|
@@ -246,8 +249,9 @@ STDERR.puts "pairs = #{pairs.inspect}"
|
|
246
249
|
api.optional_blank_line
|
247
250
|
end
|
248
251
|
|
249
|
-
def mixin
|
252
|
+
def mixin
|
250
253
|
name = api.args.first # Expect a module name
|
254
|
+
@mixins ||= []
|
251
255
|
return if @mixins.include?(name)
|
252
256
|
@mixins << name
|
253
257
|
mod = Livetext::Handler::Mixin.get_module(name, @parent)
|
@@ -257,8 +261,9 @@ STDERR.puts "pairs = #{pairs.inspect}"
|
|
257
261
|
api.optional_blank_line
|
258
262
|
end
|
259
263
|
|
260
|
-
def import
|
264
|
+
def import
|
261
265
|
name = api.args.first # Expect a module name
|
266
|
+
@imports ||= []
|
262
267
|
return if @imports.include?(name)
|
263
268
|
@imports << name
|
264
269
|
mod = Livetext::Handler::Import.get_module(name, @parent)
|
@@ -268,7 +273,7 @@ STDERR.puts "pairs = #{pairs.inspect}"
|
|
268
273
|
api.optional_blank_line
|
269
274
|
end
|
270
275
|
|
271
|
-
def copy
|
276
|
+
def copy
|
272
277
|
file = api.args.first
|
273
278
|
ok = check_file_exists(file)
|
274
279
|
|
@@ -278,67 +283,67 @@ STDERR.puts "pairs = #{pairs.inspect}"
|
|
278
283
|
[ok, file]
|
279
284
|
end
|
280
285
|
|
281
|
-
def r
|
286
|
+
def r
|
282
287
|
# FIXME api.data is broken
|
283
288
|
# api.out api.data # No processing at all
|
284
289
|
api.out api.args.join(" ")
|
285
290
|
api.optional_blank_line
|
286
291
|
end
|
287
292
|
|
288
|
-
def raw
|
293
|
+
def raw
|
289
294
|
# No processing at all (terminate with __EOF__)
|
290
295
|
api.raw_body {|line| api.out line } # no formatting
|
291
296
|
api.optional_blank_line
|
292
297
|
end
|
293
298
|
|
294
|
-
def debug
|
299
|
+
def debug
|
295
300
|
self._debug = onoff(api.args.first)
|
296
301
|
api.optional_blank_line
|
297
302
|
end
|
298
303
|
|
299
|
-
def passthru
|
304
|
+
def passthru
|
300
305
|
# FIXME - add check for args size? (helpers)
|
301
306
|
@nopass = ! onoff(api.args.first)
|
302
307
|
api.optional_blank_line
|
303
308
|
end
|
304
309
|
|
305
|
-
def nopass
|
310
|
+
def nopass
|
306
311
|
@nopass = true
|
307
312
|
api.optional_blank_line
|
308
313
|
end
|
309
314
|
|
310
|
-
def para
|
315
|
+
def para
|
311
316
|
# FIXME - add check for args size? (helpers)
|
312
317
|
@nopara = ! onoff(api.args.first)
|
313
318
|
api.optional_blank_line
|
314
319
|
end
|
315
320
|
|
316
|
-
def nopara
|
321
|
+
def nopara
|
317
322
|
@nopara = true
|
318
323
|
api.optional_blank_line
|
319
324
|
end
|
320
325
|
|
321
|
-
def heading
|
326
|
+
def heading
|
322
327
|
api.print "<center><font size=+1><b>"
|
323
328
|
api.print api.data
|
324
329
|
api.print "</b></font></center>"
|
325
330
|
api.optional_blank_line
|
326
331
|
end
|
327
332
|
|
328
|
-
def newpage
|
333
|
+
def newpage
|
329
334
|
api.out '<p style="page-break-after:always;"></p>'
|
330
335
|
api.out "<p/>"
|
331
336
|
api.optional_blank_line
|
332
337
|
end
|
333
338
|
|
334
|
-
def mono
|
339
|
+
def mono
|
335
340
|
wrap ":pre" do
|
336
341
|
api.body(true) {|line| api.out line }
|
337
342
|
end
|
338
343
|
api.optional_blank_line
|
339
344
|
end
|
340
345
|
|
341
|
-
def dlist
|
346
|
+
def dlist
|
342
347
|
delim = api.args.first
|
343
348
|
wrap(:dl) do
|
344
349
|
api.body do |line|
|
@@ -351,14 +356,14 @@ STDERR.puts "pairs = #{pairs.inspect}"
|
|
351
356
|
api.optional_blank_line
|
352
357
|
end
|
353
358
|
|
354
|
-
def link
|
359
|
+
def link
|
355
360
|
url = api.args.first
|
356
361
|
text = api.args[2..-1].join(" ")
|
357
362
|
api.out "<a style='text-decoration: none' href='#{url}'>#{text}</a>"
|
358
363
|
api.optional_blank_line
|
359
364
|
end
|
360
365
|
|
361
|
-
def xtable
|
366
|
+
def xtable # Borrowed from bookish - FIXME
|
362
367
|
# TTY.puts "=== #{__method__} #{__FILE__} #{__LINE__}"
|
363
368
|
title = api.data
|
364
369
|
delim = " :: "
|
@@ -389,13 +394,13 @@ STDERR.puts "pairs = #{pairs.inspect}"
|
|
389
394
|
api.optional_blank_line
|
390
395
|
end
|
391
396
|
|
392
|
-
def image
|
397
|
+
def image
|
393
398
|
name = api.args[0]
|
394
399
|
api.out "<img src='#{name}'></img>"
|
395
400
|
api.optional_blank_line
|
396
401
|
end
|
397
402
|
|
398
|
-
def br
|
403
|
+
def br
|
399
404
|
num = api.args.first || "1"
|
400
405
|
str = ""
|
401
406
|
num.to_i.times { str << "<br>" }
|
data/lib/livetext/userapi.rb
CHANGED
@@ -48,7 +48,7 @@ class Livetext::UserAPI
|
|
48
48
|
end
|
49
49
|
|
50
50
|
def data=(value)
|
51
|
-
@data = value
|
51
|
+
@data = value.dup
|
52
52
|
@args = format(@data).chomp.split
|
53
53
|
end
|
54
54
|
|
@@ -104,17 +104,29 @@ class Livetext::UserAPI
|
|
104
104
|
lines = []
|
105
105
|
end_found = false
|
106
106
|
loop do
|
107
|
+
# TTY.puts "BODY 0: @line = #{@line.inspect}"
|
107
108
|
@line = @live.nextline
|
109
|
+
# TTY.puts "BODY 1: @line = #{@line.inspect}"
|
108
110
|
break if @line.nil?
|
111
|
+
# TTY.puts "BODY 2: @line = #{@line.inspect}"
|
109
112
|
@line.chomp!
|
113
|
+
# TTY.puts "BODY 3: @line = #{@line.inspect}"
|
110
114
|
break if end?(@line)
|
115
|
+
# TTY.puts "BODY 4: @line = #{@line.inspect}"
|
111
116
|
next if comment?(@line)
|
117
|
+
# TTY.puts "BODY 5: @line = #{@line.inspect}"
|
112
118
|
@line = format(@line) unless raw
|
119
|
+
# TTY.puts "BODY 6: @line = #{@line.inspect}"
|
113
120
|
lines << @line
|
121
|
+
# TTY.puts "BODY 7: @line = #{@line.inspect}"
|
114
122
|
end
|
123
|
+
# TTY.puts "BODY 8: lines = #{lines.inspect}"
|
115
124
|
raise "Expected .end, found end of file" unless end?(@line) # use custom exception
|
125
|
+
# TTY.puts "BODY 9: lines = #{lines.inspect}"
|
116
126
|
optional_blank_line # FIXME Delete this??
|
127
|
+
# TTY.puts "BODY A: lines = #{lines.inspect}"
|
117
128
|
return lines unless block_given?
|
129
|
+
# TTY.puts "BODY B: lines = #{lines.inspect}"
|
118
130
|
lines.each {|line| yield line } # FIXME what about $. ?
|
119
131
|
end
|
120
132
|
|
@@ -135,7 +147,6 @@ class Livetext::UserAPI
|
|
135
147
|
end
|
136
148
|
|
137
149
|
def format(line)
|
138
|
-
return "" if line == "\n" || line.nil?
|
139
150
|
line2 = @expander.format(line)
|
140
151
|
line2
|
141
152
|
end
|
data/lib/livetext/version.rb
CHANGED
data/plugin/bookish.rb
CHANGED
@@ -0,0 +1,149 @@
|
|
1
|
+
The testgen.rb tool takes a .txt and generates a corresponding file
|
2
|
+
of MiniTest code.
|
3
|
+
|
4
|
+
$ ruby testgen.rb variables.txt # produces variables.rb
|
5
|
+
|
6
|
+
The tests here include:
|
7
|
+
|
8
|
+
variables.txt Variable expansion
|
9
|
+
functions.txt Function call evaluation
|
10
|
+
single.txt Single sigil (see Formatting below)
|
11
|
+
double.txt Double sigil (see Formatting below)
|
12
|
+
bracketed.txt Bracketed sigil (see Formatting below)
|
13
|
+
|
14
|
+
|
15
|
+
Variables:
|
16
|
+
----------
|
17
|
+
|
18
|
+
1. A variable begins with a $ and is followed by an alpha; periods may
|
19
|
+
be embedded, but each separate piece must "look like" an identifier
|
20
|
+
|
21
|
+
$x yes
|
22
|
+
$xyz yes
|
23
|
+
$xyz.abc yes
|
24
|
+
$x123 yes
|
25
|
+
$x.123 no
|
26
|
+
$345 no
|
27
|
+
|
28
|
+
2. Rather than causing an error, invalid variables are rendered "as-is"
|
29
|
+
as soon as possible:
|
30
|
+
" $ " => " $ "
|
31
|
+
" $5 " => " $5 "
|
32
|
+
"...$" => "...$" (end of line)
|
33
|
+
|
34
|
+
3. Actual variables may be user-defined or predefined. The latter usually
|
35
|
+
begin with a capital. This is only a convention so far, nothing that is
|
36
|
+
enforced.
|
37
|
+
|
38
|
+
4. The $ may be escaped as needed. This is problematic.
|
39
|
+
|
40
|
+
5. An unknown variable will not raise an error, but will be replaced with
|
41
|
+
a warning string.
|
42
|
+
|
43
|
+
|
44
|
+
Functions:
|
45
|
+
----------
|
46
|
+
|
47
|
+
1. A function looks like a variable name, but it has two $ in front.
|
48
|
+
|
49
|
+
2. If followed by space, comma, end of line, or similar delimiter, it is
|
50
|
+
called with no parameter.
|
51
|
+
|
52
|
+
3. Note that a function name may contain periods, but may not end with
|
53
|
+
one. "$$func." is parsed as a function call (with no parameter) plus a
|
54
|
+
period.
|
55
|
+
|
56
|
+
4. Use a colon to pass a single parameter delimited by a space or end of line.
|
57
|
+
Colon at end of line is valid but probably pointless.
|
58
|
+
|
59
|
+
5. Use brackets to pass a single parameter that contains spaces. The bracketed
|
60
|
+
parameter may be terminated by end of line instead of right bracket.
|
61
|
+
|
62
|
+
6. Only one parameter (a string) may be passed, but the function may parse it
|
63
|
+
however it needs to.
|
64
|
+
|
65
|
+
7. There is no enforcement of a parameter being "present or absent" except what
|
66
|
+
the function itself may enforce.
|
67
|
+
|
68
|
+
8. An unknown function will not raise an error, but will be replaced with a warning
|
69
|
+
string.
|
70
|
+
|
71
|
+
|
72
|
+
Formatting:
|
73
|
+
-----------
|
74
|
+
|
75
|
+
1. My formatting notation would be considered quirky by many people.
|
76
|
+
The sigils or markers are:
|
77
|
+
* bold
|
78
|
+
_ underscore
|
79
|
+
` code/teletype
|
80
|
+
~ strikethrough
|
81
|
+
|
82
|
+
1. A single sigil is recognized basically at beginning of line or after a space.
|
83
|
+
my_func_name No italics here
|
84
|
+
M*A*S*H No boldface here
|
85
|
+
|
86
|
+
2. A single sigil is terminated by a space or end of line.
|
87
|
+
|
88
|
+
3. A single sigil "by itself" is rendered as-is (asterisk, underscore, whatever).
|
89
|
+
|
90
|
+
4. An escaped single sigil is rendered as-is. (This is problematic.)
|
91
|
+
|
92
|
+
5. A double sigil is recognized at start of line or after a space
|
93
|
+
|
94
|
+
6. A double sigil is terminated by a space OR a comma OR a period. (The comma
|
95
|
+
and period cases seem very common to me; they are the whole justification
|
96
|
+
for the double sigil.) End of line also terminates it.
|
97
|
+
|
98
|
+
7. A double sigil by itself is rendered as-is.
|
99
|
+
|
100
|
+
8. A bracketed sigil is in general a sigil followed by: [ data ]
|
101
|
+
|
102
|
+
9. An empty bracketed sigil simply "goes away"
|
103
|
+
" *[] " => " "
|
104
|
+
|
105
|
+
10. End of line can terminate instead of right bracket -- but it may still be empty
|
106
|
+
and therefore go away.
|
107
|
+
|
108
|
+
11. NOTE: These tests use only asterisks (bold), but the logic "should" be the same
|
109
|
+
for all sigils.
|
110
|
+
|
111
|
+
|
112
|
+
|
113
|
+
Order of evaluation, etc.:
|
114
|
+
--------------------------
|
115
|
+
|
116
|
+
1. This logic is always a compromise between syntax and the code that parses it.
|
117
|
+
I prefer simplicity whenever possible, though it may introduce complexity in
|
118
|
+
other situations. I believe that the acceptable complexity of a workaround
|
119
|
+
depends on how commonplace the situation is and how onerous the workaround is.
|
120
|
+
These are both highly subjective.
|
121
|
+
|
122
|
+
2. For example: Note that the simple formatting sigils may not be nested. However,
|
123
|
+
there are functions like $$bits provided (with the silly mnemonic "bold, italic,
|
124
|
+
teletype, strikthrough"). Every combination is provided (e.g., $$bi, $$bt).
|
125
|
+
|
126
|
+
3. Note also: Formatting is only intra-line; it doesn't span lines. If you need to
|
127
|
+
work around this, use a heredoc or make your own .def for this.
|
128
|
+
|
129
|
+
4. Finally: HTML or CSS may be inserted at will (possibly with some escaping). This
|
130
|
+
can be inline or "a file at a time" via such commands as .copy and .include
|
131
|
+
|
132
|
+
5. For these reasons: Parsing is naive and simple. Variables are parsed first.
|
133
|
+
|
134
|
+
6. Next, function calls are parsed. I said variables are parsed first; this implies
|
135
|
+
that a variable can be embedded in a function parameter. But be aware these are
|
136
|
+
"naive" substitutions (like C macros).
|
137
|
+
.set alpha = "some value"
|
138
|
+
Calling $$myfunc:$alpha (means: Calling $$myfunc:some value)
|
139
|
+
Better to say $$myfunc[$alpha] (means: Better to say $$myfunc[some value]
|
140
|
+
|
141
|
+
7. Formatting is handled last. The four sigils (* _ ` ~) and their three modes
|
142
|
+
(single, double, bracketed) make 12 passes necessary for formatting. As this is
|
143
|
+
always single-line, it has not been observed to cause a delay so far.
|
144
|
+
|
145
|
+
8. The call api.format(line) essentially expands variables, calls functions, and
|
146
|
+
finally does simple formatting. See classes Expansion and Formatter.
|
147
|
+
|
148
|
+
9. User code (e.g. inside a .def) may also call expand_variables, expand_functions,
|
149
|
+
and Formatter.format separately.
|
@@ -0,0 +1,121 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
|
3
|
+
require 'livetext'
|
4
|
+
|
5
|
+
# Just another testing class. Chill.
|
6
|
+
|
7
|
+
class TestingLivetextBracketed < MiniTest::Test
|
8
|
+
|
9
|
+
def setup
|
10
|
+
@live = Livetext.new
|
11
|
+
end
|
12
|
+
|
13
|
+
def check_match(exp, actual)
|
14
|
+
if exp.is_a? Regexp
|
15
|
+
assert_match(exp, actual, "actual does not match expected")
|
16
|
+
else
|
17
|
+
assert_equal(exp, actual, "actual != expected")
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_bracketed_001_single_bracketed_item
|
22
|
+
# Single bracketed item
|
23
|
+
# No special initialization
|
24
|
+
src = "*[abc]"
|
25
|
+
exp = "<b>abc</b>"
|
26
|
+
actual = @live.api.format(src)
|
27
|
+
check_match(exp, actual)
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_bracketed_002_end_of_line_can_replace_bracket
|
31
|
+
# End of line can replace bracket
|
32
|
+
# No special initialization
|
33
|
+
src = "*[abc"
|
34
|
+
exp = "<b>abc</b>"
|
35
|
+
actual = @live.api.format(src)
|
36
|
+
check_match(exp, actual)
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_bracketed_003_end_of_line_can_replace_bracket_again
|
40
|
+
# End of line can replace bracket again
|
41
|
+
# No special initialization
|
42
|
+
src = "abc *[d"
|
43
|
+
exp = "abc <b>d</b>"
|
44
|
+
actual = @live.api.format(src)
|
45
|
+
check_match(exp, actual)
|
46
|
+
end
|
47
|
+
|
48
|
+
def test_bracketed_004_missing_right_bracket_ignored_at_eol_if_empty
|
49
|
+
# Missing right bracket ignored at eol if empty
|
50
|
+
# No special initialization
|
51
|
+
src = "abc*["
|
52
|
+
exp = "abc*["
|
53
|
+
actual = @live.api.format(src)
|
54
|
+
check_match(exp, actual)
|
55
|
+
end
|
56
|
+
|
57
|
+
def test_bracketed_005_two_simple_bracketed_items
|
58
|
+
# Two simple bracketed items
|
59
|
+
# No special initialization
|
60
|
+
src = "*[A], *[B], C"
|
61
|
+
exp = "<b>A</b>, <b>B</b>, C"
|
62
|
+
actual = @live.api.format(src)
|
63
|
+
check_match(exp, actual)
|
64
|
+
end
|
65
|
+
|
66
|
+
def test_bracketed_006_simple_bracketed_item
|
67
|
+
# Simple bracketed item
|
68
|
+
# No special initialization
|
69
|
+
src = "Just a *[test]..."
|
70
|
+
exp = "Just a <b>test</b>..."
|
71
|
+
actual = @live.api.format(src)
|
72
|
+
check_match(exp, actual)
|
73
|
+
end
|
74
|
+
|
75
|
+
def test_bracketed_007_bracketed_item_with_space
|
76
|
+
# Bracketed item with space
|
77
|
+
# No special initialization
|
78
|
+
src = "A *[simple test]"
|
79
|
+
exp = "A <b>simple test</b>"
|
80
|
+
actual = @live.api.format(src)
|
81
|
+
check_match(exp, actual)
|
82
|
+
end
|
83
|
+
|
84
|
+
def test_bracketed_008_empty_bracketed_item_results_in_null
|
85
|
+
# Empty bracketed item results in null
|
86
|
+
# No special initialization
|
87
|
+
src = " *[] "
|
88
|
+
exp = " "
|
89
|
+
actual = @live.api.format(src)
|
90
|
+
check_match(exp, actual)
|
91
|
+
end
|
92
|
+
|
93
|
+
def test_bracketed_009_bracketed_item_with_space_again
|
94
|
+
# Bracketed item with space again
|
95
|
+
# No special initialization
|
96
|
+
src = "*[ab c] d"
|
97
|
+
exp = "<b>ab c</b> d"
|
98
|
+
actual = @live.api.format(src)
|
99
|
+
check_match(exp, actual)
|
100
|
+
end
|
101
|
+
|
102
|
+
def test_bracketed_010_two_bracketed_items_with_spaces
|
103
|
+
# Two bracketed items with spaces
|
104
|
+
# No special initialization
|
105
|
+
src = "*[a b] *[c d]"
|
106
|
+
exp = "<b>a b</b> <b>c d</b>"
|
107
|
+
actual = @live.api.format(src)
|
108
|
+
check_match(exp, actual)
|
109
|
+
end
|
110
|
+
|
111
|
+
def test_bracketed_011_solitary_item_missing_right_bracket_ignored_at_eol_if_empty
|
112
|
+
# Solitary item, missing right bracket ignored at eol if empty
|
113
|
+
# No special initialization
|
114
|
+
src = "*["
|
115
|
+
exp = ""
|
116
|
+
actual = @live.api.format(src)
|
117
|
+
check_match(exp, actual)
|
118
|
+
end
|
119
|
+
|
120
|
+
|
121
|
+
end
|