livetext 0.9.11 → 0.9.17

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 (168) hide show
  1. checksums.yaml +4 -4
  2. data/README.lt3 +2 -2
  3. data/lib/cmdargs.rb +93 -0
  4. data/lib/errors.rb +15 -0
  5. data/lib/formatline.rb +59 -88
  6. data/lib/functions.rb +6 -2
  7. data/lib/handler/icanhaz.rb +35 -0
  8. data/lib/handler.rb +1 -0
  9. data/lib/helpers.rb +194 -0
  10. data/lib/html.rb +32 -0
  11. data/lib/livetext/importable.rb +2 -0
  12. data/lib/livetext.rb +35 -152
  13. data/lib/parser/file.rb +8 -0
  14. data/lib/parser/general.rb +38 -0
  15. data/lib/parser/import.rb +15 -0
  16. data/lib/parser/mixin.rb +38 -0
  17. data/lib/parser/set.rb +145 -0
  18. data/lib/parser/string.rb +70 -0
  19. data/lib/parser.rb +5 -0
  20. data/lib/processor.rb +23 -27
  21. data/lib/standard.rb +164 -346
  22. data/lib/userapi.rb +3 -5
  23. data/livetext.gemspec +1 -2
  24. data/plugin/bookish.rb +26 -22
  25. data/plugin/calibre.rb +1 -1
  26. data/plugin/livemagick.rb +10 -10
  27. data/plugin/markdown.rb +13 -11
  28. data/plugin/pyggish.rb +94 -84
  29. data/plugin/tutorial.rb +10 -5
  30. data/test/all.rb +3 -0
  31. data/test/snapshots/OMIT.txt +11 -0
  32. data/test/{data → snapshots}/basic_formatting/expected-error.txt +0 -0
  33. data/test/{data → snapshots}/basic_formatting/expected-output.txt +0 -0
  34. data/test/{data → snapshots}/basic_formatting/source.lt3 +0 -0
  35. data/test/{data → snapshots}/block_comment/expected-error.txt +0 -0
  36. data/test/{data → snapshots}/block_comment/expected-output.txt +0 -0
  37. data/test/{data → snapshots}/block_comment/source.lt3 +0 -0
  38. data/test/snapshots/clusion.txt +70 -0
  39. data/test/{data → snapshots}/comments_ignored_1/expected-error.txt +0 -0
  40. data/test/{data → snapshots}/comments_ignored_1/expected-output.txt +0 -0
  41. data/test/{data → snapshots}/comments_ignored_1/source.lt3 +0 -0
  42. data/test/{data → snapshots}/copy_is_raw/expected-error.txt +0 -0
  43. data/test/{data → snapshots}/copy_is_raw/expected-output.txt +0 -0
  44. data/test/{data → snapshots}/copy_is_raw/rawtext.inc +0 -0
  45. data/test/{data → snapshots}/copy_is_raw/source.lt3 +0 -0
  46. data/test/{data → snapshots}/crap +0 -0
  47. data/test/{data → snapshots}/def_method/expected-error.txt +0 -0
  48. data/test/{data → snapshots}/def_method/expected-output.txt +0 -0
  49. data/test/{data → snapshots}/def_method/source.lt3 +0 -0
  50. data/test/{data → snapshots}/error_inc_line_num/expected-output.txt +0 -0
  51. data/test/{data → snapshots}/error_inc_line_num/file2.lt3 +0 -0
  52. data/test/snapshots/error_inc_line_num/match-error.txt +1 -0
  53. data/test/{data → snapshots}/error_inc_line_num/source.lt3 +0 -0
  54. data/test/{data → snapshots}/error_invalid_name/expected-output.txt +0 -0
  55. data/test/snapshots/error_invalid_name/match-error.txt +1 -0
  56. data/test/{data → snapshots}/error_invalid_name/source.lt3 +0 -0
  57. data/test/{data → snapshots}/error_line_num/expected-output.txt +0 -0
  58. data/test/snapshots/error_line_num/match-error.txt +1 -0
  59. data/test/{data → snapshots}/error_line_num/source.lt3 +0 -0
  60. data/test/{data → snapshots}/error_mismatched_end/expected-output.txt +0 -2
  61. data/test/snapshots/error_mismatched_end/match-error.txt +1 -0
  62. data/test/{data → snapshots}/error_mismatched_end/source.lt3 +0 -0
  63. data/test/{data → snapshots}/error_missing_end/expected-output.txt +0 -0
  64. data/test/snapshots/error_missing_end/match-error.txt +1 -0
  65. data/test/{data → snapshots}/error_missing_end/source.lt3 +0 -0
  66. data/test/{data/error_no_such_mixin → snapshots/error_name_not_permitted}/expected-output.txt +0 -0
  67. data/test/snapshots/error_name_not_permitted/match-error.txt +1 -0
  68. data/test/{data → snapshots}/error_name_not_permitted/source.lt3 +0 -0
  69. data/test/{data → snapshots}/error_no_such_copy/expected-output.txt +0 -5
  70. data/test/snapshots/error_no_such_copy/match-error.txt +1 -0
  71. data/test/{data → snapshots}/error_no_such_copy/source.lt3 +0 -1
  72. data/test/{data → snapshots}/error_no_such_inc/expected-output.txt +0 -4
  73. data/test/snapshots/error_no_such_inc/match-error.txt +1 -0
  74. data/test/{data → snapshots}/error_no_such_inc/source.lt3 +0 -0
  75. data/test/snapshots/error_no_such_mixin/expected-output.txt +5 -0
  76. data/test/snapshots/error_no_such_mixin/match-error.txt +1 -0
  77. data/test/{data → snapshots}/error_no_such_mixin/source.lt3 +0 -0
  78. data/test/{data → snapshots}/example_alpha/expected-error.txt +0 -0
  79. data/test/{data → snapshots}/example_alpha/expected-output.txt +0 -0
  80. data/test/{data → snapshots}/example_alpha/source.lt3 +0 -0
  81. data/test/{data → snapshots}/example_alpha2/expected-error.txt +0 -0
  82. data/test/{data → snapshots}/example_alpha2/expected-output.txt +0 -0
  83. data/test/{data → snapshots}/example_alpha2/source.lt3 +0 -0
  84. data/test/{data → snapshots}/fixit +0 -0
  85. data/test/{data → snapshots}/functions/expected-error.txt +0 -0
  86. data/test/{data → snapshots}/functions/expected-output.txt +0 -0
  87. data/test/{data → snapshots}/functions/source.lt3 +0 -0
  88. data/test/{data → snapshots}/hello_world/expected-error.txt +0 -0
  89. data/test/{data → snapshots}/hello_world/expected-output.txt +0 -0
  90. data/test/{data → snapshots}/hello_world/source.lt3 +0 -0
  91. data/test/snapshots/icanhaz/expected-output.txt +5 -0
  92. data/test/snapshots/icanhaz/match-error.txt +1 -0
  93. data/test/snapshots/icanhaz/simple_import.rb +5 -0
  94. data/test/snapshots/icanhaz/source.lt3 +10 -0
  95. data/test/{data/more_complex_vars → snapshots/icanhaz2}/expected-error.txt +0 -0
  96. data/test/snapshots/icanhaz2/expected-output.txt +6 -0
  97. data/test/snapshots/icanhaz2/simple_canhaz.rb +5 -0
  98. data/test/snapshots/icanhaz2/source.lt3 +6 -0
  99. data/test/{data/predef_vars → snapshots/more_complex_vars}/expected-error.txt +0 -0
  100. data/test/{data → snapshots}/more_complex_vars/expected-output.txt +0 -0
  101. data/test/{data → snapshots}/more_complex_vars/source.lt3 +0 -0
  102. data/test/{data/raw_lines → snapshots/predef_vars}/expected-error.txt +0 -0
  103. data/test/snapshots/predef_vars/match-output.txt +6 -0
  104. data/test/{data → snapshots}/predef_vars/source.lt3 +0 -0
  105. data/test/{data/raw_text_block → snapshots/raw_lines}/expected-error.txt +0 -0
  106. data/test/{data → snapshots}/raw_lines/expected-output.txt +0 -0
  107. data/test/{data → snapshots}/raw_lines/source.lt3 +0 -0
  108. data/test/{data/simple_copy → snapshots/raw_text_block}/expected-error.txt +0 -0
  109. data/test/{data → snapshots}/raw_text_block/expected-output.txt +0 -0
  110. data/test/{data → snapshots}/raw_text_block/rawtext.inc +0 -0
  111. data/test/{data → snapshots}/raw_text_block/source.lt3 +0 -0
  112. data/test/{data/simple_include → snapshots/simple_copy}/expected-error.txt +0 -0
  113. data/test/{data → snapshots}/simple_copy/expected-output.txt +0 -0
  114. data/test/{data → snapshots}/simple_copy/simplefile.inc +0 -0
  115. data/test/{data → snapshots}/simple_copy/source.lt3 +0 -0
  116. data/test/{data/simple_mixin → snapshots/simple_import}/expected-error.txt +0 -0
  117. data/test/snapshots/simple_import/expected-output.txt +7 -0
  118. data/test/snapshots/simple_import/simple_import.rb +5 -0
  119. data/test/snapshots/simple_import/source.lt3 +7 -0
  120. data/test/{data/simple_vars → snapshots/simple_include}/expected-error.txt +0 -0
  121. data/test/{data → snapshots}/simple_include/expected-output.txt +0 -0
  122. data/test/{data → snapshots}/simple_include/simplefile.inc +0 -0
  123. data/test/{data → snapshots}/simple_include/source.lt3 +0 -1
  124. data/test/{data/single_raw_line → snapshots/simple_mixin}/expected-error.txt +0 -0
  125. data/test/{data → snapshots}/simple_mixin/expected-output.txt +0 -0
  126. data/test/{data → snapshots}/simple_mixin/simple_mixin.rb +0 -0
  127. data/test/{data → snapshots}/simple_mixin/source.lt3 +0 -0
  128. data/test/{data/table_with_heredocs → snapshots/simple_vars}/expected-error.txt +0 -0
  129. data/test/{data → snapshots}/simple_vars/expected-output.txt +0 -0
  130. data/test/{data → snapshots}/simple_vars/source.lt3 +0 -0
  131. data/test/{data/subset.txt → snapshots/single_raw_line/expected-error.txt} +0 -0
  132. data/test/{data → snapshots}/single_raw_line/expected-output.txt +0 -0
  133. data/test/{data → snapshots}/single_raw_line/source.lt3 +0 -0
  134. data/test/snapshots/subset.txt +0 -0
  135. data/test/snapshots/table_with_heredocs/expected-error.txt +0 -0
  136. data/test/{data → snapshots}/table_with_heredocs/expected-output.txt +0 -0
  137. data/test/{data → snapshots}/table_with_heredocs/source.lt3 +0 -0
  138. data/test/snapshots.rb +177 -0
  139. data/test/testlines.rb +2 -2
  140. data/test/unit/all.rb +4 -0
  141. data/test/unit/formatline.rb +650 -0
  142. data/test/unit/html.rb +38 -0
  143. data/test/unit/parser/all.rb +3 -0
  144. data/test/unit/parser/general.rb +59 -0
  145. data/test/unit/parser/importable.rb +19 -0
  146. data/test/unit/parser/mixin.rb +19 -0
  147. data/test/unit/parser/set.rb +164 -0
  148. data/test/unit/parser/string.rb +130 -0
  149. data/test/unit/parser.rb +6 -0
  150. data/test/unit/standard.rb +23 -0
  151. data/test/unit/stringparser.rb +140 -0
  152. metadata +137 -100
  153. data/test/data/error_inc_line_num/FOO +0 -21
  154. data/test/data/error_inc_line_num/expected-err-line1match.txt +0 -1
  155. data/test/data/error_invalid_name/expected-err-line1match.txt +0 -1
  156. data/test/data/error_line_num/expected-err-line1match.txt +0 -1
  157. data/test/data/error_mismatched_end/expected-err-line1match.txt +0 -1
  158. data/test/data/error_missing_end/ERR +0 -32
  159. data/test/data/error_missing_end/expected-err-line1match.txt +0 -1
  160. data/test/data/error_name_not_permitted/expected-error.txt +0 -1
  161. data/test/data/error_name_not_permitted/expected-output.txt +0 -4
  162. data/test/data/error_no_such_copy/expected-err-line1match.txt +0 -1
  163. data/test/data/error_no_such_inc/expected-err-line1match.txt +0 -1
  164. data/test/data/error_no_such_mixin/expected-err-line1match.txt +0 -1
  165. data/test/data/lines.txt +0 -124
  166. data/test/data/predef_vars/expected-output.txt +0 -6
  167. data/test/formatting.rb +0 -110
  168. data/test/test.rb +0 -140
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2f49173986fc8a17fc77f35032e823f4818d404007d5aacd2d3d5a4a74f19e02
4
- data.tar.gz: 61c0eab54d60c23abe0c27a6b8adc16f621e35c347253b557f07ffc80b31f80e
3
+ metadata.gz: d027612469e45b953a3e8589ebbedf1f746f87f50c4a90b502f4daac56d28605
4
+ data.tar.gz: b811285f434d3b2760e201eb403f864ba31cb12e31f21105fc8c4fe5e3b743a2
5
5
  SHA512:
6
- metadata.gz: '07389bbd1154d200f6f56b0373c0459bf140baeefa370d789224f2dedd53fe5120f0f7116e2c9d1381ff07a48f945786bb8e5f3478ac9002aea0f9443f61f579'
7
- data.tar.gz: 12829e57528407a55f842f8ad8de77b47396cb6fffb22d76feaf8d98d644ebf00fc50d447a24f453026980a7cb7631443e11f9f7d67121ce9529d583ef85e513
6
+ metadata.gz: 1e1b08d7d900ae551d7777576a7284d776422d2039813a764c3d9d9b0495ac14eec4e53225e1e0f3b97a1a548377f14b861e72d4b24d2a52055cd0f75404d2bf
7
+ data.tar.gz: 025055edd14e392750b482f4b0a9a973f213b24a5991bb9c7e9939c225a21bfe77398cc118983599a0fd1ccf1c1aa4c8bbf62874745a2cf5257410b747db72ee
data/README.lt3 CHANGED
@@ -1,5 +1,5 @@
1
- .mixin tutorial
2
- .mixin markdown
1
+ .icanhaz tutorial
2
+ .icanhaz markdown
3
3
 
4
4
  . copy basic.css
5
5
 
data/lib/cmdargs.rb ADDED
@@ -0,0 +1,93 @@
1
+ require_relative 'livetext'
2
+
3
+ =begin
4
+ Weird concepts to understand here...
5
+
6
+ 1. A Livetext dot-command (flush left) usually looks like:
7
+ .foobar
8
+ 2. A dot-command (left-indented) usually looks like:
9
+ $.foobar
10
+ 3. More generally, it may have any number of parameters (0, 1, ...)
11
+ .redirect somefile.txt append
12
+ 4. Variables and functions *can* appear (rare in practice??)
13
+ .redirect somefile$my_suffix $$my_mode
14
+ 5. A trailing # comment may appear
15
+ a. Stripped... saved in #raw ? #data ? #comment ? elsewhere?
16
+ b. NOT the "dot" as a comment!
17
+ 6. .foobar # This here is a comment
18
+ 7. #data accessor returns all data on the .foo line...
19
+ a. ...After the initial space
20
+ b. ...Including spaces
21
+ c. Including comment??
22
+ d. .foo This is o n l y a test.
23
+ # #data returns: "This is o n l y a test."
24
+ e. What about formatting???
25
+ f. What about: comments? variables? functions?
26
+
27
+ 7. Some commands have NO body while others have an OPTIONAL or REQUIRED body
28
+ a. Assume .cmd1 definition forbids a body (then a body is an error)
29
+ .cmd1 # may NOT have a body
30
+ b. Assume .cmd2 definition PERMITS a body
31
+ .cmd2 # may or MAY NOT have body/.end
32
+ c. Assume .cmd3 definition PERMITS a body
33
+ .cmd3 # REQUIRES a body/.end
34
+ . stuff...
35
+ .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
+
45
+
46
+ =end
47
+
48
+ class Livetext::CmdData
49
+
50
+ attr_reader :data, :args, :nargs, :arity, :comment, :raw # , ...?
51
+
52
+ def initialize(data, body: false, arity: :N) # FIXME maybe just add **options ??
53
+ # arity: (num) fixed number 0 or more
54
+ # :N arbitrary number
55
+ # n1..n2 range
56
+ # body: true => this command has a body + .end
57
+ # how raw is raw?
58
+ # remove comment - always/sometimes/never?
59
+ # var_func_parse - always/sometimes/never?
60
+ # var_func_parse inside body??
61
+ @data = data.dup # comment? vars? funcs?
62
+ @raw = data.dup # comment? vars? funcs?
63
+ @args = data.split # simple array
64
+ @nargs = nargs # not really "needed"
65
+ check_num_args(nargs)
66
+
67
+ # @varfunc = _var_func_parse(data.dup)
68
+ end
69
+
70
+ def check_num_args(num)
71
+ num_range = /(\d{0,2})(\.\.)(\d{0,2})/
72
+ min, max = 0, 9999
73
+ md = num_range.match(@nargs).to_a
74
+ bad_args = nil
75
+ case
76
+ when @nargs == ":N" # arbitrary
77
+ # max already set
78
+ when md[2] == ".." # range: 4..6 1.. ..4
79
+ vmin, vmax = md.values_at(1, 2)
80
+ min = Integer(vmin) unless vmin.empty?
81
+ max = Integer(vmax) unless vmax.empty?
82
+ min, max = Integer(min), Integer(max)
83
+ when %r[^\d+$] =~ num
84
+ min = max = Integer(num) # can raise error
85
+ else
86
+ raise "Invalid value or range '#{num.inspect}'"
87
+ end
88
+
89
+ bad_args = @args.size.between?(min, max)
90
+ raise "Expected #{num} args but found #{@args.size}!" if bad_args
91
+ end
92
+
93
+ end
data/lib/errors.rb ADDED
@@ -0,0 +1,15 @@
1
+
2
+ # More later?
3
+
4
+ def make_exception(sym, str, target_class = Object)
5
+ return if target_class.constants.include?(sym)
6
+ klass = sym # :"#{sym}_Class"
7
+ target_class.const_set(klass, StandardError.dup)
8
+ define_method(sym) do |*args|
9
+ args = [] unless args.first
10
+ msg = str.dup
11
+ args.each.with_index {|arg, i| msg.sub!("%#{i+1}", arg) }
12
+ target_class.class_eval(klass.to_s).new(msg)
13
+ end
14
+ end
15
+
data/lib/formatline.rb CHANGED
@@ -1,4 +1,7 @@
1
- class FormatLine
1
+ # Class FormatLine handles the parsing of comments, dot commands, and
2
+ # simple formatting characters.
3
+
4
+ class FormatLine < StringParser
2
5
  SimpleFormats = {}
3
6
  SimpleFormats[:b] = %w[<b> </b>]
4
7
  SimpleFormats[:i] = %w[<i> </i>]
@@ -21,20 +24,11 @@ class FormatLine
21
24
 
22
25
  Syms = { "*" => :b, "_" => :i, "`" => :t, "~" => :s }
23
26
 
24
- def terminate?(terminators, ch)
25
- if terminators.is_a? Regexp
26
- terminators === ch
27
- else
28
- terminators.include?(ch)
29
- end
30
- end
31
-
32
27
  attr_reader :out
33
28
  attr_reader :tokenlist
34
29
 
35
30
  def initialize(line)
36
- @line = line
37
- @i = -1
31
+ super
38
32
  @token = Null.dup
39
33
  @tokenlist = []
40
34
  end
@@ -42,26 +36,27 @@ class FormatLine
42
36
  def self.parse!(line)
43
37
  return nil if line.nil?
44
38
  x = self.new(line.chomp)
45
- t = x.tokenize(line)
39
+ t = x.tokenize
40
+ # TTY.puts "tokens = \n#{t.inspect}\n "
46
41
  x.evaluate
47
42
  end
48
43
 
49
- def tokenize(line)
50
- grab
44
+ def tokenize
45
+ # add grab
51
46
  loop do
52
- case curr
53
- when Escape; grab; add curr; grab; add curr
47
+ case peek
48
+ when Escape; grab; add peek; grab; add peek
54
49
  when "$"
55
50
  dollar
56
51
  when "*", "_", "`", "~"
57
- marker curr
58
- add curr
52
+ marker peek
53
+ add peek
59
54
  when LF
60
55
  break if @i >= line.size - 1
61
56
  when nil
62
57
  break
63
58
  else
64
- add curr
59
+ add peek
65
60
  end
66
61
  grab
67
62
  end
@@ -69,24 +64,33 @@ class FormatLine
69
64
  @tokenlist
70
65
  end
71
66
 
67
+ def terminate?(terminators, ch)
68
+ if terminators.is_a? Regexp
69
+ terminators === ch
70
+ else
71
+ terminators.include?(ch)
72
+ end
73
+ end
74
+
72
75
  def self.var_func_parse(str)
73
76
  return nil if str.nil?
74
77
  x = self.new(str.chomp)
75
- x.grab
76
- loop do
77
- case x.curr
78
- when Escape; x.grab; x.add x.curr; x.grab
79
- when "$"
80
- x.dollar
81
- when LF, nil
82
- break
83
- else
84
- x.add x.curr
85
- end
86
- x.grab
78
+ char = x.peek
79
+ loop do
80
+ char = x.grab
81
+ break if char == LF || char == nil
82
+ x.handle_escaping if char == Escape
83
+ x.dollar if char == "$"
84
+ x.add char
87
85
  end
88
86
  x.add_token(:str)
89
- x.evaluate
87
+ result = x.evaluate
88
+ result
89
+ end
90
+
91
+ def handle_escaping
92
+ grab
93
+ add grab
90
94
  end
91
95
 
92
96
  def embed(sym, str)
@@ -127,27 +131,6 @@ class FormatLine
127
131
  @out
128
132
  end
129
133
 
130
- def curr
131
- @line[@i]
132
- end
133
-
134
- def prev
135
- return nil if @i <= 0
136
- @line[@i-1]
137
- end
138
-
139
- def next!
140
- @line[@i+1]
141
- end
142
-
143
- def grab
144
- @line[@i+=1]
145
- end
146
-
147
- def ungrab
148
- @line[@i-=1]
149
- end
150
-
151
134
  def grab_colon_param
152
135
  grab # grab :
153
136
  param = ""
@@ -184,7 +167,7 @@ class FormatLine
184
167
  end
185
168
  end
186
169
 
187
- add curr
170
+ add peek
188
171
  grab
189
172
  param = nil if param.empty?
190
173
  param
@@ -204,8 +187,8 @@ class FormatLine
204
187
  str = Null.dup
205
188
  grab
206
189
  loop do
207
- break if curr.nil?
208
- str << curr
190
+ break if eos?
191
+ str << peek
209
192
  break if terminate?(NoAlpha, next!)
210
193
  grab
211
194
  end
@@ -216,8 +199,8 @@ class FormatLine
216
199
  str = Null.dup
217
200
  grab
218
201
  loop do
219
- break if curr.nil?
220
- str << curr
202
+ break if eos? # peek.nil?
203
+ str << peek
221
204
  break if terminate?(NoAlphaDot, next!)
222
205
  grab
223
206
  end
@@ -226,7 +209,7 @@ class FormatLine
226
209
 
227
210
  def dollar
228
211
  grab
229
- case curr
212
+ case peek
230
213
  when LF; add "$"; add_token :str
231
214
  when " "; add "$ "; add_token :str
232
215
  when nil; add "$"; add_token :str
@@ -234,10 +217,10 @@ class FormatLine
234
217
  # when "."; dollar_dot
235
218
  when /[A-Za-z]/
236
219
  add_token :str
237
- var = curr + grab_alpha_dot
220
+ var = peek + grab_alpha_dot
238
221
  add_token(:var, var)
239
222
  else
240
- add "$" + curr
223
+ add "$" + peek
241
224
  add_token(:string)
242
225
  end
243
226
  end
@@ -255,7 +238,7 @@ class FormatLine
255
238
  when "["; param = grab_func_param; add_token(:brackets, param)
256
239
  end
257
240
  else
258
- grab; add_token :str, "$$" + curr; return
241
+ grab; add_token :str, "$$" + peek; return
259
242
  end
260
243
  end
261
244
 
@@ -272,7 +255,7 @@ class FormatLine
272
255
  end
273
256
 
274
257
  grab
275
- case curr
258
+ case peek
276
259
  when Space
277
260
  add char + " "
278
261
  add_token :str
@@ -283,7 +266,7 @@ class FormatLine
283
266
  when char; double_marker(char)
284
267
  when LBrack; long_marker(char)
285
268
  else
286
- str = curr + collect!(sym, Blank)
269
+ str = peek + collect!(sym, Blank)
287
270
  add str
288
271
  add_token sym, str
289
272
  grab
@@ -316,21 +299,19 @@ class FormatLine
316
299
  str = Null.dup # next is not " ","*","["
317
300
  grab # ZZZ
318
301
  loop do
319
- if curr == Escape
320
- str << grab # ch = escaped char
302
+ if peek == Escape
321
303
  grab
304
+ str << grab
322
305
  next
323
306
  end
324
- if terminate?(terminators, curr)
307
+ if terminate?(terminators, peek)
325
308
  break
326
309
  end
327
- # STDERR.puts "#{curr.inspect} is not a terminator"
328
- str << curr # not a terminator
310
+ str << peek # not a terminator
329
311
  grab
330
- # STDERR.puts "After grab, curr is #{curr.inspect}"
331
312
  end
332
313
 
333
- if curr == "]" # skip right bracket
314
+ if peek == "]" # skip right bracket
334
315
  grab
335
316
  end
336
317
  add str
@@ -341,8 +322,8 @@ class FormatLine
341
322
  end
342
323
 
343
324
  def escaped
344
- ch = grab
345
325
  grab
326
+ ch = grab
346
327
  ch
347
328
  end
348
329
 
@@ -353,15 +334,15 @@ class FormatLine
353
334
  grab # ZZZ
354
335
  loop do
355
336
  case
356
- when curr.nil?
337
+ when peek.nil?
357
338
  return str
358
- when curr == Escape
339
+ when peek == Escape
359
340
  str << escaped
360
341
  next
361
- when terminate?(terminators, curr)
342
+ when terminate?(terminators, peek)
362
343
  break
363
344
  else
364
- str << curr # not a terminator
345
+ str << peek # not a terminator
365
346
  end
366
347
  grab
367
348
  end
@@ -373,17 +354,14 @@ class FormatLine
373
354
  STDERR.puts "=== str = #{str.inspect}"
374
355
  end
375
356
 
376
- ############
377
-
378
- ### From FormatLine:
379
-
380
357
  def funcall(name, param)
358
+ err = "[Error evaluating $$#{name}(#{param})]"
381
359
  result =
382
360
  if self.respond_to?("func_" + name.to_s)
383
361
  self.send("func_" + name.to_s, param)
384
362
  else
385
363
  fobj = ::Livetext::Functions.new
386
- fobj.send(name, param)
364
+ fobj.send(name, param) rescue err
387
365
  end
388
366
  result
389
367
  end
@@ -393,13 +371,6 @@ class FormatLine
393
371
  result
394
372
  end
395
373
 
396
- #####
397
-
398
- def showme(tag)
399
- char = @line[@cc]
400
- puts "--- #{tag}: ch=#{@ch.inspect} next=#{@next.inspect} (cc=#@cc:#{char.inspect}) out=#{@out.inspect}"
401
- end
402
-
403
374
  def embedded?
404
375
  ! (['"', "'", " ", nil].include? prev)
405
376
  end
data/lib/functions.rb CHANGED
@@ -1,6 +1,10 @@
1
- require 'standard' # FIXME
2
1
 
3
- class Livetext::Functions # Functions will go here... user-def AND pre-def??
2
+ require_relative 'standard' # FIXME umm, why is this necessary??
3
+
4
+ # Class Functions is where '$$func' functions are stored dynamically...
5
+ # user-def AND pre-def??
6
+
7
+ class Livetext::Functions
4
8
  Formats = ::Livetext::Standard::SimpleFormats
5
9
 
6
10
  @param = nil
@@ -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 ADDED
@@ -0,0 +1,194 @@
1
+
2
+ module Helpers
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
+
113
+ def check_disallowed(name)
114
+ raise DisallowedName(name) if disallowed?(name)
115
+ end
116
+
117
+ def check_file_exists(file)
118
+ raise FileNotFound(file) unless File.exist?(file)
119
+ end
120
+
121
+ def set_variables(pairs)
122
+ pairs.each do |pair|
123
+ var, value = *pair
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
168
+ end
169
+ end
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
+
194
+ end