array_enumerator 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/Gemfile ADDED
@@ -0,0 +1,14 @@
1
+ source "http://rubygems.org"
2
+ # Add dependencies required to use your gem here.
3
+ # Example:
4
+ # gem "activesupport", ">= 2.3.5"
5
+
6
+ # Add dependencies to develop your gem here.
7
+ # Include everything needed to run rake, tests, features, etc.
8
+ group :development do
9
+ gem "rspec", "~> 2.8.0"
10
+ gem "rdoc", "~> 3.12"
11
+ gem "bundler", ">= 1.0.0"
12
+ gem "jeweler", "~> 1.8.4"
13
+ gem "rcov", ">= 0"
14
+ end
@@ -0,0 +1,33 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ diff-lcs (1.1.3)
5
+ git (1.2.5)
6
+ jeweler (1.8.4)
7
+ bundler (~> 1.0)
8
+ git (>= 1.2.5)
9
+ rake
10
+ rdoc
11
+ json (1.7.3)
12
+ rake (0.9.2.2)
13
+ rcov (0.9.11)
14
+ rdoc (3.12)
15
+ json (~> 1.4)
16
+ rspec (2.8.0)
17
+ rspec-core (~> 2.8.0)
18
+ rspec-expectations (~> 2.8.0)
19
+ rspec-mocks (~> 2.8.0)
20
+ rspec-core (2.8.0)
21
+ rspec-expectations (2.8.0)
22
+ diff-lcs (~> 1.1.2)
23
+ rspec-mocks (2.8.0)
24
+
25
+ PLATFORMS
26
+ ruby
27
+
28
+ DEPENDENCIES
29
+ bundler (>= 1.0.0)
30
+ jeweler (~> 1.8.4)
31
+ rcov
32
+ rdoc (~> 3.12)
33
+ rspec (~> 2.8.0)
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2012 Kasper Johansen
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,19 @@
1
+ = array_enumerator
2
+
3
+ Description goes here.
4
+
5
+ == Contributing to array_enumerator
6
+
7
+ * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet.
8
+ * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it.
9
+ * Fork the project.
10
+ * Start a feature/bugfix branch.
11
+ * Commit and push until you are happy with your contribution.
12
+ * Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
13
+ * Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
14
+
15
+ == Copyright
16
+
17
+ Copyright (c) 2012 Kasper Johansen. See LICENSE.txt for
18
+ further details.
19
+
@@ -0,0 +1,49 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+ begin
6
+ Bundler.setup(:default, :development)
7
+ rescue Bundler::BundlerError => e
8
+ $stderr.puts e.message
9
+ $stderr.puts "Run `bundle install` to install missing gems"
10
+ exit e.status_code
11
+ end
12
+ require 'rake'
13
+
14
+ require 'jeweler'
15
+ Jeweler::Tasks.new do |gem|
16
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
17
+ gem.name = "array_enumerator"
18
+ gem.homepage = "http://github.com/kaspernj/array_enumerator"
19
+ gem.license = "MIT"
20
+ gem.summary = %Q{Enumerator abstraction layer that emulates certain array functionality (methods).}
21
+ gem.description = %Q{Enumerator abstraction layer that emulates certain array functionality (methods like empty?, slice, shift and more) by using a small cache and other tricks without loading all the data from the enumerator at the same time.}
22
+ gem.email = "k@spernj.org"
23
+ gem.authors = ["Kasper Johansen"]
24
+ # dependencies defined in Gemfile
25
+ end
26
+ Jeweler::RubygemsDotOrgTasks.new
27
+
28
+ require 'rspec/core'
29
+ require 'rspec/core/rake_task'
30
+ RSpec::Core::RakeTask.new(:spec) do |spec|
31
+ spec.pattern = FileList['spec/**/*_spec.rb']
32
+ end
33
+
34
+ RSpec::Core::RakeTask.new(:rcov) do |spec|
35
+ spec.pattern = 'spec/**/*_spec.rb'
36
+ spec.rcov = true
37
+ end
38
+
39
+ task :default => :spec
40
+
41
+ require 'rdoc/task'
42
+ Rake::RDocTask.new do |rdoc|
43
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
44
+
45
+ rdoc.rdoc_dir = 'rdoc'
46
+ rdoc.title = "array_enumerator #{version}"
47
+ rdoc.rdoc_files.include('README*')
48
+ rdoc.rdoc_files.include('lib/**/*.rb')
49
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.1
@@ -0,0 +1,63 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{array_enumerator}
8
+ s.version = "0.0.1"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Kasper Johansen"]
12
+ s.date = %q{2012-07-03}
13
+ s.description = %q{Enumerator abstraction layer that emulates certain array functionality (methods like empty?, slice, shift and more) by using a small cache and other tricks without loading all the data from the enumerator at the same time.}
14
+ s.email = %q{k@spernj.org}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE.txt",
17
+ "README.rdoc"
18
+ ]
19
+ s.files = [
20
+ ".document",
21
+ ".rspec",
22
+ "Gemfile",
23
+ "Gemfile.lock",
24
+ "LICENSE.txt",
25
+ "README.rdoc",
26
+ "Rakefile",
27
+ "VERSION",
28
+ "array_enumerator.gemspec",
29
+ "lib/array_enumerator.rb",
30
+ "spec/array_enumerator_spec.rb",
31
+ "spec/spec_helper.rb"
32
+ ]
33
+ s.homepage = %q{http://github.com/kaspernj/array_enumerator}
34
+ s.licenses = ["MIT"]
35
+ s.require_paths = ["lib"]
36
+ s.rubygems_version = %q{1.6.2}
37
+ s.summary = %q{Enumerator abstraction layer that emulates certain array functionality (methods).}
38
+
39
+ if s.respond_to? :specification_version then
40
+ s.specification_version = 3
41
+
42
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
43
+ s.add_development_dependency(%q<rspec>, ["~> 2.8.0"])
44
+ s.add_development_dependency(%q<rdoc>, ["~> 3.12"])
45
+ s.add_development_dependency(%q<bundler>, [">= 1.0.0"])
46
+ s.add_development_dependency(%q<jeweler>, ["~> 1.8.4"])
47
+ s.add_development_dependency(%q<rcov>, [">= 0"])
48
+ else
49
+ s.add_dependency(%q<rspec>, ["~> 2.8.0"])
50
+ s.add_dependency(%q<rdoc>, ["~> 3.12"])
51
+ s.add_dependency(%q<bundler>, [">= 1.0.0"])
52
+ s.add_dependency(%q<jeweler>, ["~> 1.8.4"])
53
+ s.add_dependency(%q<rcov>, [">= 0"])
54
+ end
55
+ else
56
+ s.add_dependency(%q<rspec>, ["~> 2.8.0"])
57
+ s.add_dependency(%q<rdoc>, ["~> 3.12"])
58
+ s.add_dependency(%q<bundler>, [">= 1.0.0"])
59
+ s.add_dependency(%q<jeweler>, ["~> 1.8.4"])
60
+ s.add_dependency(%q<rcov>, [">= 0"])
61
+ end
62
+ end
63
+
@@ -0,0 +1,183 @@
1
+ #This class is ment as an enumerator but with a cache that enables it to emulate array-functionality (first, empty and so on). If elements goes out of memory, then the array becomes corrupted and methods like 'first' and 'slice' will no longer work (raise errors).
2
+ class Array_enumerator
3
+ #Takes an enumerator to work with as argument.
4
+ def initialize(enum)
5
+ #The enumerator being used.
6
+ @enum = enum
7
+
8
+ #Used to calculate length without depending corruption.
9
+ @length_cache = 0
10
+
11
+ #If the virtual array has become corrupted because of forgotten elements (by calling each and enumerating through elements).
12
+ @array_corrupted = false
13
+
14
+ #To allow the object to be thread-safe.
15
+ @mutex = Mutex.new
16
+ end
17
+
18
+ #Cache the first elements (if not cached already) and returns it.
19
+ def first
20
+ check_corrupted
21
+ cache_ele if !@eles or @eles.empty?
22
+ return @eles.first
23
+ end
24
+
25
+ #Returns true if the array is empty.
26
+ def empty?
27
+ if @empty == nil
28
+ cache_ele if !@eles
29
+
30
+ if @length_cache > 0
31
+ @empty = false
32
+ else
33
+ @empty = true
34
+ end
35
+ end
36
+
37
+ return @empty
38
+ end
39
+
40
+ #Returns each element and releases them from cache.
41
+ def each(&block)
42
+ if block
43
+ to_enum.each(&block)
44
+ return nil
45
+ else
46
+ return to_enum
47
+ end
48
+ end
49
+
50
+ #Returns a enumerator that can yield the all the lements (both cached and future un-cached ones).
51
+ def to_enum
52
+ check_corrupted
53
+ @array_corrupted = true
54
+
55
+ return Enumerator.new do |yielder|
56
+ if @eles
57
+ while ele = @eles.shift
58
+ yielder << ele
59
+ end
60
+ end
61
+
62
+ yield_rest do |ele|
63
+ yielder << ele
64
+ end
65
+ end
66
+ end
67
+
68
+ #Returns the counted length. Can only be called after the end of the enumerator has been reached.
69
+ def length
70
+ raise "Cant call length before the end has been reached." if !@end
71
+ return @length_cache
72
+ end
73
+
74
+ #Giving slice negaive arguments will force it to cache all elements and crush the memory for big results.
75
+ def slice(*args)
76
+ check_corrupted
77
+
78
+ if args[0].is_a?(Range) and !args[1]
79
+ need_eles = args[0].begin + args[0].end
80
+ elsif args[0] and !args[1]
81
+ need_eles = args[0]
82
+ elsif args[0] and args[1] and args[0] > 0 and args[1] > 0
83
+ need_eles = args[0] + args[1]
84
+ elsif args[0] < 0 or args[1] < 0
85
+ raise "Slice cant take negative arguments."
86
+ else
87
+ raise "Dont now what to do with args: '#{args}'."
88
+ end
89
+
90
+ @eles = [] if !@eles
91
+ cache_eles = need_eles - @eles.length if need_eles
92
+ cache_ele(cache_eles) if need_eles and cache_eles > 0
93
+ return @eles.slice(*args)
94
+ end
95
+
96
+ #Caches necessary needed elements and then returns the result as on a normal array.
97
+ def shift(*args)
98
+ check_corrupted
99
+
100
+ if args[0]
101
+ amount = args[0]
102
+ else
103
+ amount = 1
104
+ end
105
+
106
+ @eles = [] if !@eles
107
+ cache_ele(amount - @eles.length) if !@eles or @eles.length < amount
108
+ res = @eles.shift(*args)
109
+
110
+ #Since we are removing an element, the length should go down with the amount of elements captured.
111
+ if args[0]
112
+ @length_cache -= res.length
113
+ else
114
+ @length_cache -= 1
115
+ end
116
+
117
+ return res
118
+ end
119
+
120
+ #Returns a normal array with all elements. Can also raise corrupted error if elements have been thrown out.
121
+ def to_a
122
+ check_corrupted
123
+ cache_all
124
+ return @eles
125
+ end
126
+
127
+ alias to_ary to_a
128
+
129
+ private
130
+
131
+ #Raises error because elements have been forgotten to spare memory.
132
+ def check_corrupted
133
+ raise "Too late to call. Corrupted." if @array_corrupted
134
+ end
135
+
136
+ #Yields the rest of the elements to the given block.
137
+ def yield_rest
138
+ @array_corrupted = true
139
+
140
+ begin
141
+ @mutex.synchronize do
142
+ while ele = @enum.next
143
+ @length_cache += 1
144
+ yield(ele)
145
+ end
146
+ end
147
+ rescue StopIteration
148
+ @end = true
149
+ end
150
+ end
151
+
152
+ #Caches a given amount of elements.
153
+ def cache_ele(amount = 1)
154
+ @eles = [] if !@cache
155
+
156
+ begin
157
+ @mutex.synchronize do
158
+ while @eles.length <= amount
159
+ @eles << @enum.next
160
+ @length_cache += 1
161
+ end
162
+ end
163
+ rescue StopIteration
164
+ @end = true
165
+ end
166
+ end
167
+
168
+ #Forces the rest of the elements to be cached.
169
+ def cache_all
170
+ @eles = [] if !@eles
171
+
172
+ begin
173
+ @mutex.synchronize do
174
+ while ele = @enum.next
175
+ @length_cache += 1
176
+ @eles << ele
177
+ end
178
+ end
179
+ rescue StopIteration
180
+ @end = true
181
+ end
182
+ end
183
+ end
@@ -0,0 +1,131 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe "ArrayEnumerator" do
4
+ it "shift" do
5
+ cont = %w[a b c d e].to_enum
6
+ ae = Array_enumerator.new(cont)
7
+
8
+ res = ae.shift
9
+ raise "Expected 'a' but got: '#{res}'." if res != "a"
10
+
11
+ arr = ae.to_a
12
+ exp = %w[b c d e]
13
+ raise "Expected array to be '#{exp}' but got: '#{arr}'." if arr != exp
14
+ end
15
+
16
+ it "each" do
17
+ arr = %w[a b c]
18
+ cont = arr.to_enum
19
+ ae = Array_enumerator.new(cont)
20
+
21
+ count = 0
22
+ ae.each do |ele|
23
+ raise "Expected #{arr[count]} but got: #{ele}" if ele != arr[count]
24
+ count += 1
25
+ end
26
+
27
+ raise "Expected 3 elements to yield through but got: #{count}" if count != 3
28
+
29
+ arr = %w[a b c]
30
+ cont = arr.to_enum
31
+ ae = Array_enumerator.new(cont)
32
+
33
+ res = ae.empty?
34
+ raise "Expected empty to be false but got: '#{res}'." if res != false
35
+
36
+ count = 0
37
+ ae.each do |ele|
38
+ raise "Expected #{arr[count]} but got: #{ele}" if ele != arr[count]
39
+ count += 1
40
+ end
41
+
42
+ raise "Expected 3 elements to yield through but got: #{count}" if count != 3
43
+
44
+ begin
45
+ ae.to_a
46
+ raise "Should have raised exception but didnt."
47
+ rescue
48
+ #ignore.
49
+ end
50
+
51
+ begin
52
+ ae.first
53
+ raise "Should have raised exception but didnt."
54
+ rescue
55
+ #ignore.
56
+ end
57
+
58
+ begin
59
+ ae.each do |ele|
60
+ raise "Should get here?"
61
+ end
62
+
63
+ raise "Should get here?"
64
+ rescue
65
+ #ignore.
66
+ end
67
+ end
68
+
69
+ it "empty" do
70
+ cont = %w[a b c].to_enum
71
+ ae = Array_enumerator.new(cont)
72
+
73
+ res = ae.empty?
74
+ raise "Expected empty to be false but got: '#{res}'." if res != false
75
+
76
+ first = ae.first
77
+ raise "Expected first to be 'a' but it wasnt: '#{first}'." if first != "a"
78
+ end
79
+
80
+ it "length" do
81
+ cont = %w[a b c d e].to_enum
82
+ ae = Array_enumerator.new(cont)
83
+
84
+ begin
85
+ ae.length
86
+ raise "Should have failed but didnt."
87
+ rescue
88
+ #ignore.
89
+ end
90
+
91
+ ae.each do |ele|
92
+ #ignore.
93
+ end
94
+
95
+ res = ae.length
96
+ raise "Expected length to be 5 but it wasnt: '#{res}'." if res != 5
97
+ end
98
+
99
+ it "slice" do
100
+ arr = %w[a b c d e f g h i j k l m n]
101
+ cont = arr.to_enum
102
+ ae = Array_enumerator.new(cont)
103
+
104
+ runs = [
105
+ [6],
106
+ [1, 2],
107
+ [1..3]
108
+ ]
109
+
110
+ fails = [
111
+ [-2, 2],
112
+ [2, -2]
113
+ ]
114
+
115
+ runs.each do |args|
116
+ res1 = arr.slice(*args)
117
+ res2 = ae.slice(*args)
118
+
119
+ raise "Expected res to be: #{res1} but got #{res2} for args '#{args}'." if res1 != res2
120
+ end
121
+
122
+ fails.each do |args|
123
+ begin
124
+ res2 = ae.slice(*args)
125
+ raise "Should have failed but didnt."
126
+ rescue
127
+ #ignore.
128
+ end
129
+ end
130
+ end
131
+ end
@@ -0,0 +1,12 @@
1
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
3
+ require 'rspec'
4
+ require 'array_enumerator'
5
+
6
+ # Requires supporting files with custom matchers and macros, etc,
7
+ # in ./support/ and its subdirectories.
8
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
9
+
10
+ RSpec.configure do |config|
11
+
12
+ end
metadata ADDED
@@ -0,0 +1,125 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: array_enumerator
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 0.0.1
6
+ platform: ruby
7
+ authors:
8
+ - Kasper Johansen
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2012-07-03 00:00:00 +02:00
14
+ default_executable:
15
+ dependencies:
16
+ - !ruby/object:Gem::Dependency
17
+ name: rspec
18
+ requirement: &id001 !ruby/object:Gem::Requirement
19
+ none: false
20
+ requirements:
21
+ - - ~>
22
+ - !ruby/object:Gem::Version
23
+ version: 2.8.0
24
+ type: :development
25
+ prerelease: false
26
+ version_requirements: *id001
27
+ - !ruby/object:Gem::Dependency
28
+ name: rdoc
29
+ requirement: &id002 !ruby/object:Gem::Requirement
30
+ none: false
31
+ requirements:
32
+ - - ~>
33
+ - !ruby/object:Gem::Version
34
+ version: "3.12"
35
+ type: :development
36
+ prerelease: false
37
+ version_requirements: *id002
38
+ - !ruby/object:Gem::Dependency
39
+ name: bundler
40
+ requirement: &id003 !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ version: 1.0.0
46
+ type: :development
47
+ prerelease: false
48
+ version_requirements: *id003
49
+ - !ruby/object:Gem::Dependency
50
+ name: jeweler
51
+ requirement: &id004 !ruby/object:Gem::Requirement
52
+ none: false
53
+ requirements:
54
+ - - ~>
55
+ - !ruby/object:Gem::Version
56
+ version: 1.8.4
57
+ type: :development
58
+ prerelease: false
59
+ version_requirements: *id004
60
+ - !ruby/object:Gem::Dependency
61
+ name: rcov
62
+ requirement: &id005 !ruby/object:Gem::Requirement
63
+ none: false
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: "0"
68
+ type: :development
69
+ prerelease: false
70
+ version_requirements: *id005
71
+ description: Enumerator abstraction layer that emulates certain array functionality (methods like empty?, slice, shift and more) by using a small cache and other tricks without loading all the data from the enumerator at the same time.
72
+ email: k@spernj.org
73
+ executables: []
74
+
75
+ extensions: []
76
+
77
+ extra_rdoc_files:
78
+ - LICENSE.txt
79
+ - README.rdoc
80
+ files:
81
+ - .document
82
+ - .rspec
83
+ - Gemfile
84
+ - Gemfile.lock
85
+ - LICENSE.txt
86
+ - README.rdoc
87
+ - Rakefile
88
+ - VERSION
89
+ - array_enumerator.gemspec
90
+ - lib/array_enumerator.rb
91
+ - spec/array_enumerator_spec.rb
92
+ - spec/spec_helper.rb
93
+ has_rdoc: true
94
+ homepage: http://github.com/kaspernj/array_enumerator
95
+ licenses:
96
+ - MIT
97
+ post_install_message:
98
+ rdoc_options: []
99
+
100
+ require_paths:
101
+ - lib
102
+ required_ruby_version: !ruby/object:Gem::Requirement
103
+ none: false
104
+ requirements:
105
+ - - ">="
106
+ - !ruby/object:Gem::Version
107
+ hash: 4369946615704607040
108
+ segments:
109
+ - 0
110
+ version: "0"
111
+ required_rubygems_version: !ruby/object:Gem::Requirement
112
+ none: false
113
+ requirements:
114
+ - - ">="
115
+ - !ruby/object:Gem::Version
116
+ version: "0"
117
+ requirements: []
118
+
119
+ rubyforge_project:
120
+ rubygems_version: 1.6.2
121
+ signing_key:
122
+ specification_version: 3
123
+ summary: Enumerator abstraction layer that emulates certain array functionality (methods).
124
+ test_files: []
125
+