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.
Files changed (110) hide show
  1. checksums.yaml +4 -4
  2. data/README.lt3 +2 -2
  3. data/imports/bookish.rb +288 -0
  4. data/imports/calibre.rb +28 -0
  5. data/imports/livemagick.rb +133 -0
  6. data/imports/markdown.rb +44 -0
  7. data/imports/markdown_importable.rb +46 -0
  8. data/imports/pyggish.rb +204 -0
  9. data/imports/tutorial.rb +95 -0
  10. data/lib/cmdargs.rb +93 -0
  11. data/lib/errors.rb +4 -2
  12. data/lib/formatline.rb +56 -83
  13. data/lib/functions.rb +1 -1
  14. data/lib/handler/icanhaz.rb +35 -0
  15. data/lib/handler.rb +1 -0
  16. data/lib/helpers.rb +177 -4
  17. data/lib/livetext.rb +20 -139
  18. data/lib/parser/file.rb +8 -0
  19. data/lib/parser/general.rb +1 -1
  20. data/lib/parser/import.rb +1 -3
  21. data/lib/parser/mixin.rb +22 -30
  22. data/lib/parser/set.rb +35 -26
  23. data/lib/parser/string.rb +19 -4
  24. data/lib/processor.rb +2 -12
  25. data/lib/standard.rb +73 -107
  26. data/lib/userapi.rb +1 -4
  27. data/livetext.gemspec +2 -1
  28. data/plugin/bookish.rb +26 -22
  29. data/plugin/calibre.rb +1 -1
  30. data/plugin/livemagick.rb +10 -10
  31. data/plugin/markdown.rb +13 -11
  32. data/plugin/pyggish.rb +94 -84
  33. data/plugin/tutorial.rb +10 -5
  34. data/test/snapshots/OMIT.txt +11 -0
  35. data/test/snapshots/clusion.txt +84 -0
  36. data/test/snapshots/error_inc_line_num/match-error.txt +1 -0
  37. data/test/snapshots/error_invalid_name/match-error.txt +1 -0
  38. data/test/snapshots/error_line_num/match-error.txt +1 -0
  39. data/test/snapshots/error_mismatched_end/expected-output.txt +0 -2
  40. data/test/snapshots/error_mismatched_end/match-error.txt +1 -0
  41. data/test/snapshots/error_missing_end/match-error.txt +1 -0
  42. data/test/snapshots/error_no_such_copy/match-error.txt +1 -0
  43. data/test/snapshots/error_no_such_copy/source.lt3 +0 -1
  44. data/test/snapshots/error_no_such_inc/match-error.txt +1 -0
  45. data/test/snapshots/error_no_such_mixin/match-error.txt +1 -0
  46. data/test/snapshots/icanhaz/expected-output.txt +5 -0
  47. data/test/snapshots/icanhaz/match-error.txt +1 -0
  48. data/test/snapshots/icanhaz/simple_import.rb +5 -0
  49. data/test/snapshots/{error_no_such_mixin/actual-output.txt → icanhaz/source.lt3} +3 -4
  50. data/test/snapshots/{error_invalid_name/actual-output.txt → icanhaz2/expected-error.txt} +0 -0
  51. data/test/snapshots/icanhaz2/expected-output.txt +6 -0
  52. data/test/snapshots/icanhaz2/simple_canhaz.rb +5 -0
  53. data/test/snapshots/icanhaz2/source.lt3 +6 -0
  54. data/test/snapshots/predef_vars/match-output.txt +6 -0
  55. data/test/snapshots/{error_no_such_copy/actual-output.txt → simple_import/expected-error.txt} +0 -0
  56. data/test/snapshots/simple_import/expected-output.txt +7 -0
  57. data/test/snapshots/simple_import/simple_import.rb +5 -0
  58. data/test/snapshots/simple_import/source.lt3 +7 -0
  59. data/test/snapshots/simple_include/source.lt3 +0 -1
  60. data/test/snapshots.rb +103 -107
  61. data/test/unit/all.rb +1 -0
  62. data/test/unit/formatline.rb +650 -0
  63. data/test/unit/parser/general.rb +21 -21
  64. data/test/unit/parser/importable.rb +1 -1
  65. data/test/unit/parser/mixin.rb +2 -2
  66. data/test/unit/parser/set.rb +19 -12
  67. data/test/unit/parser/string.rb +14 -14
  68. data/test/unit/parser.rb +2 -0
  69. metadata +37 -46
  70. data/test/formatting.rb +0 -103
  71. data/test/snapshots/error_inc_line_num/actual-error.txt +0 -1
  72. data/test/snapshots/error_inc_line_num/actual-output.txt +0 -13
  73. data/test/snapshots/error_inc_line_num/expected-err-line1match.txt +0 -1
  74. data/test/snapshots/error_inc_line_num/out-sdiff.txt +0 -14
  75. data/test/snapshots/error_invalid_name/actual-error.txt +0 -10
  76. data/test/snapshots/error_invalid_name/expected-err-line1match.txt +0 -1
  77. data/test/snapshots/error_invalid_name/out-sdiff.txt +0 -6
  78. data/test/snapshots/error_line_num/actual-error.txt +0 -1
  79. data/test/snapshots/error_line_num/actual-output.txt +0 -5
  80. data/test/snapshots/error_line_num/expected-err-line1match.txt +0 -1
  81. data/test/snapshots/error_line_num/out-sdiff.txt +0 -6
  82. data/test/snapshots/error_mismatched_end/actual-error.txt +0 -1
  83. data/test/snapshots/error_mismatched_end/actual-output.txt +0 -8
  84. data/test/snapshots/error_mismatched_end/expected-err-line1match.txt +0 -1
  85. data/test/snapshots/error_mismatched_end/out-sdiff.txt +0 -9
  86. data/test/snapshots/error_missing_end/actual-error.txt +0 -1
  87. data/test/snapshots/error_missing_end/actual-output.txt +0 -5
  88. data/test/snapshots/error_missing_end/expected-err-line1match.txt +0 -1
  89. data/test/snapshots/error_missing_end/out-sdiff.txt +0 -6
  90. data/test/snapshots/error_name_not_permitted/OLD-exp-out +0 -4
  91. data/test/snapshots/error_no_such_copy/actual-error.txt +0 -10
  92. data/test/snapshots/error_no_such_copy/expected-err-line1match.txt +0 -1
  93. data/test/snapshots/error_no_such_copy/out-sdiff.txt +0 -5
  94. data/test/snapshots/error_no_such_inc/actual-error.txt +0 -10
  95. data/test/snapshots/error_no_such_inc/actual-output.txt +0 -0
  96. data/test/snapshots/error_no_such_inc/expected-err-line1match.txt +0 -1
  97. data/test/snapshots/error_no_such_inc/out-sdiff.txt +0 -6
  98. data/test/snapshots/error_no_such_mixin/actual-error.txt +0 -1
  99. data/test/snapshots/error_no_such_mixin/expected-err-line1match.txt +0 -1
  100. data/test/snapshots/error_no_such_mixin/out-sdiff.txt +0 -12
  101. data/test/snapshots/lines.txt +0 -124
  102. data/test/snapshots/predef_vars/actual-error.txt +0 -0
  103. data/test/snapshots/predef_vars/actual-output.txt +0 -6
  104. data/test/snapshots/predef_vars/expected-output.txt +0 -6
  105. data/test/snapshots/predef_vars/out-sdiff.txt +0 -7
  106. data/test/snapshots/simple_mixin/actual-error.txt +0 -2
  107. data/test/snapshots/simple_mixin/actual-output.txt +0 -4
  108. data/test/snapshots/simple_mixin/out-sdiff.txt +0 -6
  109. data/test/unit/parse_misc.rb +0 -60
  110. data/test/unit/parse_set.rb +0 -157
data/lib/functions.rb CHANGED
@@ -1,5 +1,5 @@
1
1
 
2
- require_relative 'standard' # FIXME?
2
+ require_relative 'standard' # FIXME umm, why is this necessary??
3
3
 
4
4
  # Class Functions is where '$$func' functions are stored dynamically...
5
5
  # user-def AND pre-def??
@@ -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
- # raise "Illegal name '#{name}'" if _disallowed?(name)
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._setvar(var, value)
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.13"
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
- Vars = {}
28
-
29
- Space = " "
30
- Sigil = "." # Can't change yet
35
+ include Helpers
31
36
 
32
- def self.rx(str, space=nil)
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._setvar(var, val.to_s) }
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| _setvar(var, val.to_s) }
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 _get_arg(name, args) # really belongs in livetext
100
- raise "(#{name}) Expected an array" unless args.is_a? Array
101
- raise "(#{name}) Expected an arg" if args.empty?
102
- raise "(#{name}) Too many args: #{args.inspect}" if args.size > 1
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
- _setfile!("(string)")
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
 
@@ -0,0 +1,8 @@
1
+
2
+ require_relative '../livetext'
3
+
4
+ # Hmm. not today?
5
+
6
+ class Livetext::ParseFile
7
+
8
+ end
@@ -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::ParseMisc < StringParser
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
- # 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
@@ -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
- # FIXME probably belongs elsewhere?
7
+ class Livetext::ParseMixin
8
+ include Helpers
8
9
 
9
- class Livetext::ParseMixin # < StringParser
10
-
11
- # def self.parse(str)
12
- # self.new(str).parse
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 cwd_root?
20
- File.dirname(File.expand_path(".")) == "/"
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 find_mixin(name)
24
- file = "#{Plugins}/" + name.downcase + ".rb"
25
- return file if File.exist?(file)
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
- file = "./#{name}.rb"
28
- return file if File.exist?(file)
30
+ private
29
31
 
30
- raise "No such mixin '#{name}'" if cwd_root?
31
- Dir.chdir("..") { find_mixin(name) }
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
- self.next # skip comma
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 = self.peek
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 << self.next
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 self.peek == "="
85
+ raise NoEqualSign unless peek == "="
77
86
  found = true
78
- self.next # skip =... spaces too
79
- self.skip_spaces
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
- self.next # skip backslash
89
- self.next # return following char
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 = self.next # opening quote...
103
+ quote = grab # opening quote...
96
104
  value = ""
97
105
  char = nil
98
106
  loop do
99
- char = self.peek
100
- break if self.eos?
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 = self.next
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
- # puts "#{__method__}: #{@line.inspect} i = #@i peek = #{self.peek.inspect}"
122
+ char = nil
115
123
  value = ""
116
124
  loop do
117
- char = self.peek
118
- break if self.eos?
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 = self.next
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 = self.peek
132
- value = quote?(char) ? quoted_value : unquoted_value
140
+ char = peek
141
+ value = quote?(char) ? quoted_value : unquoted_value
133
142
  value
134
143
  end
135
144
  end