teepee 0.15.7 → 0.15.8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/teepee/commander-mixins/boolean.rb +147 -0
- data/lib/teepee/commander-mixins/control.rb +189 -0
- data/lib/teepee/commander-mixins/formatting.rb +206 -0
- data/lib/teepee/commander-mixins/mathematics.rb +296 -0
- data/lib/teepee/commander-mixins/thinking-bicycle-models.rb +134 -0
- data/lib/teepee/commander.rb +13 -759
- metadata +7 -2
@@ -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
|
data/lib/teepee/commander.rb
CHANGED
@@ -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
|
-
" " * count.to_number
|
711
|
-
else
|
712
|
-
" "
|
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
|