livetext 0.9.21 → 0.9.25

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.
Files changed (109) hide show
  1. checksums.yaml +4 -4
  2. data/README.lt3 +8 -8
  3. data/bin/livetext +57 -40
  4. data/imports/bookish.rb +89 -90
  5. data/imports/calibre.rb +3 -3
  6. data/imports/livemagick.rb +17 -17
  7. data/imports/markdown.rb +10 -10
  8. data/imports/pyggish.rb +15 -47
  9. data/imports/tutorial.rb +18 -18
  10. data/lib/cmdargs.rb +10 -6
  11. data/lib/{errors.rb → livetext/errors.rb} +1 -1
  12. data/lib/{formatline.rb → livetext/formatline.rb} +69 -125
  13. data/lib/livetext/funcall.rb +84 -0
  14. data/lib/{functions.rb → livetext/functions.rb} +16 -3
  15. data/lib/livetext/global_helpers.rb +37 -0
  16. data/lib/livetext/handler/import.rb +44 -0
  17. data/lib/livetext/handler/mixin.rb +37 -0
  18. data/lib/livetext/handler.rb +3 -0
  19. data/lib/{helpers.rb → livetext/helpers.rb} +89 -67
  20. data/lib/{html.rb → livetext/html.rb} +3 -2
  21. data/lib/{parser → livetext/parser}/general.rb +0 -3
  22. data/lib/{parser → livetext/parser}/set.rb +1 -6
  23. data/lib/{parser → livetext/parser}/string.rb +2 -2
  24. data/lib/{parser.rb → livetext/parser.rb} +0 -1
  25. data/lib/livetext/parsing.rb +29 -0
  26. data/lib/livetext/paths.rb +13 -0
  27. data/lib/livetext/processor.rb +89 -0
  28. data/lib/livetext/reopen.rb +12 -0
  29. data/lib/livetext/skeleton.rb +17 -0
  30. data/lib/{standard.rb → livetext/standard.rb} +152 -122
  31. data/lib/livetext/userapi.rb +153 -0
  32. data/lib/livetext/version.rb +6 -0
  33. data/lib/livetext.rb +66 -27
  34. data/plugin/bookish.rb +85 -85
  35. data/plugin/calibre.rb +3 -3
  36. data/plugin/livemagick.rb +17 -17
  37. data/plugin/markdown.rb +10 -10
  38. data/plugin/pyggish.rb +131 -162
  39. data/plugin/tutorial.rb +15 -16
  40. data/test/all.rb +6 -0
  41. data/test/snapshots/def_method/expected-output.txt +2 -0
  42. data/test/snapshots/def_method/source.lt3 +4 -2
  43. data/test/snapshots/error_inc_line_num/OUT +17 -0
  44. data/test/snapshots/error_inc_line_num/README.txt +20 -0
  45. data/test/snapshots/error_inc_line_num/expected-output.txt +0 -6
  46. data/test/snapshots/error_inc_line_num/match-error.txt +1 -1
  47. data/test/snapshots/error_line_num/match-error.txt +1 -1
  48. data/test/snapshots/error_missing_end/expected-output.txt +0 -1
  49. data/test/snapshots/error_name_not_permitted/expected-output.txt +4 -0
  50. data/test/snapshots/error_name_not_permitted/match-error.txt +1 -1
  51. data/test/snapshots/error_no_such_copy/duh +26 -0
  52. data/test/snapshots/error_no_such_copy/expected-output.txt +1 -0
  53. data/test/snapshots/error_no_such_copy/match-error.txt +1 -1
  54. data/test/snapshots/error_no_such_copy/mystery.txt +36 -0
  55. data/test/snapshots/error_no_such_inc/match-error.txt +1 -1
  56. data/test/snapshots/error_no_such_mixin/expected-output.txt +1 -0
  57. data/test/snapshots/error_no_such_mixin/match-error.txt +1 -1
  58. data/test/snapshots/error_no_such_mixin/source.lt3 +1 -1
  59. data/test/snapshots/example_alpha/source.lt3 +2 -2
  60. data/test/snapshots/example_alpha2/expected-output.txt +0 -2
  61. data/test/snapshots/example_alpha2/source.lt3 +5 -4
  62. data/test/snapshots/{icanhaz → import}/expected-output.txt +2 -1
  63. data/test/snapshots/import/match-error.txt +1 -0
  64. data/test/snapshots/{icanhaz → import}/simple_import.rb +1 -1
  65. data/test/snapshots/{icanhaz → import}/source.lt3 +2 -2
  66. data/test/snapshots/{icanhaz2 → import2}/expected-error.txt +0 -0
  67. data/test/snapshots/{icanhaz2 → import2}/expected-output.txt +3 -1
  68. data/test/snapshots/{icanhaz2/simple_canhaz.rb → import2/simple_import.rb} +1 -1
  69. data/test/snapshots/import2/source.lt3 +8 -0
  70. data/test/snapshots/import_bookish/expected-error.txt +0 -0
  71. data/test/snapshots/import_bookish/expected-output.txt +10 -0
  72. data/test/snapshots/import_bookish/source.lt3 +7 -0
  73. data/test/snapshots/import_bookish/toc.tmp +0 -0
  74. data/test/snapshots/mixin_bookish/expected-error.txt +0 -0
  75. data/test/snapshots/mixin_bookish/expected-output.txt +10 -0
  76. data/test/snapshots/mixin_bookish/source.lt3 +7 -0
  77. data/test/snapshots/mixin_bookish/toc.tmp +0 -0
  78. data/test/snapshots/more_functions/expected-error.txt +0 -0
  79. data/test/snapshots/more_functions/expected-output.txt +37 -0
  80. data/test/snapshots/more_functions/source.lt3 +40 -0
  81. data/test/snapshots/raw_lines/expected-output.txt +0 -2
  82. data/test/snapshots/simple_import/expected-output.txt +2 -0
  83. data/test/snapshots/simple_import/simple_import.rb +1 -1
  84. data/test/snapshots/simple_import/source.lt3 +3 -1
  85. data/test/snapshots/simple_mixin/simple_mixin.rb +1 -1
  86. data/test/snapshots/single_raw_line/expected-output.txt +0 -2
  87. data/test/snapshots/subset.txt +14 -14
  88. data/test/snapshots.rb +30 -13
  89. data/test/unit/formatline.rb +253 -134
  90. data/test/unit/html.rb +2 -3
  91. data/test/unit/parser/general.rb +1 -2
  92. data/test/unit/parser/mixin.rb +1 -3
  93. data/test/unit/parser/set.rb +8 -12
  94. data/test/unit/parser/string.rb +6 -6
  95. data/test/unit/parser.rb +0 -1
  96. data/test/unit/standard.rb +0 -2
  97. metadata +47 -30
  98. data/imports/markdown_importable.rb +0 -45
  99. data/lib/handler/icanhaz.rb +0 -35
  100. data/lib/handler.rb +0 -1
  101. data/lib/livetext/importable.rb +0 -2
  102. data/lib/parser/file.rb +0 -8
  103. data/lib/parser/import.rb +0 -15
  104. data/lib/parser/mixin.rb +0 -38
  105. data/lib/processor.rb +0 -83
  106. data/lib/userapi.rb +0 -160
  107. data/test/snapshots/icanhaz/match-error.txt +0 -1
  108. data/test/snapshots/icanhaz2/source.lt3 +0 -6
  109. data/test/unit/parser/importable.rb +0 -19
@@ -1,3 +1,4 @@
1
+
1
2
  require 'pathname' # For _seek - remove later??
2
3
 
3
4
  require_relative 'parser' # nested requires
@@ -14,7 +15,7 @@ make_exception(:FileNotFound, "Error: file '%1' not found")
14
15
  module Livetext::Standard
15
16
 
16
17
  include HTMLHelper
17
- include Helpers
18
+ include Livetext::Helpers
18
19
 
19
20
  SimpleFormats = # Move this?
20
21
  { b: %w[<b> </b>],
@@ -22,321 +23,339 @@ module Livetext::Standard
22
23
  t: ["<font size=+1><tt>", "</tt></font>"],
23
24
  s: %w[<strike> </strike>] }
24
25
 
25
- attr_reader :_data
26
+ attr_reader :data
26
27
 
27
28
  def data=(val) # FIXME this is weird, let's remove it soonish
28
- @_data = val.chomp
29
- @_args = val.split rescue []
30
- @_mixins = []
29
+ api.data = val.chomp
30
+ # @args = val.split rescue []
31
+ @mixins = []
32
+ @imports = []
33
+ ###
34
+ # api.data = val
31
35
  end
32
36
 
33
37
  # dumb name - bold, italic, teletype, striketrough
34
- def bits(args = nil, body = nil)
35
- b0, b1, i0, i1, t0, t1, s0, s1 = *@_args
38
+
39
+ def bits(args = nil, body = nil) # FIXME umm what is this?
40
+ b0, b1, i0, i1, t0, t1, s0, s1 = *api.args
36
41
  SimpleFormats[:b] = [b0, b1]
37
42
  SimpleFormats[:i] = [i0, i1]
38
43
  SimpleFormats[:t] = [t0, t1]
39
44
  SimpleFormats[:s] = [s0, s1]
45
+ api.optional_blank_line
40
46
  end
41
47
 
42
48
  def backtrace(args = nil, body = nil)
43
- @backtrace = onoff(@_args.first)
44
- _optional_blank_line
49
+ @backtrace = onoff(api.args.first)
50
+ api.optional_blank_line
45
51
  end
46
52
 
47
53
  def comment(args = nil, body = nil)
48
- _body
49
- _optional_blank_line
54
+ api.body
55
+ api.optional_blank_line
50
56
  end
51
57
 
52
58
  def shell(args = nil, body = nil)
53
- cmd = @_data.chomp
59
+ cmd = api.data
54
60
  system(cmd)
55
- _optional_blank_line
61
+ api.optional_blank_line
56
62
  end
57
63
 
58
64
  def func(args = nil, body = nil)
59
- funcname = @_args[0]
65
+ funcname = api.args[0]
60
66
  check_disallowed(funcname)
61
67
  func_def = <<~EOS
62
68
  def #{funcname}(param)
63
- #{_body.to_a.join("\n")}
69
+ #{api.body.to_a.join("\n")}
64
70
  end
65
71
  EOS
66
- _optional_blank_line
72
+ api.optional_blank_line
67
73
  Livetext::Functions.class_eval func_def
74
+ return true
68
75
  end
69
76
 
70
- def h1(args = nil, body = nil); _out wrapped(@_data, :h1); end
71
- def h2(args = nil, body = nil); _out wrapped(@_data, :h2); end
72
- def h3(args = nil, body = nil); _out wrapped(@_data, :h3); end
73
- def h4(args = nil, body = nil); _out wrapped(@_data, :h4); end
74
- def h5(args = nil, body = nil); _out wrapped(@_data, :h5); end
75
- def h6(args = nil, body = nil); _out wrapped(@_data, :h6); end
77
+ def h1(args = nil, body = nil); api.out wrapped(api.data, :h1); return true; end
78
+ def h2(args = nil, body = nil); api.out wrapped(api.data, :h2); return true; end
79
+ def h3(args = nil, body = nil); api.out wrapped(api.data, :h3); return true; end
80
+ def h4(args = nil, body = nil); api.out wrapped(api.data, :h4); return true; end
81
+ def h5(args = nil, body = nil); api.out wrapped(api.data, :h5); return true; end
82
+ def h6(args = nil, body = nil); api.out wrapped(api.data, :h6); return true; end
76
83
 
77
84
  def list(args = nil, body = nil)
78
85
  wrap :ul do
79
- _body {|line| _out wrapped(line, :li) }
86
+ api.body {|line| api.out wrapped(line, :li) }
80
87
  end
81
- _optional_blank_line
88
+ api.optional_blank_line
82
89
  end
83
90
 
84
91
  def list!(args = nil, body = nil)
85
92
  wrap(:ul) do
86
- lines = _body.each # enumerator
93
+ lines = api.body.each # enumerator
87
94
  loop do
88
95
  line = lines.next
89
- line = _format(line)
96
+ line = api.format(line)
90
97
  str = line[0] == " " ? line : wrapped(line, :li)
91
- _out str
98
+ api.out str
92
99
  end
93
100
  end
94
- _optional_blank_line
101
+ api.optional_blank_line
95
102
  end
96
103
 
97
104
  def shell!(args = nil, body = nil)
98
- cmd = @_data.chomp
105
+ cmd = api.data
99
106
  system(cmd)
100
- _optional_blank_line
107
+ api.optional_blank_line
101
108
  end
102
109
 
103
110
  def errout(args = nil, body = nil)
104
- STDERR.puts @_data.chomp
105
- _optional_blank_line
111
+ ::STDERR.puts api.data
112
+ api.optional_blank_line
106
113
  end
107
114
 
108
115
  def ttyout(args = nil, body = nil)
109
- TTY.puts @_data.chomp
110
- _optional_blank_line
116
+ TTY.puts api.data
117
+ api.optional_blank_line
111
118
  end
112
119
 
113
120
  def say(args = nil, body = nil)
114
- str = _format(@_data.chomp)
121
+ str = api.format(api.data)
115
122
  TTY.puts str
116
- _optional_blank_line
123
+ api.optional_blank_line
117
124
  end
118
125
 
119
126
  def banner(args = nil, body = nil)
120
- str = _format(@_data.chomp)
127
+ str = api.format(api.data)
121
128
  num = str.length
122
129
  decor = "-"*num + "\n"
123
130
  puts decor + str + "\n" + decor
124
131
  end
125
132
 
126
133
  def quit(args = nil, body = nil)
127
- puts @body
128
- @body = ""
129
134
  @output.close
130
135
  end
131
136
 
132
137
  def cleanup(args = nil, body = nil)
133
- @_args.each do |item|
138
+ api.args.each do |item|
134
139
  cmd = ::File.directory?(item) ? "rm -f #{item}/*" : "rm #{item}"
135
140
  system(cmd)
136
141
  end
142
+ api.optional_blank_line
137
143
  end
138
144
 
139
145
  def dot_def(args = nil, body = nil)
140
- name = @_args[0]
146
+ name = api.args[0]
141
147
  str = "def #{name}\n"
142
148
  check_disallowed(name)
143
149
  # Difficult to avoid eval here
144
- str << _body(true).join("\n")
150
+ str << api.body(true).join("\n")
145
151
  str << "\nend\n"
146
152
  eval str
153
+ api.optional_blank_line
147
154
  end
148
155
 
149
156
  def set(args = nil, body = nil)
150
- line = _data.chomp
157
+ line = api.data.chomp
151
158
  pairs = Livetext::ParseSet.new(line).parse
152
159
  set_variables(pairs)
160
+ api.optional_blank_line
153
161
  end
154
162
 
155
163
  # FIXME really these should be one method...
156
164
 
157
165
  def variables!(args = nil, body = nil) # cwd, not FileDir - weird, fix later
158
- prefix = _args[0]
159
- file = _args[1]
166
+ prefix = api.args[0]
167
+ file = api.args[1]
160
168
  prefix = nil if prefix == "-" # FIXME dumb hack
161
169
  if file
162
170
  here = "" # different for ! version
163
171
  lines = File.readlines(here + file)
164
172
  else
165
- lines = _body
173
+ lines = api.body
166
174
  end
167
175
  pairs = Livetext::ParseGeneral.parse_vars(prefix, lines)
168
176
  set_variables(pairs)
177
+ api.optional_blank_line
169
178
  end
170
179
 
171
180
  def variables(args = nil, body = nil)
172
- prefix = _args[0]
173
- file = _args[1]
181
+ prefix = api.args[0]
182
+ file = api.args[1]
174
183
  prefix = nil if prefix == "-" # FIXME dumb hack
175
184
  if file
176
185
  here = ::Livetext::Vars[:FileDir] + "/"
177
186
  lines = File.readlines(here + file)
178
187
  else
179
- lines = _body
188
+ lines = api.body
180
189
  end
181
190
  pairs = Livetext::ParseGeneral.parse_vars(prefix, lines)
182
191
  set_variables(pairs)
192
+ api.optional_blank_line
183
193
  end
184
194
 
185
195
  def heredoc(args = nil, body = nil)
186
- var = @_args[0]
187
- text = _body.join("\n")
196
+ var = api.args[0]
197
+ text = api.body.join("\n")
188
198
  rhs = ""
189
199
  text.each_line do |line|
190
- str = Livetext.interpolate(line.chomp)
200
+ str = api.format(line.chomp)
191
201
  rhs << str + "<br>"
192
202
  end
193
203
  indent = @parent.indentation.last
194
204
  indented = " " * indent
195
- @parent.setvar(var, rhs.chomp)
196
- _optional_blank_line
205
+ api.setvar(var, rhs.chomp)
206
+ # @parent.setvar(var, rhs.chomp)
207
+ api.optional_blank_line
197
208
  end
198
209
 
199
210
  def seek(args = nil, body = nil) # like include, but search upward as needed
200
- file = @_args.first
211
+ file = api.args.first
201
212
  file = search_upward(file)
202
213
  check_file_exists(file)
203
214
  @parent.process_file(file)
204
- _optional_blank_line
215
+ api.optional_blank_line
205
216
  end
206
217
 
207
218
  def dot_include(args = nil, body = nil) # dot command
208
- file = _format(@_args.first) # allows for variables
219
+ file = api.format(api.args.first) # allows for variables
209
220
  check_file_exists(file)
210
221
  @parent.process_file(file)
211
- _optional_blank_line
222
+ api.optional_blank_line
212
223
  end
213
224
 
214
225
  def inherit(args = nil, body = nil)
215
- file = @_args.first
226
+ file = api.args.first
216
227
  upper = "../#{file}"
217
228
  got_upper, got_file = File.exist?(upper), File.exist?(file)
218
229
  good = got_upper || got_file
219
- _error!("File #{file} not found (local or parent)") unless good
230
+ STDERR.puts "File #{file} not found (local or parent)" unless good
220
231
 
221
232
  @parent.process_file(upper) if got_upper
222
233
  @parent.process_file(file) if got_file
223
- _optional_blank_line
234
+ api.optional_blank_line
224
235
  end
225
236
 
226
237
  def mixin(args = nil, body = nil)
227
- name = @_args.first # Expect a module name
228
- return if @_mixins.include?(name)
229
- @_mixins << name
230
- mod = Livetext::ParseMixin.get_module(name) # FIXME??
238
+ name = api.args.first # Expect a module name
239
+ return if @mixins.include?(name)
240
+ @mixins << name
241
+ mod = Livetext::Handler::Mixin.get_module(name, @parent)
231
242
  self.extend(mod)
232
243
  init = "init_#{name}"
233
- self.send(init) if self.respond_to? init
234
- _optional_blank_line
244
+ self.send(init) rescue nil # if self.respond_to? init
245
+ api.optional_blank_line
235
246
  end
236
247
 
237
- def icanhaz(args = nil, body = nil)
238
- name = @_args.first # Expect a module name
239
- return if @_mixins.include?(name)
240
- @_mixins << name
241
- mod = Livetext::Handler::ICanHaz.get_module(name) # FIXME??
248
+ def import(args = nil, body = nil)
249
+ name = api.args.first # Expect a module name
250
+ return if @imports.include?(name)
251
+ @imports << name
252
+ mod = Livetext::Handler::Import.get_module(name, @parent)
242
253
  self.extend(mod)
243
254
  init = "init_#{name}"
244
- self.send(init) if self.respond_to? init
245
- _optional_blank_line
246
- end
247
-
248
- def import(args = nil, body = nil)
249
- name = @_args.first # Expect a module name
250
- return if @_mixins.include?(name)
251
- @_mixins << name
252
- mod = Livetext::ParseImport.get_module(name)
253
- parse.use_import(name)
254
- _optional_blank_line
255
+ self.send(init) rescue nil # if self.respond_to? init
256
+ api.optional_blank_line
255
257
  end
256
258
 
257
259
  def copy(args = nil, body = nil)
258
- file = @_args.first
259
- check_file_exists(file)
260
- _out grab_file(file)
261
- _optional_blank_line
260
+ file = api.args.first
261
+ ok = check_file_exists(file)
262
+
263
+ self.parent.graceful_error FileNotFound(file) unless ok # FIXME seems weird?
264
+ api.out grab_file(file)
265
+ api.optional_blank_line
266
+ [ok, file]
262
267
  end
263
268
 
264
269
  def r(args = nil, body = nil)
265
- _out @_data.chomp # No processing at all
270
+ api.out api.data # No processing at all
271
+ api.optional_blank_line
266
272
  end
267
273
 
268
274
  def raw(args = nil, body = nil)
269
275
  # No processing at all (terminate with __EOF__)
270
- _raw_body {|line| _out line } # no formatting
276
+ api.raw_body {|line| api.out line } # no formatting
277
+ api.optional_blank_line
271
278
  end
272
279
 
273
280
  def debug(args = nil, body = nil)
274
- self._debug = onoff(@_args.first)
281
+ self._debug = onoff(api.args.first)
282
+ api.optional_blank_line
275
283
  end
276
284
 
277
285
  def passthru(args = nil, body = nil)
278
286
  # FIXME - add check for args size? (helpers)
279
- @_nopass = ! onoff(_args.first)
287
+ @nopass = ! onoff(api.args.first)
288
+ api.optional_blank_line
280
289
  end
281
290
 
282
291
  def nopass(args = nil, body = nil)
283
- @_nopass = true
292
+ @nopass = true
293
+ api.optional_blank_line
284
294
  end
285
295
 
286
296
  def para(args = nil, body = nil)
287
297
  # FIXME - add check for args size? (helpers)
288
- @_nopara = ! onoff(_args.first)
298
+ @nopara = ! onoff(api.args.first)
299
+ api.optional_blank_line
289
300
  end
290
301
 
291
302
  def nopara(args = nil, body = nil)
292
- @_nopara = true
303
+ @nopara = true
304
+ api.optional_blank_line
293
305
  end
294
306
 
295
307
  def heading(args = nil, body = nil)
296
- _print "<center><font size=+1><b>"
297
- _print @_data.chomp
298
- _print "</b></font></center>"
308
+ api.print "<center><font size=+1><b>"
309
+ api.print api.data
310
+ api.print "</b></font></center>"
311
+ api.optional_blank_line
299
312
  end
300
313
 
301
314
  def newpage(args = nil, body = nil)
302
- _out '<p style="page-break-after:always;"></p>'
303
- _out "<p/>"
315
+ api.out '<p style="page-break-after:always;"></p>'
316
+ api.out "<p/>"
317
+ api.optional_blank_line
304
318
  end
305
319
 
306
320
  def mono(args = nil, body = nil)
307
321
  wrap ":pre" do
308
- _body(true) {|line| _out line }
322
+ api.body(true) {|line| api.out line }
309
323
  end
310
- _optional_blank_line
324
+ api.optional_blank_line
311
325
  end
312
326
 
313
327
  def dlist(args = nil, body = nil)
314
- delim = _args.first
328
+ delim = api.args.first
315
329
  wrap(:dl) do
316
- _body do |line|
317
- line = _format(line)
330
+ api.body do |line|
331
+ line = api.format(line)
318
332
  term, defn = line.split(delim)
319
- _out wrapped(term, :dt)
320
- _out wrapped(defn, :dd)
333
+ api.out wrapped(term, :dt)
334
+ api.out wrapped(defn, :dd)
321
335
  end
322
336
  end
337
+ api.optional_blank_line
323
338
  end
324
339
 
325
340
  def link(args = nil, body = nil)
326
- url = _args.first
327
- text = _args[2..-1].join(" ")
328
- _out "<a style='text-decoration: none' href='#{url}'>#{text}</a>"
341
+ url = api.args.first
342
+ text = api.args[2..-1].join(" ")
343
+ api.out "<a style='text-decoration: none' href='#{url}'>#{text}</a>"
344
+ api.optional_blank_line
329
345
  end
330
346
 
331
347
  def xtable(args = nil, body = nil) # Borrowed from bookish - FIXME
332
- title = @_data.chomp
348
+ # TTY.puts "=== #{__method__} #{__FILE__} #{__LINE__}"
349
+ title = api.data
333
350
  delim = " :: "
334
- _out "<br><center><table width=90% cellpadding=5>"
335
- lines = _body(true)
351
+ api.out "<br><center><table width=90% cellpadding=5>"
352
+ lines = api.body(true)
336
353
  maxw = nil
354
+ processed = []
337
355
  lines.each do |line|
338
- line = _format(line)
356
+ line = api.format(line)
339
357
  line.gsub!(/\n+/, "<br>")
358
+ processed << line
340
359
  cells = line.split(delim)
341
360
  wide = cells.map {|cell| cell.length }
342
361
  maxw = [0] * cells.size
@@ -346,25 +365,36 @@ module Livetext::Standard
346
365
  sum = maxw.inject(0, :+)
347
366
  maxw.map! {|x| (x/sum*100).floor }
348
367
 
349
- lines.each do |line|
368
+ processed.each do |line|
350
369
  cells = line.split(delim)
351
370
  wrap :tr do
352
- cells.each {|cell| _out " <td valign=top>#{cell}</td>" }
371
+ cells.each {|cell| api.out " <td valign=top>#{cell}</td>" }
353
372
  end
354
373
  end
355
- _out "</table></center>"
374
+ api.out "</table></center>"
375
+ api.optional_blank_line
356
376
  end
357
377
 
358
378
  def image(args = nil, body = nil)
359
- name = @_args[0]
360
- _out "<img src='#{name}'></img>"
379
+ name = api.args[0]
380
+ api.out "<img src='#{name}'></img>"
381
+ api.optional_blank_line
361
382
  end
362
383
 
363
384
  def br(args = nil, body = nil)
364
- num = _args.first || "1"
365
- out = ""
366
- num.to_i.times { out << "<br>" }
367
- _out out
385
+ num = api.args.first || "1"
386
+ str = ""
387
+ num.to_i.times { str << "<br>" }
388
+ api.out str
389
+ api.optional_blank_line
368
390
  end
369
391
 
392
+ def reflection # strictly experimental!
393
+ list = self.methods
394
+ obj = Object.instance_methods
395
+ diff = (list - obj).sort
396
+ api.out "#{diff.size} methods:"
397
+ api.out diff.inspect
398
+ api.optional_blank_line
399
+ end
370
400
  end
@@ -0,0 +1,153 @@
1
+
2
+ require_relative 'formatline'
3
+
4
+ # Encapsulate the UserAPI as a class
5
+
6
+ class Livetext::UserAPI
7
+
8
+ attr_accessor :data, :args
9
+
10
+ def initialize(live)
11
+ @live = live
12
+ @vars = live.vars
13
+ end
14
+
15
+ def setvar(var, val)
16
+ # FIXME don't like this...
17
+ str, sym = var.to_s, var.to_sym
18
+ Livetext::Vars[str] = val
19
+ Livetext::Vars[sym] = val
20
+ end
21
+
22
+ def check_existence(file, msg)
23
+ STDERR.puts msg unless File.exist?(file)
24
+ end
25
+
26
+ def data=(value)
27
+ @data = value
28
+ @args = format(@data).chomp.split
29
+ end
30
+
31
+ def args
32
+ return @args unless block_given?
33
+ @args.each {|arg| yield arg }
34
+ end
35
+
36
+ def vars
37
+ @vars
38
+ end
39
+
40
+ def optional_blank_line
41
+ peek = @live.peek_nextline # ???
42
+ return if peek.nil?
43
+ @line = @live.nextline if peek =~ /^ *$/
44
+ return true # This way, dot commands will usually return true
45
+ end
46
+
47
+ def comment?(str)
48
+ sigil = Livetext::Sigil
49
+ c1 = sigil + Livetext::Space
50
+ str.index(c1) == 0
51
+ end
52
+
53
+ def trailing?(char)
54
+ return true if ["\n", " ", nil].include?(char)
55
+ return false
56
+ end
57
+
58
+ def end?(str)
59
+ return true if str == ".end" || str =~ / *\$\.end/
60
+ return false
61
+ end
62
+
63
+ def raw_body(tag = "__EOF__")
64
+ lines = []
65
+ @live.save_location = @live.sources.last
66
+ loop do
67
+ @line = @live.nextline
68
+ break if @line.nil?
69
+ break if @line.chomp.strip == tag
70
+ lines << @line
71
+ end
72
+ optional_blank_line
73
+ return lines unless block_given?
74
+ lines.each {|line| yield line }
75
+ end
76
+
77
+ def body(raw=false)
78
+ lines = []
79
+ end_found = false
80
+ loop do
81
+ @line = @live.nextline
82
+ break if @line.nil?
83
+ @line.chomp!
84
+ break if end?(@line)
85
+ next if comment?(@line)
86
+ @line = format(@line) unless raw
87
+ lines << @line
88
+ end
89
+ raise "Expected .end, found end of file" unless end?(@line) # use custom exception
90
+ optional_blank_line # FIXME Delete this??
91
+ return lines unless block_given?
92
+ lines.each {|line| yield line } # FIXME what about $. ?
93
+ end
94
+
95
+ def body_text(raw=false)
96
+ raw_body.join("\n")
97
+ end
98
+
99
+ def raw_body!
100
+ raw_body(Livetext::Sigil).join("\n")
101
+ end
102
+
103
+ def handle_escapes(str, set)
104
+ str = str.dup
105
+ set.each_char do |ch|
106
+ str.gsub!("\\#{ch}", ch)
107
+ end
108
+ str
109
+ end
110
+
111
+ def format(line)
112
+ return "" if line == "\n" || line.nil?
113
+ line2 = Livetext::FormatLine.parse!(line)
114
+ # line.replace(line2)
115
+ line2
116
+ end
117
+
118
+ def passthru(line)
119
+ return if @live.nopass
120
+ out "<p>" if line == "\n" and ! @live.nopara
121
+ line = format(line)
122
+ out line
123
+ end
124
+
125
+ def out(str = "", file = nil)
126
+ return if str.nil?
127
+ return file.puts str unless file.nil?
128
+ @live.body << str
129
+ @live.body << "\n" unless str.end_with?("\n")
130
+ end
131
+
132
+ def out!(str = "")
133
+ @live.body << str # no newline
134
+ end
135
+
136
+ def puts(*args)
137
+ @live.output.puts *args
138
+ end
139
+
140
+ def print(*args)
141
+ @live.output.print *args
142
+ end
143
+
144
+ def debug=(val)
145
+ @live.debug = val
146
+ end
147
+
148
+ def debug(*args)
149
+ TTY.puts *args if @live.debug
150
+ end
151
+
152
+ end
153
+
@@ -0,0 +1,6 @@
1
+
2
+ # Defining VERSION
3
+
4
+ class Livetext
5
+ VERSION = "0.9.25"
6
+ end