Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Put the directories in git

  • Loading branch information...
commit 8db273f1bf7a28c845da0e9985fc9b80c8adb126 1 parent 5db5154
Yehuda Katz authored
Showing with 6,863 additions and 2 deletions.
  1. +0 −1  vendor/gems/dirs/multimap
  2. +20 −0 vendor/gems/dirs/multimap/MIT-LICENSE
  3. +1 −0  vendor/gems/dirs/multimap/README.rdoc
  4. +49 −0 vendor/gems/dirs/multimap/Rakefile
  5. +60 −0 vendor/gems/dirs/multimap/benchmarks/bm_nested_multimap_construction.rb
  6. +33 −0 vendor/gems/dirs/multimap/benchmarks/bm_nested_multimap_lookup.rb
  7. +2 −0  vendor/gems/dirs/multimap/ext/extconf.rb
  8. +17 −0 vendor/gems/dirs/multimap/ext/nested_multimap_ext.c
  9. +86 −0 vendor/gems/dirs/multimap/extras/graphing.rb
  10. +467 −0 vendor/gems/dirs/multimap/lib/multimap.rb
  11. +153 −0 vendor/gems/dirs/multimap/lib/multiset.rb
  12. +151 −0 vendor/gems/dirs/multimap/lib/nested_multimap.rb
  13. +20 −0 vendor/gems/dirs/multimap/multimap.gemspec
  14. +50 −0 vendor/gems/dirs/multimap/spec/enumerable_examples.rb
  15. +230 −0 vendor/gems/dirs/multimap/spec/hash_examples.rb
  16. +83 −0 vendor/gems/dirs/multimap/spec/multimap_spec.rb
  17. +172 −0 vendor/gems/dirs/multimap/spec/multiset_spec.rb
  18. +185 −0 vendor/gems/dirs/multimap/spec/nested_multimap_spec.rb
  19. +301 −0 vendor/gems/dirs/multimap/spec/set_examples.rb
  20. +0 −1  vendor/gems/dirs/rack-mount
  21. +20 −0 vendor/gems/dirs/rack-mount/LICENSE
  22. +28 −0 vendor/gems/dirs/rack-mount/README.rdoc
  23. +55 −0 vendor/gems/dirs/rack-mount/Rakefile
  24. +47 −0 vendor/gems/dirs/rack-mount/benchmark/bm_collisions_recognition.rb
  25. +41 −0 vendor/gems/dirs/rack-mount/benchmark/bm_nested_recognition.rb
  26. +10 −0 vendor/gems/dirs/rack-mount/benchmark/bm_optimizations_benchmark.rb
  27. +146 −0 vendor/gems/dirs/rack-mount/benchmark/helper.rb
  28. +11 −0 vendor/gems/dirs/rack-mount/benchmark/profile.rb
  29. +2 −0  vendor/gems/dirs/rack-mount/deps.rip
  30. +35 −0 vendor/gems/dirs/rack-mount/lib/rack/mount.rb
  31. +51 −0 vendor/gems/dirs/rack-mount/lib/rack/mount/analysis/frequency.rb
  32. +25 −0 vendor/gems/dirs/rack-mount/lib/rack/mount/analysis/histogram.rb
  33. +145 −0 vendor/gems/dirs/rack-mount/lib/rack/mount/analysis/splitting.rb
  34. +45 −0 vendor/gems/dirs/rack-mount/lib/rack/mount/const.rb
  35. +3 −0  vendor/gems/dirs/rack-mount/lib/rack/mount/exceptions.rb
  36. +163 −0 vendor/gems/dirs/rack-mount/lib/rack/mount/generatable_regexp.rb
  37. +57 −0 vendor/gems/dirs/rack-mount/lib/rack/mount/generation/route.rb
  38. +163 −0 vendor/gems/dirs/rack-mount/lib/rack/mount/generation/route_set.rb
  39. +104 −0 vendor/gems/dirs/rack-mount/lib/rack/mount/meta_method.rb
  40. +47 −0 vendor/gems/dirs/rack-mount/lib/rack/mount/mixover.rb
  41. +94 −0 vendor/gems/dirs/rack-mount/lib/rack/mount/multimap.rb
  42. +31 −0 vendor/gems/dirs/rack-mount/lib/rack/mount/prefix.rb
  43. +99 −0 vendor/gems/dirs/rack-mount/lib/rack/mount/recognition/code_generation.rb
  44. +59 −0 vendor/gems/dirs/rack-mount/lib/rack/mount/recognition/route.rb
  45. +88 −0 vendor/gems/dirs/rack-mount/lib/rack/mount/recognition/route_set.rb
  46. +49 −0 vendor/gems/dirs/rack-mount/lib/rack/mount/regexp_with_named_groups.rb
  47. +69 −0 vendor/gems/dirs/rack-mount/lib/rack/mount/route.rb
  48. +109 −0 vendor/gems/dirs/rack-mount/lib/rack/mount/route_set.rb
  49. +93 −0 vendor/gems/dirs/rack-mount/lib/rack/mount/strexp.rb
  50. +260 −0 vendor/gems/dirs/rack-mount/lib/rack/mount/utils.rb
  51. +466 −0 vendor/gems/dirs/rack-mount/lib/rack/mount/vendor/multimap/multimap.rb
  52. +153 −0 vendor/gems/dirs/rack-mount/lib/rack/mount/vendor/multimap/multiset.rb
  53. +156 −0 vendor/gems/dirs/rack-mount/lib/rack/mount/vendor/multimap/nested_multimap.rb
  54. +41 −0 vendor/gems/dirs/rack-mount/rack-mount.gemspec
  55. +89 −0 vendor/gems/dirs/rack-mount/test/abstract_unit.rb
  56. +3 −0  vendor/gems/dirs/rack-mount/test/dev.rip
  57. +6 −0 vendor/gems/dirs/rack-mount/test/fixtures.rb
  58. +1 −0  vendor/gems/dirs/rack-mount/test/fixtures/basic_set.rb
  59. +9 −0 vendor/gems/dirs/rack-mount/test/fixtures/basic_set_map.rb
  60. +93 −0 vendor/gems/dirs/rack-mount/test/fixtures/basic_set_map_19.rb
  61. +8 −0 vendor/gems/dirs/rack-mount/test/fixtures/default_set.rb
  62. +7 −0 vendor/gems/dirs/rack-mount/test/fixtures/echo_app.rb
  63. +18 −0 vendor/gems/dirs/rack-mount/test/fixtures/linear_basic_set.rb
  64. +1 −0  vendor/gems/dirs/rack-mount/test/fixtures/optimized_basic_set.rb
  65. +189 −0 vendor/gems/dirs/rack-mount/test/test_analyzer.rb
  66. +184 −0 vendor/gems/dirs/rack-mount/test/test_generatable_regexp.rb
  67. +106 −0 vendor/gems/dirs/rack-mount/test/test_generation.rb
  68. +139 −0 vendor/gems/dirs/rack-mount/test/test_meta_method.rb
  69. +40 −0 vendor/gems/dirs/rack-mount/test/test_mixover.rb
  70. +139 −0 vendor/gems/dirs/rack-mount/test/test_multimap.rb
  71. +66 −0 vendor/gems/dirs/rack-mount/test/test_prefix.rb
  72. +372 −0 vendor/gems/dirs/rack-mount/test/test_recognition.rb
  73. +28 −0 vendor/gems/dirs/rack-mount/test/test_regexp_with_named_groups.rb
  74. +100 −0 vendor/gems/dirs/rack-mount/test/test_route_set.rb
  75. +150 −0 vendor/gems/dirs/rack-mount/test/test_strexp.rb
  76. +70 −0 vendor/gems/dirs/rack-mount/test/test_utils.rb
1  vendor/gems/dirs/multimap
@@ -1 +0,0 @@
-Subproject commit 648e874278ba8148fc7bf760dfafc19dbc35dd17
20 vendor/gems/dirs/multimap/MIT-LICENSE
View
@@ -0,0 +1,20 @@
+Copyright (c) 2009 Joshua Peek
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1  vendor/gems/dirs/multimap/README.rdoc
View
@@ -0,0 +1 @@
+= Multimap
49 vendor/gems/dirs/multimap/Rakefile
View
@@ -0,0 +1,49 @@
+begin
+ require 'mg'
+ mg = MG.new('multimap.gemspec')
+ $spec = mg.spec
+rescue LoadError
+end
+
+
+require 'rake/rdoctask'
+
+Rake::RDocTask.new { |rdoc|
+ rdoc.title = 'Multimap'
+ rdoc.options << '--line-numbers' << '--inline-source'
+ rdoc.options << '--charset' << 'utf-8'
+
+ rdoc.rdoc_files.include('README.rdoc')
+ rdoc.rdoc_files.include('lib/**/*.rb')
+}
+
+namespace :rdoc do
+ task :publish => :rdoc do
+ Dir.chdir(File.dirname(__FILE__)) do
+ system "scp -r html/* joshpeek@rubyforge.org:/var/www/gforge-projects/multimap/"
+ end
+ end
+end
+
+task :default => :spec
+
+require 'spec/rake/spectask'
+
+Spec::Rake::SpecTask.new do |t|
+ t.libs << 'lib'
+ t.ruby_opts = ['-w']
+end
+
+
+begin
+ require 'rake/extensiontask'
+
+ Rake::ExtensionTask.new do |ext|
+ ext.name = 'nested_multimap_ext'
+ ext.gem_spec = $spec
+ end
+
+ desc "Run specs using C ext"
+ task "spec:ext" => [:compile, :spec, :clobber]
+rescue LoadError
+end
60 vendor/gems/dirs/multimap/benchmarks/bm_nested_multimap_construction.rb
View
@@ -0,0 +1,60 @@
+$: << 'lib'
+require 'nested_multimap'
+
+tiny_mapping = {
+ ["a"] => 100
+}
+
+medium_mapping = {
+ ["a"] => 100,
+ ["a", "b", "c"] => 200,
+ ["b"] => 300,
+ ["b", "c"] => 400,
+ ["c"] => 500,
+ ["c", "d"] => 600,
+ ["c", "d", "e"] => 700,
+ ["c", "d", "e", "f"] => 800
+}
+
+huge_mapping = {}
+alpha = ("a".."zz").to_a
+100.times do |n|
+ keys = ("a"..alpha[n % alpha.length]).to_a
+ huge_mapping[keys] = n * 100
+end
+
+require 'benchmark'
+
+Benchmark.bmbm do |x|
+ x.report("base:") {
+ NestedMultimap.new
+ }
+
+ x.report("tiny:") {
+ map = NestedMultimap.new
+ tiny_mapping.each_pair { |keys, value|
+ map[*keys] = value
+ }
+ }
+
+ x.report("medium:") {
+ map = NestedMultimap.new
+ medium_mapping.each_pair { |keys, value|
+ map[*keys] = value
+ }
+ }
+
+ x.report("huge:") {
+ map = NestedMultimap.new
+ huge_mapping.each_pair { |keys, value|
+ map[*keys] = value
+ }
+ }
+end
+
+# Pure Ruby
+# user system total real
+# base: 0.000000 0.000000 0.000000 ( 0.000014)
+# tiny: 0.000000 0.000000 0.000000 ( 0.000054)
+# medium: 0.000000 0.000000 0.000000 ( 0.000186)
+# huge: 0.050000 0.000000 0.050000 ( 0.051302)
33 vendor/gems/dirs/multimap/benchmarks/bm_nested_multimap_lookup.rb
View
@@ -0,0 +1,33 @@
+$: << 'lib'
+require 'nested_multimap'
+
+hash = { "a" => true }
+
+map = NestedMultimap.new
+map["a"] = 100
+map["a", "b", "c"] = 200
+map["a", "b", "c", "d", "e", "f"] = 300
+
+require 'benchmark'
+
+TIMES = 100_000
+Benchmark.bmbm do |x|
+ x.report("base:") { TIMES.times { hash["a"] } }
+ x.report("best:") { TIMES.times { map["a"] } }
+ x.report("average:") { TIMES.times { map["a", "b", "c"] } }
+ x.report("worst:") { TIMES.times { map["a", "b", "c", "d", "e", "f"] } }
+end
+
+# Pure Ruby
+# user system total real
+# base: 0.050000 0.000000 0.050000 ( 0.049722)
+# best: 0.480000 0.010000 0.490000 ( 0.491012)
+# average: 0.770000 0.000000 0.770000 ( 0.773535)
+# worst: 1.120000 0.010000 1.130000 ( 1.139097)
+
+# C extension
+# user system total real
+# base: 0.050000 0.000000 0.050000 ( 0.050990)
+# best: 0.090000 0.000000 0.090000 ( 0.088981)
+# average: 0.130000 0.000000 0.130000 ( 0.132098)
+# worst: 0.150000 0.000000 0.150000 ( 0.158293)
2  vendor/gems/dirs/multimap/ext/extconf.rb
View
@@ -0,0 +1,2 @@
+require 'mkmf'
+create_makefile('nested_multimap_ext')
17 vendor/gems/dirs/multimap/ext/nested_multimap_ext.c
View
@@ -0,0 +1,17 @@
+#include "ruby.h"
+
+static VALUE rb_nested_multimap_aref(int argc, VALUE *argv, VALUE self)
+{
+ int i;
+ VALUE r, k;
+
+ for (i = 0, r = self, k = TYPE(self); TYPE(r) == k; i++)
+ r = (i < argc) ? rb_hash_aref(r, argv[i]) : RHASH(r)->ifnone;
+
+ return r;
+}
+
+void Init_nested_multimap_ext() {
+ VALUE cNestedMultimap = rb_const_get(rb_cObject, rb_intern("NestedMultimap"));
+ rb_define_method(cNestedMultimap, "[]", rb_nested_multimap_aref, -1);
+}
86 vendor/gems/dirs/multimap/extras/graphing.rb
View
@@ -0,0 +1,86 @@
+require 'rubygems'
+
+gem 'ruby-graphviz'
+require 'graphviz'
+
+class Object
+ def to_graph_node
+ "node#{object_id}"
+ end
+
+ def to_graph_label
+ inspect.dot_escape
+ end
+
+ def add_to_graph(graph)
+ graph.add_node(to_graph_node, :label => to_graph_label)
+ end
+end
+
+class Array
+ def to_graph_label
+ "{#{map { |e| e.to_graph_label }.join('|')}}"
+ end
+end
+
+class String
+ DOT_ESCAPE = %w( \\ < > { } " " )
+ DOT_ESCAPE_REGEXP = Regexp.compile("(#{Regexp.union(*DOT_ESCAPE).source})")
+
+ def dot_escape
+ gsub(DOT_ESCAPE_REGEXP) {|s| "\\#{s}" }
+ end
+end
+
+class Multimap < Hash
+ def to_graph_label
+ label = []
+ hash_each_pair do |key, _|
+ label << "<#{key.to_graph_node}> #{key.to_graph_label}"
+ end
+ "#{label.join('|')}|<default>"
+ end
+
+ def add_to_graph(graph)
+ hash_node = super
+
+ hash_each_pair do |key, container|
+ node = container.add_to_graph(graph)
+ graph.add_edge("#{hash_node.name}:#{key.to_graph_node}", node)
+ end
+
+ unless default.nil?
+ node = default.add_to_graph(graph)
+ graph.add_edge("#{hash_node.name}:default", node)
+ end
+
+ hash_node
+ end
+
+ def to_graph
+ g = GraphViz::new('G')
+ g[:nodesep] = '.05'
+ g[:rankdir] = 'LR'
+
+ g.node[:shape] = 'record'
+ g.node[:width] = '.1'
+ g.node[:height] = '.1'
+
+ add_to_graph(g)
+
+ g
+ end
+
+ def open_graph!
+ to_graph.output(:path => '/opt/local/bin/', :file => '/tmp/graph.dot')
+ system('open /tmp/graph.dot')
+ end
+end
+
+if __FILE__ == $0
+ $: << 'lib'
+ require 'multimap'
+
+ map = Multimap['a' => 100, 'b' => [200, 300]]
+ map.open_graph!
+end
467 vendor/gems/dirs/multimap/lib/multimap.rb
View
@@ -0,0 +1,467 @@
+require 'multiset'
+
+# Multimap is a generalization of a map or associative array
+# abstract data type in which more than one value may be associated
+# with and returned for a given key.
+class Multimap < Hash
+ #--
+ # Ignore protected aliases back to the original Hash methods
+ #++
+ module_eval %{
+ alias_method :hash_aref, :[]
+ protected :hash_aref
+
+ alias_method :hash_aset, :[]=
+ protected :hash_aset
+
+ alias_method :hash_each_pair, :each_pair
+ protected :hash_each_pair
+ }
+
+ # call-seq:
+ # Multimap[ [key =>|, value]* ] => multimap
+ #
+ # Creates a new multimap populated with the given objects.
+ #
+ # Multimap["a", 100, "b", 200] #=> {"a"=>[100], "b"=>[200]}
+ # Multimap["a" => 100, "b" => 200] #=> {"a"=>[100], "b"=>[200]}
+ def self.[](*args)
+ default = []
+
+ if args.size == 2 && args.last.is_a?(Hash)
+ default = args.shift
+ elsif !args.first.is_a?(Hash) && args.size % 2 == 1
+ default = args.shift
+ end
+
+ if args.size == 1 && args.first.is_a?(Hash)
+ args[0] = args.first.inject({}) { |hash, (key, value)|
+ unless value.is_a?(default.class)
+ value = (default.dup << value)
+ end
+ hash[key] = value
+ hash
+ }
+ else
+ index = 0
+ args.map! { |value|
+ unless index % 2 == 0 || value.is_a?(default.class)
+ value = (default.dup << value)
+ end
+ index += 1
+ value
+ }
+ end
+
+ map = super
+ map.default = default
+ map
+ end
+
+ # call-seq:
+ # Multimap.new => multimap
+ # Multimap.new(default) => multimap
+ #
+ # Returns a new, empty multimap.
+ #
+ # map = Multimap.new(Set.new)
+ # h["a"] = 100
+ # h["b"] = 200
+ # h["a"] #=> [100].to_set
+ # h["c"] #=> [].to_set
+ def initialize(default = [])
+ super
+ end
+
+ def initialize_copy(original) #:nodoc:
+ super
+ clear
+ original.each_pair { |key, container| self[key] = container }
+ self.default = original.default.dup
+ end
+
+ #--
+ # Setting a default proc is not supported
+ #++
+ undef :default_proc
+
+ # call-seq:
+ # map[key] = value => value
+ # map.store(key, value) => value
+ #
+ # Associates the value given by <i>value</i> with the key
+ # given by <i>key</i>. Unlike a regular hash, multiple can be
+ # assoicated with the same value.
+ #
+ # map = Multimap["a" => 100, "b" => 200]
+ # map["a"] = 9
+ # map["c"] = 4
+ # map #=> {"a" => [100, 9], "b" => [200], "c" => [4]}
+ def store(key, value)
+ update_container(key) do |container|
+ container << value
+ container
+ end
+ end
+ alias_method :[]=, :store
+
+ # call-seq:
+ # map.delete(key, value) => value
+ # map.delete(key) => value
+ #
+ # Deletes and returns a key-value pair from <i>map</i>. If only
+ # <i>key</i> is given, all the values matching that key will be
+ # deleted.
+ #
+ # map = Multimap["a" => 100, "b" => [200, 300]]
+ # map.delete("b", 300) #=> 300
+ # map.delete("a") #=> [100]
+ def delete(key, value = nil)
+ if value
+ hash_aref(key).delete(value)
+ else
+ super(key)
+ end
+ end
+
+ # call-seq:
+ # map.each { |key, value| block } => map
+ #
+ # Calls <i>block</i> for each key/value pair in <i>map</i>, passing
+ # the key and value to the block as a two-element array.
+ #
+ # map = Multimap["a" => 100, "b" => [200, 300]]
+ # map.each { |key, value| puts "#{key} is #{value}" }
+ #
+ # <em>produces:</em>
+ #
+ # a is 100
+ # b is 200
+ # b is 300
+ def each
+ each_pair do |key, value|
+ yield [key, value]
+ end
+ end
+
+ # call-seq:
+ # map.each_association { |key, container| block } => map
+ #
+ # Calls <i>block</i> once for each key/container in <i>map</i>, passing
+ # the key and container to the block as parameters.
+ #
+ # map = Multimap["a" => 100, "b" => [200, 300]]
+ # map.each_association { |key, container| puts "#{key} is #{container}" }
+ #
+ # <em>produces:</em>
+ #
+ # a is [100]
+ # b is [200, 300]
+ def each_association
+ # each_pair
+ end
+ #--
+ # Ignore alias_method since the definition above serves
+ # as its documentation.
+ #++
+ undef :each_association
+ module_eval "alias_method :each_association, :each_pair"
+
+ # call-seq:
+ # map.each_container { |container| block } => map
+ #
+ # Calls <i>block</i> for each container in <i>map</i>, passing the
+ # container as a parameter.
+ #
+ # map = Multimap["a" => 100, "b" => [200, 300]]
+ # map.each_container { |container| puts container }
+ #
+ # <em>produces:</em>
+ #
+ # [100]
+ # [200, 300]
+ def each_container
+ each_association do |_, container|
+ yield container
+ end
+ end
+
+ # call-seq:
+ # map.each_key { |key| block } => map
+ #
+ # Calls <i>block</i> for each key in <i>hsh</i>, passing the key
+ # as a parameter.
+ #
+ # map = Multimap["a" => 100, "b" => [200, 300]]
+ # map.each_key { |key| puts key }
+ #
+ # <em>produces:</em>
+ #
+ # a
+ # b
+ # b
+ def each_key
+ each_pair do |key, _|
+ yield key
+ end
+ end
+
+ # call-seq:
+ # map.each_pair { |key_value_array| block } => map
+ #
+ # Calls <i>block</i> for each key/value pair in <i>map</i>,
+ # passing the key and value as parameters.
+ #
+ # map = Multimap["a" => 100, "b" => [200, 300]]
+ # map.each_pair { |key, value| puts "#{key} is #{value}" }
+ #
+ # <em>produces:</em>
+ #
+ # a is 100
+ # b is 200
+ # b is 300
+ def each_pair
+ each_association do |key, values|
+ values.each do |value|
+ yield key, value
+ end
+ end
+ end
+
+ # call-seq:
+ # map.each_value { |value| block } => map
+ #
+ # Calls <i>block</i> for each key in <i>map</i>, passing the
+ # value as a parameter.
+ #
+ # map = Multimap["a" => 100, "b" => [200, 300]]
+ # map.each_value { |value| puts value }
+ #
+ # <em>produces:</em>
+ #
+ # 100
+ # 200
+ # 300
+ def each_value
+ each_pair do |_, value|
+ yield value
+ end
+ end
+
+ def freeze #:nodoc:
+ each_container { |container| container.freeze }
+ default.freeze
+ super
+ end
+
+ # call-seq:
+ # map.has_value?(value) => true or false
+ # map.value?(value) => true or false
+ #
+ # Returns <tt>true</tt> if the given value is present for any key
+ # in <i>map</i>.
+ #
+ # map = Multimap["a" => 100, "b" => [200, 300]]
+ # map.has_value?(300) #=> true
+ # map.has_value?(999) #=> false
+ def has_value?(value)
+ values.include?(value)
+ end
+ alias_method :value?, :has_value?
+
+ # call-seq:
+ # map.index(value) => key
+ #
+ # Returns the key for a given value. If not found, returns
+ # <tt>nil</tt>.
+ #
+ # map = Multimap["a" => 100, "b" => [200, 300]]
+ # map.index(100) #=> "a"
+ # map.index(200) #=> "b"
+ # map.index(999) #=> nil
+ def index(value)
+ invert[value]
+ end
+
+ # call-seq:
+ # map.replace(other_map) => map
+ #
+ # Replaces the contents of <i>map</i> with the contents of
+ # <i>other_map</i>.
+ #
+ # map = Multimap["a" => 100, "b" => 200]
+ # map.replace({ "c" => 300, "d" => 400 })
+ # #=> Multimap["c" => 300, "d" => 400]
+ def replace(other)
+ case other
+ when Array
+ super(self.class[self.default, *other])
+ when Hash
+ super(self.class[self.default, other])
+ when self.class
+ super
+ else
+ raise ArgumentError
+ end
+ end
+
+ # call-seq:
+ # map.invert => multimap
+ #
+ # Returns a new multimap created by using <i>map</i>'s values as keys,
+ # and the keys as values.
+ #
+ # map = Multimap["n" => 100, "m" => 100, "d" => [200, 300]]
+ # map.invert #=> Multimap[100 => ["n", "m"], 200 => "d", 300 => "d"]
+ def invert
+ h = self.class.new(default.dup)
+ each_pair { |key, value| h[value] = key }
+ h
+ end
+
+ # call-seq:
+ # map.keys => multiset
+ #
+ # Returns a new +Multiset+ populated with the keys from this hash. See also
+ # <tt>Multimap#values</tt> and <tt>Multimap#containers</tt>.
+ #
+ # map = Multimap["a" => 100, "b" => [200, 300], "c" => 400]
+ # map.keys #=> Multiset.new(["a", "b", "b", "c"])
+ def keys
+ keys = Multiset.new
+ each_key { |key| keys << key }
+ keys
+ end
+
+ # call-seq:
+ # map.length => fixnum
+ # map.size => fixnum
+ #
+ # Returns the number of key-value pairs in the map.
+ #
+ # map = Multimap["a" => 100, "b" => [200, 300], "c" => 400]
+ # map.length #=> 4
+ # map.delete("a") #=> 100
+ # map.length #=> 3
+ def size
+ values.size
+ end
+ alias_method :length, :size
+
+ # call-seq:
+ # map.merge(other_map) => multimap
+ #
+ # Returns a new multimap containing the contents of <i>other_map</i> and
+ # the contents of <i>map</i>.
+ #
+ # map1 = Multimap["a" => 100, "b" => 200]
+ # map2 = Multimap["a" => 254, "c" => 300]
+ # map2.merge(map2) #=> Multimap["a" => 100, "b" => [200, 254], "c" => 300]
+ # map1 #=> Multimap["a" => 100, "b" => 200]
+ def merge(other)
+ dup.update(other)
+ end
+
+ # call-seq:
+ # map.merge!(other_map) => multimap
+ # map.update(other_map) => multimap
+ #
+ # Adds each pair from <i>other_map</i> to <i>map</i>.
+ #
+ # map1 = Multimap["a" => 100, "b" => 200]
+ # map2 = Multimap["b" => 254, "c" => 300]
+ #
+ # map1.merge!(map2)
+ # #=> Multimap["a" => 100, "b" => [200, 254], "c" => 300]
+ def update(other)
+ case other
+ when self.class
+ other.each_pair { |key, value| store(key, value) }
+ when Hash
+ update(self.class[self.default, other])
+ else
+ raise ArgumentError
+ end
+ self
+ end
+ alias_method :merge!, :update
+
+ # call-seq:
+ # map.select { |key, value| block } => multimap
+ #
+ # Returns a new Multimap consisting of the pairs for which the
+ # block returns true.
+ #
+ # map = Multimap["a" => 100, "b" => 200, "c" => 300]
+ # map.select { |k,v| k > "a" } #=> Multimap["b" => 200, "c" => 300]
+ # map.select { |k,v| v < 200 } #=> Multimap["a" => 100]
+ def select
+ inject(self.class.new) { |map, (key, value)|
+ map[key] = value if yield([key, value])
+ map
+ }
+ end
+
+ # call-seq:
+ # map.to_a => array
+ #
+ # Converts <i>map</i> to a nested array of [<i>key,
+ # value</i>] arrays.
+ #
+ # map = Multimap["a" => 100, "b" => [200, 300], "c" => 400]
+ # map.to_a #=> [["a", 100], ["b", 200], ["b", 300], ["c", 400]]
+ def to_a
+ ary = []
+ each_pair do |key, value|
+ ary << [key, value]
+ end
+ ary
+ end
+
+ # call-seq:
+ # map.to_hash => hash
+ #
+ # Converts <i>map</i> to a basic hash.
+ #
+ # map = Multimap["a" => 100, "b" => [200, 300]]
+ # map.to_hash #=> { "a" => [100], "b" => [200, 300] }
+ def to_hash
+ dup
+ end
+
+ # call-seq:
+ # map.containers => array
+ #
+ # Returns a new array populated with the containers from <i>map</i>. See
+ # also <tt>Multimap#keys</tt> and <tt>Multimap#values</tt>.
+ #
+ # map = Multimap["a" => 100, "b" => [200, 300]]
+ # map.containers #=> [[100], [200, 300]]
+ def containers
+ containers = []
+ each_container { |container| containers << container }
+ containers
+ end
+
+ # call-seq:
+ # map.values => array
+ #
+ # Returns a new array populated with the values from <i>map</i>. See
+ # also <tt>Multimap#keys</tt> and <tt>Multimap#containers</tt>.
+ #
+ # map = Multimap["a" => 100, "b" => [200, 300]]
+ # map.values #=> [100, 200, 300]
+ def values
+ values = []
+ each_value { |value| values << value }
+ values
+ end
+
+ protected
+ def update_container(key) #:nodoc:
+ container = hash_aref(key)
+ container = container.dup if container.equal?(default)
+ container = yield(container)
+ hash_aset(key, container)
+ end
+end
153 vendor/gems/dirs/multimap/lib/multiset.rb
View
@@ -0,0 +1,153 @@
+require 'set'
+
+# Multiset implements a collection of unordered values and
+# allows duplicate values.
+class Multiset < Set
+ def initialize(*args, &block) #:nodoc:
+ @hash = Hash.new(0)
+ super
+ end
+
+ # Returns the number of times an element belongs to the multiset.
+ def multiplicity(e)
+ @hash[e]
+ end
+
+ # Returns the total number of elements in a multiset, including
+ # repeated memberships
+ def cardinality
+ @hash.inject(0) { |s, (e, m)| s += m }
+ end
+ alias_method :size, :cardinality
+ alias_method :length, :cardinality
+
+ # Converts the set to an array. The order of elements is uncertain.
+ def to_a
+ inject([]) { |ary, (key, _)| ary << key }
+ end
+
+ # Returns true if the set is a superset of the given set.
+ def superset?(set)
+ set.is_a?(self.class) or raise ArgumentError, "value must be a set"
+ return false if cardinality < set.cardinality
+ set.all? { |o| set.multiplicity(o) <= multiplicity(o) }
+ end
+
+ # Returns true if the set is a proper superset of the given set.
+ def proper_superset?(set)
+ set.is_a?(self.class) or raise ArgumentError, "value must be a set"
+ return false if cardinality <= set.cardinality
+ set.all? { |o| set.multiplicity(o) <= multiplicity(o) }
+ end
+
+ # Returns true if the set is a subset of the given set.
+ def subset?(set)
+ set.is_a?(self.class) or raise ArgumentError, "value must be a set"
+ return false if set.cardinality < cardinality
+ all? { |o| multiplicity(o) <= set.multiplicity(o) }
+ end
+
+ # Returns true if the set is a proper subset of the given set.
+ def proper_subset?(set)
+ set.is_a?(self.class) or raise ArgumentError, "value must be a set"
+ return false if set.cardinality <= cardinality
+ all? { |o| multiplicity(o) <= set.multiplicity(o) }
+ end
+
+ # Calls the given block once for each element in the set, passing
+ # the element as parameter. Returns an enumerator if no block is
+ # given.
+ def each
+ @hash.each_pair do |key, multiplicity|
+ multiplicity.times do
+ yield(key)
+ end
+ end
+ self
+ end
+
+ # Adds the given object to the set and returns self. Use +merge+ to
+ # add many elements at once.
+ def add(o)
+ @hash[o] ||= 0
+ @hash[o] += 1
+ self
+ end
+ alias << add
+
+ undef :add?
+
+ # Deletes all the identical object from the set and returns self.
+ # If +n+ is given, it will remove that amount of identical objects
+ # from the set. Use +subtract+ to delete many different items at
+ # once.
+ def delete(o, n = nil)
+ if n
+ @hash[o] ||= 0
+ @hash[o] -= n if @hash[o] > 0
+ @hash.delete(o) if @hash[o] == 0
+ else
+ @hash.delete(o)
+ end
+ self
+ end
+
+ undef :delete?
+
+ # Deletes every element of the set for which block evaluates to
+ # true, and returns self.
+ def delete_if
+ each { |o| delete(o) if yield(o) }
+ self
+ end
+
+ # Merges the elements of the given enumerable object to the set and
+ # returns self.
+ def merge(enum)
+ enum.each { |o| add(o) }
+ self
+ end
+
+ # Deletes every element that appears in the given enumerable object
+ # and returns self.
+ def subtract(enum)
+ enum.each { |o| delete(o, 1) }
+ self
+ end
+
+ # Returns a new set containing elements common to the set and the
+ # given enumerable object.
+ def &(enum)
+ s = dup
+ n = self.class.new
+ enum.each { |o|
+ if s.include?(o)
+ s.delete(o, 1)
+ n.add(o)
+ end
+ }
+ n
+ end
+ alias intersection &
+
+ # Returns a new set containing elements exclusive between the set
+ # and the given enumerable object. (set ^ enum) is equivalent to
+ # ((set | enum) - (set & enum)).
+ def ^(enum)
+ n = self.class.new(enum)
+ each { |o| n.include?(o) ? n.delete(o, 1) : n.add(o) }
+ n
+ end
+
+ # Returns true if two sets are equal. Two multisets are equal if
+ # they have the same cardinalities and each element has the same
+ # multiplicity in both sets. The equality of each element inside
+ # the multiset is defined according to Object#eql?.
+ def eql?(set)
+ return true if equal?(set)
+ set = self.class.new(set) unless set.is_a?(self.class)
+ return false unless cardinality == set.cardinality
+ superset?(set) && subset?(set)
+ end
+ alias_method :==, :eql?
+end
151 vendor/gems/dirs/multimap/lib/nested_multimap.rb
View
@@ -0,0 +1,151 @@
+require 'multimap'
+
+# NestedMultimap allows values to be assoicated with a nested
+# set of keys.
+class NestedMultimap < Multimap
+ # call-seq:
+ # multimap[*keys] = value => value
+ # multimap.store(*keys, value) => value
+ #
+ # Associates the value given by <i>value</i> with multiple key
+ # given by <i>keys</i>.
+ #
+ # map = NestedMultimap.new
+ # map["a"] = 100
+ # map["a", "b"] = 101
+ # map["a"] = 102
+ # map #=> {"a"=>{"b"=>[100, 101, 102], default => [100, 102]}}
+ def store(*args)
+ keys = args
+ value = args.pop
+
+ raise ArgumentError, 'wrong number of arguments (1 for 2)' unless value
+
+ if keys.length > 1
+ update_container(keys.shift) do |container|
+ container = self.class.new(container) unless container.is_a?(self.class)
+ container[*keys] = value
+ container
+ end
+ elsif keys.length == 1
+ super(keys.first, value)
+ else
+ self << value
+ end
+ end
+ alias_method :[]=, :store
+
+ # call-seq:
+ # multimap << obj => multimap
+ #
+ # Pushes the given object on to the end of all the containers.
+ #
+ # map = NestedMultimap["a" => [100], "b" => [200, 300]]
+ # map << 300
+ # map["a"] #=> [100, 300]
+ # map["c"] #=> [300]
+ def <<(value)
+ hash_each_pair { |_, container| container << value }
+ self.default << value
+ self
+ end
+
+ # call-seq:
+ # multimap[*keys] => value
+ # multimap[key1, key2, key3] => value
+ #
+ # Retrieves the <i>value</i> object corresponding to the
+ # <i>*keys</i> object.
+ def [](*keys)
+ i, l, r, k = 0, keys.length, self, self.class
+ while r.is_a?(k)
+ r = i < l ? r.hash_aref(keys[i]) : r.default
+ i += 1
+ end
+ r
+ end
+
+ # call-seq:
+ # multimap.each_association { |key, container| block } => multimap
+ #
+ # Calls <i>block</i> once for each key/container in <i>map</i>, passing
+ # the key and container to the block as parameters.
+ #
+ # map = NestedMultimap.new
+ # map["a"] = 100
+ # map["a", "b"] = 101
+ # map["a"] = 102
+ # map["c"] = 200
+ # map.each_association { |key, container| puts "#{key} is #{container}" }
+ #
+ # <em>produces:</em>
+ #
+ # ["a", "b"] is [100, 101, 102]
+ # "c" is [200]
+ def each_association
+ super do |key, container|
+ if container.respond_to?(:each_association)
+ container.each_association do |nested_key, value|
+ yield [key, nested_key].flatten, value
+ end
+ else
+ yield key, container
+ end
+ end
+ end
+
+ # call-seq:
+ # multimap.each_container_with_default { |container| block } => map
+ #
+ # Calls <i>block</i> for every container in <i>map</i> including
+ # the default, passing the container as a parameter.
+ #
+ # map = NestedMultimap.new
+ # map["a"] = 100
+ # map["a", "b"] = 101
+ # map["a"] = 102
+ # map.each_container_with_default { |container| puts container }
+ #
+ # <em>produces:</em>
+ #
+ # [100, 101, 102]
+ # [100, 102]
+ # []
+ def each_container_with_default
+ each_container = Proc.new do |container|
+ if container.respond_to?(:each_container_with_default)
+ container.each_container_with_default do |value|
+ yield value
+ end
+ else
+ yield container
+ end
+ end
+
+ hash_each_pair { |_, container| each_container.call(container) }
+ each_container.call(default)
+
+ self
+ end
+
+ # call-seq:
+ # multimap.containers_with_default => array
+ #
+ # Returns a new array populated with all the containers from
+ # <i>map</i> including the default.
+ #
+ # map = NestedMultimap.new
+ # map["a"] = 100
+ # map["a", "b"] = 101
+ # map["a"] = 102
+ # map.containers_with_default #=> [[100, 101, 102], [100, 102], []]
+ def containers_with_default
+ containers = []
+ each_container_with_default { |container| containers << container }
+ containers
+ end
+
+ def inspect #:nodoc:
+ super.gsub(/\}$/, ", default => #{default.inspect}}")
+ end
+end
20 vendor/gems/dirs/multimap/multimap.gemspec
View
@@ -0,0 +1,20 @@
+Gem::Specification.new do |s|
+ s.name = 'multimap'
+ s.version = '1.0.1'
+ s.date = '2009-11-07'
+ s.summary = 'Ruby implementation of multimap'
+ s.description = <<-EOS
+ Multimap includes a Ruby multimap implementation
+ EOS
+ s.email = 'josh@joshpeek.com'
+ s.homepage = 'http://github.com/josh/multimap'
+ s.rubyforge_project = 'multimap'
+ s.has_rdoc = true
+ s.authors = ["Joshua Peek"]
+ s.files = [
+ "lib/multimap.rb",
+ "lib/multiset.rb",
+ "lib/nested_multimap.rb"
+ ]
+ s.extra_rdoc_files = %w[README.rdoc MIT-LICENSE]
+end
50 vendor/gems/dirs/multimap/spec/enumerable_examples.rb
View
@@ -0,0 +1,50 @@
+shared_examples_for Enumerable, Multimap, "with inital values {'a' => [100], 'b' => [200, 300]}" do
+ it "should check all key/value pairs for condition" do
+ @map.all? { |key, value| key =~ /\w/ }.should be_true
+ @map.all? { |key, value| key =~ /\d/ }.should be_false
+ @map.all? { |key, value| value > 0 }.should be_true
+ @map.all? { |key, value| value > 200 }.should be_false
+ end
+
+ it "should check any key/value pairs for condition" do
+ @map.any? { |key, value| key == "a" }.should be_true
+ @map.any? { |key, value| key == "z" }.should be_false
+ @map.any? { |key, value| value == 100 }.should be_true
+ @map.any? { |key, value| value > 1000 }.should be_false
+ end
+
+ it "should collect key/value pairs" do
+ @map.collect { |key, value| [key, value] }.should eql([["a", 100], ["b", 200], ["b", 300]])
+ @map.map { |key, value| [key, value] }.should eql([["a", 100], ["b", 200], ["b", 300]])
+ end
+
+ it "should detect key/value pair" do
+ @map.detect { |key, value| value > 200 }.should eql(["b", 300])
+ @map.find { |key, value| value > 200 }.should eql(["b", 300])
+ end
+
+ it "should return entries" do
+ @map.entries.should eql([["a", 100], ["b", 200], ["b", 300]])
+ @map.to_a.should eql([["a", 100], ["b", 200], ["b", 300]])
+ end
+
+ it "should find all key/value pairs" do
+ @map.find_all { |key, value| value >= 200 }.should eql([["b", 200], ["b", 300]])
+ @map.select { |key, value| value >= 200 }.should eql(Multimap["b", [200, 300]])
+ end
+
+ it "should combine key/value pairs with inject" do
+ @map.inject(0) { |sum, (key, value)| sum + value }.should eql(600)
+
+ @map.inject(0) { |memo, (key, value)|
+ memo > value ? memo : value
+ }.should eql(300)
+ end
+
+ it "should check for key membership" do
+ @map.member?("a").should be_true
+ @map.include?("a").should be_true
+ @map.member?("z").should be_false
+ @map.include?("z").should be_false
+ end
+end
230 vendor/gems/dirs/multimap/spec/hash_examples.rb
View
@@ -0,0 +1,230 @@
+shared_examples_for Hash, Multimap, "with inital values {'a' => [100], 'b' => [200, 300]}" do
+ before do
+ @container ||= Array
+ end
+
+ it "should be equal to another Multimap if they contain the same keys and values" do
+ map2 = Multimap.new(@container.new)
+ map2["a"] = 100
+ map2["b"] = 200
+ map2["b"] = 300
+ @map.should eql(map2)
+ end
+
+ it "should not be equal to another Multimap if they contain different values" do
+ @map.should_not == Multimap["a" => [100], "b" => [200]]
+ end
+
+ it "should retrieve container of values for key" do
+ @map["a"].should eql(@container.new([100]))
+ @map["b"].should eql(@container.new([200, 300]))
+ @map["z"].should eql(@container.new)
+ end
+
+ it "should append values to container at key" do
+ @map["a"] = 400
+ @map.store("b", 500)
+ @map["a"].should eql(@container.new([100, 400]))
+ @map["b"].should eql(@container.new([200, 300, 500]))
+ end
+
+ it "should clear all key/values" do
+ @map.clear
+ @map.should be_empty
+ end
+
+ it "should be the class of the container" do
+ @map.default.class.should eql(@container)
+ end
+
+ it "should delete all values at key" do
+ @map.delete("a")
+ @map["a"].should eql(@container.new)
+ end
+
+ it "should delete single value at key" do
+ @map.delete("b", 200)
+ @map["b"].should eql(@container.new([300]))
+ end
+
+ it "should delete if condition is matched" do
+ @map.delete_if { |key, value| key >= "b" }.should eql(@map)
+ @map["a"].should eql(@container.new([100]))
+ @map["b"].should eql(@container.new)
+
+ @map.delete_if { |key, value| key > "z" }.should eql(@map)
+ end
+
+ it "should duplicate the containers" do
+ map2 = @map.dup
+ map2.should_not equal(@map)
+ map2.should eql(@map)
+ map2["a"].should_not equal(@map["a"])
+ map2["b"].should_not equal(@map["b"])
+ end
+
+ it "should freeze containers" do
+ @map.freeze
+ @map.should be_frozen
+ @map["a"].should be_frozen
+ @map["b"].should be_frozen
+ end
+
+ it "should iterate over each key/value pair and yield an array" do
+ a = []
+ @map.each { |pair| a << pair }
+ a.should eql([["a", 100], ["b", 200], ["b", 300]])
+ end
+
+ it "should iterate over each container" do
+ a = []
+ @map.each_container { |container| a << container }
+ a.should eql([@container.new([100]), @container.new([200, 300])])
+ end
+
+ it "should iterate over each key/container" do
+ a = []
+ @map.each_association { |key, container| a << [key, container] }
+ a.should eql([["a", @container.new([100])], ["b", @container.new([200, 300])]])
+ end
+
+ it "should iterate over each key" do
+ a = []
+ @map.each_key { |key| a << key }
+ a.should eql(["a", "b", "b"])
+ end
+
+ it "should iterate over each key/value pair and yield the pair" do
+ h = {}
+ @map.each_pair { |key, value| (h[key] ||= []) << value }
+ h.should eql({ "a" => [100], "b" => [200, 300] })
+ end
+
+ it "should iterate over each value" do
+ a = []
+ @map.each_value { |value| a << value }
+ a.should eql([100, 200, 300])
+ end
+
+ it "should be empty if there are no key/value pairs" do
+ @map.clear
+ @map.should be_empty
+ end
+
+ it "should not be empty if there are any key/value pairs" do
+ @map.should_not be_empty
+ end
+
+ it "should fetch container of values for key" do
+ @map.fetch("a").should eql(@container.new([100]))
+ @map.fetch("b").should eql(@container.new([200, 300]))
+ lambda { @map.fetch("z") }.should raise_error(IndexError)
+ end
+
+ it "should check if key is present" do
+ @map.has_key?("a").should be_true
+ @map.key?("a").should be_true
+ @map.has_key?("z").should be_false
+ @map.key?("z").should be_false
+ end
+
+ it "should check containers when looking up by value" do
+ @map.has_value?(100).should be_true
+ @map.value?(100).should be_true
+ @map.has_value?(999).should be_false
+ @map.value?(999).should be_false
+ end
+
+ it "it should return the index for value" do
+ if @map.respond_to?(:index)
+ @map.index(200).should eql(@container.new(["b"]))
+ @map.index(999).should eql(@container.new)
+ end
+ end
+
+ it "should replace the contents of hash" do
+ @map.replace({ "c" => @container.new([300]), "d" => @container.new([400]) })
+ @map["a"].should eql(@container.new)
+ @map["c"].should eql(@container.new([300]))
+ end
+
+ it "should return an inverted Multimap" do
+ if @map.respond_to?(:invert)
+ map2 = Multimap.new(@container.new)
+ map2[100] = "a"
+ map2[200] = "b"
+ map2[300] = "b"
+ @map.invert.should eql(map2)
+ end
+ end
+
+ it "should return array of keys" do
+ @map.keys.should eql(["a", "b", "b"])
+ end
+
+ it "should return the number of key/value pairs" do
+ @map.length.should eql(3)
+ @map.size.should eql(3)
+ end
+
+ it "should duplicate map and with merged values" do
+ map = @map.merge("b" => 254, "c" => @container.new([300]))
+ map["a"].should eql(@container.new([100]))
+ map["b"].should eql(@container.new([200, 300, 254]))
+ map["c"].should eql(@container.new([300]))
+
+ @map["a"].should eql(@container.new([100]))
+ @map["b"].should eql(@container.new([200, 300]))
+ @map["c"].should eql(@container.new)
+ end
+
+ it "should update map" do
+ @map.update("b" => 254, "c" => @container.new([300]))
+ @map["a"].should eql(@container.new([100]))
+ @map["b"].should eql(@container.new([200, 300, 254]))
+ @map["c"].should eql(@container.new([300]))
+
+ klass = @map.class
+ @map.update(klass[@container.new, {"a" => @container.new([400, 500]), "c" => 600}])
+ @map["a"].should eql(@container.new([100, 400, 500]))
+ @map["b"].should eql(@container.new([200, 300, 254]))
+ @map["c"].should eql(@container.new([300, 600]))
+ end
+
+ it "should reject key/value pairs on copy of the map" do
+ map = @map.reject { |key, value| key >= "b" }
+ map["b"].should eql(@container.new)
+ @map["b"].should eql(@container.new([200, 300]))
+ end
+
+ it "should reject key/value pairs" do
+ @map.reject! { |key, value| key >= "b" }.should eql(@map)
+ @map["a"].should eql(@container.new([100]))
+ @map["b"].should eql(@container.new)
+
+ @map.reject! { |key, value| key >= "z" }.should eql(nil)
+ end
+
+ it "should select key/value pairs" do
+ @map.select { |k, v| k > "a" }.should eql(Multimap["b", [200, 300]])
+ @map.select { |k, v| v < 200 }.should eql(Multimap["a", 100])
+ end
+
+ it "should convert to hash" do
+ @map.to_hash["a"].should eql(@container.new([100]))
+ @map.to_hash["b"].should eql(@container.new([200, 300]))
+ @map.to_hash.should_not equal(@map)
+ end
+
+ it "should return all containers" do
+ @map.containers.should eql([@container.new([100]), @container.new([200, 300])])
+ end
+
+ it "should return all values" do
+ @map.values.should eql([100, 200, 300])
+ end
+
+ it "should return return values at keys" do
+ @map.values_at("a", "b").should eql([@container.new([100]), @container.new([200, 300])])
+ end
+end
83 vendor/gems/dirs/multimap/spec/multimap_spec.rb
View
@@ -0,0 +1,83 @@
+require 'multimap'
+
+require 'spec/enumerable_examples'
+require 'spec/hash_examples'
+
+describe Multimap, "with inital values {'a' => [100], 'b' => [200, 300]}" do
+ it_should_behave_like "Enumerable Multimap with inital values {'a' => [100], 'b' => [200, 300]}"
+ it_should_behave_like "Hash Multimap with inital values {'a' => [100], 'b' => [200, 300]}"
+
+ before do
+ @map = Multimap["a" => 100, "b" => [200, 300]]
+ end
+end
+
+describe Multimap, "with inital values {'a' => [100], 'b' => [200, 300]}" do
+ it_should_behave_like "Enumerable Multimap with inital values {'a' => [100], 'b' => [200, 300]}"
+ it_should_behave_like "Hash Multimap with inital values {'a' => [100], 'b' => [200, 300]}"
+
+ before do
+ @map = Multimap["a", 100, "b", [200, 300]]
+ end
+end
+
+require 'set'
+
+describe Multimap, "with", Set do
+ it_should_behave_like "Enumerable Multimap with inital values {'a' => [100], 'b' => [200, 300]}"
+ it_should_behave_like "Hash Multimap with inital values {'a' => [100], 'b' => [200, 300]}"
+
+ before do
+ @container = Set
+ @map = Multimap.new(@container.new)
+ @map["a"] = 100
+ @map["b"] = 200
+ @map["b"] = 300
+ end
+end
+
+
+class MiniArray
+ attr_accessor :data
+
+ def initialize(data = [])
+ @data = data
+ end
+
+ def initialize_copy(orig)
+ @data = orig.data.dup
+ end
+
+ def <<(value)
+ @data << value
+ end
+
+ def each(&block)
+ @data.each(&block)
+ end
+
+ def delete(value)
+ @data.delete(value)
+ end
+
+ def ==(other)
+ other.is_a?(self.class) && @data == other.data
+ end
+
+ def eql?(other)
+ other.is_a?(self.class) && @data.eql?(other.data)
+ end
+end
+
+describe Multimap, "with", MiniArray do
+ it_should_behave_like "Enumerable Multimap with inital values {'a' => [100], 'b' => [200, 300]}"
+ it_should_behave_like "Hash Multimap with inital values {'a' => [100], 'b' => [200, 300]}"
+
+ before do
+ @container = MiniArray
+ @map = Multimap.new(@container.new)
+ @map["a"] = 100
+ @map["b"] = 200
+ @map["b"] = 300
+ end
+end
172 vendor/gems/dirs/multimap/spec/multiset_spec.rb
View
@@ -0,0 +1,172 @@
+require 'multiset'
+
+require 'spec/set_examples'
+
+describe Multiset do
+ it_should_behave_like "Set"
+
+ it "should return the multiplicity of the element" do
+ set = Multiset.new([:a, :a, :b, :b, :b, :c])
+ set.multiplicity(:a).should eql(2)
+ set.multiplicity(:b).should eql(3)
+ set.multiplicity(:c).should eql(1)
+ end
+
+ it "should return the cardinality of the set" do
+ set = Multiset.new([:a, :a, :b, :b, :b, :c])
+ set.cardinality.should eql(6)
+ end
+
+ it "should be eql" do
+ s1 = Multiset.new([:a, :b])
+ s2 = Multiset.new([:b, :a])
+ s1.should eql(s2)
+
+ s1 = Multiset.new([:a, :a])
+ s2 = Multiset.new([:a])
+ s1.should_not eql(s2)
+ end
+
+ it "should replace the contents of the set" do
+ set = Multiset[:a, :b, :b, :c]
+ ret = set.replace(Multiset[:a, :a, :b, :b, :b, :c])
+
+ set.should equal(ret)
+ set.should eql(Multiset[:a, :a, :b, :b, :b, :c])
+
+ set = Multiset[:a, :b, :b, :c]
+ ret = set.replace([:a, :a, :b, :b, :b, :c])
+
+ set.should equal(ret)
+ set.should eql(Multiset[:a, :a, :b, :b, :b, :c])
+ end
+
+ it "should return true if the set is a superset of the given set" do
+ set = Multiset[1, 2, 2, 3]
+
+ set.superset?(Multiset[]).should be_true
+ set.superset?(Multiset[1, 2]).should be_true
+ set.superset?(Multiset[1, 2, 3]).should be_true
+ set.superset?(Multiset[1, 2, 2, 3]).should be_true
+ set.superset?(Multiset[1, 2, 2, 2]).should be_false
+ set.superset?(Multiset[1, 2, 3, 4]).should be_false
+ set.superset?(Multiset[1, 4]).should be_false
+ end
+
+ it "should return true if the set is a proper superset of the given set" do
+ set = Multiset[1, 2, 2, 3, 3]
+
+ set.proper_superset?(Multiset[]).should be_true
+ set.proper_superset?(Multiset[1, 2]).should be_true
+ set.proper_superset?(Multiset[1, 2, 3]).should be_true
+ set.proper_superset?(Multiset[1, 2, 2, 3, 3]).should be_false
+ set.proper_superset?(Multiset[1, 2, 2, 2]).should be_false
+ set.proper_superset?(Multiset[1, 2, 3, 4]).should be_false
+ set.proper_superset?(Multiset[1, 4]).should be_false
+ end
+
+ it "should return true if the set is a subset of the given set" do
+ set = Multiset[1, 2, 2, 3]
+
+ set.subset?(Multiset[1, 2, 2, 3, 4]).should be_true
+ set.subset?(Multiset[1, 2, 2, 3, 3]).should be_true
+ set.subset?(Multiset[1, 2, 2, 3]).should be_true
+ set.subset?(Multiset[1, 2, 3]).should be_false
+ set.subset?(Multiset[1, 2, 2]).should be_false
+ set.subset?(Multiset[1, 2, 3]).should be_false
+ set.subset?(Multiset[]).should be_false
+ end
+
+ it "should return true if the set is a proper subset of the given set" do
+ set = Multiset[1, 2, 2, 3, 3]
+
+ set.proper_subset?(Multiset[1, 2, 2, 3, 3, 4]).should be_true
+ set.proper_subset?(Multiset[1, 2, 2, 3, 3]).should be_false
+ set.proper_subset?(Multiset[1, 2, 3]).should be_false
+ set.proper_subset?(Multiset[1, 2, 2]).should be_false
+ set.proper_subset?(Multiset[1, 2, 3]).should be_false
+ set.proper_subset?(Multiset[]).should be_false
+ end
+
+ it "should delete the objects from the set and return self" do
+ set = Multiset[1, 2, 2, 3]
+
+ ret = set.delete(4)
+ set.should equal(ret)
+ set.should eql(Multiset[1, 2, 2, 3])
+
+ ret = set.delete(2)
+ set.should eql(ret)
+ set.should eql(Multiset[1, 3])
+ end
+
+ it "should delete the number objects from the set and return self" do
+ set = Multiset[1, 2, 2, 3]
+
+ ret = set.delete(2, 1)
+ set.should eql(ret)
+ set.should eql(Multiset[1, 2, 3])
+ end
+
+ it "should merge the elements of the given enumerable object to the set and return self" do
+ set = Multiset[1, 2, 3]
+ ret = set.merge([2, 4, 5])
+ set.should equal(ret)
+ set.should eql(Multiset[1, 2, 2, 3, 4, 5])
+
+ set = Multiset[1, 2, 3]
+ ret = set.merge(Multiset[2, 4, 5])
+ set.should equal(ret)
+ set.should eql(Multiset[1, 2, 2, 3, 4, 5])
+ end
+
+ it "should delete every element that appears in the given enumerable object and return self" do
+ set = Multiset[1, 2, 2, 3]
+ ret = set.subtract([2, 4, 6])
+ set.should equal(ret)
+ set.should eql(Multiset[1, 2, 3])
+ end
+
+ it "should return a new set containing elements common to the set and the given enumerable object" do
+ set = Multiset[1, 2, 2, 3, 4]
+
+ ret = set & [2, 2, 4, 5]
+ set.should_not equal(ret)
+ ret.should eql(Multiset[2, 2, 4])
+
+ set = Multiset[1, 2, 3]
+
+ ret = set & [1, 2, 2, 2]
+ set.should_not equal(ret)
+ ret.should eql(Multiset[1, 2])
+ end
+
+ it "should return a new set containing elements exclusive between the set and the given enumerable object" do
+ set = Multiset[1, 2, 3, 4, 5]
+ ret = set ^ [2, 4, 5, 5]
+ set.should_not equal(ret)
+ ret.should eql(Multiset[1, 3, 5])
+
+ set = Multiset[1, 2, 4, 5, 5]
+ ret = set ^ [2, 3, 4, 5]
+ set.should_not equal(ret)
+ ret.should eql(Multiset[1, 3, 5])
+ end
+end
+
+describe Multiset, "with inital values" do
+ it_should_behave_like "Set with inital values [1, 2]"
+
+ before do
+ @set = Multiset.new([1, 2])
+ end
+
+ it "should return the multiplicity of the element" do
+ @set.multiplicity(1).should eql(1)
+ @set.multiplicity(2).should eql(1)
+ end
+
+ it "should return the cardinality of the set" do
+ @set.cardinality.should eql(2)
+ end
+end
185 vendor/gems/dirs/multimap/spec/nested_multimap_spec.rb
View
@@ -0,0 +1,185 @@
+require 'nested_multimap'
+
+require 'spec/enumerable_examples'
+require 'spec/hash_examples'
+
+describe NestedMultimap, "with inital values" do
+ it_should_behave_like "Enumerable Multimap with inital values {'a' => [100], 'b' => [200, 300]}"
+ it_should_behave_like "Hash Multimap with inital values {'a' => [100], 'b' => [200, 300]}"
+
+ before do
+ @map = NestedMultimap["a" => [100], "b" => [200, 300]]
+ end
+
+ it "should set value at nested key" do
+ @map["foo", "bar", "baz"] = 100
+ @map["foo", "bar", "baz"].should eql([100])
+ end
+
+ it "should allow nil keys to be set" do
+ @map["b", nil] = 400
+ @map["b", "c"] = 500
+
+ @map["a"].should eql([100])
+ @map["b"].should eql([200, 300])
+ @map["b", nil].should eql([200, 300, 400])
+ @map["b", "c"].should eql([200, 300, 500])
+ end
+
+ it "should treat missing keys as append to all" do
+ @map[] = 400
+ @map["a"].should eql([100, 400])
+ @map["b"].should eql([200, 300, 400])
+ @map["c"].should eql([400])
+ @map[nil].should eql([400])
+ end
+
+ it "should append the value to default containers" do
+ @map << 400
+ @map["a"].should eql([100, 400])
+ @map["b"].should eql([200, 300, 400])
+ @map["c"].should eql([400])
+ @map[nil].should eql([400])
+ end
+
+ it "should append the value to all containers" do
+ @map << 500
+ @map["a"].should eql([100, 500])
+ @map["b"].should eql([200, 300, 500])
+ @map[nil].should eql([500])
+ end
+
+ it "default values should be copied to new containers" do
+ @map << 300
+ @map["x"] = 100
+ @map["x"].should eql([300, 100])
+ end
+
+ it "should list all containers" do
+ @map.containers.should eql([[100], [200, 300]])
+ end
+
+ it "should list all values" do
+ @map.values.should eql([100, 200, 300])
+ end
+end
+
+describe NestedMultimap, "with nested values" do
+ before do
+ @map = NestedMultimap.new
+ @map["a"] = 100
+ @map["b"] = 200
+ @map["b", "c"] = 300
+ @map["c", "e"] = 400
+ @map["c"] = 500
+ end
+
+ it "should retrieve container of values for key" do
+ @map["a"].should eql([100])
+ @map["b"].should eql([200])
+ @map["c"].should eql([500])
+ @map["a", "b"].should eql([100])
+ @map["b", "c"].should eql([200, 300])
+ @map["c", "e"].should eql([400, 500])
+ end
+
+ it "should append the value to default containers" do
+ @map << 600
+ @map["a"].should eql([100, 600])
+ @map["b"].should eql([200, 600])
+ @map["c"].should eql([500, 600])
+ @map["a", "b"].should eql([100, 600])
+ @map["b", "c"].should eql([200, 300, 600])
+ @map["c", "e"].should eql([400, 500, 600])
+ @map[nil].should eql([600])
+ end
+
+ it "should iterate over each key/value pair and yield an array" do
+ a = []
+ @map.each { |pair| a << pair }
+ a.should eql([
+ ["a", 100],
+ [["b", "c"], 200],
+ [["b", "c"], 300],
+ [["c", "e"], 400],
+ [["c", "e"], 500]
+ ])
+ end
+
+ it "should iterate over each key/container" do
+ a = []
+ @map.each_association { |key, container| a << [key, container] }
+ a.should eql([
+ ["a", [100]],
+ [["b", "c"], [200, 300]],
+ [["c", "e"], [400, 500]]
+ ])
+ end
+
+ it "should iterate over each container plus the default" do
+ a = []
+ @map.each_container_with_default { |container| a << container }
+ a.should eql([
+ [100],
+ [200, 300],
+ [200],
+ [400, 500],
+ [500],
+ []
+ ])
+ end
+
+ it "should iterate over each key" do
+ a = []
+ @map.each_key { |key| a << key }
+ a.should eql(["a", ["b", "c"], ["b", "c"], ["c", "e"], ["c", "e"]])
+ end
+
+ it "should iterate over each key/value pair and yield the pair" do
+ h = {}
+ @map.each_pair { |key, value| (h[key] ||= []) << value }
+ h.should eql({
+ "a" => [100],
+ ["c", "e"] => [400, 500],
+ ["b", "c"] => [200, 300]
+ })
+ end
+
+ it "should iterate over each value" do
+ a = []
+ @map.each_value { |value| a << value }
+ a.should eql([100, 200, 300, 400, 500])
+ end
+
+ it "should list all containers" do
+ @map.containers.should eql([[100], [200, 300], [400, 500]])
+ end
+
+ it "should list all containers plus the default" do
+ @map.containers_with_default.should eql([[100], [200, 300], [200], [400, 500], [500], []])
+ end
+
+ it "should return array of keys" do
+ @map.keys.should eql(["a", ["b", "c"], ["b", "c"], ["c", "e"], ["c", "e"]])
+ end
+
+ it "should list all values" do
+ @map.values.should eql([100, 200, 300, 400, 500])
+ end
+end
+
+
+require 'set'
+
+describe NestedMultimap, "with", Set do
+ it_should_behave_like "Enumerable Multimap with inital values {'a' => [100], 'b' => [200, 300]}"
+ it_should_behave_like "Hash Multimap with inital values {'a' => [100], 'b' => [200, 300]}"
+
+ before do
+ @container = Set
+ @map = NestedMultimap.new(@container.new)
+ @map["a"] = 100
+ @map["b"] = 200
+ @map["b"] = 300
+ end
+end
301 vendor/gems/dirs/multimap/spec/set_examples.rb
View
@@ -0,0 +1,301 @@
+shared_examples_for Set do
+ it "should create a new set containing the given objects" do
+ Multiset[]
+ Multiset[nil]
+ Multiset[1, 2, 3]
+
+ Multiset[].size.should eql(0)
+ Multiset[nil].size.should eql(1)
+ Multiset[[]].size.should eql(1)
+ Multiset[[nil]].size.should eql(1)
+
+ set = Multiset[2, 4, 6, 4]
+ Multiset.new([2, 4, 6]).should_not eql(set)
+
+ set = Multiset[2, 4, 6, 4]
+ Multiset.new([2, 4, 6, 4]).should eql(set)
+ end
+
+ it "should create a new set containing the elements of the given enumerable object" do
+ Multiset.new()
+ Multiset.new(nil)
+ Multiset.new([])
+ Multiset.new([1, 2])
+ Multiset.new('a'..'c')
+
+ lambda { Multiset.new(false) }.should raise_error
+ lambda { Multiset.new(1) }.should raise_error
+ lambda { Multiset.new(1, 2) }.should raise_error
+
+ Multiset.new().size.should eql(0)
+ Multiset.new(nil).size.should eql(0)
+ Multiset.new([]).size.should eql(0)
+ Multiset.new([nil]).size.should eql(1)
+
+ ary = [2, 4, 6, 4]
+ set = Multiset.new(ary)
+ ary.clear
+ set.should_not be_empty
+ set.size.should eql(4)
+
+ ary = [1, 2, 3]
+
+ s = Multiset.new(ary) { |o| o * 2 }
+ [2, 4, 6].should eql(s.sort)
+ end
+
+ it "should duplicate set" do
+ set1 = Multiset[1, 2]
+ set2 = set1.dup
+
+ set1.should_not equal(set2)
+
+ set1.should eql(set2)
+
+ set1.add(3)
+
+ set1.should_not eql(set2)
+ end
+
+ it "should return the number of elements" do
+ Multiset[].size.should eql(0)
+ Multiset[1, 2].size.should eql(2)
+ Multiset[1, 2, 1].size.should eql(3)
+ end
+
+ it "should return true if the set contains no elements" do
+ Multiset[].should be_empty
+ Multiset[1, 2].should_not be_empty
+ end
+
+ it "should remove all elements and returns self" do
+ set = Multiset[1, 2]
+ ret = set.clear
+
+ set.should equal(ret)
+ set.should be_empty
+ end
+
+ it "should replaces the contents of the set with the contents of the given enumerable object and returns self" do
+ set = Multiset[1, 2]
+ ret = set.replace('a'..'c')
+
+ set.should equal(ret)
+ set.should eql(Multiset['a', 'b', 'c'])
+ end
+
+ it "should convert the set to an array" do
+ set = Multiset[1, 2, 3, 2]
+ ary = set.to_a
+
+ ary.sort.should eql([1, 2, 2, 3])
+ end
+
+ it "should return true if the set contains the given object" do
+ set = Multiset[1, 2, 3]
+
+ set.include?(1).should be_true
+ set.include?(2).should be_true
+ set.include?(3).should be_true
+ set.include?(0).should be_false
+ set.include?(nil).should be_false
+
+ set = Multiset["1", nil, "2", nil, "0", "1", false]
+ set.include?(nil).should be_true
+ set.include?(false).should be_true
+ set.include?("1").should be_true
+ set.include?(0).should be_false
+ set.include?(true).should be_false
+ end
+
+ it "should return true if the set is a superset of the given set" do
+ set = Multiset[1, 2, 3]
+
+ lambda { set.superset?() }.should raise_error
+ lambda { set.superset?(2) }.should raise_error
+ lambda { set.superset?([2]) }.should raise_error
+
+ set.superset?(Multiset[]).should be_true
+ set.superset?(Multiset[1, 2]).should be_true
+ set.superset?(Multiset[1, 2, 3]).should be_true
+ set.superset?(Multiset[1, 2, 3, 4]).should be_false
+ set.superset?(Multiset[1, 4]).should be_false
+
+ Multiset[].superset?(Multiset[]).should be_true
+ end
+
+ it "should return true if the set is a proper superset of the given set" do
+ set = Multiset[1, 2, 3]
+
+ lambda { set.proper_superset?() }.should raise_error
+ lambda { set.proper_superset?(2) }.should raise_error
+ lambda { set.proper_superset?([2]) }.should raise_error
+
+ set.proper_superset?(Multiset[]).should be_true
+ set.proper_superset?(Multiset[1, 2]).should be_true
+ set.proper_superset?(Multiset[1, 2, 3]).should be_false
+ set.proper_superset?(Multiset[1, 2, 3, 4]).should be_false
+ set.proper_superset?(Multiset[1, 4]).should be_false
+
+ Multiset[].proper_superset?(Multiset[]).should be_false
+ end
+
+ it "should return true if the set is a subset of the given set" do
+ set = Multiset[1, 2, 3]
+
+ lambda { set.subset?() }.should raise_error
+ lambda { set.subset?(2) }.should raise_error
+ lambda { set.subset?([2]) }.should raise_error
+
+ set.subset?(Multiset[1, 2, 3, 4]).should be_true
+ set.subset?(Multiset[1, 2, 3]).should be_true
+ set.subset?(Multiset[1, 2]).should be_false
+ set.subset?(Multiset[]).should be_false
+
+ Multiset[].subset?(Multiset[1]).should be_true
+ Multiset[].subset?(Multiset[]).should be_true
+ end
+
+ it "should return true if the set is a proper subset of the given set" do
+ set = Multiset[1, 2, 3]
+
+ lambda { set.proper_subset?() }.should raise_error
+ lambda { set.proper_subset?(2) }.should raise_error
+ lambda { set.proper_subset?([2]) }.should raise_error
+
+ set.proper_subset?(Multiset[1, 2, 3, 4]).should be_true
+ set.proper_subset?(Multiset[1, 2, 3]).should be_false
+ set.proper_subset?(Multiset[1, 2]).should be_false
+ set.proper_subset?(Multiset[]).should be_false
+
+ Multiset[].proper_subset?(Multiset[]).should be_false
+ end
+
+ it "should add the given object to the set and return self" do
+ set = Multiset[1, 2, 3]
+
+ ret = set.add(2)
+ set.should equal(ret)
+ set.should eql(Multiset[1, 2, 2, 3])
+
+ ret = set.add(4)
+ set.should equal(ret)
+ set.should eql(Multiset[1, 2, 2, 3, 4])
+ end
+
+ it "should delete the given object from the set and return self" do
+ set = Multiset[1, 2, 3]
+
+ ret = set.delete(4)
+ set.should equal(ret)
+ set.should eql(Multiset[1, 2, 3])
+
+ ret = set.delete(2)
+ set.should eql(ret)
+ set.should eql(Multiset[1, 3])
+ end
+
+ it "should delete every element of the set for which block evaluates to true, and return self" do
+ set = Multiset.new(1..10)
+ ret = set.delete_if { |i| i > 10 }
+ set.should equal(ret)
+ set.should eql(Multiset.new(1..10))
+
+ set = Multiset.new(1..10)
+ ret = set.delete_if { |i| i % 3 == 0 }
+ set.should equal(ret)
+ set.should eql(Multiset[1, 2, 4, 5, 7, 8, 10])
+ end
+
+ it "should deletes every element of the set for which block evaluates to true but return nil if no changes were made" do
+ set = Multiset.new(1..10)
+
+ ret = set.reject! { |i| i > 10 }
+ ret.should be_nil
+ set.should eql(Multiset.new(1..10))
+
+ ret = set.reject! { |i| i % 3 == 0 }
+ set.should equal(ret)
+ set.should eql(Multiset[1, 2, 4, 5, 7, 8, 10])
+ end
+
+ it "should merge the elements of the given enumerable object to the set and return self" do
+ set = Multiset[1, 2, 3]
+
+ ret = set.merge([2, 4, 6])
+ set.should equal(ret)
+ set.should eql(Multiset[1, 2, 2, 3, 4, 6])
+ end
+
+ it "should delete every element that appears in the given enumerable object and return self" do
+ set = Multiset[1, 2, 3]
+
+ ret = set.subtract([2, 4, 6])
+ set.should equal(ret)
+ set.should eql(Multiset[1, 3])
+ end
+
+ it "should return a new set built by merging the set and the elements of the given enumerable object" do
+ set = Multiset[1, 2, 3]
+
+ ret = set + [2, 4, 6]
+ set.should_not equal(ret)
+ ret.should eql(Multiset[1, 2, 2, 3, 4, 6])
+ end
+
+ it "should return a new set built by duplicating the set, removing every element that appears in the given enumerable object" do
+ set = Multiset[1, 2, 3]
+
+ ret = set - [2, 4, 6]
+ set.should_not equal(ret)
+ ret.should eql(Multiset[1, 3])
+ end
+
+ it "should return a new set containing elements common to the set and the given enumerable object" do
+ set = Multiset[1, 2, 3, 4]
+
+ ret = set & [2, 4, 6]
+ set.should_not equal(ret)
+ ret.should eql(Multiset[2, 4])
+ end
+
+ it "should return a new set containing elements exclusive between the set and the given enumerable object" do
+ set = Multiset[1, 2, 3, 4]
+ ret = set ^ [2, 4, 5]
+ set.should_not equal(ret)
+ ret.should eql(Multiset[1, 3, 5])
+ end
+end
+
+shared_examples_for Set, "with inital values [1, 2]" do
+ it "should add element to set" do
+ @set.add("foo")
+
+ @set.include?(1).should be_true
+ @set.include?(2).should be_true
+ @set.include?("foo").should be_true
+ end
+
+ it "should merge elements into the set" do
+ @set.merge([2, 6])
+
+ @set.include?(1).should be_true
+ @set.include?(2).should be_true
+ @set.include?(2).should be_true
+ @set.include?(6).should be_true
+ end
+
+ it "should iterate over all the values in the set" do
+ a = []
+ @set.each { |o| a << o }
+ a.should eql([1, 2])
+ end
+
+ it "should convert to an array" do
+ @set.to_a.should eql([1, 2])
+ end
+
+ it "should convert to a set" do
+ @set.to_set.to_a.should eql([1, 2])
+ end
+end
1  vendor/gems/dirs/rack-mount
@@ -1 +0,0 @@
-Subproject commit 3784e633b42f43a4131e02519be60080d179da21
20 vendor/gems/dirs/rack-mount/LICENSE
View
@@ -0,0 +1,20 @@
+Copyright (c) 2009 Joshua Peek
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 vendor/gems/dirs/rack-mount/README.rdoc
View
@@ -0,0 +1,28 @@
+= Rack::Mount
+
+A stackable dynamic tree based Rack router.
+
+Rack::Mount supports Rack's Cascade style of trying several routes until it finds one that is not a 404. This allows multiple routes to be nested or stacked on top of each other. Since the application endpoint can trigger the router to continue matching, middleware can be used to add arbitrary conditions to any route. This allows you to route based on other request attributes, session information, or even data dynamically pulled from a database.
+
+=== Usage
+
+Rack::Mount provides a plugin API to build custom DSLs on top of.
+
+The API is extremely minimal and only 3 methods are exposed as the public API.
+
+<tt>Rack::Mount::RouteSet#add_route</tt>:: builder method for adding routes to the set
+<tt>Rack::Mount::RouteSet#call</tt>:: Rack compatible recognition and dispatching method
+<tt>Rack::Mount::RouteSet#url</tt>:: generates path from identifiers or significant keys
+
+=== Example
+
+ require 'rack/mount'
+ Routes = Rack::Mount::RouteSet.new do |set|
+ # add_route takes a rack application and conditions to match with
+ # conditions may be strings or regexps
+ # See Rack::Mount::RouteSet#add_route for more options.
+ set.add_route FooApp, :method => 'get' :path => %{/foo}
+ end
+
+ # The route set itself is a simple rack app you mount
+ run Routes
55 vendor/gems/dirs/rack-mount/Rakefile
View
@@ -0,0 +1,55 @@
+begin
+ require 'mg'
+ MG.new('rack-mount.gemspec')
+rescue LoadError
+end
+
+
+begin
+ require 'hanna/rdoctask'
+rescue LoadError
+ require 'rake/rdoctask'
+end
+
+Rake::RDocTask.new { |rdoc|
+ rdoc.rdoc_dir = 'doc'
+ rdoc.title = 'Rack::Mount'
+ rdoc.options << '--line-numbers' << '--inline-source'
+ rdoc.options << '--charset' << 'utf-8'
+
+ rdoc.rdoc_files.include('README.rdoc')
+ rdoc.rdoc_files.include('lib/**/*.rb')
+ rdoc.rdoc_files.exclude('lib/rack/mount/mappers/*.rb')
+}
+
+namespace :rdoc do
+ task :publish => :rdoc do
+ Dir.chdir(File.join(File.dirname(__FILE__), 'doc')) do
+ system 'git init'
+ system 'git add .'
+ system 'git commit -m "generate rdoc"'
+ system 'git remote add origin git@github.com:josh/rack-mount.git'
+ system 'git checkout -b gh-pages'
+ system 'git push -f origin gh-pages'
+ end
+ end
+end
+
+
+require 'rake/testtask'
+
+task :default => :test
+
+Rake::TestTask.new do |t|
+ t.libs << 'test'
+ # t.warning = true
+end
+
+
+namespace :vendor do
+ task :update_multimap do
+ system 'git clone git://github.com/josh/multimap.git'
+ FileUtils.cp_r('multimap/lib', 'lib/rack/mount/vendor/multimap')
+ FileUtils.rm_rf('multimap')
+ end
+end
47 vendor/gems/dirs/rack-mount/benchmark/bm_collisions_recognition.rb
View
@@ -0,0 +1,47 @@
+require 'helper'
+
+Map = Proc.new {
+ add('/a/:a/x').to(EchoApp)
+ ('a'..'w').each do |path|
+ add("/a/:a/#{path}").to(EchoApp)
+ end
+ add('/a/:a/y').to(EchoApp)
+ ('a'..'w').each do |path|
+ add("/a/:a/#{path}").to(EchoApp)
+ end
+ add('/a/:a/z').to(EchoApp)
+}
+
+require 'rack/mount'
+Mount = Rack::Mount::UsherMapper.map(&Map)
+
+require 'usher'
+Ush = Usher::Interface.for(:rack, &Map)
+
+TIMES = 10_000.to_i
+
+MountFirstEnv = EnvGenerator.env_for(TIMES, '/a/b/x')
+UshFirstEnv = EnvGenerator.env_for(TIMES, '/a/b/x')
+
+MountMidEnv = EnvGenerator.env_for(TIMES, '/a/b/y')
+UshMidEnv = EnvGenerator.env_for(TIMES, '/a/b/y')
+
+MountLastEnv = EnvGenerator.env_for(TIMES, '/a/b/z')
+UshLastEnv = EnvGenerator.env_for(TIMES, '/a/b/z')
+
+Benchmark.bmbm do |x|
+ x.report('rack-mount (first)') { TIMES.times { |n| Mount.call(MountFirstEnv[n]) } }
+ x.report('usher (first)') { TIMES.times { |n| Ush.call(UshFirstEnv[n]) } }
+ x.report('rack-mount (mid)') { TIMES.times { |n| Mount.call(MountMidEnv[n]) } }
+ x.report('usher (mid)') { TIMES.times { |n| Ush.call(UshMidEnv[n]) } }
+ x.report('rack-mount (last)') { TIMES.times { |n| Mount.call(MountLastEnv[n]) } }
+ x.report('usher (last)') { TIMES.times { |n| Ush.call(UshLastEnv[n]) } }
+end
+
+# user system total real
+# rack-mount (first) 0.580000 0.010000 0.590000 ( 0.661843)
+# usher (first) 0.800000 0.020000 0.820000 ( 0.870902)
+# rack-mount (mid) 0.570000 0.010000 0.580000 ( 0.606821)
+# usher (mid) 0.880000 0.010000 0.890000 ( 0.945685)
+# rack-mount (last) 0.570000 0.000000 0.570000 ( 0.599304)
+# usher (last) 0.880000 0.010000 0.890000 ( 0.912738)
41 vendor/gems/dirs/rack-mount/benchmark/bm_nested_recognition.rb
View
@@ -0,0 +1,41 @@
+require 'helper'
+
+Map = Proc.new {
+ ('a'..'zz').each do |path|
+ add("/#{path}").to(EchoApp)
+ end
+}
+
+require 'rack/mount'
+Mount = Rack::Mount::UsherMapper.map(&Map)
+
+require 'usher'
+Ush = Usher::Interface.for(:rack, &Map)
+
+TIMES = 10_000.to_i
+
+MountFirstEnv = EnvGenerator.env_for(TIMES, '/a')
+UshFirstEnv = EnvGenerator.env_for(TIMES, '/a')
+
+MountMidEnv = EnvGenerator.env_for(TIMES, '/mn')
+UshMidEnv = EnvGenerator.env_for(TIMES, '/mn')
+
+MountLastEnv = EnvGenerator.env_for(TIMES, '/zz')
+UshLastEnv = EnvGenerator.env_for(TIMES, '/zz')
+
+Benchmark.bmbm do |x|
+ x.report('rack-mount (first)') { TIMES.times { |n| Mount.call(MountFirstEnv[n]) } }
+ x.report('usher (first)') { TIMES.times { |n| Ush.call(UshFirstEnv[n]) } }
+ x.report('rack-mount (mid)') { TIMES.times { |n| Mount.call(MountMidEnv[n]) } }
+ x.report('usher (mid)') { TIMES.times { |n| Ush.call(UshMidEnv[n]) } }
+ x.report('rack-mount (last)') { TIMES.times { |n| Mount.call(MountLastEnv[n]) } }
+ x.report('usher (last)') { TIMES.times { |n| Ush.call(UshLastEnv[n]) } }
+end
+
+# user system total real
+# rack-mount (first) 0.330000 0.000000 0.330000 ( 0.325292)
+# usher (first) 0.440000 0.000000 0.440000 ( 0.436666)
+# rack-mount (mid) 0.350000 0.000000 0.350000 ( 0.347230)
+# usher (mid) 0.380000 0.000000 0.380000 ( 0.384767)
+# rack-mount (last) 0.360000 0.000000 0.360000 ( 0.359773)
+# usher (last) 0.440000 0.000000 0.440000 ( 0.446505)
10 vendor/gems/dirs/rack-mount/benchmark/bm_optimizations_benchmark.rb
View
@@ -0,0 +1,10 @@
+require 'helper'
+require 'fixtures'
+
+TIMES = 10_000.to_i
+Env = EnvGenerator.env_for(TIMES, '/account/credit_card/1')
+
+Benchmark.bmbm do |x|
+ x.report('unoptimized') { TIMES.times { |n| BasicSet.call(Env[n]) } }
+ x.report('optimized') { TIMES.times { |n| OptimizedBasicSet.call(Env[n]) } }
+end
146 vendor/gems/dirs/rack-mount/benchmark/helper.rb
View
@@ -0,0 +1,146 @@
+require 'rack/mount'
+require 'benchmark'
+
+class Rack::Mount::UsherMapper
+ def self.map(&block)
+ context = new
+ context.instance_eval(&block)
+ context.freeze
+ end
+
+ def initialize
+ @set = Rack::Mount::RouteSet.new
+ @path_info = nil
+ end
+
+ def freeze
+ @set.freeze
+ end
+
+ def add(path)
+ @path_info = Rack::Mount::Strexp.compile(path, {}, ['/'])
+ self
+ end
+
+ def to(app)
+ @set.add_route(app, :path_info => @path_info)
+ @path_info = nil
+ self
+ end
+end
+
+module EnvGenerator
+ def env_for(n, *args)
+ envs = []
+ n.times { envs << Rack::MockRequest.env_for(*args) }
+ envs
+ end
+ module_function :env_for
+end
+
+EchoApp = lambda { |env| Rack::Mount::Const::OK_RESPONSE }
+
+def Object.const_missing(name)
+ if name.to_s =~ /Controller$/
+ EchoApp
+ else
+ super
+ end
+end
+
+require 'set'