humanoid 1.2.7
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/.gitignore +6 -0
- data/.watchr +29 -0
- data/HISTORY +342 -0
- data/MIT_LICENSE +20 -0
- data/README.rdoc +56 -0
- data/Rakefile +53 -0
- data/VERSION +1 -0
- data/caliper.yml +4 -0
- data/humanoid.gemspec +374 -0
- data/lib/humanoid.rb +111 -0
- data/lib/humanoid/associations.rb +258 -0
- data/lib/humanoid/associations/belongs_to.rb +64 -0
- data/lib/humanoid/associations/belongs_to_related.rb +62 -0
- data/lib/humanoid/associations/has_many.rb +180 -0
- data/lib/humanoid/associations/has_many_related.rb +109 -0
- data/lib/humanoid/associations/has_one.rb +95 -0
- data/lib/humanoid/associations/has_one_related.rb +81 -0
- data/lib/humanoid/associations/options.rb +57 -0
- data/lib/humanoid/associations/proxy.rb +31 -0
- data/lib/humanoid/attributes.rb +184 -0
- data/lib/humanoid/callbacks.rb +23 -0
- data/lib/humanoid/collection.rb +118 -0
- data/lib/humanoid/collections/cyclic_iterator.rb +34 -0
- data/lib/humanoid/collections/master.rb +28 -0
- data/lib/humanoid/collections/mimic.rb +46 -0
- data/lib/humanoid/collections/operations.rb +41 -0
- data/lib/humanoid/collections/slaves.rb +44 -0
- data/lib/humanoid/commands.rb +182 -0
- data/lib/humanoid/commands/create.rb +21 -0
- data/lib/humanoid/commands/delete.rb +16 -0
- data/lib/humanoid/commands/delete_all.rb +23 -0
- data/lib/humanoid/commands/deletion.rb +18 -0
- data/lib/humanoid/commands/destroy.rb +19 -0
- data/lib/humanoid/commands/destroy_all.rb +23 -0
- data/lib/humanoid/commands/save.rb +27 -0
- data/lib/humanoid/components.rb +24 -0
- data/lib/humanoid/config.rb +84 -0
- data/lib/humanoid/contexts.rb +25 -0
- data/lib/humanoid/contexts/enumerable.rb +117 -0
- data/lib/humanoid/contexts/ids.rb +25 -0
- data/lib/humanoid/contexts/mongo.rb +224 -0
- data/lib/humanoid/contexts/paging.rb +42 -0
- data/lib/humanoid/criteria.rb +259 -0
- data/lib/humanoid/criterion/complex.rb +21 -0
- data/lib/humanoid/criterion/exclusion.rb +65 -0
- data/lib/humanoid/criterion/inclusion.rb +91 -0
- data/lib/humanoid/criterion/optional.rb +128 -0
- data/lib/humanoid/cursor.rb +82 -0
- data/lib/humanoid/document.rb +300 -0
- data/lib/humanoid/enslavement.rb +38 -0
- data/lib/humanoid/errors.rb +77 -0
- data/lib/humanoid/extensions.rb +84 -0
- data/lib/humanoid/extensions/array/accessors.rb +17 -0
- data/lib/humanoid/extensions/array/aliasing.rb +4 -0
- data/lib/humanoid/extensions/array/assimilation.rb +26 -0
- data/lib/humanoid/extensions/array/conversions.rb +29 -0
- data/lib/humanoid/extensions/array/parentization.rb +13 -0
- data/lib/humanoid/extensions/boolean/conversions.rb +16 -0
- data/lib/humanoid/extensions/date/conversions.rb +15 -0
- data/lib/humanoid/extensions/datetime/conversions.rb +17 -0
- data/lib/humanoid/extensions/float/conversions.rb +16 -0
- data/lib/humanoid/extensions/hash/accessors.rb +38 -0
- data/lib/humanoid/extensions/hash/assimilation.rb +30 -0
- data/lib/humanoid/extensions/hash/conversions.rb +15 -0
- data/lib/humanoid/extensions/hash/criteria_helpers.rb +20 -0
- data/lib/humanoid/extensions/hash/scoping.rb +12 -0
- data/lib/humanoid/extensions/integer/conversions.rb +16 -0
- data/lib/humanoid/extensions/nil/assimilation.rb +13 -0
- data/lib/humanoid/extensions/object/conversions.rb +33 -0
- data/lib/humanoid/extensions/proc/scoping.rb +12 -0
- data/lib/humanoid/extensions/string/conversions.rb +15 -0
- data/lib/humanoid/extensions/string/inflections.rb +97 -0
- data/lib/humanoid/extensions/symbol/inflections.rb +36 -0
- data/lib/humanoid/extensions/time/conversions.rb +18 -0
- data/lib/humanoid/factory.rb +19 -0
- data/lib/humanoid/field.rb +39 -0
- data/lib/humanoid/fields.rb +62 -0
- data/lib/humanoid/finders.rb +224 -0
- data/lib/humanoid/identity.rb +39 -0
- data/lib/humanoid/indexes.rb +30 -0
- data/lib/humanoid/matchers.rb +36 -0
- data/lib/humanoid/matchers/all.rb +11 -0
- data/lib/humanoid/matchers/default.rb +26 -0
- data/lib/humanoid/matchers/exists.rb +13 -0
- data/lib/humanoid/matchers/gt.rb +11 -0
- data/lib/humanoid/matchers/gte.rb +11 -0
- data/lib/humanoid/matchers/in.rb +11 -0
- data/lib/humanoid/matchers/lt.rb +11 -0
- data/lib/humanoid/matchers/lte.rb +11 -0
- data/lib/humanoid/matchers/ne.rb +11 -0
- data/lib/humanoid/matchers/nin.rb +11 -0
- data/lib/humanoid/matchers/size.rb +11 -0
- data/lib/humanoid/memoization.rb +27 -0
- data/lib/humanoid/named_scope.rb +40 -0
- data/lib/humanoid/scope.rb +75 -0
- data/lib/humanoid/timestamps.rb +30 -0
- data/lib/humanoid/versioning.rb +28 -0
- data/perf/benchmark.rb +77 -0
- data/spec/integration/humanoid/associations_spec.rb +301 -0
- data/spec/integration/humanoid/attributes_spec.rb +22 -0
- data/spec/integration/humanoid/commands_spec.rb +216 -0
- data/spec/integration/humanoid/contexts/enumerable_spec.rb +33 -0
- data/spec/integration/humanoid/criteria_spec.rb +224 -0
- data/spec/integration/humanoid/document_spec.rb +587 -0
- data/spec/integration/humanoid/extensions_spec.rb +26 -0
- data/spec/integration/humanoid/finders_spec.rb +119 -0
- data/spec/integration/humanoid/inheritance_spec.rb +137 -0
- data/spec/integration/humanoid/named_scope_spec.rb +46 -0
- data/spec/models/address.rb +39 -0
- data/spec/models/animal.rb +6 -0
- data/spec/models/comment.rb +8 -0
- data/spec/models/country_code.rb +6 -0
- data/spec/models/employer.rb +5 -0
- data/spec/models/game.rb +6 -0
- data/spec/models/inheritance.rb +56 -0
- data/spec/models/location.rb +5 -0
- data/spec/models/mixed_drink.rb +4 -0
- data/spec/models/name.rb +13 -0
- data/spec/models/namespacing.rb +11 -0
- data/spec/models/patient.rb +4 -0
- data/spec/models/person.rb +98 -0
- data/spec/models/pet.rb +7 -0
- data/spec/models/pet_owner.rb +6 -0
- data/spec/models/phone.rb +7 -0
- data/spec/models/post.rb +15 -0
- data/spec/models/translation.rb +5 -0
- data/spec/models/vet_visit.rb +5 -0
- data/spec/spec.opts +3 -0
- data/spec/spec_helper.rb +31 -0
- data/spec/unit/mongoid/associations/belongs_to_related_spec.rb +141 -0
- data/spec/unit/mongoid/associations/belongs_to_spec.rb +193 -0
- data/spec/unit/mongoid/associations/has_many_related_spec.rb +387 -0
- data/spec/unit/mongoid/associations/has_many_spec.rb +471 -0
- data/spec/unit/mongoid/associations/has_one_related_spec.rb +179 -0
- data/spec/unit/mongoid/associations/has_one_spec.rb +282 -0
- data/spec/unit/mongoid/associations/options_spec.rb +191 -0
- data/spec/unit/mongoid/associations_spec.rb +545 -0
- data/spec/unit/mongoid/attributes_spec.rb +484 -0
- data/spec/unit/mongoid/callbacks_spec.rb +55 -0
- data/spec/unit/mongoid/collection_spec.rb +171 -0
- data/spec/unit/mongoid/collections/cyclic_iterator_spec.rb +75 -0
- data/spec/unit/mongoid/collections/master_spec.rb +41 -0
- data/spec/unit/mongoid/collections/mimic_spec.rb +43 -0
- data/spec/unit/mongoid/collections/slaves_spec.rb +81 -0
- data/spec/unit/mongoid/commands/create_spec.rb +30 -0
- data/spec/unit/mongoid/commands/delete_all_spec.rb +58 -0
- data/spec/unit/mongoid/commands/delete_spec.rb +35 -0
- data/spec/unit/mongoid/commands/destroy_all_spec.rb +23 -0
- data/spec/unit/mongoid/commands/destroy_spec.rb +44 -0
- data/spec/unit/mongoid/commands/save_spec.rb +105 -0
- data/spec/unit/mongoid/commands_spec.rb +282 -0
- data/spec/unit/mongoid/config_spec.rb +165 -0
- data/spec/unit/mongoid/contexts/enumerable_spec.rb +374 -0
- data/spec/unit/mongoid/contexts/mongo_spec.rb +505 -0
- data/spec/unit/mongoid/contexts_spec.rb +25 -0
- data/spec/unit/mongoid/criteria_spec.rb +769 -0
- data/spec/unit/mongoid/criterion/complex_spec.rb +19 -0
- data/spec/unit/mongoid/criterion/exclusion_spec.rb +91 -0
- data/spec/unit/mongoid/criterion/inclusion_spec.rb +211 -0
- data/spec/unit/mongoid/criterion/optional_spec.rb +329 -0
- data/spec/unit/mongoid/cursor_spec.rb +74 -0
- data/spec/unit/mongoid/document_spec.rb +986 -0
- data/spec/unit/mongoid/enslavement_spec.rb +63 -0
- data/spec/unit/mongoid/errors_spec.rb +103 -0
- data/spec/unit/mongoid/extensions/array/accessors_spec.rb +50 -0
- data/spec/unit/mongoid/extensions/array/assimilation_spec.rb +24 -0
- data/spec/unit/mongoid/extensions/array/conversions_spec.rb +35 -0
- data/spec/unit/mongoid/extensions/array/parentization_spec.rb +20 -0
- data/spec/unit/mongoid/extensions/boolean/conversions_spec.rb +49 -0
- data/spec/unit/mongoid/extensions/date/conversions_spec.rb +102 -0
- data/spec/unit/mongoid/extensions/datetime/conversions_spec.rb +70 -0
- data/spec/unit/mongoid/extensions/float/conversions_spec.rb +61 -0
- data/spec/unit/mongoid/extensions/hash/accessors_spec.rb +184 -0
- data/spec/unit/mongoid/extensions/hash/assimilation_spec.rb +46 -0
- data/spec/unit/mongoid/extensions/hash/conversions_spec.rb +21 -0
- data/spec/unit/mongoid/extensions/hash/criteria_helpers_spec.rb +17 -0
- data/spec/unit/mongoid/extensions/hash/scoping_spec.rb +14 -0
- data/spec/unit/mongoid/extensions/integer/conversions_spec.rb +61 -0
- data/spec/unit/mongoid/extensions/nil/assimilation_spec.rb +24 -0
- data/spec/unit/mongoid/extensions/object/conversions_spec.rb +43 -0
- data/spec/unit/mongoid/extensions/proc/scoping_spec.rb +34 -0
- data/spec/unit/mongoid/extensions/string/conversions_spec.rb +17 -0
- data/spec/unit/mongoid/extensions/string/inflections_spec.rb +208 -0
- data/spec/unit/mongoid/extensions/symbol/inflections_spec.rb +91 -0
- data/spec/unit/mongoid/extensions/time/conversions_spec.rb +70 -0
- data/spec/unit/mongoid/factory_spec.rb +31 -0
- data/spec/unit/mongoid/field_spec.rb +81 -0
- data/spec/unit/mongoid/fields_spec.rb +158 -0
- data/spec/unit/mongoid/finders_spec.rb +368 -0
- data/spec/unit/mongoid/identity_spec.rb +88 -0
- data/spec/unit/mongoid/indexes_spec.rb +93 -0
- data/spec/unit/mongoid/matchers/all_spec.rb +27 -0
- data/spec/unit/mongoid/matchers/default_spec.rb +27 -0
- data/spec/unit/mongoid/matchers/exists_spec.rb +56 -0
- data/spec/unit/mongoid/matchers/gt_spec.rb +39 -0
- data/spec/unit/mongoid/matchers/gte_spec.rb +49 -0
- data/spec/unit/mongoid/matchers/in_spec.rb +27 -0
- data/spec/unit/mongoid/matchers/lt_spec.rb +39 -0
- data/spec/unit/mongoid/matchers/lte_spec.rb +49 -0
- data/spec/unit/mongoid/matchers/ne_spec.rb +27 -0
- data/spec/unit/mongoid/matchers/nin_spec.rb +27 -0
- data/spec/unit/mongoid/matchers/size_spec.rb +27 -0
- data/spec/unit/mongoid/matchers_spec.rb +329 -0
- data/spec/unit/mongoid/memoization_spec.rb +75 -0
- data/spec/unit/mongoid/named_scope_spec.rb +123 -0
- data/spec/unit/mongoid/scope_spec.rb +240 -0
- data/spec/unit/mongoid/timestamps_spec.rb +25 -0
- data/spec/unit/mongoid/versioning_spec.rb +41 -0
- data/spec/unit/mongoid_spec.rb +37 -0
- metadata +431 -0
data/perf/benchmark.rb
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
require "rubygems"
|
|
2
|
+
require "ruby-prof"
|
|
3
|
+
require "benchmark"
|
|
4
|
+
require "humanoid"
|
|
5
|
+
|
|
6
|
+
Humanoid.configure do |config|
|
|
7
|
+
config.persist_in_safe_mode = false
|
|
8
|
+
config.master = Mongo::Connection.new.db("humanoid_perf_test")
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
Humanoid.master.collection("people").drop
|
|
12
|
+
|
|
13
|
+
class Person
|
|
14
|
+
include Humanoid::Document
|
|
15
|
+
include Humanoid::Timestamps
|
|
16
|
+
field :birth_date, :type => Date
|
|
17
|
+
has_one :name
|
|
18
|
+
has_one :address
|
|
19
|
+
has_many :phones
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
class Name
|
|
23
|
+
include Humanoid::Document
|
|
24
|
+
field :given
|
|
25
|
+
field :family
|
|
26
|
+
field :middle
|
|
27
|
+
belongs_to :person, :inverse_of => :name
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
class Address
|
|
31
|
+
include Humanoid::Document
|
|
32
|
+
field :street
|
|
33
|
+
field :city
|
|
34
|
+
field :state
|
|
35
|
+
field :post_code
|
|
36
|
+
field :address_type
|
|
37
|
+
belongs_to :person, :inverse_of => :address
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
class Phone
|
|
41
|
+
include Humanoid::Document
|
|
42
|
+
field :country_code, :type => Integer
|
|
43
|
+
field :number
|
|
44
|
+
field :phone_type
|
|
45
|
+
belongs_to :person, :inverse_of => :phones
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# RubyProf.start
|
|
49
|
+
|
|
50
|
+
puts "Starting benchmark..."
|
|
51
|
+
|
|
52
|
+
Benchmark.bm do |bm|
|
|
53
|
+
bm.report("Humanoid") do
|
|
54
|
+
10000.times do |n|
|
|
55
|
+
person = Person.new(:birth_date => Date.new(1970, 1, 1))
|
|
56
|
+
name = Name.new(:given => "James", :family => "Kirk", :middle => "Tiberius")
|
|
57
|
+
address = Address.new(
|
|
58
|
+
:street => "1 Starfleet Command Way",
|
|
59
|
+
:city => "San Francisco",
|
|
60
|
+
:state => "CA",
|
|
61
|
+
:post_code => "94133",
|
|
62
|
+
:type => "Work"
|
|
63
|
+
)
|
|
64
|
+
phone = Phone.new(:country_code => 1, :number => "415-555-1212", :type => "Mobile")
|
|
65
|
+
person.name = name
|
|
66
|
+
person.address = address
|
|
67
|
+
person.phones << phone
|
|
68
|
+
person.save
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# result = RubyProf.stop
|
|
74
|
+
# printer = RubyProf::FlatPrinter.new(result)
|
|
75
|
+
# printer.print(STDOUT, 0)
|
|
76
|
+
|
|
77
|
+
# Humanoid.database.collection("people").drop
|
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
require "spec_helper"
|
|
2
|
+
|
|
3
|
+
describe Humanoid::Associations do
|
|
4
|
+
|
|
5
|
+
before do
|
|
6
|
+
Person.delete_all
|
|
7
|
+
Game.delete_all
|
|
8
|
+
Post.delete_all
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
context "anonymous extensions" do
|
|
12
|
+
|
|
13
|
+
before do
|
|
14
|
+
@person = Person.new(:title => "Dr")
|
|
15
|
+
@address_one = Address.new(:street => "Oxford")
|
|
16
|
+
@address_two = Address.new(:street => "Bond")
|
|
17
|
+
@name = Name.new(:first_name => "Richard", :last_name => "Dawkins")
|
|
18
|
+
@person.addresses << [ @address_one, @address_two ]
|
|
19
|
+
@person.name = @name
|
|
20
|
+
@person.save
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
context "when defined on a has_many" do
|
|
24
|
+
|
|
25
|
+
it "applies the extension" do
|
|
26
|
+
addresses = @person.addresses.find_by_street("Oxford")
|
|
27
|
+
addresses.size.should == 1
|
|
28
|
+
addresses.first.should == @address_one
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
context "when defined on a has_one" do
|
|
34
|
+
|
|
35
|
+
it "applies the extension" do
|
|
36
|
+
name = @person.name
|
|
37
|
+
name.dawkins?.should be_true
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
context "when defined on a belongs_to" do
|
|
43
|
+
|
|
44
|
+
it "applies the extension" do
|
|
45
|
+
@address_two.addressable.doctor?.should be_true
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
context "criteria on has many embedded associations" do
|
|
53
|
+
|
|
54
|
+
before do
|
|
55
|
+
@person = Person.new(:title => "Sir")
|
|
56
|
+
@sf_apartment = Address.new(:street => "Genoa Pl", :state => "CA", :address_type => "Apartment")
|
|
57
|
+
@la_home = Address.new(:street => "Rodeo Dr", :state => "CA", :address_type => "Home")
|
|
58
|
+
@sf_home = Address.new(:street => "Pacific", :state => "CA", :address_type => "Home")
|
|
59
|
+
@person.addresses << [ @sf_apartment, @la_home, @sf_home ]
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
it "handles a single criteria" do
|
|
63
|
+
cas = @person.addresses.california
|
|
64
|
+
cas.size.should == 3
|
|
65
|
+
cas.should == [ @sf_apartment, @la_home, @sf_home ]
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
it "handles chained criteria" do
|
|
69
|
+
ca_homes = @person.addresses.california.homes
|
|
70
|
+
ca_homes.size.should == 2
|
|
71
|
+
ca_homes.should == [ @la_home, @sf_home ]
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
it "handles chained criteria with named scopes" do
|
|
75
|
+
ca_homes = @person.addresses.california.homes.rodeo
|
|
76
|
+
ca_homes.size.should == 1
|
|
77
|
+
ca_homes.should == [ @la_home ]
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
context "one-to-one relational associations" do
|
|
83
|
+
|
|
84
|
+
before do
|
|
85
|
+
@person = Person.new(:title => "Sir")
|
|
86
|
+
@game = Game.new(:score => 1)
|
|
87
|
+
@person.game = @game
|
|
88
|
+
@person.save
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
it "sets the association on save" do
|
|
92
|
+
@from_db = Person.find(@person.id)
|
|
93
|
+
@from_db.game.should == @game
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
it "sets the reverse association before save" do
|
|
97
|
+
@game.person.should == @person
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
it "sets the reverse association after save" do
|
|
101
|
+
@from_db = Game.find(@game.id)
|
|
102
|
+
@game.person.should == @person
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
context "one-to-many relational associations" do
|
|
108
|
+
|
|
109
|
+
before do
|
|
110
|
+
@person = Person.new(:title => "Sir")
|
|
111
|
+
@post = Post.new(:title => "Testing")
|
|
112
|
+
@person.posts = [@post]
|
|
113
|
+
@person.save
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
it "sets the association on save" do
|
|
117
|
+
from_db = Person.find(@person.id)
|
|
118
|
+
from_db.posts.should == [@post]
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
context "when adding a new association" do
|
|
122
|
+
|
|
123
|
+
before do
|
|
124
|
+
@new_post = Post.new(:title => "New")
|
|
125
|
+
@person.posts << @new_post
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
it "rememoizes the new association" do
|
|
129
|
+
@person.posts.should == [ @post, @new_post ]
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
context "when building" do
|
|
134
|
+
|
|
135
|
+
before do
|
|
136
|
+
@person = Person.new(:title => "Mr")
|
|
137
|
+
@post = @person.posts.build(:title => "First")
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
it "sets the reverse association" do
|
|
141
|
+
@post.person.should == @person
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
context "finding associated objects" do
|
|
147
|
+
|
|
148
|
+
before do
|
|
149
|
+
@extra_post = Post.create(:title => "Orphan")
|
|
150
|
+
@from_db = Person.find(@person.id)
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
context "finding all" do
|
|
154
|
+
|
|
155
|
+
it "returns only those objects scoped to the parent" do
|
|
156
|
+
Post.all.size.should == 2
|
|
157
|
+
@from_db.posts.all.size.should == 1
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
context "finding with conditions" do
|
|
163
|
+
|
|
164
|
+
context "finding all" do
|
|
165
|
+
|
|
166
|
+
it "returns only those objects scoped to the parent" do
|
|
167
|
+
posts = @from_db.posts.find(:all, :conditions => { :title => "Testing" })
|
|
168
|
+
posts.size.should == 1
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
context "finding first" do
|
|
174
|
+
|
|
175
|
+
it "returns only those objects scoped to the parent" do
|
|
176
|
+
post = @from_db.posts.find(:first, :conditions => { :title => "Testing" })
|
|
177
|
+
post.should == @post
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
context "finding last" do
|
|
183
|
+
|
|
184
|
+
it "returns only those objects scoped to the parent" do
|
|
185
|
+
post = @from_db.posts.find(:last, :conditions => { :title => "Testing" })
|
|
186
|
+
post.should == @post
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
context "using a named scope" do
|
|
192
|
+
|
|
193
|
+
before do
|
|
194
|
+
@post.created_at = 15.days.ago
|
|
195
|
+
@post.save
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
it "returns only those scoped to the parent plus the named scope" do
|
|
199
|
+
posts = @from_db.posts.recent
|
|
200
|
+
posts.size.should == 1
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
context "using a criteria class method" do
|
|
206
|
+
|
|
207
|
+
before do
|
|
208
|
+
@post.created_at = 45.days.ago
|
|
209
|
+
@post.save
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
it "returns only those scoped to the parent plus the named scope" do
|
|
213
|
+
posts = @from_db.posts.old
|
|
214
|
+
posts.size.should == 1
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
context "nested embedded associations" do
|
|
226
|
+
|
|
227
|
+
before do
|
|
228
|
+
@person = Person.create(:title => "Mr")
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
context "one level nested" do
|
|
232
|
+
|
|
233
|
+
before do
|
|
234
|
+
@address = @person.addresses.create(:street => "Oxford St")
|
|
235
|
+
@name = @person.create_name(:first_name => "Gordon")
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
it "persists all the associations properly" do
|
|
239
|
+
@name.last_name = "Brown"
|
|
240
|
+
@person.name.last_name.should == "Brown"
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
context "multiple levels nested" do
|
|
246
|
+
|
|
247
|
+
context "when a has-many to has_one" do
|
|
248
|
+
|
|
249
|
+
before do
|
|
250
|
+
@person.phone_numbers.create(:number => "4155551212")
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
it "persists all the associations properly" do
|
|
254
|
+
from_db = Person.find(@person.id)
|
|
255
|
+
phone = from_db.phone_numbers.first
|
|
256
|
+
phone.create_country_code(:code => 1)
|
|
257
|
+
from_db.phone_numbers.first.country_code.code.should == 1
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
context "when a has-one to has-many" do
|
|
263
|
+
|
|
264
|
+
before do
|
|
265
|
+
@person = Person.new(:title => "Sir", :ssn => "1")
|
|
266
|
+
@name = Name.new(:first_name => "Syd")
|
|
267
|
+
@person.name = @name
|
|
268
|
+
@person.save
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
it "persists all the associations properly" do
|
|
272
|
+
from_db = Person.find(@person.id)
|
|
273
|
+
translation = Translation.new(:language => "fr")
|
|
274
|
+
from_db.name.translations << translation
|
|
275
|
+
from_db.attributes[:name][:translations].should_not be_nil
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
end
|
|
279
|
+
|
|
280
|
+
context "when a has-many to has-many" do
|
|
281
|
+
|
|
282
|
+
before do
|
|
283
|
+
@address = Address.new(:street => "Upper Street")
|
|
284
|
+
@person.addresses << @address
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
it "bubbles the child association up to root" do
|
|
288
|
+
location = Location.new(:name => "Home")
|
|
289
|
+
@address.locations << location
|
|
290
|
+
location.stubs(:valid?).returns(false)
|
|
291
|
+
@person.save
|
|
292
|
+
@person.addresses.first.locations.first.should == location
|
|
293
|
+
end
|
|
294
|
+
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
end
|
|
298
|
+
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
require "spec_helper"
|
|
2
|
+
|
|
3
|
+
describe Humanoid::Attributes do
|
|
4
|
+
|
|
5
|
+
context "when persisting nil attributes" do
|
|
6
|
+
|
|
7
|
+
before do
|
|
8
|
+
@person = Person.create(:score => nil, :ssn => "555-66-7777")
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
after do
|
|
12
|
+
Person.delete_all
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
it "the field should not exist" do
|
|
16
|
+
from_db = Person.find(@person.id)
|
|
17
|
+
from_db.attributes.has_key?(:score).should be_false
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
end
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
require "spec_helper"
|
|
2
|
+
|
|
3
|
+
describe Humanoid::Commands do
|
|
4
|
+
|
|
5
|
+
before do
|
|
6
|
+
@person = Person.new(:title => "Sir", :ssn => "6969696")
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
after do
|
|
10
|
+
@person.delete
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
describe ".create" do
|
|
14
|
+
|
|
15
|
+
it "saves and returns the document" do
|
|
16
|
+
person = Person.create(:title => "Sensei", :ssn => "666-66-6666")
|
|
17
|
+
person.should be_a_kind_of(Person)
|
|
18
|
+
person.should_not be_a_new_record
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
describe ".create!" do
|
|
24
|
+
|
|
25
|
+
context "inserting with a field that is not unique" do
|
|
26
|
+
|
|
27
|
+
context "when a unique index exists" do
|
|
28
|
+
|
|
29
|
+
after do
|
|
30
|
+
Person.delete_all
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
it "raises an error" do
|
|
34
|
+
Person.create!(:ssn => "555-55-9999")
|
|
35
|
+
lambda { Person.create!(:ssn => "555-55-9999") }.should raise_error
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
describe "#delete" do
|
|
45
|
+
|
|
46
|
+
context "deleting a root document" do
|
|
47
|
+
|
|
48
|
+
before do
|
|
49
|
+
@person.save
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
it "deletes the document" do
|
|
53
|
+
@person.delete
|
|
54
|
+
lambda { Person.find(@person.id) }.should raise_error
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
it "returns true" do
|
|
58
|
+
@person.delete.should be_true
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
context "deleting an embedded document" do
|
|
64
|
+
|
|
65
|
+
before do
|
|
66
|
+
@address = Address.new(:street => "Bond Street")
|
|
67
|
+
@person.addresses << @address
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
context "when the document is not yet saved" do
|
|
71
|
+
|
|
72
|
+
it "removes the document from the parent" do
|
|
73
|
+
@address.delete
|
|
74
|
+
@person.addresses.should be_empty
|
|
75
|
+
@person.attributes[:addresses].should be_empty
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
context "when the document has been saved" do
|
|
81
|
+
|
|
82
|
+
before do
|
|
83
|
+
@address.save
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
it "removes the object from the parent and database" do
|
|
87
|
+
@address.delete
|
|
88
|
+
from_db = Person.find(@person.id)
|
|
89
|
+
from_db.addresses.should be_empty
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
describe "#destroy" do
|
|
99
|
+
|
|
100
|
+
context "destroying a root document" do
|
|
101
|
+
|
|
102
|
+
before do
|
|
103
|
+
@person.save
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
it "destroys the document" do
|
|
107
|
+
@person.destroy
|
|
108
|
+
lambda { Person.find(@person.id) }.should raise_error
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
it "returns true" do
|
|
112
|
+
@person.destroy.should be_true
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
context "deleting an embedded document" do
|
|
118
|
+
|
|
119
|
+
before do
|
|
120
|
+
@address = Address.new(:street => "Bond Street")
|
|
121
|
+
@person.addresses << @address
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
context "when the document is not yet saved" do
|
|
125
|
+
|
|
126
|
+
it "removes the document from the parent" do
|
|
127
|
+
@address.destroy
|
|
128
|
+
@person.addresses.should be_empty
|
|
129
|
+
@person.attributes[:addresses].should be_empty
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
context "when the document has been saved" do
|
|
135
|
+
|
|
136
|
+
before do
|
|
137
|
+
@address.save
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
it "removes the object from the parent and database" do
|
|
141
|
+
@address.destroy
|
|
142
|
+
from_db = Person.find(@person.id)
|
|
143
|
+
from_db.addresses.should be_empty
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
describe "#save" do
|
|
153
|
+
|
|
154
|
+
context "when validation passes" do
|
|
155
|
+
|
|
156
|
+
it "returns true" do
|
|
157
|
+
@person.save.should be_true
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
describe "save!" do
|
|
165
|
+
|
|
166
|
+
context "inserting with a field that is not unique" do
|
|
167
|
+
|
|
168
|
+
context "when a unique index exists" do
|
|
169
|
+
|
|
170
|
+
it "raises an error" do
|
|
171
|
+
Person.create!(:ssn => "555-55-9999")
|
|
172
|
+
person = Person.new(:ssn => "555-55-9999")
|
|
173
|
+
lambda { person.save!(:ssn => "555-55-9999") }.should raise_error
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
describe "#update_attributes" do
|
|
183
|
+
|
|
184
|
+
context "when validation passes" do
|
|
185
|
+
|
|
186
|
+
it "returns true" do
|
|
187
|
+
@person.update_attributes(:ssn => "555-55-1234").should be_true
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
it "saves the attributes" do
|
|
191
|
+
@person.update_attributes(:ssn => "555-55-1235", :title => "Blah")
|
|
192
|
+
@from_db = Person.find(@person.id)
|
|
193
|
+
@from_db.title.should == "Blah"
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
describe ".delete_all" do
|
|
201
|
+
|
|
202
|
+
it "returns true" do
|
|
203
|
+
Person.delete_all.should == true
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
describe ".destroy_all" do
|
|
209
|
+
|
|
210
|
+
it "returns true" do
|
|
211
|
+
Person.destroy_all.should == true
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
end
|