ninjudd-ordered_set 0.1.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.
@@ -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,4 @@
1
+ ---
2
+ :patch: 0
3
+ :major: 0
4
+ :minor: 1
@@ -0,0 +1,157 @@
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 reverse_reorder!(items)
89
+ return self if items.empty?
90
+ reverse!.reorder!(items).reverse!
91
+ end
92
+
93
+ def to_ary
94
+ @order.dup
95
+ end
96
+
97
+ def index(item)
98
+ @position[item]
99
+ end
100
+
101
+ def delete(item)
102
+ @order.delete(item) do
103
+ return block_given? ? yield : nil
104
+ end
105
+ reindex
106
+ item
107
+ end
108
+
109
+ def delete_at(index, &block)
110
+ delete(self[index], &block)
111
+ end
112
+
113
+ [:sort_by, :sort, :reverse, :collect, :map, :compact, :reject].each do |method_name|
114
+ eval %{
115
+ def #{method_name}!(*args, &block)
116
+ new_order = @order.send(:#{method_name}, *args, &block)
117
+ replace(new_order)
118
+ self
119
+ end
120
+ }
121
+ end
122
+
123
+ def select!
124
+ reject! {|item| not yield(item)}
125
+ end
126
+
127
+ # Array#slice! is somewhat inconsistent with the other bang methods,
128
+ # and this emulates that. For the more consistent behavior use limit!
129
+ def slice!(*args)
130
+ removed_slice = @order.slice!(*args)
131
+ reindex
132
+ removed_slice
133
+ end
134
+
135
+ clone_method :limit
136
+ def limit!(limit, offset = 0)
137
+ new_order = @order.slice(offset, limit) || []
138
+ replace(new_order)
139
+ self
140
+ end
141
+
142
+ private
143
+
144
+ def reindex
145
+ @position.clear
146
+ @order.each_with_index do |item, index|
147
+ @position[item] = index
148
+ end
149
+ end
150
+
151
+ end
152
+
153
+ module Enumerable
154
+ def to_ordered_set
155
+ self.kind_of?(OrderedSet) ? self : OrderedSet.new(self)
156
+ end
157
+ end
@@ -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,58 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ninjudd-ordered_set
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Justin Balthrop
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-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
+
24
+ files:
25
+ - README.rdoc
26
+ - VERSION.yml
27
+ - lib/ordered_set.rb
28
+ - test/ordered_set_test.rb
29
+ - test/test_helper.rb
30
+ has_rdoc: true
31
+ homepage: http://github.com/ninjudd/ordered_set
32
+ post_install_message:
33
+ rdoc_options:
34
+ - --inline-source
35
+ - --charset=UTF-8
36
+ require_paths:
37
+ - lib
38
+ required_ruby_version: !ruby/object:Gem::Requirement
39
+ requirements:
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ version: "0"
43
+ version:
44
+ required_rubygems_version: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: "0"
49
+ version:
50
+ requirements: []
51
+
52
+ rubyforge_project:
53
+ rubygems_version: 1.2.0
54
+ signing_key:
55
+ specification_version: 2
56
+ summary: Like Set except it maintains the order of objects
57
+ test_files: []
58
+