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
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
module Humanoid #:nodoc:
|
|
3
|
+
module Extensions #:nodoc:
|
|
4
|
+
module Hash #:nodoc:
|
|
5
|
+
module CriteriaHelpers #:nodoc:
|
|
6
|
+
def expand_complex_criteria
|
|
7
|
+
hsh = {}
|
|
8
|
+
self.each_pair do |k,v|
|
|
9
|
+
if k.class == Humanoid::Criterion::Complex
|
|
10
|
+
hsh[k.key] = {"$#{k.operator}" => v}
|
|
11
|
+
else
|
|
12
|
+
hsh[k] = v
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
hsh
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
module Humanoid #:nodoc:
|
|
3
|
+
module Extensions #:nodoc:
|
|
4
|
+
module Integer #:nodoc:
|
|
5
|
+
module Conversions #:nodoc:
|
|
6
|
+
def set(value)
|
|
7
|
+
return nil if value.blank?
|
|
8
|
+
value =~ /\d/ ? value.to_i : value
|
|
9
|
+
end
|
|
10
|
+
def get(value)
|
|
11
|
+
value
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
module Humanoid #:nodoc:
|
|
3
|
+
module Extensions #:nodoc:
|
|
4
|
+
module Nil #:nodoc:
|
|
5
|
+
module Assimilation #:nodoc:
|
|
6
|
+
# Will remove the child object from the parent.
|
|
7
|
+
def assimilate(parent, options, type = nil)
|
|
8
|
+
parent.remove_attribute(options.name); self
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
module Humanoid #:nodoc:
|
|
3
|
+
module Extensions #:nodoc:
|
|
4
|
+
module Object #:nodoc:
|
|
5
|
+
# This module converts objects into humanoid related objects.
|
|
6
|
+
module Conversions #:nodoc:
|
|
7
|
+
def self.included(base)
|
|
8
|
+
base.class_eval do
|
|
9
|
+
include InstanceMethods
|
|
10
|
+
extend ClassMethods
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
module InstanceMethods
|
|
15
|
+
# Converts this object to a hash of attributes
|
|
16
|
+
def humanoidize
|
|
17
|
+
self.attributes
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
module ClassMethods
|
|
22
|
+
def set(value)
|
|
23
|
+
value.respond_to?(:attributes) ? value.attributes : value
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def get(value)
|
|
27
|
+
self.new(value)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
module Humanoid #:nodoc:
|
|
3
|
+
module Extensions #:nodoc:
|
|
4
|
+
module String #:nodoc:
|
|
5
|
+
module Inflections #:nodoc:
|
|
6
|
+
|
|
7
|
+
ActiveSupport::Inflector.inflections do |inflect|
|
|
8
|
+
inflect.singular("address", "address")
|
|
9
|
+
inflect.singular("addresses", "address")
|
|
10
|
+
inflect.irregular("canvas", "canvases")
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# Represents how special characters will get converted when creating a
|
|
14
|
+
# composite key that should be unique and part of a url.
|
|
15
|
+
CHAR_CONV = {
|
|
16
|
+
" " => "-",
|
|
17
|
+
"!" => "-excl-",
|
|
18
|
+
"\"" => "-bckslsh-",
|
|
19
|
+
"#" => "-hash-",
|
|
20
|
+
"$" => "-dol-",
|
|
21
|
+
"%" => "-perc-",
|
|
22
|
+
"&" => "-and-",
|
|
23
|
+
"'" => "-quo-",
|
|
24
|
+
"(" => "-oparen-",
|
|
25
|
+
")" => "-cparen-",
|
|
26
|
+
"*" => "-astx-",
|
|
27
|
+
"+" => "-plus-",
|
|
28
|
+
"," => "-comma-",
|
|
29
|
+
"-" => "-dash-",
|
|
30
|
+
"." => "-period-",
|
|
31
|
+
"/" => "-fwdslsh-",
|
|
32
|
+
":" => "-colon-",
|
|
33
|
+
";" => "-semicol-",
|
|
34
|
+
"<" => "-lt-",
|
|
35
|
+
"=" => "-eq-",
|
|
36
|
+
">" => "-gt-",
|
|
37
|
+
"?" => "-ques-",
|
|
38
|
+
"@" => "-at-",
|
|
39
|
+
"[" => "-obrck-",
|
|
40
|
+
"\\" => "-bckslsh-",
|
|
41
|
+
"]" => "-clbrck-",
|
|
42
|
+
"^" => "-carat-",
|
|
43
|
+
"_" => "-undscr-",
|
|
44
|
+
"`" => "-bcktick-",
|
|
45
|
+
"{" => "-ocurly-",
|
|
46
|
+
"|" => "-pipe-",
|
|
47
|
+
"}" => "-clcurly-",
|
|
48
|
+
"~" => "-tilda-"
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
REVERSALS = {
|
|
52
|
+
"asc" => "desc",
|
|
53
|
+
"ascending" => "descending",
|
|
54
|
+
"desc" => "asc",
|
|
55
|
+
"descending" => "ascending"
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
def collectionize
|
|
59
|
+
tableize.gsub("/", "_")
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def identify
|
|
63
|
+
if Humanoid.parameterize_keys
|
|
64
|
+
key = ""
|
|
65
|
+
each_char { |c| key += (CHAR_CONV[c] || c.downcase) }; key
|
|
66
|
+
else
|
|
67
|
+
self
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def labelize
|
|
72
|
+
underscore.humanize
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def invert
|
|
76
|
+
REVERSALS[self]
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def singular?
|
|
80
|
+
singularize == self
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def plural?
|
|
84
|
+
pluralize == self
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def reader
|
|
88
|
+
writer? ? gsub("=", "") : self
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def writer?
|
|
92
|
+
include?("=")
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
module Humanoid #:nodoc:
|
|
3
|
+
module Extensions #:nodoc:
|
|
4
|
+
module Symbol #:nodoc:
|
|
5
|
+
module Inflections #:nodoc:
|
|
6
|
+
|
|
7
|
+
REVERSALS = {
|
|
8
|
+
:asc => :desc,
|
|
9
|
+
:ascending => :descending,
|
|
10
|
+
:desc => :asc,
|
|
11
|
+
:descending => :ascending
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
def invert
|
|
15
|
+
REVERSALS[self]
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def singular?
|
|
19
|
+
to_s.singular?
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def plural?
|
|
23
|
+
to_s.plural?
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
["gt", "lt", "gte", "lte", "ne", "in", "nin", "mod", "all", "size", "exists"].each do |oper|
|
|
27
|
+
class_eval <<-OPERATORS
|
|
28
|
+
def #{oper}
|
|
29
|
+
Criterion::Complex.new(:key => self, :operator => "#{oper}")
|
|
30
|
+
end
|
|
31
|
+
OPERATORS
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
module Humanoid #:nodoc:
|
|
3
|
+
module Extensions #:nodoc:
|
|
4
|
+
module Time #:nodoc:
|
|
5
|
+
module Conversions #:nodoc:
|
|
6
|
+
def set(value)
|
|
7
|
+
return nil if value.blank?
|
|
8
|
+
time = ::Time.parse(value.is_a?(::Time) ? value.strftime("%Y-%m-%d %H:%M:%S %Z") : value.to_s)
|
|
9
|
+
time.utc? ? time : time.utc
|
|
10
|
+
end
|
|
11
|
+
def get(value)
|
|
12
|
+
return nil if value.blank?
|
|
13
|
+
::Time.zone ? value.getlocal : value
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
module Humanoid #:nodoc:
|
|
3
|
+
class Factory #:nodoc:
|
|
4
|
+
# Builds a new +Document+ from the supplied attributes.
|
|
5
|
+
#
|
|
6
|
+
# Example:
|
|
7
|
+
#
|
|
8
|
+
# <tt>Humanoid::Factory.build(Person, {})</tt>
|
|
9
|
+
#
|
|
10
|
+
# Options:
|
|
11
|
+
#
|
|
12
|
+
# klass: The class to instantiate from if _type is not present.
|
|
13
|
+
# attributes: The +Document+ attributes.
|
|
14
|
+
def self.build(klass, attrs)
|
|
15
|
+
type = attrs["_type"]
|
|
16
|
+
type ? type.constantize.instantiate(attrs) : klass.instantiate(attrs)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
module Humanoid #:nodoc:
|
|
3
|
+
class Field
|
|
4
|
+
|
|
5
|
+
attr_reader \
|
|
6
|
+
:default,
|
|
7
|
+
:name,
|
|
8
|
+
:type
|
|
9
|
+
|
|
10
|
+
# Create the new field with a name and optional additional options. Valid
|
|
11
|
+
# options are :default
|
|
12
|
+
#
|
|
13
|
+
# Options:
|
|
14
|
+
#
|
|
15
|
+
# name: The name of the field as a +Symbol+.
|
|
16
|
+
# options: A +Hash+ of options for the field.
|
|
17
|
+
#
|
|
18
|
+
# Example:
|
|
19
|
+
#
|
|
20
|
+
# <tt>Field.new(:score, :default => 0)</tt>
|
|
21
|
+
def initialize(name, options = {})
|
|
22
|
+
@name = name
|
|
23
|
+
@default = options[:default]
|
|
24
|
+
@type = options[:type] || String
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Used for setting an object in the attributes hash. If nil is provided the
|
|
28
|
+
# default will get returned if it exists.
|
|
29
|
+
def set(object)
|
|
30
|
+
object.nil? ? default : type.set(object)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Used for retrieving the object out of the attributes hash.
|
|
34
|
+
def get(object)
|
|
35
|
+
type.get(object)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
module Humanoid #:nodoc
|
|
3
|
+
module Fields #:nodoc
|
|
4
|
+
def self.included(base)
|
|
5
|
+
base.class_eval do
|
|
6
|
+
extend ClassMethods
|
|
7
|
+
# Set up the class attributes that must be available to all subclasses.
|
|
8
|
+
# These include defaults, fields
|
|
9
|
+
class_inheritable_accessor :defaults, :fields
|
|
10
|
+
|
|
11
|
+
self.defaults = {}
|
|
12
|
+
self.fields = {}
|
|
13
|
+
|
|
14
|
+
delegate :defaults, :fields, :to => "self.class"
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
module ClassMethods #:nodoc
|
|
19
|
+
# Defines all the fields that are accessable on the Document
|
|
20
|
+
# For each field that is defined, a getter and setter will be
|
|
21
|
+
# added as an instance method to the Document.
|
|
22
|
+
#
|
|
23
|
+
# Options:
|
|
24
|
+
#
|
|
25
|
+
# name: The name of the field, as a +Symbol+.
|
|
26
|
+
# options: A +Hash+ of options to supply to the +Field+.
|
|
27
|
+
#
|
|
28
|
+
# Example:
|
|
29
|
+
#
|
|
30
|
+
# <tt>field :score, :default => 0</tt>
|
|
31
|
+
def field(name, options = {})
|
|
32
|
+
access = name.to_s
|
|
33
|
+
set_field(access, options)
|
|
34
|
+
set_default(access, options)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
protected
|
|
38
|
+
# Define a field attribute for the +Document+.
|
|
39
|
+
def set_field(name, options = {})
|
|
40
|
+
meth = options.delete(:as) || name
|
|
41
|
+
fields[name] = Field.new(name, options)
|
|
42
|
+
create_accessors(name, meth, options)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Create the field accessors.
|
|
46
|
+
def create_accessors(name, meth, options = {})
|
|
47
|
+
define_method(meth) { read_attribute(name) }
|
|
48
|
+
define_method("#{meth}=") { |value| write_attribute(name, value) }
|
|
49
|
+
define_method("#{meth}?") do
|
|
50
|
+
attr = read_attribute(name)
|
|
51
|
+
(options[:type] == Boolean) ? attr == true : attr.present?
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Set up a default value for a field.
|
|
56
|
+
def set_default(name, options = {})
|
|
57
|
+
value = options[:default]
|
|
58
|
+
defaults[name] = value unless value.nil?
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
module Humanoid #:nodoc:
|
|
3
|
+
module Finders #:nodoc:
|
|
4
|
+
# Find +Documents+ given the conditions.
|
|
5
|
+
#
|
|
6
|
+
# Options:
|
|
7
|
+
#
|
|
8
|
+
# args: A +Hash+ with a conditions key and other options
|
|
9
|
+
#
|
|
10
|
+
# <tt>Person.all(:conditions => { :attribute => "value" })</tt>
|
|
11
|
+
def all(*args)
|
|
12
|
+
find(:all, *args)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# Returns a count of matching records in the database based on the
|
|
16
|
+
# provided arguments.
|
|
17
|
+
#
|
|
18
|
+
# <tt>Person.count(:first, :conditions => { :attribute => "value" })</tt>
|
|
19
|
+
def count(*args)
|
|
20
|
+
Criteria.translate(self, *args).count
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Helper to initialize a new +Criteria+ object for this class.
|
|
24
|
+
#
|
|
25
|
+
# Example:
|
|
26
|
+
#
|
|
27
|
+
# <tt>Person.criteria</tt>
|
|
28
|
+
def criteria
|
|
29
|
+
Criteria.new(self)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Find a +Document+ in several different ways.
|
|
33
|
+
#
|
|
34
|
+
# If a +String+ is provided, it will be assumed that it is a
|
|
35
|
+
# representation of a Mongo::ObjectID and will attempt to find a single
|
|
36
|
+
# +Document+ based on that id. If a +Symbol+ and +Hash+ is provided then
|
|
37
|
+
# it will attempt to find either a single +Document+ or multiples based
|
|
38
|
+
# on the conditions provided and the first parameter.
|
|
39
|
+
#
|
|
40
|
+
# <tt>Person.find(:first, :conditions => { :attribute => "value" })</tt>
|
|
41
|
+
#
|
|
42
|
+
# <tt>Person.find(:all, :conditions => { :attribute => "value" })</tt>
|
|
43
|
+
#
|
|
44
|
+
# <tt>Person.find(Mongo::ObjectID.new.to_s)</tt>
|
|
45
|
+
def find(*args)
|
|
46
|
+
raise Errors::InvalidOptions.new("Calling Document#find with nil is invalid") if args[0].nil?
|
|
47
|
+
type = args.delete_at(0) if args[0].is_a?(Symbol)
|
|
48
|
+
criteria = Criteria.translate(self, *args)
|
|
49
|
+
case type
|
|
50
|
+
when :first then return criteria.one
|
|
51
|
+
when :last then return criteria.last
|
|
52
|
+
else
|
|
53
|
+
return criteria
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Find the first +Document+ given the conditions, or creates a new document
|
|
58
|
+
# with the conditions that were supplied
|
|
59
|
+
#
|
|
60
|
+
# Options:
|
|
61
|
+
#
|
|
62
|
+
# args: A +Hash+ of attributes
|
|
63
|
+
#
|
|
64
|
+
# <tt>Person.find_or_create_by(:attribute => "value")</tt>
|
|
65
|
+
def find_or_create_by(attrs = {})
|
|
66
|
+
find_or(:create, attrs)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# Find the first +Document+ given the conditions, or instantiates a new document
|
|
70
|
+
# with the conditions that were supplied
|
|
71
|
+
#
|
|
72
|
+
# Options:
|
|
73
|
+
#
|
|
74
|
+
# args: A +Hash+ of attributes
|
|
75
|
+
#
|
|
76
|
+
# <tt>Person.find_or_initialize_by(:attribute => "value")</tt>
|
|
77
|
+
def find_or_initialize_by(attrs = {})
|
|
78
|
+
find_or(:new, attrs)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# Find the first +Document+ given the conditions.
|
|
82
|
+
#
|
|
83
|
+
# Options:
|
|
84
|
+
#
|
|
85
|
+
# args: A +Hash+ with a conditions key and other options
|
|
86
|
+
#
|
|
87
|
+
# <tt>Person.first(:conditions => { :attribute => "value" })</tt>
|
|
88
|
+
def first(*args)
|
|
89
|
+
find(:first, *args)
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# Find the last +Document+ given the conditions.
|
|
93
|
+
#
|
|
94
|
+
# Options:
|
|
95
|
+
#
|
|
96
|
+
# args: A +Hash+ with a conditions key and other options
|
|
97
|
+
#
|
|
98
|
+
# <tt>Person.last(:conditions => { :attribute => "value" })</tt>
|
|
99
|
+
def last(*args)
|
|
100
|
+
find(:last, *args)
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# Convenience method for returning the max value of a field.
|
|
104
|
+
#
|
|
105
|
+
# Options:
|
|
106
|
+
#
|
|
107
|
+
# field: The field to use when calculating the max.
|
|
108
|
+
#
|
|
109
|
+
# Example:
|
|
110
|
+
#
|
|
111
|
+
# <tt>Person.max(:age)</tt>
|
|
112
|
+
#
|
|
113
|
+
# Returns: <tt>Float</tt> max value.
|
|
114
|
+
def max(field)
|
|
115
|
+
Criteria.new(self).max(field)
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
# Will execute a +Criteria+ based on the +DynamicFinder+ that gets
|
|
119
|
+
# generated.
|
|
120
|
+
#
|
|
121
|
+
# Options:
|
|
122
|
+
#
|
|
123
|
+
# name: The finder method name
|
|
124
|
+
# args: The arguments to pass to the method.
|
|
125
|
+
#
|
|
126
|
+
# Example:
|
|
127
|
+
#
|
|
128
|
+
# <tt>Person.find_all_by_title_and_age("Sir", 30)</tt>
|
|
129
|
+
# def method_missing(name, *args)
|
|
130
|
+
# dyna = DynamicFinder.new(name, *args)
|
|
131
|
+
# finder, conditions = dyna.finder, dyna.conditions
|
|
132
|
+
# results = find(finder, :conditions => conditions)
|
|
133
|
+
# results ? results : dyna.create(self)
|
|
134
|
+
# end
|
|
135
|
+
|
|
136
|
+
# Convenience method for returning the min value of a field.
|
|
137
|
+
#
|
|
138
|
+
# Options:
|
|
139
|
+
#
|
|
140
|
+
# field: The field to use when calculating the min.
|
|
141
|
+
#
|
|
142
|
+
# Example:
|
|
143
|
+
#
|
|
144
|
+
# <tt>Person.min(:age)</tt>
|
|
145
|
+
#
|
|
146
|
+
# Returns: <tt>Float</tt> min value.
|
|
147
|
+
def min(field)
|
|
148
|
+
Criteria.new(self).min(field)
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
# Find all documents in paginated fashion given the supplied arguments.
|
|
152
|
+
# If no parameters are passed just default to offset 0 and limit 20.
|
|
153
|
+
#
|
|
154
|
+
# Options:
|
|
155
|
+
#
|
|
156
|
+
# params: A +Hash+ of params to pass to the Criteria API.
|
|
157
|
+
#
|
|
158
|
+
# Example:
|
|
159
|
+
#
|
|
160
|
+
# <tt>Person.paginate(:conditions => { :field => "Test" }, :page => 1,
|
|
161
|
+
# :per_page => 20)</tt>
|
|
162
|
+
#
|
|
163
|
+
# Returns paginated array of docs.
|
|
164
|
+
def paginate(params = {})
|
|
165
|
+
Criteria.translate(self, params).paginate
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
# Entry point for creating a new criteria from a Document. This will
|
|
169
|
+
# instantiate a new +Criteria+ object with the supplied select criterion
|
|
170
|
+
# already added to it.
|
|
171
|
+
#
|
|
172
|
+
# Options:
|
|
173
|
+
#
|
|
174
|
+
# args: A list of field names to retrict the returned fields to.
|
|
175
|
+
#
|
|
176
|
+
# Example:
|
|
177
|
+
#
|
|
178
|
+
# <tt>Person.only(:field1, :field2, :field3)</tt>
|
|
179
|
+
#
|
|
180
|
+
# Returns: <tt>Criteria</tt>
|
|
181
|
+
def only(*args)
|
|
182
|
+
Criteria.new(self).only(*args)
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
# Convenience method for returning the sum of a specified field for all
|
|
186
|
+
# documents in the database.
|
|
187
|
+
#
|
|
188
|
+
# Options:
|
|
189
|
+
#
|
|
190
|
+
# field: The field to use when calculating the sum.
|
|
191
|
+
#
|
|
192
|
+
# Example:
|
|
193
|
+
#
|
|
194
|
+
# <tt>Person.sum(:age)</tt>
|
|
195
|
+
#
|
|
196
|
+
# Returns: <tt>Float</tt> of the sum.
|
|
197
|
+
def sum(field)
|
|
198
|
+
Criteria.new(self).sum(field)
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
# Entry point for creating a new criteria from a Document. This will
|
|
202
|
+
# instantiate a new +Criteria+ object with the supplied select criterion
|
|
203
|
+
# already added to it.
|
|
204
|
+
#
|
|
205
|
+
# Options:
|
|
206
|
+
#
|
|
207
|
+
# selector: A where criteria to initialize.
|
|
208
|
+
#
|
|
209
|
+
# Example:
|
|
210
|
+
#
|
|
211
|
+
# <tt>Person.where(:field1 => "Value")</tt>
|
|
212
|
+
#
|
|
213
|
+
# Returns: <tt>Criteria</tt>
|
|
214
|
+
def where(selector = nil)
|
|
215
|
+
Criteria.new(self).where(selector)
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
protected
|
|
219
|
+
# Find the first object or create/initialize it.
|
|
220
|
+
def find_or(method, attrs = {})
|
|
221
|
+
first(:conditions => attrs) || send(method, attrs)
|
|
222
|
+
end
|
|
223
|
+
end
|
|
224
|
+
end
|