lookout-mongo_mapper 0.11.3

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.
Files changed (176) hide show
  1. data/LICENSE +20 -0
  2. data/README.rdoc +33 -0
  3. data/UPGRADES +26 -0
  4. data/bin/mmconsole +59 -0
  5. data/examples/attr_accessible.rb +22 -0
  6. data/examples/attr_protected.rb +22 -0
  7. data/examples/cache_key.rb +24 -0
  8. data/examples/custom_types.rb +24 -0
  9. data/examples/identity_map.rb +33 -0
  10. data/examples/identity_map/automatic.rb +2 -0
  11. data/examples/keys.rb +40 -0
  12. data/examples/modifiers/set.rb +25 -0
  13. data/examples/plugins.rb +38 -0
  14. data/examples/querying.rb +35 -0
  15. data/examples/safe.rb +43 -0
  16. data/examples/scopes.rb +52 -0
  17. data/examples/validating/embedded_docs.rb +29 -0
  18. data/lib/mongo_mapper.rb +94 -0
  19. data/lib/mongo_mapper/connection.rb +96 -0
  20. data/lib/mongo_mapper/document.rb +42 -0
  21. data/lib/mongo_mapper/embedded_document.rb +32 -0
  22. data/lib/mongo_mapper/exceptions.rb +30 -0
  23. data/lib/mongo_mapper/extensions/array.rb +19 -0
  24. data/lib/mongo_mapper/extensions/binary.rb +22 -0
  25. data/lib/mongo_mapper/extensions/boolean.rb +44 -0
  26. data/lib/mongo_mapper/extensions/date.rb +25 -0
  27. data/lib/mongo_mapper/extensions/float.rb +14 -0
  28. data/lib/mongo_mapper/extensions/hash.rb +14 -0
  29. data/lib/mongo_mapper/extensions/integer.rb +19 -0
  30. data/lib/mongo_mapper/extensions/kernel.rb +9 -0
  31. data/lib/mongo_mapper/extensions/nil_class.rb +18 -0
  32. data/lib/mongo_mapper/extensions/object.rb +26 -0
  33. data/lib/mongo_mapper/extensions/object_id.rb +32 -0
  34. data/lib/mongo_mapper/extensions/set.rb +20 -0
  35. data/lib/mongo_mapper/extensions/string.rb +18 -0
  36. data/lib/mongo_mapper/extensions/time.rb +28 -0
  37. data/lib/mongo_mapper/locale/en.yml +5 -0
  38. data/lib/mongo_mapper/middleware/identity_map.rb +16 -0
  39. data/lib/mongo_mapper/plugins.rb +22 -0
  40. data/lib/mongo_mapper/plugins/accessible.rb +52 -0
  41. data/lib/mongo_mapper/plugins/active_model.rb +18 -0
  42. data/lib/mongo_mapper/plugins/associations.rb +90 -0
  43. data/lib/mongo_mapper/plugins/associations/base.rb +92 -0
  44. data/lib/mongo_mapper/plugins/associations/belongs_to_association.rb +54 -0
  45. data/lib/mongo_mapper/plugins/associations/belongs_to_polymorphic_proxy.rb +34 -0
  46. data/lib/mongo_mapper/plugins/associations/belongs_to_proxy.rb +52 -0
  47. data/lib/mongo_mapper/plugins/associations/collection.rb +27 -0
  48. data/lib/mongo_mapper/plugins/associations/embedded_collection.rb +44 -0
  49. data/lib/mongo_mapper/plugins/associations/in_array_proxy.rb +133 -0
  50. data/lib/mongo_mapper/plugins/associations/many_association.rb +63 -0
  51. data/lib/mongo_mapper/plugins/associations/many_documents_as_proxy.rb +28 -0
  52. data/lib/mongo_mapper/plugins/associations/many_documents_proxy.rb +118 -0
  53. data/lib/mongo_mapper/plugins/associations/many_embedded_polymorphic_proxy.rb +32 -0
  54. data/lib/mongo_mapper/plugins/associations/many_embedded_proxy.rb +24 -0
  55. data/lib/mongo_mapper/plugins/associations/many_polymorphic_proxy.rb +14 -0
  56. data/lib/mongo_mapper/plugins/associations/one_as_proxy.rb +22 -0
  57. data/lib/mongo_mapper/plugins/associations/one_association.rb +48 -0
  58. data/lib/mongo_mapper/plugins/associations/one_embedded_polymorphic_proxy.rb +30 -0
  59. data/lib/mongo_mapper/plugins/associations/one_embedded_proxy.rb +44 -0
  60. data/lib/mongo_mapper/plugins/associations/one_proxy.rb +95 -0
  61. data/lib/mongo_mapper/plugins/associations/proxy.rb +134 -0
  62. data/lib/mongo_mapper/plugins/associations/single_association.rb +46 -0
  63. data/lib/mongo_mapper/plugins/caching.rb +21 -0
  64. data/lib/mongo_mapper/plugins/callbacks.rb +29 -0
  65. data/lib/mongo_mapper/plugins/clone.rb +22 -0
  66. data/lib/mongo_mapper/plugins/dirty.rb +60 -0
  67. data/lib/mongo_mapper/plugins/document.rb +41 -0
  68. data/lib/mongo_mapper/plugins/dynamic_querying.rb +45 -0
  69. data/lib/mongo_mapper/plugins/dynamic_querying/dynamic_finder.rb +44 -0
  70. data/lib/mongo_mapper/plugins/embedded_callbacks.rb +56 -0
  71. data/lib/mongo_mapper/plugins/embedded_document.rb +53 -0
  72. data/lib/mongo_mapper/plugins/equality.rb +23 -0
  73. data/lib/mongo_mapper/plugins/identity_map.rb +128 -0
  74. data/lib/mongo_mapper/plugins/indexes.rb +13 -0
  75. data/lib/mongo_mapper/plugins/inspect.rb +16 -0
  76. data/lib/mongo_mapper/plugins/keys.rb +313 -0
  77. data/lib/mongo_mapper/plugins/keys/key.rb +61 -0
  78. data/lib/mongo_mapper/plugins/logger.rb +18 -0
  79. data/lib/mongo_mapper/plugins/modifiers.rb +134 -0
  80. data/lib/mongo_mapper/plugins/pagination.rb +16 -0
  81. data/lib/mongo_mapper/plugins/persistence.rb +69 -0
  82. data/lib/mongo_mapper/plugins/protected.rb +45 -0
  83. data/lib/mongo_mapper/plugins/querying.rb +165 -0
  84. data/lib/mongo_mapper/plugins/querying/decorator.rb +36 -0
  85. data/lib/mongo_mapper/plugins/rails.rb +58 -0
  86. data/lib/mongo_mapper/plugins/rails/active_record_association_adapter.rb +33 -0
  87. data/lib/mongo_mapper/plugins/safe.rb +28 -0
  88. data/lib/mongo_mapper/plugins/sci.rb +36 -0
  89. data/lib/mongo_mapper/plugins/scopes.rb +27 -0
  90. data/lib/mongo_mapper/plugins/serialization.rb +109 -0
  91. data/lib/mongo_mapper/plugins/timestamps.rb +22 -0
  92. data/lib/mongo_mapper/plugins/touch.rb +18 -0
  93. data/lib/mongo_mapper/plugins/userstamps.rb +18 -0
  94. data/lib/mongo_mapper/plugins/validations.rb +86 -0
  95. data/lib/mongo_mapper/railtie.rb +48 -0
  96. data/lib/mongo_mapper/railtie/database.rake +65 -0
  97. data/lib/mongo_mapper/translation.rb +10 -0
  98. data/lib/mongo_mapper/version.rb +4 -0
  99. data/lib/rails/generators/mongo_mapper/config/config_generator.rb +24 -0
  100. data/lib/rails/generators/mongo_mapper/config/templates/mongo.yml +18 -0
  101. data/lib/rails/generators/mongo_mapper/model/model_generator.rb +23 -0
  102. data/lib/rails/generators/mongo_mapper/model/templates/model.rb +13 -0
  103. data/test/_NOTE_ON_TESTING +1 -0
  104. data/test/functional/associations/test_belongs_to_polymorphic_proxy.rb +64 -0
  105. data/test/functional/associations/test_belongs_to_proxy.rb +238 -0
  106. data/test/functional/associations/test_in_array_proxy.rb +349 -0
  107. data/test/functional/associations/test_many_documents_as_proxy.rb +231 -0
  108. data/test/functional/associations/test_many_documents_proxy.rb +866 -0
  109. data/test/functional/associations/test_many_embedded_polymorphic_proxy.rb +239 -0
  110. data/test/functional/associations/test_many_embedded_proxy.rb +289 -0
  111. data/test/functional/associations/test_many_polymorphic_proxy.rb +303 -0
  112. data/test/functional/associations/test_one_as_proxy.rb +491 -0
  113. data/test/functional/associations/test_one_embedded_polymorphic_proxy.rb +208 -0
  114. data/test/functional/associations/test_one_embedded_proxy.rb +100 -0
  115. data/test/functional/associations/test_one_proxy.rb +383 -0
  116. data/test/functional/test_accessible.rb +198 -0
  117. data/test/functional/test_associations.rb +46 -0
  118. data/test/functional/test_binary.rb +27 -0
  119. data/test/functional/test_caching.rb +77 -0
  120. data/test/functional/test_callbacks.rb +232 -0
  121. data/test/functional/test_dirty.rb +301 -0
  122. data/test/functional/test_document.rb +282 -0
  123. data/test/functional/test_dynamic_querying.rb +75 -0
  124. data/test/functional/test_embedded_document.rb +288 -0
  125. data/test/functional/test_equality.rb +20 -0
  126. data/test/functional/test_identity_map.rb +513 -0
  127. data/test/functional/test_indexes.rb +50 -0
  128. data/test/functional/test_logger.rb +20 -0
  129. data/test/functional/test_modifiers.rb +537 -0
  130. data/test/functional/test_pagination.rb +91 -0
  131. data/test/functional/test_protected.rb +201 -0
  132. data/test/functional/test_querying.rb +935 -0
  133. data/test/functional/test_safe.rb +76 -0
  134. data/test/functional/test_sci.rb +240 -0
  135. data/test/functional/test_scopes.rb +171 -0
  136. data/test/functional/test_timestamps.rb +62 -0
  137. data/test/functional/test_touch.rb +125 -0
  138. data/test/functional/test_userstamps.rb +44 -0
  139. data/test/functional/test_validations.rb +414 -0
  140. data/test/models.rb +261 -0
  141. data/test/support/railtie.rb +4 -0
  142. data/test/support/railtie/autoloaded.rb +2 -0
  143. data/test/support/railtie/not_autoloaded.rb +3 -0
  144. data/test/support/railtie/parent.rb +3 -0
  145. data/test/test_active_model_lint.rb +18 -0
  146. data/test/test_helper.rb +93 -0
  147. data/test/unit/associations/test_base.rb +146 -0
  148. data/test/unit/associations/test_belongs_to_association.rb +29 -0
  149. data/test/unit/associations/test_many_association.rb +63 -0
  150. data/test/unit/associations/test_one_association.rb +47 -0
  151. data/test/unit/associations/test_proxy.rb +100 -0
  152. data/test/unit/serializers/test_json_serializer.rb +216 -0
  153. data/test/unit/serializers/test_xml_serializer.rb +196 -0
  154. data/test/unit/test_clone.rb +69 -0
  155. data/test/unit/test_document.rb +249 -0
  156. data/test/unit/test_dynamic_finder.rb +125 -0
  157. data/test/unit/test_embedded_document.rb +682 -0
  158. data/test/unit/test_equality.rb +38 -0
  159. data/test/unit/test_exceptions.rb +12 -0
  160. data/test/unit/test_extensions.rb +380 -0
  161. data/test/unit/test_identity_map_middleware.rb +34 -0
  162. data/test/unit/test_inspect.rb +47 -0
  163. data/test/unit/test_key.rb +205 -0
  164. data/test/unit/test_keys.rb +65 -0
  165. data/test/unit/test_mongo_mapper.rb +143 -0
  166. data/test/unit/test_pagination.rb +11 -0
  167. data/test/unit/test_plugins.rb +89 -0
  168. data/test/unit/test_rails.rb +183 -0
  169. data/test/unit/test_rails_compatibility.rb +38 -0
  170. data/test/unit/test_rails_reflect_on_association.rb +118 -0
  171. data/test/unit/test_railtie.rb +66 -0
  172. data/test/unit/test_serialization.rb +166 -0
  173. data/test/unit/test_time_zones.rb +44 -0
  174. data/test/unit/test_translation.rb +27 -0
  175. data/test/unit/test_validations.rb +562 -0
  176. metadata +285 -0
@@ -0,0 +1,134 @@
1
+ # encoding: UTF-8
2
+ require 'forwardable'
3
+ module MongoMapper
4
+ module Plugins
5
+ module Associations
6
+ class Proxy
7
+ extend Forwardable
8
+
9
+ alias :proxy_respond_to? :respond_to?
10
+ alias :proxy_extend :extend
11
+
12
+ instance_methods.each { |m| undef_method m unless m =~ /(^__|^nil\?$|^send$|proxy_|^respond_to_missing\?$|^object_id$)/ }
13
+
14
+ attr_reader :proxy_owner, :association, :target
15
+
16
+ alias :proxy_target :target
17
+ alias :proxy_association :association
18
+
19
+ def_delegators :proxy_association, :klass, :options
20
+ def_delegator :klass, :collection
21
+
22
+ def initialize(owner, association)
23
+ @proxy_owner, @association, @loaded = owner, association, false
24
+ Array(association.options[:extend]).each { |ext| proxy_extend(ext) }
25
+ reset
26
+ end
27
+
28
+ # Active support in rails 3 beta 4 can override to_json after this is loaded,
29
+ # at least when run in mongomapper tests. The implementation was changed in master
30
+ # some time after this, so not sure whether this is still a problem.
31
+ #
32
+ # In rails 2, this isn't a problem however it also solves an issue where
33
+ # to_json isn't forwarded because it supports to_json itself
34
+ def to_json(*options)
35
+ load_target
36
+ target.to_json(*options)
37
+ end
38
+
39
+ # see comments to to_json
40
+ def as_json(*options)
41
+ load_target
42
+ target.as_json(*options)
43
+ end
44
+
45
+ def inspect
46
+ load_target
47
+ target.inspect
48
+ end
49
+
50
+ def loaded?
51
+ @loaded
52
+ end
53
+
54
+ def loaded
55
+ @loaded = true
56
+ end
57
+
58
+ def nil?
59
+ load_target
60
+ target.nil?
61
+ end
62
+
63
+ def blank?
64
+ load_target
65
+ target.blank?
66
+ end
67
+
68
+ def present?
69
+ load_target
70
+ target.present?
71
+ end
72
+
73
+ def reload
74
+ reset
75
+ load_target
76
+ self unless target.nil?
77
+ end
78
+
79
+ def replace(v)
80
+ raise NotImplementedError
81
+ end
82
+
83
+ def reset
84
+ @loaded = false
85
+ @target = nil
86
+ end
87
+
88
+ def respond_to?(*args)
89
+ proxy_respond_to?(*args) || (load_target && target.respond_to?(*args))
90
+ end
91
+
92
+ def send(method, *args)
93
+ if proxy_respond_to?(method)
94
+ super
95
+ else
96
+ load_target
97
+ target.send(method, *args)
98
+ end
99
+ end
100
+
101
+ protected
102
+ def method_missing(method, *args, &block)
103
+ if load_target
104
+ target.send(method, *args, &block)
105
+ end
106
+ end
107
+
108
+ def load_target
109
+ unless loaded?
110
+ if @target.is_a?(Array) && @target.any?
111
+ @target = find_target + @target.find_all { |record| !record.persisted? }
112
+ else
113
+ @target = find_target
114
+ end
115
+ loaded
116
+ end
117
+ @target
118
+ rescue MongoMapper::DocumentNotFound
119
+ reset
120
+ end
121
+
122
+ def find_target
123
+ raise NotImplementedError
124
+ end
125
+
126
+ def flatten_deeper(array)
127
+ array.collect do |element|
128
+ (element.respond_to?(:flatten) && !element.is_a?(Hash)) ? element.flatten : element
129
+ end.flatten
130
+ end
131
+ end
132
+ end
133
+ end
134
+ end
@@ -0,0 +1,46 @@
1
+ # encoding: UTF-8
2
+ module MongoMapper
3
+ module Plugins
4
+ module Associations
5
+ class SingleAssociation < Base
6
+ def setup(model)
7
+ @model = model
8
+ model.associations_module.module_eval <<-end_eval
9
+ def #{name}
10
+ proxy = get_proxy(associations[#{name.inspect}])
11
+ proxy.nil? ? nil : proxy
12
+ end
13
+
14
+ def #{name}=(value)
15
+ association = associations[#{name.inspect}]
16
+ proxy = get_proxy(association)
17
+
18
+ if proxy.nil? || proxy.target != value
19
+ proxy = build_proxy(association)
20
+ end
21
+
22
+ proxy.replace(value)
23
+ value
24
+ end
25
+
26
+ def #{name}?
27
+ get_proxy(associations[#{name.inspect}]).present?
28
+ end
29
+
30
+ def build_#{name}(attrs={})
31
+ get_proxy(associations[#{name.inspect}]).build(attrs)
32
+ end
33
+
34
+ def create_#{name}(attrs={})
35
+ get_proxy(associations[#{name.inspect}]).create(attrs)
36
+ end
37
+
38
+ def create_#{name}!(attrs={})
39
+ get_proxy(associations[#{name.inspect}]).create!(attrs)
40
+ end
41
+ end_eval
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,21 @@
1
+ # encoding: UTF-8
2
+ module MongoMapper
3
+ module Plugins
4
+ module Caching
5
+ extend ActiveSupport::Concern
6
+
7
+ def cache_key(*suffixes)
8
+ cache_key = case
9
+ when !persisted?
10
+ "#{self.class.name}/new"
11
+ when timestamp = self[:updated_at]
12
+ "#{self.class.name}/#{id}-#{timestamp.to_s(:number)}"
13
+ else
14
+ "#{self.class.name}/#{id}"
15
+ end
16
+ cache_key += "/#{suffixes.join('/')}" unless suffixes.empty?
17
+ cache_key
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,29 @@
1
+ # encoding: UTF-8
2
+ module MongoMapper
3
+ module Plugins
4
+ module Callbacks
5
+ extend ActiveSupport::Concern
6
+
7
+ def destroy
8
+ run_callbacks(:destroy) { super }
9
+ end
10
+
11
+ def touch(*)
12
+ run_callbacks(:touch) { super }
13
+ end
14
+
15
+ private
16
+ def create_or_update(*)
17
+ run_callbacks(:save) { super }
18
+ end
19
+
20
+ def create(*)
21
+ run_callbacks(:create) { super }
22
+ end
23
+
24
+ def update(*)
25
+ run_callbacks(:update) { super }
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,22 @@
1
+ # encoding: UTF-8
2
+ module MongoMapper
3
+ module Plugins
4
+ module Clone
5
+ extend ActiveSupport::Concern
6
+
7
+ def initialize_copy(other)
8
+ @_new = true
9
+ @_destroyed = false
10
+ @_id = nil
11
+ associations.each do |name, association|
12
+ instance_variable_set(association.ivar, nil)
13
+ end
14
+ self.attributes = other.attributes.clone.except(:_id).inject({}) do |hash, entry|
15
+ key, value = entry
16
+ hash[key] = value.duplicable? ? value.clone : value
17
+ hash
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,60 @@
1
+ # encoding: UTF-8
2
+ module MongoMapper
3
+ module Plugins
4
+ module Dirty
5
+ extend ActiveSupport::Concern
6
+
7
+ include ::ActiveModel::Dirty
8
+
9
+ def initialize(*)
10
+ # never register initial id assignment as a change
11
+ super.tap { changed_attributes.delete('_id') }
12
+ end
13
+
14
+ def initialize_from_database(*)
15
+ super.tap { changed_attributes.clear }
16
+ end
17
+
18
+ def save(*)
19
+ clear_changes { super }
20
+ end
21
+
22
+ def reload(*)
23
+ super.tap { clear_changes }
24
+ end
25
+
26
+ protected
27
+
28
+ def attribute_method?(attr)
29
+ # This overrides ::ActiveSupport::Dirty#attribute_method? to allow attributes to be any key
30
+ # in the attributes hash ( default ) or any key defined on the model that may not yet have
31
+ # had a value stored in the attributes collection.
32
+ super || key_names.include?(attr)
33
+ end
34
+
35
+ def clear_changes
36
+ previous = changes
37
+ (block_given? ? yield : true).tap do |result|
38
+ unless result == false #failed validation; nil is OK.
39
+ @previously_changed = previous
40
+ changed_attributes.clear
41
+ end
42
+ end
43
+ end
44
+
45
+ private
46
+
47
+ def write_key(key, value)
48
+ key = key.to_s
49
+ attribute_will_change!(key) unless attribute_changed?(key)
50
+ super(key, value).tap do
51
+ changed_attributes.delete(key) unless attribute_value_changed?(key)
52
+ end
53
+ end
54
+
55
+ def attribute_value_changed?(key_name)
56
+ attribute_was(key_name) != read_key(key_name)
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,41 @@
1
+ # encoding: UTF-8
2
+ module MongoMapper
3
+ module Plugins
4
+ module Document
5
+ extend ActiveSupport::Concern
6
+
7
+ module ClassMethods
8
+ def embeddable?
9
+ false
10
+ end
11
+ end
12
+
13
+ def new?
14
+ @_new
15
+ end
16
+
17
+ def destroyed?
18
+ @_destroyed == true
19
+ end
20
+
21
+ def reload
22
+ if doc = collection.find_one(:_id => id)
23
+ self.class.associations.each_value do |association|
24
+ get_proxy(association).reset
25
+ end
26
+ instance_variables.each { |ivar| instance_variable_set(ivar, nil) }
27
+ load_from_database(doc)
28
+ self
29
+ else
30
+ raise DocumentNotFound, "Document match #{_id.inspect} does not exist in #{collection.name} collection"
31
+ end
32
+ end
33
+
34
+ # Used by embedded docs to find root easily without if/respond_to? stuff.
35
+ # Documents are always root documents.
36
+ def _root_document
37
+ self
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,45 @@
1
+ # encoding: UTF-8
2
+ require 'mongo_mapper/plugins/dynamic_querying/dynamic_finder'
3
+
4
+ module MongoMapper
5
+ module Plugins
6
+ module DynamicQuerying
7
+ extend ActiveSupport::Concern
8
+
9
+ module ClassMethods
10
+ def dynamic_find(finder, args)
11
+ attributes = {}
12
+
13
+ finder.attributes.each_with_index do |attr, index|
14
+ attributes[attr] = args[index]
15
+ end
16
+
17
+ options = args.extract_options!.merge(attributes)
18
+
19
+ if result = send(finder.finder, options)
20
+ result
21
+ else
22
+ if finder.raise?
23
+ raise DocumentNotFound, "Couldn't find Document with #{attributes.inspect} in collection named #{collection.name}"
24
+ end
25
+
26
+ if finder.instantiator
27
+ self.send(finder.instantiator, attributes)
28
+ end
29
+ end
30
+ end
31
+
32
+ protected
33
+ def method_missing(method, *args, &block)
34
+ finder = DynamicFinder.new(method)
35
+
36
+ if finder.found?
37
+ dynamic_find(finder, args)
38
+ else
39
+ super
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,44 @@
1
+ # encoding: UTF-8
2
+ module MongoMapper
3
+ module Plugins
4
+ module DynamicQuerying
5
+ class DynamicFinder
6
+ attr_reader :method, :attributes, :finder, :bang, :instantiator
7
+
8
+ def initialize(method)
9
+ @method = method
10
+ @finder = :first
11
+ @bang = false
12
+ match
13
+ end
14
+
15
+ def found?
16
+ @finder.present?
17
+ end
18
+
19
+ def raise?
20
+ bang == true
21
+ end
22
+
23
+ protected
24
+ def match
25
+ case method.to_s
26
+ when /^find_(all_by|by)_([_a-zA-Z]\w*)$/
27
+ @finder = :all if $1 == 'all_by'
28
+ names = $2
29
+ when /^find_by_([_a-zA-Z]\w*)\!$/
30
+ @bang = true
31
+ names = $1
32
+ when /^find_or_(initialize|create)_by_([_a-zA-Z]\w*)$/
33
+ @instantiator = $1 == 'initialize' ? :new : :create
34
+ names = $2
35
+ else
36
+ @finder = nil
37
+ end
38
+
39
+ @attributes = names && names.split('_and_')
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end