ruote-mongodb 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.
- data/LICENSE +20 -0
- data/README +15 -0
- data/lib/ruote-mongodb.rb +6 -0
- data/lib/ruote-mongodb/mongodb_storage.rb +203 -0
- data/spec/mongodb_storage_spec.rb +225 -0
- data/test/test_storage.rb +264 -0
- metadata +149 -0
    
        data/LICENSE
    ADDED
    
    | @@ -0,0 +1,20 @@ | |
| 1 | 
            +
            Copyright (c) 2010 Nathan Stults
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            Permission is hereby granted, free of charge, to any person obtaining
         | 
| 4 | 
            +
            a copy of this software and associated documentation files (the
         | 
| 5 | 
            +
            "Software"), to deal in the Software without restriction, including
         | 
| 6 | 
            +
            without limitation the rights to use, copy, modify, merge, publish,
         | 
| 7 | 
            +
            distribute, sublicense, and/or sell copies of the Software, and to
         | 
| 8 | 
            +
            permit persons to whom the Software is furnished to do so, subject to
         | 
| 9 | 
            +
            the following conditions:
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            The above copyright notice and this permission notice shall be
         | 
| 12 | 
            +
            included in all copies or substantial portions of the Software.
         | 
| 13 | 
            +
             | 
| 14 | 
            +
            THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
         | 
| 15 | 
            +
            EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
         | 
| 16 | 
            +
            MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
         | 
| 17 | 
            +
            NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
         | 
| 18 | 
            +
            LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
         | 
| 19 | 
            +
            OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
         | 
| 20 | 
            +
            WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
         | 
    
        data/README
    ADDED
    
    | @@ -0,0 +1,15 @@ | |
| 1 | 
            +
            ruote-mongodb is a storage provider for the Ruote workflow engine: http://ruote.rubyforge.org/  It enables Ruote to store its data in MongoDB.
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            INSTALLATION:
         | 
| 4 | 
            +
            If you're using bundler, you can include this in your Gemfile as follows:
         | 
| 5 | 
            +
            gem 'ruote-mongodb', :git=>"git://github.com/PlasticLizard/ruote-mongodb.git"
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            USAGE:
         | 
| 8 | 
            +
            You can initialize Ruote::MongoDbStorage and pass it directly into the constructor for a Ruote::Worker just like any other Ruote storage provider.
         | 
| 9 | 
            +
            You can pass in connection information on the constructor as follows:
         | 
| 10 | 
            +
            Ruote::MongoDbStorage.new(:connection=>{"host"=>"localhost", "port"=>27017, "database"=>"Ruote", "username"=>"pat", "password"=>"s3cret"})
         | 
| 11 | 
            +
            You can pass also pass in a :config option in the constructor parameters with a path to a YAML file containing your configuration settings.  If you do that, also specify an :environment option representing which set of config settings to use (eg. "development" or Rails.env).
         | 
| 12 | 
            +
            Note that any specific connection settings you pass to the constructor will over-ride the settings from the YAML file.
         | 
| 13 | 
            +
            By default (if you don't pass anything in on the constructor), the provider will attempt to connect to host=localhost, port=27017, database=Ruote (unauthenticated)
         | 
| 14 | 
            +
             | 
| 15 | 
            +
            *** USE AT YOUR OWN RISK!  There is no warrany of any kind for this software. The author accepts no responsibility for data loss or any ohter harm that may come from using this software.  In particular, you should be aware that Ruote will call this storage provider's purge! method, which is designed to remove any collections from the database it's using which begin with the string stored in the @@collection_prefix class variable ("ruote_" by default).  If that sounds like it could be harmful, consider changing the prefix and/or configuring this provider to use its own database.
         | 
| @@ -0,0 +1,203 @@ | |
| 1 | 
            +
            require 'ruote'
         | 
| 2 | 
            +
            require 'date'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            module Ruote
         | 
| 5 | 
            +
              class MongoDbStorage
         | 
| 6 | 
            +
                include StorageBase
         | 
| 7 | 
            +
                include MonitorMixin
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                @@collection_prefix = "ruote_"
         | 
| 10 | 
            +
                @@encoded_dollar_sign = "~#~"
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                def initialize(options={})
         | 
| 13 | 
            +
                  super()
         | 
| 14 | 
            +
                  db_config = {"host"=>"localhost", "port"=>27017, "database"=>"Ruote"}
         | 
| 15 | 
            +
                  options = options.dup
         | 
| 16 | 
            +
                  if environment = options.delete(:environment)
         | 
| 17 | 
            +
                    all_db_config=
         | 
| 18 | 
            +
                      File.open(options.delete(:config) || 'config/database.yml','r') do |f|
         | 
| 19 | 
            +
                        YAML.load(f)
         | 
| 20 | 
            +
                      end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                    raise "no configuration for environment: #{environment}" unless env_config = all_db_config[environment]
         | 
| 23 | 
            +
                    db_config.merge!(env_config)
         | 
| 24 | 
            +
                  end
         | 
| 25 | 
            +
                  #args take precedent over config
         | 
| 26 | 
            +
                  db_config.merge! options.delete(:connection) if options[:connection]
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                  @db = Mongo::Connection.new(db_config['host'], db_config['port']).
         | 
| 29 | 
            +
            	db(db_config['database'])
         | 
| 30 | 
            +
                  if db_config['username'] && db_config['password']
         | 
| 31 | 
            +
                    @db.authenticate(db_config['username'], db_config['password'])
         | 
| 32 | 
            +
                  end
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                  unless get('configurations','engine')
         | 
| 35 | 
            +
                    put(options.merge('type'=>'configurations', '_id'=>'engine')) 
         | 
| 36 | 
            +
                  end
         | 
| 37 | 
            +
                end
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                def close_connection()
         | 
| 40 | 
            +
                  @db.connection.close()
         | 
| 41 | 
            +
                end
         | 
| 42 | 
            +
             | 
| 43 | 
            +
                def put(doc, opts={})
         | 
| 44 | 
            +
                  synchronize do
         | 
| 45 | 
            +
                    raise "doc must have a type" unless doc['type']
         | 
| 46 | 
            +
                    raise "doc must have an ID" unless doc['_id']
         | 
| 47 | 
            +
                    pre = get(doc['type'], doc['_id'])
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                    if pre && pre['_rev'] != doc['_rev']
         | 
| 50 | 
            +
                      return pre
         | 
| 51 | 
            +
                    end
         | 
| 52 | 
            +
             | 
| 53 | 
            +
                    if pre.nil? && doc['_rev']
         | 
| 54 | 
            +
                      return true
         | 
| 55 | 
            +
                    end
         | 
| 56 | 
            +
             | 
| 57 | 
            +
                    doc = if opts[:update_rev]
         | 
| 58 | 
            +
                            doc['_rev'] = pre ? pre['_rev'] : -1
         | 
| 59 | 
            +
                            doc
         | 
| 60 | 
            +
                          else
         | 
| 61 | 
            +
                            doc.merge('_rev' => doc['_rev'] || -1)
         | 
| 62 | 
            +
                          end
         | 
| 63 | 
            +
             | 
| 64 | 
            +
                    doc['put_at'] = Ruote.now_to_utc_s
         | 
| 65 | 
            +
                    doc['_rev'] = doc['_rev'] + 1
         | 
| 66 | 
            +
             | 
| 67 | 
            +
                    encoded_doc = Rufus::Json.dup(doc)
         | 
| 68 | 
            +
                    to_mongo encoded_doc
         | 
| 69 | 
            +
                    get_collection(doc['type']).save(encoded_doc)
         | 
| 70 | 
            +
             | 
| 71 | 
            +
                    nil
         | 
| 72 | 
            +
                  end
         | 
| 73 | 
            +
                end
         | 
| 74 | 
            +
             | 
| 75 | 
            +
                def get(type, key)
         | 
| 76 | 
            +
                  synchronize do
         | 
| 77 | 
            +
                    doc = get_collection(type).find_one("_id" => key)
         | 
| 78 | 
            +
                    from_mongo doc if doc
         | 
| 79 | 
            +
                    doc
         | 
| 80 | 
            +
                  end
         | 
| 81 | 
            +
                end
         | 
| 82 | 
            +
             | 
| 83 | 
            +
                def delete(doc)
         | 
| 84 | 
            +
                  drev = doc['_rev']
         | 
| 85 | 
            +
                  raise ArgumentError.new("can't delete doc without _rev") unless drev
         | 
| 86 | 
            +
                  synchronize do
         | 
| 87 | 
            +
                    raise "doc must have a type" unless doc['type']
         | 
| 88 | 
            +
                    prev = get(doc['type'], doc['_id'])
         | 
| 89 | 
            +
                    return true if prev.nil?
         | 
| 90 | 
            +
                    doc['_rev'] ||= 0
         | 
| 91 | 
            +
                    if prev['_rev'] == drev
         | 
| 92 | 
            +
                      get_collection(doc['type']).remove("_id" => doc["_id"])
         | 
| 93 | 
            +
                      nil
         | 
| 94 | 
            +
                    else
         | 
| 95 | 
            +
                      prev
         | 
| 96 | 
            +
                    end
         | 
| 97 | 
            +
                  end
         | 
| 98 | 
            +
                end
         | 
| 99 | 
            +
             | 
| 100 | 
            +
                def get_many(type, key=nil, opts={})
         | 
| 101 | 
            +
                  synchronize do
         | 
| 102 | 
            +
                    return get_collection(type).count if opts[:count]
         | 
| 103 | 
            +
                    criteria = {}
         | 
| 104 | 
            +
                    find_opts = {}
         | 
| 105 | 
            +
                    find_opts[:limit] = opts[:limit] if opts[:limit]
         | 
| 106 | 
            +
                    find_opts[:skip] = opts[:skip] if opts[:skip]
         | 
| 107 | 
            +
                    find_opts[:sort] = ["_id", opts[:descending] ? :descending : :ascending]
         | 
| 108 | 
            +
                    if key
         | 
| 109 | 
            +
                      id_criteria = Array(key).map do |k|
         | 
| 110 | 
            +
                        case k.class.to_s
         | 
| 111 | 
            +
                        when "String" then "!#{k}$"
         | 
| 112 | 
            +
                        when "Regexp" then k.source
         | 
| 113 | 
            +
                        else k.to_s
         | 
| 114 | 
            +
                        end
         | 
| 115 | 
            +
                      end
         | 
| 116 | 
            +
                      criteria = {"_id" => /#{id_criteria.join "|"}/}
         | 
| 117 | 
            +
                    end
         | 
| 118 | 
            +
                    docs = get_collection(type).find(criteria, find_opts).to_a
         | 
| 119 | 
            +
                    docs.each do |doc|
         | 
| 120 | 
            +
                      from_mongo doc
         | 
| 121 | 
            +
                    end
         | 
| 122 | 
            +
                    docs
         | 
| 123 | 
            +
                  end
         | 
| 124 | 
            +
                end
         | 
| 125 | 
            +
             | 
| 126 | 
            +
                def ids(type)
         | 
| 127 | 
            +
                  synchronize do
         | 
| 128 | 
            +
                    result = get_collection(type).find({}, {:fields=>["_id"]}).map do |row|
         | 
| 129 | 
            +
                      row["_id"].to_s
         | 
| 130 | 
            +
                    end
         | 
| 131 | 
            +
                    result.sort
         | 
| 132 | 
            +
                  end
         | 
| 133 | 
            +
                end
         | 
| 134 | 
            +
             | 
| 135 | 
            +
                def purge!
         | 
| 136 | 
            +
                  synchronize do
         | 
| 137 | 
            +
                    @db.collection_names.each do |name| 
         | 
| 138 | 
            +
                      @db.drop_collection(name) if name =~ /^#{@@collection_prefix}/
         | 
| 139 | 
            +
                    end
         | 
| 140 | 
            +
                  end
         | 
| 141 | 
            +
                end
         | 
| 142 | 
            +
             | 
| 143 | 
            +
                def add_type(type)
         | 
| 144 | 
            +
                  synchronize do
         | 
| 145 | 
            +
                    get_collection(type).create_index("_id")
         | 
| 146 | 
            +
                  end
         | 
| 147 | 
            +
                end
         | 
| 148 | 
            +
             | 
| 149 | 
            +
                def purge_type!(type)
         | 
| 150 | 
            +
                  synchronize do
         | 
| 151 | 
            +
                    @db.drop_collection(@@collection_prefix + type)
         | 
| 152 | 
            +
                  end
         | 
| 153 | 
            +
                end
         | 
| 154 | 
            +
             | 
| 155 | 
            +
                private
         | 
| 156 | 
            +
             | 
| 157 | 
            +
                def get_collection(type)
         | 
| 158 | 
            +
                  @db[@@collection_prefix + type]
         | 
| 159 | 
            +
                end
         | 
| 160 | 
            +
             | 
| 161 | 
            +
                # encodes unsupported data ($, Date) for storage in MongoDB
         | 
| 162 | 
            +
                def from_mongo(doc)
         | 
| 163 | 
            +
                  mongo_encode(doc, /^#{@@encoded_dollar_sign}/, "$", :backward)
         | 
| 164 | 
            +
                end
         | 
| 165 | 
            +
             | 
| 166 | 
            +
                # unencodes unsupported values ($, Date) from storage in MongoDB
         | 
| 167 | 
            +
                def to_mongo(doc)
         | 
| 168 | 
            +
                  mongo_encode(doc, /^\$/, @@encoded_dollar_sign, :forward)
         | 
| 169 | 
            +
                end
         | 
| 170 | 
            +
             | 
| 171 | 
            +
                # called by from_mongo and to_mongo
         | 
| 172 | 
            +
                def mongo_encode(doc, pattern, replacement, date_conv)
         | 
| 173 | 
            +
                  if doc.is_a? Hash
         | 
| 174 | 
            +
                    doc.each_pair do |key, value|
         | 
| 175 | 
            +
                      new_key = key
         | 
| 176 | 
            +
                      if key.is_a?(String) && key =~ pattern
         | 
| 177 | 
            +
                        new_key = key.sub(pattern, replacement)
         | 
| 178 | 
            +
                        doc[new_key] = value
         | 
| 179 | 
            +
                        doc.delete key
         | 
| 180 | 
            +
                      end
         | 
| 181 | 
            +
                      mongo_encode(value, pattern, replacement, date_conv)
         | 
| 182 | 
            +
                      ensure_date_encoding(value, doc, new_key, date_conv)
         | 
| 183 | 
            +
                      doc[new_key] = value.to_s if value.is_a? Symbol
         | 
| 184 | 
            +
                    end
         | 
| 185 | 
            +
                  elsif doc.is_a? Array
         | 
| 186 | 
            +
                    doc.each_with_index do |entry, i|
         | 
| 187 | 
            +
                      mongo_encode(entry, pattern, replacement, date_conv)
         | 
| 188 | 
            +
                      ensure_date_encoding(entry, doc, i, date_conv)
         | 
| 189 | 
            +
                      doc[i] = entry.to_s if entry.is_a? Symbol
         | 
| 190 | 
            +
                    end
         | 
| 191 | 
            +
                  end
         | 
| 192 | 
            +
                end
         | 
| 193 | 
            +
             | 
| 194 | 
            +
                def ensure_date_encoding(value, doc, key, date_conv)
         | 
| 195 | 
            +
                  if value.is_a?(Date) && date_conv == :forward
         | 
| 196 | 
            +
                    doc[key] = "DT_" + value.to_s
         | 
| 197 | 
            +
                  end
         | 
| 198 | 
            +
                  if value.is_a?(String) && value[0,3] == "DT_" && date_conv == :backward
         | 
| 199 | 
            +
                    doc[key] = Date.parse(value[3..-1])
         | 
| 200 | 
            +
                  end
         | 
| 201 | 
            +
                end
         | 
| 202 | 
            +
              end
         | 
| 203 | 
            +
            end
         | 
| @@ -0,0 +1,225 @@ | |
| 1 | 
            +
            require 'ruote-mongodb'
         | 
| 2 | 
            +
            require 'date'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            describe Ruote::MongoDbStorage do
         | 
| 5 | 
            +
              describe "options" do
         | 
| 6 | 
            +
                after :each do
         | 
| 7 | 
            +
                  File.delete("config/database.yml") if File.exist?("config/database.yml")
         | 
| 8 | 
            +
                end
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                it "uses sensible defaults if no DB configuration specified" do
         | 
| 11 | 
            +
                  lambda {
         | 
| 12 | 
            +
                    Ruote::MongoDbStorage.new
         | 
| 13 | 
            +
                  }.should_not raise_error
         | 
| 14 | 
            +
                end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                it "fails if invalid server passed in on constructor" do
         | 
| 17 | 
            +
                  lambda {
         | 
| 18 | 
            +
                    Ruote::MongoDbStorage.new :connection=>{"host"=>"doesntexist"}
         | 
| 19 | 
            +
                  }.should raise_error Mongo::ConnectionFailure
         | 
| 20 | 
            +
                end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                it "fails if an environment is passed in but database.yml doesn't exist" do
         | 
| 23 | 
            +
                  lambda {
         | 
| 24 | 
            +
                    Ruote::MongoDbStorage.new :environment=>"test"
         | 
| 25 | 
            +
                  }.should raise_error "No such file or directory - config/database.yml"
         | 
| 26 | 
            +
                  #TODO: consider a better error message for this case
         | 
| 27 | 
            +
                end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                it "works when database.yml specifies valid settings for the environment" do
         | 
| 30 | 
            +
                  File.open("config/database.yml", "w") do |f|
         | 
| 31 | 
            +
                    f.puts "test:"
         | 
| 32 | 
            +
                    f.puts "    host: localhost"
         | 
| 33 | 
            +
                  end
         | 
| 34 | 
            +
                  lambda {
         | 
| 35 | 
            +
                    Ruote::MongoDbStorage.new :environment=>"test"
         | 
| 36 | 
            +
                  }.should_not raise_error
         | 
| 37 | 
            +
                end
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                it "fails when environment doesn't exist in database.yml" do
         | 
| 40 | 
            +
                  File.open("config/database.yml", "w") do |f|
         | 
| 41 | 
            +
                    f.puts "test:"
         | 
| 42 | 
            +
                    f.puts "    host: localhost"
         | 
| 43 | 
            +
                  end
         | 
| 44 | 
            +
                  lambda {
         | 
| 45 | 
            +
                    Ruote::MongoDbStorage.new :environment=>"development"
         | 
| 46 | 
            +
                  }.should raise_error "no configuration for environment: development"
         | 
| 47 | 
            +
                end
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                it "fails when invalid server in database.yml" do
         | 
| 50 | 
            +
                  File.open("config/database.yml", "w") do |f|
         | 
| 51 | 
            +
                    f.puts "test:"
         | 
| 52 | 
            +
                    f.puts "    host: doesntexist"
         | 
| 53 | 
            +
                  end
         | 
| 54 | 
            +
                  lambda {
         | 
| 55 | 
            +
                    Ruote::MongoDbStorage.new :environment=>"test"
         | 
| 56 | 
            +
                  }.should raise_error Mongo::ConnectionFailure
         | 
| 57 | 
            +
                end
         | 
| 58 | 
            +
              end
         | 
| 59 | 
            +
             | 
| 60 | 
            +
              describe "provider" do
         | 
| 61 | 
            +
                before :each do
         | 
| 62 | 
            +
                  @repo = Ruote::MongoDbStorage.new
         | 
| 63 | 
            +
                  @repo.purge!
         | 
| 64 | 
            +
                end
         | 
| 65 | 
            +
             | 
| 66 | 
            +
                after :each do
         | 
| 67 | 
            +
                  @repo.close_connection
         | 
| 68 | 
            +
                end
         | 
| 69 | 
            +
             | 
| 70 | 
            +
                it "can store and retrieve a document by ID" do
         | 
| 71 | 
            +
                  key = BSON::ObjectId.new.to_s
         | 
| 72 | 
            +
                  doc = {"_id" => key, "name" => "ralph", "type" => "test"}
         | 
| 73 | 
            +
                  result = @repo.put doc
         | 
| 74 | 
            +
                  result.should be_nil
         | 
| 75 | 
            +
                  doc = @repo.get 'test', key
         | 
| 76 | 
            +
                  doc["name"].should == "ralph"
         | 
| 77 | 
            +
                end
         | 
| 78 | 
            +
             | 
| 79 | 
            +
                it "can update a document by ID" do
         | 
| 80 | 
            +
                  key = BSON::ObjectId.new.to_s
         | 
| 81 | 
            +
                  doc = {"_id" => key, "name" => "ralph", "type" => "test"}
         | 
| 82 | 
            +
                  @repo.put doc
         | 
| 83 | 
            +
                  doc = @repo.get 'test', key
         | 
| 84 | 
            +
                  doc["name"] = "bill"
         | 
| 85 | 
            +
                  @repo.put doc
         | 
| 86 | 
            +
                  doc = @repo.get 'test', key
         | 
| 87 | 
            +
                  doc["name"].should == "bill"
         | 
| 88 | 
            +
                end
         | 
| 89 | 
            +
             | 
| 90 | 
            +
                it "can store documents with keys starting with dollar sign" do
         | 
| 91 | 
            +
                  key = BSON::ObjectId.new.to_s
         | 
| 92 | 
            +
                  doc = {"_id" => key, "type" => "test", "a" => ["$b" => "c"]}
         | 
| 93 | 
            +
                  @repo.put doc
         | 
| 94 | 
            +
                  doc = @repo.get 'test', key
         | 
| 95 | 
            +
                  doc["a"].should == ["$b" => "c"]
         | 
| 96 | 
            +
                end
         | 
| 97 | 
            +
             | 
| 98 | 
            +
                it "can store documents with dates" do
         | 
| 99 | 
            +
                  key = BSON::ObjectId.new.to_s
         | 
| 100 | 
            +
                  doc = {"_id" => key, "type" => "test", "a" => ["b" => Date.parse("11/9/2010")]}
         | 
| 101 | 
            +
                  @repo.put doc
         | 
| 102 | 
            +
                  doc = @repo.get 'test', key
         | 
| 103 | 
            +
                  doc["a"][0]["b"].to_s.should == "2010-11-09"
         | 
| 104 | 
            +
                end
         | 
| 105 | 
            +
             | 
| 106 | 
            +
                it "can store large floating point numbers accurately" do
         | 
| 107 | 
            +
                  key = BSON::ObjectId.new.to_s
         | 
| 108 | 
            +
                  doc = {"_id" => key, "type" => "test", "raw" => 1289501850.34665} #1289443610.7243}
         | 
| 109 | 
            +
                  @repo.put doc
         | 
| 110 | 
            +
                  doc = @repo.get 'test', key
         | 
| 111 | 
            +
                  doc["raw"].should == 1289501850.34665 #1289443610.7243
         | 
| 112 | 
            +
                end
         | 
| 113 | 
            +
             | 
| 114 | 
            +
                it "can retrieve a document by a string ID" do
         | 
| 115 | 
            +
                  key = "hello"
         | 
| 116 | 
            +
                  doc = {"_id" => key, "name" => "ralph", "type" => "test"}
         | 
| 117 | 
            +
                  @repo.put doc
         | 
| 118 | 
            +
                  doc = @repo.get 'test', key
         | 
| 119 | 
            +
                  doc["name"].should == "ralph"
         | 
| 120 | 
            +
                end
         | 
| 121 | 
            +
             | 
| 122 | 
            +
                it "can delete a document" do
         | 
| 123 | 
            +
                  key = BSON::ObjectId.new.to_s
         | 
| 124 | 
            +
                  doc = {"_id" => key, "name" => "ralph", "type" => "test", "_rev" => 0}
         | 
| 125 | 
            +
                  @repo.put doc
         | 
| 126 | 
            +
                  @repo.delete doc
         | 
| 127 | 
            +
                  @repo.get('test', key).should be_nil
         | 
| 128 | 
            +
                end
         | 
| 129 | 
            +
             | 
| 130 | 
            +
                it "will provide a list of IDs" do
         | 
| 131 | 
            +
                  key1 = "hello" + BSON::ObjectId.new.to_s
         | 
| 132 | 
            +
                  key2 = "hello" + BSON::ObjectId.new.to_s
         | 
| 133 | 
            +
                  key3 = "hello" + BSON::ObjectId.new.to_s
         | 
| 134 | 
            +
                  @repo.put({"_id" => key1, "name" => "ralph", "type" => "test"})
         | 
| 135 | 
            +
                  @repo.put({"_id" => key2, "name" => "ralph", "type" => "test"})
         | 
| 136 | 
            +
                  @repo.put({"_id" => key3, "name" => "ralph", "type" => "test2"})
         | 
| 137 | 
            +
                  @repo.ids("test").should == [key1, key2]
         | 
| 138 | 
            +
                  @repo.ids("test2").should == [key3]
         | 
| 139 | 
            +
                end
         | 
| 140 | 
            +
             | 
| 141 | 
            +
                it "only purges collections starting with the ruote_ prefix" do
         | 
| 142 | 
            +
                  db = @repo.instance_eval "@db"
         | 
| 143 | 
            +
                  db.drop_collection("something_else")
         | 
| 144 | 
            +
                  @repo.put({"_id" => BSON::ObjectId.new.to_s, "name" => "ralph", "type" => "test"})
         | 
| 145 | 
            +
                  @repo.put({"_id" => BSON::ObjectId.new.to_s, "name" => "bill", "type" => "test2"})
         | 
| 146 | 
            +
                  db.collection_names.should == ["system.indexes", "ruote_test", "ruote_test2"]
         | 
| 147 | 
            +
                  db["something_else"].insert({"name" => "doug"})
         | 
| 148 | 
            +
                  @repo.purge!
         | 
| 149 | 
            +
                  db.collection_names.should == ["system.indexes", "something_else"]
         | 
| 150 | 
            +
                end
         | 
| 151 | 
            +
             | 
| 152 | 
            +
                it "can purge a particular type" do
         | 
| 153 | 
            +
                  key1 = BSON::ObjectId.new.to_s
         | 
| 154 | 
            +
                  key2 = BSON::ObjectId.new.to_s
         | 
| 155 | 
            +
                  @repo.put({"_id" => key1, "name" => "ralph", "type" => "test"})
         | 
| 156 | 
            +
                  @repo.put({"_id" => key2, "name" => "bill", "type" => "test2"})
         | 
| 157 | 
            +
                  @repo.purge_type! "test2"
         | 
| 158 | 
            +
                  @repo.get('test', key1)["name"].should == "ralph"
         | 
| 159 | 
            +
                  @repo.get('test2', key2).should be_nil
         | 
| 160 | 
            +
                end
         | 
| 161 | 
            +
             | 
| 162 | 
            +
                describe "can get multiple documents" do
         | 
| 163 | 
            +
                  before :each do
         | 
| 164 | 
            +
                    key1 = "TANGO!ALPHA!BRAVO"
         | 
| 165 | 
            +
                    key2 = "TANGO!ALPHA-BRAVO"
         | 
| 166 | 
            +
                    key3 = "FOXTROT!ALPHA-BRAVO"
         | 
| 167 | 
            +
                    @repo.put({"_id"=>key1, "fname"=>"ralph", "lname"=>"A", "type"=>"test"})
         | 
| 168 | 
            +
                    @repo.put({"_id"=>key2, "fname"=>"bill", "lname"=>"B", "type"=>"test"})
         | 
| 169 | 
            +
                    @repo.put({"_id"=>key3, "fname"=>"nancy", "lname"=>"A", "type"=>"test"})
         | 
| 170 | 
            +
                  end
         | 
| 171 | 
            +
             | 
| 172 | 
            +
                  it "with criteria" do
         | 
| 173 | 
            +
                    search_key = ["BRAVO", /FOXTROT/]
         | 
| 174 | 
            +
                    docs = @repo.get_many("test", search_key)
         | 
| 175 | 
            +
                    docs.count.should == 2
         | 
| 176 | 
            +
                    (docs.select {|doc| doc["fname"] == "ralph"}).count.should == 1
         | 
| 177 | 
            +
                    (docs.select {|doc| doc["fname"] == "nancy"}).count.should == 1
         | 
| 178 | 
            +
                    (docs.select {|doc| doc["fname"] == "bill"}).count.should == 0
         | 
| 179 | 
            +
                  end
         | 
| 180 | 
            +
             | 
| 181 | 
            +
                  it "without criteria" do
         | 
| 182 | 
            +
                    docs = @repo.get_many("test", nil)
         | 
| 183 | 
            +
                    docs.count.should == 3
         | 
| 184 | 
            +
                  end
         | 
| 185 | 
            +
             | 
| 186 | 
            +
                  it "up to a certain limit" do
         | 
| 187 | 
            +
                    docs = @repo.get_many("test", nil, {:limit => 2})
         | 
| 188 | 
            +
                    docs.count.should == 2
         | 
| 189 | 
            +
                    (docs.select {|doc| doc["fname"] == "nancy"}).count.should == 1
         | 
| 190 | 
            +
                    (docs.select {|doc| doc["fname"] == "ralph"}).count.should == 1
         | 
| 191 | 
            +
                  end
         | 
| 192 | 
            +
             | 
| 193 | 
            +
                  it "skipping a certain number" do
         | 
| 194 | 
            +
                    docs = @repo.get_many("test", nil, {:skip => 2})
         | 
| 195 | 
            +
                    docs.count.should == 1
         | 
| 196 | 
            +
                    (docs.select {|doc| doc["fname"] == "bill"}).count.should == 1
         | 
| 197 | 
            +
                  end
         | 
| 198 | 
            +
             | 
| 199 | 
            +
                  it "in descending order" do
         | 
| 200 | 
            +
                    docs = @repo.get_many("test", nil, {:descending => true})
         | 
| 201 | 
            +
                    docs[0]["fname"].should == "bill"
         | 
| 202 | 
            +
                    docs[1]["fname"].should == "ralph"
         | 
| 203 | 
            +
                    docs[2]["fname"].should == "nancy"
         | 
| 204 | 
            +
                  end
         | 
| 205 | 
            +
             | 
| 206 | 
            +
                  it "in ascending order" do
         | 
| 207 | 
            +
                    docs = @repo.get_many("test", nil, {:descending => false})
         | 
| 208 | 
            +
                    docs[0]["fname"].should == "nancy"
         | 
| 209 | 
            +
                    docs[1]["fname"].should == "ralph"
         | 
| 210 | 
            +
                    docs[2]["fname"].should == "bill"
         | 
| 211 | 
            +
                  end
         | 
| 212 | 
            +
             | 
| 213 | 
            +
                  it "in asceneding order, by default" do
         | 
| 214 | 
            +
                    docs = @repo.get_many("test", nil)
         | 
| 215 | 
            +
                    docs[0]["fname"].should == "nancy"
         | 
| 216 | 
            +
                    docs[1]["fname"].should == "ralph"
         | 
| 217 | 
            +
                    docs[2]["fname"].should == "bill"
         | 
| 218 | 
            +
                  end
         | 
| 219 | 
            +
             | 
| 220 | 
            +
                  it "count" do
         | 
| 221 | 
            +
                    @repo.get_many("test", nil, {:count => true}).should == 3
         | 
| 222 | 
            +
                  end
         | 
| 223 | 
            +
                end
         | 
| 224 | 
            +
              end
         | 
| 225 | 
            +
            end
         | 
| @@ -0,0 +1,264 @@ | |
| 1 | 
            +
            require 'rubygems'
         | 
| 2 | 
            +
            require 'test/unit'
         | 
| 3 | 
            +
            require 'mongo'
         | 
| 4 | 
            +
            require 'lib/ruote-mongodb'
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            #
         | 
| 7 | 
            +
            # note : using the 'errors' type, but this test is about generic storage, not
         | 
| 8 | 
            +
            #        about errors per se.
         | 
| 9 | 
            +
            #
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            class UtStorage < Test::Unit::TestCase
         | 
| 12 | 
            +
             | 
| 13 | 
            +
              def setup
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                # @s = determine_storage({})
         | 
| 16 | 
            +
                @s = Ruote::MongoDbStorage.new
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                #@s.add_type('errors')
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                @s.put(
         | 
| 21 | 
            +
                  '_id' => 'toto',
         | 
| 22 | 
            +
                  'type' => 'errors',
         | 
| 23 | 
            +
                  'message' => 'testing')
         | 
| 24 | 
            +
              end
         | 
| 25 | 
            +
              def teardown
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                @s.get_many('errors').each do |d|
         | 
| 28 | 
            +
                  @s.delete(d)
         | 
| 29 | 
            +
                end
         | 
| 30 | 
            +
              end
         | 
| 31 | 
            +
             | 
| 32 | 
            +
              def test_get_configuration
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                assert_not_nil @s.get_configuration('engine')
         | 
| 35 | 
            +
              end
         | 
| 36 | 
            +
             | 
| 37 | 
            +
              def test_get
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                h = @s.get('errors', 'toto')
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                assert_not_nil h['_rev']
         | 
| 42 | 
            +
             | 
| 43 | 
            +
                h = @s.get('errors', 'nada')
         | 
| 44 | 
            +
             | 
| 45 | 
            +
                assert_nil h
         | 
| 46 | 
            +
              end
         | 
| 47 | 
            +
             | 
| 48 | 
            +
              def test_put
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                doc =  {
         | 
| 51 | 
            +
                  '_id' => 'test_put', 'type' => 'errors', 'message' => 'testing (2)' }
         | 
| 52 | 
            +
             | 
| 53 | 
            +
                @s.put(doc)
         | 
| 54 | 
            +
             | 
| 55 | 
            +
                assert_nil doc['_rev']
         | 
| 56 | 
            +
             | 
| 57 | 
            +
                h = @s.get('errors', 'test_put')
         | 
| 58 | 
            +
             | 
| 59 | 
            +
                assert_not_nil h['_rev']
         | 
| 60 | 
            +
                assert_not_nil h['put_at']
         | 
| 61 | 
            +
              end
         | 
| 62 | 
            +
             | 
| 63 | 
            +
              def test_put_fail
         | 
| 64 | 
            +
             | 
| 65 | 
            +
                r = @s.put('_id' => 'toto', 'type' => 'errors', 'message' => 'more')
         | 
| 66 | 
            +
             | 
| 67 | 
            +
                assert_equal 'toto', r['_id']
         | 
| 68 | 
            +
                assert_not_nil r['_rev']
         | 
| 69 | 
            +
              end
         | 
| 70 | 
            +
             | 
| 71 | 
            +
              def test_put_update_rev
         | 
| 72 | 
            +
             | 
| 73 | 
            +
                doc = { '_id' => 'tpur', 'type' => 'errors', 'message' => 'more' }
         | 
| 74 | 
            +
             | 
| 75 | 
            +
                r = @s.put(doc, :update_rev => true)
         | 
| 76 | 
            +
             | 
| 77 | 
            +
                assert_not_nil doc['_rev']
         | 
| 78 | 
            +
              end
         | 
| 79 | 
            +
             | 
| 80 | 
            +
              def test_put_put_and_put
         | 
| 81 | 
            +
             | 
| 82 | 
            +
                doc = { '_id' => 'whiskas', 'type' => 'errors', 'message' => 'miam' }
         | 
| 83 | 
            +
             | 
| 84 | 
            +
                r = @s.put(doc)
         | 
| 85 | 
            +
                doc = @s.get('errors', 'whiskas')
         | 
| 86 | 
            +
             | 
| 87 | 
            +
                r = @s.put(doc)
         | 
| 88 | 
            +
                assert_nil r
         | 
| 89 | 
            +
             | 
| 90 | 
            +
                doc = @s.get('errors', 'whiskas')
         | 
| 91 | 
            +
             | 
| 92 | 
            +
                assert_not_nil doc['put_at']
         | 
| 93 | 
            +
             | 
| 94 | 
            +
                r = @s.put(doc)
         | 
| 95 | 
            +
                assert_nil r
         | 
| 96 | 
            +
              end
         | 
| 97 | 
            +
             | 
| 98 | 
            +
              def test_put_update_rev_twice
         | 
| 99 | 
            +
             | 
| 100 | 
            +
                doc = { '_id' => 'tpurt', 'type' => 'errors', 'message' => 'more' }
         | 
| 101 | 
            +
             | 
| 102 | 
            +
                r = @s.put(doc, :update_rev => true)
         | 
| 103 | 
            +
                assert_nil r
         | 
| 104 | 
            +
             | 
| 105 | 
            +
                doc = { '_id' => 'tpurt', 'type' => 'errors', 'message' => 'more' }
         | 
| 106 | 
            +
             | 
| 107 | 
            +
                r = @s.put(doc, :update_rev => true)
         | 
| 108 | 
            +
                assert_not_nil r
         | 
| 109 | 
            +
              end
         | 
| 110 | 
            +
             | 
| 111 | 
            +
              def test_delete_fail
         | 
| 112 | 
            +
             | 
| 113 | 
            +
                # missing _rev
         | 
| 114 | 
            +
             | 
| 115 | 
            +
                assert_raise(ArgumentError) do
         | 
| 116 | 
            +
                  @s.delete('_id' => 'toto')
         | 
| 117 | 
            +
                end
         | 
| 118 | 
            +
              end
         | 
| 119 | 
            +
             | 
| 120 | 
            +
              def test_delete
         | 
| 121 | 
            +
             | 
| 122 | 
            +
                doc = @s.get('errors', 'toto')
         | 
| 123 | 
            +
                puts "test_delete: #{doc}"
         | 
| 124 | 
            +
                r = @s.delete(doc)
         | 
| 125 | 
            +
             | 
| 126 | 
            +
                assert_nil r
         | 
| 127 | 
            +
              end
         | 
| 128 | 
            +
             | 
| 129 | 
            +
              def test_delete_missing
         | 
| 130 | 
            +
             | 
| 131 | 
            +
                r = @s.delete('_id' => 'x', '_rev' => '12-13231123132', 'type' => 'errors')
         | 
| 132 | 
            +
             | 
| 133 | 
            +
                assert_equal true, r
         | 
| 134 | 
            +
              end
         | 
| 135 | 
            +
             | 
| 136 | 
            +
              def test_keys_should_be_string
         | 
| 137 | 
            +
             | 
| 138 | 
            +
                doc = { '_id' => 'h0', 'type' => 'errors', :m0 => :z, :m1 => [ :a, :b ] }
         | 
| 139 | 
            +
             | 
| 140 | 
            +
                @s.put(doc)
         | 
| 141 | 
            +
             | 
| 142 | 
            +
                doc = @s.get('errors', 'h0')
         | 
| 143 | 
            +
             | 
| 144 | 
            +
                assert_equal 'z', doc['m0']
         | 
| 145 | 
            +
                assert_equal %w[ a b ], doc['m1']
         | 
| 146 | 
            +
              end
         | 
| 147 | 
            +
             | 
| 148 | 
            +
              # Updating a gone document must result in a 'true' reply.
         | 
| 149 | 
            +
              #
         | 
| 150 | 
            +
              def test_put_gone
         | 
| 151 | 
            +
             | 
| 152 | 
            +
                h = @s.get('errors', 'toto')
         | 
| 153 | 
            +
             | 
| 154 | 
            +
                assert_nil @s.delete(h)
         | 
| 155 | 
            +
             | 
| 156 | 
            +
                h['colour'] = 'blue'
         | 
| 157 | 
            +
             | 
| 158 | 
            +
                assert_equal true, @s.put(h)
         | 
| 159 | 
            +
              end
         | 
| 160 | 
            +
             | 
| 161 | 
            +
              def test_purge_type
         | 
| 162 | 
            +
             | 
| 163 | 
            +
                @s.purge_type!('errors')
         | 
| 164 | 
            +
             | 
| 165 | 
            +
                assert_equal 0, @s.get_many('errors').size
         | 
| 166 | 
            +
              end
         | 
| 167 | 
            +
             | 
| 168 | 
            +
              def test_clear
         | 
| 169 | 
            +
             | 
| 170 | 
            +
                @s.clear
         | 
| 171 | 
            +
             | 
| 172 | 
            +
                assert_equal 0, @s.get_many('errors').size
         | 
| 173 | 
            +
              end
         | 
| 174 | 
            +
             | 
| 175 | 
            +
              #def test_purge
         | 
| 176 | 
            +
              #  @s.purge!
         | 
| 177 | 
            +
              #  assert_equal 0, @s.get_many('errors').size
         | 
| 178 | 
            +
              #end
         | 
| 179 | 
            +
             | 
| 180 | 
            +
              def test_ids
         | 
| 181 | 
            +
             | 
| 182 | 
            +
                @s.put('_id' => 't_ids0', 'type' => 'errors', 'message' => 'testing')
         | 
| 183 | 
            +
                @s.put('_id' => 't_ids1', 'type' => 'errors', 'message' => 'testing')
         | 
| 184 | 
            +
                @s.put('_id' => 't_ids2', 'type' => 'errors', 'message' => 'testing')
         | 
| 185 | 
            +
             | 
| 186 | 
            +
                assert_equal %w[ t_ids0 t_ids1 t_ids2 toto ], @s.ids('errors').sort
         | 
| 187 | 
            +
              end
         | 
| 188 | 
            +
             | 
| 189 | 
            +
              def test_get_many
         | 
| 190 | 
            +
             | 
| 191 | 
            +
                30.times do |i|
         | 
| 192 | 
            +
                  @s.put(
         | 
| 193 | 
            +
                    '_id' => "xx!#{i}",
         | 
| 194 | 
            +
                    'type' => 'errors',
         | 
| 195 | 
            +
                    'wfid' => i.to_s,
         | 
| 196 | 
            +
                    'msg' => "whatever #{i}")
         | 
| 197 | 
            +
                end
         | 
| 198 | 
            +
             | 
| 199 | 
            +
                assert_equal 31, @s.get_many('errors').size
         | 
| 200 | 
            +
                assert_equal 1, @s.get_many('errors', '7').size
         | 
| 201 | 
            +
                assert_equal 1, @s.get_many('errors', /!7$/).size
         | 
| 202 | 
            +
                assert_equal 30, @s.get_many('errors', /^xx!/).size
         | 
| 203 | 
            +
                assert_equal 30, @s.get_many('errors', /x/).size
         | 
| 204 | 
            +
                assert_equal 10, @s.get_many('errors', nil, :limit => 10).size
         | 
| 205 | 
            +
              end
         | 
| 206 | 
            +
             | 
| 207 | 
            +
              def load_30_errors
         | 
| 208 | 
            +
                30.times do |i|
         | 
| 209 | 
            +
                  @s.put(
         | 
| 210 | 
            +
                    '_id' => sprintf("yy!%0.2d", i),
         | 
| 211 | 
            +
                    'type' => 'errors',
         | 
| 212 | 
            +
                    'msg' => "whatever #{i}")
         | 
| 213 | 
            +
                end
         | 
| 214 | 
            +
              end
         | 
| 215 | 
            +
             | 
| 216 | 
            +
              def test_get_many_options
         | 
| 217 | 
            +
                load_30_errors
         | 
| 218 | 
            +
             | 
| 219 | 
            +
                # limit
         | 
| 220 | 
            +
             | 
| 221 | 
            +
                assert_equal 10, @s.get_many('errors', nil, :limit => 10).size
         | 
| 222 | 
            +
             | 
| 223 | 
            +
                # count
         | 
| 224 | 
            +
             | 
| 225 | 
            +
                assert_equal 31, @s.get_many('errors', nil, :count => true)
         | 
| 226 | 
            +
             | 
| 227 | 
            +
                # skip and limit
         | 
| 228 | 
            +
             | 
| 229 | 
            +
                assert_equal(
         | 
| 230 | 
            +
                  %w[ toto yy!00 yy!01 yy!02 ],
         | 
| 231 | 
            +
                  @s.get_many(
         | 
| 232 | 
            +
                    'errors', nil, :skip => 0, :limit => 4
         | 
| 233 | 
            +
                  ).collect { |d| d['_id'] })
         | 
| 234 | 
            +
                assert_equal(
         | 
| 235 | 
            +
                  %w[ yy!02 yy!03 yy!04 ],
         | 
| 236 | 
            +
                  @s.get_many(
         | 
| 237 | 
            +
                    'errors', nil, :skip => 3, :limit => 3
         | 
| 238 | 
            +
                  ).collect { |d| d['_id'] })
         | 
| 239 | 
            +
             | 
| 240 | 
            +
                # skip, limit and reverse
         | 
| 241 | 
            +
             | 
| 242 | 
            +
                assert_equal(
         | 
| 243 | 
            +
                  %w[ yy!29 yy!28 yy!27 ],
         | 
| 244 | 
            +
                  @s.get_many(
         | 
| 245 | 
            +
                    'errors', nil, :skip => 0, :limit => 3, :descending => true
         | 
| 246 | 
            +
                  ).collect { |d| d['_id'] })
         | 
| 247 | 
            +
                assert_equal(
         | 
| 248 | 
            +
                  %w[ yy!29 yy!28 yy!27 ],
         | 
| 249 | 
            +
                  @s.get_many(
         | 
| 250 | 
            +
                    'errors', nil, :skip => 0, :limit => 3, :descending => true
         | 
| 251 | 
            +
                  ).collect { |d| d['_id'] })
         | 
| 252 | 
            +
              end
         | 
| 253 | 
            +
             | 
| 254 | 
            +
            #  def test_dump
         | 
| 255 | 
            +
            #    load_30_errors
         | 
| 256 | 
            +
            #    assert @s.dump('errors').length > 0
         | 
| 257 | 
            +
            #  end
         | 
| 258 | 
            +
             | 
| 259 | 
            +
              def test_ids
         | 
| 260 | 
            +
                load_30_errors
         | 
| 261 | 
            +
                assert_equal 31, @s.ids('errors').length
         | 
| 262 | 
            +
              end
         | 
| 263 | 
            +
            end
         | 
| 264 | 
            +
             | 
    
        metadata
    ADDED
    
    | @@ -0,0 +1,149 @@ | |
| 1 | 
            +
            --- !ruby/object:Gem::Specification 
         | 
| 2 | 
            +
            name: ruote-mongodb
         | 
| 3 | 
            +
            version: !ruby/object:Gem::Version 
         | 
| 4 | 
            +
              hash: 27
         | 
| 5 | 
            +
              prerelease: false
         | 
| 6 | 
            +
              segments: 
         | 
| 7 | 
            +
              - 0
         | 
| 8 | 
            +
              - 1
         | 
| 9 | 
            +
              - 0
         | 
| 10 | 
            +
              version: 0.1.0
         | 
| 11 | 
            +
            platform: ruby
         | 
| 12 | 
            +
            authors: 
         | 
| 13 | 
            +
            - Patrick Gannon
         | 
| 14 | 
            +
            - Nathan Stults
         | 
| 15 | 
            +
            autorequire: 
         | 
| 16 | 
            +
            bindir: bin
         | 
| 17 | 
            +
            cert_chain: []
         | 
| 18 | 
            +
             | 
| 19 | 
            +
            date: 2010-12-10 00:00:00 -08:00
         | 
| 20 | 
            +
            default_executable: 
         | 
| 21 | 
            +
            dependencies: 
         | 
| 22 | 
            +
            - !ruby/object:Gem::Dependency 
         | 
| 23 | 
            +
              name: mongo
         | 
| 24 | 
            +
              prerelease: false
         | 
| 25 | 
            +
              requirement: &id001 !ruby/object:Gem::Requirement 
         | 
| 26 | 
            +
                none: false
         | 
| 27 | 
            +
                requirements: 
         | 
| 28 | 
            +
                - - ~>
         | 
| 29 | 
            +
                  - !ruby/object:Gem::Version 
         | 
| 30 | 
            +
                    hash: 17
         | 
| 31 | 
            +
                    segments: 
         | 
| 32 | 
            +
                    - 1
         | 
| 33 | 
            +
                    - 1
         | 
| 34 | 
            +
                    - 1
         | 
| 35 | 
            +
                    version: 1.1.1
         | 
| 36 | 
            +
              type: :runtime
         | 
| 37 | 
            +
              version_requirements: *id001
         | 
| 38 | 
            +
            - !ruby/object:Gem::Dependency 
         | 
| 39 | 
            +
              name: bson
         | 
| 40 | 
            +
              prerelease: false
         | 
| 41 | 
            +
              requirement: &id002 !ruby/object:Gem::Requirement 
         | 
| 42 | 
            +
                none: false
         | 
| 43 | 
            +
                requirements: 
         | 
| 44 | 
            +
                - - ~>
         | 
| 45 | 
            +
                  - !ruby/object:Gem::Version 
         | 
| 46 | 
            +
                    hash: 17
         | 
| 47 | 
            +
                    segments: 
         | 
| 48 | 
            +
                    - 1
         | 
| 49 | 
            +
                    - 1
         | 
| 50 | 
            +
                    - 1
         | 
| 51 | 
            +
                    version: 1.1.1
         | 
| 52 | 
            +
              type: :runtime
         | 
| 53 | 
            +
              version_requirements: *id002
         | 
| 54 | 
            +
            - !ruby/object:Gem::Dependency 
         | 
| 55 | 
            +
              name: bson_ext
         | 
| 56 | 
            +
              prerelease: false
         | 
| 57 | 
            +
              requirement: &id003 !ruby/object:Gem::Requirement 
         | 
| 58 | 
            +
                none: false
         | 
| 59 | 
            +
                requirements: 
         | 
| 60 | 
            +
                - - ~>
         | 
| 61 | 
            +
                  - !ruby/object:Gem::Version 
         | 
| 62 | 
            +
                    hash: 17
         | 
| 63 | 
            +
                    segments: 
         | 
| 64 | 
            +
                    - 1
         | 
| 65 | 
            +
                    - 1
         | 
| 66 | 
            +
                    - 1
         | 
| 67 | 
            +
                    version: 1.1.1
         | 
| 68 | 
            +
              type: :runtime
         | 
| 69 | 
            +
              version_requirements: *id003
         | 
| 70 | 
            +
            - !ruby/object:Gem::Dependency 
         | 
| 71 | 
            +
              name: rspec
         | 
| 72 | 
            +
              prerelease: false
         | 
| 73 | 
            +
              requirement: &id004 !ruby/object:Gem::Requirement 
         | 
| 74 | 
            +
                none: false
         | 
| 75 | 
            +
                requirements: 
         | 
| 76 | 
            +
                - - ">="
         | 
| 77 | 
            +
                  - !ruby/object:Gem::Version 
         | 
| 78 | 
            +
                    hash: 3
         | 
| 79 | 
            +
                    segments: 
         | 
| 80 | 
            +
                    - 0
         | 
| 81 | 
            +
                    version: "0"
         | 
| 82 | 
            +
              type: :development
         | 
| 83 | 
            +
              version_requirements: *id004
         | 
| 84 | 
            +
            - !ruby/object:Gem::Dependency 
         | 
| 85 | 
            +
              name: test-unit
         | 
| 86 | 
            +
              prerelease: false
         | 
| 87 | 
            +
              requirement: &id005 !ruby/object:Gem::Requirement 
         | 
| 88 | 
            +
                none: false
         | 
| 89 | 
            +
                requirements: 
         | 
| 90 | 
            +
                - - ">="
         | 
| 91 | 
            +
                  - !ruby/object:Gem::Version 
         | 
| 92 | 
            +
                    hash: 3
         | 
| 93 | 
            +
                    segments: 
         | 
| 94 | 
            +
                    - 0
         | 
| 95 | 
            +
                    version: "0"
         | 
| 96 | 
            +
              type: :development
         | 
| 97 | 
            +
              version_requirements: *id005
         | 
| 98 | 
            +
            description: 
         | 
| 99 | 
            +
            email: 
         | 
| 100 | 
            +
            - hereiam@sonic.net
         | 
| 101 | 
            +
            executables: []
         | 
| 102 | 
            +
             | 
| 103 | 
            +
            extensions: []
         | 
| 104 | 
            +
             | 
| 105 | 
            +
            extra_rdoc_files: []
         | 
| 106 | 
            +
             | 
| 107 | 
            +
            files: 
         | 
| 108 | 
            +
            - lib/ruote-mongodb.rb
         | 
| 109 | 
            +
            - lib/ruote-mongodb/mongodb_storage.rb
         | 
| 110 | 
            +
            - test/test_storage.rb
         | 
| 111 | 
            +
            - spec/mongodb_storage_spec.rb
         | 
| 112 | 
            +
            - LICENSE
         | 
| 113 | 
            +
            - README
         | 
| 114 | 
            +
            has_rdoc: true
         | 
| 115 | 
            +
            homepage: http://github.com/PlasticLizard/ruote-mongodb
         | 
| 116 | 
            +
            licenses: []
         | 
| 117 | 
            +
             | 
| 118 | 
            +
            post_install_message: 
         | 
| 119 | 
            +
            rdoc_options: []
         | 
| 120 | 
            +
             | 
| 121 | 
            +
            require_paths: 
         | 
| 122 | 
            +
            - lib
         | 
| 123 | 
            +
            required_ruby_version: !ruby/object:Gem::Requirement 
         | 
| 124 | 
            +
              none: false
         | 
| 125 | 
            +
              requirements: 
         | 
| 126 | 
            +
              - - ">="
         | 
| 127 | 
            +
                - !ruby/object:Gem::Version 
         | 
| 128 | 
            +
                  hash: 3
         | 
| 129 | 
            +
                  segments: 
         | 
| 130 | 
            +
                  - 0
         | 
| 131 | 
            +
                  version: "0"
         | 
| 132 | 
            +
            required_rubygems_version: !ruby/object:Gem::Requirement 
         | 
| 133 | 
            +
              none: false
         | 
| 134 | 
            +
              requirements: 
         | 
| 135 | 
            +
              - - ">="
         | 
| 136 | 
            +
                - !ruby/object:Gem::Version 
         | 
| 137 | 
            +
                  hash: 3
         | 
| 138 | 
            +
                  segments: 
         | 
| 139 | 
            +
                  - 0
         | 
| 140 | 
            +
                  version: "0"
         | 
| 141 | 
            +
            requirements: []
         | 
| 142 | 
            +
             | 
| 143 | 
            +
            rubyforge_project: 
         | 
| 144 | 
            +
            rubygems_version: 1.3.7
         | 
| 145 | 
            +
            signing_key: 
         | 
| 146 | 
            +
            specification_version: 3
         | 
| 147 | 
            +
            summary: MongoDB persistence for Ruote
         | 
| 148 | 
            +
            test_files: []
         | 
| 149 | 
            +
             |