rack-mount 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,466 @@
1
+ require 'multiset'
2
+
3
+ # Multimap is a generalization of a map or associative array
4
+ # abstract data type in which more than one value may be associated
5
+ # with and returned for a given key.
6
+ class Multimap < Hash
7
+ #--
8
+ # Ignore protected aliases back to the original Hash methods
9
+ #++
10
+ module_eval %{
11
+ alias_method :hash_aref, :[]
12
+ protected :hash_aref
13
+
14
+ alias_method :hash_aset, :[]=
15
+ protected :hash_aset
16
+
17
+ alias_method :hash_each_pair, :each_pair
18
+ protected :hash_each_pair
19
+ }
20
+
21
+ # call-seq:
22
+ # Multimap[ [key =>|, value]* ] => multimap
23
+ #
24
+ # Creates a new multimap populated with the given objects.
25
+ #
26
+ # Multimap["a", 100, "b", 200] #=> {"a"=>[100], "b"=>[200]}
27
+ # Multimap["a" => 100, "b" => 200] #=> {"a"=>[100], "b"=>[200]}
28
+ def self.[](*args)
29
+ default = []
30
+
31
+ if args.size == 2 && args.last.is_a?(Hash)
32
+ default = args.shift
33
+ elsif !args.first.is_a?(Hash) && args.size % 2 == 1
34
+ default = args.shift
35
+ end
36
+
37
+ if args.size == 1 && args.first.is_a?(Hash)
38
+ args[0] = args.first.inject({}) { |hash, (key, value)|
39
+ unless value.is_a?(default.class)
40
+ value = (default.dup << value)
41
+ end
42
+ hash[key] = value
43
+ hash
44
+ }
45
+ else
46
+ index = 0
47
+ args.map! { |value|
48
+ unless index % 2 == 0 || value.is_a?(default.class)
49
+ value = (default.dup << value)
50
+ end
51
+ index += 1
52
+ value
53
+ }
54
+ end
55
+
56
+ map = super
57
+ map.default = default
58
+ map
59
+ end
60
+
61
+ # call-seq:
62
+ # Multimap.new => multimap
63
+ # Multimap.new(default) => multimap
64
+ #
65
+ # Returns a new, empty multimap.
66
+ #
67
+ # map = Multimap.new(Set.new)
68
+ # h["a"] = 100
69
+ # h["b"] = 200
70
+ # h["a"] #=> [100].to_set
71
+ # h["c"] #=> [].to_set
72
+ def initialize(default = [])
73
+ super
74
+ end
75
+
76
+ def initialize_copy(original) #:nodoc:
77
+ super
78
+ clear
79
+ original.each_pair { |key, container| self[key] = container }
80
+ self.default = original.default.dup
81
+ end
82
+
83
+ #--
84
+ # Setting a default proc is not supported
85
+ #++
86
+ undef :default_proc
87
+
88
+ # call-seq:
89
+ # map[key] = value => value
90
+ # map.store(key, value) => value
91
+ #
92
+ # Associates the value given by <i>value</i> with the key
93
+ # given by <i>key</i>. Unlike a regular hash, multiple can be
94
+ # assoicated with the same value.
95
+ #
96
+ # map = Multimap["a" => 100, "b" => 200]
97
+ # map["a"] = 9
98
+ # map["c"] = 4
99
+ # map #=> {"a" => [100, 9], "b" => [200], "c" => [4]}
100
+ def store(key, value)
101
+ update_container(key) do |container|
102
+ container << value
103
+ container
104
+ end
105
+ end
106
+ alias_method :[]=, :store
107
+
108
+ # call-seq:
109
+ # map.delete(key, value) => value
110
+ # map.delete(key) => value
111
+ #
112
+ # Deletes and returns a key-value pair from <i>map</i>. If only
113
+ # <i>key</i> is given, all the values matching that key will be
114
+ # deleted.
115
+ #
116
+ # map = Multimap["a" => 100, "b" => [200, 300]]
117
+ # map.delete("b", 300) #=> 300
118
+ # map.delete("a") #=> [100]
119
+ def delete(key, value = nil)
120
+ if value
121
+ hash_aref(key).delete(value)
122
+ else
123
+ super(key)
124
+ end
125
+ end
126
+
127
+ # call-seq:
128
+ # map.each { |key, value| block } => map
129
+ #
130
+ # Calls <i>block</i> for each key/value pair in <i>map</i>, passing
131
+ # the key and value to the block as a two-element array.
132
+ #
133
+ # map = Multimap["a" => 100, "b" => [200, 300]]
134
+ # map.each { |key, value| puts "#{key} is #{value}" }
135
+ #
136
+ # <em>produces:</em>
137
+ #
138
+ # a is 100
139
+ # b is 200
140
+ # b is 300
141
+ def each
142
+ each_pair do |key, value|
143
+ yield [key, value]
144
+ end
145
+ end
146
+
147
+ # call-seq:
148
+ # map.each_association { |key, container| block } => map
149
+ #
150
+ # Calls <i>block</i> once for each key/container in <i>map</i>, passing
151
+ # the key and container to the block as parameters.
152
+ #
153
+ # map = Multimap["a" => 100, "b" => [200, 300]]
154
+ # map.each_association { |key, container| puts "#{key} is #{container}" }
155
+ #
156
+ # <em>produces:</em>
157
+ #
158
+ # a is [100]
159
+ # b is [200, 300]
160
+ def each_association
161
+ # each_pair
162
+ end
163
+ #--
164
+ # Ignore alias_method since the definition above serves
165
+ # as its documentation.
166
+ #++
167
+ module_eval "alias_method :each_association, :each_pair"
168
+
169
+ # call-seq:
170
+ # map.each_container { |container| block } => map
171
+ #
172
+ # Calls <i>block</i> for each container in <i>map</i>, passing the
173
+ # container as a parameter.
174
+ #
175
+ # map = Multimap["a" => 100, "b" => [200, 300]]
176
+ # map.each_container { |container| puts container }
177
+ #
178
+ # <em>produces:</em>
179
+ #
180
+ # [100]
181
+ # [200, 300]
182
+ def each_container
183
+ each_association do |_, container|
184
+ yield container
185
+ end
186
+ end
187
+
188
+ # call-seq:
189
+ # map.each_key { |key| block } => map
190
+ #
191
+ # Calls <i>block</i> for each key in <i>hsh</i>, passing the key
192
+ # as a parameter.
193
+ #
194
+ # map = Multimap["a" => 100, "b" => [200, 300]]
195
+ # map.each_key { |key| puts key }
196
+ #
197
+ # <em>produces:</em>
198
+ #
199
+ # a
200
+ # b
201
+ # b
202
+ def each_key
203
+ each_pair do |key, _|
204
+ yield key
205
+ end
206
+ end
207
+
208
+ # call-seq:
209
+ # map.each_pair { |key_value_array| block } => map
210
+ #
211
+ # Calls <i>block</i> for each key/value pair in <i>map</i>,
212
+ # passing the key and value as parameters.
213
+ #
214
+ # map = Multimap["a" => 100, "b" => [200, 300]]
215
+ # map.each_pair { |key, value| puts "#{key} is #{value}" }
216
+ #
217
+ # <em>produces:</em>
218
+ #
219
+ # a is 100
220
+ # b is 200
221
+ # b is 300
222
+ def each_pair
223
+ each_association do |key, values|
224
+ values.each do |value|
225
+ yield key, value
226
+ end
227
+ end
228
+ end
229
+
230
+ # call-seq:
231
+ # map.each_value { |value| block } => map
232
+ #
233
+ # Calls <i>block</i> for each key in <i>map</i>, passing the
234
+ # value as a parameter.
235
+ #
236
+ # map = Multimap["a" => 100, "b" => [200, 300]]
237
+ # map.each_value { |value| puts value }
238
+ #
239
+ # <em>produces:</em>
240
+ #
241
+ # 100
242
+ # 200
243
+ # 300
244
+ def each_value
245
+ each_pair do |_, value|
246
+ yield value
247
+ end
248
+ end
249
+
250
+ def freeze #:nodoc:
251
+ each_container { |container| container.freeze }
252
+ default.freeze
253
+ super
254
+ end
255
+
256
+ # call-seq:
257
+ # map.has_value?(value) => true or false
258
+ # map.value?(value) => true or false
259
+ #
260
+ # Returns <tt>true</tt> if the given value is present for any key
261
+ # in <i>map</i>.
262
+ #
263
+ # map = Multimap["a" => 100, "b" => [200, 300]]
264
+ # map.has_value?(300) #=> true
265
+ # map.has_value?(999) #=> false
266
+ def has_value?(value)
267
+ values.include?(value)
268
+ end
269
+ alias_method :value?, :has_value?
270
+
271
+ # call-seq:
272
+ # map.index(value) => key
273
+ #
274
+ # Returns the key for a given value. If not found, returns
275
+ # <tt>nil</tt>.
276
+ #
277
+ # map = Multimap["a" => 100, "b" => [200, 300]]
278
+ # map.index(100) #=> "a"
279
+ # map.index(200) #=> "b"
280
+ # map.index(999) #=> nil
281
+ def index(value)
282
+ invert[value]
283
+ end
284
+
285
+ # call-seq:
286
+ # map.replace(other_map) => map
287
+ #
288
+ # Replaces the contents of <i>map</i> with the contents of
289
+ # <i>other_map</i>.
290
+ #
291
+ # map = Multimap["a" => 100, "b" => 200]
292
+ # map.replace({ "c" => 300, "d" => 400 })
293
+ # #=> Multimap["c" => 300, "d" => 400]
294
+ def replace(other)
295
+ case other
296
+ when Array
297
+ super(self.class[self.default, *other])
298
+ when Hash
299
+ super(self.class[self.default, other])
300
+ when self.class
301
+ super
302
+ else
303
+ raise ArgumentError
304
+ end
305
+ end
306
+
307
+ # call-seq:
308
+ # map.invert => multimap
309
+ #
310
+ # Returns a new multimap created by using <i>map</i>'s values as keys,
311
+ # and the keys as values.
312
+ #
313
+ # map = Multimap["n" => 100, "m" => 100, "d" => [200, 300]]
314
+ # map.invert #=> Multimap[100 => ["n", "m"], 200 => "d", 300 => "d"]
315
+ def invert
316
+ h = self.class.new(default.dup)
317
+ each_pair { |key, value| h[value] = key }
318
+ h
319
+ end
320
+
321
+ # call-seq:
322
+ # map.keys => multiset
323
+ #
324
+ # Returns a new +Multiset+ populated with the keys from this hash. See also
325
+ # <tt>Multimap#values</tt> and <tt>Multimap#containers</tt>.
326
+ #
327
+ # map = Multimap["a" => 100, "b" => [200, 300], "c" => 400]
328
+ # map.keys #=> Multiset.new(["a", "b", "b", "c"])
329
+ def keys
330
+ keys = Multiset.new
331
+ each_key { |key| keys << key }
332
+ keys
333
+ end
334
+
335
+ # call-seq:
336
+ # map.length => fixnum
337
+ # map.size => fixnum
338
+ #
339
+ # Returns the number of key-value pairs in the map.
340
+ #
341
+ # map = Multimap["a" => 100, "b" => [200, 300], "c" => 400]
342
+ # map.length #=> 4
343
+ # map.delete("a") #=> 100
344
+ # map.length #=> 3
345
+ def size
346
+ values.size
347
+ end
348
+ alias_method :length, :size
349
+
350
+ # call-seq:
351
+ # map.merge(other_map) => multimap
352
+ #
353
+ # Returns a new multimap containing the contents of <i>other_map</i> and
354
+ # the contents of <i>map</i>.
355
+ #
356
+ # map1 = Multimap["a" => 100, "b" => 200]
357
+ # map2 = Multimap["a" => 254, "c" => 300]
358
+ # map2.merge(map2) #=> Multimap["a" => 100, "b" => [200, 254], "c" => 300]
359
+ # map1 #=> Multimap["a" => 100, "b" => 200]
360
+ def merge(other)
361
+ dup.update(other)
362
+ end
363
+
364
+ # call-seq:
365
+ # map.merge!(other_map) => multimap
366
+ # map.update(other_map) => multimap
367
+ #
368
+ # Adds each pair from <i>other_map</i> to <i>map</i>.
369
+ #
370
+ # map1 = Multimap["a" => 100, "b" => 200]
371
+ # map2 = Multimap["b" => 254, "c" => 300]
372
+ #
373
+ # map1.merge!(map2)
374
+ # #=> Multimap["a" => 100, "b" => [200, 254], "c" => 300]
375
+ def update(other)
376
+ case other
377
+ when self.class
378
+ other.each_pair { |key, value| store(key, value) }
379
+ when Hash
380
+ update(self.class[self.default, other])
381
+ else
382
+ raise ArgumentError
383
+ end
384
+ self
385
+ end
386
+ alias_method :merge!, :update
387
+
388
+ # call-seq:
389
+ # map.select { |key, value| block } => multimap
390
+ #
391
+ # Returns a new Multimap consisting of the pairs for which the
392
+ # block returns true.
393
+ #
394
+ # map = Multimap["a" => 100, "b" => 200, "c" => 300]
395
+ # map.select { |k,v| k > "a" } #=> Multimap["b" => 200, "c" => 300]
396
+ # map.select { |k,v| v < 200 } #=> Multimap["a" => 100]
397
+ def select
398
+ inject(self.class.new) { |map, (key, value)|
399
+ map[key] = value if yield([key, value])
400
+ map
401
+ }
402
+ end
403
+
404
+ # call-seq:
405
+ # map.to_a => array
406
+ #
407
+ # Converts <i>map</i> to a nested array of [<i>key,
408
+ # value</i>] arrays.
409
+ #
410
+ # map = Multimap["a" => 100, "b" => [200, 300], "c" => 400]
411
+ # map.to_a #=> [["a", 100], ["b", 200], ["b", 300], ["c", 400]]
412
+ def to_a
413
+ ary = []
414
+ each_pair do |key, value|
415
+ ary << [key, value]
416
+ end
417
+ ary
418
+ end
419
+
420
+ # call-seq:
421
+ # map.to_hash => hash
422
+ #
423
+ # Converts <i>map</i> to a basic hash.
424
+ #
425
+ # map = Multimap["a" => 100, "b" => [200, 300]]
426
+ # map.to_hash #=> { "a" => [100], "b" => [200, 300] }
427
+ def to_hash
428
+ dup
429
+ end
430
+
431
+ # call-seq:
432
+ # map.containers => array
433
+ #
434
+ # Returns a new array populated with the containers from <i>map</i>. See
435
+ # also <tt>Multimap#keys</tt> and <tt>Multimap#values</tt>.
436
+ #
437
+ # map = Multimap["a" => 100, "b" => [200, 300]]
438
+ # map.containers #=> [[100], [200, 300]]
439
+ def containers
440
+ containers = []
441
+ each_container { |container| containers << container }
442
+ containers
443
+ end
444
+
445
+ # call-seq:
446
+ # map.values => array
447
+ #
448
+ # Returns a new array populated with the values from <i>map</i>. See
449
+ # also <tt>Multimap#keys</tt> and <tt>Multimap#containers</tt>.
450
+ #
451
+ # map = Multimap["a" => 100, "b" => [200, 300]]
452
+ # map.values #=> [100, 200, 300]
453
+ def values
454
+ values = []
455
+ each_value { |value| values << value }
456
+ values
457
+ end
458
+
459
+ protected
460
+ def update_container(key) #:nodoc:
461
+ container = hash_aref(key)
462
+ container = container.dup if container.equal?(default)
463
+ container = yield(container)
464
+ hash_aset(key, container)
465
+ end
466
+ end
@@ -0,0 +1,153 @@
1
+ require 'set'
2
+
3
+ # Multiset implements a collection of unordered values and
4
+ # allows duplicate values.
5
+ class Multiset < Set
6
+ def initialize(*args, &block) #:nodoc:
7
+ @hash = Hash.new(0)
8
+ super
9
+ end
10
+
11
+ # Returns the number of times an element belongs to the multiset.
12
+ def multiplicity(e)
13
+ @hash[e]
14
+ end
15
+
16
+ # Returns the total number of elements in a multiset, including
17
+ # repeated memberships
18
+ def cardinality
19
+ @hash.inject(0) { |s, (e, m)| s += m }
20
+ end
21
+ alias_method :size, :cardinality
22
+ alias_method :length, :cardinality
23
+
24
+ # Converts the set to an array. The order of elements is uncertain.
25
+ def to_a
26
+ inject([]) { |ary, (key, _)| ary << key }
27
+ end
28
+
29
+ # Returns true if the set is a superset of the given set.
30
+ def superset?(set)
31
+ set.is_a?(self.class) or raise ArgumentError, "value must be a set"
32
+ return false if cardinality < set.cardinality
33
+ set.all? { |o| set.multiplicity(o) <= multiplicity(o) }
34
+ end
35
+
36
+ # Returns true if the set is a proper superset of the given set.
37
+ def proper_superset?(set)
38
+ set.is_a?(self.class) or raise ArgumentError, "value must be a set"
39
+ return false if cardinality <= set.cardinality
40
+ set.all? { |o| set.multiplicity(o) <= multiplicity(o) }
41
+ end
42
+
43
+ # Returns true if the set is a subset of the given set.
44
+ def subset?(set)
45
+ set.is_a?(self.class) or raise ArgumentError, "value must be a set"
46
+ return false if set.cardinality < cardinality
47
+ all? { |o| multiplicity(o) <= set.multiplicity(o) }
48
+ end
49
+
50
+ # Returns true if the set is a proper subset of the given set.
51
+ def proper_subset?(set)
52
+ set.is_a?(self.class) or raise ArgumentError, "value must be a set"
53
+ return false if set.cardinality <= cardinality
54
+ all? { |o| multiplicity(o) <= set.multiplicity(o) }
55
+ end
56
+
57
+ # Calls the given block once for each element in the set, passing
58
+ # the element as parameter. Returns an enumerator if no block is
59
+ # given.
60
+ def each
61
+ @hash.each_pair do |key, multiplicity|
62
+ multiplicity.times do
63
+ yield(key)
64
+ end
65
+ end
66
+ self
67
+ end
68
+
69
+ # Adds the given object to the set and returns self. Use +merge+ to
70
+ # add many elements at once.
71
+ def add(o)
72
+ @hash[o] ||= 0
73
+ @hash[o] += 1
74
+ self
75
+ end
76
+ alias << add
77
+
78
+ undef :add?
79
+
80
+ # Deletes all the identical object from the set and returns self.
81
+ # If +n+ is given, it will remove that amount of identical objects
82
+ # from the set. Use +subtract+ to delete many different items at
83
+ # once.
84
+ def delete(o, n = nil)
85
+ if n
86
+ @hash[o] ||= 0
87
+ @hash[o] -= n if @hash[o] > 0
88
+ @hash.delete(o) if @hash[o] == 0
89
+ else
90
+ @hash.delete(o)
91
+ end
92
+ self
93
+ end
94
+
95
+ undef :delete?
96
+
97
+ # Deletes every element of the set for which block evaluates to
98
+ # true, and returns self.
99
+ def delete_if
100
+ each { |o| delete(o) if yield(o) }
101
+ self
102
+ end
103
+
104
+ # Merges the elements of the given enumerable object to the set and
105
+ # returns self.
106
+ def merge(enum)
107
+ enum.each { |o| add(o) }
108
+ self
109
+ end
110
+
111
+ # Deletes every element that appears in the given enumerable object
112
+ # and returns self.
113
+ def subtract(enum)
114
+ enum.each { |o| delete(o, 1) }
115
+ self
116
+ end
117
+
118
+ # Returns a new set containing elements common to the set and the
119
+ # given enumerable object.
120
+ def &(enum)
121
+ s = dup
122
+ n = self.class.new
123
+ enum.each { |o|
124
+ if s.include?(o)
125
+ s.delete(o, 1)
126
+ n.add(o)
127
+ end
128
+ }
129
+ n
130
+ end
131
+ alias intersection &
132
+
133
+ # Returns a new set containing elements exclusive between the set
134
+ # and the given enumerable object. (set ^ enum) is equivalent to
135
+ # ((set | enum) - (set & enum)).
136
+ def ^(enum)
137
+ n = self.class.new(enum)
138
+ each { |o| n.include?(o) ? n.delete(o, 1) : n.add(o) }
139
+ n
140
+ end
141
+
142
+ # Returns true if two sets are equal. Two multisets are equal if
143
+ # they have the same cardinalities and each element has the same
144
+ # multiplicity in both sets. The equality of each element inside
145
+ # the multiset is defined according to Object#eql?.
146
+ def eql?(set)
147
+ return true if equal?(set)
148
+ set = self.class.new(set) unless set.is_a?(self.class)
149
+ return false unless cardinality == set.cardinality
150
+ superset?(set) && subset?(set)
151
+ end
152
+ alias_method :==, :eql?
153
+ end