moron_text 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
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
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
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 ===
@@ -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
@@ -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"
@@ -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
@@ -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
@@ -0,0 +1,8 @@
1
+
2
+ require 'Bacon_Colored'
3
+ require 'moron_text'
4
+ require 'pry'
5
+
6
+ def trim str
7
+ str.split("\n").map(&:strip).join("\n")
8
+ end
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: []