teepee 0.6.0 → 0.7.0

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.
@@ -0,0 +1,89 @@
1
+ # -*- coding: utf-8 -*-
2
+ # -*- mode: Ruby -*-
3
+
4
+ # Copyright © 2013-2015, 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
+ require 'active_support/all'
39
+ require 'monkey-patch'
40
+
41
+ require 'teepee/constants'
42
+ require 'teepee/errors'
43
+ require 'teepee/commander'
44
+
45
+ include ERB::Util
46
+
47
+ module Teepee
48
+ class ActionableCommander < Commander
49
+ def initialize action_view, controller
50
+ @action_view = action_view
51
+ @controller = controller
52
+ end
53
+
54
+ def id_command_handler(id,
55
+ klass,
56
+ singular = klass.to_s.camelcase_to_snakecase,
57
+ plural = singular.pluralize,
58
+ partial = "#{plural}/inline",
59
+ view="")
60
+ if not id
61
+ command_error "#{singular}_id: error: no #{singular} ID specified"
62
+ elsif not id.to_s =~ /\A[0-9]+\z/
63
+ command_error "#{singular}_id: error: invalid #{singular} ID specified"
64
+ else
65
+ thing = klass.find Integer(id.to_s)
66
+ if thing
67
+ @@action_view.render partial: partial,
68
+ locals: {singular.to_sym => thing}
69
+ else
70
+ command_error "unknown #{singular} ID #{id.to_s}"
71
+ end
72
+ end
73
+ end
74
+
75
+ def user user
76
+ if not user
77
+ command_error "user: error: no user specified"
78
+ else
79
+ the_user = User.smart_find user.to_s
80
+ if the_user
81
+ @action_view.render partial: 'users/name_link',
82
+ locals: {the_user: the_user}
83
+ else
84
+ command_error "unknown user #{user.to_s}"
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,268 @@
1
+ # -*- coding: utf-8 -*-
2
+ # -*- mode: Ruby -*-
3
+
4
+ # Copyright © 2013-2015, 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
+ require 'active_support/all'
39
+ require 'monkey-patch'
40
+
41
+ require 'teepee/constants'
42
+ require 'teepee/errors'
43
+ require 'teepee/parser-node'
44
+ require 'teepee/commander'
45
+ require 'teepee/actionable-commander'
46
+
47
+ module Teepee
48
+ class CommandParser < ParserNode
49
+ attr_reader :command, :expressions
50
+
51
+ def initialize(command, expressions)
52
+ raise ArgumentError if not command.is_a? WordToken
53
+ @command = command
54
+ raise ArgumentError if not expressions.is_a? Array
55
+ expressions.each do |expression|
56
+ raise ArgumentError if not expression.kind_of? ParserNode
57
+ end
58
+ @expressions = expressions
59
+ end
60
+
61
+ def command_error(message)
62
+ %{<span style="color: red">[#{message}]</span>}
63
+ end
64
+
65
+ def to_html
66
+ case command.word
67
+ when "backslash", "bslash"
68
+ @@commander.backslash
69
+ when "left-brace",
70
+ "left_brace",
71
+ "leftbrace",
72
+ "lbrace",
73
+ "opening-brace",
74
+ "opening_brace",
75
+ "openingbrace",
76
+ "obrace"
77
+ @@commander.left_brace
78
+ when "right-brace",
79
+ "right_brace",
80
+ "rightbrace",
81
+ "rbrace",
82
+ "closing-brace",
83
+ "closing_brace",
84
+ "closingbrace",
85
+ "cbrace"
86
+ @@commander.right_brace
87
+ when "br", "newline"
88
+ @@commander.br
89
+ when "bold", "b", "textbf"
90
+ @@commander.b expressions
91
+ when "del",
92
+ "s",
93
+ "strike",
94
+ "strikethrough",
95
+ "strikeout"
96
+ @@commander.del expressions
97
+ when "i"
98
+ @@commander.i
99
+ when "italic",
100
+ "textit",
101
+ "it"
102
+ @@commander.it expressions
103
+ when "underline",
104
+ "u"
105
+ @@commander.u expressions
106
+ when "tt",
107
+ "texttt",
108
+ "teletype",
109
+ "typewriter"
110
+ @@commander.tt expressions
111
+ when "small"
112
+ @@commander.small expressions
113
+ when "big"
114
+ @@commander.big expressions
115
+ when "subscript",
116
+ "sub"
117
+ @@commander.sub expressions
118
+ when "superscript",
119
+ "sup"
120
+ @@commander.sup expressions
121
+ when "user",
122
+ "user-id",
123
+ "user_id"
124
+ @@commander.user first_word_token
125
+ when "link-id",
126
+ "link_id"
127
+ @@commander.link_id first_word_token
128
+ when "keyword-id",
129
+ "keyword_id"
130
+ @@commander.keyword_id first_word_token
131
+ when "tag-id",
132
+ "tag_id"
133
+ @@commander.tag_id first_word_token
134
+ when "forum-id",
135
+ "forum_id"
136
+ @@commander.forum_id first_word_token
137
+ when "folder-id",
138
+ "folder_id"
139
+ @@commander.folder_id first_word_token
140
+ when "bookmarks-folder-id",
141
+ "bookmarks_folder_id",
142
+ "bookmarks_folder-id",
143
+ "bookmarks-folder_id",
144
+ "bookmark-folder-id",
145
+ "bookmark_folder_id",
146
+ "bookmark_folder-id",
147
+ "bookmark-folder_id"
148
+ @@commander.bookmarks_folder_id first_word_token
149
+ when "pi"
150
+ @@commander.pi
151
+ when "e"
152
+ @@commander.e
153
+ when "+"
154
+ @@commander.+ *numbers_from_expressions
155
+ when "-"
156
+ @@commander.- *numbers_from_expressions
157
+ when "*"
158
+ @@commander.* *numbers_from_expressions
159
+ when "/"
160
+ @@commander./ *numbers_from_expressions
161
+ when "%"
162
+ @@commander.% *numbers_from_expressions
163
+ when "^", "**"
164
+ @@commander.** *numbers_from_expressions
165
+ when "sin", "cos", "tan",
166
+ "asin", "acos", "atan",
167
+ "sinh", "cosh", "tanh",
168
+ "asinh", "acosh", "atanh",
169
+ "erf", "erfc",
170
+ "gamma", "log10", "sqrt"
171
+ @@commander.send command.word.to_sym, number_from_expression
172
+ when "d2r",
173
+ "deg->rad",
174
+ "degrees->radians"
175
+ @@commander.degrees2radians number_from_expression
176
+ when "r2d",
177
+ "rad->deg",
178
+ "radians->degrees"
179
+ @@commander.radians2degrees number_from_expression
180
+ when "lgamma"
181
+ @@commander.lgamma number_from_expression
182
+ when "ld",
183
+ "log2"
184
+ @@commander.ld number_from_expression
185
+ when "ln"
186
+ @@commander.ln number_from_expression
187
+ when "log"
188
+ base, number = numbers_from_expressions
189
+ @@commander.log base, number
190
+ when "ldexp"
191
+ fraction, exponent = numbers_from_expressions
192
+ @@commander.ldexp fraction, exponent
193
+ when "hypot"
194
+ @@commander.hypot numbers_from_expressions
195
+ else
196
+ command_error "unknown command #{command.to_html}"
197
+ end
198
+ end
199
+
200
+ def html_tag(tag)
201
+ "<#{tag}>" + expressions.map(&:to_html).join + "</#{tag}>"
202
+ end
203
+
204
+ def tb_href(target, string)
205
+ %{<a href="#{TB_COM}/#{target}">#{string}</a>}
206
+ end
207
+
208
+ def first_word_token
209
+ expressions.select {|expr| expr.is_a? WordToken}.first
210
+ end
211
+
212
+ def numbers_from_expressions
213
+ expressions
214
+ .map do |number|
215
+ begin
216
+ Float(number.to_html)
217
+ rescue ArgumentError
218
+ nil
219
+ end
220
+ end.reject &:nil?
221
+ end
222
+
223
+ def number_from_expression
224
+ numbers_from_expressions.first
225
+ end
226
+
227
+ class << self
228
+ @@commander = Commander.new
229
+ @@action_view = nil
230
+ @@controller = nil
231
+
232
+ def parse(tokens)
233
+ expressions = []
234
+ rest = tokens
235
+ backslash, command, left_brace = rest.shift(3)
236
+ right_brace = nil
237
+ raise ParseError if not backslash.is_a? BackslashToken
238
+ raise ParseError if not command.is_a? WordToken
239
+ if not left_brace.is_a? LeftBraceToken # A command with no interior.
240
+ rest.unshift left_brace if not left_brace.is_a? WhitespaceToken
241
+ return [CommandParser.new(command, []), rest]
242
+ end
243
+ while rest.length > 0
244
+ if rest.first.is_a? WordToken
245
+ expressions << rest.shift
246
+ elsif rest.first.is_a? WhitespaceToken
247
+ expressions << rest.shift
248
+ elsif rest.first.is_a? BackslashToken
249
+ result, rest = CommandParser.parse(rest)
250
+ expressions << result
251
+ elsif rest.first.is_a? RightBraceToken
252
+ right_brace = rest.shift
253
+ return [CommandParser.new(command, expressions), rest]
254
+ else
255
+ raise ParseError
256
+ end
257
+ end
258
+ if right_brace.nil? # Allow a forgotten final right brace.
259
+ return [CommandParser.new(command, expressions), rest]
260
+ end
261
+ end
262
+
263
+ def commander= new
264
+ @@commander = new
265
+ end
266
+ end
267
+ end
268
+ end
@@ -0,0 +1,320 @@
1
+ # -*- coding: utf-8 -*-
2
+ # -*- mode: Ruby -*-
3
+
4
+ # Copyright © 2013-2015, 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
+ require 'active_support/all'
39
+ require 'monkey-patch'
40
+
41
+ require 'teepee/constants'
42
+ require 'teepee/errors'
43
+
44
+ include ERB::Util
45
+
46
+ module Teepee
47
+ class Commander
48
+ def command_error message
49
+ %{<span style="color: red">[#{message}]</span>}
50
+ end
51
+
52
+ def command_not_yet_implemented command
53
+ command_error "The command #{command} is not yet implemented."
54
+ end
55
+
56
+ def ensure_numeric number
57
+ if number.kind_of? Complex
58
+ command_error "Complex numbers are not yet supported."
59
+ elsif not number.kind_of? Numeric
60
+ command_error "Non-numeric result."
61
+ else
62
+ number
63
+ end
64
+ end
65
+
66
+ def html_tag tag, expressions
67
+ "<#{tag}>" + expressions.map(&:to_html).join + "</#{tag}>"
68
+ end
69
+
70
+ def tb_href target, string
71
+ %{<a href="#{TB_COM}/#{target}">#{string}</a>}
72
+ end
73
+
74
+ def id_command_handler(id,
75
+ klass,
76
+ singular = klass.to_s.camelcase_to_snakecase,
77
+ plural = singular.pluralize,
78
+ partial = "#{plural}/inline",
79
+ view="")
80
+ if not id
81
+ command_error "#{singular}_id: error: no #{singular} ID specified"
82
+ elsif not id.to_s =~ /\A[0-9]+\z/
83
+ command_error "#{singular}_id: error: invalid #{singular} ID specified"
84
+ else
85
+ tb_href "/#{plural}/#{id.to_s}/#{view}", "#{klass} ##{id.to_s}"
86
+ end
87
+ end
88
+
89
+ #----------------------------------------------------------------------------
90
+
91
+ def + *numbers
92
+ ensure_numeric numbers.inject 0, :+
93
+ end
94
+
95
+ def - *numbers
96
+ if numbers.length == 1
97
+ ensure_numeric -numbers.first
98
+ else
99
+ ensure_numeric numbers.reduce :-
100
+ end
101
+ end
102
+
103
+ def * *numbers
104
+ ensure_numeric numbers.inject 1, :*
105
+ end
106
+
107
+ def / *numbers
108
+ if numbers.length == 1
109
+ ensure_numeric 1 / numbers.first
110
+ else
111
+ ensure_numeric numbers.reduce :/
112
+ end
113
+ end
114
+
115
+ def % *numbers
116
+ ensure_numeric numbers.reduce :%
117
+ end
118
+
119
+ def ** *numbers
120
+ ensure_numeric numbers.reduce :**
121
+ end
122
+
123
+ def acos number
124
+ ensure_numeric Math.acos number
125
+ end
126
+
127
+ def acosh number
128
+ ensure_numeric Math.acosh number
129
+ end
130
+
131
+ def asin number
132
+ ensure_numeric Math.asin number
133
+ end
134
+
135
+ def asinh number
136
+ ensure_numeric Math.asinh number
137
+ end
138
+
139
+ def atan number
140
+ ensure_numeric Math.atan number
141
+ end
142
+
143
+ def atanh number
144
+ ensure_numeric Math.atanh number
145
+ end
146
+
147
+ def b expressions
148
+ html_tag :b, expressions
149
+ end
150
+
151
+ def backslash
152
+ "\\"
153
+ end
154
+
155
+ def big expressions
156
+ html_tag :big, expressions
157
+ end
158
+
159
+ def bookmarks_folder_id id
160
+ id_command_handler id, Folder, "folder", "folders", "folders/bookmarks_inline", "bookmarks"
161
+ end
162
+
163
+ def br
164
+ "\n</br>\n"
165
+ end
166
+
167
+ def cos angle
168
+ ensure_numeric Math.cos angle
169
+ end
170
+
171
+ def cosh number
172
+ ensure_numeric Math.cosh number
173
+ end
174
+
175
+ def degrees2radians degrees
176
+ ensure_numeric degrees * Math::PI / 180.0
177
+ end
178
+
179
+ def del expressions
180
+ html_tag :del, expressions
181
+ end
182
+
183
+ def e
184
+ Math::E
185
+ end
186
+
187
+ def erf number
188
+ ensure_numeric Math.erf number
189
+ end
190
+
191
+ def erfc number
192
+ ensure_numeric Math.erfc number
193
+ end
194
+
195
+ def folder_id id
196
+ id_command_handler id, Folder
197
+ end
198
+
199
+ def forum_id id
200
+ id_command_handler id, Forum
201
+ end
202
+
203
+ def gamma number
204
+ ensure_numeric Math.gamma number
205
+ end
206
+
207
+ def i
208
+ command_error "Complex numbers are not yet supported."
209
+ end
210
+
211
+ def it expressions
212
+ html_tag :i, expressions
213
+ end
214
+
215
+ def hypot numbers
216
+ ensure_numeric Math.sqrt numbers.map {|n| n**2}
217
+ end
218
+
219
+ def ld n
220
+ ensure_numeric Math.log2 n
221
+ end
222
+
223
+ def ldexp fraction, exponent
224
+ ensure_numeric Math.ldexp fraction, exponent
225
+ end
226
+
227
+ def left_brace
228
+ "{"
229
+ end
230
+
231
+ def lgamma n
232
+ ensure_numeric Math::lgamma(n).first
233
+ end
234
+
235
+ def link_id
236
+ id_command_handler id, Link
237
+ end
238
+
239
+ def ln number
240
+ ensure_numeric Math.log number
241
+ end
242
+
243
+ def log base, number
244
+ if number.nil?
245
+ number, base = base, number
246
+ ensure_numeric Math.log number # default to natural logarithm
247
+ else
248
+ ensure_numeric Math.log number, base
249
+ end
250
+ end
251
+
252
+ def log10 number
253
+ ensure_numeric Math.log10 number
254
+ end
255
+
256
+ def pi
257
+ Math::PI
258
+ end
259
+
260
+ def radians2degrees radians
261
+ ensure_numeric(radians * 180.0 / Math::PI)
262
+ end
263
+
264
+ def right_brace
265
+ "}"
266
+ end
267
+
268
+ def sin angle
269
+ ensure_numeric Math.sin angle
270
+ end
271
+
272
+ def sinh number
273
+ ensure_numeric Math.sinh number
274
+ end
275
+
276
+ def small expressions
277
+ html_tag :small, expressions
278
+ end
279
+
280
+ def sqrt number
281
+ ensure_numeric Math.sqrt number
282
+ end
283
+
284
+ def sub expressions
285
+ html_tag :sub, expressions
286
+ end
287
+
288
+ def sup expressions
289
+ html_tag :sup, expressions
290
+ end
291
+
292
+ def tag_id id
293
+ id_command_handler id, Tag
294
+ end
295
+
296
+ def tan angle
297
+ ensure_numeric Math.tan angle
298
+ end
299
+
300
+ def tanh number
301
+ ensure_numeric Math.tanh number
302
+ end
303
+
304
+ def tt expressions
305
+ html_tag :tt, expressions
306
+ end
307
+
308
+ def u expressions
309
+ html_tag :u, expressions
310
+ end
311
+
312
+ def user user
313
+ if not user
314
+ command_error "user: error: no user specified"
315
+ else
316
+ tb_href "users/#{user}", user.to_s
317
+ end
318
+ end
319
+ end
320
+ end