moron_text 1.0.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.
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: []