mack-data_mapper 0.8.1 → 0.8.2

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 (166) hide show
  1. data/lib/gems/addressable-2.0.0/lib/addressable/idna.rb +4867 -0
  2. data/lib/gems/addressable-2.0.0/lib/addressable/uri.rb +2469 -0
  3. data/lib/gems/addressable-2.0.0/lib/addressable/version.rb +35 -0
  4. data/lib/gems/dm-aggregates-0.9.7/lib/dm-aggregates/adapters/data_objects_adapter.rb +85 -0
  5. data/lib/gems/dm-aggregates-0.9.7/lib/dm-aggregates/aggregate_functions.rb +201 -0
  6. data/lib/gems/dm-aggregates-0.9.7/lib/dm-aggregates/collection.rb +11 -0
  7. data/lib/gems/dm-aggregates-0.9.7/lib/dm-aggregates/model.rb +11 -0
  8. data/lib/gems/dm-aggregates-0.9.7/lib/dm-aggregates/repository.rb +7 -0
  9. data/lib/gems/dm-aggregates-0.9.7/lib/dm-aggregates/support/symbol.rb +21 -0
  10. data/lib/gems/dm-aggregates-0.9.7/lib/dm-aggregates/version.rb +7 -0
  11. data/lib/gems/dm-aggregates-0.9.7/lib/dm-aggregates.rb +15 -0
  12. data/lib/gems/dm-core-0.9.7/lib/dm-core/adapters/abstract_adapter.rb +209 -0
  13. data/lib/gems/dm-core-0.9.7/lib/dm-core/adapters/data_objects_adapter.rb +709 -0
  14. data/lib/gems/dm-core-0.9.7/lib/dm-core/adapters/in_memory_adapter.rb +87 -0
  15. data/lib/gems/dm-core-0.9.7/lib/dm-core/adapters/mysql_adapter.rb +136 -0
  16. data/lib/gems/dm-core-0.9.7/lib/dm-core/adapters/postgres_adapter.rb +188 -0
  17. data/lib/gems/dm-core-0.9.7/lib/dm-core/adapters/sqlite3_adapter.rb +105 -0
  18. data/lib/gems/dm-core-0.9.7/lib/dm-core/adapters.rb +22 -0
  19. data/lib/gems/dm-core-0.9.7/lib/dm-core/associations/many_to_many.rb +147 -0
  20. data/lib/gems/dm-core-0.9.7/lib/dm-core/associations/many_to_one.rb +107 -0
  21. data/lib/gems/dm-core-0.9.7/lib/dm-core/associations/one_to_many.rb +318 -0
  22. data/lib/gems/dm-core-0.9.7/lib/dm-core/associations/one_to_one.rb +61 -0
  23. data/lib/gems/dm-core-0.9.7/lib/dm-core/associations/relationship.rb +223 -0
  24. data/lib/gems/dm-core-0.9.7/lib/dm-core/associations/relationship_chain.rb +81 -0
  25. data/lib/gems/dm-core-0.9.7/lib/dm-core/associations.rb +200 -0
  26. data/lib/gems/dm-core-0.9.7/lib/dm-core/auto_migrations.rb +105 -0
  27. data/lib/gems/dm-core-0.9.7/lib/dm-core/collection.rb +642 -0
  28. data/lib/gems/dm-core-0.9.7/lib/dm-core/dependency_queue.rb +32 -0
  29. data/lib/gems/dm-core-0.9.7/lib/dm-core/hook.rb +11 -0
  30. data/lib/gems/dm-core-0.9.7/lib/dm-core/identity_map.rb +42 -0
  31. data/lib/gems/dm-core-0.9.7/lib/dm-core/is.rb +16 -0
  32. data/lib/gems/dm-core-0.9.7/lib/dm-core/logger.rb +232 -0
  33. data/lib/gems/dm-core-0.9.7/lib/dm-core/migrations/destructive_migrations.rb +17 -0
  34. data/lib/gems/dm-core-0.9.7/lib/dm-core/migrator.rb +29 -0
  35. data/lib/gems/dm-core-0.9.7/lib/dm-core/model.rb +488 -0
  36. data/lib/gems/dm-core-0.9.7/lib/dm-core/naming_conventions.rb +84 -0
  37. data/lib/gems/dm-core-0.9.7/lib/dm-core/property.rb +663 -0
  38. data/lib/gems/dm-core-0.9.7/lib/dm-core/property_set.rb +169 -0
  39. data/lib/gems/dm-core-0.9.7/lib/dm-core/query.rb +628 -0
  40. data/lib/gems/dm-core-0.9.7/lib/dm-core/repository.rb +159 -0
  41. data/lib/gems/dm-core-0.9.7/lib/dm-core/resource.rb +637 -0
  42. data/lib/gems/dm-core-0.9.7/lib/dm-core/scope.rb +58 -0
  43. data/lib/gems/dm-core-0.9.7/lib/dm-core/support/array.rb +13 -0
  44. data/lib/gems/dm-core-0.9.7/lib/dm-core/support/assertions.rb +8 -0
  45. data/lib/gems/dm-core-0.9.7/lib/dm-core/support/errors.rb +23 -0
  46. data/lib/gems/dm-core-0.9.7/lib/dm-core/support/kernel.rb +11 -0
  47. data/lib/gems/dm-core-0.9.7/lib/dm-core/support/symbol.rb +41 -0
  48. data/lib/gems/dm-core-0.9.7/lib/dm-core/support.rb +7 -0
  49. data/lib/gems/dm-core-0.9.7/lib/dm-core/transaction.rb +267 -0
  50. data/lib/gems/dm-core-0.9.7/lib/dm-core/type.rb +160 -0
  51. data/lib/gems/dm-core-0.9.7/lib/dm-core/type_map.rb +80 -0
  52. data/lib/gems/dm-core-0.9.7/lib/dm-core/types/boolean.rb +7 -0
  53. data/lib/gems/dm-core-0.9.7/lib/dm-core/types/discriminator.rb +34 -0
  54. data/lib/gems/dm-core-0.9.7/lib/dm-core/types/object.rb +24 -0
  55. data/lib/gems/dm-core-0.9.7/lib/dm-core/types/paranoid_boolean.rb +34 -0
  56. data/lib/gems/dm-core-0.9.7/lib/dm-core/types/paranoid_datetime.rb +33 -0
  57. data/lib/gems/dm-core-0.9.7/lib/dm-core/types/serial.rb +9 -0
  58. data/lib/gems/dm-core-0.9.7/lib/dm-core/types/text.rb +10 -0
  59. data/lib/gems/dm-core-0.9.7/lib/dm-core/types.rb +19 -0
  60. data/lib/gems/dm-core-0.9.7/lib/dm-core/version.rb +3 -0
  61. data/lib/gems/dm-core-0.9.7/lib/dm-core.rb +217 -0
  62. data/lib/gems/dm-core-0.9.7/script/all +5 -0
  63. data/lib/gems/dm-core-0.9.7/script/performance.rb +284 -0
  64. data/lib/gems/dm-core-0.9.7/script/profile.rb +87 -0
  65. data/lib/gems/dm-migrations-0.9.7/lib/dm-migrations/version.rb +5 -0
  66. data/lib/gems/dm-migrations-0.9.7/lib/dm-migrations.rb +1 -0
  67. data/lib/gems/dm-migrations-0.9.7/lib/migration.rb +215 -0
  68. data/lib/gems/dm-migrations-0.9.7/lib/migration_runner.rb +88 -0
  69. data/lib/gems/dm-migrations-0.9.7/lib/spec/example/migration_example_group.rb +73 -0
  70. data/lib/gems/dm-migrations-0.9.7/lib/spec/matchers/migration_matchers.rb +107 -0
  71. data/lib/gems/dm-migrations-0.9.7/lib/sql/column.rb +9 -0
  72. data/lib/gems/dm-migrations-0.9.7/lib/sql/mysql.rb +52 -0
  73. data/lib/gems/dm-migrations-0.9.7/lib/sql/postgresql.rb +78 -0
  74. data/lib/gems/dm-migrations-0.9.7/lib/sql/sqlite3.rb +43 -0
  75. data/lib/gems/dm-migrations-0.9.7/lib/sql/table.rb +19 -0
  76. data/lib/gems/dm-migrations-0.9.7/lib/sql/table_creator.rb +81 -0
  77. data/lib/gems/dm-migrations-0.9.7/lib/sql/table_modifier.rb +53 -0
  78. data/lib/gems/dm-migrations-0.9.7/lib/sql.rb +10 -0
  79. data/lib/gems/dm-observer-0.9.7/lib/dm-observer/version.rb +5 -0
  80. data/lib/gems/dm-observer-0.9.7/lib/dm-observer.rb +91 -0
  81. data/lib/gems/dm-serializer-0.9.7/lib/dm-serializer/version.rb +5 -0
  82. data/lib/gems/dm-serializer-0.9.7/lib/dm-serializer.rb +183 -0
  83. data/lib/gems/dm-timestamps-0.9.7/lib/dm-timestamps/version.rb +5 -0
  84. data/lib/gems/dm-timestamps-0.9.7/lib/dm-timestamps.rb +57 -0
  85. data/lib/gems/dm-types-0.9.7/lib/dm-types/bcrypt_hash.rb +31 -0
  86. data/lib/gems/dm-types-0.9.7/lib/dm-types/csv.rb +28 -0
  87. data/lib/gems/dm-types-0.9.7/lib/dm-types/enum.rb +70 -0
  88. data/lib/gems/dm-types-0.9.7/lib/dm-types/epoch_time.rb +27 -0
  89. data/lib/gems/dm-types-0.9.7/lib/dm-types/file_path.rb +27 -0
  90. data/lib/gems/dm-types-0.9.7/lib/dm-types/flag.rb +61 -0
  91. data/lib/gems/dm-types-0.9.7/lib/dm-types/ip_address.rb +30 -0
  92. data/lib/gems/dm-types-0.9.7/lib/dm-types/json.rb +40 -0
  93. data/lib/gems/dm-types-0.9.7/lib/dm-types/regexp.rb +20 -0
  94. data/lib/gems/dm-types-0.9.7/lib/dm-types/serial.rb +8 -0
  95. data/lib/gems/dm-types-0.9.7/lib/dm-types/slug.rb +37 -0
  96. data/lib/gems/dm-types-0.9.7/lib/dm-types/uri.rb +29 -0
  97. data/lib/gems/dm-types-0.9.7/lib/dm-types/uuid.rb +64 -0
  98. data/lib/gems/dm-types-0.9.7/lib/dm-types/version.rb +5 -0
  99. data/lib/gems/dm-types-0.9.7/lib/dm-types/yaml.rb +36 -0
  100. data/lib/gems/dm-types-0.9.7/lib/dm-types.rb +28 -0
  101. data/lib/gems/dm-validations-0.9.7/lib/dm-validations/absent_field_validator.rb +60 -0
  102. data/lib/gems/dm-validations-0.9.7/lib/dm-validations/acceptance_validator.rb +76 -0
  103. data/lib/gems/dm-validations-0.9.7/lib/dm-validations/auto_validate.rb +153 -0
  104. data/lib/gems/dm-validations-0.9.7/lib/dm-validations/block_validator.rb +60 -0
  105. data/lib/gems/dm-validations-0.9.7/lib/dm-validations/confirmation_validator.rb +80 -0
  106. data/lib/gems/dm-validations-0.9.7/lib/dm-validations/contextual_validators.rb +56 -0
  107. data/lib/gems/dm-validations-0.9.7/lib/dm-validations/custom_validator.rb +72 -0
  108. data/lib/gems/dm-validations-0.9.7/lib/dm-validations/format_validator.rb +97 -0
  109. data/lib/gems/dm-validations-0.9.7/lib/dm-validations/formats/email.rb +40 -0
  110. data/lib/gems/dm-validations-0.9.7/lib/dm-validations/formats/url.rb +20 -0
  111. data/lib/gems/dm-validations-0.9.7/lib/dm-validations/generic_validator.rb +100 -0
  112. data/lib/gems/dm-validations-0.9.7/lib/dm-validations/length_validator.rb +113 -0
  113. data/lib/gems/dm-validations-0.9.7/lib/dm-validations/method_validator.rb +68 -0
  114. data/lib/gems/dm-validations-0.9.7/lib/dm-validations/numeric_validator.rb +83 -0
  115. data/lib/gems/dm-validations-0.9.7/lib/dm-validations/primitive_validator.rb +60 -0
  116. data/lib/gems/dm-validations-0.9.7/lib/dm-validations/required_field_validator.rb +88 -0
  117. data/lib/gems/dm-validations-0.9.7/lib/dm-validations/support/object.rb +5 -0
  118. data/lib/gems/dm-validations-0.9.7/lib/dm-validations/uniqueness_validator.rb +64 -0
  119. data/lib/gems/dm-validations-0.9.7/lib/dm-validations/validation_errors.rb +63 -0
  120. data/lib/gems/dm-validations-0.9.7/lib/dm-validations/version.rb +5 -0
  121. data/lib/gems/dm-validations-0.9.7/lib/dm-validations/within_validator.rb +53 -0
  122. data/lib/gems/dm-validations-0.9.7/lib/dm-validations.rb +234 -0
  123. data/lib/gems/json_pure-1.1.3/GPL +340 -0
  124. data/lib/gems/json_pure-1.1.3/VERSION +1 -0
  125. data/lib/gems/json_pure-1.1.3/bin/edit_json.rb +10 -0
  126. data/lib/gems/json_pure-1.1.3/bin/prettify_json.rb +76 -0
  127. data/lib/gems/json_pure-1.1.3/lib/json/Array.xpm +21 -0
  128. data/lib/gems/json_pure-1.1.3/lib/json/FalseClass.xpm +21 -0
  129. data/lib/gems/json_pure-1.1.3/lib/json/Hash.xpm +21 -0
  130. data/lib/gems/json_pure-1.1.3/lib/json/Key.xpm +73 -0
  131. data/lib/gems/json_pure-1.1.3/lib/json/NilClass.xpm +21 -0
  132. data/lib/gems/json_pure-1.1.3/lib/json/Numeric.xpm +28 -0
  133. data/lib/gems/json_pure-1.1.3/lib/json/String.xpm +96 -0
  134. data/lib/gems/json_pure-1.1.3/lib/json/TrueClass.xpm +21 -0
  135. data/lib/gems/json_pure-1.1.3/lib/json/add/core.rb +135 -0
  136. data/lib/gems/json_pure-1.1.3/lib/json/add/rails.rb +58 -0
  137. data/lib/gems/json_pure-1.1.3/lib/json/common.rb +354 -0
  138. data/lib/gems/json_pure-1.1.3/lib/json/editor.rb +1362 -0
  139. data/lib/gems/json_pure-1.1.3/lib/json/ext.rb +13 -0
  140. data/lib/gems/json_pure-1.1.3/lib/json/json.xpm +1499 -0
  141. data/lib/gems/json_pure-1.1.3/lib/json/pure/generator.rb +394 -0
  142. data/lib/gems/json_pure-1.1.3/lib/json/pure/parser.rb +259 -0
  143. data/lib/gems/json_pure-1.1.3/lib/json/pure.rb +75 -0
  144. data/lib/gems/json_pure-1.1.3/lib/json/version.rb +9 -0
  145. data/lib/gems/json_pure-1.1.3/lib/json.rb +235 -0
  146. data/lib/gems/launchy-0.3.2/bin/launchy +12 -0
  147. data/lib/gems/launchy-0.3.2/lib/launchy/application.rb +163 -0
  148. data/lib/gems/launchy-0.3.2/lib/launchy/browser.rb +85 -0
  149. data/lib/gems/launchy-0.3.2/lib/launchy/command_line.rb +48 -0
  150. data/lib/gems/launchy-0.3.2/lib/launchy/gemspec.rb +53 -0
  151. data/lib/gems/launchy-0.3.2/lib/launchy/specification.rb +133 -0
  152. data/lib/gems/launchy-0.3.2/lib/launchy/version.rb +18 -0
  153. data/lib/gems/launchy-0.3.2/lib/launchy.rb +58 -0
  154. data/lib/gems/uuidtools-1.0.3/lib/uuidtools/version.rb +32 -0
  155. data/lib/gems/uuidtools-1.0.3/lib/uuidtools.rb +648 -0
  156. data/lib/gems.rb +13 -0
  157. data/lib/mack-data_mapper/migration_generator/migration_generator.rb +5 -0
  158. data/lib/mack-data_mapper/migration_generator/templates/db/migrations/%=@migration_name%.rb.template +1 -1
  159. data/lib/mack-data_mapper/model_generator/manifest.yml +3 -3
  160. data/lib/mack-data_mapper/model_generator/model_generator.rb +8 -1
  161. data/lib/mack-data_mapper/model_generator/templates/model.rb.template +1 -1
  162. data/lib/mack-data_mapper/model_generator/templates/rspec.rb.template +1 -1
  163. data/lib/mack-data_mapper/model_generator/templates/test_case.rb.template +1 -1
  164. data/lib/mack-data_mapper.rb +3 -2
  165. data/lib/mack-data_mapper_tasks.rb +7 -0
  166. metadata +235 -86
@@ -0,0 +1,637 @@
1
+ require 'set'
2
+
3
+ module DataMapper
4
+ module Resource
5
+ include Assertions
6
+
7
+ ##
8
+ #
9
+ # Appends a module for inclusion into the model class after
10
+ # DataMapper::Resource.
11
+ #
12
+ # This is a useful way to extend DataMapper::Resource while still retaining
13
+ # a self.included method.
14
+ #
15
+ # @param [Module] inclusion the module that is to be appended to the module
16
+ # after DataMapper::Resource
17
+ #
18
+ # @return [TrueClass, FalseClass] whether or not the inclusions have been
19
+ # successfully appended to the list
20
+ # @return <TrueClass, FalseClass>
21
+ #-
22
+ # @api public
23
+ def self.append_inclusions(*inclusions)
24
+ extra_inclusions.concat inclusions
25
+ true
26
+ end
27
+
28
+ def self.extra_inclusions
29
+ @extra_inclusions ||= []
30
+ end
31
+
32
+ # When Resource is included in a class this method makes sure
33
+ # it gets all the methods
34
+ #
35
+ # -
36
+ # @api private
37
+ def self.included(model)
38
+ model.extend Model
39
+ model.extend ClassMethods if defined?(ClassMethods)
40
+ model.const_set('Resource', self) unless model.const_defined?('Resource')
41
+ extra_inclusions.each { |inclusion| model.send(:include, inclusion) }
42
+ descendants << model
43
+ class << model
44
+ @_valid_model = false
45
+ attr_reader :_valid_model
46
+ end
47
+ end
48
+
49
+ # Return all classes that include the DataMapper::Resource module
50
+ #
51
+ # ==== Returns
52
+ # Set:: a set containing the including classes
53
+ #
54
+ # ==== Example
55
+ #
56
+ # Class Foo
57
+ # include DataMapper::Resource
58
+ # end
59
+ #
60
+ # DataMapper::Resource.descendants.to_a.first == Foo
61
+ #
62
+ # -
63
+ # @api semipublic
64
+ def self.descendants
65
+ @descendants ||= Set.new
66
+ end
67
+
68
+ # +---------------
69
+ # Instance methods
70
+
71
+ attr_writer :collection
72
+
73
+ alias model class
74
+
75
+ # returns the value of the attribute. Do not read from instance variables directly,
76
+ # but use this method. This method handels the lazy loading the attribute and returning
77
+ # of defaults if nessesary.
78
+ #
79
+ # ==== Parameters
80
+ # name<Symbol>:: name attribute to lookup
81
+ #
82
+ # ==== Returns
83
+ # <Types>:: the value stored at that given attribute, nil if none, and default if necessary
84
+ #
85
+ # ==== Example
86
+ #
87
+ # Class Foo
88
+ # include DataMapper::Resource
89
+ #
90
+ # property :first_name, String
91
+ # property :last_name, String
92
+ #
93
+ # def full_name
94
+ # "#{attribute_get(:first_name)} #{attribute_get(:last_name)}"
95
+ # end
96
+ #
97
+ # # using the shorter syntax
98
+ # def name_for_address_book
99
+ # "#{last_name}, #{first_name}"
100
+ # end
101
+ # end
102
+ #
103
+ # -
104
+ # @api semipublic
105
+ def attribute_get(name)
106
+ properties[name].get(self)
107
+ end
108
+
109
+ # sets the value of the attribute and marks the attribute as dirty
110
+ # if it has been changed so that it may be saved. Do not set from
111
+ # instance variables directly, but use this method. This method
112
+ # handels the lazy loading the property and returning of defaults
113
+ # if nessesary.
114
+ #
115
+ # ==== Parameters
116
+ # name<Symbol>:: name attribute to set
117
+ # value<Type>:: value to store at that location
118
+ #
119
+ # ==== Returns
120
+ # <Types>:: the value stored at that given attribute, nil if none, and default if necessary
121
+ #
122
+ # ==== Example
123
+ #
124
+ # Class Foo
125
+ # include DataMapper::Resource
126
+ #
127
+ # property :first_name, String
128
+ # property :last_name, String
129
+ #
130
+ # def full_name(name)
131
+ # name = name.split(' ')
132
+ # attribute_set(:first_name, name[0])
133
+ # attribute_set(:last_name, name[1])
134
+ # end
135
+ #
136
+ # # using the shorter syntax
137
+ # def name_from_address_book(name)
138
+ # name = name.split(', ')
139
+ # first_name = name[1]
140
+ # last_name = name[0]
141
+ # end
142
+ # end
143
+ #
144
+ # -
145
+ # @api semipublic
146
+ def attribute_set(name, value)
147
+ properties[name].set(self, value)
148
+ end
149
+
150
+ # Compares if its the same object or if attributes are equal
151
+ #
152
+ # ==== Parameters
153
+ # other<Object>:: Object to compare to
154
+ #
155
+ # ==== Returns
156
+ # <True>:: the outcome of the comparison as a boolean
157
+ #
158
+ # -
159
+ # @api public
160
+ def eql?(other)
161
+ return true if object_id == other.object_id
162
+ return false unless other.kind_of?(model)
163
+ return true if repository == other.repository && key == other.key
164
+
165
+ properties.each do |property|
166
+ return false if property.get!(self) != property.get!(other)
167
+ end
168
+
169
+ true
170
+ end
171
+
172
+ alias == eql?
173
+
174
+ # Computes a hash for the resource
175
+ #
176
+ # ==== Returns
177
+ # <Integer>:: the hash value of the resource
178
+ #
179
+ # -
180
+ # @api public
181
+ def hash
182
+ model.hash + key.hash
183
+ end
184
+
185
+ # Inspection of the class name and the attributes
186
+ #
187
+ # ==== Returns
188
+ # <String>:: with the class name, attributes with their values
189
+ #
190
+ # ==== Example
191
+ #
192
+ # >> Foo.new
193
+ # => #<Foo name=nil updated_at=nil created_at=nil id=nil>
194
+ #
195
+ # -
196
+ # @api public
197
+ def inspect
198
+ attrs = []
199
+
200
+ properties.each do |property|
201
+ value = if property.lazy? && !attribute_loaded?(property.name) && !new_record?
202
+ '<not loaded>'
203
+ else
204
+ send(property.getter).inspect
205
+ end
206
+
207
+ attrs << "#{property.name}=#{value}"
208
+ end
209
+
210
+ "#<#{model.name} #{attrs * ' '}>"
211
+ end
212
+
213
+ # TODO docs
214
+ def pretty_print(pp)
215
+ pp.group(1, "#<#{model.name}", ">") do
216
+ pp.breakable
217
+ pp.seplist(attributes.to_a) do |k_v|
218
+ pp.text k_v[0].to_s
219
+ pp.text " = "
220
+ pp.pp k_v[1]
221
+ end
222
+ end
223
+ end
224
+
225
+ ##
226
+ #
227
+ # ==== Returns
228
+ # <Repository>:: the respository this resource belongs to in the context of a collection OR in the class's context
229
+ #
230
+ # @api public
231
+ def repository
232
+ @repository || model.repository
233
+ end
234
+
235
+ # default id method to return the resource id when there is a
236
+ # single key, and the model was defined with a primary key named
237
+ # something other than id
238
+ #
239
+ # ==== Returns
240
+ # <Array[Key], Key> key or keys
241
+ #
242
+ # --
243
+ # @api public
244
+ def id
245
+ key = self.key
246
+ key.first if key.size == 1
247
+ end
248
+
249
+ def key
250
+ key_properties.map do |property|
251
+ original_values[property.name] || property.get!(self)
252
+ end
253
+ end
254
+
255
+ def readonly!
256
+ @readonly = true
257
+ end
258
+
259
+ def readonly?
260
+ @readonly == true
261
+ end
262
+
263
+ # save the instance to the data-store
264
+ #
265
+ # ==== Returns
266
+ # <True, False>:: results of the save
267
+ #
268
+ # @see DataMapper::Repository#save
269
+ #
270
+ # --
271
+ # #public
272
+ def save(context = :default)
273
+ # Takes a context, but does nothing with it. This is to maintain the
274
+ # same API through out all of dm-more. dm-validations requires a
275
+ # context to be passed
276
+
277
+ associations_saved = false
278
+ child_associations.each { |a| associations_saved |= a.save }
279
+
280
+ saved = new_record? ? create : update
281
+
282
+ if saved
283
+ original_values.clear
284
+ end
285
+
286
+ parent_associations.each { |a| associations_saved |= a.save }
287
+
288
+ # We should return true if the model (or any of its associations)
289
+ # were saved.
290
+ (saved | associations_saved) == true
291
+ end
292
+
293
+ # destroy the instance, remove it from the repository
294
+ #
295
+ # ==== Returns
296
+ # <True, False>:: results of the destruction
297
+ #
298
+ # --
299
+ # @api public
300
+ def destroy
301
+ return false if new_record?
302
+ return false unless repository.delete(to_query)
303
+
304
+ @new_record = true
305
+ repository.identity_map(model).delete(key)
306
+ original_values.clear
307
+
308
+ properties.each do |property|
309
+ # We'll set the original value to nil as if we had a new record
310
+ original_values[property.name] = nil if attribute_loaded?(property.name)
311
+ end
312
+
313
+ true
314
+ end
315
+
316
+ # Checks if the attribute has been loaded
317
+ #
318
+ # ==== Example
319
+ #
320
+ # class Foo
321
+ # include DataMapper::Resource
322
+ # property :name, String
323
+ # property :description, Text, :lazy => false
324
+ # end
325
+ #
326
+ # Foo.new.attribute_loaded?(:description) # will return false
327
+ #
328
+ # --
329
+ # @api public
330
+ def attribute_loaded?(name)
331
+ instance_variable_defined?(properties[name].instance_variable_name)
332
+ end
333
+
334
+ # fetches all the names of the attributes that have been loaded,
335
+ # even if they are lazy but have been called
336
+ #
337
+ # ==== Returns
338
+ # Array[<Symbol>]:: names of attributes that have been loaded
339
+ #
340
+ # ==== Example
341
+ #
342
+ # class Foo
343
+ # include DataMapper::Resource
344
+ # property :name, String
345
+ # property :description, Text, :lazy => false
346
+ # end
347
+ #
348
+ # Foo.new.loaded_attributes # returns [:name]
349
+ #
350
+ # --
351
+ # @api public
352
+ def loaded_attributes
353
+ properties.map{|p| p.name if attribute_loaded?(p.name)}.compact
354
+ end
355
+
356
+ # set of original values of properties
357
+ #
358
+ # ==== Returns
359
+ # Hash:: original values of properties
360
+ #
361
+ # --
362
+ # @api public
363
+ def original_values
364
+ @original_values ||= {}
365
+ end
366
+
367
+ # Hash of attributes that have been marked dirty
368
+ #
369
+ # ==== Returns
370
+ # Hash:: attributes that have been marked dirty
371
+ #
372
+ # --
373
+ # @api private
374
+ def dirty_attributes
375
+ dirty_attributes = {}
376
+ properties = self.properties
377
+
378
+ original_values.each do |name, old_value|
379
+ property = properties[name]
380
+ new_value = property.get!(self)
381
+
382
+ dirty = case property.track
383
+ when :hash then old_value != new_value.hash
384
+ else
385
+ property.value(old_value) != property.value(new_value)
386
+ end
387
+
388
+ if dirty
389
+ property.hash
390
+ dirty_attributes[property] = property.value(new_value)
391
+ end
392
+ end
393
+
394
+ dirty_attributes
395
+ end
396
+
397
+ # Checks if the class is dirty
398
+ #
399
+ # ==== Returns
400
+ # True:: returns if class is dirty
401
+ #
402
+ # --
403
+ # @api public
404
+ def dirty?
405
+ dirty_attributes.any?
406
+ end
407
+
408
+ # Checks if the attribute is dirty
409
+ #
410
+ # ==== Parameters
411
+ # name<Symbol>:: name of attribute
412
+ #
413
+ # ==== Returns
414
+ # True:: returns if attribute is dirty
415
+ #
416
+ # --
417
+ # @api public
418
+ def attribute_dirty?(name)
419
+ dirty_attributes.has_key?(properties[name])
420
+ end
421
+
422
+ def collection
423
+ @collection ||= if query = to_query
424
+ Collection.new(query) { |c| c << self }
425
+ end
426
+ end
427
+
428
+ # Reload association and all child association
429
+ #
430
+ # ==== Returns
431
+ # self:: returns the class itself
432
+ #
433
+ # --
434
+ # @api public
435
+ def reload
436
+ unless new_record?
437
+ reload_attributes(*loaded_attributes)
438
+ (parent_associations + child_associations).each { |association| association.reload }
439
+ end
440
+
441
+ self
442
+ end
443
+
444
+ # Reload specific attributes
445
+ #
446
+ # ==== Parameters
447
+ # *attributes<Array[<Symbol>]>:: name of attribute
448
+ #
449
+ # ==== Returns
450
+ # self:: returns the class itself
451
+ #
452
+ # --
453
+ # @api public
454
+ def reload_attributes(*attributes)
455
+ unless attributes.empty? || new_record?
456
+ collection.reload(:fields => attributes)
457
+ end
458
+
459
+ self
460
+ end
461
+
462
+ # Checks if the model has been saved
463
+ #
464
+ # ==== Returns
465
+ # True:: status if the model is new
466
+ #
467
+ # --
468
+ # @api public
469
+ def new_record?
470
+ !defined?(@new_record) || @new_record
471
+ end
472
+
473
+ # all the attributes of the model
474
+ #
475
+ # ==== Returns
476
+ # Hash[<Symbol>]:: All the (non)-lazy attributes
477
+ #
478
+ # --
479
+ # @api public
480
+ def attributes
481
+ properties.map do |p|
482
+ [p.name, send(p.getter)] if p.reader_visibility == :public
483
+ end.compact.to_hash
484
+ end
485
+
486
+ # Mass assign of attributes
487
+ #
488
+ # ==== Parameters
489
+ # value_hash <Hash[<Symbol>]>::
490
+ #
491
+ # --
492
+ # @api public
493
+ def attributes=(values_hash)
494
+ values_hash.each_pair do |k,v|
495
+ setter = "#{k.to_s.sub(/\?\z/, '')}="
496
+
497
+ if respond_to?(setter)
498
+ send(setter, v)
499
+ else
500
+ raise NameError, "#{setter} is not a public property"
501
+ end
502
+ end
503
+ end
504
+
505
+ # Updates attributes and saves model
506
+ #
507
+ # ==== Parameters
508
+ # attributes<Hash> Attributes to be updated
509
+ # keys<Symbol, String, Array> keys of Hash to update (others won't be updated)
510
+ #
511
+ # ==== Returns
512
+ # <TrueClass, FalseClass> if model got saved or not
513
+ #
514
+ #-
515
+ # @api public
516
+ def update_attributes(hash, *update_only)
517
+ unless hash.is_a?(Hash)
518
+ raise ArgumentError, "Expecting the first parameter of " +
519
+ "update_attributes to be a hash; got #{hash.inspect}"
520
+ end
521
+ loop_thru = update_only.empty? ? hash.keys : update_only
522
+ loop_thru.each { |attr| send("#{attr}=", hash[attr]) }
523
+ save
524
+ end
525
+
526
+ # TODO: add docs
527
+ def to_query(query = {})
528
+ model.to_query(repository, key, query) unless new_record?
529
+ end
530
+
531
+ protected
532
+
533
+ def properties
534
+ model.properties(repository.name)
535
+ end
536
+
537
+ def key_properties
538
+ model.key(repository.name)
539
+ end
540
+
541
+ def relationships
542
+ model.relationships(repository.name)
543
+ end
544
+
545
+ # Needs to be a protected method so that it is hookable
546
+ def create
547
+ # Can't create a resource that is not dirty and doesn't have serial keys
548
+ return false if new_record? && !dirty? && !model.key.any? { |p| p.serial? }
549
+ # set defaults for new resource
550
+ properties.each do |property|
551
+ next if attribute_loaded?(property.name)
552
+ property.set(self, property.default_for(self))
553
+ end
554
+
555
+ return false unless repository.create([ self ]) == 1
556
+
557
+ @repository = repository
558
+ @new_record = false
559
+
560
+ repository.identity_map(model).set(key, self)
561
+
562
+ true
563
+ end
564
+
565
+ # Needs to be a protected method so that it is hookable
566
+ def update
567
+ dirty_attributes = self.dirty_attributes
568
+ return true if dirty_attributes.empty?
569
+ repository.update(dirty_attributes, to_query) == 1
570
+ end
571
+
572
+ private
573
+
574
+ def initialize(attributes = {}) # :nodoc:
575
+ assert_valid_model
576
+ self.attributes = attributes
577
+ end
578
+
579
+ def assert_valid_model # :nodoc:
580
+ return if self.class._valid_model
581
+ properties = self.properties
582
+
583
+ if properties.empty? && relationships.empty?
584
+ raise IncompleteResourceError, "#{model.name} must have at least one property or relationship to be initialized."
585
+ end
586
+
587
+ if properties.key.empty?
588
+ raise IncompleteResourceError, "#{model.name} must have a key."
589
+ end
590
+
591
+ self.class.instance_variable_set("@_valid_model", true)
592
+ end
593
+
594
+ # TODO document
595
+ # @api semipublic
596
+ def attribute_get!(name)
597
+ properties[name].get!(self)
598
+ end
599
+
600
+ # TODO document
601
+ # @api semipublic
602
+ def attribute_set!(name, value)
603
+ properties[name].set!(self, value)
604
+ end
605
+
606
+ def lazy_load(name)
607
+ reload_attributes(*properties.lazy_load_context(name) - loaded_attributes)
608
+ end
609
+
610
+ def child_associations
611
+ @child_associations ||= []
612
+ end
613
+
614
+ def parent_associations
615
+ @parent_associations ||= []
616
+ end
617
+
618
+ # TODO: move to dm-more/dm-transactions
619
+ module Transaction
620
+ # Produce a new Transaction for the class of this Resource
621
+ #
622
+ # ==== Returns
623
+ # <DataMapper::Adapters::Transaction>::
624
+ # a new DataMapper::Adapters::Transaction with all DataMapper::Repositories
625
+ # of the class of this DataMapper::Resource added.
626
+ #-
627
+ # @api public
628
+ #
629
+ # TODO: move to dm-more/dm-transactions
630
+ def transaction
631
+ model.transaction { |*block_args| yield(*block_args) }
632
+ end
633
+ end # module Transaction
634
+
635
+ include Transaction
636
+ end # module Resource
637
+ end # module DataMapper
@@ -0,0 +1,58 @@
1
+ module DataMapper
2
+ module Scope
3
+ Model.append_extensions self
4
+
5
+ # @api private
6
+ def default_scope(repository_name = nil)
7
+ repository_name = self.default_repository_name if repository_name == :default || repository_name.nil?
8
+ @default_scope ||= {}
9
+ @default_scope[repository_name] ||= {}
10
+ end
11
+
12
+ # @api private
13
+ def query
14
+ scope_stack.last
15
+ end
16
+
17
+ protected
18
+
19
+ # @api semipublic
20
+ def with_scope(query)
21
+ # merge the current scope with the passed in query
22
+ with_exclusive_scope(self.query ? self.query.merge(query) : query) {|*block_args| yield(*block_args) }
23
+ end
24
+
25
+ # @api semipublic
26
+ def with_exclusive_scope(query)
27
+ query = DataMapper::Query.new(repository, self, query) if query.kind_of?(Hash)
28
+
29
+ scope_stack << query
30
+
31
+ begin
32
+ return yield(query)
33
+ ensure
34
+ scope_stack.pop
35
+ end
36
+ end
37
+
38
+ private
39
+
40
+ # @api private
41
+ def merge_with_default_scope(query)
42
+ DataMapper::Query.new(query.repository, query.model, default_scope_for_query(query)).update(query)
43
+ end
44
+
45
+ # @api private
46
+ def scope_stack
47
+ scope_stack_for = Thread.current[:dm_scope_stack] ||= {}
48
+ scope_stack_for[self] ||= []
49
+ end
50
+
51
+ # @api private
52
+ def default_scope_for_query(query)
53
+ repository_name = query.repository.name
54
+ default_repository_name = query.model.default_repository_name
55
+ self.default_scope(default_repository_name).merge(self.default_scope(repository_name))
56
+ end
57
+ end # module Scope
58
+ end # module DataMapper
@@ -0,0 +1,13 @@
1
+ class Array
2
+
3
+ ##
4
+ # atm it assumes self is an array of [key,value]-arrays
5
+ # this is just a better way to make hashes than Hash[*array.flatten]
6
+ # since you cannot flatten only one level in ruby 1.8.6
7
+ #
8
+ def to_hash
9
+ h = {}
10
+ self.each{ |k,v| h[k] = v }
11
+ h
12
+ end
13
+ end # class Symbol
@@ -0,0 +1,8 @@
1
+ module DataMapper
2
+ module Assertions
3
+ def assert_kind_of(name, value, *klasses)
4
+ klasses.each { |k| return if value.kind_of?(k) }
5
+ raise ArgumentError, "+#{name}+ should be #{klasses.map { |k| k.name } * ' or '}, but was #{value.class.name}", caller(2)
6
+ end
7
+ end
8
+ end # module DataMapper