mongomapper_ext 0.0.4
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/.document +5 -0
- data/.gitignore +21 -0
- data/LICENSE +20 -0
- data/README.rdoc +19 -0
- data/Rakefile +59 -0
- data/VERSION +1 -0
- data/examples/filter.rb +23 -0
- data/examples/helper.rb +6 -0
- data/examples/slugizer.rb +15 -0
- data/examples/storage.rb +22 -0
- data/examples/types.rb +32 -0
- data/examples/update.rb +14 -0
- data/lib/mongomapper_ext/file.rb +35 -0
- data/lib/mongomapper_ext/filter.rb +76 -0
- data/lib/mongomapper_ext/slugizer.rb +46 -0
- data/lib/mongomapper_ext/storage.rb +73 -0
- data/lib/mongomapper_ext/types/open_struct.rb +19 -0
- data/lib/mongomapper_ext/types/set.rb +9 -0
- data/lib/mongomapper_ext/types/timestamp.rb +15 -0
- data/lib/mongomapper_ext/update.rb +10 -0
- data/lib/mongomapper_ext.rb +23 -0
- data/test/helper.rb +23 -0
- data/test/models.rb +52 -0
- data/test/support/custom_matchers.rb +55 -0
- data/test/test_filter.rb +43 -0
- data/test/test_slugizer.rb +40 -0
- data/test/test_storage.rb +64 -0
- data/test/test_update.rb +16 -0
- data/test/types/test_open_struct.rb +19 -0
- data/test/types/test_set.rb +26 -0
- data/test/types/test_timestamp.rb +40 -0
- metadata +160 -0
    
        data/.document
    ADDED
    
    
    
        data/.gitignore
    ADDED
    
    
    
        data/LICENSE
    ADDED
    
    | @@ -0,0 +1,20 @@ | |
| 1 | 
            +
            Copyright (c) 2009 David A. Cuadrado
         | 
| 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.rdoc
    ADDED
    
    | @@ -0,0 +1,19 @@ | |
| 1 | 
            +
            = mongomapper_ext
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            MongoMapper extensions.
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            == Note on Patches/Pull Requests
         | 
| 6 | 
            +
             
         | 
| 7 | 
            +
            * Fork the project.
         | 
| 8 | 
            +
            * Make your feature addition or bug fix.
         | 
| 9 | 
            +
            * Add tests for it. This is important so I don't break it in a
         | 
| 10 | 
            +
              future version unintentionally.
         | 
| 11 | 
            +
            * Commit, do not mess with rakefile, version, or history.
         | 
| 12 | 
            +
              (if you want to have your own version, that is fine but
         | 
| 13 | 
            +
               bump version in a commit by itself I can ignore when I pull)
         | 
| 14 | 
            +
            * Send me a pull request. Bonus points for topic branches.
         | 
| 15 | 
            +
             | 
| 16 | 
            +
            == Copyright
         | 
| 17 | 
            +
             | 
| 18 | 
            +
            Copyright (c) 2009 David A. Cuadrado. See LICENSE for details.
         | 
| 19 | 
            +
             | 
    
        data/Rakefile
    ADDED
    
    | @@ -0,0 +1,59 @@ | |
| 1 | 
            +
            require 'rubygems'
         | 
| 2 | 
            +
            require 'rake'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            begin
         | 
| 5 | 
            +
              require 'jeweler'
         | 
| 6 | 
            +
              Jeweler::Tasks.new do |gem|
         | 
| 7 | 
            +
                gem.name = "mongomapper_ext"
         | 
| 8 | 
            +
                gem.summary = %Q{MongoMapper extensions}
         | 
| 9 | 
            +
                gem.description = %Q{MongoMapper extensions}
         | 
| 10 | 
            +
                gem.email = "krawek@gmail.com"
         | 
| 11 | 
            +
                gem.homepage = "http://github.com/dcu/mongomapper_ext"
         | 
| 12 | 
            +
                gem.authors = ["David A. Cuadrado"]
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                gem.add_dependency('mongo_mapper', '>= 0.5.6')
         | 
| 15 | 
            +
                gem.add_dependency('ruby-stemmer', '>= 0.5.3')
         | 
| 16 | 
            +
                gem.add_dependency('uuidtools', '>= 2.0.0')
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                gem.add_development_dependency("shoulda", ">= 2.10.2")
         | 
| 19 | 
            +
                gem.add_development_dependency('jnunemaker-matchy', '0.4.0')
         | 
| 20 | 
            +
                gem.add_development_dependency('mocha', '>= 0.9.4')
         | 
| 21 | 
            +
              end
         | 
| 22 | 
            +
            rescue LoadError
         | 
| 23 | 
            +
              puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
         | 
| 24 | 
            +
            end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
            require 'rake/testtask'
         | 
| 27 | 
            +
            Rake::TestTask.new(:test) do |test|
         | 
| 28 | 
            +
              test.libs << 'lib' << 'test'
         | 
| 29 | 
            +
              test.pattern = 'test/**/test_*.rb'
         | 
| 30 | 
            +
              test.verbose = true
         | 
| 31 | 
            +
            end
         | 
| 32 | 
            +
             | 
| 33 | 
            +
            begin
         | 
| 34 | 
            +
              require 'rcov/rcovtask'
         | 
| 35 | 
            +
              Rcov::RcovTask.new do |test|
         | 
| 36 | 
            +
                test.libs << 'test'
         | 
| 37 | 
            +
                test.pattern = 'test/**/test_*.rb'
         | 
| 38 | 
            +
                test.verbose = true
         | 
| 39 | 
            +
              end
         | 
| 40 | 
            +
            rescue LoadError
         | 
| 41 | 
            +
              task :rcov do
         | 
| 42 | 
            +
                abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
         | 
| 43 | 
            +
              end
         | 
| 44 | 
            +
            end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
            task :test => :check_dependencies
         | 
| 47 | 
            +
             | 
| 48 | 
            +
            task :default => :test
         | 
| 49 | 
            +
             | 
| 50 | 
            +
            require 'rake/rdoctask'
         | 
| 51 | 
            +
            Rake::RDocTask.new do |rdoc|
         | 
| 52 | 
            +
              version = File.exist?('VERSION') ? File.read('VERSION') : ""
         | 
| 53 | 
            +
             | 
| 54 | 
            +
              rdoc.rdoc_dir = 'rdoc'
         | 
| 55 | 
            +
              rdoc.title = "mongomapper_ext #{version}"
         | 
| 56 | 
            +
              rdoc.rdoc_files.include('README*')
         | 
| 57 | 
            +
              rdoc.rdoc_files.include('lib/**/*.rb')
         | 
| 58 | 
            +
            end
         | 
| 59 | 
            +
             | 
    
        data/VERSION
    ADDED
    
    | @@ -0,0 +1 @@ | |
| 1 | 
            +
            0.0.4
         | 
    
        data/examples/filter.rb
    ADDED
    
    | @@ -0,0 +1,23 @@ | |
| 1 | 
            +
            require './helper'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            class FilterEx
         | 
| 4 | 
            +
              include MongoMapper::Document
         | 
| 5 | 
            +
              include MongoMapperExt::Filter
         | 
| 6 | 
            +
             | 
| 7 | 
            +
              key :title, String
         | 
| 8 | 
            +
              key :body, String
         | 
| 9 | 
            +
             | 
| 10 | 
            +
              filterable_keys :title, :body
         | 
| 11 | 
            +
            end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            FilterEx.delete_all
         | 
| 14 | 
            +
            o1 = FilterEx.create(:title => "A Great Title", :body => "A great Body")
         | 
| 15 | 
            +
            o2 = FilterEx.create(:title => "A Good Title", :body => "A good Body")
         | 
| 16 | 
            +
             | 
| 17 | 
            +
             | 
| 18 | 
            +
            puts "filter: #{FilterEx.filter("title").size}"
         | 
| 19 | 
            +
            puts "filter: #{FilterEx.filter("title", :limit => 1).inspect}"
         | 
| 20 | 
            +
            puts "filter: #{FilterEx.filter("great").inspect}"
         | 
| 21 | 
            +
             | 
| 22 | 
            +
             | 
| 23 | 
            +
            FilterEx.delete_all
         | 
    
        data/examples/helper.rb
    ADDED
    
    
| @@ -0,0 +1,15 @@ | |
| 1 | 
            +
            require './helper'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            class SlugizerEx
         | 
| 4 | 
            +
              include MongoMapper::Document
         | 
| 5 | 
            +
              include MongoMapperExt::Slugizer
         | 
| 6 | 
            +
             | 
| 7 | 
            +
              slug_key :title
         | 
| 8 | 
            +
             | 
| 9 | 
            +
              key :title
         | 
| 10 | 
            +
            end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
            u = SlugizerEx.create(:title => "The title of the blogpost!!!")
         | 
| 13 | 
            +
             | 
| 14 | 
            +
            puts u.slug
         | 
| 15 | 
            +
            puts SlugizerEx.by_slug(u.slug).inspect
         | 
    
        data/examples/storage.rb
    ADDED
    
    | @@ -0,0 +1,22 @@ | |
| 1 | 
            +
            require './helper'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            class StorageEx
         | 
| 4 | 
            +
              include MongoMapper::Document
         | 
| 5 | 
            +
              include MongoMapperExt::Storage
         | 
| 6 | 
            +
             | 
| 7 | 
            +
              file_key :my_file
         | 
| 8 | 
            +
            end
         | 
| 9 | 
            +
             | 
| 10 | 
            +
            file = StringIO.new("file content")
         | 
| 11 | 
            +
            file2 = StringIO.new("file content 2")
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            s = StorageEx.new
         | 
| 14 | 
            +
            s.put_file("filename.txt", file)
         | 
| 15 | 
            +
            s.my_file = file2
         | 
| 16 | 
            +
             | 
| 17 | 
            +
            s.save
         | 
| 18 | 
            +
             | 
| 19 | 
            +
            from_db = StorageEx.find(s.id)
         | 
| 20 | 
            +
             | 
| 21 | 
            +
            puts from_db.fetch_file("filename.txt").read
         | 
| 22 | 
            +
            puts from_db.my_file.read
         | 
    
        data/examples/types.rb
    ADDED
    
    | @@ -0,0 +1,32 @@ | |
| 1 | 
            +
            require './helper'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            class TypeEx
         | 
| 4 | 
            +
              include MongoMapper::Document
         | 
| 5 | 
            +
             | 
| 6 | 
            +
              key :time, Timestamp
         | 
| 7 | 
            +
              key :config, OpenStruct
         | 
| 8 | 
            +
              key :set, Set
         | 
| 9 | 
            +
            end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
             | 
| 12 | 
            +
            type = TypeEx.new(:set => Set.new, :config => OpenStruct.new)
         | 
| 13 | 
            +
             | 
| 14 | 
            +
            type.config.name = "Alan"
         | 
| 15 | 
            +
            type.config.last_name = "Turing"
         | 
| 16 | 
            +
             | 
| 17 | 
            +
             | 
| 18 | 
            +
            type.time = Time.now
         | 
| 19 | 
            +
            type.set += [1,1,2,3,2,2]
         | 
| 20 | 
            +
             | 
| 21 | 
            +
            type.save
         | 
| 22 | 
            +
             | 
| 23 | 
            +
            from_db = TypeEx.find(type.id)
         | 
| 24 | 
            +
             | 
| 25 | 
            +
            puts from_db.config.inspect
         | 
| 26 | 
            +
            puts from_db.set.inspect
         | 
| 27 | 
            +
             | 
| 28 | 
            +
            Time.zone = "Hawaii"
         | 
| 29 | 
            +
            puts from_db.time.inspect
         | 
| 30 | 
            +
             | 
| 31 | 
            +
            from_db.destroy
         | 
| 32 | 
            +
             | 
    
        data/examples/update.rb
    ADDED
    
    
| @@ -0,0 +1,35 @@ | |
| 1 | 
            +
            module MongoMapperExt
         | 
| 2 | 
            +
              class File < GridFS::GridStore
         | 
| 3 | 
            +
                attr_reader :id, :attributes
         | 
| 4 | 
            +
             | 
| 5 | 
            +
                def initialize(owner, attrs = {})
         | 
| 6 | 
            +
                  @owner = owner
         | 
| 7 | 
            +
                  @id = attrs.delete("_id")
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                  class_eval do
         | 
| 10 | 
            +
                    attrs.each do |k,v|
         | 
| 11 | 
            +
                      define_method(k) do
         | 
| 12 | 
            +
                        v
         | 
| 13 | 
            +
                      end
         | 
| 14 | 
            +
                    end
         | 
| 15 | 
            +
                  end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                  super(@owner.class.database, attrs["filename"], "r", :root => @owner.collection.name)
         | 
| 18 | 
            +
                end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                def [](name)
         | 
| 21 | 
            +
                  @attributes[name.to_s]
         | 
| 22 | 
            +
                end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                def self.fetch(owner, filename)
         | 
| 25 | 
            +
                  db = owner.class.database
         | 
| 26 | 
            +
                  criteria, options = MongoMapper::FinderOptions.new(owner.class, :filename => filename, :metadata => {:_id => owner.id}, :limit => 1).to_a
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                  obj = db.collection("#{owner.collection.name}.files").find(criteria, options).next_object
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                  if obj
         | 
| 31 | 
            +
                    self.new(owner, obj)
         | 
| 32 | 
            +
                  end
         | 
| 33 | 
            +
                end
         | 
| 34 | 
            +
              end
         | 
| 35 | 
            +
            end
         | 
| @@ -0,0 +1,76 @@ | |
| 1 | 
            +
            module MongoMapperExt
         | 
| 2 | 
            +
              module Filter
         | 
| 3 | 
            +
                def self.included(klass)
         | 
| 4 | 
            +
                  require 'lingua/stemmer'
         | 
| 5 | 
            +
             | 
| 6 | 
            +
                  klass.class_eval do
         | 
| 7 | 
            +
                    extend ClassMethods
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                    key :_keywords, Array
         | 
| 10 | 
            +
                    ensure_index :_keywords
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                    before_save :_update_keywords
         | 
| 13 | 
            +
                  end
         | 
| 14 | 
            +
                end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                module ClassMethods
         | 
| 17 | 
            +
                  def filterable_keys(*keys)
         | 
| 18 | 
            +
                    @filterable_keys ||= Set.new
         | 
| 19 | 
            +
                    @filterable_keys += keys
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                    @filterable_keys
         | 
| 22 | 
            +
                  end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                  def language(lang = 'en')
         | 
| 25 | 
            +
                    @language ||= lang
         | 
| 26 | 
            +
                  end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                  def filter(query, opts = {})
         | 
| 29 | 
            +
                    q = query.downcase.split.map do |k|
         | 
| 30 | 
            +
                      Regexp.escape(k)
         | 
| 31 | 
            +
                    end.join("|")
         | 
| 32 | 
            +
                    if opts[:per_page]
         | 
| 33 | 
            +
                      self.paginate(opts.deep_merge(:conditions => {:_keywords => /^(#{q}).*/ }))
         | 
| 34 | 
            +
                    else
         | 
| 35 | 
            +
                      self.find(:all, opts.deep_merge(:conditions => {:_keywords => /^(#{q}).*/ }))
         | 
| 36 | 
            +
                    end
         | 
| 37 | 
            +
                  end
         | 
| 38 | 
            +
                end
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                protected
         | 
| 41 | 
            +
                def _update_keywords
         | 
| 42 | 
            +
                  lang = self.class.language
         | 
| 43 | 
            +
                  if lang.kind_of?(Symbol)
         | 
| 44 | 
            +
                    lang = send(lang)
         | 
| 45 | 
            +
                  elsif lang.kind_of?(Proc)
         | 
| 46 | 
            +
                    lang = lang.call(self)
         | 
| 47 | 
            +
                  end
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                  s = Lingua::Stemmer.new(:language => lang)
         | 
| 50 | 
            +
             | 
| 51 | 
            +
                  self._keywords = []
         | 
| 52 | 
            +
                  self.class.filterable_keys.each do |key|
         | 
| 53 | 
            +
                    self._keywords += keywords_for_value(s, read_attribute(key))
         | 
| 54 | 
            +
                  end
         | 
| 55 | 
            +
                end
         | 
| 56 | 
            +
             | 
| 57 | 
            +
                private
         | 
| 58 | 
            +
                def keywords_for_value(stemmer, val)
         | 
| 59 | 
            +
                  if val.kind_of?(String)
         | 
| 60 | 
            +
                    val.downcase.split.map do |word|
         | 
| 61 | 
            +
                      stem = stemmer.stem(word)
         | 
| 62 | 
            +
                      if stem != word
         | 
| 63 | 
            +
                        [stem, word]
         | 
| 64 | 
            +
                      else
         | 
| 65 | 
            +
                        word
         | 
| 66 | 
            +
                      end
         | 
| 67 | 
            +
                    end.flatten
         | 
| 68 | 
            +
                  elsif val.kind_of?(Array)
         | 
| 69 | 
            +
                    val.map { |e| keywords_for_value(stemmer, e) }.flatten
         | 
| 70 | 
            +
                  else
         | 
| 71 | 
            +
                    [val]
         | 
| 72 | 
            +
                  end
         | 
| 73 | 
            +
                end
         | 
| 74 | 
            +
              end
         | 
| 75 | 
            +
            end
         | 
| 76 | 
            +
             | 
| @@ -0,0 +1,46 @@ | |
| 1 | 
            +
            module MongoMapperExt
         | 
| 2 | 
            +
              module Slugizer
         | 
| 3 | 
            +
                def self.included(klass)
         | 
| 4 | 
            +
                  klass.class_eval do
         | 
| 5 | 
            +
                    extend ClassMethods
         | 
| 6 | 
            +
                    extend Finder
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                    key :slug, String
         | 
| 9 | 
            +
                    ensure_index :slug
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                    before_validation_on_create :generate_slug
         | 
| 12 | 
            +
                  end
         | 
| 13 | 
            +
                end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                def to_param
         | 
| 16 | 
            +
                  if self.slug.blank?
         | 
| 17 | 
            +
                    self.id
         | 
| 18 | 
            +
                  else
         | 
| 19 | 
            +
                    self.slug
         | 
| 20 | 
            +
                  end
         | 
| 21 | 
            +
                end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                protected
         | 
| 24 | 
            +
                def generate_slug
         | 
| 25 | 
            +
                  if self.slug.blank?
         | 
| 26 | 
            +
                    key = UUIDTools::UUID.random_create.hexdigest[0,4] #optimize
         | 
| 27 | 
            +
                    self.slug = key+"-"+self[self.class.slug_key].gsub(/[^A-Za-z0-9\s\-]/, "")[0,20].strip.gsub(/\s+/, "-").downcase
         | 
| 28 | 
            +
                  end
         | 
| 29 | 
            +
                end
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                module ClassMethods
         | 
| 32 | 
            +
                  def slug_key(key = :name)
         | 
| 33 | 
            +
                    @slug_key ||= key
         | 
| 34 | 
            +
                  end
         | 
| 35 | 
            +
                end
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                module Finder
         | 
| 38 | 
            +
                  def by_slug(id)
         | 
| 39 | 
            +
                    self.find_by_slug(id) || self.find_by_id(id)
         | 
| 40 | 
            +
                  end
         | 
| 41 | 
            +
                  alias :find_by_slug_or_id :by_slug
         | 
| 42 | 
            +
                end
         | 
| 43 | 
            +
              end
         | 
| 44 | 
            +
            end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
            MongoMapper::Associations::Proxy.send(:include, MongoMapperExt::Slugizer::Finder)
         | 
| @@ -0,0 +1,73 @@ | |
| 1 | 
            +
            module MongoMapperExt
         | 
| 2 | 
            +
              module Storage
         | 
| 3 | 
            +
                def self.included(model)
         | 
| 4 | 
            +
                  model.class_eval do
         | 
| 5 | 
            +
                    extend ClassMethods
         | 
| 6 | 
            +
                    after_create :_sync_pending_files
         | 
| 7 | 
            +
                  end
         | 
| 8 | 
            +
                end
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                # FIXME: enable metadata. re http://jira.mongodb.org/browse/SERVER-377
         | 
| 11 | 
            +
                def put_file(filename, io, metadata = {})
         | 
| 12 | 
            +
                  if !new?
         | 
| 13 | 
            +
                    # :metadata => metadata.deep_merge({:_id => self.id})
         | 
| 14 | 
            +
                    GridFS::GridStore.open(self.class.database, filename, "w",
         | 
| 15 | 
            +
                                           :root => self.collection.name,
         | 
| 16 | 
            +
                                           :metadata => {:_id => self.id}) do |f|
         | 
| 17 | 
            +
                      while data = io.read(256)
         | 
| 18 | 
            +
                        f.write(data)
         | 
| 19 | 
            +
                      end
         | 
| 20 | 
            +
                      io.close
         | 
| 21 | 
            +
                    end
         | 
| 22 | 
            +
                  else
         | 
| 23 | 
            +
                    (@_pending_files ||= {})[filename] = io
         | 
| 24 | 
            +
                  end
         | 
| 25 | 
            +
                end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                def fetch_file(filename)
         | 
| 28 | 
            +
                  if !new?
         | 
| 29 | 
            +
                    MongoMapperExt::File.fetch(self, filename)
         | 
| 30 | 
            +
                  end
         | 
| 31 | 
            +
                end
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                def files
         | 
| 34 | 
            +
                  criteria, options = MongoMapper::FinderOptions.new(self.class, :metadata => {:_id => self.id}).to_a
         | 
| 35 | 
            +
                  coll = self.class.database.collection("#{self.collection.name}.files")
         | 
| 36 | 
            +
                  @files = coll.find(criteria, options).map do |a|
         | 
| 37 | 
            +
                    MongoMapperExt::File.new(self, a)
         | 
| 38 | 
            +
                  end
         | 
| 39 | 
            +
                end
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                protected
         | 
| 42 | 
            +
                def _sync_pending_files
         | 
| 43 | 
            +
                  if @_pending_files
         | 
| 44 | 
            +
                    @_pending_files.each do |filename, data|
         | 
| 45 | 
            +
                      put_file(filename, data)
         | 
| 46 | 
            +
                    end
         | 
| 47 | 
            +
                    @_pending_files = nil
         | 
| 48 | 
            +
                  end
         | 
| 49 | 
            +
                end
         | 
| 50 | 
            +
             | 
| 51 | 
            +
                module ClassMethods
         | 
| 52 | 
            +
                  def file_key(name)
         | 
| 53 | 
            +
                    define_method("#{name}=") do |file|
         | 
| 54 | 
            +
                      file_id = UUIDTools::UUID.random_create.hexdigest
         | 
| 55 | 
            +
                      filename = name
         | 
| 56 | 
            +
             | 
| 57 | 
            +
                      if file.respond_to?(:original_filename)
         | 
| 58 | 
            +
                        filename = file.original_filename
         | 
| 59 | 
            +
                      elsif file.respond_to?(:path)
         | 
| 60 | 
            +
                        filename = file.path
         | 
| 61 | 
            +
                      end
         | 
| 62 | 
            +
             | 
| 63 | 
            +
                      put_file(file_id, file, :original_filename => filename)
         | 
| 64 | 
            +
                      self["_#{name}"] = file_id
         | 
| 65 | 
            +
                    end
         | 
| 66 | 
            +
             | 
| 67 | 
            +
                    define_method(name) do
         | 
| 68 | 
            +
                      fetch_file(self["_#{name}"])
         | 
| 69 | 
            +
                    end
         | 
| 70 | 
            +
                  end
         | 
| 71 | 
            +
                end
         | 
| 72 | 
            +
              end
         | 
| 73 | 
            +
            end
         | 
| @@ -0,0 +1,19 @@ | |
| 1 | 
            +
            require 'ostruct'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            class OpenStruct
         | 
| 4 | 
            +
              def self.to_mongo(value)
         | 
| 5 | 
            +
                if value.kind_of?(self)
         | 
| 6 | 
            +
                  value.send(:table)
         | 
| 7 | 
            +
                else
         | 
| 8 | 
            +
                  value
         | 
| 9 | 
            +
                end
         | 
| 10 | 
            +
              end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
              def self.from_mongo(value)
         | 
| 13 | 
            +
                if value.kind_of?(self)
         | 
| 14 | 
            +
                  value
         | 
| 15 | 
            +
                else
         | 
| 16 | 
            +
                  OpenStruct.new(value || {})
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
              end
         | 
| 19 | 
            +
            end
         | 
| @@ -0,0 +1,23 @@ | |
| 1 | 
            +
            $:.unshift File.dirname(__FILE__)
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require 'mongo/gridfs'
         | 
| 4 | 
            +
            require 'mongo_mapper'
         | 
| 5 | 
            +
            require 'uuidtools'
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            # types
         | 
| 8 | 
            +
            require 'mongomapper_ext/types/open_struct'
         | 
| 9 | 
            +
            require 'mongomapper_ext/types/timestamp'
         | 
| 10 | 
            +
            require 'mongomapper_ext/types/set'
         | 
| 11 | 
            +
             | 
| 12 | 
            +
            # storage
         | 
| 13 | 
            +
            require 'mongomapper_ext/file'
         | 
| 14 | 
            +
            require 'mongomapper_ext/storage'
         | 
| 15 | 
            +
             | 
| 16 | 
            +
            # update
         | 
| 17 | 
            +
            require 'mongomapper_ext/update'
         | 
| 18 | 
            +
             | 
| 19 | 
            +
            # filter
         | 
| 20 | 
            +
            require 'mongomapper_ext/filter'
         | 
| 21 | 
            +
             | 
| 22 | 
            +
            # slug
         | 
| 23 | 
            +
            require 'mongomapper_ext/slugizer'
         | 
    
        data/test/helper.rb
    ADDED
    
    | @@ -0,0 +1,23 @@ | |
| 1 | 
            +
            require 'rubygems'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            gem 'jnunemaker-matchy'
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            require 'matchy'
         | 
| 6 | 
            +
            require 'shoulda'
         | 
| 7 | 
            +
            require 'timecop'
         | 
| 8 | 
            +
            require 'mocha'
         | 
| 9 | 
            +
            require 'pp'
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            require 'support/custom_matchers'
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
         | 
| 14 | 
            +
            $LOAD_PATH.unshift(File.dirname(__FILE__))
         | 
| 15 | 
            +
             | 
| 16 | 
            +
            require 'mongomapper_ext'
         | 
| 17 | 
            +
            require 'models'
         | 
| 18 | 
            +
             | 
| 19 | 
            +
            class Test::Unit::TestCase
         | 
| 20 | 
            +
              include CustomMatchers
         | 
| 21 | 
            +
            end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
            MongoMapper.database = 'test'
         | 
    
        data/test/models.rb
    ADDED
    
    | @@ -0,0 +1,52 @@ | |
| 1 | 
            +
             | 
| 2 | 
            +
            class Event # for safe_update, and Timestamp
         | 
| 3 | 
            +
              include MongoMapper::Document
         | 
| 4 | 
            +
             | 
| 5 | 
            +
              key :start_date, Timestamp
         | 
| 6 | 
            +
              key :end_date, Timestamp
         | 
| 7 | 
            +
             | 
| 8 | 
            +
              key :password, String
         | 
| 9 | 
            +
            end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            class Recipe # for Set
         | 
| 12 | 
            +
              include MongoMapper::Document
         | 
| 13 | 
            +
              include MongoMapperExt::Filter
         | 
| 14 | 
            +
             | 
| 15 | 
            +
              language Proc.new { |d| d.language }
         | 
| 16 | 
            +
              filterable_keys :language
         | 
| 17 | 
            +
             | 
| 18 | 
            +
              key :ingredients, Set
         | 
| 19 | 
            +
              key :description, String
         | 
| 20 | 
            +
              key :language, String, :default => 'en'
         | 
| 21 | 
            +
            end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
            class Avatar # for Storage and File
         | 
| 24 | 
            +
              include MongoMapper::Document
         | 
| 25 | 
            +
              include MongoMapperExt::Storage
         | 
| 26 | 
            +
             | 
| 27 | 
            +
              file_key :data
         | 
| 28 | 
            +
            end
         | 
| 29 | 
            +
             | 
| 30 | 
            +
            class UserConfig #for OpenStruct
         | 
| 31 | 
            +
              include MongoMapper::Document
         | 
| 32 | 
            +
              key :entries, OpenStruct
         | 
| 33 | 
            +
            end
         | 
| 34 | 
            +
             | 
| 35 | 
            +
            class BlogPost # for Slug and Filter
         | 
| 36 | 
            +
              include MongoMapper::Document
         | 
| 37 | 
            +
              include MongoMapperExt::Filter
         | 
| 38 | 
            +
              include MongoMapperExt::Slugizer
         | 
| 39 | 
            +
             | 
| 40 | 
            +
              filterable_keys :title, :body, :tags, :date
         | 
| 41 | 
            +
              slug_key :title
         | 
| 42 | 
            +
              language :find_language
         | 
| 43 | 
            +
             | 
| 44 | 
            +
              key :title, String
         | 
| 45 | 
            +
              key :body, String
         | 
| 46 | 
            +
              key :tags, Array
         | 
| 47 | 
            +
              key :date, Time
         | 
| 48 | 
            +
             | 
| 49 | 
            +
              def find_language
         | 
| 50 | 
            +
                'en'
         | 
| 51 | 
            +
              end
         | 
| 52 | 
            +
            end
         | 
| @@ -0,0 +1,55 @@ | |
| 1 | 
            +
            module CustomMatchers
         | 
| 2 | 
            +
              custom_matcher :be_nil do |receiver, matcher, args|
         | 
| 3 | 
            +
                matcher.positive_failure_message = "Expected #{receiver} to be nil but it wasn't"
         | 
| 4 | 
            +
                matcher.negative_failure_message = "Expected #{receiver} not to be nil but it was"
         | 
| 5 | 
            +
                receiver.nil?
         | 
| 6 | 
            +
              end
         | 
| 7 | 
            +
              
         | 
| 8 | 
            +
              custom_matcher :be_blank do |receiver, matcher, args|
         | 
| 9 | 
            +
                matcher.positive_failure_message = "Expected #{receiver} to be blank but it wasn't"
         | 
| 10 | 
            +
                matcher.negative_failure_message = "Expected #{receiver} not to be blank but it was"
         | 
| 11 | 
            +
                receiver.blank?
         | 
| 12 | 
            +
              end
         | 
| 13 | 
            +
              
         | 
| 14 | 
            +
              custom_matcher :be_true do |receiver, matcher, args|
         | 
| 15 | 
            +
                matcher.positive_failure_message = "Expected #{receiver} to be true but it wasn't"
         | 
| 16 | 
            +
                matcher.negative_failure_message = "Expected #{receiver} not to be true but it was"
         | 
| 17 | 
            +
                receiver.eql?(true)
         | 
| 18 | 
            +
              end
         | 
| 19 | 
            +
              
         | 
| 20 | 
            +
              custom_matcher :be_false do |receiver, matcher, args|
         | 
| 21 | 
            +
                matcher.positive_failure_message = "Expected #{receiver} to be false but it wasn't"
         | 
| 22 | 
            +
                matcher.negative_failure_message = "Expected #{receiver} not to be false but it was"
         | 
| 23 | 
            +
                receiver.eql?(false)
         | 
| 24 | 
            +
              end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
              custom_matcher :be_valid do |receiver, matcher, args|
         | 
| 27 | 
            +
                matcher.positive_failure_message = "Expected to be valid but it was invalid #{receiver.errors.inspect}"
         | 
| 28 | 
            +
                matcher.negative_failure_message = "Expected to be invalid but it was valid #{receiver.errors.inspect}"
         | 
| 29 | 
            +
                receiver.valid?
         | 
| 30 | 
            +
              end
         | 
| 31 | 
            +
             | 
| 32 | 
            +
              custom_matcher :have_error_on do |receiver, matcher, args|
         | 
| 33 | 
            +
                receiver.valid?
         | 
| 34 | 
            +
                attribute = args[0]
         | 
| 35 | 
            +
                expected_message = args[1]
         | 
| 36 | 
            +
                
         | 
| 37 | 
            +
                if expected_message.nil?
         | 
| 38 | 
            +
                  matcher.positive_failure_message = "#{receiver} had no errors on #{attribute}"
         | 
| 39 | 
            +
                  matcher.negative_failure_message = "#{receiver} had errors on #{attribute} #{receiver.errors.inspect}"
         | 
| 40 | 
            +
                  !receiver.errors.on(attribute).blank?
         | 
| 41 | 
            +
                else
         | 
| 42 | 
            +
                  actual = receiver.errors.on(attribute)
         | 
| 43 | 
            +
                  matcher.positive_failure_message = %Q(Expected error on #{attribute} to be "#{expected_message}" but was "#{actual}")
         | 
| 44 | 
            +
                  matcher.negative_failure_message = %Q(Expected error on #{attribute} not to be "#{expected_message}" but was "#{actual}")
         | 
| 45 | 
            +
                  actual == expected_message
         | 
| 46 | 
            +
                end
         | 
| 47 | 
            +
              end
         | 
| 48 | 
            +
              
         | 
| 49 | 
            +
              custom_matcher :have_index do |receiver, matcher, args|
         | 
| 50 | 
            +
                index_name = args[0]
         | 
| 51 | 
            +
                matcher.positive_failure_message = "#{receiver} does not have index named #{index_name}, but should"
         | 
| 52 | 
            +
                matcher.negative_failure_message = "#{receiver} does have index named #{index_name}, but should not"
         | 
| 53 | 
            +
                !receiver.collection.index_information.detect { |index| index[0] == index_name }.nil?
         | 
| 54 | 
            +
              end
         | 
| 55 | 
            +
            end
         | 
    
        data/test/test_filter.rb
    ADDED
    
    | @@ -0,0 +1,43 @@ | |
| 1 | 
            +
            require 'helper'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            class TestFilter < Test::Unit::TestCase
         | 
| 4 | 
            +
              context "filtering data" do
         | 
| 5 | 
            +
                setup do
         | 
| 6 | 
            +
                  BlogPost.delete_all
         | 
| 7 | 
            +
                  @blogpost = BlogPost.create(:title => "%How dOEs tHIs Work?!",
         | 
| 8 | 
            +
                                              :body => "HeRe is tHe Body of the bLog pOsT",
         | 
| 9 | 
            +
                                              :tags => ["my", "list", "of", "tags"],
         | 
| 10 | 
            +
                                              :date => Time.parse('01-01-2009'))
         | 
| 11 | 
            +
                end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                should "be case insensitive" do
         | 
| 14 | 
            +
                  BlogPost.filter("body").should == [@blogpost]
         | 
| 15 | 
            +
                end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                should "be able to find by title" do
         | 
| 18 | 
            +
                  BlogPost.filter("this").should == [@blogpost]
         | 
| 19 | 
            +
                end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                should "be able to find by body" do
         | 
| 22 | 
            +
                  BlogPost.filter("blog").should == [@blogpost]
         | 
| 23 | 
            +
                end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                should "be able to find by tags" do
         | 
| 26 | 
            +
                  BlogPost.filter("list").should == [@blogpost]
         | 
| 27 | 
            +
                end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                should "be able to find by title or body" do
         | 
| 30 | 
            +
                  BlogPost.filter("work blog").should == [@blogpost]
         | 
| 31 | 
            +
                end
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                should "ignore inexistant words" do
         | 
| 34 | 
            +
                  BlogPost.filter("work lalala").should == [@blogpost]
         | 
| 35 | 
            +
                end
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                should "allow to paginate results" do
         | 
| 38 | 
            +
                  results = BlogPost.filter("tag", :per_page => 1, :page => 1)
         | 
| 39 | 
            +
                  results.should == [@blogpost]
         | 
| 40 | 
            +
                  results.total_pages.should == 1
         | 
| 41 | 
            +
                end
         | 
| 42 | 
            +
              end
         | 
| 43 | 
            +
            end
         | 
| @@ -0,0 +1,40 @@ | |
| 1 | 
            +
            require 'helper'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            class TestSlugizer < Test::Unit::TestCase
         | 
| 4 | 
            +
              context "working with slugs" do
         | 
| 5 | 
            +
                setup do
         | 
| 6 | 
            +
                  BlogPost.delete_all
         | 
| 7 | 
            +
                  @blogpost = BlogPost.create(:title => "%bLog pOSt tiTLe!",
         | 
| 8 | 
            +
                                              :body => "HeRe is tHe Body of the bLog pOsT")
         | 
| 9 | 
            +
                end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                should "generate the slug" do
         | 
| 12 | 
            +
                  @blogpost.slug.should =~ /\w+-blog-post-title/
         | 
| 13 | 
            +
                end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                should "return the slug as param" do
         | 
| 16 | 
            +
                  @blogpost.to_param =~ /\w+-blog-post-title/
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                should "return the id if slug was not generated" do
         | 
| 20 | 
            +
                  @blogpost.slug = nil
         | 
| 21 | 
            +
                  @blogpost.to_param.should == @blogpost.id
         | 
| 22 | 
            +
                end
         | 
| 23 | 
            +
              end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
              context "finding objects" do
         | 
| 26 | 
            +
                setup do
         | 
| 27 | 
            +
                  BlogPost.delete_all
         | 
| 28 | 
            +
                  @blogpost = BlogPost.create(:title => "%bLog pOSt tiTLe!",
         | 
| 29 | 
            +
                                              :body => "HeRe is tHe Body of the bLog pOsT")
         | 
| 30 | 
            +
                end
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                should "be able to find by slug" do
         | 
| 33 | 
            +
                  BlogPost.by_slug(@blogpost.slug).should == @blogpost
         | 
| 34 | 
            +
                end
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                should "be able to find by id" do
         | 
| 37 | 
            +
                  BlogPost.by_slug(@blogpost.id).should == @blogpost
         | 
| 38 | 
            +
                end
         | 
| 39 | 
            +
              end
         | 
| 40 | 
            +
            end
         | 
| @@ -0,0 +1,64 @@ | |
| 1 | 
            +
            require 'helper'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            class StorageTest < Test::Unit::TestCase
         | 
| 4 | 
            +
              context "Storing files" do
         | 
| 5 | 
            +
                setup do
         | 
| 6 | 
            +
                  @avatar = Avatar.create
         | 
| 7 | 
            +
                  @data = StringIO.new("my avatar image")
         | 
| 8 | 
            +
                end
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                should "store the file" do
         | 
| 11 | 
            +
                  @avatar.put_file("an_avatar.png", @data)
         | 
| 12 | 
            +
                  data = Avatar.find(@avatar.id).fetch_file("an_avatar.png").read
         | 
| 13 | 
            +
                  data.should == "my avatar image"
         | 
| 14 | 
            +
                end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                should "close the file after storing" do
         | 
| 17 | 
            +
                  @avatar.put_file("an_avatar.png", @data)
         | 
| 18 | 
            +
                  @data.should be_closed
         | 
| 19 | 
            +
                end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                context "in attributes" do
         | 
| 22 | 
            +
                  should "store the given file" do
         | 
| 23 | 
            +
                    @avatar.data = @data
         | 
| 24 | 
            +
                    @avatar.save!
         | 
| 25 | 
            +
                    @avatar.data.should_not be_nil
         | 
| 26 | 
            +
                    @avatar.data.read.should == "my avatar image"
         | 
| 27 | 
            +
                  end
         | 
| 28 | 
            +
                end
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                context "with new objects" do
         | 
| 31 | 
            +
                  setup do
         | 
| 32 | 
            +
                    @avatar = Avatar.new
         | 
| 33 | 
            +
                  end
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                  should "store the file after saving" do
         | 
| 36 | 
            +
                    @avatar.put_file("an_avatar.png", @data)
         | 
| 37 | 
            +
                    @avatar.save
         | 
| 38 | 
            +
                    @avatar.fetch_file("an_avatar.png").read.should == "my avatar image"
         | 
| 39 | 
            +
                  end
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                  should "store not the file if object is new" do
         | 
| 42 | 
            +
                    @avatar.put_file("an_avatar.png", @data)
         | 
| 43 | 
            +
                    @avatar.fetch_file("an_avatar.png").should be_nil
         | 
| 44 | 
            +
                  end
         | 
| 45 | 
            +
                end
         | 
| 46 | 
            +
              end
         | 
| 47 | 
            +
             | 
| 48 | 
            +
              context "Fetching files" do
         | 
| 49 | 
            +
                setup do
         | 
| 50 | 
            +
                  @avatar = Avatar.create
         | 
| 51 | 
            +
                  @data = StringIO.new("my avatar image")
         | 
| 52 | 
            +
                end
         | 
| 53 | 
            +
             | 
| 54 | 
            +
                should "fetch the list of files" do
         | 
| 55 | 
            +
                  @avatar.put_file("file1", StringIO.new("data1"))
         | 
| 56 | 
            +
                  @avatar.put_file("file2", StringIO.new("data2"))
         | 
| 57 | 
            +
                  @avatar.put_file("file3", StringIO.new("data3"))
         | 
| 58 | 
            +
                  file_names = @avatar.files.map { |f| f.filename }
         | 
| 59 | 
            +
                  file_names.should include("file1")
         | 
| 60 | 
            +
                  file_names.should include("file2")
         | 
| 61 | 
            +
                  file_names.should include("file3")
         | 
| 62 | 
            +
                end
         | 
| 63 | 
            +
              end
         | 
| 64 | 
            +
            end
         | 
    
        data/test/test_update.rb
    ADDED
    
    | @@ -0,0 +1,16 @@ | |
| 1 | 
            +
            require 'helper'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            class UpdateTest < Test::Unit::TestCase
         | 
| 4 | 
            +
              should "only update the given white listed attributes" do
         | 
| 5 | 
            +
                event = Event.new(:password => "original")
         | 
| 6 | 
            +
                start_date = Time.zone.now
         | 
| 7 | 
            +
                end_date = start_date.tomorrow
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                event.safe_update(%w[start_date end_date], {"start_date" => start_date,
         | 
| 10 | 
            +
                                                            "end_date" => end_date,
         | 
| 11 | 
            +
                                                            "password" => "hacked"})
         | 
| 12 | 
            +
                event.password.should == "original"
         | 
| 13 | 
            +
                event.start_date.to_s.should == start_date.to_s
         | 
| 14 | 
            +
                event.end_date.to_s.should == end_date.to_s
         | 
| 15 | 
            +
              end
         | 
| 16 | 
            +
            end
         | 
| @@ -0,0 +1,19 @@ | |
| 1 | 
            +
            require 'helper'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            class OpenStructTest < Test::Unit::TestCase
         | 
| 4 | 
            +
              def from_db
         | 
| 5 | 
            +
                UserConfig.find(@config.id)
         | 
| 6 | 
            +
              end
         | 
| 7 | 
            +
             | 
| 8 | 
            +
              context "working with sets" do
         | 
| 9 | 
            +
                setup do
         | 
| 10 | 
            +
                  @config = UserConfig.create!(:entries => OpenStruct.new({}))
         | 
| 11 | 
            +
                end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                should "allow to add new keys" do
         | 
| 14 | 
            +
                  @config.entries.new_key = "my new key"
         | 
| 15 | 
            +
                  @config.save!
         | 
| 16 | 
            +
                  from_db.entries.new_key.should == "my new key"
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
              end
         | 
| 19 | 
            +
            end
         | 
| @@ -0,0 +1,26 @@ | |
| 1 | 
            +
            require 'helper'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            class SetTest < Test::Unit::TestCase
         | 
| 4 | 
            +
              def from_db
         | 
| 5 | 
            +
                Recipe.find(@recipe.id)
         | 
| 6 | 
            +
              end
         | 
| 7 | 
            +
             | 
| 8 | 
            +
              context "working with sets" do
         | 
| 9 | 
            +
                setup do
         | 
| 10 | 
            +
                  @recipe = Recipe.create!(:ingredients => %w[salt sugar water salt sugar water])
         | 
| 11 | 
            +
                end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                should "not have duplicates" do
         | 
| 14 | 
            +
                  from_db.ingredients.size.should == 3
         | 
| 15 | 
            +
                  from_db.ingredients.should include("salt")
         | 
| 16 | 
            +
                  from_db.ingredients.should include("sugar")
         | 
| 17 | 
            +
                  from_db.ingredients.should include("water")
         | 
| 18 | 
            +
                end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                should "not add duplicates" do
         | 
| 21 | 
            +
                  original_size = @recipe.ingredients.size
         | 
| 22 | 
            +
                  @recipe.ingredients << "salt"
         | 
| 23 | 
            +
                  @recipe.ingredients.size.should == original_size
         | 
| 24 | 
            +
                end
         | 
| 25 | 
            +
              end
         | 
| 26 | 
            +
            end
         | 
| @@ -0,0 +1,40 @@ | |
| 1 | 
            +
            require 'helper'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            class TimestampTest < Test::Unit::TestCase
         | 
| 4 | 
            +
              def from_db
         | 
| 5 | 
            +
                Event.find(@event.id)
         | 
| 6 | 
            +
              end
         | 
| 7 | 
            +
             | 
| 8 | 
            +
              context "working with timestamps" do
         | 
| 9 | 
            +
                setup do
         | 
| 10 | 
            +
                  Event.delete_all
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                  Time.zone = 'UTC'
         | 
| 13 | 
            +
                  @start_time = Time.zone.parse('01-01-2009')
         | 
| 14 | 
            +
                  @end_time = @start_time.tomorrow
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                  @event = Event.create!(:start_date => @start_time, :end_date => @end_time)
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                should "store the date" do
         | 
| 20 | 
            +
                  from_db.start_date.to_s.should == @start_time.to_s
         | 
| 21 | 
            +
                end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                should "be able to convert the time to the given timezone" do
         | 
| 24 | 
            +
                  Time.zone = 'Hawaii'
         | 
| 25 | 
            +
                  from_db.start_date.to_s.should == "2008-12-31 14:00:00 -1000"
         | 
| 26 | 
            +
                end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                should "be able to compare dates" do
         | 
| 29 | 
            +
                  start_time = @start_time.tomorrow.tomorrow
         | 
| 30 | 
            +
                  end_time = start_time.tomorrow
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                  @event2 = Event.create!(:start_date => start_time, :end_datime => end_time)
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                  Event.count.should == 2
         | 
| 35 | 
            +
                  events = Event.find(:all, :$where => ("this.start_date >= %d && this.start_date <= %d" % [@event.start_date.yesterday.to_i, @event2.start_date.yesterday.to_i]))
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                  events.should == [@event]
         | 
| 38 | 
            +
                end
         | 
| 39 | 
            +
              end
         | 
| 40 | 
            +
            end
         | 
    
        metadata
    ADDED
    
    | @@ -0,0 +1,160 @@ | |
| 1 | 
            +
            --- !ruby/object:Gem::Specification 
         | 
| 2 | 
            +
            name: mongomapper_ext
         | 
| 3 | 
            +
            version: !ruby/object:Gem::Version 
         | 
| 4 | 
            +
              version: 0.0.4
         | 
| 5 | 
            +
            platform: ruby
         | 
| 6 | 
            +
            authors: 
         | 
| 7 | 
            +
            - David A. Cuadrado
         | 
| 8 | 
            +
            autorequire: 
         | 
| 9 | 
            +
            bindir: bin
         | 
| 10 | 
            +
            cert_chain: []
         | 
| 11 | 
            +
             | 
| 12 | 
            +
            date: 2009-10-25 00:00:00 -05:00
         | 
| 13 | 
            +
            default_executable: 
         | 
| 14 | 
            +
            dependencies: 
         | 
| 15 | 
            +
            - !ruby/object:Gem::Dependency 
         | 
| 16 | 
            +
              name: mongo_mapper
         | 
| 17 | 
            +
              type: :runtime
         | 
| 18 | 
            +
              version_requirement: 
         | 
| 19 | 
            +
              version_requirements: !ruby/object:Gem::Requirement 
         | 
| 20 | 
            +
                requirements: 
         | 
| 21 | 
            +
                - - ">="
         | 
| 22 | 
            +
                  - !ruby/object:Gem::Version 
         | 
| 23 | 
            +
                    version: 0.5.6
         | 
| 24 | 
            +
                version: 
         | 
| 25 | 
            +
            - !ruby/object:Gem::Dependency 
         | 
| 26 | 
            +
              name: ruby-stemmer
         | 
| 27 | 
            +
              type: :runtime
         | 
| 28 | 
            +
              version_requirement: 
         | 
| 29 | 
            +
              version_requirements: !ruby/object:Gem::Requirement 
         | 
| 30 | 
            +
                requirements: 
         | 
| 31 | 
            +
                - - ">="
         | 
| 32 | 
            +
                  - !ruby/object:Gem::Version 
         | 
| 33 | 
            +
                    version: 0.5.3
         | 
| 34 | 
            +
                version: 
         | 
| 35 | 
            +
            - !ruby/object:Gem::Dependency 
         | 
| 36 | 
            +
              name: uuidtools
         | 
| 37 | 
            +
              type: :runtime
         | 
| 38 | 
            +
              version_requirement: 
         | 
| 39 | 
            +
              version_requirements: !ruby/object:Gem::Requirement 
         | 
| 40 | 
            +
                requirements: 
         | 
| 41 | 
            +
                - - ">="
         | 
| 42 | 
            +
                  - !ruby/object:Gem::Version 
         | 
| 43 | 
            +
                    version: 2.0.0
         | 
| 44 | 
            +
                version: 
         | 
| 45 | 
            +
            - !ruby/object:Gem::Dependency 
         | 
| 46 | 
            +
              name: shoulda
         | 
| 47 | 
            +
              type: :development
         | 
| 48 | 
            +
              version_requirement: 
         | 
| 49 | 
            +
              version_requirements: !ruby/object:Gem::Requirement 
         | 
| 50 | 
            +
                requirements: 
         | 
| 51 | 
            +
                - - ">="
         | 
| 52 | 
            +
                  - !ruby/object:Gem::Version 
         | 
| 53 | 
            +
                    version: 2.10.2
         | 
| 54 | 
            +
                version: 
         | 
| 55 | 
            +
            - !ruby/object:Gem::Dependency 
         | 
| 56 | 
            +
              name: jnunemaker-matchy
         | 
| 57 | 
            +
              type: :development
         | 
| 58 | 
            +
              version_requirement: 
         | 
| 59 | 
            +
              version_requirements: !ruby/object:Gem::Requirement 
         | 
| 60 | 
            +
                requirements: 
         | 
| 61 | 
            +
                - - "="
         | 
| 62 | 
            +
                  - !ruby/object:Gem::Version 
         | 
| 63 | 
            +
                    version: 0.4.0
         | 
| 64 | 
            +
                version: 
         | 
| 65 | 
            +
            - !ruby/object:Gem::Dependency 
         | 
| 66 | 
            +
              name: mocha
         | 
| 67 | 
            +
              type: :development
         | 
| 68 | 
            +
              version_requirement: 
         | 
| 69 | 
            +
              version_requirements: !ruby/object:Gem::Requirement 
         | 
| 70 | 
            +
                requirements: 
         | 
| 71 | 
            +
                - - ">="
         | 
| 72 | 
            +
                  - !ruby/object:Gem::Version 
         | 
| 73 | 
            +
                    version: 0.9.4
         | 
| 74 | 
            +
                version: 
         | 
| 75 | 
            +
            description: MongoMapper extensions
         | 
| 76 | 
            +
            email: krawek@gmail.com
         | 
| 77 | 
            +
            executables: []
         | 
| 78 | 
            +
             | 
| 79 | 
            +
            extensions: []
         | 
| 80 | 
            +
             | 
| 81 | 
            +
            extra_rdoc_files: 
         | 
| 82 | 
            +
            - LICENSE
         | 
| 83 | 
            +
            - README.rdoc
         | 
| 84 | 
            +
            files: 
         | 
| 85 | 
            +
            - .document
         | 
| 86 | 
            +
            - .gitignore
         | 
| 87 | 
            +
            - LICENSE
         | 
| 88 | 
            +
            - README.rdoc
         | 
| 89 | 
            +
            - Rakefile
         | 
| 90 | 
            +
            - VERSION
         | 
| 91 | 
            +
            - examples/filter.rb
         | 
| 92 | 
            +
            - examples/helper.rb
         | 
| 93 | 
            +
            - examples/slugizer.rb
         | 
| 94 | 
            +
            - examples/storage.rb
         | 
| 95 | 
            +
            - examples/types.rb
         | 
| 96 | 
            +
            - examples/update.rb
         | 
| 97 | 
            +
            - lib/mongomapper_ext.rb
         | 
| 98 | 
            +
            - lib/mongomapper_ext/file.rb
         | 
| 99 | 
            +
            - lib/mongomapper_ext/filter.rb
         | 
| 100 | 
            +
            - lib/mongomapper_ext/slugizer.rb
         | 
| 101 | 
            +
            - lib/mongomapper_ext/storage.rb
         | 
| 102 | 
            +
            - lib/mongomapper_ext/types/open_struct.rb
         | 
| 103 | 
            +
            - lib/mongomapper_ext/types/set.rb
         | 
| 104 | 
            +
            - lib/mongomapper_ext/types/timestamp.rb
         | 
| 105 | 
            +
            - lib/mongomapper_ext/update.rb
         | 
| 106 | 
            +
            - test/helper.rb
         | 
| 107 | 
            +
            - test/models.rb
         | 
| 108 | 
            +
            - test/support/custom_matchers.rb
         | 
| 109 | 
            +
            - test/test_filter.rb
         | 
| 110 | 
            +
            - test/test_slugizer.rb
         | 
| 111 | 
            +
            - test/test_storage.rb
         | 
| 112 | 
            +
            - test/test_update.rb
         | 
| 113 | 
            +
            - test/types/test_open_struct.rb
         | 
| 114 | 
            +
            - test/types/test_set.rb
         | 
| 115 | 
            +
            - test/types/test_timestamp.rb
         | 
| 116 | 
            +
            has_rdoc: true
         | 
| 117 | 
            +
            homepage: http://github.com/dcu/mongomapper_ext
         | 
| 118 | 
            +
            licenses: []
         | 
| 119 | 
            +
             | 
| 120 | 
            +
            post_install_message: 
         | 
| 121 | 
            +
            rdoc_options: 
         | 
| 122 | 
            +
            - --charset=UTF-8
         | 
| 123 | 
            +
            require_paths: 
         | 
| 124 | 
            +
            - lib
         | 
| 125 | 
            +
            required_ruby_version: !ruby/object:Gem::Requirement 
         | 
| 126 | 
            +
              requirements: 
         | 
| 127 | 
            +
              - - ">="
         | 
| 128 | 
            +
                - !ruby/object:Gem::Version 
         | 
| 129 | 
            +
                  version: "0"
         | 
| 130 | 
            +
              version: 
         | 
| 131 | 
            +
            required_rubygems_version: !ruby/object:Gem::Requirement 
         | 
| 132 | 
            +
              requirements: 
         | 
| 133 | 
            +
              - - ">="
         | 
| 134 | 
            +
                - !ruby/object:Gem::Version 
         | 
| 135 | 
            +
                  version: "0"
         | 
| 136 | 
            +
              version: 
         | 
| 137 | 
            +
            requirements: []
         | 
| 138 | 
            +
             | 
| 139 | 
            +
            rubyforge_project: 
         | 
| 140 | 
            +
            rubygems_version: 1.3.5
         | 
| 141 | 
            +
            signing_key: 
         | 
| 142 | 
            +
            specification_version: 3
         | 
| 143 | 
            +
            summary: MongoMapper extensions
         | 
| 144 | 
            +
            test_files: 
         | 
| 145 | 
            +
            - test/test_slugizer.rb
         | 
| 146 | 
            +
            - test/test_filter.rb
         | 
| 147 | 
            +
            - test/test_storage.rb
         | 
| 148 | 
            +
            - test/test_update.rb
         | 
| 149 | 
            +
            - test/support/custom_matchers.rb
         | 
| 150 | 
            +
            - test/models.rb
         | 
| 151 | 
            +
            - test/helper.rb
         | 
| 152 | 
            +
            - test/types/test_open_struct.rb
         | 
| 153 | 
            +
            - test/types/test_timestamp.rb
         | 
| 154 | 
            +
            - test/types/test_set.rb
         | 
| 155 | 
            +
            - examples/types.rb
         | 
| 156 | 
            +
            - examples/filter.rb
         | 
| 157 | 
            +
            - examples/update.rb
         | 
| 158 | 
            +
            - examples/storage.rb
         | 
| 159 | 
            +
            - examples/helper.rb
         | 
| 160 | 
            +
            - examples/slugizer.rb
         |