og 0.24.0 → 0.25.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. data/ProjectInfo +2 -5
  2. data/README +2 -0
  3. data/doc/AUTHORS +4 -1
  4. data/doc/RELEASES +53 -0
  5. data/examples/run.rb +2 -2
  6. data/lib/{og/mixin → glue}/hierarchical.rb +19 -19
  7. data/lib/{og/mixin → glue}/optimistic_locking.rb +1 -1
  8. data/lib/glue/orderable.rb +235 -0
  9. data/lib/glue/revisable.rb +2 -0
  10. data/lib/glue/taggable.rb +176 -0
  11. data/lib/{og/mixin/taggable.rb → glue/taggable_old.rb} +6 -0
  12. data/lib/glue/timestamped.rb +37 -0
  13. data/lib/{og/mixin → glue}/tree.rb +3 -8
  14. data/lib/og.rb +21 -20
  15. data/lib/og/collection.rb +15 -1
  16. data/lib/og/entity.rb +256 -114
  17. data/lib/og/manager.rb +60 -27
  18. data/lib/og/{mixin/schema_inheritance_base.rb → markers.rb} +5 -2
  19. data/lib/og/relation.rb +70 -74
  20. data/lib/og/relation/belongs_to.rb +5 -3
  21. data/lib/og/relation/has_many.rb +1 -0
  22. data/lib/og/relation/joins_many.rb +5 -4
  23. data/lib/og/store.rb +25 -46
  24. data/lib/og/store/alpha/filesys.rb +1 -1
  25. data/lib/og/store/alpha/kirby.rb +30 -30
  26. data/lib/og/store/alpha/memory.rb +49 -49
  27. data/lib/og/store/alpha/sqlserver.rb +7 -7
  28. data/lib/og/store/kirby.rb +38 -38
  29. data/lib/og/store/mysql.rb +43 -43
  30. data/lib/og/store/psql.rb +222 -53
  31. data/lib/og/store/sql.rb +165 -105
  32. data/lib/og/store/sqlite.rb +29 -25
  33. data/lib/og/validation.rb +24 -14
  34. data/lib/{vendor → og/vendor}/README +0 -0
  35. data/lib/{vendor → og/vendor}/kbserver.rb +1 -1
  36. data/lib/{vendor → og/vendor}/kirbybase.rb +230 -79
  37. data/lib/{vendor → og/vendor}/mysql.rb +0 -0
  38. data/lib/{vendor → og/vendor}/mysql411.rb +0 -0
  39. data/test/og/mixin/tc_hierarchical.rb +1 -1
  40. data/test/og/mixin/tc_optimistic_locking.rb +1 -1
  41. data/test/og/mixin/tc_orderable.rb +1 -1
  42. data/test/og/mixin/tc_taggable.rb +2 -2
  43. data/test/og/mixin/tc_timestamped.rb +2 -2
  44. data/test/og/tc_finder.rb +33 -0
  45. data/test/og/tc_inheritance.rb +2 -2
  46. data/test/og/tc_scoped.rb +45 -0
  47. data/test/og/tc_store.rb +1 -7
  48. metadata +21 -18
  49. data/lib/og/mixin/orderable.rb +0 -174
  50. data/lib/og/mixin/revisable.rb +0 -0
  51. data/lib/og/mixin/timestamped.rb +0 -24
@@ -16,7 +16,7 @@ class Manager
16
16
  class EntityInfo
17
17
  attr_accessor :klass
18
18
  attr_accessor :enchanted
19
- attr_accessor :options
19
+ attr_accessor :options
20
20
 
21
21
  def initialize(klass = nil)
22
22
  @klass = klass
@@ -31,7 +31,7 @@ class Manager
31
31
 
32
32
  # The store used for persistence. This is a virtual field
33
33
  # when running in thread_safe mode.
34
-
34
+
35
35
  attr_accessor :store
36
36
 
37
37
  # The collection of Entities managed by this manager.
@@ -42,30 +42,31 @@ class Manager
42
42
  @options = options
43
43
  @entities = {}
44
44
  @pool = Pool.new
45
-
45
+
46
46
  @store_class = Store.for_name(options[:store])
47
47
  @store_class.destroy(options) if options[:destroy]
48
+ @store_class.destroy_tables(options) if options[:destroy_tables]
48
49
 
49
50
  if Og.thread_safe
50
51
  (options[:connection_count] || 5).times do
51
52
  @pool << @store_class.new(options)
52
- end
53
+ end
53
54
  else
54
55
  @store = @store_class.new(options)
55
56
  end
56
57
  end
57
58
 
58
- # Get a store from the pool.
59
-
59
+ # Get a store from the pool.
60
+
60
61
  def get_store
61
62
  if Og.thread_safe
62
63
  thread = Thread.current
63
-
64
+
64
65
  unless st = thread[:og_store] and st.is_a?(@store_class)
65
66
  st = @pool.pop()
66
67
  thread[:og_store] = st
67
68
  end
68
-
69
+
69
70
  return st
70
71
  else
71
72
  return @store
@@ -75,20 +76,20 @@ class Manager
75
76
  alias_method :conn, :get_store
76
77
 
77
78
  # Return a store to the pool.
78
-
79
+
79
80
  def put_store
80
81
  if Og.thread_safe
81
82
  thread = Thread.current
82
-
83
+
83
84
  if conn = thread[:og_store]
84
85
  thread[:og_store] = nil
85
86
  return @pool.push(conn)
86
87
  end
87
88
  end
88
- end
89
+ end
89
90
 
90
91
  # Resolve polymorphic relations.
91
-
92
+
92
93
  def resolve_polymorphic(klass)
93
94
  Relations.resolve_polymorphic(klass)
94
95
  end
@@ -100,6 +101,7 @@ class Manager
100
101
 
101
102
  info = EntityInfo.new(klass)
102
103
 
104
+ # DON'T DO THIS!!!
103
105
  klass.module_eval %{
104
106
  def ==(other)
105
107
  other ? @#{klass.primary_key.symbol} == other.#{klass.primary_key.symbol} : false
@@ -108,9 +110,9 @@ class Manager
108
110
 
109
111
  klass.class.send(:attr_accessor, :ogmanager)
110
112
  klass.instance_variable_set '@ogmanager', self
111
-
112
- Relation.enchant(klass)
113
-
113
+
114
+ Relation.enchant(klass)
115
+
114
116
  # ensure that the superclass is managed before the
115
117
  # subclass.
116
118
 
@@ -120,25 +122,32 @@ class Manager
120
122
  store.enchant(klass, self); put_store
121
123
 
122
124
  # Call special class enchanting code.
123
-
125
+
124
126
  klass.enchant if klass.respond_to?(:enchant)
125
-
127
+
126
128
  @entities[klass] = info
127
129
  end
128
130
 
129
131
  # Is this class manageable by Og?
130
-
132
+
131
133
  def manageable?(klass)
132
- klass.respond_to?(:properties) and (!klass.properties.empty?) # and klass.ann.this.polymorphic.nil?
134
+ klass.respond_to?(:properties) and (!klass.properties.empty?) # and klass.ann.self.polymorphic.nil?
133
135
  end
134
136
 
135
- # Is the class managed by Og?
137
+ # Is the class managed by Og?
136
138
 
137
139
  def managed?(klass)
138
140
  @entities.include?(klass)
139
141
  end
140
142
  alias_method :entity?, :managed?
141
143
 
144
+ # ==
145
+ # Returns an array containing all classes managed by this manager.
146
+ # ==
147
+ def managed_classes
148
+ @entities.map {|e| e[0]}
149
+ end
150
+
142
151
  # Use Ruby's advanced reflection features to find
143
152
  # all manageable classes. Managable are all classes that
144
153
  # define Properties.
@@ -156,34 +165,58 @@ class Manager
156
165
  end
157
166
 
158
167
  # Manage a collection of classes.
159
-
168
+
160
169
  def manage_classes(*classes)
161
170
  classes = manageable_classes.flatten # if classes.empty? FIXME!
162
-
171
+
163
172
  classes.each { |c| Relation.resolve_targets(c) }
164
173
  classes.each { |c| Relation.resolve_polymorphic_markers(c) }
165
174
  classes.each { |c| Relation.resolve_polymorphic_relations(c) }
166
-
175
+
167
176
  # The polymorpic resolution step creates more manageable classes.
168
-
177
+
169
178
  classes = manageable_classes.flatten # if classes.empty? FIXME!
170
-
179
+
171
180
  Logger.debug "Og manageable classes: #{classes.inspect}" if $DBG
172
-
181
+
173
182
  classes.each { |c| Relation.resolve_targets(c) }
174
183
  classes.each { |c| Relation.resolve_names(c) }
175
184
  classes.each { |c| manage(c) }
185
+ =begin
186
+ # gmosx: LETS better investigate this.
187
+
188
+ # Checks for obsolete tables lying around in the og store.
189
+ # rp: this shouldn't really be here but I can't think of a better
190
+ # way to add this functionality.
191
+
192
+ store = get_store()
193
+
194
+ if store.respond_to? :unmanaged_tables
195
+ unmanaged_tables = store.unmanaged_tables(self)
196
+ unmanaged_tables.each do |table|
197
+
198
+ if @options[:evolve_schema] == true and @options[:evolve_schema_purge_tables] == true
199
+ sql = "DROP TABLE #{table}"
200
+ Logger.debug "Dropping unmanaged database table #{table}"
201
+ store.conn.exec(sql)
202
+ else
203
+ Logger.info "There is a table within the database named '#{table}' that is not managed by an Og class."
204
+ end
205
+ end
206
+ end
207
+ =end
176
208
  end
177
209
  alias_method :manage_class, :manage_classes
178
210
 
179
211
  def unmanage_classes(*classes)
180
212
  classes = manageable_classes.flatten if classes.empty?
181
-
213
+
182
214
  for c in classes
183
215
  @entities.delete_if { |k, v| v.klass == c }
184
216
  end
185
217
  end
186
218
  alias_method :unmanage_class, :unmanage_classes
219
+
187
220
  end
188
221
 
189
222
  end
@@ -1,5 +1,10 @@
1
1
  module Og
2
2
 
3
+ # Marker module. If included in a class, the Og automanager
4
+ # ignores this class.
5
+
6
+ module Unmanageable; end
7
+
3
8
  # This is a marker module that denotes that the
4
9
  # base class follows the SingleTableInheritance
5
10
  # pattern. Ie, all the subclasses of the base
@@ -8,5 +13,3 @@ module Og
8
13
  module SchemaInheritanceBase; end
9
14
 
10
15
  end
11
-
12
- # * George Moschovitis <gm@navel.gr>
@@ -6,7 +6,7 @@ require 'mega/annotation'
6
6
 
7
7
  module Og
8
8
 
9
- # A relation between Entities.
9
+ # A relation between Entities.
10
10
  #--
11
11
  # Relations are resolved in multiple passes. First
12
12
  # the relations are logged in :relations...
@@ -15,51 +15,51 @@ module Og
15
15
  class Relation
16
16
 
17
17
  # The parameters of this relation.
18
-
18
+
19
19
  attr_accessor :options
20
-
20
+
21
21
  # A generalized initialize method for all relations.
22
22
  # Contains common setup code.
23
-
23
+
24
24
  def initialize(args, options = {})
25
25
  @options = options
26
26
  @options.update(args.pop) if args.last.is_a?(Hash)
27
27
 
28
28
  target_name = if collection
29
29
  :target_plural_name
30
- else
31
- :target_singular_name
30
+ else
31
+ :target_singular_name
32
32
  end
33
33
 
34
34
  # Check that all needed options are provided.
35
-
35
+
36
36
  if args.empty? or (not (args.last.is_a?(Class) or args.last.is_a?(Symbol)))
37
37
  raise 'Class of target not defined'
38
38
  end
39
39
 
40
40
  # Try to set the target class. Checks for class and
41
41
  # class symbol.
42
-
42
+
43
43
  if args.last.to_s.capitalized?
44
44
  @options[:target_class] = args.pop
45
45
  end
46
-
46
+
47
47
  # Try to set the target name.
48
-
48
+
49
49
  if args.last.is_a? Symbol
50
50
  @options[target_name] = args.pop
51
- end
52
-
51
+ end
52
+
53
53
  # Inflect target_class if not provided.
54
-
54
+
55
55
  @options[:target_class] ||= @options[target_name].to_s.singular.camelize.intern
56
-
56
+
57
57
  # FIXME: this is a hack!
58
58
  # setup() rescue nil
59
59
  end
60
60
 
61
61
  # Get an option.
62
-
62
+
63
63
  def [](key)
64
64
  @options[key]
65
65
  end
@@ -71,26 +71,26 @@ class Relation
71
71
  end
72
72
 
73
73
  # Is this a polymorphic marker?
74
-
74
+
75
75
  def polymorphic_marker?
76
- target_class == Object
76
+ target_class == Object
77
77
  end
78
-
78
+
79
79
  # Is this a polymorphic relation ?
80
-
80
+
81
81
  def polymorphic?
82
- target_class.ann.this[:polymorphic]
82
+ target_class.ann.self[:polymorphic]
83
83
  end
84
-
84
+
85
85
  # Resolve a polymorphic target class.
86
86
  # Overrided in subclasses.
87
-
87
+
88
88
  def resolve_polymorphic
89
89
  end
90
-
90
+
91
91
  # This method is implemented in subclasses.
92
-
93
- def enchant
92
+
93
+ def enchant
94
94
  end
95
95
 
96
96
  # Access the hash values as methods.
@@ -106,10 +106,10 @@ end
106
106
 
107
107
  class Relation
108
108
  class << self
109
-
110
- # To avoid forward declarations, references to undefined
109
+
110
+ # To avoid forward declarations, references to undefined
111
111
  # (at the time of the creation of the relation) classes are
112
- # stored as symbols. These symbols are resolved by this
112
+ # stored as symbols. These symbols are resolved by this
113
113
  # method.
114
114
  #--
115
115
  # FIXME: do something more elegant here.
@@ -154,68 +154,68 @@ class Relation
154
154
  def resolve_polymorphic_markers(klass)
155
155
  for r in klass.relations
156
156
  if r.polymorphic_marker?
157
- r.owner_class.ann :this, :polymorphic => r.owner_class
157
+ r.owner_class.ann :self, :polymorphic => r.owner_class
158
158
  end
159
159
  end
160
160
  end
161
161
 
162
162
  # Resolve polymorphic relations.
163
163
  # If the target class is polymorphic, create a specialized
164
- # version of that class (the target) enclosed in the
164
+ # version of that class (the target) enclosed in the
165
165
  # owner namespace.
166
- #
166
+ #
167
167
  # For example:
168
168
  #
169
169
  # class Article
170
170
  # has_many Comment
171
171
  # ...
172
172
  # end
173
-
173
+
174
174
  def resolve_polymorphic_relations(klass)
175
175
  for r in klass.relations
176
176
  if r.polymorphic?
177
-
177
+
178
178
  target_dm = r.target_class.to_s.demodulize
179
179
  r.owner_class.module_eval %{
180
180
  class #{r.owner_class}::#{target_dm} < #{r.target_class}
181
181
  end
182
182
  }
183
-
183
+
184
184
  # Replace the target class.
185
-
185
+
186
186
  r[:target_class] = eval("#{r.owner_class}::#{target_dm}")
187
187
  end
188
-
188
+
189
189
  r.resolve_polymorphic
190
190
  end
191
191
  end
192
-
192
+
193
193
  # Resolve the names of the relations.
194
-
194
+
195
195
  def resolve_names(klass)
196
196
  for r in klass.relations
197
197
  target_name = if r.collection
198
198
  :target_plural_name
199
- else
199
+ else
200
200
  :target_singular_name
201
201
  end
202
-
202
+
203
203
  # Inflect the relation name.
204
-
204
+
205
205
  unless r[target_name]
206
206
  r[target_name] = if r.collection
207
207
  r.target_class.to_s.demodulize.underscore.downcase.plural.intern
208
208
  else
209
209
  r.target_class.to_s.demodulize.underscore.downcase.intern
210
- end
210
+ end
211
211
  end
212
-
213
- r[:name] = r[target_name]
212
+
213
+ r[:name] = r[target_name]
214
214
  end
215
215
  end
216
-
217
- # General resovle method.
218
-
216
+
217
+ # General resolve method.
218
+
219
219
  def resolve(klass, action = :resolve_polymorphic)
220
220
  for r in klass.relations
221
221
  r.send(action)
@@ -223,41 +223,36 @@ class Relation
223
223
  end
224
224
 
225
225
  # Perform relation enchanting on this class.
226
-
227
- def enchant(klass)
226
+
227
+ def enchant(klass)
228
228
  # update inherited relations.
229
-
229
+
230
230
  for r in klass.relations
231
231
  r[:owner_class] = klass
232
232
  end
233
-
234
- # enchant.
235
-
233
+
234
+ # enchant.
235
+
236
236
  for r in klass.relations
237
237
  # p "=== #{klass} : #{r.class} : #{r.name}"
238
238
  r.enchant() unless r.polymorphic_marker?
239
239
  end
240
-
240
+
241
241
  end
242
-
242
+
243
243
  end
244
244
  end
245
245
 
246
- # Relations domain specific language (DSL). This
246
+ # Relations domain specific language (DSL). This
247
247
  # language defines macros that are used to define Entity
248
- # relations. Additional macros allow for relation
248
+ # relations. Additional macros allow for relation
249
249
  # inspection.
250
250
 
251
251
  module RelationDSL
252
- def self.append_features(base)
253
- super
254
- base.module_eval do
255
- inheritor(:relations, [], :+) unless @relations
256
- end
257
- base.extend(ClassMethods)
258
- end
259
252
 
260
- module ClassMethods
253
+ inheritor(:relations, [], :+) #unless @relations
254
+
255
+ class_inherit do
261
256
 
262
257
  # === Examples
263
258
  #
@@ -265,7 +260,7 @@ module RelationDSL
265
260
  # belongs_to Article # inflects :article
266
261
  # belongs_to :article, Article
267
262
  # belongs_to :article, Article, :view => 'lala'
268
-
263
+
269
264
  def belongs_to(*args)
270
265
  require 'og/relation/belongs_to'
271
266
  relations! << Og::BelongsTo.new(args, :owner_class => self)
@@ -275,7 +270,7 @@ module RelationDSL
275
270
  #
276
271
  # refers_to :topic # inflects Topic
277
272
  # refers_to Topic # inflects :topic
278
-
273
+
279
274
  def refers_to(*args)
280
275
  require 'og/relation/refers_to'
281
276
  relations! << Og::RefersTo.new(args, :owner_class => self)
@@ -284,31 +279,31 @@ module RelationDSL
284
279
  # === Examples
285
280
  #
286
281
  # has_one User
287
-
282
+
288
283
  def has_one(*args)
289
284
  require 'og/relation/has_one'
290
285
  relations! << Og::HasOne.new(args, :owner_class => self)
291
286
  end
292
-
287
+
293
288
  # === Examples
294
289
  #
295
290
  # has_many Comment
296
291
  # has_many :comments, Comment
297
-
292
+
298
293
  def has_many(*args)
299
294
  require 'og/relation/has_many'
300
295
  relations! << Og::HasMany.new(args, :owner_class => self, :collection => true)
301
296
  end
302
297
 
303
298
  # ..
304
-
299
+
305
300
  def joins_many(*args)
306
301
  require 'og/relation/joins_many'
307
302
  relations! << Og::JoinsMany.new(args, :owner_class => self, :collection => true)
308
303
  end
309
-
304
+
310
305
  # ..
311
-
306
+
312
307
  def many_to_many(*args)
313
308
  require 'og/relation/many_to_many'
314
309
  relations! << Og::ManyToMany.new(args, :owner_class => self, :collection => true)
@@ -318,8 +313,9 @@ module RelationDSL
318
313
  relations.find { |r| r[:name] == name }
319
314
  end
320
315
  alias_method :relation, :inspect_relation
321
-
316
+
322
317
  end
318
+
323
319
  end
324
320
 
325
321
  end