teepee 0.15.7 → 0.15.8

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,296 @@
1
+ # -*- coding: utf-8 -*-
2
+ # -*- mode: Ruby -*-
3
+
4
+ # Copyright © 2013-2016, Christopher Mark Gore,
5
+ # Soli Deo Gloria,
6
+ # All rights reserved.
7
+ #
8
+ # 2317 South River Road, Saint Charles, Missouri 63303 USA.
9
+ # Web: http://cgore.com
10
+ # Email: cgore@cgore.com
11
+ #
12
+ # Redistribution and use in source and binary forms, with or without
13
+ # modification, are permitted provided that the following conditions are met:
14
+ #
15
+ # * Redistributions of source code must retain the above copyright
16
+ # notice, this list of conditions and the following disclaimer.
17
+ #
18
+ # * Redistributions in binary form must reproduce the above copyright
19
+ # notice, this list of conditions and the following disclaimer in the
20
+ # documentation and/or other materials provided with the distribution.
21
+ #
22
+ # * Neither the name of Christopher Mark Gore nor the names of other
23
+ # contributors may be used to endorse or promote products derived from
24
+ # this software without specific prior written permission.
25
+ #
26
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
27
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
30
+ # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36
+ # POSSIBILITY OF SUCH DAMAGE.
37
+
38
+
39
+ module Teepee
40
+ module CommanderMixins
41
+ module Mathematics
42
+ def numeric? *numbers
43
+ numbers.all? {|number| number.kind_of? Numeric}
44
+ end
45
+
46
+ def non_numeric_error nan
47
+ command_error "The value \"#{nan}\" is not a number."
48
+ end
49
+
50
+ def ensure_numeric number
51
+ if number.kind_of? Complex
52
+ command_error "Complex numbers are not yet supported."
53
+ elsif not number.kind_of? Numeric
54
+ command_error "Non-numeric result."
55
+ else
56
+ number
57
+ end
58
+ end
59
+
60
+ def number_from_word word
61
+ begin
62
+ word.to_number
63
+ rescue ArgumentError, NoMethodError
64
+ nil
65
+ end
66
+ end
67
+
68
+ def to_numbers words
69
+ words.map {|word| number_from_word word}.reject &:nil?
70
+ end
71
+
72
+ def + numbers
73
+ ensure_numeric to_numbers(numbers).inject 0, :+
74
+ end
75
+
76
+ def - numbers
77
+ numbers = to_numbers numbers
78
+ if numbers.length == 1
79
+ ensure_numeric -numbers.first
80
+ else
81
+ ensure_numeric numbers.reduce :-
82
+ end
83
+ end
84
+
85
+ def * numbers
86
+ ensure_numeric to_numbers(numbers).inject 1, :*
87
+ end
88
+
89
+ def / numbers
90
+ numbers = to_numbers numbers
91
+ if numbers.length == 1
92
+ ensure_numeric 1 / numbers.first
93
+ else
94
+ ensure_numeric numbers.reduce :/
95
+ end
96
+ end
97
+
98
+ def ** numbers
99
+ ensure_numeric to_numbers(numbers).reduce :**
100
+ end
101
+
102
+ def % numbers
103
+ to_numbers(numbers).inject { |base, percent| base*percent/100.0 }
104
+ end
105
+
106
+ def add_percentage numbers
107
+ to_numbers(numbers).inject {|base, percent| base * (1+percent/100.0) }
108
+ end
109
+
110
+ def subtract_percentage numbers
111
+ to_numbers(numbers).inject {|base, percent| base * (1-percent/100.0) }
112
+ end
113
+
114
+ def percent_total numbers
115
+ to_numbers(numbers).inject {|total, part| Float(part)/Float(total)*100.0 }
116
+ end
117
+
118
+ def acos angle
119
+ ensure_numeric Math.acos angle.to_number
120
+ end
121
+
122
+ def acosh angle
123
+ ensure_numeric Math.acosh angle.to_number
124
+ end
125
+
126
+ def asin angle
127
+ ensure_numeric Math.asin angle.to_number
128
+ end
129
+
130
+ def asinh angle
131
+ ensure_numeric Math.asinh angle.to_number
132
+ end
133
+
134
+ def atan angle
135
+ ensure_numeric Math.atan angle.to_number
136
+ end
137
+
138
+ def atanh angle
139
+ ensure_numeric Math.atanh angle.to_number
140
+ end
141
+
142
+ def ceiling number
143
+ ensure_numeric number.to_number.ceil
144
+ end
145
+
146
+ def cos angle
147
+ ensure_numeric Math.cos angle.to_number
148
+ end
149
+
150
+ def cosh angle
151
+ ensure_numeric Math.cosh angle.to_number
152
+ end
153
+
154
+ def degrees2radians degrees
155
+ ensure_numeric degrees.to_number * Math::PI / 180.0
156
+ end
157
+
158
+ def e
159
+ Math::E
160
+ end
161
+
162
+ def erf number
163
+ ensure_numeric Math.erf number.to_number
164
+ end
165
+
166
+ def erfc number
167
+ ensure_numeric Math.erfc number.to_number
168
+ end
169
+
170
+ def floor number
171
+ ensure_numeric number.to_number.floor
172
+ end
173
+
174
+ def gamma number
175
+ ensure_numeric Math.gamma number.to_number
176
+ end
177
+
178
+ def greater_than numbers
179
+ if numbers.empty?
180
+ true_constant
181
+ elsif numbers.length == 1
182
+ true_constant
183
+ else
184
+ numbers[0].to_number > numbers[1].to_number and greater_than numbers.rest
185
+ end
186
+ end
187
+
188
+ def greater_than_or_equal numbers
189
+ if numbers.empty?
190
+ true_constant
191
+ elsif numbers.length == 1
192
+ true_constant
193
+ else
194
+ numbers[0].to_number >= numbers[1].to_number and greater_than_or_equal numbers.rest
195
+ end
196
+ end
197
+
198
+ def i
199
+ command_error "Complex numbers are not yet supported."
200
+ end
201
+
202
+ def hypot numbers
203
+ ensure_numeric Math.sqrt to_numbers(numbers).map {|n| n**2}
204
+ end
205
+
206
+ def ld number
207
+ ensure_numeric Math.log2 number.to_number
208
+ end
209
+
210
+ def ldexp fraction, exponent
211
+ ensure_numeric Math.ldexp fraction.to_number, exponent.to_number
212
+ end
213
+
214
+ def less_than numbers
215
+ if numbers.empty?
216
+ true_constant
217
+ elsif numbers.length == 1
218
+ true_constant
219
+ else
220
+ numbers[0].to_number < numbers[1].to_number and less_than numbers.rest
221
+ end
222
+ end
223
+
224
+ def less_than_or_equal numbers
225
+ if numbers.empty?
226
+ true_constant
227
+ elsif numbers.length == 1
228
+ true_constant
229
+ else
230
+ numbers[0].to_number <= numbers[1].to_number and less_than_or_equal numbers.rest
231
+ end
232
+ end
233
+
234
+ def lgamma number
235
+ ensure_numeric Math::lgamma(number.to_number).first
236
+ end
237
+
238
+ def ln number
239
+ ensure_numeric Math.log number.to_number
240
+ end
241
+
242
+ def log base, number
243
+ if number.nil?
244
+ number, base = base, number
245
+ ensure_numeric Math.log10 number.to_number # default to log base 10
246
+ else
247
+ ensure_numeric Math.log number.to_number, base.to_number
248
+ end
249
+ end
250
+
251
+ def log10 number
252
+ ensure_numeric Math.log10 number.to_number
253
+ end
254
+
255
+ def mod numbers
256
+ ensure_numeric to_numbers(numbers).reduce :%
257
+ end
258
+
259
+ def pi
260
+ Math::PI
261
+ end
262
+
263
+ def radians2degrees radians
264
+ ensure_numeric(radians.to_number * 180.0 / Math::PI)
265
+ end
266
+
267
+ def round number, precision = nil, *_
268
+ if precision.nil? or precision.to_number.nil?
269
+ ensure_numeric number.to_number.round
270
+ else
271
+ ensure_numeric number.to_number.round precision.to_number
272
+ end
273
+ end
274
+
275
+ def sin angle
276
+ ensure_numeric Math.sin angle.to_number
277
+ end
278
+
279
+ def sinh angle
280
+ ensure_numeric Math.sinh angle.to_number
281
+ end
282
+
283
+ def sqrt number
284
+ ensure_numeric Math.sqrt number.to_number
285
+ end
286
+
287
+ def tan angle
288
+ ensure_numeric Math.tan angle.to_number
289
+ end
290
+
291
+ def tanh angle
292
+ ensure_numeric Math.tanh angle.to_number
293
+ end
294
+ end
295
+ end
296
+ end
@@ -0,0 +1,134 @@
1
+ # -*- coding: utf-8 -*-
2
+ # -*- mode: Ruby -*-
3
+
4
+ # Copyright © 2013-2016, Christopher Mark Gore,
5
+ # Soli Deo Gloria,
6
+ # All rights reserved.
7
+ #
8
+ # 2317 South River Road, Saint Charles, Missouri 63303 USA.
9
+ # Web: http://cgore.com
10
+ # Email: cgore@cgore.com
11
+ #
12
+ # Redistribution and use in source and binary forms, with or without
13
+ # modification, are permitted provided that the following conditions are met:
14
+ #
15
+ # * Redistributions of source code must retain the above copyright
16
+ # notice, this list of conditions and the following disclaimer.
17
+ #
18
+ # * Redistributions in binary form must reproduce the above copyright
19
+ # notice, this list of conditions and the following disclaimer in the
20
+ # documentation and/or other materials provided with the distribution.
21
+ #
22
+ # * Neither the name of Christopher Mark Gore nor the names of other
23
+ # contributors may be used to endorse or promote products derived from
24
+ # this software without specific prior written permission.
25
+ #
26
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
27
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
30
+ # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36
+ # POSSIBILITY OF SUCH DAMAGE.
37
+
38
+
39
+ module Teepee
40
+ module CommanderMixins
41
+ module ThinkingBicycleModels
42
+ def tb_href target, string
43
+ %{<a href="#{TB_COM}/#{target}">#{string}</a>}
44
+ end
45
+
46
+ def id_command_handler(id,
47
+ klass,
48
+ singular = klass.to_s.camelcase_to_snakecase,
49
+ plural = singular.pluralize,
50
+ partial = "#{plural}/inline",
51
+ view="")
52
+ if not id
53
+ command_error "#{singular}_id: error: no #{singular} ID specified"
54
+ elsif not id.to_s =~ /\A[0-9]+\z/
55
+ command_error "#{singular}_id: error: invalid #{singular} ID specified"
56
+ else
57
+ tb_href "#{plural}/#{id.to_s}/#{view}", "#{klass.to_s} ##{id.to_s}"
58
+ end
59
+ end
60
+
61
+ def bookmarks_folder_id id
62
+ id_command_handler id, :Folder, "folder", "folders", "folders/bookmarks_inline", "bookmarks"
63
+ end
64
+
65
+ def folder_id id
66
+ id_command_handler id, :Folder
67
+ end
68
+
69
+ def forum_id id
70
+ id_command_handler id, :Forum
71
+ end
72
+
73
+ def image expressions
74
+ expressions = strip expressions
75
+ uri, *alt_text = expressions
76
+ uri = ERB::Util.html_escape uri.to_html
77
+ if not valid_uri? uri
78
+ command_error "Not a valid URI for the image."
79
+ else
80
+ if alt_text.empty?
81
+ html_tag :img, nil, {src: uri}
82
+ else
83
+ html_tag :img, nil, {src: uri, alt: alt_text.map(&:to_html).join.strip}
84
+ end
85
+ end
86
+ end
87
+
88
+ def keyword_id id
89
+ id_command_handler id, :Keyword
90
+ end
91
+
92
+ def link expressions
93
+ expressions = strip expressions
94
+ uri, *desc = expressions
95
+ uri = ERB::Util.html_escape uri.to_html
96
+ if not valid_uri? uri
97
+ command_error "Not a valid URI."
98
+ else
99
+ desc = [uri] if desc.empty?
100
+ html_tag :a, desc, {href: uri}
101
+ end
102
+ end
103
+
104
+ def link_id id
105
+ id_command_handler id, :Link
106
+ end
107
+
108
+ def mailto email_address
109
+ email_address = email_address.to_html
110
+ if valid_email_address? email_address
111
+ html_tag :a, [email_address], {href: "mailto:#{email_address}"}
112
+ else
113
+ command_error "I'm not sure that's a valid email address."
114
+ end
115
+ end
116
+
117
+ def note_id id
118
+ id_command_handler id, :Note
119
+ end
120
+
121
+ def tag_id id
122
+ id_command_handler id, :Tag
123
+ end
124
+
125
+ def user user
126
+ if not user
127
+ command_error "user: error: no user specified"
128
+ else
129
+ tb_href "users/#{user}", user.to_html
130
+ end
131
+ end
132
+ end
133
+ end
134
+ end
@@ -35,8 +35,20 @@
35
35
  # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36
36
  # POSSIBILITY OF SUCH DAMAGE.
37
37
 
38
+ require 'teepee/commander-mixins/boolean'
39
+ require 'teepee/commander-mixins/control'
40
+ require 'teepee/commander-mixins/formatting'
41
+ require 'teepee/commander-mixins/mathematics'
42
+ require 'teepee/commander-mixins/thinking-bicycle-models'
43
+
38
44
  module Teepee
39
45
  class Commander
46
+ include CommanderMixins::Boolean
47
+ include CommanderMixins::Control
48
+ include CommanderMixins::Formatting
49
+ include CommanderMixins::Mathematics
50
+ include CommanderMixins::ThinkingBicycleModels
51
+
40
52
  attr_accessor :parser
41
53
 
42
54
  def initialize params
@@ -61,73 +73,6 @@ module Teepee
61
73
  command_error "The variable \"#{variable}\" is not defined."
62
74
  end
63
75
 
64
- def numeric? *numbers
65
- numbers.all? {|number| number.kind_of? Numeric}
66
- end
67
-
68
- def non_numeric_error nan
69
- command_error "The value \"#{nan}\" is not a number."
70
- end
71
-
72
- def ensure_numeric number
73
- if number.kind_of? Complex
74
- command_error "Complex numbers are not yet supported."
75
- elsif not number.kind_of? Numeric
76
- command_error "Non-numeric result."
77
- else
78
- number
79
- end
80
- end
81
-
82
- def ensure_boolean boolean
83
- if boolean.to_html == "true" or boolean.to_html == "false"
84
- boolean
85
- else
86
- command_error "Non-boolean value."
87
- end
88
- end
89
-
90
- def html_tag tag, expressions, attribs=nil
91
- opening_tag = if attribs
92
- attribs_string = attribs.map {|k,v| %{#{k}="#{v}"}}.join " "
93
- if expressions.nil?
94
- "<#{tag} #{attribs_string}/>"
95
- else
96
- "<#{tag} #{attribs_string}>"
97
- end
98
- else
99
- if expressions.nil?
100
- "<#{tag}/>"
101
- else
102
- "<#{tag}>"
103
- end
104
- end
105
- if expressions.nil?
106
- opening_tag
107
- else
108
- opening_tag + expressions.map(&:to_html).join.strip + "</#{tag}>"
109
- end
110
- end
111
-
112
- def tb_href target, string
113
- %{<a href="#{TB_COM}/#{target}">#{string}</a>}
114
- end
115
-
116
- def id_command_handler(id,
117
- klass,
118
- singular = klass.to_s.camelcase_to_snakecase,
119
- plural = singular.pluralize,
120
- partial = "#{plural}/inline",
121
- view="")
122
- if not id
123
- command_error "#{singular}_id: error: no #{singular} ID specified"
124
- elsif not id.to_s =~ /\A[0-9]+\z/
125
- command_error "#{singular}_id: error: invalid #{singular} ID specified"
126
- else
127
- tb_href "#{plural}/#{id.to_s}/#{view}", "#{klass.to_s} ##{id.to_s}"
128
- end
129
- end
130
-
131
76
  def left_strip expressions
132
77
  while expressions.first.kind_of? WhitespaceToken
133
78
  expressions.shift
@@ -147,109 +92,13 @@ module Teepee
147
92
  end
148
93
 
149
94
  def valid_email_address? email_address
150
- email_address =~ /\A[[:graph:]]+@[\w.]+\z/
151
- end
152
-
153
- def true_constant? expression
154
- expression.to_html == "true"
155
- end
156
-
157
- def false_constant? expression
158
- expression.to_html == "false"
95
+ email_address =~ /\A[[:graph:]]+@[\w._-]+\z/
159
96
  end
160
97
 
161
98
  def pipe? expression
162
99
  expression.is_a? PipeToken
163
100
  end
164
101
 
165
- def number_from_word word
166
- begin
167
- word.to_number
168
- rescue ArgumentError, NoMethodError
169
- nil
170
- end
171
- end
172
-
173
- def to_numbers words
174
- words.map {|word| number_from_word word}.reject &:nil?
175
- end
176
-
177
- #----------------------------------------------------------------------------
178
-
179
- def + numbers
180
- ensure_numeric to_numbers(numbers).inject 0, :+
181
- end
182
-
183
- def - numbers
184
- numbers = to_numbers numbers
185
- if numbers.length == 1
186
- ensure_numeric -numbers.first
187
- else
188
- ensure_numeric numbers.reduce :-
189
- end
190
- end
191
-
192
- def * numbers
193
- ensure_numeric to_numbers(numbers).inject 1, :*
194
- end
195
-
196
- def / numbers
197
- numbers = to_numbers numbers
198
- if numbers.length == 1
199
- ensure_numeric 1 / numbers.first
200
- else
201
- ensure_numeric numbers.reduce :/
202
- end
203
- end
204
-
205
- def ** numbers
206
- ensure_numeric to_numbers(numbers).reduce :**
207
- end
208
-
209
- def % numbers
210
- to_numbers(numbers).inject { |base, percent| base*percent/100.0 }
211
- end
212
-
213
- def add_percentage numbers
214
- to_numbers(numbers).inject {|base, percent| base * (1+percent/100.0) }
215
- end
216
-
217
- def subtract_percentage numbers
218
- to_numbers(numbers).inject {|base, percent| base * (1-percent/100.0) }
219
- end
220
-
221
- def percent_total numbers
222
- to_numbers(numbers).inject {|total, part| Float(part)/Float(total)*100.0 }
223
- end
224
-
225
- def acos angle
226
- ensure_numeric Math.acos angle.to_number
227
- end
228
-
229
- def acosh angle
230
- ensure_numeric Math.acosh angle.to_number
231
- end
232
-
233
- def asin angle
234
- ensure_numeric Math.asin angle.to_number
235
- end
236
-
237
- def asinh angle
238
- ensure_numeric Math.asinh angle.to_number
239
- end
240
-
241
- def atan angle
242
- ensure_numeric Math.atan angle.to_number
243
- end
244
-
245
- def atanh angle
246
- ensure_numeric Math.atanh angle.to_number
247
- end
248
-
249
- def b expressions
250
- html_tag :b, expressions
251
- end
252
-
253
102
  def backquote
254
103
  "`"
255
104
  end
@@ -258,375 +107,10 @@ module Teepee
258
107
  "\\"
259
108
  end
260
109
 
261
- def big expressions
262
- html_tag :big, expressions
263
- end
264
-
265
- def bookmarks_folder_id id
266
- id_command_handler id, :Folder, "folder", "folders", "folders/bookmarks_inline", "bookmarks"
267
- end
268
-
269
- def boolean_and booleans
270
- if booleans.empty?
271
- return true_constant
272
- end
273
- b = booleans.first.to_html
274
- if false_constant? b
275
- false_constant
276
- elsif true_constant? b or booleans.first.kind_of? WhitespaceToken
277
- boolean_and booleans[1..-1]
278
- else
279
- command_error "Not a boolean value #{booleans.first}"
280
- end
281
- end
282
-
283
- def boolean_nand booleans
284
- boolean_not boolean_and booleans
285
- end
286
-
287
- def boolean_nor booleans
288
- boolean_not boolean_or booleans
289
- end
290
-
291
- def boolean_not boolean
292
- boolean = boolean.to_html
293
- if true_constant? boolean
294
- false_constant
295
- elsif false_constant? boolean
296
- true_constant
297
- else
298
- command_error "Not a boolean value"
299
- end
300
- end
301
-
302
- def boolean_or booleans
303
- if booleans.empty?
304
- return false_constant
305
- end
306
- b = booleans.first.to_html
307
- if true_constant? b
308
- true_constant
309
- elsif false_constant? b or booleans.first.kind_of? WhitespaceToken
310
- boolean_or booleans[1..-1]
311
- else
312
- command_error "Not a boolean value"
313
- end
314
- end
315
-
316
- def boolean_xnor booleans
317
- boolean_not boolean_xor booleans
318
- end
319
-
320
- def boolean_xor booleans
321
- # There are two schools of thought as to what a multi-variable XOR is.
322
- # 1. Chained XORs, giving a parity check.
323
- # 2. 'Exclusively' one true for ALL inputs.
324
- # I'm going with the second: one and only one true, the rest false.
325
- # It seems therefore that the zero-argument version should be false then.
326
- if booleans.empty?
327
- false_constant
328
- else
329
- any_trues = false
330
- booleans.each do |boolean|
331
- if true_constant? boolean
332
- if any_trues
333
- return false_constant
334
- else
335
- any_trues = true
336
- end
337
- elsif false_constant? boolean
338
- # do nothing
339
- elsif boolean.kind_of? WhitespaceToken
340
- # do nothing
341
- else
342
- return command_error "Not a boolean value"
343
- end
344
- end
345
- return any_trues.to_html
346
- end
347
- end
348
-
349
- def br
350
- html_tag :br, nil
351
- end
352
-
353
- def case_operator expressions
354
- value, _, *rest = strip expressions
355
- if value and not rest.empty?
356
- def cond_helper value, expressions
357
- test_value, _, form, *rest = strip expressions
358
- if equal [value.to_html, test_value.to_html]
359
- form
360
- elsif not rest.empty?
361
- cond_helper value, rest
362
- end
363
- end
364
- cond_helper value, rest
365
- end
366
- end
367
-
368
- def ceiling number
369
- ensure_numeric number.to_number.ceil
370
- end
371
-
372
- def comment expressions
373
- nil
374
- end
375
-
376
- def cond_operator expressions
377
- conditional, _, form, *rest = strip expressions
378
- if true_constant? conditional.to_html
379
- form
380
- elsif not rest.empty?
381
- cond_operator rest
382
- end
383
- end
384
-
385
- def cos angle
386
- ensure_numeric Math.cos angle.to_number
387
- end
388
-
389
- def cosh angle
390
- ensure_numeric Math.cosh angle.to_number
391
- end
392
-
393
- def decrement variable
394
- return variable_not_defined_error variable if not is_defined? variable
395
- old_value = get_operator(variable).to_number
396
- return non_numeric_error old_value if not numeric? old_value
397
- @parser.variables[variable.to_html] = old_value - 1
398
- end
399
-
400
- def define expressions
401
- variable, _, value = expressions
402
- k = variable.to_html
403
- v = value.to_html
404
- @parser.variables[k] = v
405
- get_operator k
406
- end
407
-
408
- def is_defined? variables
409
- if not variables.is_a? Array
410
- return is_defined? [variables]
411
- elsif Set.new(variables.map(&:to_html)).subset? Set.new(@parser.variables.keys)
412
- true_constant
413
- else
414
- false_constant
415
- end
416
- end
417
-
418
- def degrees2radians degrees
419
- ensure_numeric degrees.to_number * Math::PI / 180.0
420
- end
421
-
422
- def del expressions
423
- html_tag :del, expressions
424
- end
425
-
426
110
  def dollar
427
111
  "$"
428
112
  end
429
113
 
430
- def dotimes expressions
431
- n = expressions.first.to_number
432
- return "" if n.nil? or n < 1
433
- span_operator expressions[1..-1] * n
434
- end
435
-
436
- def e
437
- Math::E
438
- end
439
-
440
- def equal expressions
441
- if expressions.empty?
442
- true_constant
443
- elsif expressions.length == 1
444
- true_constant
445
- else
446
- expressions[0].to_html == expressions[1].to_html and equal expressions.rest
447
- end
448
- end
449
-
450
- def enumerate expressions
451
- html_tag :ol, expressions
452
- end
453
-
454
- def enumerate_numeric expressions
455
- html_tag :ol, expressions, {type: "1"}
456
- end
457
-
458
- def enumerate_uppercase expressions
459
- html_tag :ol, expressions, {type: "A"}
460
- end
461
-
462
- def enumerate_lowercase expressions
463
- html_tag :ol, expressions, {type: "a"}
464
- end
465
-
466
- def enumerate_roman_uppercase expressions
467
- html_tag :ol, expressions, {type: "I"}
468
- end
469
-
470
- def enumerate_roman_lowercase expressions
471
- html_tag :ol, expressions, {type: "i"}
472
- end
473
-
474
- def erf number
475
- ensure_numeric Math.erf number.to_number
476
- end
477
-
478
- def erfc number
479
- ensure_numeric Math.erfc number.to_number
480
- end
481
-
482
- def false_constant
483
- "false"
484
- end
485
-
486
- def floor number
487
- ensure_numeric number.to_number.floor
488
- end
489
-
490
- def folder_id id
491
- id_command_handler id, :Folder
492
- end
493
-
494
- def forum_id id
495
- id_command_handler id, :Forum
496
- end
497
-
498
- def gamma number
499
- ensure_numeric Math.gamma number.to_number
500
- end
501
-
502
- def get_operator variable
503
- @parser.variables[variable.to_html].to_html
504
- end
505
-
506
- def greater_than numbers
507
- if numbers.empty?
508
- true_constant
509
- elsif numbers.length == 1
510
- true_constant
511
- else
512
- numbers[0].to_number > numbers[1].to_number and greater_than numbers.rest
513
- end
514
- end
515
-
516
- def greater_than_or_equal numbers
517
- if numbers.empty?
518
- true_constant
519
- elsif numbers.length == 1
520
- true_constant
521
- else
522
- numbers[0].to_number >= numbers[1].to_number and greater_than_or_equal numbers.rest
523
- end
524
- end
525
-
526
- def h1 expressions
527
- html_tag :h1, expressions
528
- end
529
-
530
- def h2 expressions
531
- html_tag :h2, expressions
532
- end
533
-
534
- def h3 expressions
535
- html_tag :h3, expressions
536
- end
537
-
538
- def h4 expressions
539
- html_tag :h4, expressions
540
- end
541
-
542
- def h5 expressions
543
- html_tag :h5, expressions
544
- end
545
-
546
- def h6 expressions
547
- html_tag :h6, expressions
548
- end
549
-
550
- def i
551
- command_error "Complex numbers are not yet supported."
552
- end
553
-
554
- def if_operator expressions
555
- expressions = strip expressions
556
- conditional, _, true_clause, _, false_clause = expressions
557
- if true_constant? conditional.to_html
558
- true_clause.to_html
559
- elsif false_clause
560
- false_clause.to_html
561
- end
562
- end
563
-
564
- def image expressions
565
- expressions = strip expressions
566
- uri, *alt_text = expressions
567
- uri = ERB::Util.html_escape uri.to_html
568
- if not valid_uri? uri
569
- command_error "Not a valid URI for the image."
570
- else
571
- if alt_text.empty?
572
- html_tag :img, nil, {src: uri}
573
- else
574
- html_tag :img, nil, {src: uri, alt: alt_text.map(&:to_html).join.strip}
575
- end
576
- end
577
- end
578
-
579
- def increment variable
580
- return variable_not_defined_error variable if not is_defined? variable
581
- old_value = get_operator(variable).to_number
582
- return non_numeric_error old_value if not numeric? old_value
583
- @parser.variables[variable.to_html] = old_value + 1
584
- end
585
-
586
- def it expressions
587
- html_tag :i, expressions
588
- end
589
-
590
- def item expressions
591
- html_tag :li, expressions
592
- end
593
-
594
- def itemize expressions
595
- html_tag :ul, expressions
596
- end
597
-
598
- def itemize_disc expressions
599
- html_tag :ul, expressions, {style: "list-style-type:disc"}
600
- end
601
-
602
- def itemize_circle expressions
603
- html_tag :ul, expressions, {style: "list-style-type:circle"}
604
- end
605
-
606
- def itemize_square expressions
607
- html_tag :ul, expressions, {style: "list-style-type:square"}
608
- end
609
-
610
- def itemize_none expressions
611
- html_tag :ul, expressions, {style: "list-style-type:none"}
612
- end
613
-
614
- def hypot numbers
615
- ensure_numeric Math.sqrt to_numbers(numbers).map {|n| n**2}
616
- end
617
-
618
- def keyword_id id
619
- id_command_handler id, :Keyword
620
- end
621
-
622
- def ld number
623
- ensure_numeric Math.log2 number.to_number
624
- end
625
-
626
- def ldexp fraction, exponent
627
- ensure_numeric Math.ldexp fraction.to_number, exponent.to_number
628
- end
629
-
630
114
  def left_brace
631
115
  "{"
632
116
  end
@@ -635,123 +119,10 @@ module Teepee
635
119
  "["
636
120
  end
637
121
 
638
- def less_than numbers
639
- if numbers.empty?
640
- true_constant
641
- elsif numbers.length == 1
642
- true_constant
643
- else
644
- numbers[0].to_number < numbers[1].to_number and less_than numbers.rest
645
- end
646
- end
647
-
648
- def less_than_or_equal numbers
649
- if numbers.empty?
650
- true_constant
651
- elsif numbers.length == 1
652
- true_constant
653
- else
654
- numbers[0].to_number <= numbers[1].to_number and less_than_or_equal numbers.rest
655
- end
656
- end
657
-
658
- def lgamma number
659
- ensure_numeric Math::lgamma(number.to_number).first
660
- end
661
-
662
- def link expressions
663
- expressions = strip expressions
664
- uri, *desc = expressions
665
- uri = ERB::Util.html_escape uri.to_html
666
- if not valid_uri? uri
667
- command_error "Not a valid URI."
668
- else
669
- desc = [uri] if desc.empty?
670
- html_tag :a, desc, {href: uri}
671
- end
672
- end
673
-
674
- def link_id id
675
- id_command_handler id, :Link
676
- end
677
-
678
- def ln number
679
- ensure_numeric Math.log number.to_number
680
- end
681
-
682
- def log base, number
683
- if number.nil?
684
- number, base = base, number
685
- ensure_numeric Math.log10 number.to_number # default to log base 10
686
- else
687
- ensure_numeric Math.log number.to_number, base.to_number
688
- end
689
- end
690
-
691
- def log10 number
692
- ensure_numeric Math.log10 number.to_number
693
- end
694
-
695
- def mailto email_address
696
- email_address = email_address.to_html
697
- if valid_email_address? email_address
698
- html_tag :a, [email_address], {href: "mailto:#{email_address}"}
699
- else
700
- command_error "I'm not sure that's a valid email address."
701
- end
702
- end
703
-
704
- def mod numbers
705
- ensure_numeric to_numbers(numbers).reduce :%
706
- end
707
-
708
- def nbsp count
709
- if count and count.to_number and count.to_number > 0
710
- "&nbsp;" * count.to_number
711
- else
712
- "&nbsp;"
713
- end
714
- end
715
-
716
- def not_equal numbers
717
- if numbers.empty?
718
- true_constant
719
- elsif numbers.length == 1
720
- true_constant
721
- else
722
- numbers[0].to_number != numbers[1].to_number and equal numbers.rest
723
- end
724
- end
725
-
726
- def note_id id
727
- id_command_handler id, :Note
728
- end
729
-
730
- def pi
731
- Math::PI
732
- end
733
-
734
122
  def pipe
735
123
  "|"
736
124
  end
737
125
 
738
- def prog1_operator expressions
739
- expressions.map(&:to_html).first
740
- end
741
-
742
- def progn_operator expressions
743
- expressions.map(&:to_html).last
744
- end
745
-
746
- def prognil expressions
747
- expressions.map(&:to_html)
748
- ""
749
- end
750
-
751
- def radians2degrees radians
752
- ensure_numeric(radians.to_number * 180.0 / Math::PI)
753
- end
754
-
755
126
  def right_brace
756
127
  "}"
757
128
  end
@@ -760,129 +131,12 @@ module Teepee
760
131
  "]"
761
132
  end
762
133
 
763
- def round number, precision = nil, *_
764
- if precision.nil? or precision.to_number.nil?
765
- ensure_numeric number.to_number.round
766
- else
767
- ensure_numeric number.to_number.round precision.to_number
768
- end
769
- end
770
-
771
- def sin angle
772
- ensure_numeric Math.sin angle.to_number
773
- end
774
-
775
- def sinh angle
776
- ensure_numeric Math.sinh angle.to_number
777
- end
778
-
779
- def small expressions
780
- html_tag :small, expressions
781
- end
782
-
783
134
  def squiggle
784
135
  "~"
785
136
  end
786
137
 
787
- def sqrt number
788
- ensure_numeric Math.sqrt number.to_number
789
- end
790
-
791
138
  def space
792
139
  " "
793
140
  end
794
-
795
- def span_operator expressions
796
- html_tag :span, expressions
797
- end
798
-
799
- def sub expressions
800
- html_tag :sub, expressions
801
- end
802
-
803
- def sup expressions
804
- html_tag :sup, expressions
805
- end
806
-
807
- def table expressions
808
- html_tag :table, expressions
809
- end
810
-
811
- def table_data expressions
812
- html_tag :td, expressions
813
- end
814
-
815
- def table_header expressions
816
- html_tag :th, expressions
817
- end
818
-
819
- def table_row expressions
820
- html_tag :tr, expressions
821
- end
822
-
823
- def tag_id id
824
- id_command_handler id, :Tag
825
- end
826
-
827
- def tan angle
828
- ensure_numeric Math.tan angle.to_number
829
- end
830
-
831
- def tanh angle
832
- ensure_numeric Math.tanh angle.to_number
833
- end
834
-
835
- def true_constant
836
- "true"
837
- end
838
-
839
- def tt expressions
840
- html_tag :tt, expressions
841
- end
842
-
843
- def u expressions
844
- html_tag :u, expressions
845
- end
846
-
847
- def undefine expressions
848
- expressions.each do |expression|
849
- @parser.variables.delete expression.to_html
850
- end
851
- ""
852
- end
853
-
854
- def unless_operator expressions
855
- expressions = strip expressions
856
- conditional = expressions.first
857
- expressions = strip expressions.rest
858
- if false_constant? conditional.to_html
859
- if expressions.length <= 1
860
- expressions.first
861
- else
862
- span_operator expressions
863
- end
864
- end
865
- end
866
-
867
- def user user
868
- if not user
869
- command_error "user: error: no user specified"
870
- else
871
- tb_href "users/#{user}", user.to_html
872
- end
873
- end
874
-
875
- def when_operator expressions
876
- expressions = strip expressions
877
- conditional = expressions.first
878
- expressions = strip expressions.rest
879
- if true_constant? conditional.to_html
880
- if expressions.length <= 1
881
- expressions.first
882
- else
883
- span_operator expressions
884
- end
885
- end
886
- end
887
141
  end
888
142
  end