ordered_set 0.1.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.
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2008 Justin Balthrop
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,35 @@
1
+ = OrderedSet
2
+
3
+ OrderSet is an class for storing sets of objects. Unlike a Set, it maintains the order of
4
+ the objects, but unlike an Array, each object can only exist once, and checking for
5
+ inclusion takes constant time.
6
+
7
+ == Usage:
8
+
9
+ s = [1,3,2,3,4,3].to_ordered_set
10
+ s.to_a
11
+ # => [1,3,2,4]
12
+
13
+ t = OrderedSet.new([6,7,5,6,5])
14
+ t.to_a
15
+ # => [6,7,5]
16
+
17
+ (s + t).to_a
18
+ # => [1,3,2,4,6,7,5]
19
+
20
+ s << 5
21
+ s.to_a
22
+ # => [1,3,2,4,5]
23
+
24
+ s.delete(1)
25
+ s.to_a
26
+ # => [3,2,4,5]
27
+
28
+ == Install:
29
+
30
+ sudo gem install ninjudd-deep_clonable -s http://gems.github.com
31
+ sudo gem install ninjudd-ordered_set -s http://gems.github.com
32
+
33
+ == License:
34
+
35
+ Copyright (c) 2008 Justin Balthrop, Geni.com; Published under The MIT License, see LICENSE
@@ -0,0 +1,44 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'rake/rdoctask'
4
+
5
+ begin
6
+ require 'jeweler'
7
+ Jeweler::Tasks.new do |s|
8
+ s.name = "ordered_set"
9
+ s.summary = %Q{Like Set except it maintains the order of objects}
10
+ s.email = "code@justinbalthrop.com"
11
+ s.homepage = "http://github.com/ninjudd/ordered_set"
12
+ s.description = "Like Set except it maintains the order of objects"
13
+ s.authors = ["Justin Balthrop"]
14
+ end
15
+ Jeweler::GemcutterTasks.new
16
+ rescue LoadError
17
+ puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
18
+ end
19
+
20
+ Rake::TestTask.new do |t|
21
+ t.libs << 'lib'
22
+ t.pattern = 'test/**/*_test.rb'
23
+ t.verbose = false
24
+ end
25
+
26
+ Rake::RDocTask.new do |rdoc|
27
+ rdoc.rdoc_dir = 'rdoc'
28
+ rdoc.title = 'ordered_set'
29
+ rdoc.options << '--line-numbers' << '--inline-source'
30
+ rdoc.rdoc_files.include('README*')
31
+ rdoc.rdoc_files.include('lib/**/*.rb')
32
+ end
33
+
34
+ begin
35
+ require 'rcov/rcovtask'
36
+ Rcov::RcovTask.new do |t|
37
+ t.libs << 'test'
38
+ t.test_files = FileList['test/**/*_test.rb']
39
+ t.verbose = true
40
+ end
41
+ rescue LoadError
42
+ end
43
+
44
+ task :default => :test
@@ -0,0 +1,5 @@
1
+ ---
2
+ :build:
3
+ :patch: 1
4
+ :major: 0
5
+ :minor: 1
@@ -0,0 +1,161 @@
1
+ require 'rubygems'
2
+ require 'deep_clonable'
3
+ require 'forwardable'
4
+
5
+ class OrderedSet
6
+ include Enumerable
7
+ extend Forwardable
8
+
9
+ deep_clonable
10
+
11
+ def initialize(items = [])
12
+ @order = []
13
+ @position = {}
14
+ replace(items)
15
+ end
16
+
17
+ def_delegators :@order, :each, :join, :[], :first, :last, :slice, :size, :length, :empty?
18
+ alias limit slice
19
+
20
+ def replace(items)
21
+ clear
22
+ items.each do |item|
23
+ self << item
24
+ end
25
+ self
26
+ end
27
+
28
+ def clear
29
+ @order.clear
30
+ @position.clear
31
+ end
32
+
33
+ def include?(item)
34
+ @position.has_key?(item)
35
+ end
36
+
37
+ def <<(item)
38
+ return if include?(item)
39
+ @position[item] = @order.size
40
+ @order << item
41
+ end
42
+
43
+ clone_method :+, :add!
44
+ def add!(items)
45
+ items.each do |item|
46
+ self << item
47
+ end
48
+ self
49
+ end
50
+ alias concat add!
51
+
52
+ def unshift!(items)
53
+ need_reindex = false
54
+ items.each do |item|
55
+ next if include?(item)
56
+ @order.unshift(item)
57
+ need_reindex = true # Need to recalculate the positions.
58
+ end
59
+ reindex if need_reindex
60
+ self
61
+ end
62
+
63
+ def unshift(item)
64
+ unshift!([item])
65
+ end
66
+
67
+ clone_method :-, :subtract!
68
+ def subtract!(items)
69
+ @order.replace(self.to_a - items.to_a)
70
+ reindex
71
+ self
72
+ end
73
+
74
+ clone_method :&, :intersect!
75
+ def intersect!(items)
76
+ @order.replace(self.to_a & items.to_a)
77
+ reindex
78
+ self
79
+ end
80
+
81
+ def reorder!(items)
82
+ new_order = (items.to_a & self.to_a) + self.to_a
83
+ @order.replace(new_order.uniq)
84
+ reindex
85
+ self
86
+ end
87
+
88
+ def shuffle!
89
+ sort_by! { rand }
90
+ end
91
+
92
+ def reverse_reorder!(items)
93
+ return self if items.empty?
94
+ reverse!.reorder!(items).reverse!
95
+ end
96
+
97
+ def to_ary
98
+ @order.dup
99
+ end
100
+
101
+ def index(item)
102
+ @position[item]
103
+ end
104
+
105
+ def delete(item)
106
+ @order.delete(item) do
107
+ return block_given? ? yield : nil
108
+ end
109
+ reindex
110
+ item
111
+ end
112
+
113
+ def delete_at(index, &block)
114
+ delete(self[index], &block)
115
+ end
116
+
117
+ [:sort_by, :sort, :reverse, :collect, :map, :compact, :reject].each do |method_name|
118
+ eval %{
119
+ def #{method_name}!(*args, &block)
120
+ new_order = @order.send(:#{method_name}, *args, &block)
121
+ replace(new_order)
122
+ self
123
+ end
124
+ }
125
+ end
126
+
127
+ def select!
128
+ reject! {|item| not yield(item)}
129
+ end
130
+
131
+ # Array#slice! is somewhat inconsistent with the other bang methods,
132
+ # and this emulates that. For the more consistent behavior use limit!
133
+ def slice!(*args)
134
+ removed_slice = @order.slice!(*args)
135
+ reindex
136
+ removed_slice
137
+ end
138
+
139
+ clone_method :limit
140
+ def limit!(limit, offset = 0)
141
+ new_order = @order.slice(offset, limit) || []
142
+ replace(new_order)
143
+ self
144
+ end
145
+
146
+ private
147
+
148
+ def reindex
149
+ @position.clear
150
+ @order.each_with_index do |item, index|
151
+ @position[item] = index
152
+ end
153
+ end
154
+
155
+ end
156
+
157
+ module Enumerable
158
+ def to_ordered_set
159
+ self.kind_of?(OrderedSet) ? self : OrderedSet.new(self)
160
+ end
161
+ end
@@ -0,0 +1,49 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{ordered_set}
8
+ s.version = "0.1.1"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Justin Balthrop"]
12
+ s.date = %q{2010-04-13}
13
+ s.description = %q{Like Set except it maintains the order of objects}
14
+ s.email = %q{code@justinbalthrop.com}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE",
17
+ "README.rdoc"
18
+ ]
19
+ s.files = [
20
+ "LICENSE",
21
+ "README.rdoc",
22
+ "Rakefile",
23
+ "VERSION.yml",
24
+ "lib/ordered_set.rb",
25
+ "ordered_set.gemspec",
26
+ "test/ordered_set_test.rb",
27
+ "test/test_helper.rb"
28
+ ]
29
+ s.homepage = %q{http://github.com/ninjudd/ordered_set}
30
+ s.rdoc_options = ["--charset=UTF-8"]
31
+ s.require_paths = ["lib"]
32
+ s.rubygems_version = %q{1.3.5}
33
+ s.summary = %q{Like Set except it maintains the order of objects}
34
+ s.test_files = [
35
+ "test/ordered_set_test.rb",
36
+ "test/test_helper.rb"
37
+ ]
38
+
39
+ if s.respond_to? :specification_version then
40
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
41
+ s.specification_version = 3
42
+
43
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
44
+ else
45
+ end
46
+ else
47
+ end
48
+ end
49
+
@@ -0,0 +1,300 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+
3
+ class OrderedSetTest < Test::Unit::TestCase
4
+
5
+ should 'create an ordered_set' do
6
+ assert [1,3,2,3,1,:foo].to_ordered_set.is_a?(OrderedSet)
7
+ assert OrderedSet.new([1,3,2,3,1,:foo]).is_a?(OrderedSet)
8
+ end
9
+
10
+ should 'be enumerable' do
11
+ assert_equal [nil,1], [nil,1,1,nil].to_ordered_set.collect {|i| i}
12
+ assert_equal [1,3,2,:foo], [1,3,2,3,1,:foo].to_ordered_set.collect {|i| i}
13
+ assert_equal [-1,-3,-12], [1,3,12,3,1].to_ordered_set.collect {|i| -i}
14
+ assert_equal [1], [1,1,0,1,0,0,0,1].to_ordered_set.select {|i| i != 0}
15
+ end
16
+
17
+ should 'replace the set contents' do
18
+ set = [].to_ordered_set
19
+ set.replace([5,0,5])
20
+
21
+ assert_equal [5,0], set.to_a
22
+ assert_consistent set
23
+ end
24
+
25
+ should 'join elements in set' do
26
+ set = ["five","O","five"].to_ordered_set
27
+ assert_equal 'five-O', set.join('-')
28
+ set << 5
29
+ assert_equal 'five-O-5', set.join('-')
30
+ assert_consistent set
31
+ end
32
+
33
+ should 'add sets' do
34
+ set = [1,3,4].to_ordered_set + [2,3,5].to_ordered_set
35
+
36
+ assert_equal [1,3,4,2,5], set.to_a
37
+ assert_consistent set
38
+ end
39
+
40
+ should 'subtract sets' do
41
+ set = [5,1,3,4].to_ordered_set - [2,3,5].to_ordered_set
42
+
43
+ assert_equal [1,4], set.to_a
44
+ assert_consistent set
45
+ end
46
+
47
+ should 'intersect sets' do
48
+ set = [5,1,3,4].to_ordered_set & [2,3,5].to_ordered_set
49
+
50
+ assert_equal [5,3], set.to_a
51
+ assert_consistent set
52
+ end
53
+
54
+ should 'reorder set' do
55
+ set = [5,1,3,4].to_ordered_set
56
+ set.reorder!([2,3,5].to_ordered_set)
57
+
58
+ assert_equal [3,5,1,4], set.to_a
59
+ assert_consistent set
60
+ end
61
+
62
+ should 'clear set' do
63
+ set = [1,2,3].to_ordered_set
64
+
65
+ set.clear
66
+ assert set.empty?
67
+ end
68
+
69
+ should 'clone set' do
70
+ set = [1,2,3].to_ordered_set
71
+ copy = set.clone
72
+
73
+ copy.clear
74
+ assert_equal [], copy.to_a
75
+ assert_equal [1,2,3], set.to_a
76
+ end
77
+
78
+ should 'include? all elements' do
79
+ set = [1,3,2,3,1,:foo,nil].to_ordered_set
80
+
81
+ assert set.include?(1)
82
+ assert set.include?(3)
83
+ assert set.include?(:foo)
84
+ assert set.include?(nil)
85
+ assert_consistent set
86
+ end
87
+
88
+ should 'have the correct size and length' do
89
+ set = [1,1,1,1,2,2,1,2,3,4,2,1,0].to_ordered_set
90
+ assert_equal 5, set.size
91
+ assert_equal 5, set.length
92
+ assert_consistent set
93
+ end
94
+
95
+ should 'be empty' do
96
+ set = [].to_ordered_set
97
+ assert set.empty?
98
+
99
+ set = [1].to_ordered_set
100
+ assert !set.empty?
101
+ end
102
+
103
+ should 'check for any elements' do
104
+ set = [].to_ordered_set
105
+ assert !set.any?
106
+
107
+ set = [1].to_ordered_set
108
+ assert set.any?
109
+ end
110
+
111
+ should 'support index operator' do
112
+ set = [1,2,2,3,4,1,0].to_ordered_set
113
+
114
+ assert_equal 1, set[0]
115
+ assert_equal 4, set[3]
116
+ assert_equal nil, set[100]
117
+ assert_equal [2,3], set[1,2]
118
+ assert_equal [3,4,0], set[2..4]
119
+ assert_consistent set
120
+ end
121
+
122
+ should 'get a slice from a set' do
123
+ set = [1,2,2,3,4,1,0].to_ordered_set
124
+
125
+ assert_equal 1, set.slice(0)
126
+ assert_equal 4, set.slice(3)
127
+ assert_equal nil, set.slice(100)
128
+ assert_equal [2,3], set.slice(1,2)
129
+ assert_equal [3,4,0], set.slice(2..4)
130
+ assert_consistent set
131
+ end
132
+
133
+ should 'lookup index of element' do
134
+ set = [1,2,2,3,4,1,0].to_ordered_set
135
+
136
+ assert_equal 1, set.index(2)
137
+ assert_equal 4, set.index(0)
138
+ assert_consistent set
139
+ end
140
+
141
+ should 'append elements' do
142
+ set = [1,2,2,3,4,1,0].to_ordered_set
143
+
144
+ set << 1
145
+ assert_equal 5, set.size
146
+ assert set.include?(1)
147
+ assert_equal [1,2,3,4,0], set.to_a
148
+ assert_consistent set
149
+
150
+ set << 100
151
+ assert_equal 6, set.size
152
+ assert set.include?(100)
153
+ assert_equal [1,2,3,4,0,100], set.to_a
154
+ assert_consistent set
155
+ end
156
+
157
+ should 'unshift elements' do
158
+ set = [1,2,2,3,4,1,0].to_ordered_set
159
+
160
+ set.unshift(1)
161
+ assert_equal 5, set.size
162
+ assert set.include?(1)
163
+ assert_equal [1,2,3,4,0], set.to_a
164
+ assert_consistent set
165
+
166
+ set.unshift(100)
167
+ assert_equal 6, set.size
168
+ assert set.include?(100)
169
+ assert_equal [100,1,2,3,4,0], set.to_a
170
+ assert_consistent set
171
+ end
172
+
173
+
174
+ should 'delete elements' do
175
+ set = [1,2,2,3,4,1,nil].to_ordered_set
176
+
177
+ assert_equal 1, set.delete(1)
178
+ assert_equal [2,3,4,nil], set.to_a
179
+ assert_equal 4, set.size
180
+ assert !set.include?(1)
181
+ assert_consistent set
182
+
183
+ assert_equal nil, set.delete(nil)
184
+ assert_equal [2,3,4], set.to_a
185
+ assert_equal 3, set.size
186
+ assert !set.include?(nil)
187
+ assert_consistent set
188
+
189
+ assert_equal false, set.delete(100) { false }
190
+ assert_equal [2,3,4], set.to_a
191
+ assert_equal 3, set.size
192
+ assert !set.include?(100)
193
+ assert_consistent set
194
+ end
195
+
196
+ should 'delete elements at specified position' do
197
+ set = [1,2,2,3,4,1,nil].to_ordered_set
198
+
199
+ assert_equal 1, set.delete_at(0)
200
+ assert_equal [2,3,4,nil], set.to_a
201
+ assert_equal 4, set.size
202
+ assert !set.include?(1)
203
+ assert_consistent set
204
+
205
+ assert_equal nil, set.delete_at(3)
206
+ assert_equal [2,3,4], set.to_a
207
+ assert_equal 3, set.size
208
+ assert !set.include?(nil)
209
+ assert_consistent set
210
+
211
+ assert_equal false, set.delete(100) { false }
212
+ assert_equal [2,3,4], set.to_a
213
+ assert_equal 3, set.size
214
+ assert !set.include?(100)
215
+ assert_consistent set
216
+ end
217
+
218
+ should 'sort set' do
219
+ set = [1,2,2,3,4,1,0].to_ordered_set
220
+
221
+ set.sort!
222
+ assert_equal [0,1,2,3,4], set.to_a
223
+ assert_consistent set
224
+ end
225
+
226
+ should 'reverse set' do
227
+ set = [0,1,2,2,3,4,1,0].to_ordered_set
228
+
229
+ set.reverse!
230
+ assert_equal [4,3,2,1,0], set.to_a
231
+ assert_consistent set
232
+ end
233
+
234
+ should 'modify using collect!' do
235
+ set = [0,1,2,2,3,4,1,0,5,6,8,9,11,32424].to_ordered_set
236
+
237
+ set.collect! {|i| i % 3}
238
+ assert_equal [0,1,2], set.to_a
239
+ assert_consistent set
240
+ end
241
+
242
+ should 'modify using map!' do
243
+ set = [0,1,2,2,3,4,1,0].to_ordered_set
244
+
245
+ set.collect! {|i| i * 10}
246
+ assert_equal [0,10,20,30,40], set.to_a
247
+ assert_consistent set
248
+ end
249
+
250
+ should 'compact set' do
251
+ set = [0,1,2,2,nil,3,nil,4,1,0].to_ordered_set
252
+
253
+ set.compact!
254
+ assert_equal [0,1,2,3,4], set.to_a
255
+ assert_consistent set
256
+ end
257
+
258
+ should 'select elements from set' do
259
+ set = [0,1,2,2,3,4,1,0].to_ordered_set
260
+
261
+ set.select! {|i| i % 2 == 0}
262
+ assert_equal [0,2,4], set.to_a
263
+ assert_consistent set
264
+ end
265
+
266
+ should 'reject elements from set' do
267
+ set = [0,1,2,2,3,4,1,0].to_ordered_set
268
+
269
+ set.reject! {|i| i % 2 == 0}
270
+ assert_equal [1,3], set.to_a
271
+ assert_consistent set
272
+ end
273
+
274
+ should 'modify set with slice!' do
275
+ set = [0,1,2,2,3,4,1,0].to_ordered_set
276
+
277
+ assert_equal [1,2,3], set.slice!(1..3)
278
+ assert_equal [0,4], set.to_a
279
+ assert_consistent set
280
+ end
281
+
282
+ should 'limit set' do
283
+ set = [0,1,2,2,3,4,1,0].to_ordered_set.limit!(3, 1)
284
+
285
+ assert_equal [1,2,3], set.to_a
286
+ assert_consistent set
287
+
288
+ set = [0,1,2,2,3,4,1,0].to_ordered_set.limit!(2)
289
+
290
+ assert_equal [0,1], set.to_a
291
+ assert_consistent set
292
+ end
293
+
294
+ def assert_consistent(set)
295
+ set.each do |item|
296
+ assert set.include?(item)
297
+ end
298
+ end
299
+
300
+ end
@@ -0,0 +1,11 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+ require 'shoulda'
4
+ require 'mocha'
5
+
6
+ $LOAD_PATH.unshift File.dirname(__FILE__) + "/../lib"
7
+ $LOAD_PATH.unshift File.dirname(__FILE__) + "/../../deep_clonable/lib"
8
+ require 'ordered_set'
9
+
10
+ class Test::Unit::TestCase
11
+ end
metadata ADDED
@@ -0,0 +1,64 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ordered_set
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ platform: ruby
6
+ authors:
7
+ - Justin Balthrop
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2010-04-13 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description: Like Set except it maintains the order of objects
17
+ email: code@justinbalthrop.com
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files:
23
+ - LICENSE
24
+ - README.rdoc
25
+ files:
26
+ - LICENSE
27
+ - README.rdoc
28
+ - Rakefile
29
+ - VERSION.yml
30
+ - lib/ordered_set.rb
31
+ - ordered_set.gemspec
32
+ - test/ordered_set_test.rb
33
+ - test/test_helper.rb
34
+ has_rdoc: true
35
+ homepage: http://github.com/ninjudd/ordered_set
36
+ licenses: []
37
+
38
+ post_install_message:
39
+ rdoc_options:
40
+ - --charset=UTF-8
41
+ require_paths:
42
+ - lib
43
+ required_ruby_version: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: "0"
48
+ version:
49
+ required_rubygems_version: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: "0"
54
+ version:
55
+ requirements: []
56
+
57
+ rubyforge_project:
58
+ rubygems_version: 1.3.5
59
+ signing_key:
60
+ specification_version: 3
61
+ summary: Like Set except it maintains the order of objects
62
+ test_files:
63
+ - test/ordered_set_test.rb
64
+ - test/test_helper.rb