livetext 0.9.13 → 0.9.19
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/README.lt3 +2 -2
- data/imports/bookish.rb +288 -0
- data/imports/calibre.rb +28 -0
- data/imports/livemagick.rb +133 -0
- data/imports/markdown.rb +44 -0
- data/imports/markdown_importable.rb +46 -0
- data/imports/pyggish.rb +204 -0
- data/imports/tutorial.rb +95 -0
- data/lib/cmdargs.rb +93 -0
- data/lib/errors.rb +4 -2
- data/lib/formatline.rb +56 -83
- data/lib/functions.rb +1 -1
- data/lib/handler/icanhaz.rb +35 -0
- data/lib/handler.rb +1 -0
- data/lib/helpers.rb +177 -4
- data/lib/livetext.rb +20 -139
- data/lib/parser/file.rb +8 -0
- data/lib/parser/general.rb +1 -1
- data/lib/parser/import.rb +1 -3
- data/lib/parser/mixin.rb +22 -30
- data/lib/parser/set.rb +35 -26
- data/lib/parser/string.rb +19 -4
- data/lib/processor.rb +2 -12
- data/lib/standard.rb +73 -107
- data/lib/userapi.rb +1 -4
- data/livetext.gemspec +2 -1
- data/plugin/bookish.rb +26 -22
- data/plugin/calibre.rb +1 -1
- data/plugin/livemagick.rb +10 -10
- data/plugin/markdown.rb +13 -11
- data/plugin/pyggish.rb +94 -84
- data/plugin/tutorial.rb +10 -5
- data/test/snapshots/OMIT.txt +11 -0
- data/test/snapshots/clusion.txt +84 -0
- data/test/snapshots/error_inc_line_num/match-error.txt +1 -0
- data/test/snapshots/error_invalid_name/match-error.txt +1 -0
- data/test/snapshots/error_line_num/match-error.txt +1 -0
- data/test/snapshots/error_mismatched_end/expected-output.txt +0 -2
- data/test/snapshots/error_mismatched_end/match-error.txt +1 -0
- data/test/snapshots/error_missing_end/match-error.txt +1 -0
- data/test/snapshots/error_no_such_copy/match-error.txt +1 -0
- data/test/snapshots/error_no_such_copy/source.lt3 +0 -1
- data/test/snapshots/error_no_such_inc/match-error.txt +1 -0
- data/test/snapshots/error_no_such_mixin/match-error.txt +1 -0
- data/test/snapshots/icanhaz/expected-output.txt +5 -0
- data/test/snapshots/icanhaz/match-error.txt +1 -0
- data/test/snapshots/icanhaz/simple_import.rb +5 -0
- data/test/snapshots/{error_no_such_mixin/actual-output.txt → icanhaz/source.lt3} +3 -4
- data/test/snapshots/{error_invalid_name/actual-output.txt → icanhaz2/expected-error.txt} +0 -0
- data/test/snapshots/icanhaz2/expected-output.txt +6 -0
- data/test/snapshots/icanhaz2/simple_canhaz.rb +5 -0
- data/test/snapshots/icanhaz2/source.lt3 +6 -0
- data/test/snapshots/predef_vars/match-output.txt +6 -0
- data/test/snapshots/{error_no_such_copy/actual-output.txt → simple_import/expected-error.txt} +0 -0
- data/test/snapshots/simple_import/expected-output.txt +7 -0
- data/test/snapshots/simple_import/simple_import.rb +5 -0
- data/test/snapshots/simple_import/source.lt3 +7 -0
- data/test/snapshots/simple_include/source.lt3 +0 -1
- data/test/snapshots.rb +103 -107
- data/test/unit/all.rb +1 -0
- data/test/unit/formatline.rb +650 -0
- data/test/unit/parser/general.rb +21 -21
- data/test/unit/parser/importable.rb +1 -1
- data/test/unit/parser/mixin.rb +2 -2
- data/test/unit/parser/set.rb +19 -12
- data/test/unit/parser/string.rb +14 -14
- data/test/unit/parser.rb +2 -0
- metadata +37 -46
- data/test/formatting.rb +0 -103
- data/test/snapshots/error_inc_line_num/actual-error.txt +0 -1
- data/test/snapshots/error_inc_line_num/actual-output.txt +0 -13
- data/test/snapshots/error_inc_line_num/expected-err-line1match.txt +0 -1
- data/test/snapshots/error_inc_line_num/out-sdiff.txt +0 -14
- data/test/snapshots/error_invalid_name/actual-error.txt +0 -10
- data/test/snapshots/error_invalid_name/expected-err-line1match.txt +0 -1
- data/test/snapshots/error_invalid_name/out-sdiff.txt +0 -6
- data/test/snapshots/error_line_num/actual-error.txt +0 -1
- data/test/snapshots/error_line_num/actual-output.txt +0 -5
- data/test/snapshots/error_line_num/expected-err-line1match.txt +0 -1
- data/test/snapshots/error_line_num/out-sdiff.txt +0 -6
- data/test/snapshots/error_mismatched_end/actual-error.txt +0 -1
- data/test/snapshots/error_mismatched_end/actual-output.txt +0 -8
- data/test/snapshots/error_mismatched_end/expected-err-line1match.txt +0 -1
- data/test/snapshots/error_mismatched_end/out-sdiff.txt +0 -9
- data/test/snapshots/error_missing_end/actual-error.txt +0 -1
- data/test/snapshots/error_missing_end/actual-output.txt +0 -5
- data/test/snapshots/error_missing_end/expected-err-line1match.txt +0 -1
- data/test/snapshots/error_missing_end/out-sdiff.txt +0 -6
- data/test/snapshots/error_name_not_permitted/OLD-exp-out +0 -4
- data/test/snapshots/error_no_such_copy/actual-error.txt +0 -10
- data/test/snapshots/error_no_such_copy/expected-err-line1match.txt +0 -1
- data/test/snapshots/error_no_such_copy/out-sdiff.txt +0 -5
- data/test/snapshots/error_no_such_inc/actual-error.txt +0 -10
- data/test/snapshots/error_no_such_inc/actual-output.txt +0 -0
- data/test/snapshots/error_no_such_inc/expected-err-line1match.txt +0 -1
- data/test/snapshots/error_no_such_inc/out-sdiff.txt +0 -6
- data/test/snapshots/error_no_such_mixin/actual-error.txt +0 -1
- data/test/snapshots/error_no_such_mixin/expected-err-line1match.txt +0 -1
- data/test/snapshots/error_no_such_mixin/out-sdiff.txt +0 -12
- data/test/snapshots/lines.txt +0 -124
- data/test/snapshots/predef_vars/actual-error.txt +0 -0
- data/test/snapshots/predef_vars/actual-output.txt +0 -6
- data/test/snapshots/predef_vars/expected-output.txt +0 -6
- data/test/snapshots/predef_vars/out-sdiff.txt +0 -7
- data/test/snapshots/simple_mixin/actual-error.txt +0 -2
- data/test/snapshots/simple_mixin/actual-output.txt +0 -4
- data/test/snapshots/simple_mixin/out-sdiff.txt +0 -6
- data/test/unit/parse_misc.rb +0 -60
- data/test/unit/parse_set.rb +0 -157
data/lib/functions.rb
CHANGED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
|
|
2
|
+
class Livetext::Handler::ICanHaz
|
|
3
|
+
include Helpers
|
|
4
|
+
|
|
5
|
+
attr_reader :file
|
|
6
|
+
|
|
7
|
+
def initialize(name)
|
|
8
|
+
@name = name
|
|
9
|
+
@file = find_file(name)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def self.get_module(name)
|
|
13
|
+
handler = self.new(name)
|
|
14
|
+
const1 = Object.constants
|
|
15
|
+
@file = handler.file.sub(/.rb$/, "")
|
|
16
|
+
require @file # + ".rb"
|
|
17
|
+
const2 = Object.constants
|
|
18
|
+
names = (const2 - const1)
|
|
19
|
+
abort "Expected ONE new constant: #{names.inspect}" if names.size != 1
|
|
20
|
+
modname = names.first.to_s
|
|
21
|
+
newmod = Object.const_get("::" + modname)
|
|
22
|
+
newmod # return actual module
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
private
|
|
26
|
+
|
|
27
|
+
def cwd_root?
|
|
28
|
+
File.dirname(File.expand_path(".")) == "/"
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def fname2module(name)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
end
|
|
35
|
+
|
data/lib/handler.rb
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
require_relative 'handler/icanhaz'
|
data/lib/helpers.rb
CHANGED
|
@@ -1,10 +1,117 @@
|
|
|
1
1
|
|
|
2
2
|
module Helpers
|
|
3
3
|
|
|
4
|
+
Space = " "
|
|
5
|
+
Sigil = "." # Can't change yet
|
|
6
|
+
|
|
7
|
+
def escape_html(string)
|
|
8
|
+
enc = string.encoding
|
|
9
|
+
unless enc.ascii_compatible?
|
|
10
|
+
if enc.dummy?
|
|
11
|
+
origenc = enc
|
|
12
|
+
enc = Encoding::Converter.asciicompat_encoding(enc)
|
|
13
|
+
string = enc ? string.encode(enc) : string.b
|
|
14
|
+
end
|
|
15
|
+
table = Hash[TABLE_FOR_ESCAPE_HTML__.map {|pair|pair.map {|s|s.encode(enc)}}]
|
|
16
|
+
string = string.gsub(/#{"['&\"<>]".encode(enc)}/, table)
|
|
17
|
+
string.encode!(origenc) if origenc
|
|
18
|
+
return string
|
|
19
|
+
end
|
|
20
|
+
string.gsub(/['&\"<>]/, TABLE_FOR_ESCAPE_HTML__)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def find_file(name, ext=".rb")
|
|
24
|
+
paths = [Livetext::Path.sub(/lib/, "imports/"), "./"]
|
|
25
|
+
base = "#{name}#{ext}"
|
|
26
|
+
paths.each do |path|
|
|
27
|
+
file = path + base
|
|
28
|
+
return file if File.exist?(file)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
raise "No such mixin '#{name}'"
|
|
32
|
+
|
|
33
|
+
# # Really want to search upward??
|
|
34
|
+
# raise "No such mixin '#{name}'" if cwd_root?
|
|
35
|
+
# Dir.chdir("..") { find_file(name) }
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def self.rx(str, space=nil)
|
|
39
|
+
Regexp.compile("^" + Regexp.escape(str) + "#{space}")
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
Comment = rx(Sigil, Space)
|
|
43
|
+
Dotcmd = rx(Sigil)
|
|
44
|
+
Ddotcmd = /^ *\$\.[A-Za-z]/
|
|
45
|
+
|
|
46
|
+
## FIXME process_file[!] should call process[_text]
|
|
47
|
+
|
|
48
|
+
def process_file(fname, btrace=false)
|
|
49
|
+
setfile(fname)
|
|
50
|
+
text = File.readlines(fname)
|
|
51
|
+
enum = text.each
|
|
52
|
+
@backtrace = btrace
|
|
53
|
+
@main.source(enum, fname, 0)
|
|
54
|
+
line = nil
|
|
55
|
+
loop do
|
|
56
|
+
line = @main.nextline
|
|
57
|
+
break if line.nil?
|
|
58
|
+
process_line(line)
|
|
59
|
+
end
|
|
60
|
+
val = @main.finalize if @main.respond_to? :finalize
|
|
61
|
+
@body
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def process_line(line) # FIXME inefficient?
|
|
65
|
+
nomarkup = true
|
|
66
|
+
case line # must apply these in order
|
|
67
|
+
when Comment
|
|
68
|
+
handle_scomment(line)
|
|
69
|
+
when Dotcmd
|
|
70
|
+
handle_dotcmd(line)
|
|
71
|
+
when Ddotcmd
|
|
72
|
+
indent = line.index("$") + 1
|
|
73
|
+
@indentation.push(indent)
|
|
74
|
+
line.sub!(/^ *\$/, "")
|
|
75
|
+
handle_dotcmd(line)
|
|
76
|
+
indentation.pop
|
|
77
|
+
else
|
|
78
|
+
@main._passthru(line)
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def handle_dotcmd(line, indent = 0)
|
|
83
|
+
indent = @indentation.last # top of stack
|
|
84
|
+
line = line.sub(/# .*$/, "")
|
|
85
|
+
name = get_name(line).to_sym
|
|
86
|
+
result = nil
|
|
87
|
+
case
|
|
88
|
+
when name == :end # special case
|
|
89
|
+
puts @body
|
|
90
|
+
raise EndWithoutOpening()
|
|
91
|
+
when @main.respond_to?(name)
|
|
92
|
+
result = @main.send(name)
|
|
93
|
+
else
|
|
94
|
+
puts @body # earlier correct output, not flushed yet
|
|
95
|
+
raise "Name '#{name}' is unknown"
|
|
96
|
+
return
|
|
97
|
+
end
|
|
98
|
+
result
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def handle_scomment(line)
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def get_name(line)
|
|
105
|
+
name, data = line.split(" ", 2)
|
|
106
|
+
name = name[1..-1] # chop off sigil
|
|
107
|
+
name = "dot_" + name if %w[include def].include?(name)
|
|
108
|
+
@main.data = data
|
|
109
|
+
@main.check_disallowed(name)
|
|
110
|
+
name
|
|
111
|
+
end
|
|
112
|
+
|
|
4
113
|
def check_disallowed(name)
|
|
5
|
-
|
|
6
|
-
# FIXME use custom exception
|
|
7
|
-
raise DisallowedName, name if _disallowed?(name)
|
|
114
|
+
raise DisallowedName(name) if disallowed?(name)
|
|
8
115
|
end
|
|
9
116
|
|
|
10
117
|
def check_file_exists(file)
|
|
@@ -14,8 +121,74 @@ module Helpers
|
|
|
14
121
|
def set_variables(pairs)
|
|
15
122
|
pairs.each do |pair|
|
|
16
123
|
var, value = *pair
|
|
17
|
-
@parent.
|
|
124
|
+
@parent.setvar(var, value)
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def grab_file(fname)
|
|
129
|
+
File.read(fname)
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def search_upward(file)
|
|
133
|
+
value = nil
|
|
134
|
+
return file if File.exist?(file)
|
|
135
|
+
|
|
136
|
+
count = 1
|
|
137
|
+
loop do
|
|
138
|
+
front = "../" * count
|
|
139
|
+
count += 1
|
|
140
|
+
here = Pathname.new(front).expand_path.dirname.to_s
|
|
141
|
+
break if here == "/"
|
|
142
|
+
path = front + file
|
|
143
|
+
value = path if File.exist?(path)
|
|
144
|
+
break if value
|
|
145
|
+
end
|
|
146
|
+
STDERR.puts "Cannot find #{file.inspect} from #{Dir.pwd}" unless value
|
|
147
|
+
return value
|
|
148
|
+
rescue
|
|
149
|
+
STDERR.puts "Can't find #{file.inspect} from #{Dir.pwd}"
|
|
150
|
+
return nil
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
def include_file(file)
|
|
154
|
+
@_args = [file]
|
|
155
|
+
dot_include
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def onoff(arg) # helper
|
|
159
|
+
arg ||= "on"
|
|
160
|
+
raise ExpectedOnOff unless String === arg
|
|
161
|
+
case arg.downcase
|
|
162
|
+
when "on"
|
|
163
|
+
return true
|
|
164
|
+
when "off"
|
|
165
|
+
return false
|
|
166
|
+
else
|
|
167
|
+
raise ExpectedOnOff
|
|
18
168
|
end
|
|
19
169
|
end
|
|
20
170
|
|
|
171
|
+
def setvar(var, val)
|
|
172
|
+
str, sym = var.to_s, var.to_sym
|
|
173
|
+
Livetext::Vars[str] = val
|
|
174
|
+
Livetext::Vars[sym] = val
|
|
175
|
+
@_vars[str] = val
|
|
176
|
+
@_vars[sym] = val
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
def setfile(file)
|
|
180
|
+
if file
|
|
181
|
+
setvar(:File, file)
|
|
182
|
+
dir = File.dirname(File.expand_path(file))
|
|
183
|
+
setvar(:FileDir, dir)
|
|
184
|
+
else
|
|
185
|
+
setvar(:File, "[no file]")
|
|
186
|
+
setvar(:FileDir, "[no dir]")
|
|
187
|
+
end
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
def setfile!(file) # FIXME why does this variant exist?
|
|
191
|
+
setvar(:File, file)
|
|
192
|
+
end
|
|
193
|
+
|
|
21
194
|
end
|
data/lib/livetext.rb
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
# Class Livetext skeleton (top level).
|
|
2
2
|
|
|
3
3
|
class Livetext
|
|
4
|
-
VERSION = "0.9.
|
|
4
|
+
VERSION = "0.9.19"
|
|
5
5
|
Path = File.expand_path(File.join(File.dirname(__FILE__)))
|
|
6
|
+
|
|
7
|
+
module Handler
|
|
8
|
+
end
|
|
6
9
|
end
|
|
7
10
|
|
|
8
11
|
# $LOAD_PATH << Livetext::Path
|
|
@@ -15,27 +18,24 @@ require_relative 'userapi'
|
|
|
15
18
|
require_relative 'standard'
|
|
16
19
|
require_relative 'formatline'
|
|
17
20
|
require_relative 'processor'
|
|
21
|
+
require_relative 'helpers'
|
|
22
|
+
require_relative 'handler'
|
|
18
23
|
|
|
19
24
|
Plugins = File.expand_path(File.join(File.dirname(__FILE__), "../plugin"))
|
|
25
|
+
Imports = File.expand_path(File.join(File.dirname(__FILE__), "../imports"))
|
|
20
26
|
|
|
21
27
|
TTY = ::File.open("/dev/tty", "w")
|
|
22
28
|
|
|
29
|
+
make_exception(:EndWithoutOpening, "Error: found .end with no opening command")
|
|
30
|
+
|
|
23
31
|
# Class Livetext reopened (top level).
|
|
24
32
|
|
|
25
33
|
class Livetext
|
|
26
34
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
Space = " "
|
|
30
|
-
Sigil = "." # Can't change yet
|
|
35
|
+
include Helpers
|
|
31
36
|
|
|
32
|
-
|
|
33
|
-
Regexp.compile("^" + Regexp.escape(str) + "#{space}")
|
|
34
|
-
end
|
|
37
|
+
Vars = {}
|
|
35
38
|
|
|
36
|
-
Comment = rx(Sigil, Livetext::Space)
|
|
37
|
-
Dotcmd = rx(Sigil)
|
|
38
|
-
Ddotcmd = /^ *\$\.[A-Za-z]/
|
|
39
39
|
|
|
40
40
|
attr_reader :main
|
|
41
41
|
attr_accessor :no_puts
|
|
@@ -55,16 +55,17 @@ class Livetext
|
|
|
55
55
|
call = Array(call)
|
|
56
56
|
mix.each {|lib| obj.mixin(lib) }
|
|
57
57
|
call.each {|cmd| obj.main.send(cmd[1..-1]) } # ignores leading dot, no param
|
|
58
|
-
vars.each_pair {|var, val| obj.
|
|
58
|
+
vars.each_pair {|var, val| obj.setvar(var, val.to_s) }
|
|
59
59
|
obj
|
|
60
60
|
end
|
|
61
61
|
|
|
62
62
|
def customize(mix: [], call: [], vars: {})
|
|
63
63
|
mix = Array(mix)
|
|
64
64
|
call = Array(call)
|
|
65
|
+
# FIXME HF won't this break??
|
|
65
66
|
mix.each {|lib| mixin(lib) }
|
|
66
67
|
call.each {|cmd| @main.send(cmd[1..-1]) } # ignores leading dot, no param
|
|
67
|
-
vars.each_pair {|var, val|
|
|
68
|
+
vars.each_pair {|var, val| setvar(var, val.to_s) }
|
|
68
69
|
self
|
|
69
70
|
end
|
|
70
71
|
|
|
@@ -77,81 +78,17 @@ class Livetext
|
|
|
77
78
|
@main = Processor.new(self, output)
|
|
78
79
|
@indentation = [0]
|
|
79
80
|
@_vars = Livetext::Vars
|
|
80
|
-
|
|
81
|
-
# Other predefined variables (see also _setfile)
|
|
82
|
-
_setvar(:User, `whoami`.chomp)
|
|
83
|
-
_setvar(:Version, Livetext::VERSION)
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
def _parse_colon_args(args, hash) # really belongs in livetext
|
|
87
|
-
h2 = hash.dup
|
|
88
|
-
e = args.each
|
|
89
|
-
loop do
|
|
90
|
-
arg = e.next.chop.to_sym
|
|
91
|
-
raise "_parse_args: #{arg} is unknown" unless hash.keys.include?(arg)
|
|
92
|
-
h2[arg] = e.next
|
|
93
|
-
end
|
|
94
|
-
h2 = h2.reject {|k,v| v.nil? }
|
|
95
|
-
h2.each_pair {|k, v| raise "#{k} has no value" if v.empty? }
|
|
96
|
-
h2
|
|
81
|
+
initial_vars
|
|
97
82
|
end
|
|
98
83
|
|
|
99
|
-
def
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
val = args[0]
|
|
104
|
-
raise "Expected an argument '#{name}'" if val.nil?
|
|
105
|
-
val
|
|
106
|
-
end
|
|
107
|
-
|
|
108
|
-
def mixin(mod)
|
|
109
|
-
@main._mixin(mod)
|
|
110
|
-
end
|
|
111
|
-
|
|
112
|
-
def _setvar(var, val)
|
|
113
|
-
str, sym = var.to_s, var.to_sym
|
|
114
|
-
Livetext::Vars[str] = val
|
|
115
|
-
Livetext::Vars[sym] = val
|
|
116
|
-
@_vars[str] = val
|
|
117
|
-
@_vars[sym] = val
|
|
118
|
-
end
|
|
119
|
-
|
|
120
|
-
def _setfile(file)
|
|
121
|
-
if file
|
|
122
|
-
_setvar(:File, file)
|
|
123
|
-
dir = File.dirname(File.expand_path(file))
|
|
124
|
-
_setvar(:FileDir, dir)
|
|
125
|
-
else
|
|
126
|
-
_setvar(:File, "[no file]")
|
|
127
|
-
_setvar(:FileDir, "[no dir]")
|
|
128
|
-
end
|
|
129
|
-
end
|
|
130
|
-
|
|
131
|
-
def _setfile!(file)
|
|
132
|
-
_setvar(:File, file)
|
|
133
|
-
end
|
|
134
|
-
|
|
135
|
-
def process_line(line) # FIXME inefficient?
|
|
136
|
-
nomarkup = true
|
|
137
|
-
case line # must apply these in order
|
|
138
|
-
when Comment
|
|
139
|
-
handle_scomment(line)
|
|
140
|
-
when Dotcmd
|
|
141
|
-
handle_dotcmd(line)
|
|
142
|
-
when Ddotcmd
|
|
143
|
-
indent = line.index("$") + 1
|
|
144
|
-
@indentation.push(indent)
|
|
145
|
-
line.sub!(/^ *\$/, "")
|
|
146
|
-
handle_dotcmd(line)
|
|
147
|
-
indentation.pop
|
|
148
|
-
else
|
|
149
|
-
@main._passthru(line)
|
|
150
|
-
end
|
|
84
|
+
def initial_vars
|
|
85
|
+
# Other predefined variables (see also setfile)
|
|
86
|
+
setvar(:User, `whoami`.chomp)
|
|
87
|
+
setvar(:Version, Livetext::VERSION)
|
|
151
88
|
end
|
|
152
89
|
|
|
153
90
|
def transform(text)
|
|
154
|
-
|
|
91
|
+
setfile!("(string)")
|
|
155
92
|
enum = text.each_line
|
|
156
93
|
front = text.match(/.*?\n/).to_a.first.chomp rescue ""
|
|
157
94
|
@main.source(enum, "STDIN: '#{front}...'", 0)
|
|
@@ -188,61 +125,5 @@ class Livetext
|
|
|
188
125
|
self.body
|
|
189
126
|
end
|
|
190
127
|
|
|
191
|
-
## FIXME process_file[!] should call process[_text]
|
|
192
|
-
|
|
193
|
-
def process_file(fname, btrace=false)
|
|
194
|
-
_setfile(fname)
|
|
195
|
-
text = File.readlines(fname) # FIXME currently causes failure
|
|
196
|
-
enum = text.each
|
|
197
|
-
@backtrace = btrace
|
|
198
|
-
@main.source(enum, fname, 0)
|
|
199
|
-
line = nil
|
|
200
|
-
loop do
|
|
201
|
-
line = @main.nextline
|
|
202
|
-
break if line.nil?
|
|
203
|
-
process_line(line)
|
|
204
|
-
end
|
|
205
|
-
val = @main.finalize if @main.respond_to? :finalize
|
|
206
|
-
@body
|
|
207
|
-
rescue => err
|
|
208
|
-
STDERR.puts "[process_file] fname = #{fname.inspect}\n line = #{line.inspect}"
|
|
209
|
-
STDERR.puts "ERROR #{err} in process_file"
|
|
210
|
-
err.backtrace.each {|x| STDERR.puts " " + x }
|
|
211
|
-
# @body = ""
|
|
212
|
-
end
|
|
213
|
-
|
|
214
|
-
def handle_scomment(line)
|
|
215
|
-
end
|
|
216
|
-
|
|
217
|
-
def _get_name(line)
|
|
218
|
-
name, data = line.split(" ", 2)
|
|
219
|
-
name = name[1..-1] # chop off sigil
|
|
220
|
-
name = "_" + name if %w[include def].include?(name)
|
|
221
|
-
@main.data = data
|
|
222
|
-
@main.check_disallowed(name)
|
|
223
|
-
name
|
|
224
|
-
end
|
|
225
|
-
|
|
226
|
-
def handle_dotcmd(line, indent = 0)
|
|
227
|
-
indent = @indentation.last # top of stack
|
|
228
|
-
line = line.sub(/# .*$/, "")
|
|
229
|
-
name = _get_name(line).to_sym
|
|
230
|
-
result = nil
|
|
231
|
-
if @main.respond_to?(name)
|
|
232
|
-
result = @main.send(name)
|
|
233
|
-
else
|
|
234
|
-
@main._error! "Name '#{name}' is unknown"
|
|
235
|
-
return
|
|
236
|
-
end
|
|
237
|
-
result
|
|
238
|
-
rescue => err
|
|
239
|
-
STDERR.puts "Error: #{err.inspect}"
|
|
240
|
-
# STDERR.puts err.backtrace
|
|
241
|
-
# @main._error!(err)
|
|
242
|
-
puts @body
|
|
243
|
-
@body = ""
|
|
244
|
-
return @body
|
|
245
|
-
end
|
|
246
|
-
|
|
247
128
|
end
|
|
248
129
|
|
data/lib/parser/file.rb
ADDED
data/lib/parser/general.rb
CHANGED
|
@@ -7,7 +7,7 @@ make_exception(:NilValue, "Error: nil value")
|
|
|
7
7
|
make_exception(:NullString, "Error: null string")
|
|
8
8
|
make_exception(:ExpectedString, "Error: expected a string")
|
|
9
9
|
|
|
10
|
-
class Livetext::
|
|
10
|
+
class Livetext::ParseGeneral < StringParser
|
|
11
11
|
|
|
12
12
|
def initialize(str)
|
|
13
13
|
super
|
data/lib/parser/import.rb
CHANGED
|
@@ -4,9 +4,7 @@ require '../livetext/importable'
|
|
|
4
4
|
make_exception(:BadVariableName, "Error: invalid variable name")
|
|
5
5
|
make_exception(:NoEqualSign, "Error: no equal sign found")
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
class Livetext::ParseImport
|
|
7
|
+
class Livetext::Handler::Import
|
|
10
8
|
def use_import(name)
|
|
11
9
|
require name
|
|
12
10
|
include name
|
data/lib/parser/mixin.rb
CHANGED
|
@@ -1,46 +1,38 @@
|
|
|
1
1
|
require_relative '../livetext'
|
|
2
|
+
require_relative '../helpers'
|
|
2
3
|
require_relative 'string'
|
|
3
4
|
|
|
4
|
-
make_exception(:BadVariableName, "Error: invalid variable name")
|
|
5
5
|
make_exception(:NoEqualSign, "Error: no equal sign found")
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
class Livetext::ParseMixin
|
|
8
|
+
include Helpers
|
|
8
9
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
# end
|
|
14
|
-
#
|
|
15
|
-
# def initialize(line)
|
|
16
|
-
# super
|
|
17
|
-
# end
|
|
10
|
+
def initialize(name)
|
|
11
|
+
@name = name
|
|
12
|
+
@file = find_file(name)
|
|
13
|
+
end
|
|
18
14
|
|
|
19
|
-
def
|
|
20
|
-
|
|
15
|
+
def self.get_module(name)
|
|
16
|
+
parse = self.new(name)
|
|
17
|
+
modname, code = parse.read_mixin
|
|
18
|
+
eval(code) # Avoid in the future
|
|
19
|
+
newmod = Object.const_get("::" + modname)
|
|
20
|
+
# return actual module
|
|
21
|
+
newmod
|
|
21
22
|
end
|
|
22
23
|
|
|
23
|
-
def
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
def read_mixin
|
|
25
|
+
modname = @name.gsub("/","_").capitalize
|
|
26
|
+
meths = grab_file(@file)
|
|
27
|
+
[modname, "module ::#{modname}; #{meths}\nend"]
|
|
28
|
+
end
|
|
26
29
|
|
|
27
|
-
|
|
28
|
-
return file if File.exist?(file)
|
|
30
|
+
private
|
|
29
31
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
+
def cwd_root?
|
|
33
|
+
File.dirname(File.expand_path(".")) == "/"
|
|
32
34
|
end
|
|
33
35
|
|
|
34
|
-
def use_mixin(name, file)
|
|
35
|
-
modname = name.gsub("/","_").capitalize
|
|
36
|
-
meths = grab_file(file)
|
|
37
|
-
string = "module ::#{modname}; #{meths}\nend"
|
|
38
|
-
eval(string)
|
|
39
|
-
newmod = Object.const_get("::" + modname)
|
|
40
|
-
self.extend(newmod)
|
|
41
|
-
init = "init_#{name}"
|
|
42
|
-
self.send(init) if self.respond_to? init
|
|
43
|
-
end
|
|
44
36
|
|
|
45
37
|
end
|
|
46
38
|
|
data/lib/parser/set.rb
CHANGED
|
@@ -17,22 +17,31 @@ class Livetext::ParseSet < StringParser
|
|
|
17
17
|
super
|
|
18
18
|
end
|
|
19
19
|
|
|
20
|
+
def wtf(note="")
|
|
21
|
+
TTY.puts "| PARSER: @i = #@i @len = #@len"
|
|
22
|
+
TTY.puts "|#{note}"
|
|
23
|
+
TTY.puts "| [" + @line.gsub(" ", "_") + "]"
|
|
24
|
+
TTY.print "| " # 0-based (one extra space)
|
|
25
|
+
@i.times { TTY.print "-" }
|
|
26
|
+
TTY.puts "^"
|
|
27
|
+
TTY.puts
|
|
28
|
+
end
|
|
29
|
+
|
|
20
30
|
def parse
|
|
21
31
|
pairs = []
|
|
22
|
-
|
|
32
|
+
char = nil
|
|
23
33
|
loop do
|
|
24
|
-
skip_spaces
|
|
25
|
-
char = self.peek
|
|
26
34
|
break if eos? # end of string
|
|
35
|
+
char = skip_spaces
|
|
27
36
|
raise "Expected alpha to start var name" unless char =~ /[a-z]/i
|
|
28
37
|
pairs << assignment
|
|
29
|
-
skip_spaces
|
|
30
|
-
char = self.peek
|
|
38
|
+
char = skip_spaces
|
|
31
39
|
break if eos? # end of string
|
|
32
40
|
case char
|
|
33
41
|
when nil # end of string
|
|
34
42
|
when ","
|
|
35
|
-
|
|
43
|
+
char = grab # skip comma
|
|
44
|
+
char = skip_spaces
|
|
36
45
|
else
|
|
37
46
|
raise "Expected comma or end of string (found #{char.inspect})"
|
|
38
47
|
end
|
|
@@ -47,7 +56,7 @@ class Livetext::ParseSet < StringParser
|
|
|
47
56
|
var = get_var
|
|
48
57
|
skip_equal
|
|
49
58
|
value = get_value
|
|
50
|
-
value = FormatLine.var_func_parse(value)
|
|
59
|
+
value = FormatLine.var_func_parse(value) # FIXME broken now?
|
|
51
60
|
pair = [var, value]
|
|
52
61
|
pair
|
|
53
62
|
end
|
|
@@ -55,11 +64,11 @@ class Livetext::ParseSet < StringParser
|
|
|
55
64
|
def get_var
|
|
56
65
|
name = ""
|
|
57
66
|
loop do
|
|
58
|
-
char =
|
|
67
|
+
char = peek
|
|
59
68
|
break if eos? # end of string
|
|
60
69
|
case char
|
|
61
70
|
when /[a-zA-Z_\.0-9]/
|
|
62
|
-
name <<
|
|
71
|
+
name << grab
|
|
63
72
|
next
|
|
64
73
|
when /[ =]/
|
|
65
74
|
return name
|
|
@@ -73,11 +82,10 @@ class Livetext::ParseSet < StringParser
|
|
|
73
82
|
def skip_equal
|
|
74
83
|
found = false
|
|
75
84
|
skip_spaces
|
|
76
|
-
raise NoEqualSign unless
|
|
85
|
+
raise NoEqualSign unless peek == "="
|
|
77
86
|
found = true
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
peek = self.peek
|
|
87
|
+
grab # skip =
|
|
88
|
+
skip_spaces # skip spaces too
|
|
81
89
|
return peek # just for testing
|
|
82
90
|
rescue StopIteration
|
|
83
91
|
raise NoEqualSign unless found
|
|
@@ -85,40 +93,41 @@ class Livetext::ParseSet < StringParser
|
|
|
85
93
|
end
|
|
86
94
|
|
|
87
95
|
def escaped
|
|
88
|
-
|
|
89
|
-
|
|
96
|
+
grab # skip backslash
|
|
97
|
+
grab # return following char
|
|
90
98
|
end
|
|
91
99
|
|
|
92
100
|
make_exception(:BadQuotedString, "Bad quoted string: %1")
|
|
93
101
|
|
|
94
102
|
def quoted_value
|
|
95
|
-
quote =
|
|
103
|
+
quote = grab # opening quote...
|
|
96
104
|
value = ""
|
|
97
105
|
char = nil
|
|
98
106
|
loop do
|
|
99
|
-
char =
|
|
100
|
-
break if
|
|
107
|
+
char = grab
|
|
108
|
+
break if eos?
|
|
101
109
|
break if char == quote
|
|
110
|
+
# break if char.nil?
|
|
102
111
|
char = escaped if char == "\\"
|
|
103
112
|
value << char
|
|
104
|
-
char = self.next
|
|
105
113
|
end
|
|
106
114
|
if char == quote
|
|
107
|
-
char =
|
|
115
|
+
# char = grab
|
|
108
116
|
return value
|
|
109
117
|
end
|
|
110
118
|
raise BadQuotedString, quote + value
|
|
111
119
|
end
|
|
112
120
|
|
|
113
121
|
def unquoted_value
|
|
114
|
-
|
|
122
|
+
char = nil
|
|
115
123
|
value = ""
|
|
116
124
|
loop do
|
|
117
|
-
char =
|
|
118
|
-
break if
|
|
125
|
+
char = peek
|
|
126
|
+
break if eos? # FIXME oops???
|
|
127
|
+
# break if char.nil?
|
|
119
128
|
break if char == " " || char == ","
|
|
120
129
|
value << char
|
|
121
|
-
char =
|
|
130
|
+
char = grab
|
|
122
131
|
end
|
|
123
132
|
value
|
|
124
133
|
end
|
|
@@ -128,8 +137,8 @@ class Livetext::ParseSet < StringParser
|
|
|
128
137
|
end
|
|
129
138
|
|
|
130
139
|
def get_value
|
|
131
|
-
char =
|
|
132
|
-
value = quote?(char) ?
|
|
140
|
+
char = peek
|
|
141
|
+
value = quote?(char) ? quoted_value : unquoted_value
|
|
133
142
|
value
|
|
134
143
|
end
|
|
135
144
|
end
|