livetext 0.9.15 → 0.9.21

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 (71) hide show
  1. checksums.yaml +4 -4
  2. data/README.lt3 +4 -2
  3. data/README.md +330 -339
  4. data/bin/livetext +0 -2
  5. data/imports/bookish.rb +288 -0
  6. data/imports/calibre.rb +28 -0
  7. data/imports/livemagick.rb +133 -0
  8. data/imports/markdown.rb +44 -0
  9. data/imports/markdown_importable.rb +45 -0
  10. data/imports/pyggish.rb +204 -0
  11. data/imports/tutorial.rb +95 -0
  12. data/lib/cmdargs.rb +26 -17
  13. data/lib/formatline.rb +4 -4
  14. data/lib/handler/icanhaz.rb +35 -0
  15. data/lib/handler.rb +1 -0
  16. data/lib/helpers.rb +59 -2
  17. data/lib/livetext.rb +6 -1
  18. data/lib/parser/general.rb +1 -1
  19. data/lib/parser/import.rb +1 -3
  20. data/lib/parser/mixin.rb +1 -16
  21. data/lib/parser/set.rb +2 -2
  22. data/lib/parser/string.rb +9 -8
  23. data/lib/processor.rb +19 -11
  24. data/lib/standard.rb +13 -2
  25. data/lib/userapi.rb +3 -2
  26. data/livetext.gemspec +2 -1
  27. data/plugin/markdown.rb +6 -6
  28. data/plugin/tutorial.rb +4 -3
  29. data/test/snapshots/icanhaz/expected-output.txt +5 -0
  30. data/test/snapshots/icanhaz/match-error.txt +1 -0
  31. data/test/snapshots/icanhaz/simple_import.rb +5 -0
  32. data/test/snapshots/icanhaz/source.lt3 +10 -0
  33. data/test/snapshots/{error_invalid_name/actual-output.txt → icanhaz2/expected-error.txt} +0 -0
  34. data/test/snapshots/icanhaz2/expected-output.txt +6 -0
  35. data/test/snapshots/icanhaz2/simple_canhaz.rb +5 -0
  36. data/test/snapshots/icanhaz2/source.lt3 +6 -0
  37. data/test/snapshots/subset.txt +84 -0
  38. data/test/snapshots.rb +71 -37
  39. data/test/unit/parser/set.rb +17 -15
  40. data/test/unit/parser/string.rb +45 -6
  41. metadata +19 -33
  42. data/test/affirm/kbks.jpg +0 -0
  43. data/test/affirm/lm-kbks.lt +0 -19
  44. data/test/cleanup +0 -1
  45. data/test/newtest +0 -14
  46. data/test/sdtest +0 -6
  47. data/test/snapshots/OMIT.txt +0 -9
  48. data/test/snapshots/clusion.txt +0 -35
  49. data/test/snapshots/crap +0 -16
  50. data/test/snapshots/error_inc_line_num/actual-error.txt +0 -14
  51. data/test/snapshots/error_inc_line_num/actual-output.txt +0 -7
  52. data/test/snapshots/error_inc_line_num/out-sdiff.txt +0 -14
  53. data/test/snapshots/error_invalid_name/actual-error.txt +0 -10
  54. data/test/snapshots/error_invalid_name/out-sdiff.txt +0 -6
  55. data/test/snapshots/error_missing_end/actual-error.txt +0 -10
  56. data/test/snapshots/error_missing_end/actual-output.txt +0 -0
  57. data/test/snapshots/error_missing_end/out-sdiff.txt +0 -6
  58. data/test/snapshots/error_no_such_copy/actual-error.txt +0 -10
  59. data/test/snapshots/error_no_such_copy/actual-output.txt +0 -0
  60. data/test/snapshots/error_no_such_copy/out-sdiff.txt +0 -5
  61. data/test/snapshots/error_no_such_inc/actual-error.txt +0 -10
  62. data/test/snapshots/error_no_such_inc/actual-output.txt +0 -0
  63. data/test/snapshots/error_no_such_inc/out-sdiff.txt +0 -6
  64. data/test/snapshots/error_no_such_mixin/actual-error.txt +0 -37
  65. data/test/snapshots/error_no_such_mixin/actual-output.txt +0 -0
  66. data/test/snapshots/error_no_such_mixin/out-sdiff.txt +0 -6
  67. data/test/snapshots/fixit +0 -6
  68. data/test/snapshots/simple_import/actual-error.txt +0 -8
  69. data/test/snapshots/simple_import/actual-output.txt +0 -3
  70. data/test/snapshots/simple_import/err-sdiff.txt +0 -9
  71. data/test/snapshots/simple_import/out-sdiff.txt +0 -9
@@ -0,0 +1,204 @@
1
+ require 'rouge'
2
+
3
+ module Pyggish
4
+ def self.pyg_change(code, klass, style)
5
+ color = style[0..6]
6
+ modifier = style[8]
7
+ mod_open = modifier ? "<#{modifier}>" : ""
8
+ mod_close = modifier ? "</#{modifier}>" : ""
9
+ rx = /<span class="#{klass}">(?<cname>[^<]+?)<\/span>/
10
+ loop do
11
+ md = rx.match(code)
12
+ break if md.nil?
13
+ str = md[:cname]
14
+ result = code.sub!(rx, "<font color=#{color}>#{mod_open}#{str}#{mod_close}</font>")
15
+ break if result.nil?
16
+ end
17
+ end
18
+
19
+ def self._codebar_color(lexer)
20
+ color = case lexer
21
+ when :elixir
22
+ "#fc88fc"
23
+ when :ruby
24
+ "#fc8888"
25
+ else
26
+ raise "Unknown lexer"
27
+ end
28
+ end
29
+
30
+ def self.pyg_finalize(code, lexer=:elixir)
31
+ Styles.each_pair {|klass, style| pyg_change(code, klass, style) }
32
+ File.open("debug-pf1", "w") {|f| f.puts code }
33
+ code.sub!(/<pre>/, "<pre>\n")
34
+ code.gsub!(/<span class="[np]">/, "")
35
+ code.gsub!(/<\/span>/, "")
36
+ color = _codebar_color(lexer)
37
+ code.sub!(/<td class="linenos"/, "<td width=2%></td><td width=5% bgcolor=#{color}")
38
+ code.gsub!(/<td/, "<td valign=top ")
39
+ code.gsub!(/ class="[^"]*?"/, "") # Get rid of remaining Pygments CSS
40
+ File.open("debug-pf2", "w") {|f| f.puts code }
41
+ lines = code.split("\n")
42
+ # lines.each {|line| line << "\n" }
43
+ n1 = lines.index {|x| x =~ /<pre>/ }
44
+ n2 = lines.index {|x| x =~ /<\/pre>/ }
45
+ # FIXME ?
46
+ n1 ||= 0
47
+ n2 ||= -1
48
+ lines[n1].sub!(/ 1$/, " 1 ")
49
+ (n1+1).upto(n2) {|n| lines[n].replace(" " + lines[n] + " ") }
50
+ code = lines.join("\n")
51
+ File.open("debug-pf3", "w") {|f| f.puts code }
52
+ code
53
+ end
54
+
55
+ def _process_code(text)
56
+ File.open("debug-pc1", "w") {|f| f.puts text }
57
+ lines = text.split("\n")
58
+ lines = lines.select {|x| x !~ /##~ omit/ }
59
+ @refs = {}
60
+ lines.each.with_index do |line, i|
61
+ if line =~ /##~ ref/
62
+ frag, name = line.split(/ *##~ ref/)
63
+ @refs[name.strip] = i
64
+ line.replace(frag)
65
+ end
66
+ end
67
+ lines.map! {|line| " " + line }
68
+ text2 = lines.join("\n")
69
+ File.open("debug-pc2", "w") {|f| f.puts text2 }
70
+ text.replace(text2)
71
+ end
72
+
73
+ def _colorize(code, lexer=:elixir)
74
+ text = ::Pygments.highlight(code, lexer: lexer, options: {linenos: "table"})
75
+ _debug "--- in _colorize: text = #{text.inspect}"
76
+ text2 = PygmentFix.pyg_finalize(text, lexer)
77
+ result = "<!-- colorized code -->\n" + text2
78
+ result
79
+ end
80
+
81
+ def _colorize!(code, lexer=:elixir)
82
+ text = ::Pygments.highlight(code, lexer: lexer, options: {})
83
+ _debug "--- in _colorize!: text = #{text.inspect}"
84
+ text2 = PygmentFix.pyg_finalize(text, lexer)
85
+ result = "<!-- colorized code -->\n" + text2
86
+ result
87
+ end
88
+
89
+ def OLD_ruby
90
+ file = @_args.first
91
+ if file.nil?
92
+ code = "# Ruby code\n"
93
+ _body {|line| code << line + "\n" }
94
+ else
95
+ code = "# Ruby code\n\n" + ::File.read(file)
96
+ end
97
+
98
+ _process_code(code)
99
+ html = _colorize(code, :ruby)
100
+ _out "\n#{html}\n "
101
+ end
102
+
103
+ def OLD_elixir
104
+ file = @_args.first
105
+ if file.nil?
106
+ code = ""
107
+ _body {|line| code << line + "\n" }
108
+ else
109
+ code = ::File.read(file)
110
+ end
111
+
112
+ _process_code(code)
113
+ html = _colorize(code, :elixir)
114
+ _out "\n#{html}\n "
115
+ end
116
+
117
+ def fragment
118
+ lang = @_args.empty? ? :elixir : @_args.first.to_sym # ruby or elixir
119
+ @_args = []
120
+ send(lang)
121
+ _out "\n"
122
+ end
123
+
124
+ def code # FIXME ?
125
+ text = ""
126
+ _body {|line| _out " " + line }
127
+ end
128
+
129
+ def mono
130
+ _out "<pre>"
131
+ _body {|line| _out " " + line }
132
+ _out "</pre>"
133
+ end
134
+
135
+ def create_code_styles
136
+ dir = @_outdir || "."
137
+ theme, back = "Github", "white"
138
+ css = Rouge::Themes.const_get(theme).render(scope: '.rb_highlight')
139
+ added = <<~CSS
140
+ .rb_highlight {
141
+ font-family: 'Monaco', 'Andale Mono', 'Lucida Grande', 'Courier', 'Lucida Console', 'Courier New', monospace;
142
+ white-space: pre;
143
+ background-color: #{back}
144
+ }
145
+ CSS
146
+
147
+ css.gsub!(/{\n/, "{\n font-family: courier;")
148
+ css = added + "\n" + css
149
+ # STDERR.puts "Writing #{theme} theme to ruby.css"
150
+ File.write("#{dir}/ruby.css", css)
151
+
152
+ css = Rouge::Themes.const_get(theme).render(scope: '.ex_highlight')
153
+ added = added.sub(/rb/, "ex")
154
+ css.gsub!(/{\n/, "{\n font-family: courier;")
155
+ css = added + "\n" + css
156
+ # STDERR.puts "Writing #{theme} theme to elixir.css"
157
+ File.write("#{dir}/elixir.css", css)
158
+ end
159
+
160
+
161
+ def format_ruby(source, theme = "Github", back = "black")
162
+ # theme/back not used now
163
+ formatter = Rouge::Formatters::HTML.new
164
+ lexer = Rouge::Lexers::Ruby.new
165
+ body = formatter.format(lexer.lex(source))
166
+ text = "<div class=rb_highlight>#{body}</div>"
167
+ text
168
+ end
169
+
170
+ def format_elixir(source, theme = "Github", back = "black")
171
+ # theme/back not used now
172
+ formatter = Rouge::Formatters::HTML.new
173
+ lexer = Rouge::Lexers::Elixir.new
174
+ body = formatter.format(lexer.lex(source))
175
+ text = "<div class=ex_highlight>#{body}</div>"
176
+ text
177
+ end
178
+
179
+ def ruby
180
+ file = @_args.first
181
+ if file.nil?
182
+ code = " # Ruby code\n\n"
183
+ _body {|line| code << " " + line + "\n" }
184
+ else
185
+ code = "# Ruby code\n\n" + ::File.read(file)
186
+ end
187
+
188
+ html = format_ruby(code)
189
+ _out html
190
+ end
191
+
192
+ def elixir
193
+ file = @_args.first
194
+ if file.nil?
195
+ code = ""
196
+ _body {|line| code << " " + line + "\n" }
197
+ else
198
+ code = ::File.read(file)
199
+ end
200
+
201
+ html = format_elixir(code)
202
+ _out html
203
+ end
204
+ end
@@ -0,0 +1,95 @@
1
+ # require 'cgi'
2
+
3
+ require 'helpers'
4
+
5
+ module Tutorial
6
+ include Helpers
7
+
8
+ def title(args = nil, body = nil)
9
+ h1
10
+ _optional_blank_line
11
+ end
12
+
13
+ def section(args = nil, body = nil)
14
+ h3
15
+ _optional_blank_line
16
+ end
17
+
18
+ def code(args = nil, body = nil)
19
+ first = true # dumb hack! fixes blank space
20
+ _body do |line|
21
+ tag, first = "<pre>", false if first
22
+ _out "#{tag} #{escape_html(line)}" # indentation
23
+ end
24
+ _out "</pre>"
25
+ _optional_blank_line
26
+ end
27
+
28
+ def rx(str)
29
+ ::Regexp.compile(::Regexp.escape(str))
30
+ end
31
+
32
+ def inout(args = nil, body = nil)
33
+ src, out = _args
34
+ t1 = ::File.readlines(src) rescue (abort "t1 = #{src}")
35
+ t2 = ::File.readlines(out) rescue (abort "t2 = #{out}")
36
+ # To pacify markdown for README (FIXME later)
37
+ t1 = t1.map {|x| " " + x.sub(/ +$/,"").gsub(/_/, "\\_") }.join
38
+ t2 = t2.map {|x| " " + x.sub(/ +$/,"").gsub(/_/, "\\_") }.join
39
+
40
+ _out <<-HTML
41
+ <table width=80% cellpadding=4>
42
+ <tr>
43
+ <td width=50%><b>Input</b></td>
44
+ <td width=50%><b>Output</b></td>
45
+ </tr>
46
+ <tr>
47
+ <td width=50% bgcolor=#fee0fe valign=top>
48
+ <pre>#{t1}</pre>
49
+ </td>
50
+ <td width=50% bgcolor=#eeeeee valign=top>
51
+ <pre>#{t2}</pre>
52
+ </td>
53
+ </tr>
54
+ </table>
55
+ HTML
56
+ _optional_blank_line
57
+ end
58
+
59
+ def put_table(src, exp)
60
+ t1 = ::File.readlines(src) rescue (abort "t1 = #{src}")
61
+ t2 = ::File.readlines(exp) rescue (abort "t2 = #{out}")
62
+ t1 = t1.map {|x| " " + x.sub(/ +$/,"").gsub(/_/, "\\_") }.join
63
+ t2 = t2.map {|x| " " + x.sub(/ +$/,"").gsub(/_/, "\\_") }.join
64
+
65
+ _out <<-HTML
66
+ <font size=+1>
67
+ <table width=80% cellpadding=4>
68
+ <tr>
69
+ <td width=50%><b>Input</b></td>
70
+ <td width=50%><b>Output</b></td>
71
+ </tr>
72
+ <tr>
73
+ <td width=50% bgcolor=#fee0fe valign=top>
74
+ <pre>#{t1}</pre>
75
+ </td>
76
+ <td width=50% bgcolor=#eeeeee valign=top>
77
+ <pre>#{t2}</pre>
78
+ </td>
79
+ </tr>
80
+ </table>
81
+ </font>
82
+ HTML
83
+ end
84
+
85
+ def testcase(args = nil, body = nil)
86
+ name = _args.first
87
+ _out "\n<font size=+1><b>Test: </font><font size=+2><tt>#{name}</tt></font></b></h3><br>"
88
+ src, exp = "test/snapshots/#{name}/source.lt3", "test/snapshots/#{name}/expected-output.txt"
89
+ @_args = [src, exp] # Better way to do this??
90
+ put_table(src, exp)
91
+ _out "<br>"
92
+ _optional_blank_line
93
+ end
94
+ end
95
+
data/lib/cmdargs.rb CHANGED
@@ -4,44 +4,53 @@ require_relative 'livetext'
4
4
  Weird concepts to understand here...
5
5
 
6
6
  1. A Livetext dot-command (flush left) usually looks like:
7
- .foobar
7
+ .foobar
8
+
8
9
  2. A dot-command (left-indented) usually looks like:
9
- $.foobar
10
+ $.foobar
11
+
10
12
  3. More generally, it may have any number of parameters (0, 1, ...)
11
- .redirect somefile.txt append
13
+ .redirect somefile.txt append
14
+
12
15
  4. Variables and functions *can* appear (rare in practice??)
13
- .redirect somefile$my_suffix $$my_mode
16
+ .redirect somefile$my_suffix $$my_mode
17
+
14
18
  5. A trailing # comment may appear
15
19
  a. Stripped... saved in #raw ? #data ? #comment ? elsewhere?
16
20
  b. NOT the "dot" as a comment!
21
+
17
22
  6. .foobar # This here is a comment
23
+
18
24
  7. #data accessor returns all data on the .foo line...
19
25
  a. ...After the initial space
20
- b. ...Including spaces
26
+ b. ...Including later spaces
21
27
  c. Including comment??
22
28
  d. .foo This is o n l y a test.
23
29
  # #data returns: "This is o n l y a test."
24
30
  e. What about formatting???
25
31
  f. What about: comments? variables? functions?
26
32
 
27
- 7. Some commands have NO body while others have an OPTIONAL or REQUIRED body
33
+ 8. Some commands have NO body while others have an OPTIONAL or REQUIRED body
28
34
  a. Assume .cmd1 definition forbids a body (then a body is an error)
29
35
  .cmd1 # may NOT have a body
30
36
  b. Assume .cmd2 definition PERMITS a body
31
37
  .cmd2 # may or MAY NOT have body/.end
32
- c. Assume .cmd3 definition PERMITS a body
38
+ c. Assume .cmd3 definition REQUIRES a body
33
39
  .cmd3 # REQUIRES a body/.end
34
40
  . stuff...
35
41
  .end
36
- 8. Inside a body:
37
- 8a. Leading dot has no special meaning (though the associated method may parse it!)
38
- 8b. BUG? Currently leading dot is a comment INSIDE a body?
39
- 8a. No leading char is special (though the associated method may parse it!)
40
- 8a. No trailing #-comments (though the associated method may parse it!)
41
- 8c. ?? We should or shouldn't look for variables/functions? or make it an option?
42
- 8d. .end may naturally not be used (but see .raw where it may)
43
- 9. the args accessor is a simple array of strings
44
42
 
43
+ 9. Inside a body:
44
+ a. Leading dot has no special meaning (though the associated method may parse it!)
45
+ b. BUG? Currently leading dot is a comment INSIDE a body?
46
+ c. No leading char is special (though the associated method may parse it!)
47
+ d. No trailing #-comments (though the associated method may parse it!)
48
+ e. ?? We should or shouldn't look for variables/functions? or make it an option?
49
+ f. .end may naturally not be used (but see .raw where it may)
50
+
51
+ 10. The args accessor is a simple array of strings
52
+ a. there is also raw_args (without variables/functions, etc.)
53
+ b. Much of this HAS NOT been thought through yet!
45
54
 
46
55
  =end
47
56
 
@@ -64,11 +73,11 @@ class Livetext::CmdData
64
73
  @nargs = nargs # not really "needed"
65
74
  check_num_args(nargs)
66
75
 
67
- # @varfunc = _var_func_parse(data.dup)
76
+ # @varfunc = Livetext.interpolate(data.dup)
68
77
  end
69
78
 
70
79
  def check_num_args(num)
71
- num_range = /(\d{0,2})(\.\.)(\d{0,2})/
80
+ num_range = /(\d{0,2})(\.\.)(\d{0,2})/ # Not "really" right...
72
81
  min, max = 0, 9999
73
82
  md = num_range.match(@nargs).to_a
74
83
  bad_args = nil
data/lib/formatline.rb CHANGED
@@ -52,7 +52,7 @@ class FormatLine < StringParser
52
52
  marker peek
53
53
  add peek
54
54
  when LF
55
- break if @i >= line.size - 1
55
+ break if eos? # @i >= line.size - 1
56
56
  when nil
57
57
  break
58
58
  else
@@ -117,11 +117,11 @@ class FormatLine < StringParser
117
117
  if [:colon, :brackets].include? arg[0]
118
118
  arg = gen.next # for real
119
119
  param = arg[1]
120
- param = FormatLine.var_func_parse(param)
120
+ param = Livetext.interpolate(param)
121
121
  end
122
122
  @out << funcall(val, param)
123
123
  when :b, :i, :t, :s
124
- val = FormatLine.var_func_parse(val)
124
+ val = Livetext.interpolate(val)
125
125
  @out << embed(sym, val)
126
126
  else
127
127
  add_token :str
@@ -199,7 +199,7 @@ class FormatLine < StringParser
199
199
  str = Null.dup
200
200
  grab
201
201
  loop do
202
- break if eos? # peek.nil?
202
+ break if peek.nil? # eos?
203
203
  str << peek
204
204
  break if terminate?(NoAlphaDot, next!)
205
205
  grab
@@ -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
@@ -4,6 +4,40 @@ module Helpers
4
4
  Space = " "
5
5
  Sigil = "." # Can't change yet
6
6
 
7
+ ESCAPING = { "'" => '&#39;', '&' => '&amp;', '"' => '&quot;',
8
+ '<' => '&lt;', '>' => '&gt;' }
9
+
10
+ def escape_html(string)
11
+ enc = string.encoding
12
+ unless enc.ascii_compatible?
13
+ if enc.dummy?
14
+ origenc = enc
15
+ enc = Encoding::Converter.asciicompat_encoding(enc)
16
+ string = enc ? string.encode(enc) : string.b
17
+ end
18
+ table = Hash[ESCAPING.map {|pair|pair.map {|s|s.encode(enc)}}]
19
+ string = string.gsub(/#{"['&\"<>]".encode(enc)}/, table)
20
+ string.encode!(origenc) if origenc
21
+ return string
22
+ end
23
+ string.gsub(/['&\"<>]/, ESCAPING)
24
+ end
25
+
26
+ def find_file(name, ext=".rb")
27
+ paths = [Livetext::Path.sub(/lib/, "imports/"), "./"]
28
+ base = "#{name}#{ext}"
29
+ paths.each do |path|
30
+ file = path + base
31
+ return file if File.exist?(file)
32
+ end
33
+
34
+ raise "No such mixin '#{name}'"
35
+
36
+ # # Really want to search upward??
37
+ # raise "No such mixin '#{name}'" if cwd_root?
38
+ # Dir.chdir("..") { find_file(name) }
39
+ end
40
+
7
41
  def self.rx(str, space=nil)
8
42
  Regexp.compile("^" + Regexp.escape(str) + "#{space}")
9
43
  end
@@ -30,7 +64,7 @@ module Helpers
30
64
  @body
31
65
  end
32
66
 
33
- def process_line(line) # FIXME inefficient?
67
+ def process_line(line)
34
68
  nomarkup = true
35
69
  case line # must apply these in order
36
70
  when Comment
@@ -59,6 +93,29 @@ module Helpers
59
93
  raise EndWithoutOpening()
60
94
  when @main.respond_to?(name)
61
95
  result = @main.send(name)
96
+
97
+ # NOTE: The above line is where the magic happens!
98
+ # A name like 'foobar' results in an invocation of
99
+ # @main.foobar (where @main is a Processor, and any
100
+ # new methods (e.g. from a mixin) are added to @main
101
+ #
102
+ # So all the functionality from _args and _raw_args
103
+ # and _data (among others?) will be encapsulated in
104
+ # 'some' kind of PORO which handles access to all
105
+ # these things as well as the 'body' between the
106
+ # command and its corresponding .end
107
+ #
108
+ # The 'body' functionality is so commonly used, I plan
109
+ # to pass it in separately as needed (even though the
110
+ # args object should make it available also).
111
+ #
112
+ # Every method corresponding to a dot commmand will
113
+ # get args and body passed in as needed. Every one of
114
+ # the signatures already has (args = nil, body = nil)
115
+ # but nothing is being passed in that way yet.
116
+ #
117
+ # Refer to lib/cmdargs.rb for more! This is *strictly*
118
+ # experimental and a "work in progress."
62
119
  else
63
120
  puts @body # earlier correct output, not flushed yet
64
121
  raise "Name '#{name}' is unknown"
@@ -74,8 +131,8 @@ module Helpers
74
131
  name, data = line.split(" ", 2)
75
132
  name = name[1..-1] # chop off sigil
76
133
  name = "dot_" + name if %w[include def].include?(name)
77
- @main.data = data
78
134
  @main.check_disallowed(name)
135
+ @main.data = data
79
136
  name
80
137
  end
81
138
 
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.15"
4
+ VERSION = "0.9.21"
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
@@ -16,8 +19,10 @@ require_relative 'standard'
16
19
  require_relative 'formatline'
17
20
  require_relative 'processor'
18
21
  require_relative 'helpers'
22
+ require_relative 'handler'
19
23
 
20
24
  Plugins = File.expand_path(File.join(File.dirname(__FILE__), "../plugin"))
25
+ Imports = File.expand_path(File.join(File.dirname(__FILE__), "../imports"))
21
26
 
22
27
  TTY = ::File.open("/dev/tty", "w")
23
28
 
@@ -27,7 +27,7 @@ class Livetext::ParseGeneral < StringParser
27
27
  lines.each do |line|
28
28
  next if line.strip.empty?
29
29
  var, value = line.split(" ", 2)
30
- val = FormatLine.var_func_parse(value)
30
+ val = Livetext.interpolate(value)
31
31
  var = prefix + "." + var if prefix
32
32
  pairs << [var, value]
33
33
  end
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
- # FIXME probably belongs elsewhere?
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
@@ -2,13 +2,9 @@ require_relative '../livetext'
2
2
  require_relative '../helpers'
3
3
  require_relative 'string'
4
4
 
5
- make_exception(:BadVariableName, "Error: invalid variable name")
6
5
  make_exception(:NoEqualSign, "Error: no equal sign found")
7
6
 
8
- # FIXME probably belongs elsewhere?
9
-
10
- class Livetext::ParseMixin # < StringParser
11
-
7
+ class Livetext::ParseMixin
12
8
  include Helpers
13
9
 
14
10
  def initialize(name)
@@ -37,17 +33,6 @@ class Livetext::ParseMixin # < StringParser
37
33
  File.dirname(File.expand_path(".")) == "/"
38
34
  end
39
35
 
40
- def find_file(name, ext=".rb")
41
- base = "./#{name}#{ext}"
42
- file = "#{Plugins}/#{base}"
43
- return file if File.exist?(file)
44
-
45
- file = base
46
- return file if File.exist?(file)
47
-
48
- raise "No such mixin '#{name}'" if cwd_root?
49
- Dir.chdir("..") { find_file(name) }
50
- end
51
36
 
52
37
  end
53
38
 
data/lib/parser/set.rb CHANGED
@@ -31,8 +31,8 @@ class Livetext::ParseSet < StringParser
31
31
  pairs = []
32
32
  char = nil
33
33
  loop do
34
- break if eos? # end of string
35
34
  char = skip_spaces
35
+ break if eos? # end of string
36
36
  raise "Expected alpha to start var name" unless char =~ /[a-z]/i
37
37
  pairs << assignment
38
38
  char = skip_spaces
@@ -56,7 +56,7 @@ class Livetext::ParseSet < StringParser
56
56
  var = get_var
57
57
  skip_equal
58
58
  value = get_value
59
- value = FormatLine.var_func_parse(value) # FIXME broken now?
59
+ value = Livetext.interpolate(value)
60
60
  pair = [var, value]
61
61
  pair
62
62
  end
data/lib/parser/string.rb CHANGED
@@ -15,12 +15,13 @@ class StringParser
15
15
  return nil if @eos
16
16
  char = @line[@i]
17
17
  @i += 1
18
- @eos = true if @i > @len
18
+ check_eos
19
19
  char
20
20
  end
21
21
 
22
22
  def ungrab
23
- @i -= 1 # FIXME what about eos...?
23
+ @i -= 1
24
+ check_eos
24
25
  end
25
26
 
26
27
  def next!
@@ -32,12 +33,7 @@ class StringParser
32
33
  @line[@i-1]
33
34
  end
34
35
 
35
- def last?
36
- @i > @len - 1
37
- end
38
-
39
36
  def eos?
40
- @eos = true if last? # duh?
41
37
  @eos
42
38
  end
43
39
 
@@ -52,11 +48,16 @@ class StringParser
52
48
  char = peek
53
49
  break if eos?
54
50
  break if char != " "
55
- grab
51
+ char = grab
56
52
  end
57
53
  char
58
54
  end
59
55
 
56
+ private
57
+
58
+ def check_eos
59
+ @eos = @i >= @len
60
+ end
60
61
  end
61
62
 
62
63
  =begin