livetext 0.9.52 → 0.9.55
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 +3 -3
- data/lib/livetext/core.rb +108 -53
- data/lib/livetext/expansion.rb +21 -21
- data/lib/livetext/formatter.rb +70 -200
- data/lib/livetext/formatter_component.rb +189 -0
- data/lib/livetext/function_registry.rb +163 -0
- data/lib/livetext/handler/mixin.rb +25 -0
- data/lib/livetext/helpers.rb +25 -7
- data/lib/livetext/reopen.rb +2 -0
- data/lib/livetext/skeleton.rb +0 -3
- data/lib/livetext/standard.rb +118 -70
- data/lib/livetext/variable_manager.rb +65 -0
- data/lib/livetext/variables.rb +4 -0
- data/lib/livetext/version.rb +1 -1
- data/lib/livetext.rb +9 -3
- data/plugin/booktool.rb +8 -8
- data/test/snapshots/complex_body/expected-error.txt +0 -0
- data/test/snapshots/complex_body/expected-output.txt +8 -0
- data/test/snapshots/complex_body/source.lt3 +19 -0
- data/test/snapshots/debug_command/expected-error.txt +0 -0
- data/test/snapshots/debug_command/expected-output.txt +1 -0
- data/test/snapshots/debug_command/source.lt3 +3 -0
- data/test/snapshots/def_parameters/expected-error.txt +0 -0
- data/test/snapshots/def_parameters/expected-output.txt +21 -0
- data/test/snapshots/def_parameters/source.lt3 +44 -0
- data/test/snapshots/functions_reflection/expected-error.txt +0 -0
- data/test/snapshots/functions_reflection/expected-output.txt +27 -0
- data/test/snapshots/functions_reflection/source.lt3 +5 -0
- data/test/snapshots/multiple_functions/expected-error.txt +0 -0
- data/test/snapshots/multiple_functions/expected-output.txt +5 -0
- data/test/snapshots/multiple_functions/source.lt3 +16 -0
- data/test/snapshots/nested_includes/expected-error.txt +0 -0
- data/test/snapshots/nested_includes/expected-output.txt +68 -0
- data/test/snapshots/nested_includes/level2.inc +34 -0
- data/test/snapshots/nested_includes/level3.inc +20 -0
- data/test/snapshots/nested_includes/source.lt3 +49 -0
- data/test/snapshots/parameter_handling/expected-error.txt +0 -0
- data/test/snapshots/parameter_handling/expected-output.txt +7 -0
- data/test/snapshots/parameter_handling/source.lt3 +10 -0
- data/test/snapshots/subset.txt +1 -0
- data/test/snapshots/system_info/expected-error.txt +0 -0
- data/test/snapshots/system_info/expected-output.txt +18 -0
- data/test/snapshots/system_info/source.lt3 +16 -0
- data/test/unit/all.rb +4 -0
- data/test/unit/core_methods.rb +137 -0
- data/test/unit/formatter.rb +84 -0
- data/test/unit/formatter_component.rb +84 -0
- data/test/unit/function_registry.rb +132 -0
- data/test/unit/variable_manager.rb +71 -0
- metadata +36 -3
- data/lib/livetext/processor.rb +0 -88
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 00c147a97637c967777f1a1a8bae52d8e0ca8e65f3e032e9a03f0f3bbc2c5d50
|
4
|
+
data.tar.gz: c931920c669cf05c76176d19bcfb9c06149d3bf6b32167aa2e6da7b50290adef
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 59836de9481a1239cf0c0f00f55681da634c7e96e337c67d2c4fb8974ec3dad06fa83bbe7eb7f73596c73d97e9359aab613efbf87d0ddfe70e9a3a50c65e931e
|
7
|
+
data.tar.gz: b0e1a74d2d75e8c47afff0881594d1022dbb63e71ec67b8304622b9885bc62429d6782286482a45520587207fc48e4158d0a857f51bcac5596c51cc779f2cf01
|
data/imports/bookish.rb
CHANGED
@@ -205,7 +205,7 @@ api.tty "## sec: cp 4"
|
|
205
205
|
title = api.data
|
206
206
|
delim = " :: "
|
207
207
|
api.out "<br><center><table width=90% cellpadding=5>"
|
208
|
-
lines =
|
208
|
+
lines = body
|
209
209
|
maxw = nil
|
210
210
|
lines.each do |line|
|
211
211
|
api.format(line)
|
@@ -238,8 +238,8 @@ api.tty "## sec: cp 4"
|
|
238
238
|
_debug "Closing TOC"
|
239
239
|
@toc.close
|
240
240
|
rescue => err
|
241
|
-
puts
|
242
|
-
|
241
|
+
puts self.body
|
242
|
+
self.body = ""
|
243
243
|
_errout "Exception: #{err.inspect}"
|
244
244
|
end
|
245
245
|
|
data/lib/livetext/core.rb
CHANGED
@@ -8,7 +8,23 @@ class Livetext
|
|
8
8
|
|
9
9
|
TTY = ::File.open("/dev/tty", "w")
|
10
10
|
|
11
|
-
|
11
|
+
Disallowed =
|
12
|
+
%i[ __binding__ __id__ __send__ class
|
13
|
+
clone display dup enum_for
|
14
|
+
eql? equal? extend freeze
|
15
|
+
frozen? hash inspect instance_eval
|
16
|
+
instance_exec instance_of? is_a? kind_of?
|
17
|
+
method methods nil? object_id
|
18
|
+
pretty_inspect private_methods protected_methods public_method
|
19
|
+
public_methods public_send respond_to? send
|
20
|
+
singleton_class singleton_method singleton_methods taint
|
21
|
+
tainted? tap to_enum to_s
|
22
|
+
trust untaint untrust untrusted?
|
23
|
+
define_singleton_method instance_variable_defined?
|
24
|
+
instance_variable_get instance_variable_set
|
25
|
+
remove_instance_variable instance_variables ]
|
26
|
+
|
27
|
+
attr_reader :sources, :function_registry, :variables, :formatter
|
12
28
|
attr_accessor :nopass, :nopara
|
13
29
|
attr_accessor :body, :indentation
|
14
30
|
|
@@ -17,7 +33,7 @@ class Livetext
|
|
17
33
|
end
|
18
34
|
|
19
35
|
def vars
|
20
|
-
@
|
36
|
+
@variables
|
21
37
|
end
|
22
38
|
|
23
39
|
def self.interpolate(str)
|
@@ -27,16 +43,10 @@ class Livetext
|
|
27
43
|
str3
|
28
44
|
end
|
29
45
|
|
30
|
-
def peek_nextline
|
31
|
-
@main.peek_nextline # delegate
|
32
|
-
end
|
33
46
|
|
34
|
-
def nextline
|
35
|
-
@main.nextline # delegate
|
36
|
-
end
|
37
47
|
|
38
48
|
def sources
|
39
|
-
@
|
49
|
+
@sources # delegate
|
40
50
|
end
|
41
51
|
|
42
52
|
def save_location
|
@@ -48,18 +58,15 @@ class Livetext
|
|
48
58
|
end
|
49
59
|
|
50
60
|
def initialize(output = ::STDOUT) # Livetext
|
51
|
-
@source = nil
|
52
|
-
@_mixins = []
|
53
|
-
@_imports = []
|
54
|
-
@_outdir = "."
|
55
|
-
@no_puts = output.nil?
|
56
61
|
@body = ""
|
57
|
-
@main = Processor.new(self, output) # nil = make @main its own parent??
|
58
|
-
@parent = @main
|
59
62
|
@indentation = [0]
|
60
|
-
@_vars = Livetext::Vars
|
61
63
|
@api = UserAPI.new(self)
|
62
|
-
|
64
|
+
@output = ::Livetext.output = output
|
65
|
+
@html = Livetext::HTML.new(@api)
|
66
|
+
@sources = []
|
67
|
+
@function_registry = Livetext::FunctionRegistry.new
|
68
|
+
@variables = Livetext::VariableManager.new(self)
|
69
|
+
@formatter = Livetext::Formatter.new(self)
|
63
70
|
# puts "------ init: self = "
|
64
71
|
# p self
|
65
72
|
end
|
@@ -71,7 +78,7 @@ class Livetext
|
|
71
78
|
mix.each do |lib|
|
72
79
|
obj.invoke_dotcmd(:mixin, lib.dup)
|
73
80
|
end
|
74
|
-
call.each {|cmd| obj.
|
81
|
+
call.each {|cmd| obj.send(cmd[1..-1]) } # ignores leading dot, no param
|
75
82
|
obj.api.setvars(vars)
|
76
83
|
obj
|
77
84
|
end
|
@@ -80,22 +87,17 @@ class Livetext
|
|
80
87
|
mix = Array(mix)
|
81
88
|
call = Array(call)
|
82
89
|
mix.each {|lib| mixin(lib) }
|
83
|
-
call.each {|cmd|
|
90
|
+
call.each {|cmd| send(cmd[1..-1]) } # ignores leading dot, no param
|
84
91
|
# vars.each_pair {|var, val| @api.set(var, val.to_s) }
|
85
92
|
api.setvars(vars)
|
86
93
|
self
|
87
94
|
end
|
88
95
|
|
89
|
-
|
96
|
+
def inspect
|
90
97
|
api_abbr = @api ? "(non-nil)" : "(not shown)"
|
91
|
-
main_abbr = @main ? "(non-nil)" : "(not shown)"
|
92
98
|
"Livetext:\n" +
|
93
|
-
" source = #{@source.inspect}\n" +
|
94
|
-
" mixins = #{@_mixins.inspect}\n" +
|
95
|
-
" import = #{@_mixins.inspect}\n" +
|
96
|
-
" main = #{main_abbr}\n" +
|
97
99
|
" indent = #{@indentation.inspect}\n" +
|
98
|
-
" vars = #{@
|
100
|
+
" vars = #{@variables.inspect}\n" +
|
99
101
|
" api = #{api_abbr}\n" +
|
100
102
|
" body = (#{@body.size} bytes)"
|
101
103
|
end
|
@@ -104,23 +106,83 @@ class Livetext
|
|
104
106
|
@api
|
105
107
|
end
|
106
108
|
|
109
|
+
def error(*args)
|
110
|
+
::STDERR.puts *args
|
111
|
+
end
|
112
|
+
|
113
|
+
def disallowed?(name)
|
114
|
+
flag = Disallowed.include?(name.to_sym)
|
115
|
+
flag
|
116
|
+
end
|
117
|
+
|
118
|
+
def output=(io)
|
119
|
+
@output = io
|
120
|
+
end
|
121
|
+
|
122
|
+
def html
|
123
|
+
@html
|
124
|
+
end
|
125
|
+
|
126
|
+
def source(enum, file, line)
|
127
|
+
@sources.push([enum, file, line])
|
128
|
+
end
|
129
|
+
|
130
|
+
def peek_nextline
|
131
|
+
return nil if @sources.empty?
|
132
|
+
source = @sources.last
|
133
|
+
line = source[0].peek
|
134
|
+
line
|
135
|
+
rescue StopIteration
|
136
|
+
@sources.pop
|
137
|
+
nil
|
138
|
+
rescue => err
|
139
|
+
TTY.puts "#{__method__}: RESCUE err = #{err.inspect}"
|
140
|
+
nil
|
141
|
+
end
|
142
|
+
|
143
|
+
def nextline
|
144
|
+
return nil if @sources.empty?
|
145
|
+
line = @sources.last[0].next
|
146
|
+
@sources.last[2] += 1
|
147
|
+
line
|
148
|
+
rescue StopIteration
|
149
|
+
@sources.pop
|
150
|
+
nil
|
151
|
+
end
|
152
|
+
|
107
153
|
def api=(obj)
|
108
154
|
@api = obj
|
109
155
|
end
|
110
156
|
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
157
|
+
|
158
|
+
|
159
|
+
def process(text: nil, file: nil, vars: {})
|
160
|
+
# Set variables first
|
161
|
+
@variables.set_multiple(vars) unless vars.empty?
|
162
|
+
|
163
|
+
# Process based on input type
|
164
|
+
case
|
165
|
+
when file && text.nil?
|
166
|
+
process_file(file)
|
167
|
+
when file.nil? && text
|
168
|
+
transform_text(text)
|
169
|
+
when file.nil? && text.nil?
|
170
|
+
raise "Must specify file or text"
|
171
|
+
when file && text
|
172
|
+
raise "Cannot specify file and text"
|
173
|
+
end
|
174
|
+
|
175
|
+
[self.body, @variables.to_h]
|
115
176
|
end
|
116
177
|
|
117
|
-
|
178
|
+
# Keep transform for backward compatibility, but make it private
|
179
|
+
private def transform_text(text)
|
118
180
|
setfile!("(string)")
|
119
181
|
enum = text.each_line
|
120
182
|
front = text.match(/.*?\n/).to_a.first.chomp rescue ""
|
121
|
-
|
183
|
+
source(enum, "STDIN: '#{front}...'", 0)
|
122
184
|
loop do
|
123
|
-
line =
|
185
|
+
line = nextline
|
124
186
|
break if line.nil?
|
125
187
|
process_line(line)
|
126
188
|
end
|
@@ -129,29 +191,22 @@ class Livetext
|
|
129
191
|
result
|
130
192
|
end
|
131
193
|
|
132
|
-
#
|
194
|
+
# Keep for backward compatibility
|
195
|
+
def transform(text)
|
196
|
+
transform_text(text)
|
197
|
+
end
|
198
|
+
|
199
|
+
# Keep for backward compatibility
|
133
200
|
def xform(*args, file: nil, text: nil, vars: {})
|
134
|
-
|
135
|
-
|
136
|
-
xform_file(file)
|
137
|
-
when file.nil? && text
|
138
|
-
transform(text)
|
139
|
-
when file.nil? && text.nil?
|
140
|
-
raise "Must specify file or text"
|
141
|
-
when file && text
|
142
|
-
raise "Cannot specify file and text"
|
143
|
-
end
|
144
|
-
self.process_file(file)
|
145
|
-
self.body
|
201
|
+
body, _vars = process(file: file, text: text, vars: vars)
|
202
|
+
body
|
146
203
|
end
|
147
204
|
|
205
|
+
# Keep for backward compatibility
|
148
206
|
def xform_file(file, vars: nil)
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
self.process_file(file)
|
153
|
-
# checkpoint! "...returned"
|
154
|
-
self.body
|
207
|
+
vars_hash = vars.nil? ? {} : vars
|
208
|
+
body, _vars = process(file: file, vars: vars_hash)
|
209
|
+
body
|
155
210
|
end
|
156
211
|
|
157
212
|
end
|
data/lib/livetext/expansion.rb
CHANGED
@@ -8,8 +8,6 @@ class Livetext::Expansion
|
|
8
8
|
Lbrack = "\\["
|
9
9
|
Colon = ":"
|
10
10
|
|
11
|
-
Formatter = ::Livetext::Formatter
|
12
|
-
|
13
11
|
def initialize(instance) # Livetext::Expansion
|
14
12
|
@live = instance
|
15
13
|
end
|
@@ -18,7 +16,7 @@ class Livetext::Expansion
|
|
18
16
|
return "" if line == "\n" || line.nil?
|
19
17
|
with_vars = expand_variables(line)
|
20
18
|
with_func = expand_function_calls(with_vars)
|
21
|
-
formatted =
|
19
|
+
formatted = @live.formatter.format(with_func)
|
22
20
|
end
|
23
21
|
|
24
22
|
def expand_variables(str)
|
@@ -53,28 +51,30 @@ class Livetext::Expansion
|
|
53
51
|
end
|
54
52
|
|
55
53
|
def funcall(name, param)
|
56
|
-
|
54
|
+
# Use the unified function registry
|
57
55
|
name = name.gsub(/\./, "__")
|
56
|
+
result = @live.function_registry.call(name, param)
|
58
57
|
|
59
|
-
#
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
58
|
+
# If not found in registry, fall back to old system for backward compatibility
|
59
|
+
if result.start_with?("[Error evaluating $$#{name}(")
|
60
|
+
# Try old Livetext::Functions system
|
61
|
+
fobj = ::Livetext::Functions.new
|
62
|
+
old_result = fobj.send(name, param) rescue nil
|
63
|
+
return old_result.to_s if old_result
|
64
|
+
|
65
|
+
# Try Livetext instance (for mixin functions)
|
66
|
+
if @live.respond_to?(name)
|
67
|
+
method = @live.method(name)
|
68
|
+
if method.parameters.empty?
|
69
|
+
old_result = @live.send(name) rescue nil
|
70
|
+
else
|
71
|
+
old_result = @live.send(name, param) rescue nil
|
72
|
+
end
|
73
|
+
return old_result.to_s if old_result
|
72
74
|
end
|
73
|
-
return result.to_s
|
74
75
|
end
|
75
76
|
|
76
|
-
|
77
|
-
err
|
77
|
+
result
|
78
78
|
end
|
79
79
|
|
80
80
|
def expand_function_calls(str)
|
@@ -85,7 +85,7 @@ class Livetext::Expansion
|
|
85
85
|
rbrack = "\\]"
|
86
86
|
space_eol = "( |$)"
|
87
87
|
prx1 = "(?<param>[^ ]+)"
|
88
|
-
prx2 = "(?<param
|
88
|
+
prx2 = "(?<param>.*)"
|
89
89
|
pat2 = "(?<full_param>#{colon}#{prx1})"
|
90
90
|
pat3 = "(?<full_param>#{lbrack}#{prx2}#{rbrack})"
|
91
91
|
rx = Regexp.compile("#{pat1}(#{pat2}|#{pat3})?")
|
data/lib/livetext/formatter.rb
CHANGED
@@ -1,35 +1,84 @@
|
|
1
|
-
|
1
|
+
# Formatter - Centralized text formatting for Livetext
|
2
|
+
class Livetext::Formatter
|
3
|
+
def initialize(parent)
|
4
|
+
@parent = parent
|
5
|
+
end
|
2
6
|
|
3
|
-
def
|
4
|
-
|
7
|
+
def format(text)
|
8
|
+
return "" if text.nil? || text.empty?
|
9
|
+
|
10
|
+
text = text.chomp
|
5
11
|
# First, mark escaped characters so they won't be processed as formatting
|
6
|
-
|
12
|
+
text = mark_escaped_characters(text)
|
7
13
|
|
8
|
-
# Process all marker types in sequence
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
14
|
+
# Process all marker types in sequence
|
15
|
+
text = handle_double_markers(text)
|
16
|
+
text = handle_bracketed_markers(text)
|
17
|
+
text = handle_single_markers(text)
|
18
|
+
text = handle_underscore_markers(text)
|
19
|
+
text = handle_backtick_markers(text)
|
20
|
+
text = handle_tilde_markers(text)
|
15
21
|
|
16
|
-
|
17
|
-
|
22
|
+
text = unmark_escaped_characters(text)
|
23
|
+
text
|
24
|
+
end
|
25
|
+
|
26
|
+
def format_line(line)
|
27
|
+
return "" if line.nil?
|
28
|
+
format(line.chomp)
|
29
|
+
end
|
30
|
+
|
31
|
+
def format_multiple(lines)
|
32
|
+
lines.map { |line| format_line(line) }
|
33
|
+
end
|
34
|
+
|
35
|
+
# Convenience methods for common formatting patterns
|
36
|
+
def bold(text)
|
37
|
+
"<b>#{text}</b>"
|
38
|
+
end
|
39
|
+
|
40
|
+
def italic(text)
|
41
|
+
"<i>#{text}</i>"
|
42
|
+
end
|
43
|
+
|
44
|
+
def code(text)
|
45
|
+
"<tt>#{text}</tt>"
|
46
|
+
end
|
47
|
+
|
48
|
+
def strike(text)
|
49
|
+
"<strike>#{text}</strike>"
|
50
|
+
end
|
51
|
+
|
52
|
+
def link(text, url)
|
53
|
+
"<a href='#{url}'>#{text}</a>"
|
54
|
+
end
|
55
|
+
|
56
|
+
def escape_html(text)
|
57
|
+
text.gsub(/[&<>"']/) do |char|
|
58
|
+
case char
|
59
|
+
when '&' then '&'
|
60
|
+
when '<' then '<'
|
61
|
+
when '>' then '>'
|
62
|
+
when '"' then '"'
|
63
|
+
when "'" then '''
|
64
|
+
else char
|
65
|
+
end
|
66
|
+
end
|
18
67
|
end
|
19
68
|
|
20
69
|
private
|
21
70
|
|
22
|
-
def
|
71
|
+
def mark_escaped_characters(str)
|
23
72
|
# Replace escaped characters with a null byte marker (safe for internal use)
|
24
73
|
str.gsub(/\\([*_`~])/, "\u0000\\1")
|
25
74
|
end
|
26
75
|
|
27
|
-
def
|
76
|
+
def unmark_escaped_characters(str)
|
28
77
|
# Restore escaped characters
|
29
78
|
str.gsub(/\u0000([*_`~])/, '\1')
|
30
79
|
end
|
31
80
|
|
32
|
-
def
|
81
|
+
def handle_double_markers(str)
|
33
82
|
# **word -> <b>word</b> (terminated by space, comma, period)
|
34
83
|
# But ignore standalone ** or ** surrounded by spaces
|
35
84
|
str.gsub(/(?<=\s|^)\*\*([^\s,.]*)/) do |match|
|
@@ -41,7 +90,7 @@ module Livetext::Formatter
|
|
41
90
|
end
|
42
91
|
end
|
43
92
|
|
44
|
-
def
|
93
|
+
def handle_bracketed_markers(str)
|
45
94
|
# Handle all bracketed markers: *[content], _[content], `[content]
|
46
95
|
# *[content] -> <b>content</b>
|
47
96
|
# _[content] -> <i>content</i>
|
@@ -85,7 +134,7 @@ module Livetext::Formatter
|
|
85
134
|
str
|
86
135
|
end
|
87
136
|
|
88
|
-
def
|
137
|
+
def handle_single_markers(str)
|
89
138
|
# *word -> <b>word</b> (only at start of word or after space)
|
90
139
|
# But ignore standalone * or * surrounded by spaces
|
91
140
|
# Also ignore * that are part of ** patterns (already processed)
|
@@ -102,7 +151,7 @@ module Livetext::Formatter
|
|
102
151
|
end
|
103
152
|
end
|
104
153
|
|
105
|
-
def
|
154
|
+
def handle_underscore_markers(str)
|
106
155
|
# _word -> <i>word</i> (only at start of word or after space)
|
107
156
|
# But ignore standalone _ or _ surrounded by spaces
|
108
157
|
str.gsub(/(?<=\s|^)_([^\s]*)/) do |match|
|
@@ -114,7 +163,7 @@ module Livetext::Formatter
|
|
114
163
|
end
|
115
164
|
end
|
116
165
|
|
117
|
-
def
|
166
|
+
def handle_backtick_markers(str)
|
118
167
|
# `word -> <tt>word</tt> (only at start of word or after space)
|
119
168
|
# But ignore standalone ` or ` surrounded by spaces
|
120
169
|
str.gsub(/(?<=\s|^)`([^\s]*)/) do |match|
|
@@ -126,7 +175,7 @@ module Livetext::Formatter
|
|
126
175
|
end
|
127
176
|
end
|
128
177
|
|
129
|
-
def
|
178
|
+
def handle_tilde_markers(str)
|
130
179
|
# ~word -> <strike>word</strike> (only at start of word or after space)
|
131
180
|
# But ignore standalone ~ or ~ surrounded by spaces
|
132
181
|
str.gsub(/(?<=\s|^)~([^\s]*)/) do |match|
|
@@ -137,183 +186,4 @@ module Livetext::Formatter
|
|
137
186
|
end
|
138
187
|
end
|
139
188
|
end
|
140
|
-
|
141
189
|
end
|
142
|
-
|
143
|
-
# Legacy classes - kept for compatibility but not used
|
144
|
-
class Livetext::Formatter::Delimited
|
145
|
-
def initialize(str, marker, tag)
|
146
|
-
@str, @marker, @tag = str.dup, marker, tag
|
147
|
-
@buffer = ""
|
148
|
-
@cdata = ""
|
149
|
-
@state = :INITIAL
|
150
|
-
end
|
151
|
-
|
152
|
-
def status(where)
|
153
|
-
if $debug
|
154
|
-
STDERR.printf "%-11s %-7s #{@marker.inspect} \n #{' '*11} state = %-8s str = %-20s buffer = %-20s cdata = %-20s\n",
|
155
|
-
where, self.class, @state, @str.inspect, @buffer.inspect, @cdata.inspect
|
156
|
-
end
|
157
|
-
end
|
158
|
-
|
159
|
-
def front
|
160
|
-
@str[0]
|
161
|
-
end
|
162
|
-
|
163
|
-
def grab(n=1)
|
164
|
-
char = @str.slice!(0..(n-1))
|
165
|
-
char
|
166
|
-
end
|
167
|
-
|
168
|
-
def grab_terminator
|
169
|
-
@state = :LOOPING
|
170
|
-
end
|
171
|
-
|
172
|
-
def eol?
|
173
|
-
@str.empty?
|
174
|
-
end
|
175
|
-
|
176
|
-
def space?
|
177
|
-
front == " "
|
178
|
-
end
|
179
|
-
|
180
|
-
def escape?
|
181
|
-
front == "\\"
|
182
|
-
end
|
183
|
-
|
184
|
-
def terminated?
|
185
|
-
space?
|
186
|
-
end
|
187
|
-
|
188
|
-
def marker?
|
189
|
-
@str.start_with?(@marker)
|
190
|
-
end
|
191
|
-
|
192
|
-
def space_marker?
|
193
|
-
@str.start_with?(" " + @marker)
|
194
|
-
end
|
195
|
-
|
196
|
-
def wrap(text)
|
197
|
-
if text.empty?
|
198
|
-
result = @marker
|
199
|
-
result = "" if @marker[1] == "["
|
200
|
-
return result
|
201
|
-
end
|
202
|
-
"<#{@tag}>#{text}</#{@tag}>"
|
203
|
-
end
|
204
|
-
|
205
|
-
def initial
|
206
|
-
n = @marker.length
|
207
|
-
case
|
208
|
-
when escape?
|
209
|
-
grab
|
210
|
-
@buffer << grab
|
211
|
-
when space_marker?
|
212
|
-
@buffer << grab
|
213
|
-
grab(n)
|
214
|
-
@state = :CDATA
|
215
|
-
when marker?
|
216
|
-
grab(n)
|
217
|
-
@state = :CDATA
|
218
|
-
when eol?
|
219
|
-
@state = :FINAL
|
220
|
-
else
|
221
|
-
@state = :BUFFER
|
222
|
-
end
|
223
|
-
end
|
224
|
-
|
225
|
-
def buffer
|
226
|
-
@buffer << grab
|
227
|
-
@state = :LOOPING
|
228
|
-
end
|
229
|
-
|
230
|
-
def cdata
|
231
|
-
case
|
232
|
-
when eol?
|
233
|
-
if @cdata.empty?
|
234
|
-
@buffer << @marker unless @marker[1] == "["
|
235
|
-
else
|
236
|
-
@buffer << wrap(@cdata)
|
237
|
-
end
|
238
|
-
@state = :FINAL
|
239
|
-
when terminated?
|
240
|
-
@buffer << wrap(@cdata)
|
241
|
-
grab_terminator
|
242
|
-
@cdata = ""
|
243
|
-
@state = :LOOPING
|
244
|
-
else
|
245
|
-
@cdata << grab
|
246
|
-
@state = :CDATA
|
247
|
-
end
|
248
|
-
end
|
249
|
-
|
250
|
-
def looping
|
251
|
-
n = @marker.length
|
252
|
-
case
|
253
|
-
when escape?
|
254
|
-
grab
|
255
|
-
@buffer << grab
|
256
|
-
when space_marker?
|
257
|
-
@buffer << grab
|
258
|
-
grab(n)
|
259
|
-
@state = :CDATA
|
260
|
-
when eol?
|
261
|
-
@state = :FINAL
|
262
|
-
else
|
263
|
-
@buffer << grab
|
264
|
-
end
|
265
|
-
end
|
266
|
-
|
267
|
-
def handle
|
268
|
-
loop do
|
269
|
-
break if @state == :FINAL
|
270
|
-
meth = @state.downcase
|
271
|
-
send(meth)
|
272
|
-
end
|
273
|
-
return @buffer
|
274
|
-
end
|
275
|
-
|
276
|
-
def self.process(str)
|
277
|
-
bold = self.new(str, "*", "b")
|
278
|
-
sb = bold.handle
|
279
|
-
ital = self.new(sb, "_", "i")
|
280
|
-
si = ital.handle
|
281
|
-
code = self.new(si, "`", "tt")
|
282
|
-
sc = code.handle
|
283
|
-
stri = self.new(sc, "~", "strike")
|
284
|
-
si = stri.handle
|
285
|
-
si
|
286
|
-
end
|
287
|
-
end
|
288
|
-
|
289
|
-
class Livetext::Formatter::Single < Livetext::Formatter::Delimited
|
290
|
-
end
|
291
|
-
|
292
|
-
class Livetext::Formatter::Double < Livetext::Formatter::Delimited
|
293
|
-
def initialize(str, sigil, tag)
|
294
|
-
super
|
295
|
-
@marker = sigil + sigil
|
296
|
-
end
|
297
|
-
|
298
|
-
def terminated?
|
299
|
-
terms = [" ", ".", ","]
|
300
|
-
terms.include?(front)
|
301
|
-
end
|
302
|
-
end
|
303
|
-
|
304
|
-
class Livetext::Formatter::Bracketed < Livetext::Formatter::Delimited
|
305
|
-
def initialize(str, sigil, tag)
|
306
|
-
super
|
307
|
-
@marker = sigil + "["
|
308
|
-
end
|
309
|
-
|
310
|
-
def terminated?
|
311
|
-
front == "]" || eol?
|
312
|
-
end
|
313
|
-
|
314
|
-
def grab_terminator
|
315
|
-
@state = :LOOPING
|
316
|
-
grab
|
317
|
-
end
|
318
|
-
end
|
319
|
-
|