og 0.24.0 → 0.25.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 (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