array_scanner 0.0.1

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,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ ZWQ4MTcwNjcxNTljZWZjYWFlOGU0OTQxODg0ZmIxMDA3NzhhYTcwYw==
5
+ data.tar.gz: !binary |-
6
+ ZjY5ODhkMzQzYTBhNzg5NTUwYjQ2MGNkY2IyODg3YWU1Yjc4ZWUwMQ==
7
+ !binary "U0hBNTEy":
8
+ metadata.gz: !binary |-
9
+ ZTc0ZjRlNTYwNDIzMzJjYjZlOTI4MmJmMWE3ODliNmIzN2EwYzMzN2ZmNDE4
10
+ MTk3YjU4YjgyZDFhYzkwYjU4MmQ0ZGIyZjgwYzA4ZmZmMmFlMGZlMGE0ZmRi
11
+ ZDIwYTBlMDU2ZTg2ZGRmMzQwNGMyYjFkZjFlMTlmODlmZmE2YjE=
12
+ data.tar.gz: !binary |-
13
+ ZDlhMGY0YTg3ZDNhZjQ3Mjc2NzNjMTM3MmJjYzU2YTQ4NTdkMTIyOTYwOGNk
14
+ ODY1ZmY4MWViZTM3ZWQ0ZTMzYjkzYjEwMGUxM2U2MDRjZjE0NWJhZjcxZGM3
15
+ OWMzMTY1NWJjNTNjNDVlZmMxYWE4MTFkZGVjYWUzMWJlNjA0Yzk=
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/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in array_scanner.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 LFDM
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,78 @@
1
+ # ArrayScanner
2
+
3
+ Class for traversing an array, remembering the position of a pointer and
4
+ recent scan operations, very much like Ruby's standard library
5
+ StringScanner.
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ gem 'array_scanner'
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install array_scanner
20
+
21
+ ## Example Usage
22
+
23
+ ArrayScanner.new([:a, :b, :c, :d, :e, :f, :g])
24
+
25
+ inspect => "Pointer at 0/6. Current element: :a"
26
+
27
+ forward(2) => 2
28
+ o-------2-------> *
29
+
30
+ current_element => :c
31
+ *
32
+
33
+ scan { |el| el == :c } => :c
34
+ o---1--> *
35
+
36
+ position => 3
37
+ *
38
+
39
+ rest => [:d, :e, :f, :g]
40
+ *
41
+
42
+ rest_size => 4
43
+ *
44
+
45
+ scan_until { |el| el == :f } => [:d, :e]
46
+ o-------2-------> *
47
+
48
+ unscan => 3
49
+ * <-------2-------o
50
+
51
+ scan_until(true) { |el| el == :f } => [:d, :e, :f]
52
+ o------------3-----------> *
53
+
54
+ eoa? => true
55
+ *
56
+
57
+ rewind_to { |el| el == :b } => :b
58
+ * <--------------------5--------------------- *
59
+
60
+ surroundings => [:a, :c]
61
+ *
62
+
63
+ last_positions => [6, 3, 5, 3, 2, 0]
64
+ *
65
+
66
+ last_results => [[:d, :e, :f], [:d, :e], :c]
67
+ *
68
+
69
+ Check tests for more behaviour.
70
+
71
+
72
+ ## Contributing
73
+
74
+ 1. Fork it
75
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
76
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
77
+ 4. Push to the branch (`git push origin my-new-feature`)
78
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,24 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'array_scanner/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "array_scanner"
8
+ spec.version = ArrayScanner::VERSION
9
+ spec.authors = ["LFDM"]
10
+ spec.email = ["1986gh@gmail.com"]
11
+ spec.description = %q{ArrayScanner that mimics ruby's std lib StringScanner}
12
+ spec.summary = %q{Class for traversing an array, remembering the position of a pointer and recent scan operations.}
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.3"
22
+ spec.add_development_dependency "rake"
23
+ spec.add_development_dependency "rspec"
24
+ end
@@ -0,0 +1,3 @@
1
+ class ArrayScanner
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,224 @@
1
+ require "array_scanner/version"
2
+ require_relative "hist"
3
+
4
+ class ArrayScanner
5
+ attr_reader :position, :pos_hist, :res_hist
6
+ alias :pos :position
7
+ alias :pointer :position
8
+
9
+ def initialize(arr, history_size = 10)
10
+ raise TypeError.new("Argument is not an Array.") unless arr.is_a?(Array)
11
+ raise TypeError.new("History size is not a Fixnum.") unless history_size.is_a?(Fixnum)
12
+
13
+ @arr = arr
14
+ @position = 0
15
+
16
+ @pos_hist = Hist.new(history_size)
17
+ @res_hist = Hist.new(history_size)
18
+ end
19
+
20
+ def size
21
+ @arr.size
22
+ end
23
+
24
+ alias :length :size
25
+
26
+ def eoa
27
+ size - 1
28
+ end
29
+
30
+ def eoa?
31
+ @position == eoa
32
+ end
33
+
34
+ def current_element
35
+ @arr[@position]
36
+ end
37
+
38
+ alias :points_at :current_element
39
+ alias :current :current_element
40
+
41
+ def position=(new)
42
+ raise TypeError.new("New position not a Fixnum.") unless new.is_a? Fixnum
43
+ raise ArgumentError.new("New position #{new} outside of range 0..#{eoa}.") unless new.between?(0, eoa)
44
+
45
+ @pos_hist.push(@position)
46
+ @position = new
47
+ end
48
+
49
+ alias :pos= :position=
50
+ alias :pointer= :position=
51
+
52
+ def surroundings
53
+ [scanned.last, rest[1]]
54
+ end
55
+
56
+ def last_position
57
+ @pos_hist.recent
58
+ end
59
+
60
+ def last_positions(n = nil)
61
+ n ? @pos_hist.recent(n) : @pos_hist.stack
62
+ end
63
+
64
+ def unscan(steps = 1)
65
+ return nil if last_positions.empty?
66
+ self.position = last_positions[steps - 1] || last_positions.last
67
+ end
68
+
69
+ def last_result(valid = false)
70
+ valid ? @res_hist.stack.find { |x| x } : @res_hist.recent
71
+ end
72
+
73
+ def last_results(n = nil)
74
+ n ? @res_hist.recent(n) : @res_hist.stack
75
+ end
76
+
77
+ def forward(fixnum)
78
+ new = @position + fixnum
79
+ self.position = (new > eoa ? eoa : new)
80
+ end
81
+
82
+ def forward_to
83
+ if block_given?
84
+ f = rest.find { |x| yield(x) }
85
+ f ? self.position = @arr.index(f) : nil
86
+ else
87
+ raise needs_block
88
+ end
89
+ end
90
+
91
+ def rewind(fixnum)
92
+ new = @position - fixnum
93
+ self.position = (new < 0 ? 0 : new)
94
+ end
95
+
96
+ def rewind_to
97
+ if block_given?
98
+ b = scanned.find { |x| yield(x) }
99
+ b ? self.position = @arr.index(b) : nil
100
+ else
101
+ raise needs_block
102
+ end
103
+ end
104
+
105
+ def reset
106
+ self.position = 0
107
+ end
108
+
109
+ def terminate
110
+ self.position = eoa
111
+ end
112
+
113
+ alias :clear :terminate
114
+
115
+ def scanned
116
+ @arr[0...@position]
117
+ end
118
+
119
+ def scanned_size
120
+ @position
121
+ end
122
+
123
+ def rest
124
+ @arr[@position..-1]
125
+ end
126
+
127
+ def rest_size
128
+ size - @position
129
+ end
130
+
131
+ def scan(forward = true)
132
+ res = @arr[@position]
133
+
134
+ if block_given? and not yield(res)
135
+ rr(false)
136
+ else
137
+ forward(1) if forward &! eoa?
138
+ rr(res)
139
+ end
140
+ end
141
+
142
+ def scan_until(include_true_element = false)
143
+ if block_given?
144
+ if e = rest.find { |el| yield(el) }
145
+ i = @arr.index(e)
146
+ i += 1 if include_true_element
147
+
148
+ self.position = (i > eoa ? eoa : i)
149
+ rr(@arr[last_position...i])
150
+ else
151
+ rr(false)
152
+ end
153
+ else
154
+ raise needs_block
155
+ end
156
+ end
157
+
158
+ def peek(n = nil)
159
+ n ? rest.take(n) : rest.first
160
+ end
161
+
162
+ def peek_until
163
+ if block_given?
164
+ i = rest.index { |el| yield(el) }
165
+ i ? rest[0...i] : []
166
+ else
167
+ raise needs_block
168
+ end
169
+ end
170
+
171
+ def look_behind(n = nil)
172
+ n ? scanned.reverse.take(n) : scanned.last
173
+ end
174
+
175
+ def look_behind_until
176
+ if block_given?
177
+ rev = scanned.reverse
178
+ i = rev.index { |el| yield(el) }
179
+ i ? rev[0...i] : []
180
+ else
181
+ raise needs_block
182
+ end
183
+ end
184
+
185
+ def find
186
+ if block_given?
187
+ rest.find { |e| yield e }
188
+ else
189
+ raise needs_block
190
+ end
191
+ end
192
+
193
+ alias :next :find
194
+
195
+ def previous
196
+ if block_given?
197
+ scanned.reverse.find { |e| yield e }
198
+ else
199
+ raise needs_block
200
+ end
201
+ end
202
+
203
+ def rr(obj)
204
+ # means return result
205
+ @res_hist.push(obj)
206
+ obj
207
+ end
208
+
209
+ def needs_block
210
+ ArgumentError.new("Method needs block.")
211
+ end
212
+
213
+ def to_a
214
+ @arr
215
+ end
216
+
217
+ def to_s
218
+ @arr.to_s
219
+ end
220
+
221
+ def inspect
222
+ "Pointer at #{@position}/#{eoa}. Current element: #{":" if current.is_a?(Symbol)}#{current}"
223
+ end
224
+ end
data/lib/hist.rb ADDED
@@ -0,0 +1,21 @@
1
+ class Hist
2
+ attr_reader :stack, :max_size
3
+
4
+ def initialize(max_size = 10)
5
+ @stack = []
6
+ @max_size = max_size
7
+ end
8
+
9
+ def push(obj)
10
+ @stack.pop if @stack.size == @max_size
11
+ @stack.unshift(obj)
12
+ end
13
+
14
+ def recent(n = nil)
15
+ n ? @stack.take(n) : @stack.first
16
+ end
17
+
18
+ def [](i)
19
+ @stack[i]
20
+ end
21
+ end
@@ -0,0 +1,481 @@
1
+ require_relative "../../lib/array_scanner"
2
+
3
+ describe ArrayScanner do
4
+ describe "#initialize" do
5
+ it "should raise type errors for wrong arguments" do
6
+ expect { ArrayScanner.new({}) } .to raise_error(TypeError)
7
+ expect { ArrayScanner.new([], nil) }.to raise_error(TypeError)
8
+ end
9
+ end
10
+
11
+ before :each do
12
+ @a = ArrayScanner.new([1,2,3,4,5])
13
+ end
14
+
15
+ describe "#size" do
16
+ it "should return the arrays size" do
17
+ @a.size.should be 5
18
+ end
19
+ end
20
+
21
+ describe "#length" do
22
+ it "is an alias for #size" do
23
+ @a.length.should == @a.size
24
+ end
25
+ end
26
+
27
+ describe "#eoa" do
28
+ it "should return last valid position, i.d. end of array" do
29
+ @a.eoa.should be 4
30
+ end
31
+ end
32
+
33
+ describe "#eoa?" do
34
+ it "should return false if not at end of array" do
35
+ @a.eoa?.should be_false
36
+ end
37
+
38
+ it "should return true if at end of array" do
39
+ @a.position = 4
40
+ @a.eoa?.should be_true
41
+ end
42
+ end
43
+
44
+ describe "#current_element" do
45
+ it "should return element at the pointers position" do
46
+ @a.position = 2
47
+ @a.current_element.should be 3
48
+ end
49
+ end
50
+
51
+ describe "#current" do
52
+ it "is an alias for #current_element" do
53
+ @a.position = 2
54
+ @a.current.should be 3
55
+ end
56
+ end
57
+
58
+ describe "#points_at" do
59
+ it "is an alias for #current_element" do
60
+ @a.position = 2
61
+ @a.points_at.should be 3
62
+ end
63
+ end
64
+
65
+ describe "#position" do
66
+ it "should return current position" do
67
+ @a.position.should be 0
68
+ end
69
+ end
70
+
71
+ describe "#pos" do
72
+ it "is an alias for #position" do
73
+ @a.pos.should be 0
74
+ end
75
+ end
76
+
77
+ describe "#pointer" do
78
+ it "is an alias for #position" do
79
+ @a.pointer.should be 0
80
+ end
81
+ end
82
+
83
+ describe "#position=" do
84
+ it "should set new position" do
85
+ @a.position = 4
86
+ @a.position.should be 4
87
+ end
88
+
89
+ it "should raise error when new position is invalid type" do
90
+ expect { @a.position = "" }.to raise_error(TypeError)
91
+ end
92
+
93
+ it "should raise error when new position is outside of arrays range" do
94
+ expect { @a.position = 6 }.to raise_error(ArgumentError)
95
+ expect { @a.position = 5 }.to raise_error(ArgumentError)
96
+ end
97
+
98
+ it "should add to positions history stack" do
99
+ [1,2,3].each { |n| @a.position = n }
100
+ @a.pos_hist.stack.should == [2,1,0]
101
+ end
102
+ end
103
+
104
+ describe "#pos=" do
105
+ it "is an alias for #position=" do
106
+ @a.pos = 4
107
+ @a.position.should be 4
108
+ end
109
+ end
110
+
111
+ describe "#pointer=" do
112
+ it "is an alias for #position=" do
113
+ @a.pointer = 4
114
+ @a.position.should be 4
115
+ end
116
+ end
117
+
118
+ describe "#surroundings" do
119
+ it "should return element in front and element behind pointer" do
120
+ @a.pos = 2
121
+ @a.surroundings.should == [2,4]
122
+ end
123
+
124
+ it "should return nil elements for edge positions" do
125
+ @a.surroundings.should == [nil, 2]
126
+ @a.terminate
127
+ @a.surroundings.should == [4, nil]
128
+ end
129
+ end
130
+
131
+ describe "#last_position" do
132
+ it "should return last position after recent movement" do
133
+ @a.position = 1 and @a.position = 2
134
+ @a.last_position.should be 1
135
+ end
136
+ end
137
+
138
+ describe "#last_positions" do
139
+ it "should return array of all pointer movements when called without arg" do
140
+ @a.position = 3 and @a.position = 1 and @a.position = 4
141
+ @a.last_positions.should == [1,3,0]
142
+ end
143
+
144
+ it "should return array of all pointer movements according to argument number" do
145
+ @a.position = 3 and @a.position = 1 and @a.forward(1)
146
+ @a.last_positions(2).should == [1,3]
147
+ end
148
+ end
149
+
150
+ describe "#unscan" do
151
+ before :each do
152
+ [1,2,3,4].each { |n| @a.pos_hist.push(n) }
153
+ end
154
+
155
+ context "without argument" do
156
+ it "should reset pointer to last position and return new value" do
157
+ @a.unscan.should be 4
158
+ @a.position.should be 4
159
+ end
160
+ end
161
+
162
+ context "with argument" do
163
+ it "should reset pointer by n steps and return new value" do
164
+ @a.unscan(3).should be 2
165
+ @a.position.should be 2
166
+ end
167
+ end
168
+
169
+ it "should return nil when position history is empty" do
170
+ @a.pos_hist.stack.clear
171
+ @a.unscan.should be_nil
172
+ end
173
+
174
+ end
175
+
176
+ describe "#last_result" do
177
+ it "should return last result" do
178
+ @a.scan
179
+ @a.last_result.should == 1
180
+ end
181
+
182
+ it "should return last valid result with true argument" do
183
+ @a.scan and @a.scan { |x| x == 100 }
184
+ @a.last_result.should be_false
185
+ @a.last_result(true).should == 1
186
+ end
187
+ end
188
+
189
+ describe "#forward" do
190
+ it "should forward pointer by argument" do
191
+ @a.forward(2)
192
+ @a.position.should be 2
193
+ end
194
+
195
+ it "should foward pointer to eoa if new position is outside of range" do
196
+ @a.forward(10)
197
+ @a.position.should be 4
198
+ end
199
+ end
200
+
201
+ describe "#forward_to" do
202
+ it "should forward pointer and return new position if block is true" do
203
+ @a.forward_to { |el| el == 3 }.should be 2
204
+ @a.position.should be 2
205
+ end
206
+
207
+ it "should not forward pointer and return nil if block is false" do
208
+ @a.forward_to { |el| el == 7 }.should be_nil
209
+ @a.position.should be 0
210
+ end
211
+
212
+ it "raises ArgumentError without block" do
213
+ expect { @a.look_behind_until }.to raise_error(ArgumentError)
214
+ end
215
+ end
216
+
217
+ describe "#rewind" do
218
+ it "should rewind pointer by argument" do
219
+ @a.position = 3
220
+ @a.rewind(2)
221
+ @a.position.should be 1
222
+ end
223
+
224
+ it "should rewind to zero if new position is outside of range" do
225
+ @a.position = 2
226
+ @a.rewind(4)
227
+ @a.position.should be 0
228
+ end
229
+ end
230
+
231
+ describe "#rewind_to" do
232
+ it "should rewind pointer to new position if block is true" do
233
+ @a.position = 4
234
+ @a.rewind_to { |el| el == 2 }.should be 1
235
+ @a.position.should be 1
236
+ end
237
+
238
+ it "should not rewind pointer and return nil if block is false" do
239
+ @a.position = 4
240
+ @a.rewind_to { |el| el == 5 }.should be_nil
241
+ @a.position.should be 4
242
+ end
243
+
244
+ it "raises ArgumentError without block" do
245
+ expect { @a.look_behind_until }.to raise_error(ArgumentError)
246
+ end
247
+ end
248
+
249
+ describe "#reset" do
250
+ it "should reset pointer to 0" do
251
+ @a.position = 4
252
+ @a.reset
253
+ @a.position.should be 0
254
+ end
255
+ end
256
+
257
+ describe "#terminate" do
258
+ it "should set pointer to eoa position" do
259
+ @a.terminate
260
+ @a.position.should be 4
261
+ end
262
+ end
263
+
264
+ describe "#clear" do
265
+ it "is an alias for #terminate" do
266
+ @a.clear.should be @a.terminate
267
+ end
268
+ end
269
+
270
+ describe "#scanned" do
271
+ it "should return already scanned elements" do
272
+ @a.position = 3
273
+ @a.scanned.should == [1,2,3]
274
+ end
275
+ end
276
+
277
+ describe "#scanned_size" do
278
+ it "should return number of scanned elements" do
279
+ @a.position = 3
280
+ @a.scanned_size.should be 3
281
+ end
282
+ end
283
+
284
+ describe "#rest" do
285
+ it "should return remaining elements" do
286
+ @a.position = 1
287
+ @a.rest.should == [2,3,4,5]
288
+ end
289
+ end
290
+
291
+ describe "#rest_size" do
292
+ it "should return number of remaining elements" do
293
+ @a.position = 1
294
+ @a.rest_size.should be 4
295
+ end
296
+ end
297
+
298
+ describe "#scan" do
299
+ context "without blk" do
300
+ it "should return array element at current position and advance pointer" do
301
+ @a.position = 2
302
+ @a.scan.should be 3
303
+ @a.position.should be 3
304
+ end
305
+
306
+ it "should not advance pointer with false argument" do
307
+ @a.scan(false)
308
+ @a.position.should be 0
309
+ end
310
+
311
+ it "should not advance pointer if at eoa" do
312
+ @a.position = 4
313
+ @a.scan
314
+ @a.position.should be 4
315
+ end
316
+ end
317
+
318
+ context "with blk" do
319
+ it "should return false for false block" do
320
+ @a.scan { |el| el == 6 }.should be_false
321
+ end
322
+
323
+ it "should return array element at current position for true block and advance position by 1" do
324
+ @a.position = 2
325
+ @a.scan { |el| el == 3 }.should be 3
326
+ @a.position.should be 3
327
+ end
328
+
329
+ it "should not advance pointer with false argument" do
330
+ @a.scan(false) { |el| el == 3 }.should be false
331
+ @a.position.should be 0
332
+ end
333
+ end
334
+ end
335
+
336
+ describe "#scan_until" do
337
+ it "should return array from current position to position before the block evaluated to true and move pointer" do
338
+ @a.scan_until { |el| el == 3 }.should == [1,2]
339
+ @a.position.should be 2
340
+ end
341
+
342
+ it "should return false when block is false and not move pointer." do
343
+ @a.scan_until { |el| el == 8 }.should be_false
344
+ @a.position.should be 0
345
+ end
346
+
347
+ it "should include the element for which the block evaluated true when true argument is given." do
348
+ @a.scan_until(true) { |el| el == 3 }.should == [1,2,3]
349
+ @a.position.should be 3
350
+ end
351
+
352
+ it "should rest pointer at eoa when true argument is given and the truthy result is at eoa." do
353
+ @a.scan_until(true) { |el| el == 5 }.should == [1,2,3,4,5]
354
+ @a.position.should == @a.eoa
355
+ end
356
+
357
+ it "raises ArgumentError without block" do
358
+ expect { @a.look_behind_until }.to raise_error(ArgumentError)
359
+ end
360
+ end
361
+
362
+ describe "#peek" do
363
+ it "should return next element without argument" do
364
+ @a.position = 1
365
+ @a.peek.should == 2
366
+ end
367
+
368
+ it "should array of next elements by argument number" do
369
+ @a.peek(1).should == [1]
370
+ @a.peek(2).should == [1,2]
371
+ end
372
+ end
373
+
374
+ describe "#peek_until" do
375
+ it "should return array of next elements between current position and the element for which the block is true" do
376
+ @a.position = 1
377
+ @a.peek_until { |el| el == 5 }.should == [2,3,4]
378
+ end
379
+
380
+ it "should return empty array if block is false" do
381
+ @a.peek_until { |el| el == 6 }.should == []
382
+ end
383
+
384
+ it "raises ArgumentError without block" do
385
+ expect { @a.look_behind_until }.to raise_error(ArgumentError)
386
+ end
387
+ end
388
+
389
+ describe "#look_behind" do
390
+ it "should return element behind pointer (i.e. pointer position - 1), when no arguemnt is given" do
391
+ @a.pos = 2
392
+ @a.look_behind.should be 2
393
+ end
394
+
395
+ it "should array of previous elements by argument number (reverse order)" do
396
+ @a.pos = 4
397
+ @a.look_behind(1).should == [4]
398
+ @a.look_behind(2).should == [4,3]
399
+ end
400
+
401
+ it "should return nil when there is nothing behind without argument" do
402
+ @a.look_behind.should be_nil
403
+ end
404
+
405
+ it "should return empty array when there is nothing behind with argument" do
406
+ @a.look_behind(3).should == []
407
+ end
408
+
409
+ it "should return everything behind when argument number is larger than number of elements behind" do
410
+ @a.pos = 2
411
+ @a.look_behind(4).should == [2,1]
412
+ end
413
+ end
414
+
415
+ describe "#look_behind_until" do
416
+ it "should return arguemnt of previous element between current position and the element for which the block is true - in reverse order" do
417
+ @a.pos = 4
418
+ @a.look_behind_until { |el| el == 2 }.should == [4,3]
419
+ end
420
+
421
+ it "should return empty array if block is false" do
422
+ @a.look_behind_until { |el| el == 1 }.should == []
423
+ end
424
+
425
+ it "raises ArgumentError without block" do
426
+ expect { @a.look_behind_until }.to raise_error(ArgumentError)
427
+ end
428
+ end
429
+
430
+ describe "#find" do
431
+ it "should return next element after pointer for true block" do
432
+ @a.position = 1
433
+ @a.find { |x| x == 3 }.should be 3
434
+ end
435
+
436
+ it "should return nil for no find - e.g. pointer is already behind the looked up element" do
437
+ @a.position = 3
438
+ @a.find { |x| x == 0 }.should be_nil
439
+ end
440
+ end
441
+
442
+ describe "#next" do
443
+ it "is an alias for #find" do
444
+ @a.position = 1
445
+ @a.next { |x| x == 3 }.should be 3
446
+ end
447
+ end
448
+
449
+ describe "#previous" do
450
+ it "should return previous element in front of pointer for true block" do
451
+ @a.position = 3
452
+ @a.previous { |x| x == 2 }.should be 2
453
+ end
454
+ end
455
+
456
+ describe "#rr" do
457
+ it "should add to results history and return the argument" do
458
+ @a.rr(1).should be 1
459
+ @a.res_hist.stack.should == [1]
460
+ end
461
+ end
462
+
463
+ describe "#to_a" do
464
+ it "should return simple array" do
465
+ @a.to_a.should == [1,2,3,4,5]
466
+ end
467
+ end
468
+
469
+ describe "#to_s" do
470
+ it "should return simple array to_s" do
471
+ @a.to_s.should == "[1, 2, 3, 4, 5]"
472
+ end
473
+ end
474
+
475
+ describe "#inspect" do
476
+ it "should return pointer information" do
477
+ @a.pos = 2
478
+ @a.inspect.should == "Pointer at 2/4. Current element: 3"
479
+ end
480
+ end
481
+ end
@@ -0,0 +1,55 @@
1
+ require_relative "../../lib/hist"
2
+
3
+ describe Hist do
4
+ describe "#initialize" do
5
+ it "should come with default stack size 10" do
6
+ Hist.new.max_size.should be 10
7
+ end
8
+
9
+ it "should take max sizes as argument" do
10
+ Hist.new(11).max_size.should be 11
11
+ end
12
+ end
13
+
14
+ describe "#[]" do
15
+ it "delegates [] to stack" do
16
+ a = Hist.new
17
+ a.push(1) and a.push(2)
18
+ a[1].should be 1
19
+ a[0].should be 2
20
+ end
21
+ end
22
+
23
+ describe "#push" do
24
+ before :each do
25
+ @a = Hist.new(3)
26
+ end
27
+
28
+ it "should push new element to stack" do
29
+ @a.push(1)
30
+ @a.stack.should == [1]
31
+ end
32
+
33
+ it "should not take more elements than max size" do
34
+ @a.instance_variable_set(:@stack, [1,2,3])
35
+ @a.push(4)
36
+ @a.stack.should == [4,1,2]
37
+ end
38
+ end
39
+
40
+ describe "#recent" do
41
+ before :each do
42
+ @a = Hist.new(3)
43
+ @a.instance_variable_set(:@stack, [1,2,3])
44
+ end
45
+
46
+ it "should return recently added element to stack without argument" do
47
+ @a.recent.should be 1
48
+ end
49
+
50
+ it "should return array of recently added elements according to argument number" do
51
+ @a.recent(2).should == [1,2]
52
+ end
53
+ end
54
+ end
55
+
metadata ADDED
@@ -0,0 +1,100 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: array_scanner
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - LFDM
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-04-22 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.3'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ! '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ! '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ! '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description: ArrayScanner that mimics ruby's std lib StringScanner
56
+ email:
57
+ - 1986gh@gmail.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - .gitignore
63
+ - Gemfile
64
+ - LICENSE.txt
65
+ - README.md
66
+ - Rakefile
67
+ - array_scanner.gemspec
68
+ - lib/array_scanner.rb
69
+ - lib/array_scanner/version.rb
70
+ - lib/hist.rb
71
+ - spec/lib/array_scanner_spec.rb
72
+ - spec/lib/hist_spec.rb
73
+ homepage: ''
74
+ licenses:
75
+ - MIT
76
+ metadata: {}
77
+ post_install_message:
78
+ rdoc_options: []
79
+ require_paths:
80
+ - lib
81
+ required_ruby_version: !ruby/object:Gem::Requirement
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ required_rubygems_version: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ! '>='
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ requirements: []
92
+ rubyforge_project:
93
+ rubygems_version: 2.0.3
94
+ signing_key:
95
+ specification_version: 4
96
+ summary: Class for traversing an array, remembering the position of a pointer and
97
+ recent scan operations.
98
+ test_files:
99
+ - spec/lib/array_scanner_spec.rb
100
+ - spec/lib/hist_spec.rb