moron_text 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/Future-1.md +64 -0
- data/Future-2.md +56 -0
- data/Gemfile +3 -0
- data/LICENSE +23 -0
- data/README.md +38 -0
- data/VERSION +1 -0
- data/lib/moron_text.rb +382 -0
- data/moron_text.gemspec +31 -0
- data/specs/0000-parse.rb +50 -0
- data/specs/0010-run.rb +24 -0
- data/specs/0011-run_Class.rb +52 -0
- data/specs/0012-typo.rb +102 -0
- data/specs/0020-grab_text.rb +51 -0
- data/specs/0021-grab_prev_text.rb +46 -0
- data/specs/0030-return.rb +42 -0
- data/specs/0031-next.rb +57 -0
- data/specs/lib/helpers.rb +8 -0
- metadata +133 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 144d379141e2a6c2b6f27a3225fcd1a62f7df66f
|
4
|
+
data.tar.gz: df899b273eceefcab7b505dcbb0829055f2d015a
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 274084399d161b9ffb57091f3bbae6c49a0c6f1fad3b2202048736ee92b47c8706723923f508be7fbd7e45c702535742c07b8eb0084be043e5067b52e85d2842
|
7
|
+
data.tar.gz: 2ebae11133e9839546d02de3f6ba76f5e26fe871c2fc739c50605e47c408e3d5118baa404824bfc9d1a4020921d82162584f6a82787dab5b61289ce297986b22
|
data/.gitignore
ADDED
data/Future-1.md
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
|
2
|
+
# Syntax:
|
3
|
+
|
4
|
+
TEXT : InTRO
|
5
|
+
|
6
|
+
In the far east corner of the Galos Building...
|
7
|
+
|
8
|
+
TEXT : OuTRO ----------------
|
9
|
+
We end with a swipe towards the past...
|
10
|
+
!InTRO
|
11
|
+
!POS
|
12
|
+
--------------------------
|
13
|
+
|
14
|
+
ABOUT : first-guess
|
15
|
+
ON : apple
|
16
|
+
|
|
17
|
+
| PUT "100,100" into POS
|
18
|
+
|
|
19
|
+
| BLOCK : MOVE_CARD
|
20
|
+
| | SET the location of card button x to POS
|
21
|
+
| | ADD 15 to item 1 of POS
|
22
|
+
| |---
|
23
|
+
|
|
24
|
+
| REPEAT with x = 1 to the number of card buttons
|
25
|
+
| | MOVE_CARD .
|
26
|
+
| | PLAY_HARD .
|
27
|
+
| | DIE_HARD .
|
28
|
+
| | LIVE_HARD .
|
29
|
+
| |---
|
30
|
+
|
|
31
|
+
| REPEAT with x = 1 to the number of card buttons
|
32
|
+
| | SET the location of card button x to POS
|
33
|
+
| | ADD 15 to item 1 of POS
|
34
|
+
| |---
|
35
|
+
|
|
36
|
+
| ADD 15 to item 1 of POS
|
37
|
+
| ALERT : InTRO
|
38
|
+
| OuTRO .
|
39
|
+
| REPLACE : !POS POS
|
40
|
+
| REPLACE : !InTRO InTRO
|
41
|
+
| ALERT .
|
42
|
+
|---
|
43
|
+
|
44
|
+
ON FIRST TRUE :
|
45
|
+
|
|
46
|
+
| |---
|
47
|
+
| | ARR size > 2
|
48
|
+
| |---
|
49
|
+
| | DO SOMETHING .
|
50
|
+
| |---
|
51
|
+
|
|
52
|
+
| |---
|
53
|
+
| | ARR size < 5
|
54
|
+
| |---
|
55
|
+
| | DO SOMETHING ELSE.
|
56
|
+
| |---
|
57
|
+
|
|
58
|
+
| |---
|
59
|
+
| | DEFAULT .
|
60
|
+
| |---
|
61
|
+
|
|
62
|
+
|---
|
63
|
+
|
64
|
+
|
data/Future-2.md
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
|
2
|
+
## Example: Form that saves a record.
|
3
|
+
|
4
|
+
Which is your favorite fruit?
|
5
|
+
( ) apple
|
6
|
+
| I like apples too!
|
7
|
+
( ) orange
|
8
|
+
| I hate oranges. Blah!
|
9
|
+
( ) round
|
10
|
+
| ( ) prune
|
11
|
+
| ( ) raisin
|
12
|
+
| ( ) grapes
|
13
|
+
MERGE : previous answers
|
14
|
+
( ) Other.
|
15
|
+
|* Other: [___]
|
16
|
+
|
17
|
+
{ Send }
|
18
|
+
|
19
|
+
WHEN : Other: [xxx]
|
20
|
+
Cool... I never heard of ^X.
|
21
|
+
|
22
|
+
## Example: Arithmetic Calculator
|
23
|
+
|
24
|
+
[| STACK |]
|
25
|
+
{ 0 ... 9 . } || { + }
|
26
|
+
|| { - }
|
27
|
+
|| { * }
|
28
|
+
|| { / }
|
29
|
+
=======================
|
30
|
+
{ = }
|
31
|
+
|
32
|
+
ON : CLICK NUMBER
|
33
|
+
VALUE -> [| STACK |] .
|
34
|
+
" " -> [| STACK |] .
|
35
|
+
|
36
|
+
ON : CLICK NON-ALPHA-NUM AND NOT =
|
37
|
+
VALUE -> [| STACK |] .
|
38
|
+
" " -> [| STACK |] .
|
39
|
+
|
40
|
+
ON : CLICK =
|
41
|
+
MATH-EVAL : LAST 3 .
|
42
|
+
|
43
|
+
## Example:
|
44
|
+
|
45
|
+
ON : any wrong answer
|
46
|
+
SHOW PICTURE : http://www..../failure.jpg
|
47
|
+
|
48
|
+
ON : final right answer
|
49
|
+
|
50
|
+
You got it! Wait while I show you your secret
|
51
|
+
admirer.
|
52
|
+
|
53
|
+
Please wait a few seconds:
|
54
|
+
|
55
|
+
WAIT AND SHOW CLOCK : 5 secs
|
56
|
+
GO TO : http://www../admirer
|
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
|
2
|
+
Copyright (c) 2014 da99
|
3
|
+
|
4
|
+
MIT License
|
5
|
+
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
7
|
+
a copy of this software and associated documentation files (the
|
8
|
+
"Software"), to deal in the Software without restriction, including
|
9
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
10
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
11
|
+
permit persons to whom the Software is furnished to do so, subject to
|
12
|
+
the following conditions:
|
13
|
+
|
14
|
+
The above copyright notice and this permission notice shall be
|
15
|
+
included in all copies or substantial portions of the Software.
|
16
|
+
|
17
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
18
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
19
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
20
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
21
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
22
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
23
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
|
2
|
+
# Note:
|
3
|
+
|
4
|
+
This is not ready yet.
|
5
|
+
|
6
|
+
# Installation
|
7
|
+
|
8
|
+
gem 'moron_text'
|
9
|
+
|
10
|
+
# Moron\_Text
|
11
|
+
|
12
|
+
## Example: Menu
|
13
|
+
|
14
|
+
```ruby
|
15
|
+
moron = Moron_Text.new(<<-EOF)
|
16
|
+
CORRECT /*
|
17
|
+
This is the right answer.
|
18
|
+
WRONG /*
|
19
|
+
This is the 1st wrong answer.
|
20
|
+
WRONG /*
|
21
|
+
This is the 2nd wrong answer.
|
22
|
+
WRONG /*
|
23
|
+
This is the 3rd wrong answer.
|
24
|
+
ON /* CORRECT
|
25
|
+
You chose wisely.
|
26
|
+
EOF
|
27
|
+
|
28
|
+
moron.run do | name, line, text |
|
29
|
+
case name
|
30
|
+
when 'CORRECT'
|
31
|
+
when 'WRONG'
|
32
|
+
when 'ON'
|
33
|
+
else
|
34
|
+
text.next
|
35
|
+
end
|
36
|
+
end
|
37
|
+
```
|
38
|
+
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
1.0.0
|
data/lib/moron_text.rb
ADDED
@@ -0,0 +1,382 @@
|
|
1
|
+
|
2
|
+
require "about_pos"
|
3
|
+
|
4
|
+
class Moron_Text
|
5
|
+
|
6
|
+
SPACE = ' '.freeze
|
7
|
+
DELIM = "\\s+" + Regexp.escape("/*")
|
8
|
+
|
9
|
+
PATTERNS = {
|
10
|
+
:command__arg => [
|
11
|
+
%r!\A\s*(.+)#{DELIM}\s+(.+)\Z!,
|
12
|
+
:value, :arg
|
13
|
+
],
|
14
|
+
|
15
|
+
:command => [
|
16
|
+
/\A\s*(.+)#{DELIM}\s*\Z/,
|
17
|
+
:value
|
18
|
+
]
|
19
|
+
}
|
20
|
+
|
21
|
+
NEW_LINE_REG_EXP = /\r?\n/
|
22
|
+
NL = "\n".freeze
|
23
|
+
TYPO = Class.new(RuntimeError) do
|
24
|
+
|
25
|
+
attr_reader :moron, :line_number
|
26
|
+
|
27
|
+
def initialize moron, text = "Typo"
|
28
|
+
super text
|
29
|
+
@moron = moron
|
30
|
+
@line_number = @moron.line_number
|
31
|
+
end
|
32
|
+
|
33
|
+
def line
|
34
|
+
moron.lines[line_number-1]
|
35
|
+
end
|
36
|
+
|
37
|
+
def line_context
|
38
|
+
start = line_number - 3 - 1
|
39
|
+
stop = line_number + 3 - 1
|
40
|
+
start = 0 if start < 0
|
41
|
+
i = start
|
42
|
+
moron.lines.slice(start, stop - start).map { |o|
|
43
|
+
i += 1
|
44
|
+
[i, o]
|
45
|
+
}
|
46
|
+
end
|
47
|
+
end # === Class TYPO
|
48
|
+
|
49
|
+
MISSING_KEY = lambda { |hash, key|
|
50
|
+
fail RuntimeError, "Missing key: #{key.inspect}"
|
51
|
+
}
|
52
|
+
|
53
|
+
class << self
|
54
|
+
|
55
|
+
def standard_name n
|
56
|
+
n.split.map(&:upcase).join(SPACE)
|
57
|
+
end
|
58
|
+
|
59
|
+
def run *args
|
60
|
+
case
|
61
|
+
|
62
|
+
when block_given?
|
63
|
+
@run_lambda = lambda { |*args| yield(*args) }
|
64
|
+
|
65
|
+
when args.size == 3
|
66
|
+
args.last.next unless @run_lambda
|
67
|
+
@run_lambda.call(*args)
|
68
|
+
|
69
|
+
when args.size == 1 && args.first.is_a?(Proc)
|
70
|
+
@run_lambda = args.first
|
71
|
+
|
72
|
+
else
|
73
|
+
fail "Unknown args: #{args.inspect}"
|
74
|
+
|
75
|
+
end # === case
|
76
|
+
end
|
77
|
+
|
78
|
+
end # === class self ===
|
79
|
+
|
80
|
+
attr_reader :lines, :parsed_lines, :stack, :defs
|
81
|
+
|
82
|
+
def initialize str
|
83
|
+
@str = str
|
84
|
+
@lines = nil
|
85
|
+
@parsed_lines = nil
|
86
|
+
@stack = nil
|
87
|
+
@has_run = false
|
88
|
+
@defs = {}
|
89
|
+
@line_number = nil
|
90
|
+
@parsed_line_number = nil
|
91
|
+
@next_parse_line = nil
|
92
|
+
@settings = {}
|
93
|
+
@settings.default_proc = MISSING_KEY
|
94
|
+
end # === def initialize
|
95
|
+
|
96
|
+
def turn_on sym
|
97
|
+
@settings[sym] = true
|
98
|
+
end
|
99
|
+
|
100
|
+
def turn_off sym
|
101
|
+
@settings[sym] = false
|
102
|
+
end
|
103
|
+
|
104
|
+
def on? sym
|
105
|
+
if !@settings.has_key?(sym)
|
106
|
+
@settings[sym] = false
|
107
|
+
end
|
108
|
+
|
109
|
+
if @settings[sym] != true && @settings[sym] != false
|
110
|
+
fail "Invalid type for: #{sym.inspect}: #{settings[sym].inspect}"
|
111
|
+
end
|
112
|
+
|
113
|
+
@settings[sym]
|
114
|
+
end
|
115
|
+
|
116
|
+
def off? sym
|
117
|
+
if !@settings.has_key?(sym)
|
118
|
+
@settings[sym] = false
|
119
|
+
end
|
120
|
+
|
121
|
+
!on?[sym]
|
122
|
+
end
|
123
|
+
|
124
|
+
def []= k, v
|
125
|
+
@settings[k] = v
|
126
|
+
end
|
127
|
+
|
128
|
+
def [] k
|
129
|
+
@settings[k]
|
130
|
+
end
|
131
|
+
|
132
|
+
def typo!
|
133
|
+
throw :moron_flow, :typo
|
134
|
+
end
|
135
|
+
|
136
|
+
def typo msg
|
137
|
+
TYPO.new(self, msg)
|
138
|
+
end
|
139
|
+
|
140
|
+
def line_number
|
141
|
+
current[:line_number]
|
142
|
+
end
|
143
|
+
|
144
|
+
def current
|
145
|
+
@parsed_lines[@parsed_line_number]
|
146
|
+
end
|
147
|
+
|
148
|
+
def grab_prev_text
|
149
|
+
prev_text
|
150
|
+
end
|
151
|
+
|
152
|
+
def prev_text
|
153
|
+
fail typo("Missing previous text for line.") unless @seq.prev?
|
154
|
+
prev = @seq.prev.value
|
155
|
+
fail typo("Missing previous text for line.") unless prev[:type] == :text
|
156
|
+
prev[:value]
|
157
|
+
end
|
158
|
+
|
159
|
+
def grab_text
|
160
|
+
val = text
|
161
|
+
@seq.grab
|
162
|
+
val
|
163
|
+
end
|
164
|
+
|
165
|
+
def text
|
166
|
+
fail typo("Missing text for line.") unless @seq.next?
|
167
|
+
|
168
|
+
next_ = @seq.next.value
|
169
|
+
fail typo("Missing text for line.") unless next_[:type] == :text
|
170
|
+
|
171
|
+
next_[:value]
|
172
|
+
end
|
173
|
+
|
174
|
+
def split
|
175
|
+
current[:arg].split
|
176
|
+
end
|
177
|
+
|
178
|
+
def numbers
|
179
|
+
split.map { |u|
|
180
|
+
begin
|
181
|
+
Float(u)
|
182
|
+
rescue ArguementError
|
183
|
+
fail typo("Numerical typo.")
|
184
|
+
end
|
185
|
+
}
|
186
|
+
end
|
187
|
+
|
188
|
+
def fulfills? cond
|
189
|
+
parsed = current
|
190
|
+
About_Pos.Forward(cond).all? { |v,i,m|
|
191
|
+
args = m.grab
|
192
|
+
case v
|
193
|
+
when :on
|
194
|
+
args.any? { |on_name| on?(on_name) }
|
195
|
+
when :value
|
196
|
+
args.any? { |v| parsed[:value] == v }
|
197
|
+
else
|
198
|
+
fail "Typo: #{v.inspect}"
|
199
|
+
end
|
200
|
+
}
|
201
|
+
end
|
202
|
+
|
203
|
+
def next
|
204
|
+
throw :moron_flow, :next
|
205
|
+
end
|
206
|
+
|
207
|
+
def return *args
|
208
|
+
@stack.concat args
|
209
|
+
throw :moron_flow, :ignore
|
210
|
+
end
|
211
|
+
|
212
|
+
def run l = nil
|
213
|
+
return @stack if @has_run
|
214
|
+
|
215
|
+
parse
|
216
|
+
@stack = []
|
217
|
+
@line_number = 0
|
218
|
+
|
219
|
+
About_Pos.Forward(@parsed_lines) { |line, i, m|
|
220
|
+
@parsed_line_number = i
|
221
|
+
@seq = m
|
222
|
+
|
223
|
+
case line[:type]
|
224
|
+
|
225
|
+
when :text
|
226
|
+
line
|
227
|
+
|
228
|
+
when :command
|
229
|
+
if line.has_key?(:grab_all_text)
|
230
|
+
line[:text] = [
|
231
|
+
(line.has_key?(:text) ? line[:text] : nil),
|
232
|
+
(m.next? && m.next.value[:type] == :text ? m.grab[:value] : nil)
|
233
|
+
].
|
234
|
+
compact.
|
235
|
+
join(NL)
|
236
|
+
end
|
237
|
+
|
238
|
+
if line.has_key?(:allow)
|
239
|
+
case
|
240
|
+
when line[:allow].all? { |c| c.is_a?(Array) }
|
241
|
+
line[:allow].detect { |cond,i,m| fulfills? cond }
|
242
|
+
else
|
243
|
+
fulfills? line[:allow]
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
args = [line[:value], line, self]
|
248
|
+
val = nil
|
249
|
+
do_next = :next
|
250
|
+
|
251
|
+
if block_given?
|
252
|
+
do_next = catch(:moron_flow) { val = yield(*args) }
|
253
|
+
end
|
254
|
+
|
255
|
+
if do_next == :next && l
|
256
|
+
do_next = catch(:moron_flow) { val = l.call(*args) }
|
257
|
+
end
|
258
|
+
|
259
|
+
if do_next == :next
|
260
|
+
do_next = catch(:moron_flow) { val = self.class.run(*args) }
|
261
|
+
end
|
262
|
+
|
263
|
+
fail(typo "Typo: #{line[:value]}") if do_next == :typo || do_next == :next
|
264
|
+
(@stack << val) unless do_next == :ignore
|
265
|
+
|
266
|
+
else
|
267
|
+
fail "Programmer error: #{line[:type].inspect}"
|
268
|
+
|
269
|
+
end # case line[:type]
|
270
|
+
|
271
|
+
} # === About_Pos
|
272
|
+
|
273
|
+
@has_run = true
|
274
|
+
@stack
|
275
|
+
end
|
276
|
+
|
277
|
+
def meta_line type, val
|
278
|
+
{
|
279
|
+
:type =>type,
|
280
|
+
:value =>val,
|
281
|
+
:original =>@lines[@parse_index-1],
|
282
|
+
:line_number =>@parse_index,
|
283
|
+
:is_closed =>false,
|
284
|
+
:arg =>nil
|
285
|
+
}
|
286
|
+
end
|
287
|
+
|
288
|
+
def parse
|
289
|
+
return @parsed_lines if @parsed_lines
|
290
|
+
|
291
|
+
@lines = @str.split(NEW_LINE_REG_EXP)
|
292
|
+
@parse_index = 0
|
293
|
+
|
294
|
+
@parsed_lines = []
|
295
|
+
|
296
|
+
# === Pass 1: Create an array of commands and text.
|
297
|
+
@lines.each { |line|
|
298
|
+
|
299
|
+
@parse_index += 1
|
300
|
+
parsed = nil
|
301
|
+
|
302
|
+
is_command = PATTERNS.detect { |name, pattern|
|
303
|
+
match = line.match pattern.first
|
304
|
+
next unless match
|
305
|
+
captures = match.captures
|
306
|
+
shift_capture = lambda {
|
307
|
+
fail "Captures already empty: #{name.inspect}" if captures.empty?
|
308
|
+
captures.shift
|
309
|
+
}
|
310
|
+
|
311
|
+
parsed = meta_line(:command, nil)
|
312
|
+
start = 0
|
313
|
+
step = start
|
314
|
+
stop = pattern.size
|
315
|
+
capture_i = 0
|
316
|
+
while step < (stop-1)
|
317
|
+
grab_next = lambda {
|
318
|
+
step += 1
|
319
|
+
fail("No more items.") if step >= stop
|
320
|
+
pattern[step]
|
321
|
+
}
|
322
|
+
|
323
|
+
val = grab_next.call
|
324
|
+
next if step == start
|
325
|
+
|
326
|
+
case val
|
327
|
+
|
328
|
+
when :value
|
329
|
+
if parsed[:type] == :command
|
330
|
+
parsed[:value] = Moron_Text.standard_name shift_capture.call
|
331
|
+
else
|
332
|
+
parsed[:value] = shift_capture.call
|
333
|
+
end
|
334
|
+
|
335
|
+
when :arg
|
336
|
+
parsed[:arg] = shift_capture.call
|
337
|
+
|
338
|
+
when :is_closed
|
339
|
+
parsed[:is_closed] = true
|
340
|
+
|
341
|
+
when :allow
|
342
|
+
parsed[:allow] = grab_next.call
|
343
|
+
|
344
|
+
when :grab_all_text
|
345
|
+
parsed[:grab_all_text] = true
|
346
|
+
parsed[:text] = captures.compact.join ' '.freeze
|
347
|
+
|
348
|
+
else
|
349
|
+
fail "Typo: unknown pattern command: #{val.inspect}"
|
350
|
+
|
351
|
+
end # case val
|
352
|
+
end # while step < stop
|
353
|
+
|
354
|
+
match
|
355
|
+
} # detect if is command?
|
356
|
+
|
357
|
+
if !is_command
|
358
|
+
parsed = meta_line(:text, line.dup)
|
359
|
+
end
|
360
|
+
|
361
|
+
parsed.default_proc = MISSING_KEY
|
362
|
+
@parsed_lines << parsed
|
363
|
+
|
364
|
+
}
|
365
|
+
|
366
|
+
# === PASS 2: combine text, strip it
|
367
|
+
lines = []
|
368
|
+
About_Pos.Forward(@parsed_lines) { |o, i, m|
|
369
|
+
if o[:type] == :text
|
370
|
+
while m.next? && m.next.value[:type] == :text
|
371
|
+
o[:value] << NL
|
372
|
+
o[:value] << m.grab[:value]
|
373
|
+
end
|
374
|
+
o[:value].strip!
|
375
|
+
end
|
376
|
+
lines << o
|
377
|
+
}
|
378
|
+
|
379
|
+
@parsed_lines = lines
|
380
|
+
end # === def parse
|
381
|
+
|
382
|
+
end # === class Moron_Text ===
|
data/moron_text.gemspec
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "moron_text"
|
7
|
+
spec.version = `cat VERSION`
|
8
|
+
spec.authors = ["da99"]
|
9
|
+
spec.email = ["i-hate-spam-1234567@mailinator.com"]
|
10
|
+
spec.summary = %q{A DSL for WWW mini-apps.}
|
11
|
+
spec.description = %q{
|
12
|
+
It won't be useful for you. It is meant to be
|
13
|
+
used with the WWW_App gem.
|
14
|
+
}
|
15
|
+
spec.homepage = "https://github.com/da99/moron_text"
|
16
|
+
spec.license = "MIT"
|
17
|
+
|
18
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |file|
|
19
|
+
file.index('bin/') == 0 && file != "bin/#{File.basename Dir.pwd}"
|
20
|
+
}
|
21
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
22
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
23
|
+
spec.require_paths = ["lib"]
|
24
|
+
|
25
|
+
spec.add_dependency "about_pos" , ">= 2.0.0"
|
26
|
+
|
27
|
+
spec.add_development_dependency "pry" , "~> 0.9"
|
28
|
+
spec.add_development_dependency "bundler" , "~> 1.5"
|
29
|
+
spec.add_development_dependency "bacon" , "~> 1.0"
|
30
|
+
spec.add_development_dependency "Bacon_Colored" , "~> 0.1"
|
31
|
+
end
|
data/specs/0000-parse.rb
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
|
2
|
+
describe ":parse" do
|
3
|
+
|
4
|
+
it "returns an array describing the text" do
|
5
|
+
o = Moron_Text.new(<<-EOF)
|
6
|
+
MENU /* My Title
|
7
|
+
This is some text.
|
8
|
+
MENU2 /* arg arg
|
9
|
+
MENU3 /*
|
10
|
+
More text
|
11
|
+
content.
|
12
|
+
EOF
|
13
|
+
|
14
|
+
o.parse.map { |line|
|
15
|
+
line.values_at(:type, :value, :arg)
|
16
|
+
}.should == [
|
17
|
+
[:command, 'MENU', 'My Title'],
|
18
|
+
[:text, "This is some text.", nil],
|
19
|
+
[:command, 'MENU2', 'arg arg'],
|
20
|
+
[:command, 'MENU3', nil],
|
21
|
+
[:text, "More text\n content.", nil]
|
22
|
+
]
|
23
|
+
end
|
24
|
+
|
25
|
+
it "parses stripped text" do
|
26
|
+
o = Moron_Text.new(trim <<-EOF)
|
27
|
+
CMD /*
|
28
|
+
some text
|
29
|
+
EOF
|
30
|
+
|
31
|
+
o.parse.map { |line|
|
32
|
+
line.values_at(:type, :value)
|
33
|
+
}.should == [
|
34
|
+
[:command, 'CMD'],
|
35
|
+
[:text, 'some text']
|
36
|
+
]
|
37
|
+
end
|
38
|
+
|
39
|
+
it "parses the following as a command: CMD :" do
|
40
|
+
o = Moron_Text.new(<<-EOF)
|
41
|
+
CMD /*
|
42
|
+
some text
|
43
|
+
EOF
|
44
|
+
|
45
|
+
o.parse.map { |line|
|
46
|
+
line[:type]
|
47
|
+
}.should == [:command, :text]
|
48
|
+
end
|
49
|
+
|
50
|
+
end # === describe ":parse"
|
data/specs/0010-run.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
|
2
|
+
describe :run do
|
3
|
+
|
4
|
+
it "runs the text as code" do
|
5
|
+
o = Moron_Text.new(<<-EOF)
|
6
|
+
ADD /* 1 2 3
|
7
|
+
SUBTRACT /* 100 5 5
|
8
|
+
EOF
|
9
|
+
|
10
|
+
o.run do |name, line, moron|
|
11
|
+
case name
|
12
|
+
when 'ADD'
|
13
|
+
moron.numbers.reduce(:+)
|
14
|
+
when 'SUBTRACT'
|
15
|
+
moron.numbers.reduce(:-)
|
16
|
+
else
|
17
|
+
moron.next
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
o.stack.should == [6, 90]
|
22
|
+
end
|
23
|
+
|
24
|
+
end # === describe ":run"
|
@@ -0,0 +1,52 @@
|
|
1
|
+
|
2
|
+
describe ":run Class" do
|
3
|
+
|
4
|
+
it "runs given block on commands" do
|
5
|
+
stack = []
|
6
|
+
|
7
|
+
c = Class.new(Moron_Text)
|
8
|
+
c.run { |name, line, moron|
|
9
|
+
stack << [name, line[:arg]]
|
10
|
+
}
|
11
|
+
|
12
|
+
o = c.new(<<-EOF)
|
13
|
+
BLADE_1 /* 1 2 3
|
14
|
+
BLADE_2 /* 100 5 5
|
15
|
+
EOF
|
16
|
+
|
17
|
+
o.run
|
18
|
+
|
19
|
+
stack.should == [
|
20
|
+
['BLADE_1', '1 2 3'],
|
21
|
+
['BLADE_2', '100 5 5'],
|
22
|
+
]
|
23
|
+
end
|
24
|
+
|
25
|
+
it "runs given block if instance .run block uses .next" do
|
26
|
+
stack = []
|
27
|
+
|
28
|
+
c = Class.new(Moron_Text)
|
29
|
+
c.run { |name, line, moron|
|
30
|
+
stack << [name, line[:arg]]
|
31
|
+
}
|
32
|
+
|
33
|
+
o = c.new(<<-EOF)
|
34
|
+
BLADE_1 /* 1
|
35
|
+
BLADE_2 /* c
|
36
|
+
EOF
|
37
|
+
|
38
|
+
o.run { |name, line, moron|
|
39
|
+
stack << "instance"
|
40
|
+
moron.next
|
41
|
+
fail "Not reachable"
|
42
|
+
}
|
43
|
+
|
44
|
+
stack.should == [
|
45
|
+
"instance",
|
46
|
+
['BLADE_1', '1'],
|
47
|
+
"instance",
|
48
|
+
['BLADE_2', 'c'],
|
49
|
+
]
|
50
|
+
end
|
51
|
+
|
52
|
+
end # === describe ":run Class"
|
data/specs/0012-typo.rb
ADDED
@@ -0,0 +1,102 @@
|
|
1
|
+
|
2
|
+
describe :typo do
|
3
|
+
|
4
|
+
it "raises a TYPO" do
|
5
|
+
o = Moron_Text.new(<<-EOF)
|
6
|
+
DUCK /* a
|
7
|
+
Quack
|
8
|
+
EOF
|
9
|
+
|
10
|
+
lambda {
|
11
|
+
o.run do |name, line, moron|
|
12
|
+
fail moron.typo('blah') if name == 'DUCK'
|
13
|
+
end
|
14
|
+
}.should.raise(Moron_Text::TYPO).
|
15
|
+
message.should.match /blah/
|
16
|
+
end
|
17
|
+
|
18
|
+
it "returns a TYPO with :line" do
|
19
|
+
o = Moron_Text.new(trim <<-EOF)
|
20
|
+
GOOSE /*
|
21
|
+
Line 2
|
22
|
+
Line 3
|
23
|
+
DUCK /*
|
24
|
+
Line 5
|
25
|
+
EOF
|
26
|
+
|
27
|
+
lambda {
|
28
|
+
o.run do |name, line, moron|
|
29
|
+
case name
|
30
|
+
when 'GOOSE'
|
31
|
+
"done"
|
32
|
+
when 'DUCK'
|
33
|
+
fail moron.typo('blah 1')
|
34
|
+
else
|
35
|
+
moron.typo!
|
36
|
+
end
|
37
|
+
end
|
38
|
+
}.
|
39
|
+
should.raise(Moron_Text::TYPO).
|
40
|
+
line.should == 'DUCK /*'
|
41
|
+
end
|
42
|
+
|
43
|
+
it "returns a TYPO with :line_number" do
|
44
|
+
o = Moron_Text.new(<<-EOF)
|
45
|
+
GOOSE /*
|
46
|
+
Line 2
|
47
|
+
Line 3
|
48
|
+
DUCK /*
|
49
|
+
Line 5
|
50
|
+
EOF
|
51
|
+
|
52
|
+
lambda {
|
53
|
+
o.run do |name, line, moron|
|
54
|
+
case name
|
55
|
+
when 'GOOSE'
|
56
|
+
"done"
|
57
|
+
when 'DUCK'
|
58
|
+
fail moron.typo('blah 2')
|
59
|
+
else
|
60
|
+
moron.typo!
|
61
|
+
end
|
62
|
+
end
|
63
|
+
}.
|
64
|
+
should.raise(Moron_Text::TYPO).
|
65
|
+
line_number.should == 4
|
66
|
+
end # === it returns a TYPO with :line_number
|
67
|
+
|
68
|
+
it 'returns a TYPO with :line_context' do
|
69
|
+
o = Moron_Text.new(<<-EOF)
|
70
|
+
GOOSE /*
|
71
|
+
Line 2
|
72
|
+
Line 3
|
73
|
+
DUCK /*
|
74
|
+
Line 5
|
75
|
+
EOF
|
76
|
+
space = ' '
|
77
|
+
|
78
|
+
lambda {
|
79
|
+
o.run do |name, line, moron|
|
80
|
+
case name
|
81
|
+
when 'GOOSE'
|
82
|
+
"done"
|
83
|
+
when 'DUCK'
|
84
|
+
fail moron.typo('blah 3')
|
85
|
+
else
|
86
|
+
moron.typo!
|
87
|
+
end
|
88
|
+
end
|
89
|
+
}.
|
90
|
+
should.raise(Moron_Text::TYPO).
|
91
|
+
line_context.should == [
|
92
|
+
[1, "#{space}GOOSE /*"],
|
93
|
+
[2, "#{space} Line 2"],
|
94
|
+
[3, "#{space} Line 3"],
|
95
|
+
[4, "#{space}DUCK /*"],
|
96
|
+
[5, "#{space} Line 5"]
|
97
|
+
]
|
98
|
+
end
|
99
|
+
|
100
|
+
end # === describe :typo
|
101
|
+
|
102
|
+
|
@@ -0,0 +1,51 @@
|
|
1
|
+
|
2
|
+
describe :grab_text do
|
3
|
+
|
4
|
+
it "pops the following text" do
|
5
|
+
o = Moron_Text.new(<<-EOF)
|
6
|
+
DUCK /*
|
7
|
+
QUACK
|
8
|
+
BIRD /*
|
9
|
+
Whistle
|
10
|
+
EOF
|
11
|
+
|
12
|
+
sounds = []
|
13
|
+
o.run do |name, line, moron|
|
14
|
+
case name
|
15
|
+
when 'DUCK'
|
16
|
+
sounds << moron.grab_text
|
17
|
+
when 'BIRD'
|
18
|
+
sounds << moron.grab_text
|
19
|
+
else
|
20
|
+
moron.typo!
|
21
|
+
end
|
22
|
+
end
|
23
|
+
sounds.should == %w{ QUACK Whistle }
|
24
|
+
end
|
25
|
+
|
26
|
+
it "pops multiple lines of text" do
|
27
|
+
o = Moron_Text.new(<<-EOF)
|
28
|
+
DUCK /*
|
29
|
+
|
30
|
+
This is one line.
|
31
|
+
|
32
|
+
This is another line.
|
33
|
+
|
34
|
+
EOF
|
35
|
+
|
36
|
+
txt = nil
|
37
|
+
o.run { |name, line, moron|
|
38
|
+
if name == 'DUCK'
|
39
|
+
txt = moron.grab_text
|
40
|
+
else
|
41
|
+
moron.typo!
|
42
|
+
end
|
43
|
+
}
|
44
|
+
txt.should == <<-EOF.strip
|
45
|
+
This is one line.
|
46
|
+
|
47
|
+
This is another line.
|
48
|
+
EOF
|
49
|
+
end
|
50
|
+
|
51
|
+
end # === describe :text
|
@@ -0,0 +1,46 @@
|
|
1
|
+
|
2
|
+
describe :grab_prev_text do
|
3
|
+
|
4
|
+
it "pops the previous text" do
|
5
|
+
o = Moron_Text.new(<<-EOF)
|
6
|
+
This is text.
|
7
|
+
BIRD /*
|
8
|
+
Whistle
|
9
|
+
EOF
|
10
|
+
|
11
|
+
sounds = []
|
12
|
+
o.run { |name, line, moron|
|
13
|
+
if name == 'BIRD'
|
14
|
+
sounds << moron.grab_prev_text
|
15
|
+
else
|
16
|
+
moron.typo!
|
17
|
+
end
|
18
|
+
}
|
19
|
+
sounds.should == ['This is text.']
|
20
|
+
end
|
21
|
+
|
22
|
+
it "pops multiple lines of text" do
|
23
|
+
o = Moron_Text.new(<<-EOF)
|
24
|
+
This is one line.
|
25
|
+
|
26
|
+
This is another line.
|
27
|
+
DUCK /*
|
28
|
+
|
29
|
+
EOF
|
30
|
+
|
31
|
+
txt = nil
|
32
|
+
o.run { |name, line, moron|
|
33
|
+
if name == 'DUCK'
|
34
|
+
txt = moron.grab_prev_text
|
35
|
+
else
|
36
|
+
moron.typo!
|
37
|
+
end
|
38
|
+
}
|
39
|
+
trim(txt).should == trim(<<-EOF)
|
40
|
+
This is one line.
|
41
|
+
|
42
|
+
This is another line.
|
43
|
+
EOF
|
44
|
+
end
|
45
|
+
|
46
|
+
end # === describe :text
|
@@ -0,0 +1,42 @@
|
|
1
|
+
|
2
|
+
describe :return do
|
3
|
+
|
4
|
+
it "concats arguments to stack" do
|
5
|
+
m = Moron_Text.new(<<-EOF)
|
6
|
+
MENU /* 1
|
7
|
+
MENU /* 2
|
8
|
+
MENU /* 3
|
9
|
+
EOF
|
10
|
+
|
11
|
+
m.run { |name, line, moron| moron.return line[:arg] }
|
12
|
+
m.stack.should == '1 2 3'.split
|
13
|
+
end # === it adds value to stack
|
14
|
+
|
15
|
+
it "prevents the rest of the block or lambda from executing" do
|
16
|
+
m = Moron_Text.new(<<-EOF)
|
17
|
+
MENU /* 4
|
18
|
+
MENU /* 5
|
19
|
+
MENU /* 6
|
20
|
+
EOF
|
21
|
+
|
22
|
+
m.run { |name, line, moron|
|
23
|
+
moron.return line[:arg]
|
24
|
+
fail
|
25
|
+
}
|
26
|
+
|
27
|
+
m.stack.should == '4 5 6'.split
|
28
|
+
end # === it prevents the rest of the block or lambda from executing
|
29
|
+
|
30
|
+
it "does not alter the stack if no arguments are passed to it" do
|
31
|
+
m = Moron_Text.new(<<-EOF)
|
32
|
+
MENU /* 4
|
33
|
+
MENU /* 5
|
34
|
+
MENU /* 6
|
35
|
+
EOF
|
36
|
+
|
37
|
+
m.run { |name, line, moron| moron.return }
|
38
|
+
|
39
|
+
m.stack.should == []
|
40
|
+
end # === it does not alter the stack if no arguments are passed to it
|
41
|
+
|
42
|
+
end # === describe :return
|
data/specs/0031-next.rb
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
|
2
|
+
describe :next do
|
3
|
+
|
4
|
+
it "runs the given lambda if called from the :run block" do
|
5
|
+
m = Moron_Text.new(<<-EOF)
|
6
|
+
COMM 1 /* 1
|
7
|
+
COMM 2 /* 1
|
8
|
+
EOF
|
9
|
+
|
10
|
+
stack = []
|
11
|
+
l = lambda { |name, line, moron| stack << :lambda }
|
12
|
+
m.run(l) { |name, line, moron| stack << :block; moron.next }
|
13
|
+
stack.should == [:block, :lambda, :block, :lambda]
|
14
|
+
end
|
15
|
+
|
16
|
+
it "runs the given Class :run block if called from the instance :run lambda" do
|
17
|
+
stack = []
|
18
|
+
c = Class.new(Moron_Text)
|
19
|
+
c.run { |name, line, moron| stack << :class }
|
20
|
+
o = c.new(<<-EOF)
|
21
|
+
COMM 3 /* 2
|
22
|
+
COMM 4 /* 2
|
23
|
+
EOF
|
24
|
+
l = lambda { |name, line, moron| stack << :lambda; moron.next }
|
25
|
+
o.run(l)
|
26
|
+
stack.should == [:lambda, :class, :lambda, :class]
|
27
|
+
end
|
28
|
+
|
29
|
+
it "runs the given Class :run block if called from: instance :run lambda and block" do
|
30
|
+
stack = []
|
31
|
+
c = Class.new(Moron_Text)
|
32
|
+
c.run { |name, line, moron| stack << :class }
|
33
|
+
o = c.new(<<-EOF)
|
34
|
+
COMM 5 /* 3
|
35
|
+
COMM 6 /* 3
|
36
|
+
EOF
|
37
|
+
l = lambda { |name, line, moron| stack << :lambda; moron.next }
|
38
|
+
o.run(l) { |name, line, moron| stack << :block; moron.next }
|
39
|
+
stack.should == [:block, :lambda, :class, :block, :lambda, :class]
|
40
|
+
end
|
41
|
+
|
42
|
+
it "fails w/ Typo if :next is called in Class :run" do
|
43
|
+
stack = []
|
44
|
+
c = Class.new(Moron_Text)
|
45
|
+
c.run { |name, line, moron| moron.next if name == 'COMM 8' }
|
46
|
+
o = c.new(<<-EOF)
|
47
|
+
COMM 7 /* 4
|
48
|
+
COMM 8 /* 4
|
49
|
+
COMM 9 /* 4
|
50
|
+
EOF
|
51
|
+
lambda {
|
52
|
+
o.run { |name, line, moron| stack << :block; moron.next }
|
53
|
+
}.should.raise(Moron_Text::TYPO).
|
54
|
+
message.should =~ /Typo. COMM 8/
|
55
|
+
end
|
56
|
+
|
57
|
+
end # === describe :next
|
metadata
ADDED
@@ -0,0 +1,133 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: moron_text
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- da99
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-01-26 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: about_pos
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 2.0.0
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 2.0.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: pry
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0.9'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0.9'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: bundler
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.5'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.5'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: bacon
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: Bacon_Colored
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0.1'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0.1'
|
83
|
+
description: "\n It won't be useful for you. It is meant to be\n used with the
|
84
|
+
WWW_App gem.\n "
|
85
|
+
email:
|
86
|
+
- i-hate-spam-1234567@mailinator.com
|
87
|
+
executables: []
|
88
|
+
extensions: []
|
89
|
+
extra_rdoc_files: []
|
90
|
+
files:
|
91
|
+
- ".gitignore"
|
92
|
+
- Future-1.md
|
93
|
+
- Future-2.md
|
94
|
+
- Gemfile
|
95
|
+
- LICENSE
|
96
|
+
- README.md
|
97
|
+
- VERSION
|
98
|
+
- lib/moron_text.rb
|
99
|
+
- moron_text.gemspec
|
100
|
+
- specs/0000-parse.rb
|
101
|
+
- specs/0010-run.rb
|
102
|
+
- specs/0011-run_Class.rb
|
103
|
+
- specs/0012-typo.rb
|
104
|
+
- specs/0020-grab_text.rb
|
105
|
+
- specs/0021-grab_prev_text.rb
|
106
|
+
- specs/0030-return.rb
|
107
|
+
- specs/0031-next.rb
|
108
|
+
- specs/lib/helpers.rb
|
109
|
+
homepage: https://github.com/da99/moron_text
|
110
|
+
licenses:
|
111
|
+
- MIT
|
112
|
+
metadata: {}
|
113
|
+
post_install_message:
|
114
|
+
rdoc_options: []
|
115
|
+
require_paths:
|
116
|
+
- lib
|
117
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
118
|
+
requirements:
|
119
|
+
- - ">="
|
120
|
+
- !ruby/object:Gem::Version
|
121
|
+
version: '0'
|
122
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
123
|
+
requirements:
|
124
|
+
- - ">="
|
125
|
+
- !ruby/object:Gem::Version
|
126
|
+
version: '0'
|
127
|
+
requirements: []
|
128
|
+
rubyforge_project:
|
129
|
+
rubygems_version: 2.4.5
|
130
|
+
signing_key:
|
131
|
+
specification_version: 4
|
132
|
+
summary: A DSL for WWW mini-apps.
|
133
|
+
test_files: []
|