sam-dm-core 0.9.6 → 0.9.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. data/Manifest.txt +5 -0
  2. data/QUICKLINKS +1 -2
  3. data/Rakefile +3 -3
  4. data/SPECS +9 -10
  5. data/lib/dm-core.rb +15 -22
  6. data/lib/dm-core/adapters.rb +18 -0
  7. data/lib/dm-core/adapters/abstract_adapter.rb +17 -10
  8. data/lib/dm-core/adapters/data_objects_adapter.rb +18 -16
  9. data/lib/dm-core/adapters/mysql_adapter.rb +1 -1
  10. data/lib/dm-core/adapters/postgres_adapter.rb +2 -2
  11. data/lib/dm-core/adapters/sqlite3_adapter.rb +1 -1
  12. data/lib/dm-core/associations.rb +3 -2
  13. data/lib/dm-core/associations/many_to_many.rb +2 -2
  14. data/lib/dm-core/associations/many_to_one.rb +1 -1
  15. data/lib/dm-core/associations/one_to_many.rb +13 -7
  16. data/lib/dm-core/associations/relationship.rb +20 -15
  17. data/lib/dm-core/auto_migrations.rb +4 -12
  18. data/lib/dm-core/collection.rb +9 -5
  19. data/lib/dm-core/dependency_queue.rb +2 -1
  20. data/lib/dm-core/identity_map.rb +3 -6
  21. data/lib/dm-core/model.rb +44 -27
  22. data/lib/dm-core/property.rb +3 -13
  23. data/lib/dm-core/property_set.rb +29 -22
  24. data/lib/dm-core/query.rb +49 -47
  25. data/lib/dm-core/repository.rb +3 -3
  26. data/lib/dm-core/resource.rb +12 -12
  27. data/lib/dm-core/scope.rb +7 -7
  28. data/lib/dm-core/support/kernel.rb +6 -2
  29. data/lib/dm-core/transaction.rb +7 -7
  30. data/lib/dm-core/version.rb +1 -1
  31. data/script/performance.rb +109 -30
  32. data/script/profile.rb +2 -2
  33. data/spec/integration/association_spec.rb +13 -1
  34. data/spec/integration/associations/one_to_many_spec.rb +40 -3
  35. data/spec/integration/auto_migrations_spec.rb +16 -1
  36. data/spec/integration/dependency_queue_spec.rb +0 -12
  37. data/spec/integration/postgres_adapter_spec.rb +1 -1
  38. data/spec/integration/property_spec.rb +4 -4
  39. data/spec/integration/resource_spec.rb +6 -0
  40. data/spec/integration/sti_spec.rb +22 -0
  41. data/spec/integration/strategic_eager_loading_spec.rb +21 -6
  42. data/spec/integration/type_spec.rb +1 -1
  43. data/spec/lib/model_loader.rb +10 -1
  44. data/spec/models/zoo.rb +1 -0
  45. data/spec/spec_helper.rb +3 -2
  46. data/spec/unit/adapters/data_objects_adapter_spec.rb +3 -3
  47. data/spec/unit/associations/many_to_many_spec.rb +16 -1
  48. data/spec/unit/associations/many_to_one_spec.rb +9 -2
  49. data/spec/unit/model_spec.rb +12 -30
  50. data/spec/unit/property_set_spec.rb +8 -1
  51. data/spec/unit/query_spec.rb +41 -0
  52. data/spec/unit/resource_spec.rb +27 -4
  53. data/spec/unit/transaction_spec.rb +13 -13
  54. data/tasks/ci.rb +4 -36
  55. data/tasks/dm.rb +3 -3
  56. metadata +7 -16
data/Manifest.txt CHANGED
@@ -1,4 +1,5 @@
1
1
  .autotest
2
+ .gitignore
2
3
  CONTRIBUTING
3
4
  FAQ
4
5
  History.txt
@@ -9,10 +10,12 @@ README.txt
9
10
  Rakefile
10
11
  SPECS
11
12
  TODO
13
+ dm-core.gemspec
12
14
  lib/dm-core.rb
13
15
  lib/dm-core/adapters.rb
14
16
  lib/dm-core/adapters/abstract_adapter.rb
15
17
  lib/dm-core/adapters/data_objects_adapter.rb
18
+ lib/dm-core/adapters/in_memory_adapter.rb
16
19
  lib/dm-core/adapters/mysql_adapter.rb
17
20
  lib/dm-core/adapters/postgres_adapter.rb
18
21
  lib/dm-core/adapters/sqlite3_adapter.rb
@@ -86,6 +89,7 @@ spec/lib/logging_helper.rb
86
89
  spec/lib/mock_adapter.rb
87
90
  spec/lib/model_loader.rb
88
91
  spec/lib/publicize_methods.rb
92
+ spec/models/content.rb
89
93
  spec/models/vehicles.rb
90
94
  spec/models/zoo.rb
91
95
  spec/spec.opts
@@ -93,6 +97,7 @@ spec/spec_helper.rb
93
97
  spec/unit/adapters/abstract_adapter_spec.rb
94
98
  spec/unit/adapters/adapter_shared_spec.rb
95
99
  spec/unit/adapters/data_objects_adapter_spec.rb
100
+ spec/unit/adapters/in_memory_adapter_spec.rb
96
101
  spec/unit/adapters/postgres_adapter_spec.rb
97
102
  spec/unit/associations/many_to_many_spec.rb
98
103
  spec/unit/associations/many_to_one_spec.rb
data/QUICKLINKS CHANGED
@@ -1,7 +1,7 @@
1
1
  = Quick Links
2
2
 
3
3
  * Setup and Configuration - DataMapper
4
- * Finders and CRUD -
4
+ * Finders and CRUD -
5
5
  * Properties - DataMapper::Property
6
6
  * FAQ[link:/files/FAQ.html]
7
7
  * Contact Us
@@ -9,4 +9,3 @@
9
9
  * Bug Reports - http://wm.lighthouseapp.com/projects/4819-datamapper/overview
10
10
  * IRC Channel - <tt>##datamapper</tt> on irc.freenode.net
11
11
  * Mailing List - http://groups.google.com/group/datamapper/
12
-
data/Rakefile CHANGED
@@ -13,9 +13,9 @@ AUTHOR = "Sam Smoot"
13
13
  EMAIL = "ssmoot@gmail.com"
14
14
  GEM_NAME = "dm-core"
15
15
  GEM_VERSION = DataMapper::VERSION
16
- GEM_DEPENDENCIES = ["data_objects", ">=0.9.5"], ["extlib", ">=0.9.5"],
17
- ["rspec", ">=1.1.3"], ["addressable", ">=1.0.4"]
18
-
16
+ GEM_DEPENDENCIES = ["data_objects", "~>0.9.9"],
17
+ ["extlib", "~>0.9.9"],
18
+ ["addressable", "~>2.0.1"]
19
19
 
20
20
  PROJECT_NAME = "datamapper"
21
21
  PROJECT_DESCRIPTION = "Faster, Better, Simpler."
data/SPECS CHANGED
@@ -2,14 +2,14 @@ Reading Specs
2
2
  =============
3
3
 
4
4
  Blah blah blah...
5
-
5
+
6
6
  Writing Specs
7
7
  =============
8
8
 
9
9
  Here are some general dos and don'ts
10
-
10
+
11
11
  = DO:
12
-
12
+
13
13
  * Write more specs for error conditions than clean conditions.
14
14
  * Write specs with readability in mind. Somebody knew to DataMapper should be
15
15
  able to read specs to learn how something works.
@@ -18,14 +18,14 @@ Writing Specs
18
18
  * Limit a describe block to 10 - 15 examples.
19
19
  * Group specs by method being tested. (See the 'Ordering Specs' section)
20
20
  * Use custom matchers.
21
-
21
+
22
22
  = DON'T:
23
-
23
+
24
24
  * Spec more than one unit of functionality in an example. An example should be
25
25
  as short as possible (while still remaining readable).
26
26
  * Spec implementation. Refactoring code should not break specs.
27
27
  * Declare models in the spec file.
28
-
28
+
29
29
  And a final do: Do go against the guidelines if your best judgement tells you
30
30
  to. These are just guidelines and are obviously not fast rules.
31
31
 
@@ -39,7 +39,7 @@ Models
39
39
  few simple metaphors, such as a zoo, a blog implementation, etc... Following
40
40
  metaphors makes it easier for a reader to guess what is going on with respect
41
41
  to the models.
42
-
42
+
43
43
  The second reason is to allow the spec environment to be as pristine as
44
44
  possible going into an example. Models being loaded from the model directory
45
45
  are tracked and reloaded before each example. Any changes that might be made
@@ -51,13 +51,12 @@ Mocks and Stubs
51
51
  Obviously, mocks and stubs are a powerful feature when it comes to BDD;
52
52
  however, remember that you are writing specs for behavior and NOT
53
53
  implementation.
54
-
54
+
55
55
  Ordering Specs
56
56
  ==============
57
57
 
58
58
  Specs aren't much use if nobody can find where anything is, so keeping specs
59
59
  well organized is critical. Currently, we are trying out the following
60
60
  structure:
61
-
61
+
62
62
  * List guidelines here...
63
-
data/lib/dm-core.rb CHANGED
@@ -11,22 +11,22 @@
11
11
 
12
12
  require 'date'
13
13
  require 'pathname'
14
+ require 'rubygems'
14
15
  require 'set'
15
16
  require 'time'
16
17
  require 'yaml'
17
18
 
18
- require 'rubygems'
19
-
20
- gem 'addressable', '>=1.0.4'
19
+ gem 'addressable', '~>2.0.1'
21
20
  require 'addressable/uri'
22
21
 
23
- gem 'extlib', '>=0.9.5'
22
+ gem 'extlib', '~>0.9.9'
24
23
  require 'extlib'
25
- require "extlib/inflection"
24
+ require 'extlib/inflection'
26
25
 
27
26
  begin
27
+ gem 'fastthread', '~>1.0.1'
28
28
  require 'fastthread'
29
- rescue LoadError
29
+ rescue Gem::LoadError
30
30
  # fastthread not installed
31
31
  end
32
32
 
@@ -133,8 +133,8 @@ module DataMapper
133
133
  case uri_or_options
134
134
  when Hash
135
135
  adapter_name = uri_or_options[:adapter].to_s
136
- when String, Addressable::URI
137
- uri_or_options = Addressable::URI.parse(uri_or_options) if uri_or_options.kind_of?(String)
136
+ when String, DataObjects::URI, Addressable::URI
137
+ uri_or_options = DataObjects::URI.parse(uri_or_options) if uri_or_options.kind_of?(String)
138
138
  adapter_name = uri_or_options.scheme
139
139
  end
140
140
 
@@ -169,26 +169,19 @@ module DataMapper
169
169
  # @param [Symbol] args the name of a repository to act within or return, :default is default
170
170
  # @yield [Proc] (optional) block to execute within the context of the named repository
171
171
  # @demo spec/integration/repository_spec.rb
172
- def self.repository(*args, &block) # :yields: current_context
173
- if args.size > 1
174
- raise ArgumentError, "Can only pass in one optional argument, but passed in #{args.size} arguments", caller
175
- end
176
-
177
- if args.any? && !args.first.kind_of?(Symbol)
178
- raise ArgumentError, "First optional argument must be a Symbol, but was #{args.first.inspect}", caller
179
- end
180
-
181
- name = args.first
182
-
172
+ def self.repository(name = nil) # :yields: current_context
183
173
  current_repository = if name
174
+ raise ArgumentError, "First optional argument must be a Symbol, but was #{args.first.inspect}" unless name.is_a?(Symbol)
184
175
  Repository.context.detect { |r| r.name == name } || Repository.new(name)
185
176
  else
186
177
  Repository.context.last || Repository.new(Repository.default_name)
187
178
  end
188
179
 
189
- return current_repository unless block_given?
190
-
191
- current_repository.scope(&block)
180
+ if block_given?
181
+ current_repository.scope { |*block_args| yield(*block_args) }
182
+ else
183
+ current_repository
184
+ end
192
185
  end
193
186
 
194
187
  # A logger should always be present. Lets be consistent with DO
@@ -1,4 +1,22 @@
1
1
  dir = Pathname(__FILE__).dirname.expand_path / 'adapters'
2
2
 
3
3
  require dir / 'abstract_adapter'
4
+ require dir / 'in_memory_adapter'
5
+
6
+ # TODO Factor these out into dm-more
4
7
  require dir / 'data_objects_adapter'
8
+ begin
9
+ require dir / 'sqlite3_adapter'
10
+ rescue LoadError
11
+ # ignore it
12
+ end
13
+ begin
14
+ require dir / 'mysql_adapter'
15
+ rescue LoadError
16
+ # ignore it
17
+ end
18
+ begin
19
+ require dir / 'postgres_adapter'
20
+ rescue LoadError
21
+ # ignore it
22
+ end
@@ -38,7 +38,7 @@ module DataMapper
38
38
  # connection string for configuration.
39
39
  def initialize(name, uri_or_options)
40
40
  assert_kind_of 'name', name, Symbol
41
- assert_kind_of 'uri_or_options', uri_or_options, Addressable::URI, Hash, String
41
+ assert_kind_of 'uri_or_options', uri_or_options, Addressable::URI, DataObjects::URI, Hash, String
42
42
 
43
43
  @name = name
44
44
  @uri = normalize_uri(uri_or_options)
@@ -46,12 +46,7 @@ module DataMapper
46
46
  @resource_naming_convention = NamingConventions::Resource::UnderscoredAndPluralized
47
47
  @field_naming_convention = NamingConventions::Field::Underscored
48
48
 
49
- @transactions = Hash.new do |hash, key|
50
- hash.delete_if do |k, v|
51
- !k.respond_to?(:alive?) || !k.alive?
52
- end
53
- hash[key] = []
54
- end
49
+ @transactions = {}
55
50
  end
56
51
 
57
52
  # TODO: move to dm-more/dm-migrations
@@ -144,7 +139,7 @@ module DataMapper
144
139
  #
145
140
  # TODO: move to dm-more/dm-transaction
146
141
  def push_transaction(transaction)
147
- @transactions[Thread.current] << transaction
142
+ transactions(Thread.current) << transaction
148
143
  end
149
144
 
150
145
  #
@@ -156,7 +151,7 @@ module DataMapper
156
151
  #
157
152
  # TODO: move to dm-more/dm-transaction
158
153
  def pop_transaction
159
- @transactions[Thread.current].pop
154
+ transactions(Thread.current).pop
160
155
  end
161
156
 
162
157
  #
@@ -169,7 +164,7 @@ module DataMapper
169
164
  #
170
165
  # TODO: move to dm-more/dm-transaction
171
166
  def current_transaction
172
- @transactions[Thread.current].last
167
+ transactions(Thread.current).last
173
168
  end
174
169
 
175
170
  #
@@ -194,6 +189,18 @@ module DataMapper
194
189
  def transaction_primitive
195
190
  raise NotImplementedError
196
191
  end
192
+
193
+ private
194
+ def transactions(thread)
195
+ unless @transactions[thread]
196
+ @transactions.delete_if do |key, value|
197
+ !key.respond_to?(:alive?) || !key.alive?
198
+ end
199
+ @transactions[thread] = []
200
+ end
201
+ @transactions[thread]
202
+ end
203
+
197
204
  end
198
205
 
199
206
  include Transaction
@@ -1,4 +1,4 @@
1
- gem 'data_objects', '>=0.9.5'
1
+ gem 'data_objects', '~>0.9.9'
2
2
  require 'data_objects'
3
3
 
4
4
  module DataMapper
@@ -117,24 +117,26 @@ module DataMapper
117
117
  protected
118
118
 
119
119
  def normalize_uri(uri_or_options)
120
- if uri_or_options.kind_of?(String)
121
- uri_or_options = Addressable::URI.parse(uri_or_options)
120
+ if uri_or_options.kind_of?(String) || uri_or_options.kind_of?(Addressable::URI)
121
+ uri_or_options = DataObjects::URI.parse(uri_or_options)
122
122
  end
123
123
 
124
- if uri_or_options.kind_of?(Addressable::URI)
125
- return uri_or_options.normalize
124
+ if uri_or_options.kind_of?(DataObjects::URI)
125
+ return uri_or_options
126
126
  end
127
127
 
128
- adapter = uri_or_options.delete(:adapter).to_s
129
- user = uri_or_options.delete(:username)
130
- password = uri_or_options.delete(:password)
131
- host = uri_or_options.delete(:host)
132
- port = uri_or_options.delete(:port)
133
- database = uri_or_options.delete(:database)
134
- query = uri_or_options.to_a.map { |pair| pair * '=' } * '&'
135
- query = nil if query == ''
128
+ query = uri_or_options.except(:adapter, :username, :password, :host, :port, :database).map { |pair| pair.join('=') }.join('&')
129
+ query = nil if query.blank?
136
130
 
137
- return Addressable::URI.new(adapter, user, password, host, port, database, query, nil)
131
+ return DataObjects::URI.parse(Addressable::URI.new(
132
+ :scheme => uri_or_options[:adapter].to_s,
133
+ :user => uri_or_options[:username],
134
+ :password => uri_or_options[:password],
135
+ :host => uri_or_options[:host],
136
+ :port => uri_or_options[:port],
137
+ :path => uri_or_options[:database],
138
+ :query => query
139
+ ))
138
140
  end
139
141
 
140
142
  # TODO: clean up once transaction related methods move to dm-more/dm-transactions
@@ -164,7 +166,7 @@ module DataMapper
164
166
  end
165
167
  end
166
168
 
167
- def with_connection(&block)
169
+ def with_connection
168
170
  connection = nil
169
171
  begin
170
172
  connection = create_connection
@@ -177,7 +179,7 @@ module DataMapper
177
179
  end
178
180
  end
179
181
 
180
- def with_reader(statement, bind_values = [], &block)
182
+ def with_reader(statement, bind_values = [])
181
183
  with_connection do |connection|
182
184
  reader = nil
183
185
  begin
@@ -1,4 +1,4 @@
1
- gem 'do_mysql', '>=0.9.5'
1
+ gem 'do_mysql', '~>0.9.9'
2
2
  require 'do_mysql'
3
3
 
4
4
  module DataMapper
@@ -1,4 +1,4 @@
1
- gem 'do_postgres', '>=0.9.5'
1
+ gem 'do_postgres', '~>0.9.9'
2
2
  require 'do_postgres'
3
3
 
4
4
  module DataMapper
@@ -86,7 +86,7 @@ module DataMapper
86
86
  end
87
87
 
88
88
  # TODO: move to dm-more/dm-migrations
89
- def without_notices(&block)
89
+ def without_notices
90
90
  # execute the block with NOTICE messages disabled
91
91
  begin
92
92
  execute('SET client_min_messages = warning')
@@ -1,4 +1,4 @@
1
- gem 'do_sqlite3', '>=0.9.5'
1
+ gem 'do_sqlite3', '~>0.9.9'
2
2
  require 'do_sqlite3'
3
3
 
4
4
  module DataMapper
@@ -45,8 +45,8 @@ module DataMapper
45
45
  end
46
46
 
47
47
  def relationships(repository_name = default_repository_name)
48
- @relationships ||= Hash.new { |h,k| h[k] = k == Repository.default_name ? {} : h[Repository.default_name].dup }
49
- @relationships[repository_name]
48
+ @relationships ||= {}
49
+ @relationships[repository_name] ||= repository_name == Repository.default_name ? {} : relationships(Repository.default_name).dup
50
50
  end
51
51
 
52
52
  def n
@@ -145,6 +145,7 @@ module DataMapper
145
145
  #
146
146
  # @api public
147
147
  def belongs_to(name, options={})
148
+ @_valid_relations = false
148
149
  relationship = ManyToOne.setup(name, self, options)
149
150
  # Please leave this in - I will release contextual serialization soon
150
151
  # which requires this -- guyvdb
@@ -48,7 +48,7 @@ module DataMapper
48
48
  opts[:mutable] = true
49
49
 
50
50
  names = [ opts[:child_model], opts[:parent_model].name ].sort
51
- model_name = names.join
51
+ model_name = names.join.gsub("::", "")
52
52
  storage_name = Extlib::Inflection.tableize(Extlib::Inflection.pluralize(names[0]) + names[1])
53
53
 
54
54
  opts[:near_relationship_name] = Extlib::Inflection.tableize(model_name).to_sym
@@ -67,7 +67,7 @@ module DataMapper
67
67
  EOS
68
68
 
69
69
  names.each do |n|
70
- model.belongs_to(Extlib::Inflection.underscore(n).to_sym)
70
+ model.belongs_to(Extlib::Inflection.underscore(n).gsub("/", "_").to_sym, :class_name => n)
71
71
  end
72
72
 
73
73
  Object.const_set(model_name, model)
@@ -48,7 +48,7 @@ module DataMapper
48
48
  class Proxy
49
49
  include Assertions
50
50
 
51
- instance_methods.each { |m| undef_method m unless %w[ __id__ __send__ class kind_of? respond_to? assert_kind_of should should_not instance_variable_set instance_variable_get ].include?(m) }
51
+ instance_methods.each { |m| undef_method m unless %w[ __id__ __send__ kind_of? respond_to? assert_kind_of should should_not instance_variable_set instance_variable_get ].include?(m.to_s) }
52
52
 
53
53
  def replace(parent)
54
54
  @parent = parent
@@ -72,7 +72,7 @@ module DataMapper
72
72
  class Proxy
73
73
  include Assertions
74
74
 
75
- instance_methods.each { |m| undef_method m unless %w[ __id__ __send__ class kind_of? respond_to? assert_kind_of should should_not instance_variable_set instance_variable_get ].include?(m) }
75
+ instance_methods.each { |m| undef_method m unless %w[ __id__ __send__ class kind_of? respond_to? assert_kind_of should should_not instance_variable_set instance_variable_get ].include?(m.to_s) }
76
76
 
77
77
  # FIXME: remove when RelationshipChain#get_children can return a Collection
78
78
  def all(query = {})
@@ -132,7 +132,7 @@ module DataMapper
132
132
  orphan_resource(super)
133
133
  end
134
134
 
135
- def delete(resource, &block)
135
+ def delete(resource)
136
136
  assert_mutable
137
137
  orphan_resource(super)
138
138
  end
@@ -156,6 +156,15 @@ module DataMapper
156
156
  resource
157
157
  end
158
158
 
159
+ def new(attributes = {})
160
+ assert_mutable
161
+ raise UnsavedParentError, 'You cannot intialize until the parent is saved' if @parent.new_record?
162
+ attributes = default_attributes.merge(attributes)
163
+ resource = children.respond_to?(:new) ? super(attributes) : @relationship.child_model.new(attributes)
164
+ self << resource
165
+ resource
166
+ end
167
+
159
168
  def create(attributes = {})
160
169
  assert_mutable
161
170
  raise UnsavedParentError, 'You cannot create until the parent is saved' if @parent.new_record?
@@ -297,11 +306,8 @@ module DataMapper
297
306
  end
298
307
 
299
308
  def method_missing(method, *args, &block)
300
- results = children.__send__(method, *args, &block) if children.respond_to?(method)
301
-
302
- return self if LazyArray::RETURN_SELF.include?(method) && results.kind_of?(Array)
303
-
304
- results
309
+ results = children.send(method, *args, &block)
310
+ results.equal?(children) ? self : results
305
311
  end
306
312
  end # class Proxy
307
313
  end # module OneToMany