livetext 0.9.14 → 0.9.15

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 (66) hide show
  1. checksums.yaml +4 -4
  2. data/lib/cmdargs.rb +93 -0
  3. data/lib/formatline.rb +56 -83
  4. data/lib/helpers.rb +142 -4
  5. data/lib/livetext.rb +11 -141
  6. data/lib/parser/file.rb +8 -0
  7. data/lib/parser/mixin.rb +28 -15
  8. data/lib/parser/set.rb +35 -26
  9. data/lib/parser/string.rb +19 -4
  10. data/lib/processor.rb +1 -4
  11. data/lib/standard.rb +56 -96
  12. data/plugin/bookish.rb +26 -22
  13. data/plugin/calibre.rb +1 -1
  14. data/plugin/livemagick.rb +10 -10
  15. data/plugin/markdown.rb +13 -11
  16. data/plugin/pyggish.rb +94 -84
  17. data/plugin/tutorial.rb +10 -5
  18. data/test/all.rb +0 -1
  19. data/test/snapshots/OMIT.txt +7 -8
  20. data/test/snapshots/clusion.txt +35 -0
  21. data/test/snapshots/error_inc_line_num/actual-error.txt +14 -0
  22. data/test/snapshots/error_inc_line_num/actual-output.txt +7 -0
  23. data/test/snapshots/error_inc_line_num/match-error.txt +1 -1
  24. data/test/snapshots/error_inc_line_num/out-sdiff.txt +14 -0
  25. data/test/snapshots/error_invalid_name/actual-error.txt +10 -0
  26. data/test/snapshots/error_invalid_name/actual-output.txt +0 -0
  27. data/test/snapshots/error_invalid_name/match-error.txt +1 -1
  28. data/test/snapshots/error_invalid_name/out-sdiff.txt +6 -0
  29. data/test/snapshots/error_line_num/match-error.txt +1 -1
  30. data/test/snapshots/error_mismatched_end/match-error.txt +1 -1
  31. data/test/snapshots/error_missing_end/actual-error.txt +10 -0
  32. data/test/snapshots/error_missing_end/actual-output.txt +0 -0
  33. data/test/snapshots/error_missing_end/match-error.txt +1 -1
  34. data/test/snapshots/error_missing_end/out-sdiff.txt +6 -0
  35. data/test/snapshots/error_no_such_copy/actual-error.txt +10 -0
  36. data/test/snapshots/error_no_such_copy/actual-output.txt +0 -0
  37. data/test/snapshots/error_no_such_copy/match-error.txt +1 -1
  38. data/test/snapshots/error_no_such_copy/out-sdiff.txt +5 -0
  39. data/test/snapshots/error_no_such_copy/source.lt3 +0 -1
  40. data/test/snapshots/error_no_such_inc/actual-error.txt +10 -0
  41. data/test/snapshots/error_no_such_inc/actual-output.txt +0 -0
  42. data/test/snapshots/error_no_such_inc/match-error.txt +1 -1
  43. data/test/snapshots/error_no_such_inc/out-sdiff.txt +6 -0
  44. data/test/snapshots/error_no_such_mixin/actual-error.txt +37 -0
  45. data/test/snapshots/error_no_such_mixin/actual-output.txt +0 -0
  46. data/test/snapshots/error_no_such_mixin/out-sdiff.txt +6 -0
  47. data/test/snapshots/simple_import/actual-error.txt +8 -0
  48. data/test/snapshots/simple_import/actual-output.txt +3 -0
  49. data/test/snapshots/simple_import/err-sdiff.txt +9 -0
  50. data/test/snapshots/simple_import/expected-error.txt +0 -0
  51. data/test/snapshots/simple_import/expected-output.txt +7 -0
  52. data/test/snapshots/simple_import/out-sdiff.txt +9 -0
  53. data/test/snapshots/simple_import/simple_import.rb +5 -0
  54. data/test/snapshots/simple_import/source.lt3 +7 -0
  55. data/test/snapshots/simple_include/source.lt3 +0 -1
  56. data/test/snapshots.rb +3 -2
  57. data/test/unit/all.rb +1 -0
  58. data/test/unit/formatline.rb +650 -0
  59. data/test/unit/parser/importable.rb +1 -1
  60. data/test/unit/parser/mixin.rb +1 -1
  61. data/test/unit/parser/set.rb +19 -12
  62. data/test/unit/parser/string.rb +14 -14
  63. metadata +32 -5
  64. data/test/formatting-tests.rb +0 -35
  65. data/test/formatting.rb +0 -103
  66. data/test/snapshots/formatting-tests.txt +0 -124
data/lib/livetext.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  # Class Livetext skeleton (top level).
2
2
 
3
3
  class Livetext
4
- VERSION = "0.9.14"
4
+ VERSION = "0.9.15"
5
5
  Path = File.expand_path(File.join(File.dirname(__FILE__)))
6
6
  end
7
7
 
@@ -9,13 +9,13 @@ end
9
9
 
10
10
  require 'fileutils'
11
11
 
12
- require 'helpers'
13
12
  require_relative 'errors'
14
13
  require_relative 'functions'
15
14
  require_relative 'userapi'
16
15
  require_relative 'standard'
17
16
  require_relative 'formatline'
18
17
  require_relative 'processor'
18
+ require_relative 'helpers'
19
19
 
20
20
  Plugins = File.expand_path(File.join(File.dirname(__FILE__), "../plugin"))
21
21
 
@@ -31,16 +31,6 @@ class Livetext
31
31
 
32
32
  Vars = {}
33
33
 
34
- Space = " "
35
- Sigil = "." # Can't change yet
36
-
37
- def self.rx(str, space=nil)
38
- Regexp.compile("^" + Regexp.escape(str) + "#{space}")
39
- end
40
-
41
- Comment = rx(Sigil, Livetext::Space)
42
- Dotcmd = rx(Sigil)
43
- Ddotcmd = /^ *\$\.[A-Za-z]/
44
34
 
45
35
  attr_reader :main
46
36
  attr_accessor :no_puts
@@ -60,16 +50,17 @@ class Livetext
60
50
  call = Array(call)
61
51
  mix.each {|lib| obj.mixin(lib) }
62
52
  call.each {|cmd| obj.main.send(cmd[1..-1]) } # ignores leading dot, no param
63
- vars.each_pair {|var, val| obj._setvar(var, val.to_s) }
53
+ vars.each_pair {|var, val| obj.setvar(var, val.to_s) }
64
54
  obj
65
55
  end
66
56
 
67
57
  def customize(mix: [], call: [], vars: {})
68
58
  mix = Array(mix)
69
59
  call = Array(call)
60
+ # FIXME HF won't this break??
70
61
  mix.each {|lib| mixin(lib) }
71
62
  call.each {|cmd| @main.send(cmd[1..-1]) } # ignores leading dot, no param
72
- vars.each_pair {|var, val| _setvar(var, val.to_s) }
63
+ vars.each_pair {|var, val| setvar(var, val.to_s) }
73
64
  self
74
65
  end
75
66
 
@@ -82,81 +73,17 @@ class Livetext
82
73
  @main = Processor.new(self, output)
83
74
  @indentation = [0]
84
75
  @_vars = Livetext::Vars
85
-
86
- # Other predefined variables (see also _setfile)
87
- _setvar(:User, `whoami`.chomp)
88
- _setvar(:Version, Livetext::VERSION)
89
- end
90
-
91
- def _parse_colon_args(args, hash) # really belongs in livetext
92
- h2 = hash.dup
93
- e = args.each
94
- loop do
95
- arg = e.next.chop.to_sym
96
- raise "_parse_args: #{arg} is unknown" unless hash.keys.include?(arg)
97
- h2[arg] = e.next
98
- end
99
- h2 = h2.reject {|k,v| v.nil? }
100
- h2.each_pair {|k, v| raise "#{k} has no value" if v.empty? }
101
- h2
102
- end
103
-
104
- def _get_arg(name, args) # really belongs in livetext
105
- raise "(#{name}) Expected an array" unless args.is_a? Array
106
- raise "(#{name}) Expected an arg" if args.empty?
107
- raise "(#{name}) Too many args: #{args.inspect}" if args.size > 1
108
- val = args[0]
109
- raise "Expected an argument '#{name}'" if val.nil?
110
- val
111
- end
112
-
113
- def mixin(mod)
114
- @main._mixin(mod)
115
- end
116
-
117
- def _setvar(var, val)
118
- str, sym = var.to_s, var.to_sym
119
- Livetext::Vars[str] = val
120
- Livetext::Vars[sym] = val
121
- @_vars[str] = val
122
- @_vars[sym] = val
76
+ initial_vars
123
77
  end
124
78
 
125
- def _setfile(file)
126
- if file
127
- _setvar(:File, file)
128
- dir = File.dirname(File.expand_path(file))
129
- _setvar(:FileDir, dir)
130
- else
131
- _setvar(:File, "[no file]")
132
- _setvar(:FileDir, "[no dir]")
133
- end
134
- end
135
-
136
- def _setfile!(file)
137
- _setvar(:File, file)
138
- end
139
-
140
- def process_line(line) # FIXME inefficient?
141
- nomarkup = true
142
- case line # must apply these in order
143
- when Comment
144
- handle_scomment(line)
145
- when Dotcmd
146
- handle_dotcmd(line)
147
- when Ddotcmd
148
- indent = line.index("$") + 1
149
- @indentation.push(indent)
150
- line.sub!(/^ *\$/, "")
151
- handle_dotcmd(line)
152
- indentation.pop
153
- else
154
- @main._passthru(line)
155
- end
79
+ def initial_vars
80
+ # Other predefined variables (see also setfile)
81
+ setvar(:User, `whoami`.chomp)
82
+ setvar(:Version, Livetext::VERSION)
156
83
  end
157
84
 
158
85
  def transform(text)
159
- _setfile!("(string)")
86
+ setfile!("(string)")
160
87
  enum = text.each_line
161
88
  front = text.match(/.*?\n/).to_a.first.chomp rescue ""
162
89
  @main.source(enum, "STDIN: '#{front}...'", 0)
@@ -193,62 +120,5 @@ class Livetext
193
120
  self.body
194
121
  end
195
122
 
196
- ## FIXME process_file[!] should call process[_text]
197
-
198
- def process_file(fname, btrace=false)
199
- _setfile(fname)
200
- text = File.readlines(fname)
201
- enum = text.each
202
- @backtrace = btrace
203
- @main.source(enum, fname, 0)
204
- line = nil
205
- loop do
206
- line = @main.nextline
207
- break if line.nil?
208
- process_line(line)
209
- end
210
- val = @main.finalize if @main.respond_to? :finalize
211
- @body
212
- rescue => err
213
- STDERR.puts "[process_file] fname = #{fname.inspect}\n line = #{line.inspect}"
214
- STDERR.puts "ERROR #{err} in process_file"
215
- err.backtrace.each {|x| STDERR.puts " " + x }
216
- # @body = ""
217
- end
218
-
219
- def handle_scomment(line)
220
- end
221
-
222
- def _get_name(line)
223
- name, data = line.split(" ", 2)
224
- name = name[1..-1] # chop off sigil
225
- name = "_" + name if %w[include def].include?(name)
226
- @main.data = data
227
- @main.check_disallowed(name)
228
- name
229
- end
230
-
231
- def handle_dotcmd(line, indent = 0)
232
- indent = @indentation.last # top of stack
233
- line = line.sub(/# .*$/, "")
234
- name = _get_name(line).to_sym
235
- result = nil
236
- case
237
- when name == :end # special case
238
- puts @body
239
- raise EndWithoutOpening()
240
- when @main.respond_to?(name)
241
- result = @main.send(name)
242
- else
243
- @main._error! "Name '#{name}' is unknown"
244
- return
245
- end
246
- result
247
- rescue => err
248
- puts @body # earlier correct output, not flushed yet
249
- STDERR.puts "Error: #{err.inspect}"
250
- STDERR.puts err.backtrace
251
- end
252
-
253
123
  end
254
124
 
@@ -0,0 +1,8 @@
1
+
2
+ require_relative '../livetext'
3
+
4
+ # Hmm. not today?
5
+
6
+ class Livetext::ParseFile
7
+
8
+ end
data/lib/parser/mixin.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  require_relative '../livetext'
2
+ require_relative '../helpers'
2
3
  require_relative 'string'
3
4
 
4
5
  make_exception(:BadVariableName, "Error: invalid variable name")
@@ -10,30 +11,42 @@ class Livetext::ParseMixin # < StringParser
10
11
 
11
12
  include Helpers
12
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
+
13
36
  def cwd_root?
14
37
  File.dirname(File.expand_path(".")) == "/"
15
38
  end
16
39
 
17
- def find_mixin(name)
18
- file = "#{Plugins}/" + name.downcase + ".rb"
40
+ def find_file(name, ext=".rb")
41
+ base = "./#{name}#{ext}"
42
+ file = "#{Plugins}/#{base}"
19
43
  return file if File.exist?(file)
20
44
 
21
- file = "./#{name}.rb"
45
+ file = base
22
46
  return file if File.exist?(file)
23
47
 
24
48
  raise "No such mixin '#{name}'" if cwd_root?
25
- Dir.chdir("..") { find_mixin(name) }
26
- end
27
-
28
- def use_mixin(name, file)
29
- modname = name.gsub("/","_").capitalize
30
- meths = grab_file(file)
31
- string = "module ::#{modname}; #{meths}\nend"
32
- eval(string)
33
- newmod = Object.const_get("::" + modname)
34
- self.extend(newmod)
35
- init = "init_#{name}"
36
- self.send(init) if self.respond_to? init
49
+ Dir.chdir("..") { find_file(name) }
37
50
  end
38
51
 
39
52
  end
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
data/lib/parser/string.rb CHANGED
@@ -5,14 +5,13 @@ class StringParser
5
5
  def initialize(line)
6
6
  raise NilValue if line.nil?
7
7
  raise ExpectedString unless String === line
8
- # raise NullString if line.empty?
9
8
  @line = line
10
9
  @len = @line.length
11
10
  @eos = @len == 0 ? true : false
12
11
  @i = 0
13
12
  end
14
13
 
15
- def next
14
+ def grab
16
15
  return nil if @eos
17
16
  char = @line[@i]
18
17
  @i += 1
@@ -20,6 +19,19 @@ class StringParser
20
19
  char
21
20
  end
22
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
+
23
35
  def last?
24
36
  @i > @len - 1
25
37
  end
@@ -35,11 +47,14 @@ class StringParser
35
47
  end
36
48
 
37
49
  def skip_spaces
50
+ char = nil
38
51
  loop do
39
- break if peek != " "
52
+ char = peek
40
53
  break if eos?
41
- self.next
54
+ break if char != " "
55
+ grab
42
56
  end
57
+ char
43
58
  end
44
59
 
45
60
  end
data/lib/processor.rb CHANGED
@@ -45,7 +45,7 @@ class Livetext
45
45
  raise GenericError.new("Error: #{err}") if raise_error
46
46
  end
47
47
 
48
- def _disallowed?(name)
48
+ def disallowed?(name)
49
49
  Disallowed.include?(name.to_sym)
50
50
  end
51
51
 
@@ -71,8 +71,5 @@ class Livetext
71
71
  @sources.pop
72
72
  nil
73
73
  end
74
-
75
-
76
74
  end
77
-
78
75
  end