livetext 0.9.10 → 0.9.15

Sign up to get free protection for your applications and to get access to all the features.
Files changed (177) hide show
  1. checksums.yaml +4 -4
  2. data/lib/cmdargs.rb +93 -0
  3. data/lib/errors.rb +15 -0
  4. data/lib/formatline.rb +59 -88
  5. data/lib/functions.rb +6 -2
  6. data/lib/helpers.rb +163 -0
  7. data/lib/html.rb +32 -0
  8. data/lib/livetext/importable.rb +2 -0
  9. data/lib/livetext.rb +30 -148
  10. data/lib/parser/file.rb +8 -0
  11. data/lib/parser/general.rb +38 -0
  12. data/lib/parser/import.rb +17 -0
  13. data/lib/parser/mixin.rb +53 -0
  14. data/lib/parser/set.rb +145 -0
  15. data/lib/parser/string.rb +70 -0
  16. data/lib/parser.rb +5 -0
  17. data/lib/processor.rb +23 -27
  18. data/lib/standard.rb +155 -348
  19. data/lib/userapi.rb +2 -5
  20. data/livetext.gemspec +1 -2
  21. data/plugin/bookish.rb +26 -22
  22. data/plugin/calibre.rb +1 -1
  23. data/plugin/livemagick.rb +10 -10
  24. data/plugin/markdown.rb +13 -11
  25. data/plugin/pyggish.rb +94 -84
  26. data/plugin/tutorial.rb +10 -5
  27. data/test/all.rb +3 -0
  28. data/test/snapshots/OMIT.txt +9 -0
  29. data/test/{data → snapshots}/basic_formatting/expected-error.txt +0 -0
  30. data/test/{data → snapshots}/basic_formatting/expected-output.txt +0 -0
  31. data/test/{data → snapshots}/basic_formatting/source.lt3 +0 -0
  32. data/test/{data → snapshots}/block_comment/expected-error.txt +0 -0
  33. data/test/{data → snapshots}/block_comment/expected-output.txt +0 -0
  34. data/test/{data → snapshots}/block_comment/source.lt3 +0 -0
  35. data/test/snapshots/clusion.txt +35 -0
  36. data/test/{data → snapshots}/comments_ignored_1/expected-error.txt +0 -0
  37. data/test/{data → snapshots}/comments_ignored_1/expected-output.txt +0 -0
  38. data/test/{data → snapshots}/comments_ignored_1/source.lt3 +0 -0
  39. data/test/{data → snapshots}/copy_is_raw/expected-error.txt +0 -0
  40. data/test/{data → snapshots}/copy_is_raw/expected-output.txt +0 -0
  41. data/test/{data → snapshots}/copy_is_raw/rawtext.inc +0 -0
  42. data/test/{data → snapshots}/copy_is_raw/source.lt3 +0 -0
  43. data/test/{data → snapshots}/crap +0 -0
  44. data/test/{data → snapshots}/def_method/expected-error.txt +0 -0
  45. data/test/{data → snapshots}/def_method/expected-output.txt +0 -0
  46. data/test/{data → snapshots}/def_method/source.lt3 +0 -0
  47. data/test/snapshots/error_inc_line_num/actual-error.txt +14 -0
  48. data/test/{data/error_inc_line_num/expected-output.txt → snapshots/error_inc_line_num/actual-output.txt} +0 -0
  49. data/test/snapshots/error_inc_line_num/expected-output.txt +13 -0
  50. data/test/{data → snapshots}/error_inc_line_num/file2.lt3 +0 -0
  51. data/test/snapshots/error_inc_line_num/match-error.txt +1 -0
  52. data/test/snapshots/error_inc_line_num/out-sdiff.txt +14 -0
  53. data/test/{data → snapshots}/error_inc_line_num/source.lt3 +0 -0
  54. data/test/snapshots/error_invalid_name/actual-error.txt +10 -0
  55. data/test/{data/error_no_such_mixin/expected-output.txt → snapshots/error_invalid_name/actual-output.txt} +0 -0
  56. data/test/{data → snapshots}/error_invalid_name/expected-output.txt +0 -0
  57. data/test/snapshots/error_invalid_name/match-error.txt +1 -0
  58. data/test/snapshots/error_invalid_name/out-sdiff.txt +6 -0
  59. data/test/{data → snapshots}/error_invalid_name/source.lt3 +0 -0
  60. data/test/{data → snapshots}/error_line_num/expected-output.txt +0 -0
  61. data/test/snapshots/error_line_num/match-error.txt +1 -0
  62. data/test/{data → snapshots}/error_line_num/source.lt3 +0 -0
  63. data/test/{data → snapshots}/error_mismatched_end/expected-output.txt +0 -0
  64. data/test/snapshots/error_mismatched_end/match-error.txt +1 -0
  65. data/test/{data → snapshots}/error_mismatched_end/source.lt3 +0 -0
  66. data/test/snapshots/error_missing_end/actual-error.txt +10 -0
  67. data/test/{data/example_alpha/expected-error.txt → snapshots/error_missing_end/actual-output.txt} +0 -0
  68. data/test/{data → snapshots}/error_missing_end/expected-output.txt +1 -0
  69. data/test/snapshots/error_missing_end/match-error.txt +1 -0
  70. data/test/snapshots/error_missing_end/out-sdiff.txt +6 -0
  71. data/test/{data → snapshots}/error_missing_end/source.lt3 +0 -0
  72. data/test/{data/example_alpha2/expected-error.txt → snapshots/error_name_not_permitted/expected-output.txt} +0 -0
  73. data/test/snapshots/error_name_not_permitted/match-error.txt +1 -0
  74. data/test/{data → snapshots}/error_name_not_permitted/source.lt3 +0 -0
  75. data/test/snapshots/error_no_such_copy/actual-error.txt +10 -0
  76. data/test/{data/functions/expected-error.txt → snapshots/error_no_such_copy/actual-output.txt} +0 -0
  77. data/test/{data → snapshots}/error_no_such_copy/expected-output.txt +0 -1
  78. data/test/snapshots/error_no_such_copy/match-error.txt +1 -0
  79. data/test/snapshots/error_no_such_copy/out-sdiff.txt +5 -0
  80. data/test/{data → snapshots}/error_no_such_copy/source.lt3 +0 -0
  81. data/test/snapshots/error_no_such_inc/actual-error.txt +10 -0
  82. data/test/{data/hello_world/expected-error.txt → snapshots/error_no_such_inc/actual-output.txt} +0 -0
  83. data/test/{data → snapshots}/error_no_such_inc/expected-output.txt +0 -0
  84. data/test/snapshots/error_no_such_inc/match-error.txt +1 -0
  85. data/test/snapshots/error_no_such_inc/out-sdiff.txt +6 -0
  86. data/test/{data → snapshots}/error_no_such_inc/source.lt3 +0 -0
  87. data/test/snapshots/error_no_such_mixin/actual-error.txt +37 -0
  88. data/test/{data/more_complex_vars/expected-error.txt → snapshots/error_no_such_mixin/actual-output.txt} +0 -0
  89. data/test/snapshots/error_no_such_mixin/expected-output.txt +5 -0
  90. data/test/snapshots/error_no_such_mixin/match-error.txt +1 -0
  91. data/test/snapshots/error_no_such_mixin/out-sdiff.txt +6 -0
  92. data/test/{data → snapshots}/error_no_such_mixin/source.lt3 +0 -0
  93. data/test/{data/raw_lines → snapshots/example_alpha}/expected-error.txt +0 -0
  94. data/test/{data → snapshots}/example_alpha/expected-output.txt +0 -0
  95. data/test/{data → snapshots}/example_alpha/source.lt3 +0 -0
  96. data/test/{data/raw_text_block → snapshots/example_alpha2}/expected-error.txt +0 -0
  97. data/test/{data → snapshots}/example_alpha2/expected-output.txt +0 -0
  98. data/test/{data → snapshots}/example_alpha2/source.lt3 +0 -0
  99. data/test/{data → snapshots}/fixit +0 -0
  100. data/test/{data/simple_copy → snapshots/functions}/expected-error.txt +0 -0
  101. data/test/{data → snapshots}/functions/expected-output.txt +0 -0
  102. data/test/{data → snapshots}/functions/source.lt3 +0 -0
  103. data/test/{data/simple_include → snapshots/hello_world}/expected-error.txt +0 -0
  104. data/test/{data → snapshots}/hello_world/expected-output.txt +0 -0
  105. data/test/{data → snapshots}/hello_world/source.lt3 +0 -0
  106. data/test/{data/simple_mixin → snapshots/more_complex_vars}/expected-error.txt +0 -0
  107. data/test/{data → snapshots}/more_complex_vars/expected-output.txt +0 -0
  108. data/test/{data → snapshots}/more_complex_vars/source.lt3 +0 -0
  109. data/test/{data/simple_vars → snapshots/predef_vars}/expected-error.txt +0 -0
  110. data/test/snapshots/predef_vars/match-output.txt +6 -0
  111. data/test/snapshots/predef_vars/source.lt3 +6 -0
  112. data/test/{data/single_raw_line → snapshots/raw_lines}/expected-error.txt +0 -0
  113. data/test/{data → snapshots}/raw_lines/expected-output.txt +0 -0
  114. data/test/{data → snapshots}/raw_lines/source.lt3 +0 -0
  115. data/test/{data/table_with_heredocs → snapshots/raw_text_block}/expected-error.txt +0 -0
  116. data/test/{data → snapshots}/raw_text_block/expected-output.txt +0 -0
  117. data/test/{data → snapshots}/raw_text_block/rawtext.inc +0 -0
  118. data/test/{data → snapshots}/raw_text_block/source.lt3 +0 -0
  119. data/test/{data/subset.txt → snapshots/simple_copy/expected-error.txt} +0 -0
  120. data/test/{data → snapshots}/simple_copy/expected-output.txt +0 -0
  121. data/test/{data → snapshots}/simple_copy/simplefile.inc +0 -0
  122. data/test/{data → snapshots}/simple_copy/source.lt3 +0 -0
  123. data/test/snapshots/simple_import/actual-error.txt +8 -0
  124. data/test/snapshots/simple_import/actual-output.txt +3 -0
  125. data/test/snapshots/simple_import/err-sdiff.txt +9 -0
  126. data/test/snapshots/simple_import/expected-error.txt +0 -0
  127. data/test/snapshots/simple_import/expected-output.txt +7 -0
  128. data/test/snapshots/simple_import/out-sdiff.txt +9 -0
  129. data/test/snapshots/simple_import/simple_import.rb +5 -0
  130. data/test/snapshots/simple_import/source.lt3 +7 -0
  131. data/test/snapshots/simple_include/expected-error.txt +0 -0
  132. data/test/{data → snapshots}/simple_include/expected-output.txt +0 -0
  133. data/test/{data → snapshots}/simple_include/simplefile.inc +0 -0
  134. data/test/{data → snapshots}/simple_include/source.lt3 +0 -1
  135. data/test/snapshots/simple_mixin/expected-error.txt +0 -0
  136. data/test/{data → snapshots}/simple_mixin/expected-output.txt +0 -0
  137. data/test/{data → snapshots}/simple_mixin/simple_mixin.rb +0 -0
  138. data/test/{data → snapshots}/simple_mixin/source.lt3 +0 -0
  139. data/test/snapshots/simple_vars/expected-error.txt +0 -0
  140. data/test/{data → snapshots}/simple_vars/expected-output.txt +0 -0
  141. data/test/{data → snapshots}/simple_vars/source.lt3 +0 -0
  142. data/test/snapshots/single_raw_line/expected-error.txt +0 -0
  143. data/test/{data → snapshots}/single_raw_line/expected-output.txt +0 -0
  144. data/test/{data → snapshots}/single_raw_line/source.lt3 +0 -0
  145. data/test/snapshots/subset.txt +0 -0
  146. data/test/snapshots/table_with_heredocs/expected-error.txt +0 -0
  147. data/test/{data → snapshots}/table_with_heredocs/expected-output.txt +0 -0
  148. data/test/{data → snapshots}/table_with_heredocs/source.lt3 +0 -0
  149. data/test/snapshots.rb +169 -0
  150. data/test/testlines.rb +17 -7
  151. data/test/unit/all.rb +4 -0
  152. data/test/unit/formatline.rb +650 -0
  153. data/test/unit/html.rb +38 -0
  154. data/test/unit/parser/all.rb +3 -0
  155. data/test/unit/parser/general.rb +59 -0
  156. data/test/unit/parser/importable.rb +19 -0
  157. data/test/unit/parser/mixin.rb +19 -0
  158. data/test/unit/parser/set.rb +164 -0
  159. data/test/unit/parser/string.rb +130 -0
  160. data/test/unit/parser.rb +6 -0
  161. data/test/unit/standard.rb +23 -0
  162. data/test/unit/stringparser.rb +140 -0
  163. metadata +150 -97
  164. data/test/data/error_inc_line_num/expected-err-line1match.txt +0 -1
  165. data/test/data/error_invalid_name/expected-err-line1match.txt +0 -1
  166. data/test/data/error_line_num/expected-err-line1match.txt +0 -1
  167. data/test/data/error_mismatched_end/expected-err-line1match.txt +0 -1
  168. data/test/data/error_missing_end/expected-err-line1match.txt +0 -1
  169. data/test/data/error_name_not_permitted/expected-error.txt +0 -1
  170. data/test/data/error_name_not_permitted/expected-output.txt +0 -4
  171. data/test/data/error_no_such_copy/expected-err-line1match.txt +0 -1
  172. data/test/data/error_no_such_inc/expected-err-line1match.txt +0 -1
  173. data/test/data/error_no_such_mixin/expected-err-line1match.txt +0 -1
  174. data/test/data/lines.txt +0 -120
  175. data/test/extratests.txt +0 -20
  176. data/test/formatting.rb +0 -110
  177. data/test/test.rb +0 -140
data/lib/livetext.rb CHANGED
@@ -1,34 +1,43 @@
1
+ # Class Livetext skeleton (top level).
2
+
1
3
  class Livetext
2
- VERSION = "0.9.10"
4
+ VERSION = "0.9.15"
3
5
  Path = File.expand_path(File.join(File.dirname(__FILE__)))
4
6
  end
5
7
 
6
- require 'fileutils'
8
+ # $LOAD_PATH << Livetext::Path
7
9
 
8
- $: << Livetext::Path
10
+ require 'fileutils'
9
11
 
10
- require 'functions'
11
- require 'userapi'
12
- require 'standard'
13
- require 'formatline'
14
- require 'processor'
12
+ require_relative 'errors'
13
+ require_relative 'functions'
14
+ require_relative 'userapi'
15
+ require_relative 'standard'
16
+ require_relative 'formatline'
17
+ require_relative 'processor'
18
+ require_relative 'helpers'
15
19
 
16
20
  Plugins = File.expand_path(File.join(File.dirname(__FILE__), "../plugin"))
17
21
 
18
22
  TTY = ::File.open("/dev/tty", "w")
19
23
 
24
+ make_exception(:EndWithoutOpening, "Error: found .end with no opening command")
25
+
26
+ # Class Livetext reopened (top level).
27
+
20
28
  class Livetext
29
+
30
+ include Helpers
31
+
21
32
  Vars = {}
22
33
 
34
+
23
35
  attr_reader :main
24
36
  attr_accessor :no_puts
25
37
  attr_accessor :body, :indentation
26
38
 
27
- # FIXME - phase out stupid 'parameters' method
28
-
29
39
  class << self
30
- attr_accessor :parameters # from outside world (process_text)
31
- attr_accessor :output # both bad solutions?
40
+ attr_accessor :output # bad solution?
32
41
  end
33
42
 
34
43
  def vars
@@ -41,30 +50,20 @@ class Livetext
41
50
  call = Array(call)
42
51
  mix.each {|lib| obj.mixin(lib) }
43
52
  call.each {|cmd| obj.main.send(cmd[1..-1]) } # ignores leading dot, no param
44
- vars.each_pair {|var, val| obj._setvar(var, val.to_s) }
53
+ vars.each_pair {|var, val| obj.setvar(var, val.to_s) }
45
54
  obj
46
55
  end
47
56
 
48
57
  def customize(mix: [], call: [], vars: {})
49
58
  mix = Array(mix)
50
59
  call = Array(call)
60
+ # FIXME HF won't this break??
51
61
  mix.each {|lib| mixin(lib) }
52
62
  call.each {|cmd| @main.send(cmd[1..-1]) } # ignores leading dot, no param
53
- vars.each_pair {|var, val| _setvar(var, val.to_s) }
63
+ vars.each_pair {|var, val| setvar(var, val.to_s) }
54
64
  self
55
65
  end
56
66
 
57
- Space = " "
58
- Sigil = "." # Can't change yet
59
-
60
- def self.rx(str, space=nil)
61
- Regexp.compile("^" + Regexp.escape(str) + "#{space}")
62
- end
63
-
64
- Comment = rx(Sigil, Livetext::Space)
65
- Dotcmd = rx(Sigil)
66
- Ddotcmd = /^ *\$\.[A-Za-z]/
67
-
68
67
  def initialize(output = ::STDOUT)
69
68
  @source = nil
70
69
  @_mixins = []
@@ -74,73 +73,17 @@ class Livetext
74
73
  @main = Processor.new(self, output)
75
74
  @indentation = [0]
76
75
  @_vars = Livetext::Vars
76
+ initial_vars
77
77
  end
78
78
 
79
- def _parse_colon_args(args, hash) # really belongs in livetext
80
- h2 = hash.dup
81
- e = args.each
82
- loop do
83
- arg = e.next.chop.to_sym
84
- raise "_parse_args: #{arg} is unknown" unless hash.keys.include?(arg)
85
- h2[arg] = e.next
86
- end
87
- h2 = h2.reject {|k,v| v.nil? }
88
- h2.each_pair {|k, v| raise "#{k} has no value" if v.empty? }
89
- h2
90
- end
91
-
92
- def _get_arg(name, args) # really belongs in livetext
93
- raise "(#{name}) Expected an array" unless args.is_a? Array
94
- raise "(#{name}) Expected an arg" if args.empty?
95
- raise "(#{name}) Too many args: #{args.inspect}" if args.size > 1
96
- val = args[0]
97
- raise "Expected an argument '#{name}'" if val.nil?
98
- val
99
- end
100
-
101
- def mixin(mod)
102
- @main._mixin(mod)
103
- end
104
-
105
- def _setvar(var, val)
106
- str, sym = var.to_s, var.to_sym
107
- Livetext::Vars[str] = val
108
- Livetext::Vars[sym] = val
109
- @_vars[str] = val
110
- @_vars[sym] = val
111
- end
112
-
113
- def _setfile(file)
114
- _setvar(:File, file)
115
- dir = File.dirname(File.expand_path(file))
116
- _setvar(:FileDir, dir)
117
- end
118
-
119
- def _setfile!(file)
120
- _setvar(:File, file)
121
- end
122
-
123
- def process_line(line) # FIXME inefficient?
124
- nomarkup = true
125
- case line # must apply these in order
126
- when Comment
127
- handle_scomment(line)
128
- when Dotcmd
129
- # STDERR.puts "line = #{line.inspect}"
130
- handle_dotcmd(line)
131
- when Ddotcmd
132
- indent = line.index("$") + 1
133
- @indentation.push(indent)
134
- line.sub!(/^ *\$/, "")
135
- handle_dotcmd(line)
136
- indentation.pop
137
- else
138
- @main._passthru(line)
139
- end
79
+ def initial_vars
80
+ # Other predefined variables (see also setfile)
81
+ setvar(:User, `whoami`.chomp)
82
+ setvar(:Version, Livetext::VERSION)
140
83
  end
141
84
 
142
85
  def transform(text)
143
- _setfile!("(string)")
86
+ setfile!("(string)")
144
87
  enum = text.each_line
145
88
  front = text.match(/.*?\n/).to_a.first.chomp rescue ""
146
89
  @main.source(enum, "STDIN: '#{front}...'", 0)
@@ -177,66 +120,5 @@ class Livetext
177
120
  self.body
178
121
  end
179
122
 
180
- ## FIXME process_file[!] should call process[_text]
181
-
182
- def process_file(fname, btrace=false)
183
- _setfile(fname)
184
- text = File.readlines(fname)
185
- enum = text.each
186
- @backtrace = btrace
187
- @main.source(enum, fname, 0)
188
- line = nil
189
- loop do
190
- line = @main.nextline
191
- break if line.nil?
192
- process_line(line)
193
- end
194
- val = @main.finalize if @main.respond_to? :finalize
195
- @body
196
- rescue => err
197
- STDERR.puts "[process_file] fname = #{fname.inspect}\n line = #{line.inspect}"
198
- STDERR.puts "ERROR #{err} in process_file"
199
- err.backtrace.each {|x| STDERR.puts " " + x }
200
- @body = ""
201
- end
202
-
203
- def handle_scomment(line)
204
- end
205
-
206
- def _check_name(name)
207
- @main._error! "Name '#{name}' is not permitted" if @main._disallowed?(name)
208
- @main._error! "Mismatched 'end'" if name == "end"
209
- name = "_" + name if %w[def include].include?(name)
210
- name
211
- end
212
-
213
- def _get_name(line)
214
- name, data = line.split(" ", 2)
215
- name = name[1..-1] # chop off sigil
216
- @main.data = data
217
- name = _check_name(name)
218
- end
219
-
220
- def handle_dotcmd(line, indent = 0)
221
- indent = @indentation.last # top of stack
222
- line = line.sub(/# .*$/, "")
223
- name = _get_name(line).to_sym
224
- result = nil
225
- if @main.respond_to?(name)
226
- result = @main.send(name)
227
- else
228
- @main._error! "Name '#{name}' is unknown"
229
- return
230
- end
231
- result
232
- rescue => err
233
- STDERR.puts "Error was: #{err.inspect} (calling @main._error!)"
234
- STDERR.puts err.backtrace
235
- @main._error!(err)
236
- # puts @body
237
- @body = ""
238
- return @body
239
- end
240
-
241
123
  end
242
124
 
@@ -0,0 +1,8 @@
1
+
2
+ require_relative '../livetext'
3
+
4
+ # Hmm. not today?
5
+
6
+ class Livetext::ParseFile
7
+
8
+ end
@@ -0,0 +1,38 @@
1
+
2
+ require_relative '../livetext'
3
+ require_relative 'string'
4
+
5
+ make_exception(:MismatchedQuotes, "Error: mismatched quotes")
6
+ make_exception(:NilValue, "Error: nil value")
7
+ make_exception(:NullString, "Error: null string")
8
+ make_exception(:ExpectedString, "Error: expected a string")
9
+
10
+ class Livetext::ParseGeneral < StringParser
11
+
12
+ def initialize(str)
13
+ super
14
+ end
15
+
16
+ def strip_quotes
17
+ raise NullString if @line.empty?
18
+ start, stop = @line[0], @line[-1]
19
+ return @line unless %['"].include?(start)
20
+ raise MismatchedQuotes if start != stop
21
+ @line[1..-2]
22
+ end
23
+
24
+ def self.parse_vars(lines, prefix: nil)
25
+ lines.map! {|line| line.sub(/# .*/, "").strip } # strip comments
26
+ pairs = []
27
+ lines.each do |line|
28
+ next if line.strip.empty?
29
+ var, value = line.split(" ", 2)
30
+ val = FormatLine.var_func_parse(value)
31
+ var = prefix + "." + var if prefix
32
+ pairs << [var, value]
33
+ end
34
+ pairs
35
+ end
36
+
37
+ end
38
+
@@ -0,0 +1,17 @@
1
+
2
+ require '../livetext/importable'
3
+
4
+ make_exception(:BadVariableName, "Error: invalid variable name")
5
+ make_exception(:NoEqualSign, "Error: no equal sign found")
6
+
7
+ # FIXME probably belongs elsewhere?
8
+
9
+ class Livetext::ParseImport
10
+ def use_import(name)
11
+ require name
12
+ include name
13
+ init = "init_#{name}"
14
+ self.send(init) if self.respond_to? init
15
+ end
16
+ end
17
+
@@ -0,0 +1,53 @@
1
+ require_relative '../livetext'
2
+ require_relative '../helpers'
3
+ require_relative 'string'
4
+
5
+ make_exception(:BadVariableName, "Error: invalid variable name")
6
+ make_exception(:NoEqualSign, "Error: no equal sign found")
7
+
8
+ # FIXME probably belongs elsewhere?
9
+
10
+ class Livetext::ParseMixin # < StringParser
11
+
12
+ include Helpers
13
+
14
+ def initialize(name)
15
+ @name = name
16
+ @file = find_file(name)
17
+ end
18
+
19
+ def self.get_module(name)
20
+ parse = self.new(name)
21
+ modname, code = parse.read_mixin
22
+ eval(code) # Avoid in the future
23
+ newmod = Object.const_get("::" + modname)
24
+ # return actual module
25
+ newmod
26
+ end
27
+
28
+ def read_mixin
29
+ modname = @name.gsub("/","_").capitalize
30
+ meths = grab_file(@file)
31
+ [modname, "module ::#{modname}; #{meths}\nend"]
32
+ end
33
+
34
+ private
35
+
36
+ def cwd_root?
37
+ File.dirname(File.expand_path(".")) == "/"
38
+ end
39
+
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
+
52
+ end
53
+
data/lib/parser/set.rb ADDED
@@ -0,0 +1,145 @@
1
+
2
+ require_relative '../livetext'
3
+ require_relative 'string'
4
+
5
+ make_exception(:BadVariableName, "Error: invalid variable name")
6
+ make_exception(:NoEqualSign, "Error: no equal sign found")
7
+
8
+ class Livetext::ParseSet < StringParser
9
+
10
+ attr_reader :line, :eos, :i, :len
11
+
12
+ def self.parse(str)
13
+ self.new(str).parse
14
+ end
15
+
16
+ def initialize(line)
17
+ super
18
+ end
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
+
30
+ def parse
31
+ pairs = []
32
+ char = nil
33
+ loop do
34
+ break if eos? # end of string
35
+ char = skip_spaces
36
+ raise "Expected alpha to start var name" unless char =~ /[a-z]/i
37
+ pairs << assignment
38
+ char = skip_spaces
39
+ break if eos? # end of string
40
+ case char
41
+ when nil # end of string
42
+ when ","
43
+ char = grab # skip comma
44
+ char = skip_spaces
45
+ else
46
+ raise "Expected comma or end of string (found #{char.inspect})"
47
+ end
48
+ end
49
+ pairs
50
+ end
51
+
52
+ def assignment # one single var=value
53
+ pair = nil
54
+ var = value = nil
55
+ return if eos?
56
+ var = get_var
57
+ skip_equal
58
+ value = get_value
59
+ value = FormatLine.var_func_parse(value) # FIXME broken now?
60
+ pair = [var, value]
61
+ pair
62
+ end
63
+
64
+ def get_var
65
+ name = ""
66
+ loop do
67
+ char = peek
68
+ break if eos? # end of string
69
+ case char
70
+ when /[a-zA-Z_\.0-9]/
71
+ name << grab
72
+ next
73
+ when /[ =]/
74
+ return name
75
+ else
76
+ raise BadVariableName, char, name
77
+ end
78
+ end
79
+ raise NoEqualSign
80
+ end
81
+
82
+ def skip_equal
83
+ found = false
84
+ skip_spaces
85
+ raise NoEqualSign unless peek == "="
86
+ found = true
87
+ grab # skip =
88
+ skip_spaces # skip spaces too
89
+ return peek # just for testing
90
+ rescue StopIteration
91
+ raise NoEqualSign unless found
92
+ return nil
93
+ end
94
+
95
+ def escaped
96
+ grab # skip backslash
97
+ grab # return following char
98
+ end
99
+
100
+ make_exception(:BadQuotedString, "Bad quoted string: %1")
101
+
102
+ def quoted_value
103
+ quote = grab # opening quote...
104
+ value = ""
105
+ char = nil
106
+ loop do
107
+ char = grab
108
+ break if eos?
109
+ break if char == quote
110
+ # break if char.nil?
111
+ char = escaped if char == "\\"
112
+ value << char
113
+ end
114
+ if char == quote
115
+ # char = grab
116
+ return value
117
+ end
118
+ raise BadQuotedString, quote + value
119
+ end
120
+
121
+ def unquoted_value
122
+ char = nil
123
+ value = ""
124
+ loop do
125
+ char = peek
126
+ break if eos? # FIXME oops???
127
+ # break if char.nil?
128
+ break if char == " " || char == ","
129
+ value << char
130
+ char = grab
131
+ end
132
+ value
133
+ end
134
+
135
+ def quote?(char)
136
+ char == ?" || char == ?'
137
+ end
138
+
139
+ def get_value
140
+ char = peek
141
+ value = quote?(char) ? quoted_value : unquoted_value
142
+ value
143
+ end
144
+ end
145
+
@@ -0,0 +1,70 @@
1
+ class StringParser
2
+
3
+ attr_reader :line, :eos, :i, :len
4
+
5
+ def initialize(line)
6
+ raise NilValue if line.nil?
7
+ raise ExpectedString unless String === line
8
+ @line = line
9
+ @len = @line.length
10
+ @eos = @len == 0 ? true : false
11
+ @i = 0
12
+ end
13
+
14
+ def grab
15
+ return nil if @eos
16
+ char = @line[@i]
17
+ @i += 1
18
+ @eos = true if @i > @len
19
+ char
20
+ end
21
+
22
+ def ungrab
23
+ @i -= 1 # FIXME what about eos...?
24
+ end
25
+
26
+ def next!
27
+ @line[@i + 1]
28
+ end
29
+
30
+ def prev
31
+ return nil if @i <= 0
32
+ @line[@i-1]
33
+ end
34
+
35
+ def last?
36
+ @i > @len - 1
37
+ end
38
+
39
+ def eos?
40
+ @eos = true if last? # duh?
41
+ @eos
42
+ end
43
+
44
+ def peek
45
+ return nil if @eos
46
+ @line[@i]
47
+ end
48
+
49
+ def skip_spaces
50
+ char = nil
51
+ loop do
52
+ char = peek
53
+ break if eos?
54
+ break if char != " "
55
+ grab
56
+ end
57
+ char
58
+ end
59
+
60
+ end
61
+
62
+ =begin
63
+ skip
64
+ next! skip! peek!(?)
65
+ expect_alpha
66
+ expect_number
67
+ skip_spaces
68
+ expect_eos
69
+ =end
70
+
data/lib/parser.rb ADDED
@@ -0,0 +1,5 @@
1
+
2
+ require_relative 'parser/string'
3
+ require_relative 'parser/general'
4
+ require_relative 'parser/set'
5
+ require_relative 'parser/mixin'
data/lib/processor.rb CHANGED
@@ -1,21 +1,27 @@
1
+ # Class Livetext is the actual top-level class.
2
+
1
3
  class Livetext
2
4
 
5
+ # Class Processor does the actual work of processing input.
6
+
3
7
  class Processor
8
+
9
+ GenericError = Class.new(StandardError)
10
+
4
11
  include Livetext::Standard
5
12
  include Livetext::UserAPI
6
13
 
7
- Disallowed = [:nil?, :===, :=~, :!~, :eql?, :hash, :<=>,
8
- :class, :singleton_class, :clone, :dup, :taint, :tainted?,
9
- :untaint, :untrust, :untrusted?, :trust, :freeze, :frozen?,
10
- :to_s, :inspect, :methods, :singleton_methods, :protected_methods,
11
- :private_methods, :public_methods, :instance_variables,
12
- :instance_variable_get, :instance_variable_set,
13
- :instance_variable_defined?, :remove_instance_variable,
14
- :instance_of?, :kind_of?, :is_a?, :tap, :send, :public_send,
15
- :respond_to?, :extend, :display, :method, :public_method,
16
- :singleton_method, :define_singleton_method, :object_id, :to_enum,
17
- :enum_for, :pretty_inspect, :==, :equal?, :!, :!=, :instance_eval,
18
- :instance_exec, :__send__, :__id__, :__binding__]
14
+ Disallowed = %i[ ! != !~ <=> == === =~ __binding__ __id__ __send__ class
15
+ clone define_singleton_method display dup enum_for eql?
16
+ equal? extend freeze frozen? hash inspect instance_eval
17
+ instance_exec instance_of? instance_variable_defined?
18
+ instance_variable_get instance_variable_set instance_variables is_a?
19
+ kind_of? method methods nil? object_id
20
+ pretty_inspect private_methods protected_methods public_method
21
+ public_methods public_send remove_instance_variable
22
+ respond_to? send singleton_class singleton_method
23
+ singleton_methods taint tainted? tap to_enum
24
+ to_s trust untaint untrust untrusted?]
19
25
 
20
26
  def initialize(parent, output = nil)
21
27
  @parent = parent
@@ -32,18 +38,14 @@ class Livetext
32
38
  @output = io
33
39
  end
34
40
 
35
- def _error!(err, abort=true, trace=false)
41
+ def _error!(err, raise_error=false, trace=false) # FIXME much bullshit happens here
36
42
  where = @sources.last || @save_location
37
- # puts @parent.body
38
- puts "[lib/processor] Error: #{err}"
39
- puts err.backtrace.join("\n") if err.respond_to?(:backtrace)
40
- STDERR.puts "[lib/processor] Error: #{err}" # (at #{where[1]} line #{where[2]})"
41
- raise "lib/processor error!"
43
+ STDERR.puts "Error: #{err} (at #{where[1]} line #{where[2]})"
42
44
  STDERR.puts err.backtrace if err.respond_to?(:backtrace) # && trace
43
- exit if abort
45
+ raise GenericError.new("Error: #{err}") if raise_error
44
46
  end
45
47
 
46
- def _disallowed?(name)
48
+ def disallowed?(name)
47
49
  Disallowed.include?(name.to_sym)
48
50
  end
49
51
 
@@ -56,7 +58,7 @@ class Livetext
56
58
  rescue StopIteration
57
59
  @sources.pop
58
60
  nil
59
- rescue
61
+ rescue => err
60
62
  nil
61
63
  end
62
64
 
@@ -69,11 +71,5 @@ class Livetext
69
71
  @sources.pop
70
72
  nil
71
73
  end
72
-
73
- def grab_file(fname)
74
- File.read(fname)
75
- end
76
-
77
74
  end
78
-
79
75
  end