datamapper 0.1.1 → 0.2.0

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 (131) hide show
  1. data/CHANGELOG +65 -0
  2. data/README +193 -1
  3. data/do_performance.rb +153 -0
  4. data/environment.rb +45 -0
  5. data/example.rb +119 -22
  6. data/lib/data_mapper.rb +36 -16
  7. data/lib/data_mapper/adapters/abstract_adapter.rb +8 -0
  8. data/lib/data_mapper/adapters/data_object_adapter.rb +360 -0
  9. data/lib/data_mapper/adapters/mysql_adapter.rb +30 -179
  10. data/lib/data_mapper/adapters/postgresql_adapter.rb +90 -199
  11. data/lib/data_mapper/adapters/sql/coersion.rb +32 -3
  12. data/lib/data_mapper/adapters/sql/commands/conditions.rb +97 -128
  13. data/lib/data_mapper/adapters/sql/commands/load_command.rb +234 -231
  14. data/lib/data_mapper/adapters/sql/commands/loader.rb +99 -0
  15. data/lib/data_mapper/adapters/sql/mappings/associations_set.rb +30 -0
  16. data/lib/data_mapper/adapters/sql/mappings/column.rb +68 -6
  17. data/lib/data_mapper/adapters/sql/mappings/schema.rb +6 -3
  18. data/lib/data_mapper/adapters/sql/mappings/table.rb +71 -42
  19. data/lib/data_mapper/adapters/sql/quoting.rb +8 -2
  20. data/lib/data_mapper/adapters/sqlite3_adapter.rb +32 -201
  21. data/lib/data_mapper/associations.rb +21 -7
  22. data/lib/data_mapper/associations/belongs_to_association.rb +96 -80
  23. data/lib/data_mapper/associations/has_and_belongs_to_many_association.rb +158 -67
  24. data/lib/data_mapper/associations/has_many_association.rb +96 -78
  25. data/lib/data_mapper/associations/has_n_association.rb +64 -0
  26. data/lib/data_mapper/associations/has_one_association.rb +49 -79
  27. data/lib/data_mapper/associations/reference.rb +47 -0
  28. data/lib/data_mapper/base.rb +216 -50
  29. data/lib/data_mapper/callbacks.rb +71 -24
  30. data/lib/data_mapper/{session.rb → context.rb} +20 -8
  31. data/lib/data_mapper/database.rb +176 -45
  32. data/lib/data_mapper/embedded_value.rb +65 -0
  33. data/lib/data_mapper/identity_map.rb +12 -4
  34. data/lib/data_mapper/support/active_record_impersonation.rb +12 -8
  35. data/lib/data_mapper/support/enumerable.rb +8 -0
  36. data/lib/data_mapper/support/serialization.rb +13 -0
  37. data/lib/data_mapper/support/string.rb +1 -12
  38. data/lib/data_mapper/support/symbol.rb +3 -0
  39. data/lib/data_mapper/validations/unique_validator.rb +1 -2
  40. data/lib/data_mapper/validations/validation_helper.rb +18 -1
  41. data/performance.rb +109 -34
  42. data/plugins/can_has_sphinx/LICENSE +23 -0
  43. data/plugins/can_has_sphinx/README +4 -0
  44. data/plugins/can_has_sphinx/REVISION +1 -0
  45. data/plugins/can_has_sphinx/Rakefile +22 -0
  46. data/plugins/can_has_sphinx/init.rb +1 -0
  47. data/plugins/can_has_sphinx/install.rb +1 -0
  48. data/plugins/can_has_sphinx/lib/acts_as_sphinx.rb +123 -0
  49. data/plugins/can_has_sphinx/lib/sphinx.rb +460 -0
  50. data/plugins/can_has_sphinx/scripts/sphinx.sh +47 -0
  51. data/plugins/can_has_sphinx/tasks/acts_as_sphinx_tasks.rake +41 -0
  52. data/plugins/dataobjects/REVISION +1 -0
  53. data/plugins/dataobjects/Rakefile +7 -0
  54. data/plugins/dataobjects/do.rb +246 -0
  55. data/plugins/dataobjects/do_mysql.rb +179 -0
  56. data/plugins/dataobjects/do_postgres.rb +181 -0
  57. data/plugins/dataobjects/do_sqlite3.rb +153 -0
  58. data/plugins/dataobjects/spec/do_spec.rb +150 -0
  59. data/plugins/dataobjects/spec/spec_helper.rb +81 -0
  60. data/plugins/dataobjects/swig_mysql/do_mysql.bundle +0 -0
  61. data/plugins/dataobjects/swig_mysql/extconf.rb +33 -0
  62. data/plugins/dataobjects/swig_mysql/mysql_c.c +18800 -0
  63. data/plugins/dataobjects/swig_mysql/mysql_c.i +8 -0
  64. data/plugins/dataobjects/swig_mysql/mysql_supp.i +46 -0
  65. data/plugins/dataobjects/swig_postgres/Makefile +146 -0
  66. data/plugins/dataobjects/swig_postgres/extconf.rb +29 -0
  67. data/plugins/dataobjects/swig_postgres/postgres_c.bundle +0 -0
  68. data/plugins/dataobjects/swig_postgres/postgres_c.c +8185 -0
  69. data/plugins/dataobjects/swig_postgres/postgres_c.i +73 -0
  70. data/plugins/dataobjects/swig_sqlite/db +0 -0
  71. data/plugins/dataobjects/swig_sqlite/extconf.rb +9 -0
  72. data/plugins/dataobjects/swig_sqlite/sqlite3_c.c +4725 -0
  73. data/plugins/dataobjects/swig_sqlite/sqlite_c.i +168 -0
  74. data/rakefile.rb +45 -23
  75. data/spec/acts_as_tree_spec.rb +39 -0
  76. data/spec/associations_spec.rb +220 -0
  77. data/spec/attributes_spec.rb +15 -0
  78. data/spec/base_spec.rb +44 -0
  79. data/spec/callbacks_spec.rb +45 -0
  80. data/spec/can_has_sphinx.rb +6 -0
  81. data/spec/coersion_spec.rb +34 -0
  82. data/spec/conditions_spec.rb +49 -0
  83. data/spec/conversions_to_yaml_spec.rb +17 -0
  84. data/spec/count_command_spec.rb +11 -0
  85. data/spec/delete_command_spec.rb +1 -1
  86. data/spec/embedded_value_spec.rb +23 -0
  87. data/spec/fixtures/animals_exhibits.yaml +2 -0
  88. data/spec/fixtures/people.yaml +18 -1
  89. data/spec/{legacy.rb → legacy_spec.rb} +3 -3
  90. data/spec/load_command_spec.rb +157 -20
  91. data/spec/magic_columns_spec.rb +9 -0
  92. data/spec/mock_adapter.rb +20 -0
  93. data/spec/models/animal.rb +1 -1
  94. data/spec/models/animals_exhibit.rb +6 -0
  95. data/spec/models/exhibit.rb +2 -0
  96. data/spec/models/person.rb +26 -1
  97. data/spec/models/project.rb +19 -0
  98. data/spec/models/sales_person.rb +1 -0
  99. data/spec/models/section.rb +6 -0
  100. data/spec/models/zoo.rb +3 -1
  101. data/spec/query_spec.rb +9 -0
  102. data/spec/save_command_spec.rb +65 -1
  103. data/spec/schema_spec.rb +89 -0
  104. data/spec/single_table_inheritance_spec.rb +27 -0
  105. data/spec/spec_helper.rb +9 -55
  106. data/spec/{symbolic_operators.rb → symbolic_operators_spec.rb} +9 -5
  107. data/spec/{validates_confirmation_of.rb → validates_confirmation_of_spec.rb} +4 -3
  108. data/spec/{validates_format_of.rb → validates_format_of_spec.rb} +5 -4
  109. data/spec/{validates_length_of.rb → validates_length_of_spec.rb} +8 -7
  110. data/spec/{validates_uniqueness_of.rb → validates_uniqueness_of_spec.rb} +7 -10
  111. data/spec/{validations.rb → validations_spec.rb} +24 -6
  112. data/tasks/drivers.rb +20 -0
  113. data/tasks/fixtures.rb +42 -0
  114. metadata +181 -42
  115. data/lib/data_mapper/adapters/sql/commands/advanced_load_command.rb +0 -140
  116. data/lib/data_mapper/adapters/sql/commands/delete_command.rb +0 -113
  117. data/lib/data_mapper/adapters/sql/commands/save_command.rb +0 -141
  118. data/lib/data_mapper/adapters/sql/commands/table_exists_command.rb +0 -33
  119. data/lib/data_mapper/adapters/sql_adapter.rb +0 -163
  120. data/lib/data_mapper/associations/advanced_has_many_association.rb +0 -55
  121. data/lib/data_mapper/support/blank_slate.rb +0 -3
  122. data/lib/data_mapper/support/proc.rb +0 -69
  123. data/lib/data_mapper/support/struct.rb +0 -26
  124. data/lib/data_mapper/unit_of_work.rb +0 -38
  125. data/spec/basic_finder.rb +0 -67
  126. data/spec/belongs_to.rb +0 -47
  127. data/spec/has_and_belongs_to_many.rb +0 -25
  128. data/spec/has_many.rb +0 -34
  129. data/spec/new_record.rb +0 -24
  130. data/spec/sub_select.rb +0 -16
  131. data/spec/support/string_spec.rb +0 -7
@@ -1,16 +1,62 @@
1
1
  module DataMapper
2
2
 
3
+ # CallbacksHelper adds a class-method ClassMethods#callbacks
4
+ # when included in a class, and defines short-cut class-methods to
5
+ # add delegates to callbacks for the built-in Callbacks::EVENTS.
6
+ module CallbacksHelper
7
+
8
+ # The ::included callback extends the included class with a
9
+ # ::callbacks method, and sets up helper methods for the standard
10
+ # events declared in Callbacks::EVENTS.
11
+ def self.included(base)
12
+ base.extend(ClassMethods)
13
+
14
+ # Declare helpers for the standard EVENTS
15
+ Callbacks::EVENTS.each do |name|
16
+ base.class_eval <<-EOS
17
+ def self.#{name}(string = nil, &block)
18
+ if string.nil?
19
+ callbacks.add(:#{name}, block)
20
+ else
21
+ callbacks.add(:#{name}, string)
22
+ end
23
+ end
24
+ EOS
25
+ end
26
+ end
27
+
28
+ # Defines class-methods for the class that CallbacksHelper is
29
+ # included in.
30
+ module ClassMethods
31
+
32
+ # Provides lazily initialized access to a Callbacks instance.
33
+ def callbacks
34
+ @callbacks || ( @callbacks = DataMapper::Callbacks.new )
35
+ end
36
+ end
37
+ end
38
+
39
+ # Callbacks is a collection to assign and execute blocks of code when
40
+ # hooks throughout the DataMapper call Callbacks#execute. A set of the
41
+ # standard callbacks is declared in the Callbacks::EVENTS array.
3
42
  class Callbacks
4
43
 
44
+ # These are a collection of default callbacks that are hooked
45
+ # into the DataMapper. You're free to add your own events just by
46
+ # calling #add, but you'll have add the appropriate hooks into the
47
+ # system to actually execute them yourself.
5
48
  EVENTS = [
6
49
  :before_materialize, :after_materialize,
7
50
  :before_save, :after_save,
8
51
  :before_create, :after_create,
9
52
  :before_update, :after_update,
10
53
  :before_destroy, :after_destroy,
11
- :before_validate, :after_validate
54
+ :before_validation, :after_validation
12
55
  ]
13
-
56
+
57
+ # Initializes an internal Hash that ensures callback names are always
58
+ # of type Symbol, and assigns an Array to store your delegating code
59
+ # when the callback is looked-up by name.
14
60
  def initialize
15
61
  @callbacks = Hash.new do |h,k|
16
62
  raise 'Callback names must be Symbols' unless k.kind_of?(Symbol)
@@ -18,32 +64,33 @@ module DataMapper
18
64
  end
19
65
  end
20
66
 
21
- alias ruby_method_missing method_missing
22
- def method_missing(sym, *args)
23
- if EVENTS.include?(sym)
24
- self.class.send(:define_method, sym) { @callbacks[sym] }
25
- return send(sym)
26
- elsif sym.to_s =~ /^execute_(\w+)/ && EVENTS.include?($1.to_sym)
27
- return execute(args.first, $1.to_sym)
28
- end
29
-
30
- super
31
- end
32
-
33
- def execute(name, instance)
34
- @callbacks[name].each do |callback|
35
- if callback.kind_of?(String)
36
- instance.instance_eval(callback)
37
- else
38
- instance.instance_eval(&callback)
67
+ # Executes a given callback and returns TRUE or FALSE depending on the
68
+ # return value of the callbacks. All callbacks must return successfully
69
+ # in order for the call to #execute to return TRUE. Callbacks always
70
+ # execute against an +instance+. You may pass additional arguments
71
+ # which will in turn be passed to any Proc objects assigned to a specific
72
+ # callback. Strings assigned to callbacks do not accept parameters.
73
+ # They are instance-eval'ed instead. When the callback is a Symbol,
74
+ # it is sent to the instance under the assumption it is a method call.
75
+ def execute(name, instance, *args)
76
+ @callbacks[name].all? do |callback|
77
+ case callback
78
+ when String then instance.instance_eval(callback)
79
+ when Proc then callback[instance, *args]
80
+ when Symbol then instance.send(callback, *args)
81
+ else raise ''
39
82
  end
40
83
  end
41
84
  end
42
85
 
43
- def add(name, string = nil, &block)
44
- callback = send(name)
45
- raise ArgumentError.new("You didn't specify a callback in either string or block form.") if string.nil? && block.nil?
46
- callback << (string.nil? ? block : string)
86
+ # Asign delegating code to a callback. The +block+ parameter
87
+ # can be a Proc object, a String which will be eval'ed when
88
+ # the callback is executed, or a Symbol, which will be sent to
89
+ # the instance executed against (as a method call).
90
+ def add(name, block)
91
+ callback = @callbacks[name]
92
+ raise ArgumentError.new("You didn't specify a callback in String, Symbol or Proc form.") if block.nil?
93
+ callback << block
47
94
  end
48
95
  end
49
96
 
@@ -2,7 +2,7 @@ require 'data_mapper/identity_map'
2
2
 
3
3
  module DataMapper
4
4
 
5
- class Session
5
+ class Context
6
6
 
7
7
  class MaterializationError < StandardError
8
8
  end
@@ -17,7 +17,7 @@ module DataMapper
17
17
  @identity_map || ( @identity_map = IdentityMap.new )
18
18
  end
19
19
 
20
- def first(klass, *args, &b)
20
+ def first(klass, *args)
21
21
  id = nil
22
22
  options = nil
23
23
 
@@ -44,32 +44,40 @@ module DataMapper
44
44
  @adapter.load(self, klass, options)
45
45
  end
46
46
 
47
+ def count(klass, options = {})
48
+ @adapter.count(klass, options)
49
+ end
50
+
47
51
  def save(instance)
48
52
  @adapter.save(self, instance)
49
53
  end
50
54
 
51
55
  def destroy(instance)
52
- @adapter.delete(instance, :session => self)
56
+ @adapter.delete(self, instance)
53
57
  end
54
58
 
55
59
  def delete_all(klass)
56
- @adapter.delete(klass, :session => self)
60
+ @adapter.delete(self, klass)
57
61
  end
58
62
 
59
63
  def truncate(klass)
60
- @adapter.delete(klass, :truncate => true, :session => self)
64
+ @adapter.truncate(self, klass)
61
65
  end
62
66
 
63
67
  def create_table(klass)
64
- @adapter[klass].create!
68
+ @adapter.create_table(klass)
65
69
  end
66
70
 
67
71
  def drop_table(klass)
68
- @adapter[klass].drop!
72
+ @adapter.drop(self, klass)
69
73
  end
70
74
 
71
75
  def table_exists?(klass)
72
- @adapter[klass].exists?
76
+ @adapter.table_exists?(klass)
77
+ end
78
+
79
+ def execute(*args)
80
+ @adapter.execute(*args)
73
81
  end
74
82
 
75
83
  def query(*args)
@@ -80,6 +88,10 @@ module DataMapper
80
88
  @adapter.schema
81
89
  end
82
90
 
91
+ def table(klass)
92
+ @adapter.table(klass)
93
+ end
94
+
83
95
  def log
84
96
  @adapter.log
85
97
  end
@@ -1,5 +1,6 @@
1
1
  require 'logger'
2
- require 'data_mapper/session'
2
+ require 'data_mapper/context'
3
+ require 'data_mapper/adapters/abstract_adapter'
3
4
 
4
5
  # Delegates to DataMapper::database.
5
6
  # Will not overwrite if a method of the same name is pre-defined.
@@ -9,17 +10,24 @@ end unless methods.include?(:database)
9
10
 
10
11
  module DataMapper
11
12
 
12
- # Block Syntax:
13
- # Pushes the named database onto the context-stack,
14
- # yields a new session, and pops the context-stack.
15
- # Non-Block Syntax:
16
- # Returns the current session, or if there is none,
17
- # a new Session.
18
- def self.database(name = :default)
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
19
27
  unless block_given?
20
- Database.context.last || Session.new(Database[name].adapter)
28
+ Database.context.last || Context.new(Database[name].adapter)
21
29
  else
22
- Database.context.push(Session.new(Database[name].adapter))
30
+ Database.context.push(Context.new(Database[name].adapter))
23
31
  result = yield(Database.context.last)
24
32
  Database.context.pop
25
33
  result
@@ -30,70 +38,193 @@ module DataMapper
30
38
  attr_accessor :options
31
39
  end
32
40
 
41
+ # The Database class allows us to setup a default database for use throughout our applications
42
+ # or allows us to setup a collection of databases to use.
43
+ #
44
+ # === Example
45
+ # ==== To setup a default database
46
+ # DataMapper::Database.setup({
47
+ # :adapter => 'mysql'
48
+ # :host => 'localhost'
49
+ # :username => 'root'
50
+ # :password => 'R00tPaswooooord'
51
+ # :database => 'selecta_development'
52
+ # })
53
+ #
54
+ # ==== To setup a named database
55
+ # DataMapper::Database.setup(:second_database, {
56
+ # :adapter => 'postgresql'
57
+ # :host => 'localhost'
58
+ # :username => 'second_user'
59
+ # :password => 'second_password'
60
+ # :database => 'second_database'
61
+ # })
62
+ #
63
+ #
64
+ # ==== Working with multiple databases (see #DataMapper::database)
65
+ # DataMapper.database(:second_database) do
66
+ # ...
67
+ # end
68
+ #
69
+ # DataMapper.database(:default) do
70
+ # ...
71
+ # end
72
+ #
73
+ # or even...
74
+ #
75
+ # #The below variables still hold on to their database sessions.
76
+ # #So no confusion happens when passing variables around scopes.
77
+ #
78
+ # DataMapper.database(:second_database) do
79
+ #
80
+ # animal = Animal.first
81
+ #
82
+ # DataMapper.database(:default) do
83
+ # Animal.new(animal).save
84
+ # end # :default database
85
+ #
86
+ # end # :second_database
33
87
  class Database
34
88
 
35
89
  @databases = {}
36
90
  @context = []
37
91
 
92
+ # Allows you to access any of the named databases you have already setup.
93
+ #
94
+ # default_db = DataMapper::Database[:default]
95
+ # second_db = DataMapper::Database[:second_database]
38
96
  def self.[](name)
39
97
  @databases[name]
40
98
  end
41
99
 
100
+ # Returns the array of Database sessions currently being used
101
+ #
102
+ # This is what gives us thread safety, boys and girls
42
103
  def self.context
43
104
  @context
44
105
  end
45
106
 
46
- def self.setup(name = :default, &initializer)
107
+ # Setup creates a database and sets all of your properties for that database.
108
+ # Setup looks for either a hash of options passed in to the database or a symbolized name
109
+ # for your database, as well as it's hash of parameters
110
+ #
111
+ # If no options are passed, an ArgumentException will be raised.
112
+ #
113
+ # DataMapper::Database.setup(name = :default, options_hash)
114
+ #
115
+ # DataMapper::Database.setup({
116
+ # :adapter => 'mysql'
117
+ # :host => 'localhost'
118
+ # :username => 'root'
119
+ # :password => 'R00tPaswooooord'
120
+ # :database => 'selecta_development'
121
+ # })
122
+ #
123
+ #
124
+ # DataMapper::Database.setup(:named_database, {
125
+ # :adapter => 'mysql'
126
+ # :host => 'localhost'
127
+ # :username => 'root'
128
+ # :password => 'R00tPaswooooord'
129
+ # :database => 'selecta_development'
130
+ # })
131
+
132
+ def self.setup(*args)
133
+
134
+ name, options = nil
135
+
136
+ if (args.nil?) || (args[1].nil? && args[0].class != Hash)
137
+ raise ArgumentError.new('Database cannot be setup without at least an options hash.')
138
+ end
139
+
140
+ if args.size == 1
141
+ name, options = :default, args[0]
142
+ elsif args.size == 2
143
+ name, options = args[0], args[1]
144
+ end
145
+
47
146
  current = self.new(name)
48
- current.instance_eval(&initializer)
147
+
148
+ current.single_threaded = false if options[:single_threaded] == false
149
+
150
+ options.each_pair do |k,v|
151
+ current.send("#{k}=", v)
152
+ end
153
+
49
154
  @databases[name] = current
50
155
  end
51
156
 
157
+ # Creates a new database object with the name you specify, and a default set of options.
158
+ #
159
+ # The default options are as follows:
160
+ # {:single_threaded => true, :host => 'localhost', :database => nil, :username => 'root', :password => '', :adapter = nil }
52
161
  def initialize(name)
53
162
  @name = name
54
- end
55
-
56
- attr_reader :name
57
-
58
- def adapter(value = nil)
59
- return @adapter if value.nil?
60
-
61
- raise ArgumentError.new('The adapter is readonly after being set') unless @adapter.nil?
62
163
 
63
- require "data_mapper/adapters/#{String::memoized_underscore(value)}_adapter"
64
- adapter_class = Adapters::const_get(Inflector.classify(value) + "Adapter")
164
+ @single_threaded = true
165
+ @adapter = nil
166
+ @host = 'localhost'
167
+ @database = nil
168
+ @schema_search_path = nil
169
+ @username = 'root'
170
+ @password = ''
171
+ @index_path = (Dir::pwd + "/indexes")
65
172
 
66
- @adapter = adapter_class.new(self)
173
+ @log_level = Logger::WARN
174
+ @log_stream = nil
67
175
  end
68
176
 
69
- def host(value = nil); value.nil? ? (@host || 'localhost') : @host = value end
70
- def database(value = nil); value.nil? ? @database : @database = value end
71
- def username(value = nil); value.nil? ? @username : @username = value end
72
- def password(value = nil); value.nil? ? (@password || '') : @password = value end
177
+ attr_reader :name, :adapter
178
+ attr_writer :single_threaded
179
+ attr_accessor :host, :database, :schema_search_path, :username, :password, :log_stream, :log_level, :index_path, :socket
73
180
 
74
- # single_threaded mode is disabled by default currently since it's buggy.
75
- def single_threaded(value = nil); value.nil? ? (@single_threaded.nil? ? @single_threaded = false : @single_threaded) : @single_threaded = value end
181
+ # Returns true or false
182
+ #
183
+ # NOTE: single_threaded is true unless explicitly set to false.
184
+ def single_threaded?
185
+ @single_threaded
186
+ end
76
187
 
77
- def log(value = nil)
78
- @log = value unless value.nil?
79
-
80
- if @log.nil?
81
- @log = log_stream.nil? ? Logger.new(nil) : Logger.new(log_stream, File::WRONLY | File::APPEND | File::CREAT)
82
- @log.level = log_level || Logger::WARN
83
- at_exit { @log.close }
188
+ # Allows us to set the adapter for this database object. It can only be set once, and expects two types of values.
189
+ #
190
+ # You may pass in either a class inheriting from DataMapper::Adapters::AbstractAdapter
191
+ # or pass in a string indicating the type of adapter you would like to use.
192
+ #
193
+ # To create your own adapters, create a file in data_mapper/adapters/new_adapter.rb that inherits from AbstractAdapter
194
+ #
195
+ # database.adapter=("postgresql")
196
+ def adapter=(value)
197
+ if @adapter
198
+ raise ArgumentError.new('The adapter is readonly after being set')
84
199
  end
85
200
 
86
- @log
87
- end
88
-
89
- def log_level(value = nil)
90
- return @log_level if value.nil?
91
- @log_level = value
201
+ if value.is_a?(DataMapper::Adapters::AbstractAdapter)
202
+ @adapter = value
203
+ elsif value.is_a?(Class)
204
+ @adapter = value.new(self)
205
+ else
206
+ begin
207
+ require "data_mapper/adapters/#{Inflector.underscore(value)}_adapter"
208
+ rescue LoadError
209
+ require "#{Inflector.underscore(value)}_adapter"
210
+ end
211
+ adapter_class = Adapters::const_get(Inflector.classify(value) + "Adapter")
212
+
213
+ @adapter = adapter_class.new(self)
214
+ end
92
215
  end
93
216
 
94
- def log_stream(value = nil)
95
- return @log_stream if value.nil?
96
- @log_stream = value
217
+ # Default Logger from Ruby's logger.rb
218
+ def log
219
+ @log = Logger.new(@log_stream, File::WRONLY | File::APPEND | File::CREAT)
220
+ @log.level = @log_level
221
+ at_exit { @log.close }
222
+
223
+ class << self
224
+ attr_reader :log
225
+ end
226
+
227
+ return @log
97
228
  end
98
229
 
99
230
  end