mongo_doc 0.3.1 → 0.3.2

Sign up to get free protection for your applications and to get access to all the features.
data/README.textile CHANGED
@@ -1,9 +1,17 @@
1
1
  h1. MongoDoc
2
2
 
3
- Version: 0.2.4 2/23/10
3
+ Version: 0.3.2 2010/03/11
4
4
 
5
- 2010-02-23 API is *changing* significantly
6
- 2010-01-23 Tracking MongoDoc with @git@? *READ THIS NOTE*[1]
5
+ * 2010-03-10 Slides are out of date, use key instead of attr_accessor with MongoDoc::Document (implementation was way too hackish)
6
+ * 2010-02-23 API is *changing* significantly
7
+ * 2010-01-23 Tracking MongoDoc with @git@? *READ THIS NOTE*[1]
8
+
9
+ h2. Quick Start
10
+
11
+ * install MongoDB (at least 1.3.2)
12
+ * install the Ruby driver @gem install mongo@
13
+ * install MongoDoc @gem install mongo_doc@
14
+ * run an example from this directory @ruby -Ilib examples/simple_object.rb@
7
15
 
8
16
  h2. Introduction
9
17
 
data/TODO CHANGED
@@ -1,4 +1,4 @@
1
- As of 2010-02-23
1
+ As of 2010-03-06
2
2
 
3
3
  Associations
4
4
  ------------
@@ -8,13 +8,18 @@ Pull associations out of attributes and refactor
8
8
  Criteria
9
9
  --------
10
10
 
11
- Make critieria module, include into Document, CriteriaProxy, Association?
11
+ Make critieria module; include into CriteriaProxy, Association?
12
+ page, per_page, paginate shuould be wrapped or not?
13
+
14
+ Contexts
15
+ --------
16
+
17
+ Extract Mongo context as module, Document#collection => klass.collection Collection#collection => klass
12
18
 
13
19
  Documentation
14
20
  -------------
15
21
 
16
22
  How to get started with Rails
17
- Using mongohq
18
23
 
19
24
  Dynamic Attributes
20
25
  ------------------
@@ -29,3 +34,7 @@ Validations
29
34
 
30
35
  validates_hash_keys :has_hash_name, :in => [array of names]
31
36
 
37
+
38
+ Q
39
+ -
40
+ What is Criteria#ids
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.3.1
1
+ 0.3.2
@@ -25,7 +25,12 @@ Contact.collection.drop
25
25
  contact = Contact.new(:name => 'Hashrocket', :interests => ['ruby', 'rails', 'agile'])
26
26
  contact.addresses << Address.new(:street => '320 1st Street North, #712', :city => 'Jacksonville Beach', :state => 'FL', :zip_code => '32250', :phone_number => '877 885 8846')
27
27
  contact.save
28
+
29
+ # Finders
30
+ Contact.find_all.each {|c| puts c.name}
31
+ puts contact.to_param
28
32
  puts Contact.find_one(contact.to_param).addresses.first.street
33
+ Contact.find(contact.to_param).each {|c| puts c.name}
29
34
 
30
35
  hashrocket = Contact.in_state('FL').find {|contact| contact.name == 'Hashrocket'}
31
36
 
@@ -33,3 +38,9 @@ hashrocket_address = hashrocket.addresses.first
33
38
  hashrocket_address.update_attributes(:street => '320 First Street North, #712')
34
39
 
35
40
  puts Contact.where(:name => 'Hashrocket').first.addresses.first.street
41
+
42
+ # Criteria behave like new AR3 AREL queries
43
+ hr = Contact.where(:name => 'Hashrocket')
44
+ hr_in = hr.where('addresses.state' => 'IN')
45
+ puts hr.count
46
+ puts hr_in.count
@@ -25,6 +25,10 @@ contact.addresses = [address]
25
25
 
26
26
  collection.save(contact)
27
27
 
28
- results = collection.find('addresses.state' => 'FL')
29
- hashrocket = results.to_a.find {|contact| contact.name == 'Hashrocket'}
30
- puts hashrocket.addresses.first.phone_number
28
+ in_florida = collection.where('addresses.state' => 'FL')
29
+ puts in_florida.first.addresses.first.phone_number
30
+ rocket_oid_names = collection.where('name' => /rocket/)
31
+ puts rocket_oid_names.first.addresses.first.phone_number
32
+ interested_in_ruby = collection.in('interests' => ['ruby'])
33
+ puts interested_in_ruby.first.addresses.first.phone_number
34
+
@@ -0,0 +1,9 @@
1
+ Feature: Collection with Criteria
2
+
3
+ Scenario: saving a ruby object
4
+ Given a new collection named 'test'
5
+ And an object 'movie'
6
+ When I save the object 'movie'
7
+ And I query the collection 'test' with the criteria where(:title => 'Gone with the Wind')
8
+ Then the query result has 1 documents
9
+
@@ -12,3 +12,6 @@ Then /the collection should have (\d+) documents?/ do |count|
12
12
  @collection.count.should == count.to_i
13
13
  end
14
14
 
15
+ When "I query the collection '$collection_name' with the criteria $criteria" do |collection_name, criteria|
16
+ @query = eval("@collection.#{criteria}")
17
+ end
@@ -28,3 +28,11 @@ class Contact
28
28
  scope :contract_work, any_in(:interests => ['contract work'])
29
29
  scope :in_state, lambda {|state| where('addresses.state' => state)}
30
30
  end
31
+
32
+ class Event
33
+ include MongoDoc::Document
34
+
35
+ key :name
36
+ key :venue
37
+ key :date, :type => Date
38
+ end
@@ -7,18 +7,18 @@ end
7
7
 
8
8
  class Movie
9
9
  include ValueEquals
10
-
10
+
11
11
  attr_accessor :title, :director, :writers
12
12
  end
13
13
 
14
14
  class Director
15
15
  include ValueEquals
16
-
16
+
17
17
  attr_accessor :name, :awards
18
18
  end
19
19
 
20
20
  class AcademyAward
21
21
  include ValueEquals
22
-
22
+
23
23
  attr_accessor :year, :category
24
24
  end
@@ -6,6 +6,10 @@ def query(klass_name = nil)
6
6
  @query ||= klass(klass_name).criteria
7
7
  end
8
8
 
9
+ When "I also want a $number query with criteria $criteria" do |number, criteria|
10
+ instance_variable_set("@#{number}", eval("query.#{criteria}"))
11
+ end
12
+
9
13
  Then /^the query result is equal to the document '(.*)'$/ do |name|
10
14
  doc = instance_variable_get("@#{name}")
11
15
  query.should == doc
@@ -55,3 +59,8 @@ end
55
59
  Then /^the query (is|is not) (empty|blank)$/ do |is, empty|
56
60
  query.send("#{empty}?").should == (is == 'is')
57
61
  end
62
+
63
+ Then /^the (.+) query (is|is not) (empty|blank)$/ do |number, is, empty|
64
+ instance_variable_get("@#{number}").send("#{empty}?").should == (is == 'is')
65
+ end
66
+
@@ -0,0 +1,28 @@
1
+ def last
2
+ @last
3
+ end
4
+
5
+ def last=(value)
6
+ @last = value
7
+ end
8
+
9
+ def all
10
+ @all ||= []
11
+ end
12
+
13
+ def all=(value)
14
+ @all = value
15
+ end
16
+
17
+ Given /^a class Event$/ do
18
+ end
19
+
20
+ Given /^I create an (.+) '(.+)' with:$/ do |klass_name, object_name, table|
21
+ Given "an #{klass_name} document named '#{object_name}' :", table
22
+ end
23
+
24
+ Then /^the object '(.+)' has an attribute '(.+)' of type (.*)$/ do |object_name, attr_name, type_name|
25
+ object = instance_variable_get("@#{object_name}")
26
+ type_name.constantize.should === object.send(attr_name)
27
+ end
28
+
@@ -0,0 +1,10 @@
1
+ Feature: String casting
2
+
3
+ Background:
4
+ Given a class Event
5
+
6
+ Scenario: Creating a new document
7
+ When I create an Event 'event' with:
8
+ | Name | Venue | Date |
9
+ | NoSQL Live | John Hancock Conference Center | 2010-03-11 |
10
+ Then the object 'event' has an attribute 'date' of type Date
@@ -134,3 +134,9 @@ Feature: MongoDoc::Base
134
134
  Scenario: Is a criteria empty?
135
135
  When I query contacts with criteria all('interests' => ['ruby'])
136
136
  Then the query is not empty
137
+
138
+ Scenario: Criteria return a new criteria
139
+ When I query contacts with criteria all('interests' => ['ruby'])
140
+ And I also want a second query with criteria where('addresses.state' => 'HI')
141
+ Then the query is not empty
142
+ And the second query is empty
@@ -19,6 +19,20 @@ module MongoDoc
19
19
  end
20
20
  end
21
21
 
22
+ def attributes
23
+ hash = {}
24
+ self.class._attributes.each do |attr|
25
+ hash[attr] = send(attr)
26
+ end
27
+ hash
28
+ end
29
+
30
+ def attributes=(attrs)
31
+ attrs.each do |key, value|
32
+ send("#{key}=", value)
33
+ end
34
+ end
35
+
22
36
  def _root
23
37
  @_root
24
38
  end
@@ -42,9 +56,41 @@ module MongoDoc
42
56
  end
43
57
 
44
58
  def key(*args)
59
+ opts = args.extract_options!
60
+ default = opts.delete(:default)
61
+ type = opts.delete(:type)
45
62
  args.each do |name|
46
63
  _keys << name unless _keys.include?(name)
47
- attr_accessor name
64
+ if default
65
+ attr_writer name
66
+
67
+ define_method("_default_#{name}", default.kind_of?(Proc) ? default : Proc.new { default })
68
+ private "_default_#{name}"
69
+
70
+ module_eval(<<-RUBY, __FILE__, __LINE__)
71
+ def #{name}
72
+ unless defined? @#{name}
73
+ @#{name} = _default_#{name}
74
+ end
75
+ class << self; attr_reader :#{name} end
76
+ @#{name}
77
+ end
78
+ RUBY
79
+ else
80
+ attr_accessor name
81
+ end
82
+
83
+ if type and type.respond_to?(:cast_from_string)
84
+ module_eval(<<-RUBY, __FILE__, __LINE__)
85
+ def #{name}_with_type=(value) # def birth_date_with_type=(value)
86
+ if value.kind_of?(String) # if value.kind_of?(String)
87
+ value = #{type}.cast_from_string(value) # value = Date.cast_from_string(value)
88
+ end # end
89
+ self.#{name}_without_type = value # self.birth_date_without_type = value
90
+ end # end
91
+ RUBY
92
+ alias_method_chain "#{name}=", :type
93
+ end
48
94
  end
49
95
  end
50
96
 
@@ -1,18 +1,4 @@
1
- require 'mongo_doc/ext/array'
2
- require 'mongo_doc/ext/binary'
3
- require 'mongo_doc/ext/boolean_class'
4
- require 'mongo_doc/ext/date'
5
- require 'mongo_doc/ext/date_time'
6
- require 'mongo_doc/ext/dbref'
7
- require 'mongo_doc/ext/hash'
8
- require 'mongo_doc/ext/nil_class'
9
- require 'mongo_doc/ext/numeric'
10
- require 'mongo_doc/ext/object'
11
- require 'mongo_doc/ext/object_id'
12
- require 'mongo_doc/ext/regexp'
13
- require 'mongo_doc/ext/string'
14
- require 'mongo_doc/ext/symbol'
15
- require 'mongo_doc/ext/time'
1
+ require 'mongo_doc/ext'
16
2
 
17
3
  module MongoDoc
18
4
  module BSON
@@ -29,7 +15,7 @@ module MongoDoc
29
15
  bson
30
16
  end
31
17
  end
32
-
18
+
33
19
  def self.bson_create(bson_hash, options = {})
34
20
  return bson_hash if options[:raw_json]
35
21
  klass = bson_hash.delete(CLASS_KEY)
@@ -1,10 +1,33 @@
1
1
  require 'mongo_doc/cursor'
2
+ require 'mongo_doc/criteria'
2
3
 
3
4
  module MongoDoc
4
5
  class Collection
5
6
  attr_accessor :_collection
6
7
 
7
- delegate :[], :clear, :count, :create_index, :db, :distinct, :drop, :drop_index, :drop_indexes, :group, :hint, :index_information, :map_reduce, :mapreduce, :name, :options, :pk_factory, :remove, :rename, :size, :to => :_collection
8
+ include MongoDoc::Criteria
9
+
10
+ delegate \
11
+ :[],
12
+ :clear,
13
+ :count,
14
+ :create_index,
15
+ :db,
16
+ :distinct,
17
+ :drop,
18
+ :drop_index,
19
+ :drop_indexes,
20
+ :group,
21
+ :hint,
22
+ :index_information,
23
+ :map_reduce,
24
+ :mapreduce,
25
+ :name,
26
+ :options,
27
+ :pk_factory,
28
+ :remove,
29
+ :rename,
30
+ :size, :to => :_collection
8
31
 
9
32
  def initialize(name)
10
33
  self._collection = self.class.mongo_collection(name)
@@ -40,6 +63,10 @@ module MongoDoc
40
63
 
41
64
  protected
42
65
 
66
+ def collection
67
+ self
68
+ end
69
+
43
70
  def last_error
44
71
  MongoDoc::Connection.database.command({'getlasterror' => 1})
45
72
  end
@@ -6,6 +6,9 @@ require "mongo_doc/contexts/mongo"
6
6
 
7
7
  module Mongoid
8
8
  module Contexts
9
+
10
+ class UnknownContext < RuntimeError; end
11
+
9
12
  # Determines the context to be used for this criteria. If the class is an
10
13
  # embedded document, then the context will be the array in the has_many
11
14
  # association it is in. If the class is a root, then the database itself
@@ -15,10 +18,13 @@ module Mongoid
15
18
  #
16
19
  # <tt>Contexts.context_for(criteria)</tt>
17
20
  def self.context_for(criteria)
18
- if criteria.klass.respond_to?(:collection)
21
+ if criteria.klass.respond_to?(:_append)
22
+ return MongoDoc::Contexts::Enumerable.new(criteria)
23
+ elsif criteria.klass.respond_to?(:collection)
19
24
  return MongoDoc::Contexts::Mongo.new(criteria)
25
+ else
26
+ raise UnknownContext.new("Context not found for: #{criteria.klass}")
20
27
  end
21
- return MongoDoc::Contexts::Enumerable.new(criteria)
22
28
  end
23
29
 
24
30
  end
@@ -10,27 +10,59 @@ module MongoDoc
10
10
  #
11
11
  # <tt>Person.criteria</tt>
12
12
  def criteria
13
- Mongoid::Criteria.new(self)
13
+ CriteriaWrapper.new(self)
14
14
  end
15
15
 
16
16
  delegate \
17
+ :aggregate,
18
+ :all,
17
19
  :and,
18
20
  :any_in,
19
- :cache,
20
- :enslave,
21
+ :blank?,
22
+ :count,
23
+ :empty?,
21
24
  :excludes,
22
25
  :extras,
26
+ :first,
27
+ :group,
23
28
  :id,
24
29
  :in,
30
+ :last,
25
31
  :limit,
32
+ :max,
33
+ :min,
26
34
  :not_in,
27
35
  :offset,
36
+ :one,
28
37
  :only,
29
38
  :order_by,
30
39
  :page,
40
+ :paginate,
31
41
  :per_page,
32
42
  :skip,
43
+ :sum,
33
44
  :where, :to => :criteria
45
+
46
+ class CriteriaWrapper < Mongoid::Criteria
47
+ %w(all and any_in cache enslave excludes extras fuse in limit not_in offset only order_by skip where).each do |method|
48
+ class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
49
+ def #{method}_with_wrapping(*args, &block) # def and(*args, &block)
50
+ new_criteria = CriteriaWrapper.new(klass) # new_criteria = CriteriaWrapper.new(klass)
51
+ new_criteria.merge(self) # new_criteria.merge(criteria)
52
+ new_criteria.#{method}_without_wrapping(*args, &block) # new_criteria.and_without_wrapping(*args, &block)
53
+ new_criteria # new_criteria
54
+ end # end
55
+
56
+ alias_method_chain :#{method}, :wrapping
57
+ protected :#{method}_without_wrapping
58
+ RUBY
59
+ end
60
+
61
+ protected
62
+
63
+ attr_accessor :criteria
64
+
65
+ end
34
66
  end
35
67
  end
36
68
 
@@ -36,20 +36,6 @@ module MongoDoc
36
36
  self.class._attributes.all? {|var| self.send(var) == other.send(var)}
37
37
  end
38
38
 
39
- def attributes
40
- hash = {}
41
- self.class._attributes.each do |attr|
42
- hash[attr] = send(attr)
43
- end
44
- hash
45
- end
46
-
47
- def attributes=(attrs)
48
- attrs.each do |key, value|
49
- send("#{key}=", value)
50
- end
51
- end
52
-
53
39
  def new_record?
54
40
  _id.nil?
55
41
  end
@@ -132,13 +118,13 @@ module MongoDoc
132
118
 
133
119
  def create(attrs = {})
134
120
  instance = new(attrs)
135
- instance.save(false)
121
+ instance.save(true)
136
122
  instance
137
123
  end
138
124
 
139
125
  def create!(attrs = {})
140
126
  instance = new(attrs)
141
- instance.save!(true)
127
+ instance.save!
142
128
  instance
143
129
  end
144
130
  end
@@ -1,3 +1,9 @@
1
+ class Boolean
2
+ def self.cast_from_string(value)
3
+ value == '1' || value.downcase == 'true'
4
+ end
5
+ end
6
+
1
7
  class FalseClass
2
8
  def to_bson(*args)
3
9
  self
@@ -8,4 +14,4 @@ class TrueClass
8
14
  def to_bson(*args)
9
15
  self
10
16
  end
11
- end
17
+ end
@@ -13,4 +13,7 @@ class Date
13
13
  Date.parse(*bson_hash.values_at('dt', 'sg'))
14
14
  end
15
15
 
16
+ def self.cast_from_string(value)
17
+ Date.parse(value) unless value.blank?
18
+ end
16
19
  end
@@ -10,4 +10,8 @@ class DateTime
10
10
  def self.bson_create(bson_hash, options = nil)
11
11
  DateTime.parse(*bson_hash.values_at('dt', 'sg'))
12
12
  end
13
+
14
+ def self.cast_from_string(string)
15
+ DateTime.parse(string) unless string.blank?
16
+ end
13
17
  end
@@ -4,14 +4,14 @@ class Numeric
4
4
  end
5
5
  end
6
6
 
7
- class Float
8
- def to_bson(*args)
9
- self
7
+ class BigDecimal
8
+ def self.cast_from_string(string)
9
+ BigDecimal.new(string) unless string.blank?
10
10
  end
11
11
  end
12
12
 
13
13
  class Integer
14
- def to_bson(*args)
15
- self
14
+ def self.cast_from_string(string)
15
+ string.to_i unless string.blank?
16
16
  end
17
17
  end
@@ -2,4 +2,8 @@ class Time
2
2
  def to_bson(*args)
3
3
  self
4
4
  end
5
- end
5
+
6
+ def self.cast_from_string(string)
7
+ Time.parse(string) unless string.blank?
8
+ end
9
+ end
@@ -0,0 +1,15 @@
1
+ require 'mongo_doc/ext/array'
2
+ require 'mongo_doc/ext/binary'
3
+ require 'mongo_doc/ext/boolean_class'
4
+ require 'mongo_doc/ext/date'
5
+ require 'mongo_doc/ext/date_time'
6
+ require 'mongo_doc/ext/dbref'
7
+ require 'mongo_doc/ext/hash'
8
+ require 'mongo_doc/ext/nil_class'
9
+ require 'mongo_doc/ext/numeric'
10
+ require 'mongo_doc/ext/object'
11
+ require 'mongo_doc/ext/object_id'
12
+ require 'mongo_doc/ext/regexp'
13
+ require 'mongo_doc/ext/string'
14
+ require 'mongo_doc/ext/symbol'
15
+ require 'mongo_doc/ext/time'
@@ -6,17 +6,6 @@ module MongoDoc
6
6
  base.extend(Criteria) unless base === Criteria
7
7
  end
8
8
 
9
- %w(count first last).each do |name|
10
- module_eval <<-RUBY
11
- # #{name.humanize} for this +Document+ class
12
- #
13
- # <tt>Person.#{name}</tt>
14
- def #{name}
15
- criteria.#{name}
16
- end
17
- RUBY
18
- end
19
-
20
9
  # Find a +Document+ based on id (+String+ or +Mongo::ObjectID+)
21
10
  #
22
11
  # <tt>Person.find('1')</tt>
@@ -22,6 +22,7 @@ module Mongoid #:nodoc:
22
22
  def all(attributes = {})
23
23
  update_selector(attributes, "$all")
24
24
  end
25
+ alias :all_in :all
25
26
 
26
27
  # Adds a criterion to the +Criteria+ that specifies values that must
27
28
  # be matched in order to return results. This is similar to a SQL "WHERE"
@@ -61,7 +62,7 @@ module Mongoid #:nodoc:
61
62
  def in(attributes = {})
62
63
  update_selector(attributes, "$in")
63
64
  end
64
- alias any_in in
65
+ alias :any_in :in
65
66
 
66
67
  # Adds a criterion to the +Criteria+ that specifies values that must
67
68
  # be matched in order to return results. This is similar to a SQL "WHERE"
data/mongo_doc.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{mongo_doc}
8
- s.version = "0.3.1"
8
+ s.version = "0.3.2"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Les Hill"]
12
- s.date = %q{2010-03-06}
12
+ s.date = %q{2010-03-11}
13
13
  s.description = %q{ODM for MongoDB}
14
14
  s.email = %q{leshill@gmail.com}
15
15
  s.extra_rdoc_files = [
@@ -28,6 +28,7 @@ Gem::Specification.new do |s|
28
28
  "data/.gitignore",
29
29
  "examples/simple_document.rb",
30
30
  "examples/simple_object.rb",
31
+ "features/collections.feature",
31
32
  "features/finders.feature",
32
33
  "features/mongodb.yml",
33
34
  "features/mongodoc_base.feature",
@@ -47,7 +48,9 @@ Gem::Specification.new do |s|
47
48
  "features/step_definitions/query_steps.rb",
48
49
  "features/step_definitions/removing_documents_steps.rb",
49
50
  "features/step_definitions/scope_steps.rb",
51
+ "features/step_definitions/string_casting_steps.rb",
50
52
  "features/step_definitions/util_steps.rb",
53
+ "features/string_casting.feature",
51
54
  "features/support/support.rb",
52
55
  "features/using_criteria.feature",
53
56
  "lib/mongo_doc.rb",
@@ -66,6 +69,7 @@ Gem::Specification.new do |s|
66
69
  "lib/mongo_doc/criteria.rb",
67
70
  "lib/mongo_doc/cursor.rb",
68
71
  "lib/mongo_doc/document.rb",
72
+ "lib/mongo_doc/ext.rb",
69
73
  "lib/mongo_doc/ext/array.rb",
70
74
  "lib/mongo_doc/ext/binary.rb",
71
75
  "lib/mongo_doc/ext/boolean_class.rb",
@@ -115,6 +119,7 @@ Gem::Specification.new do |s|
115
119
  "spec/associations/collection_proxy_spec.rb",
116
120
  "spec/associations/document_proxy_spec.rb",
117
121
  "spec/associations/hash_proxy_spec.rb",
122
+ "spec/attributes_accessor_spec.rb",
118
123
  "spec/attributes_spec.rb",
119
124
  "spec/bson_matchers.rb",
120
125
  "spec/bson_spec.rb",
@@ -129,6 +134,7 @@ Gem::Specification.new do |s|
129
134
  "spec/document_ext.rb",
130
135
  "spec/document_spec.rb",
131
136
  "spec/embedded_save_spec.rb",
137
+ "spec/ext_spec.rb",
132
138
  "spec/finders_spec.rb",
133
139
  "spec/hash_matchers.rb",
134
140
  "spec/matchers_spec.rb",
@@ -149,6 +155,7 @@ Gem::Specification.new do |s|
149
155
  "spec/associations/collection_proxy_spec.rb",
150
156
  "spec/associations/document_proxy_spec.rb",
151
157
  "spec/associations/hash_proxy_spec.rb",
158
+ "spec/attributes_accessor_spec.rb",
152
159
  "spec/attributes_spec.rb",
153
160
  "spec/bson_matchers.rb",
154
161
  "spec/bson_spec.rb",
@@ -163,6 +170,7 @@ Gem::Specification.new do |s|
163
170
  "spec/document_ext.rb",
164
171
  "spec/document_spec.rb",
165
172
  "spec/embedded_save_spec.rb",
173
+ "spec/ext_spec.rb",
166
174
  "spec/finders_spec.rb",
167
175
  "spec/hash_matchers.rb",
168
176
  "spec/matchers_spec.rb",
@@ -0,0 +1,33 @@
1
+ require 'spec_helper'
2
+
3
+ describe "MongoDoc::Attributes attributes accessor" do
4
+ class AttributesTest
5
+ include MongoDoc::Attributes
6
+
7
+ key :name
8
+ key :age
9
+ key :birthdate
10
+ end
11
+
12
+ context "#attributes" do
13
+ subject do
14
+ AttributesTest.new.attributes
15
+ end
16
+
17
+ it "returns a hash of the given attributes" do
18
+ should have_key(:name)
19
+ should have_key(:age)
20
+ should have_key(:birthdate)
21
+ end
22
+ end
23
+
24
+ context "#attributes=" do
25
+ let(:object) { AttributesTest.new }
26
+
27
+ it "sets attributes from a hash" do
28
+ name = 'name'
29
+ object.attributes = {:name => name}
30
+ object.name.should == name
31
+ end
32
+ end
33
+ end
@@ -1,4 +1,4 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
1
+ require 'spec_helper'
2
2
 
3
3
  describe "MongoDoc::Attributes" do
4
4
  class AttributesTest
@@ -12,22 +12,20 @@ describe "MongoDoc::Attributes" do
12
12
 
13
13
  context ".key" do
14
14
  class TestKeys
15
- include MongoDoc::Document
15
+ include MongoDoc::Attributes
16
+
17
+ key :attr1, :attr2
16
18
  end
17
19
 
18
20
  it "adds its arguments to _keys" do
19
- TestKeys.key :attr1, :attr2
20
21
  TestKeys._keys.should == [:attr1, :attr2]
21
22
  end
22
23
 
23
24
  describe "accessors" do
24
- before do
25
- TestKeys.key :attr1
26
- end
27
-
28
25
  subject do
29
26
  TestKeys.new
30
27
  end
28
+
31
29
  it "has an attr1 reader" do
32
30
  should respond_to(:attr1)
33
31
  end
@@ -37,9 +35,67 @@ describe "MongoDoc::Attributes" do
37
35
  end
38
36
  end
39
37
 
38
+ context "default values" do
39
+ class TestDefault
40
+ include MongoDoc::Attributes
41
+
42
+ key :with_default, :default => 'value'
43
+ end
44
+
45
+ let(:object) { TestDefault.new }
46
+
47
+ it "uses the default value" do
48
+ object.with_default.should == 'value'
49
+ end
50
+
51
+ it "only uses the default value once" do
52
+ object.with_default.should == 'value'
53
+ class << object
54
+ def _default_with_default
55
+ 'other value'
56
+ end
57
+ end
58
+ object.with_default.should == 'value'
59
+ end
60
+
61
+ it "does not set the default value if the setter is invoked first" do
62
+ object.with_default = nil
63
+ object.with_default.should be_nil
64
+ end
65
+ end
66
+
67
+ context "specified type" do
68
+ class TestType
69
+ include MongoDoc::Attributes
70
+
71
+ key :birthdate, :type => Date
72
+ end
73
+
74
+ let(:object) { TestType.new }
75
+
76
+ it "does not call Type.cast_from_string when the set value is not a string" do
77
+ Date.should_not_receive :cast_from_string
78
+ object.birthdate = Date.today
79
+ end
80
+
81
+ context "when the accessor is set with a string" do
82
+ let(:date) { Date.today }
83
+
84
+ it "delegates to Type.cast_from_string to set the value" do
85
+ Date.should_receive(:cast_from_string).with(date.to_s)
86
+ object.birthdate = date.to_s
87
+ end
88
+
89
+ it "sets the value to the result of the case" do
90
+ object.birthdate = date.to_s
91
+ object.birthdate.should == date
92
+ end
93
+ end
94
+ end
95
+
40
96
  describe "used with inheritance" do
41
97
  class TestParent
42
- include MongoDoc::Document
98
+ include MongoDoc::Attributes
43
99
 
44
100
  key :parent_attr
45
101
  end
@@ -17,6 +17,14 @@ describe "MongoDoc::Collection" do
17
17
  MongoDoc::Collection.new('collection_name')
18
18
  end
19
19
 
20
+ it "has Criteria mixed in" do
21
+ MongoDoc::Criteria.should === collection
22
+ end
23
+
24
+ it "#collection references self for Mongo context" do
25
+ collection.send(:collection).should == collection
26
+ end
27
+
20
28
  %w([] clear count create_index db distinct drop drop_index drop_indexes group hint index_information map_reduce mapreduce name options pk_factory remove rename size).each do |delegated_method|
21
29
  it "delegates #{delegated_method} to the Mongo::Collection" do
22
30
  mongo_collection.should_receive(delegated_method)
@@ -1,6 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe "MongoDoc::Contexts::MongoDoc" do
3
+ describe "MongoDoc::Contexts::Mongo" do
4
4
 
5
5
  class Address
6
6
  include MongoDoc::Document
@@ -2,27 +2,55 @@ require "spec_helper"
2
2
 
3
3
  describe MongoDoc::Contexts do
4
4
 
5
+ class ContextTest
6
+ include MongoDoc::Document
7
+
8
+ has_many :children
9
+ end
10
+
5
11
  context ".context_for" do
6
12
  let(:criteria) { stub('criteria', :klass => klass) }
7
13
 
8
14
  context "when criteria is for a top-level MongoDoc::Document" do
9
- let(:klass) { stub('klass', :collection => stub('collection')) }
15
+ let(:klass) { ContextTest }
10
16
 
11
- it "creates a MongoDoc context" do
17
+ it "creates a Mongo context" do
12
18
  MongoDoc::Contexts::Mongo.should_receive(:new).with(criteria)
13
19
  Mongoid::Contexts.context_for(criteria)
14
20
  end
15
21
  end
16
22
 
17
- context "when criteria is for an embedded MongoDoc::Document" do
18
- let(:klass) { stub('klass') }
23
+ context "when criteria is for an association" do
24
+ let(:klass) { ContextTest.new.children }
19
25
 
20
26
  it "creates an Enumerable context" do
21
27
  MongoDoc::Contexts::Enumerable.should_receive(:new).with(criteria)
22
28
  Mongoid::Contexts.context_for(criteria)
23
29
  end
24
30
  end
25
- end
26
31
 
32
+ context "when criteria is for a MongoDoc::Collection" do
33
+ let(:klass) { MongoDoc::Collection.new('collection') }
34
+
35
+ before do
36
+ MongoDoc::Collection.stub(:mongo_collection).and_return(stub('collection'))
37
+ end
38
+
39
+ it "creates a Mongo context" do
40
+ MongoDoc::Contexts::Mongo.should_receive(:new).with(criteria)
41
+ Mongoid::Contexts.context_for(criteria)
42
+ end
43
+ end
44
+
45
+ context "when criteria is not recognized" do
46
+ let(:klass) { Object }
47
+
48
+ it "raises an exception" do
49
+ expect do
50
+ Mongoid::Contexts.context_for(criteria)
51
+ end.should raise_error(Mongoid::Contexts::UnknownContext)
52
+ end
53
+ end
54
+ end
27
55
  end
28
56
 
@@ -4,16 +4,41 @@ describe MongoDoc::Criteria do
4
4
 
5
5
  class CriteriaTest
6
6
  extend MongoDoc::Criteria
7
+
8
+ def self.collection; end
7
9
  end
8
10
 
9
11
  context ".criteria" do
10
- it "creates a new criteria for the document" do
11
- CriteriaTest.criteria.should be_a_kind_of(Mongoid::Criteria)
12
+ it "creates a new CriteriaWrapper for the document" do
13
+ CriteriaTest.criteria.should be_a_kind_of(MongoDoc::Criteria::CriteriaWrapper)
14
+ end
15
+ end
16
+
17
+ context "CriteriaWrapper" do
18
+ let(:wrapper) { MongoDoc::Criteria::CriteriaWrapper.new(CriteriaTest) }
19
+
20
+ it "is a Criteria" do
21
+ Mongoid::Criteria.should === wrapper
12
22
  end
13
23
 
14
24
  it "sets the criteria klass" do
15
- CriteriaTest.criteria.klass.should == CriteriaTest
25
+ wrapper.klass.should == CriteriaTest
26
+ end
27
+
28
+ %w(all and any_in cache enslave excludes fuse in limit offset only order_by skip where).each do |wrapping_method|
29
+ it "#{wrapping_method} returns a new CriteriaWrapper" do
30
+ wrapper.send(wrapping_method).object_id.should_not == wrapper.object_id
31
+ end
32
+ end
33
+
34
+ it "extras returns a new CriteriaWrapper" do
35
+ wrapper.extras({}).object_id.should_not == wrapper.object_id
16
36
  end
37
+
38
+ it "not_in returns a new CriteriaWrapper" do
39
+ wrapper.not_in({}).object_id.should_not == wrapper.object_id
40
+ end
41
+
17
42
  end
18
43
 
19
44
  context "criteria delegates" do
@@ -23,11 +48,22 @@ describe MongoDoc::Criteria do
23
48
  CriteriaTest.stub(:criteria).and_return(criteria)
24
49
  end
25
50
 
26
- %w(and cache enslave excludes extras id in limit not_in offset only order_by page per_page skip where).each do |criteria_op|
51
+ %w(aggregate all and any_in blank? count empty? excludes extras first group id in last limit max min not_in offset one only order_by page paginate per_page skip sum where).each do |criteria_op|
27
52
  it "#{criteria_op} delegates to the criteria" do
28
53
  criteria.should_receive(criteria_op)
29
54
  CriteriaTest.send(criteria_op)
30
55
  end
31
56
  end
32
57
  end
58
+
59
+ context "criteria are reusable" do
60
+ it "creates a new instance on each invocation" do
61
+ original = CriteriaTest.any_in(:name => 'Les Hill')
62
+ chained = original.only(:name)
63
+ original.should_not == chained
64
+ end
65
+ end
66
+
67
+
68
+
33
69
  end
@@ -33,24 +33,9 @@ describe "MongoDoc::Document" do
33
33
  end
34
34
  end
35
35
 
36
- context "attributes" do
37
- it "has an initialize method that takes a hash" do
38
- data = 'data'
39
- FormForTest.new(:data => data).data.should == data
40
- end
41
-
42
- it "can set attributes from a hash" do
43
- test = FormForTest.new
44
- data = 'data'
45
- test.attributes = {:data => data}
46
- test.data.should == data
47
- end
48
-
49
- it "returns all its attributes" do
50
- data = 'data'
51
- test = FormForTest.new(:data => data)
52
- test.attributes.should == {:data => data}
53
- end
36
+ it "#initialize takes a hash" do
37
+ data = 'data'
38
+ FormForTest.new(:data => data).data.should == data
54
39
  end
55
40
  end
56
41
 
@@ -238,8 +223,8 @@ describe "MongoDoc::Document" do
238
223
  CreateTest.stub(:new).and_return(instance)
239
224
  end
240
225
 
241
- it "calls save on the instance with safe => false" do
242
- instance.should_receive(:save).with(false)
226
+ it "calls save on the instance with validate => true" do
227
+ instance.should_receive(:save).with(true)
243
228
  CreateTest.create(:data => data)
244
229
  end
245
230
 
@@ -261,7 +246,7 @@ describe "MongoDoc::Document" do
261
246
  end
262
247
 
263
248
  it "calls save! on the instance" do
264
- instance.should_receive(:save!)
249
+ instance.should_receive(:save!).with(no_args)
265
250
  CreateTest.create!(:data => data)
266
251
  end
267
252
 
data/spec/ext_spec.rb ADDED
@@ -0,0 +1,81 @@
1
+ require 'spec_helper.rb'
2
+
3
+ describe "Ruby Object Extensions" do
4
+ context "Conversions" do
5
+ context "Boolean" do
6
+ it "converts from a '1' to true" do
7
+ Boolean.cast_from_string('1').should be_true
8
+ end
9
+
10
+ it "converts from a 'tRuE' to true" do
11
+ Boolean.cast_from_string('tRuE').should be_true
12
+ end
13
+
14
+ it "converts anything else to false" do
15
+ Boolean.cast_from_string('0').should be_false
16
+ end
17
+ end
18
+
19
+ context "Date" do
20
+ it "returns nil for a blank string" do
21
+ Date.cast_from_string('').should be_nil
22
+ end
23
+
24
+ it "converts from a string to a Date" do
25
+ date = Date.today
26
+ Date.cast_from_string(date.to_s).should == date
27
+ end
28
+ end
29
+
30
+ context "DateTime" do
31
+ it "returns nil for a blank string" do
32
+ DateTime.cast_from_string('').should be_nil
33
+ end
34
+
35
+ it "converts from a string to a DateTime" do
36
+ datetime = DateTime.now
37
+ DateTime.cast_from_string(datetime.to_s).should === datetime
38
+ end
39
+ end
40
+
41
+ context "Numeric" do
42
+ context "BigDecimal" do
43
+ it "returns nil for a blank string" do
44
+ BigDecimal.cast_from_string('').should be_nil
45
+ end
46
+
47
+ it "converts from a string to a BigDecimal" do
48
+ big_decimal = BigDecimal.new("123")
49
+ BigDecimal.cast_from_string(big_decimal.to_s).should == big_decimal
50
+ end
51
+ end
52
+
53
+ context "Integer" do
54
+ it "returns nil for a blank string" do
55
+ Integer.cast_from_string('').should be_nil
56
+ end
57
+
58
+ it "converts from a string to a Bignum" do
59
+ big_number = 1000000000000
60
+ Integer.cast_from_string(big_number.to_s).should == big_number
61
+ end
62
+
63
+ it "converts from a string to a Fixnum" do
64
+ fixnum = 1
65
+ Integer.cast_from_string(fixnum.to_s).should == fixnum
66
+ end
67
+ end
68
+ end
69
+
70
+ context "Time" do
71
+ it "returns nil for a blank string" do
72
+ Time.cast_from_string('').should be_nil
73
+ end
74
+
75
+ it "converts from a string to a Time" do
76
+ time = Time.now
77
+ Time.cast_from_string(time.to_s).to_s.should == time.to_s
78
+ end
79
+ end
80
+ end
81
+ end
data/spec/finders_spec.rb CHANGED
@@ -58,16 +58,4 @@ describe MongoDoc::Finders do
58
58
  end
59
59
  end
60
60
 
61
- context "all other finders" do
62
- before do
63
- FindersTest.stub(:criteria).and_return(criteria)
64
- end
65
-
66
- %w(count first last).each do |which|
67
- it "calls #{which} on the new criteria" do
68
- criteria.should_receive(which)
69
- FindersTest.send(which)
70
- end
71
- end
72
- end
73
61
  end
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 3
8
- - 1
9
- version: 0.3.1
8
+ - 2
9
+ version: 0.3.2
10
10
  platform: ruby
11
11
  authors:
12
12
  - Les Hill
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-03-06 00:00:00 -05:00
17
+ date: 2010-03-11 00:00:00 -05:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
@@ -134,6 +134,7 @@ files:
134
134
  - data/.gitignore
135
135
  - examples/simple_document.rb
136
136
  - examples/simple_object.rb
137
+ - features/collections.feature
137
138
  - features/finders.feature
138
139
  - features/mongodb.yml
139
140
  - features/mongodoc_base.feature
@@ -153,7 +154,9 @@ files:
153
154
  - features/step_definitions/query_steps.rb
154
155
  - features/step_definitions/removing_documents_steps.rb
155
156
  - features/step_definitions/scope_steps.rb
157
+ - features/step_definitions/string_casting_steps.rb
156
158
  - features/step_definitions/util_steps.rb
159
+ - features/string_casting.feature
157
160
  - features/support/support.rb
158
161
  - features/using_criteria.feature
159
162
  - lib/mongo_doc.rb
@@ -172,6 +175,7 @@ files:
172
175
  - lib/mongo_doc/criteria.rb
173
176
  - lib/mongo_doc/cursor.rb
174
177
  - lib/mongo_doc/document.rb
178
+ - lib/mongo_doc/ext.rb
175
179
  - lib/mongo_doc/ext/array.rb
176
180
  - lib/mongo_doc/ext/binary.rb
177
181
  - lib/mongo_doc/ext/boolean_class.rb
@@ -221,6 +225,7 @@ files:
221
225
  - spec/associations/collection_proxy_spec.rb
222
226
  - spec/associations/document_proxy_spec.rb
223
227
  - spec/associations/hash_proxy_spec.rb
228
+ - spec/attributes_accessor_spec.rb
224
229
  - spec/attributes_spec.rb
225
230
  - spec/bson_matchers.rb
226
231
  - spec/bson_spec.rb
@@ -235,6 +240,7 @@ files:
235
240
  - spec/document_ext.rb
236
241
  - spec/document_spec.rb
237
242
  - spec/embedded_save_spec.rb
243
+ - spec/ext_spec.rb
238
244
  - spec/finders_spec.rb
239
245
  - spec/hash_matchers.rb
240
246
  - spec/matchers_spec.rb
@@ -279,6 +285,7 @@ test_files:
279
285
  - spec/associations/collection_proxy_spec.rb
280
286
  - spec/associations/document_proxy_spec.rb
281
287
  - spec/associations/hash_proxy_spec.rb
288
+ - spec/attributes_accessor_spec.rb
282
289
  - spec/attributes_spec.rb
283
290
  - spec/bson_matchers.rb
284
291
  - spec/bson_spec.rb
@@ -293,6 +300,7 @@ test_files:
293
300
  - spec/document_ext.rb
294
301
  - spec/document_spec.rb
295
302
  - spec/embedded_save_spec.rb
303
+ - spec/ext_spec.rb
296
304
  - spec/finders_spec.rb
297
305
  - spec/hash_matchers.rb
298
306
  - spec/matchers_spec.rb