livetext 0.9.30 → 0.9.31
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/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
|