datamapper 0.3.2 → 0.9.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.
- data/History.txt +0 -0
- data/Manifest.txt +5 -0
- data/README.txt +11 -0
- data/Rakefile +70 -0
- data/lib/datamapper.rb +8 -0
- metadata +152 -319
- data/CHANGELOG +0 -145
- data/FAQ +0 -96
- data/MIT-LICENSE +0 -22
- data/QUICKLINKS +0 -12
- data/README +0 -105
- data/environment.rb +0 -62
- data/example.rb +0 -156
- data/lib/data_mapper.rb +0 -88
- data/lib/data_mapper/adapters/abstract_adapter.rb +0 -43
- data/lib/data_mapper/adapters/data_object_adapter.rb +0 -480
- data/lib/data_mapper/adapters/mysql_adapter.rb +0 -72
- data/lib/data_mapper/adapters/postgresql_adapter.rb +0 -258
- data/lib/data_mapper/adapters/sql/coersion.rb +0 -134
- data/lib/data_mapper/adapters/sql/commands/load_command.rb +0 -545
- data/lib/data_mapper/adapters/sql/mappings/associations_set.rb +0 -34
- data/lib/data_mapper/adapters/sql/mappings/column.rb +0 -279
- data/lib/data_mapper/adapters/sql/mappings/conditions.rb +0 -172
- data/lib/data_mapper/adapters/sql/mappings/schema.rb +0 -60
- data/lib/data_mapper/adapters/sql/mappings/table.rb +0 -459
- data/lib/data_mapper/adapters/sql/quoting.rb +0 -24
- data/lib/data_mapper/adapters/sqlite3_adapter.rb +0 -159
- data/lib/data_mapper/associations.rb +0 -106
- data/lib/data_mapper/associations/belongs_to_association.rb +0 -160
- data/lib/data_mapper/associations/has_and_belongs_to_many_association.rb +0 -437
- data/lib/data_mapper/associations/has_many_association.rb +0 -283
- data/lib/data_mapper/associations/has_n_association.rb +0 -143
- data/lib/data_mapper/associations/reference.rb +0 -47
- data/lib/data_mapper/attributes.rb +0 -73
- data/lib/data_mapper/auto_migrations.rb +0 -36
- data/lib/data_mapper/base.rb +0 -17
- data/lib/data_mapper/callbacks.rb +0 -107
- data/lib/data_mapper/context.rb +0 -112
- data/lib/data_mapper/database.rb +0 -234
- data/lib/data_mapper/dependency_queue.rb +0 -28
- data/lib/data_mapper/embedded_value.rb +0 -145
- data/lib/data_mapper/identity_map.rb +0 -47
- data/lib/data_mapper/is/tree.rb +0 -121
- data/lib/data_mapper/migration.rb +0 -155
- data/lib/data_mapper/persistence.rb +0 -852
- data/lib/data_mapper/property.rb +0 -310
- data/lib/data_mapper/query.rb +0 -164
- data/lib/data_mapper/support/blank.rb +0 -35
- data/lib/data_mapper/support/connection_pool.rb +0 -117
- data/lib/data_mapper/support/enumerable.rb +0 -35
- data/lib/data_mapper/support/errors.rb +0 -16
- data/lib/data_mapper/support/inflector.rb +0 -265
- data/lib/data_mapper/support/object.rb +0 -54
- data/lib/data_mapper/support/serialization.rb +0 -96
- data/lib/data_mapper/support/silence.rb +0 -10
- data/lib/data_mapper/support/string.rb +0 -72
- data/lib/data_mapper/support/struct.rb +0 -7
- data/lib/data_mapper/support/symbol.rb +0 -82
- data/lib/data_mapper/support/typed_set.rb +0 -65
- data/lib/data_mapper/types/base.rb +0 -44
- data/lib/data_mapper/types/string.rb +0 -34
- data/lib/data_mapper/validatable_extensions/errors.rb +0 -12
- data/lib/data_mapper/validatable_extensions/macros.rb +0 -7
- data/lib/data_mapper/validatable_extensions/validatable_instance_methods.rb +0 -62
- data/lib/data_mapper/validatable_extensions/validation_base.rb +0 -18
- data/lib/data_mapper/validatable_extensions/validations/formats/email.rb +0 -43
- data/lib/data_mapper/validatable_extensions/validations/validates_acceptance_of.rb +0 -7
- data/lib/data_mapper/validatable_extensions/validations/validates_confirmation_of.rb +0 -7
- data/lib/data_mapper/validatable_extensions/validations/validates_each.rb +0 -7
- data/lib/data_mapper/validatable_extensions/validations/validates_format_of.rb +0 -28
- data/lib/data_mapper/validatable_extensions/validations/validates_length_of.rb +0 -15
- data/lib/data_mapper/validatable_extensions/validations/validates_numericality_of.rb +0 -7
- data/lib/data_mapper/validatable_extensions/validations/validates_presence_of.rb +0 -7
- data/lib/data_mapper/validatable_extensions/validations/validates_true_for.rb +0 -7
- data/lib/data_mapper/validatable_extensions/validations/validates_uniqueness_of.rb +0 -40
- data/lib/data_mapper/validations.rb +0 -20
- data/lib/data_mapper/validations/number_validator.rb +0 -40
- data/lib/data_mapper/validations/string_validator.rb +0 -20
- data/lib/data_mapper/validations/validator.rb +0 -13
- data/performance.rb +0 -307
- data/plugins/can_has_sphinx/LICENSE +0 -23
- data/plugins/can_has_sphinx/README +0 -4
- data/plugins/can_has_sphinx/REVISION +0 -1
- data/plugins/can_has_sphinx/Rakefile +0 -22
- data/plugins/can_has_sphinx/init.rb +0 -1
- data/plugins/can_has_sphinx/install.rb +0 -1
- data/plugins/can_has_sphinx/lib/acts_as_sphinx.rb +0 -123
- data/plugins/can_has_sphinx/lib/sphinx.rb +0 -460
- data/plugins/can_has_sphinx/scripts/sphinx.sh +0 -47
- data/plugins/can_has_sphinx/tasks/acts_as_sphinx_tasks.rake +0 -41
- data/profile_data_mapper.rb +0 -40
- data/rakefile.rb +0 -159
- data/spec/acts_as_tree_spec.rb +0 -67
- data/spec/adapters/data_object_adapter_spec.rb +0 -31
- data/spec/associations/belongs_to_association_spec.rb +0 -98
- data/spec/associations/has_and_belongs_to_many_association_spec.rb +0 -377
- data/spec/associations/has_many_association_spec.rb +0 -337
- data/spec/attributes_spec.rb +0 -52
- data/spec/auto_migrations_spec.rb +0 -101
- data/spec/callbacks_spec.rb +0 -186
- data/spec/can_has_sphinx.rb +0 -5
- data/spec/coersion_spec.rb +0 -41
- data/spec/column_spec.rb +0 -114
- data/spec/count_command_spec.rb +0 -45
- data/spec/database_spec.rb +0 -18
- data/spec/dataobjects_spec.rb +0 -27
- data/spec/delete_command_spec.rb +0 -11
- data/spec/dependency_spec.rb +0 -29
- data/spec/embedded_value_spec.rb +0 -161
- data/spec/fixtures/animals.yaml +0 -33
- data/spec/fixtures/animals_exhibits.yaml +0 -2
- data/spec/fixtures/careers.yaml +0 -5
- data/spec/fixtures/comments.yaml +0 -1
- data/spec/fixtures/exhibits.yaml +0 -90
- data/spec/fixtures/fruit.yaml +0 -6
- data/spec/fixtures/people.yaml +0 -37
- data/spec/fixtures/posts.yaml +0 -3
- data/spec/fixtures/projects.yaml +0 -13
- data/spec/fixtures/sections.yaml +0 -5
- data/spec/fixtures/serializers.yaml +0 -6
- data/spec/fixtures/tasks.yaml +0 -6
- data/spec/fixtures/tasks_tasks.yaml +0 -2
- data/spec/fixtures/tomatoes.yaml +0 -1
- data/spec/fixtures/users.yaml +0 -1
- data/spec/fixtures/zoos.yaml +0 -24
- data/spec/is_a_tree_spec.rb +0 -149
- data/spec/legacy_spec.rb +0 -16
- data/spec/load_command_spec.rb +0 -322
- data/spec/magic_columns_spec.rb +0 -26
- data/spec/migration_spec.rb +0 -267
- data/spec/mock_adapter.rb +0 -20
- data/spec/models/animal.rb +0 -12
- data/spec/models/candidate.rb +0 -8
- data/spec/models/career.rb +0 -7
- data/spec/models/chain.rb +0 -8
- data/spec/models/comment.rb +0 -6
- data/spec/models/exhibit.rb +0 -14
- data/spec/models/fence.rb +0 -7
- data/spec/models/fruit.rb +0 -8
- data/spec/models/job.rb +0 -8
- data/spec/models/person.rb +0 -30
- data/spec/models/post.rb +0 -14
- data/spec/models/project.rb +0 -41
- data/spec/models/sales_person.rb +0 -5
- data/spec/models/section.rb +0 -8
- data/spec/models/serializer.rb +0 -5
- data/spec/models/task.rb +0 -9
- data/spec/models/tomato.rb +0 -27
- data/spec/models/user.rb +0 -12
- data/spec/models/zoo.rb +0 -13
- data/spec/natural_key_spec.rb +0 -36
- data/spec/paranoia_spec.rb +0 -38
- data/spec/persistence_spec.rb +0 -479
- data/spec/postgres_spec.rb +0 -96
- data/spec/property_spec.rb +0 -151
- data/spec/query_spec.rb +0 -77
- data/spec/save_command_spec.rb +0 -94
- data/spec/schema_spec.rb +0 -8
- data/spec/serialize_spec.rb +0 -19
- data/spec/single_table_inheritance_spec.rb +0 -43
- data/spec/spec_helper.rb +0 -45
- data/spec/support/blank_spec.rb +0 -8
- data/spec/support/inflector_spec.rb +0 -41
- data/spec/support/object_spec.rb +0 -9
- data/spec/support/serialization_spec.rb +0 -61
- data/spec/support/silence_spec.rb +0 -15
- data/spec/support/string_spec.rb +0 -7
- data/spec/support/struct_spec.rb +0 -12
- data/spec/support/typed_set_spec.rb +0 -66
- data/spec/symbolic_operators_spec.rb +0 -27
- data/spec/table_spec.rb +0 -79
- data/spec/types/string.rb +0 -81
- data/spec/validates_confirmation_of_spec.rb +0 -55
- data/spec/validates_format_of_spec.rb +0 -78
- data/spec/validates_length_of_spec.rb +0 -117
- data/spec/validates_uniqueness_of_spec.rb +0 -92
- data/spec/validations/number_validator.rb +0 -59
- data/spec/validations/string_validator.rb +0 -14
- data/spec/validations_spec.rb +0 -141
- data/tasks/fixtures.rb +0 -53
data/lib/data_mapper/database.rb
DELETED
|
@@ -1,234 +0,0 @@
|
|
|
1
|
-
require 'logger'
|
|
2
|
-
require 'data_mapper/context'
|
|
3
|
-
require 'data_mapper/adapters/abstract_adapter'
|
|
4
|
-
|
|
5
|
-
# Delegates to DataMapper::database.
|
|
6
|
-
# Will not overwrite if a method of the same name is pre-defined.
|
|
7
|
-
def database(name = :default, &block)
|
|
8
|
-
DataMapper::database(name, &block)
|
|
9
|
-
end unless methods.include?(:database)
|
|
10
|
-
|
|
11
|
-
module DataMapper
|
|
12
|
-
|
|
13
|
-
# ===Block Syntax:
|
|
14
|
-
# Pushes the named database onto the context-stack,
|
|
15
|
-
# yields a new session, and pops the context-stack.
|
|
16
|
-
#
|
|
17
|
-
# results = DataMapper.database(:second_database) do |current_context|
|
|
18
|
-
# ...
|
|
19
|
-
# end
|
|
20
|
-
#
|
|
21
|
-
# ===Non-Block Syntax:
|
|
22
|
-
# Returns the current session, or if there is none,
|
|
23
|
-
# a new Session.
|
|
24
|
-
#
|
|
25
|
-
# current_database = DataMapper.database
|
|
26
|
-
def self.database(name = :default) # :yields: current_context
|
|
27
|
-
unless block_given?
|
|
28
|
-
Database.context.last || Context.new(Database[name].adapter)
|
|
29
|
-
else
|
|
30
|
-
begin
|
|
31
|
-
Database.context.push(Context.new(Database[name].adapter))
|
|
32
|
-
return yield(Database.context.last)
|
|
33
|
-
ensure
|
|
34
|
-
Database.context.pop
|
|
35
|
-
end
|
|
36
|
-
end
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
class DatabaseError < StandardError
|
|
40
|
-
attr_accessor :options
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
# The Database class allows us to setup a default database for use throughout our applications
|
|
44
|
-
# or allows us to setup a collection of databases to use.
|
|
45
|
-
#
|
|
46
|
-
# === Example
|
|
47
|
-
# ==== To setup a default database
|
|
48
|
-
# DataMapper::Database.setup({
|
|
49
|
-
# :adapter => 'mysql'
|
|
50
|
-
# :host => 'localhost'
|
|
51
|
-
# :username => 'root'
|
|
52
|
-
# :password => 'R00tPaswooooord'
|
|
53
|
-
# :database => 'selecta_development'
|
|
54
|
-
# })
|
|
55
|
-
#
|
|
56
|
-
# ==== To setup a named database
|
|
57
|
-
# DataMapper::Database.setup(:second_database, {
|
|
58
|
-
# :adapter => 'postgresql'
|
|
59
|
-
# :host => 'localhost'
|
|
60
|
-
# :username => 'second_user'
|
|
61
|
-
# :password => 'second_password'
|
|
62
|
-
# :database => 'second_database'
|
|
63
|
-
# })
|
|
64
|
-
#
|
|
65
|
-
#
|
|
66
|
-
# ==== Working with multiple databases (see #DataMapper::database)
|
|
67
|
-
# DataMapper.database(:second_database) do
|
|
68
|
-
# ...
|
|
69
|
-
# end
|
|
70
|
-
#
|
|
71
|
-
# DataMapper.database(:default) do
|
|
72
|
-
# ...
|
|
73
|
-
# end
|
|
74
|
-
#
|
|
75
|
-
# or even...
|
|
76
|
-
#
|
|
77
|
-
# #The below variables still hold on to their database sessions.
|
|
78
|
-
# #So no confusion happens when passing variables around scopes.
|
|
79
|
-
#
|
|
80
|
-
# DataMapper.database(:second_database) do
|
|
81
|
-
#
|
|
82
|
-
# animal = Animal.first
|
|
83
|
-
#
|
|
84
|
-
# DataMapper.database(:default) do
|
|
85
|
-
# Animal.new(animal).save
|
|
86
|
-
# end # :default database
|
|
87
|
-
#
|
|
88
|
-
# end # :second_database
|
|
89
|
-
class Database
|
|
90
|
-
|
|
91
|
-
@databases = {}
|
|
92
|
-
|
|
93
|
-
# Allows you to access any of the named databases you have already setup.
|
|
94
|
-
#
|
|
95
|
-
# default_db = DataMapper::Database[:default]
|
|
96
|
-
# second_db = DataMapper::Database[:second_database]
|
|
97
|
-
def self.[](name)
|
|
98
|
-
@databases[name]
|
|
99
|
-
end
|
|
100
|
-
|
|
101
|
-
# Returns the array of Database sessions currently being used
|
|
102
|
-
#
|
|
103
|
-
# This is what gives us thread safety, boys and girls
|
|
104
|
-
def self.context
|
|
105
|
-
Thread::current[:database_contexts] || Thread::current[:database_contexts] = []
|
|
106
|
-
end
|
|
107
|
-
|
|
108
|
-
# Setup creates a database and sets all of your properties for that database.
|
|
109
|
-
# Setup looks for either a hash of options passed in to the database or a symbolized name
|
|
110
|
-
# for your database, as well as it's hash of parameters
|
|
111
|
-
#
|
|
112
|
-
# If no options are passed, an ArgumentException will be raised.
|
|
113
|
-
#
|
|
114
|
-
# DataMapper::Database.setup(name = :default, options_hash)
|
|
115
|
-
#
|
|
116
|
-
# DataMapper::Database.setup({
|
|
117
|
-
# :adapter => 'mysql'
|
|
118
|
-
# :host => 'localhost'
|
|
119
|
-
# :username => 'root'
|
|
120
|
-
# :password => 'R00tPaswooooord'
|
|
121
|
-
# :database => 'selecta_development'
|
|
122
|
-
# })
|
|
123
|
-
#
|
|
124
|
-
#
|
|
125
|
-
# DataMapper::Database.setup(:named_database, {
|
|
126
|
-
# :adapter => 'mysql'
|
|
127
|
-
# :host => 'localhost'
|
|
128
|
-
# :username => 'root'
|
|
129
|
-
# :password => 'R00tPaswooooord'
|
|
130
|
-
# :database => 'selecta_development'
|
|
131
|
-
# })
|
|
132
|
-
|
|
133
|
-
def self.setup(*args)
|
|
134
|
-
|
|
135
|
-
name, options = nil
|
|
136
|
-
|
|
137
|
-
if (args.nil?) || (args[1].nil? && args[0].class != Hash)
|
|
138
|
-
raise ArgumentError.new('Database cannot be setup without at least an options hash.')
|
|
139
|
-
end
|
|
140
|
-
|
|
141
|
-
if args.size == 1
|
|
142
|
-
name, options = :default, args[0]
|
|
143
|
-
elsif args.size == 2
|
|
144
|
-
name, options = args[0], args[1]
|
|
145
|
-
end
|
|
146
|
-
|
|
147
|
-
current = self.new(name)
|
|
148
|
-
|
|
149
|
-
current.single_threaded = false if options[:single_threaded] == false
|
|
150
|
-
|
|
151
|
-
options.each_pair do |k,v|
|
|
152
|
-
current.send("#{k}=", v)
|
|
153
|
-
end
|
|
154
|
-
|
|
155
|
-
@databases[name] = current
|
|
156
|
-
end
|
|
157
|
-
|
|
158
|
-
# Creates a new database object with the name you specify, and a default set of options.
|
|
159
|
-
#
|
|
160
|
-
# The default options are as follows:
|
|
161
|
-
# { :host => 'localhost', :database => nil, :port => nil, :username => 'root', :password => '', :adapter = nil }
|
|
162
|
-
def initialize(name)
|
|
163
|
-
@name = name
|
|
164
|
-
|
|
165
|
-
@adapter = nil
|
|
166
|
-
@host = 'localhost'
|
|
167
|
-
@database = nil
|
|
168
|
-
@port = nil
|
|
169
|
-
@schema_search_path = nil
|
|
170
|
-
@username = 'root'
|
|
171
|
-
@password = ''
|
|
172
|
-
@socket = nil
|
|
173
|
-
|
|
174
|
-
@log_level = Logger::WARN
|
|
175
|
-
@log_stream = nil
|
|
176
|
-
end
|
|
177
|
-
|
|
178
|
-
attr_reader :name, :adapter, :log_stream
|
|
179
|
-
|
|
180
|
-
attr_accessor :host, :database, :port, :schema_search_path, :username, :password, :log_level, :index_path, :socket
|
|
181
|
-
|
|
182
|
-
def log_stream=(val)
|
|
183
|
-
@log_stream = (val.is_a?(String) && val =~ /STDOUT/ ? STDOUT : val)
|
|
184
|
-
end
|
|
185
|
-
|
|
186
|
-
# Allows us to set the adapter for this database object. It can only be set once, and expects two types of values.
|
|
187
|
-
#
|
|
188
|
-
# You may pass in either a class inheriting from DataMapper::Adapters::AbstractAdapter
|
|
189
|
-
# or pass in a string indicating the type of adapter you would like to use.
|
|
190
|
-
#
|
|
191
|
-
# To create your own adapters, create a file in data_mapper/adapters/new_adapter.rb that inherits from AbstractAdapter
|
|
192
|
-
#
|
|
193
|
-
# database.adapter=("postgresql")
|
|
194
|
-
def adapter=(value)
|
|
195
|
-
if @adapter
|
|
196
|
-
raise ArgumentError.new('The adapter is readonly after being set')
|
|
197
|
-
end
|
|
198
|
-
|
|
199
|
-
if value.is_a?(DataMapper::Adapters::AbstractAdapter)
|
|
200
|
-
@adapter = value
|
|
201
|
-
elsif value.is_a?(Class)
|
|
202
|
-
@adapter = value.new(self)
|
|
203
|
-
else
|
|
204
|
-
begin
|
|
205
|
-
require "data_mapper/adapters/#{Inflector.underscore(value)}_adapter"
|
|
206
|
-
rescue LoadError
|
|
207
|
-
require "#{Inflector.underscore(value)}_adapter"
|
|
208
|
-
end
|
|
209
|
-
adapter_class = Adapters::const_get(Inflector.classify(value) + "Adapter")
|
|
210
|
-
|
|
211
|
-
@adapter = adapter_class.new(self)
|
|
212
|
-
end
|
|
213
|
-
end
|
|
214
|
-
|
|
215
|
-
# Default Logger from Ruby's logger.rb
|
|
216
|
-
def logger
|
|
217
|
-
@logger = create_logger
|
|
218
|
-
|
|
219
|
-
class << self
|
|
220
|
-
attr_reader :logger
|
|
221
|
-
end
|
|
222
|
-
|
|
223
|
-
return @logger
|
|
224
|
-
end
|
|
225
|
-
|
|
226
|
-
def create_logger
|
|
227
|
-
x = Logger.new(@log_stream, File::WRONLY | File::APPEND | File::CREAT)
|
|
228
|
-
x.level = @log_level
|
|
229
|
-
at_exit { x.close }
|
|
230
|
-
return x
|
|
231
|
-
end
|
|
232
|
-
end
|
|
233
|
-
|
|
234
|
-
end
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
module DataMapper
|
|
2
|
-
class DependencyQueue
|
|
3
|
-
|
|
4
|
-
def initialize
|
|
5
|
-
@dependencies = Hash.new { |h,k| h[k] = [] }
|
|
6
|
-
end
|
|
7
|
-
|
|
8
|
-
def add(class_name, &b)
|
|
9
|
-
@dependencies[class_name] << b
|
|
10
|
-
resolve!
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
def resolve!
|
|
14
|
-
@dependencies.each_pair do |class_name, callbacks|
|
|
15
|
-
if Object.const_defined?(class_name)
|
|
16
|
-
klass = Object.const_get(class_name)
|
|
17
|
-
|
|
18
|
-
callbacks.each do |b|
|
|
19
|
-
b.call(klass)
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
callbacks.clear
|
|
23
|
-
end
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
end # class DependencyQueue
|
|
28
|
-
end # module DataMapper
|
|
@@ -1,145 +0,0 @@
|
|
|
1
|
-
module DataMapper
|
|
2
|
-
|
|
3
|
-
# == EmbeddedValue
|
|
4
|
-
# As an alternative to an extraneous has_one association, EmbeddedValue offers a means
|
|
5
|
-
# to serialize component objects to a table without having to define an entirely new model.
|
|
6
|
-
#
|
|
7
|
-
# Example:
|
|
8
|
-
#
|
|
9
|
-
# class Person < DataMapper::Base
|
|
10
|
-
#
|
|
11
|
-
# property :name, :string
|
|
12
|
-
# property :occupation, :string
|
|
13
|
-
#
|
|
14
|
-
# embed :address, :prefix => true do
|
|
15
|
-
# property :street, :string
|
|
16
|
-
# property :city, :string
|
|
17
|
-
# property :state, :string, :size => 2
|
|
18
|
-
# property :zip_code, :string, :size => 10
|
|
19
|
-
#
|
|
20
|
-
# def city_state_zip_code
|
|
21
|
-
# "#{city}, #{state} #{zip_code}"
|
|
22
|
-
# end
|
|
23
|
-
#
|
|
24
|
-
# end
|
|
25
|
-
# end
|
|
26
|
-
#
|
|
27
|
-
# Columns for the Address model will appear in the Person table. Passing
|
|
28
|
-
# <tt>:prefix => true</tt> will prefix the column name with the parent table's name.
|
|
29
|
-
# The default behavior is to use the columns as they are defined. Using the above
|
|
30
|
-
# example, the database table structure will become:
|
|
31
|
-
#
|
|
32
|
-
# Column Datatype, Options
|
|
33
|
-
# ===============================================================
|
|
34
|
-
# name :string
|
|
35
|
-
# occupation :string
|
|
36
|
-
# address_street :string
|
|
37
|
-
# address_city :string
|
|
38
|
-
# address_state :string, :size => 2
|
|
39
|
-
# address_zip_code :string, :size => 10
|
|
40
|
-
#
|
|
41
|
-
# EmbeddedValue's become instance methods off of an instance of the parent
|
|
42
|
-
# class and return a sub-class of the parent class.
|
|
43
|
-
#
|
|
44
|
-
# bob = Person.first(:name => 'Bob')
|
|
45
|
-
# bob.address # => #<Person::Address:0x1a492b8>
|
|
46
|
-
# bob.address.city # => "Pittsburgh"
|
|
47
|
-
# bob.address.city_state_zip_code # => "Pitsburgh, PA 90210"
|
|
48
|
-
|
|
49
|
-
class EmbeddedValue
|
|
50
|
-
EMBEDDED_PROPERTIES = []
|
|
51
|
-
|
|
52
|
-
def initialize(instance)
|
|
53
|
-
@instance = instance
|
|
54
|
-
@container_prefix = ''
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
def self.inherited(base)
|
|
58
|
-
base.const_set('EMBEDDED_PROPERTIES', [])
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
# add an embedded property. For more information about how to define properties, visit Property.
|
|
62
|
-
def self.property(name, type, options = {})
|
|
63
|
-
# set lazy option on the mapping if defined in the embed block
|
|
64
|
-
options[:lazy] ||= @container_lazy
|
|
65
|
-
|
|
66
|
-
options[:reader] ||= options[:accessor] || @container_reader_visibility
|
|
67
|
-
options[:writer] ||= options[:accessor] || @container_writer_visibility
|
|
68
|
-
|
|
69
|
-
property_name = @container_prefix ? @container_prefix + name.to_s : name
|
|
70
|
-
|
|
71
|
-
property = containing_class.property(property_name, type, options)
|
|
72
|
-
define_property_getter(name, property)
|
|
73
|
-
define_property_setter(name, property)
|
|
74
|
-
end
|
|
75
|
-
|
|
76
|
-
# define embedded property getters
|
|
77
|
-
def self.define_property_getter(name, property) # :nodoc:
|
|
78
|
-
|
|
79
|
-
# add the method on the embedded class
|
|
80
|
-
class_eval <<-EOS
|
|
81
|
-
#{property.reader_visibility.to_s}
|
|
82
|
-
def #{name}
|
|
83
|
-
#{"@instance.lazy_load!("+ property.name.inspect + ")" if property.lazy?}
|
|
84
|
-
@instance.instance_variable_get(#{property.instance_variable_name.inspect})
|
|
85
|
-
end
|
|
86
|
-
EOS
|
|
87
|
-
|
|
88
|
-
# add a shortcut boolean? method if applicable (ex: activated?)
|
|
89
|
-
if property.type == :boolean
|
|
90
|
-
class_eval("alias #{property.name}? #{property.name}")
|
|
91
|
-
end
|
|
92
|
-
end
|
|
93
|
-
|
|
94
|
-
# define embedded property setters
|
|
95
|
-
def self.define_property_setter(name, property) # :nodoc:
|
|
96
|
-
|
|
97
|
-
# add the method on the embedded class
|
|
98
|
-
class_eval <<-EOS
|
|
99
|
-
#{property.writer_visibility.to_s}
|
|
100
|
-
def #{name.to_s.sub(/\?$/, '')}=(value)
|
|
101
|
-
@instance.instance_variable_set(#{property.instance_variable_name.inspect}, value)
|
|
102
|
-
end
|
|
103
|
-
EOS
|
|
104
|
-
end
|
|
105
|
-
|
|
106
|
-
# returns the class in which the EmbeddedValue is declared
|
|
107
|
-
def self.containing_class
|
|
108
|
-
@containing_class || @containing_class = begin
|
|
109
|
-
tree = name.split('::')
|
|
110
|
-
tree.pop
|
|
111
|
-
tree.inject(Object) { |klass, current| klass.const_get(current) }
|
|
112
|
-
end
|
|
113
|
-
end
|
|
114
|
-
|
|
115
|
-
def self.define(container, name, options, &block)
|
|
116
|
-
embedded_class, embedded_class_name, accessor_name = nil
|
|
117
|
-
|
|
118
|
-
accessor_name = name.to_s
|
|
119
|
-
embedded_class_name = Inflector.camelize(accessor_name)
|
|
120
|
-
embedded_class = Class.new(EmbeddedValue)
|
|
121
|
-
container.const_set(embedded_class_name, embedded_class) unless container.const_defined?(embedded_class_name)
|
|
122
|
-
|
|
123
|
-
if options[:prefix]
|
|
124
|
-
container_prefix = options[:prefix].kind_of?(String) ? options[:prefix] : "#{accessor_name}_"
|
|
125
|
-
embedded_class.instance_variable_set('@container_prefix', container_prefix)
|
|
126
|
-
end
|
|
127
|
-
|
|
128
|
-
embedded_class.instance_variable_set('@containing_class', container)
|
|
129
|
-
|
|
130
|
-
embedded_class.instance_variable_set('@container_lazy', !!options[:lazy])
|
|
131
|
-
embedded_class.instance_variable_set('@container_reader_visibility', options[:reader] || options[:accessor] || :public)
|
|
132
|
-
embedded_class.instance_variable_set('@container_writer_visibility', options[:writer] || options[:accessor] || :public)
|
|
133
|
-
|
|
134
|
-
embedded_class.class_eval(&block) if block_given?
|
|
135
|
-
|
|
136
|
-
container.class_eval <<-EOS
|
|
137
|
-
def #{accessor_name}
|
|
138
|
-
#{embedded_class_name}.new(self)
|
|
139
|
-
end
|
|
140
|
-
EOS
|
|
141
|
-
end
|
|
142
|
-
|
|
143
|
-
end
|
|
144
|
-
|
|
145
|
-
end # module DataMapper
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
module DataMapper
|
|
2
|
-
|
|
3
|
-
# Tracks objects to help ensure that each object gets loaded only once.
|
|
4
|
-
# See: http://www.martinfowler.com/eaaCatalog/identityMap.html
|
|
5
|
-
class IdentityMap
|
|
6
|
-
|
|
7
|
-
def initialize
|
|
8
|
-
# WeakHash is much more expensive, and not necessary if the IdentityMap is tied to Session instead of Database.
|
|
9
|
-
# @cache = Hash.new { |h,k| h[k] = Support::WeakHash.new }
|
|
10
|
-
@cache = Hash.new { |h,k| h[k] = Hash.new }
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
# Pass a Class and a key, and to retrieve an instance.
|
|
14
|
-
# If the instance isn't found, nil is returned.
|
|
15
|
-
def get(klass, key)
|
|
16
|
-
@cache[mapped_class(klass)][key]
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
# Pass an instance to add it to the IdentityMap.
|
|
20
|
-
# The instance must have an assigned key.
|
|
21
|
-
def set(instance)
|
|
22
|
-
instance_key = instance.key
|
|
23
|
-
raise "Can't store an instance with a nil key in the IdentityMap" if instance_key.nil?
|
|
24
|
-
|
|
25
|
-
@cache[mapped_class(instance.class)][instance_key] = instance
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
# Remove an instance from the IdentityMap.
|
|
29
|
-
def delete(instance)
|
|
30
|
-
@cache[mapped_class(instance.class)].delete(instance.key)
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
# Clears a particular set of classes from the IdentityMap.
|
|
34
|
-
def clear!(klass)
|
|
35
|
-
@cache.delete(klass)
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
private
|
|
39
|
-
def mapped_class(klass)
|
|
40
|
-
unless klass.superclass.respond_to?(:persistent?)
|
|
41
|
-
klass
|
|
42
|
-
else
|
|
43
|
-
mapped_class(klass.superclass)
|
|
44
|
-
end
|
|
45
|
-
end
|
|
46
|
-
end
|
|
47
|
-
end
|