og 0.16.0 → 0.17.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. data/CHANGELOG +485 -0
  2. data/README +35 -12
  3. data/Rakefile +4 -7
  4. data/benchmark/bench.rb +1 -1
  5. data/doc/AUTHORS +3 -3
  6. data/doc/RELEASES +153 -2
  7. data/doc/config.txt +0 -7
  8. data/doc/tutorial.txt +7 -0
  9. data/examples/README +5 -0
  10. data/examples/mysql_to_psql.rb +25 -50
  11. data/examples/run.rb +62 -77
  12. data/install.rb +1 -1
  13. data/lib/og.rb +45 -106
  14. data/lib/og/collection.rb +156 -0
  15. data/lib/og/entity.rb +131 -0
  16. data/lib/og/errors.rb +10 -15
  17. data/lib/og/manager.rb +115 -0
  18. data/lib/og/{mixins → mixin}/hierarchical.rb +43 -37
  19. data/lib/og/{mixins → mixin}/orderable.rb +35 -35
  20. data/lib/og/{mixins → mixin}/timestamped.rb +0 -6
  21. data/lib/og/{mixins → mixin}/tree.rb +0 -4
  22. data/lib/og/relation.rb +178 -0
  23. data/lib/og/relation/belongs_to.rb +14 -0
  24. data/lib/og/relation/has_many.rb +62 -0
  25. data/lib/og/relation/has_one.rb +17 -0
  26. data/lib/og/relation/joins_many.rb +69 -0
  27. data/lib/og/relation/many_to_many.rb +17 -0
  28. data/lib/og/relation/refers_to.rb +31 -0
  29. data/lib/og/store.rb +223 -0
  30. data/lib/og/store/filesys.rb +113 -0
  31. data/lib/og/store/madeleine.rb +4 -0
  32. data/lib/og/store/memory.rb +291 -0
  33. data/lib/og/store/mysql.rb +283 -0
  34. data/lib/og/store/psql.rb +238 -0
  35. data/lib/og/store/sql.rb +599 -0
  36. data/lib/og/store/sqlite.rb +190 -0
  37. data/lib/og/store/sqlserver.rb +262 -0
  38. data/lib/og/types.rb +19 -0
  39. data/lib/og/validation.rb +0 -4
  40. data/test/og/{mixins → mixin}/tc_hierarchical.rb +21 -23
  41. data/test/og/{mixins → mixin}/tc_orderable.rb +15 -14
  42. data/test/og/mixin/tc_timestamped.rb +38 -0
  43. data/test/og/store/tc_filesys.rb +71 -0
  44. data/test/og/tc_relation.rb +36 -0
  45. data/test/og/tc_store.rb +290 -0
  46. data/test/og/tc_types.rb +21 -0
  47. metadata +54 -40
  48. data/examples/mock_example.rb +0 -50
  49. data/lib/og/adapters/base.rb +0 -706
  50. data/lib/og/adapters/filesys.rb +0 -117
  51. data/lib/og/adapters/mysql.rb +0 -350
  52. data/lib/og/adapters/oracle.rb +0 -368
  53. data/lib/og/adapters/psql.rb +0 -272
  54. data/lib/og/adapters/sqlite.rb +0 -265
  55. data/lib/og/adapters/sqlserver.rb +0 -356
  56. data/lib/og/database.rb +0 -290
  57. data/lib/og/enchant.rb +0 -149
  58. data/lib/og/meta.rb +0 -407
  59. data/lib/og/testing/mock.rb +0 -165
  60. data/lib/og/typemacros.rb +0 -24
  61. data/test/og/adapters/tc_filesys.rb +0 -83
  62. data/test/og/adapters/tc_sqlite.rb +0 -86
  63. data/test/og/adapters/tc_sqlserver.rb +0 -96
  64. data/test/og/tc_automanage.rb +0 -46
  65. data/test/og/tc_lifecycle.rb +0 -105
  66. data/test/og/tc_many_to_many.rb +0 -61
  67. data/test/og/tc_meta.rb +0 -55
  68. data/test/og/tc_validation.rb +0 -89
  69. data/test/tc_og.rb +0 -364
@@ -1,7 +1,3 @@
1
- # * George Moschovitis <gm@navel.gr>
2
- # (c) 2004-2005 Navel, all rights reserved.
3
- # $Id: orderable.rb 1 2005-04-11 11:04:30Z gmosx $
4
-
5
1
  require 'glue/dynamic_include'
6
2
 
7
3
  module Og
@@ -11,34 +7,36 @@ module Og
11
7
  module Orderable
12
8
 
13
9
  def self.append_dynamic_features(base, options)
14
- c = {
10
+ o = {
15
11
  :position => 'position',
16
12
  :type => Fixnum,
17
- :scope => '"1 = 1"'
18
13
  }
19
- c.update(options) if options
14
+ o.update(options) if options
20
15
 
21
- if c[:scope].is_a?(Symbol) && c[:scope].to_s !~ /_oid$/
22
- c[:scope] = "#{c[:scope]}_oid".intern
16
+ if o[:scope].is_a?(Symbol) && o[:scope].to_s !~ /_oid$/
17
+ o[:scope] = "#{o[:scope]}_oid".intern
23
18
  end
24
19
 
25
- position = c[:position]
26
- scope = c[:scope]
27
-
28
- if scope.is_a?(Symbol)
29
- scope = %{(#{scope} ? "#{scope} = \#{@#{scope}}" : "#{scope} IS NULL")}
30
- end
31
-
32
- base.module_eval <<-EOE, __FILE__, __LINE__
33
- property :#{position}, #{c[:type]}
34
-
35
- def og_pre_insert(conn)
36
- add_to_bottom
37
- end
20
+ position = o[:position]
21
+ scope = o[:scope]
38
22
 
39
- def self.og_pre_delete(conn, obj)
40
- obj.decrement_position_of_lower_items
23
+ if scope
24
+ if scope.is_a?(Symbol)
25
+ scope = %{(#{scope} ? "#{scope} = \#{@#{scope}}" : "#{scope} IS NULL")}
41
26
  end
27
+
28
+ cond = 'condition => ' + scope
29
+ cond_and = ':condition => ' + scope + ' + " AND " +'
30
+ else
31
+ cond = ':condition => nil'
32
+ cond_and = ':condition => '
33
+ end
34
+
35
+ code = %{
36
+ property :#{position}, #{o[:type]}
37
+
38
+ pre "add_to_bottom", :on => :og_insert
39
+ pre "decrement_position_of_lower_items", :on => :og_delete
42
40
 
43
41
  def move_higher
44
42
  if higher = higher_item
@@ -87,12 +85,12 @@ module Orderable
87
85
  end
88
86
 
89
87
  def higher_item
90
- #{base}.one(#{scope} + " AND #{position}=\#\{@#{position} - 1\}")
88
+ #{base}.one(#{cond_and}"#{position}=\#\{@#{position} - 1\}")
91
89
  end
92
90
  alias_method :previous_item, :higher_item
93
91
 
94
92
  def lower_item
95
- #{base}.one(#{scope} + " AND #{position}=\#\{@#{position} + 1\}")
93
+ #{base}.one(#{cond_and}"#{position}=\#\{@#{position} + 1\}")
96
94
  end
97
95
  alias_method :next_item, :lower_item
98
96
 
@@ -101,7 +99,7 @@ module Orderable
101
99
  alias_method :first_item, :top_item
102
100
 
103
101
  def bottom_item
104
- #{base}.one(#{scope} + " ORDER BY #{position} DESC")
102
+ #{base}.one(#{cond}, :order => "#{position} DESC", :limit => 1)
105
103
  end
106
104
  alias_method :last_item, :last_item
107
105
 
@@ -117,12 +115,12 @@ module Orderable
117
115
 
118
116
  def increment_position
119
117
  @#{position} += 1
120
- set_property('#{position}', @#{position})
118
+ update(:#{position})
121
119
  end
122
120
 
123
121
  def decrement_position
124
122
  @#{position} -= 1
125
- set_property('#{position}', @#{position})
123
+ update(:#{position})
126
124
  end
127
125
 
128
126
  def bottom_position
@@ -132,26 +130,28 @@ module Orderable
132
130
 
133
131
  def set_top_position
134
132
  @#{position} = 1
135
- set_property('#{position}', 1)
133
+ update(:#{position})
136
134
  end
137
135
 
138
136
  def set_bottom_position
139
137
  @#{position} = bottom_position + 1
140
- set_property('#{position}', @#{position})
138
+ update(:#{position})
141
139
  end
142
140
 
143
141
  def increment_position_of_higher_items
144
- #{base}.update("#{position}=(#{position} + 1)", "WHERE " + #{scope} + " AND #{position} < \#\{@#{position}\}")
142
+ #{base}.update_property("#{position}=(#{position} + 1)", #{cond_and}"#{position} < \#\{@#{position}\}")
145
143
  end
146
144
 
147
145
  def increment_position_of_all_items
148
- #{base}.update("#{position}=(#{position} + 1)", "WHERE " + #{scope})
146
+ #{base}.update_property("#{position}=(#{position} + 1)", #{cond})
149
147
  end
150
148
 
151
149
  def decrement_position_of_lower_items
152
- #{base}.update("#{position}=(#{position} - 1)", "WHERE " + #{scope} + " AND #{position} > \#\{@#{position}\}")
150
+ #{base}.update_property("#{position}=(#{position} - 1)", #{cond_and}"#{position} > \#\{@#{position}\}")
153
151
  end
154
- EOE
152
+ }
153
+
154
+ base.module_eval(code)
155
155
  end
156
156
 
157
157
 
@@ -1,13 +1,8 @@
1
- # * George Moschovitis <gm@navel.gr>
2
- # (c) 2005 Navel, all rights reserved.
3
- # $Id: timestamped.rb 23 2005-04-16 18:20:00Z gmosx $
4
-
5
1
  module Og
6
2
 
7
3
  # Adds timestamping functionality.
8
4
 
9
5
  module Timestamped
10
-
11
6
  property :create_time, Time
12
7
  property :update_time, Time
13
8
  property :access_time, Time
@@ -18,7 +13,6 @@ module Timestamped
18
13
  def touch!
19
14
  @access_time = Time.now
20
15
  end
21
-
22
16
  end
23
17
 
24
18
  end
@@ -1,7 +1,3 @@
1
- # * George Moschovitis <gm@navel.gr>
2
- # (c) 2004-2005 Navel, all rights reserved.
3
- # $Id: tree.rb 1 2005-04-11 11:04:30Z gmosx $
4
-
5
1
  # NOT WORKING YET !!!
6
2
 
7
3
  raise 'This is not working yet, do not require this file.'
@@ -0,0 +1,178 @@
1
+ require 'facet/object/constant'
2
+ require 'facet/string/plural'
3
+ require 'facet/string/demodulize'
4
+ require 'facet/string/underscore'
5
+
6
+ module Og
7
+
8
+ # A relation between Entities.
9
+
10
+ class Relation
11
+
12
+ attr_accessor :options
13
+
14
+ def initialize(args, options = {})
15
+ @options = options
16
+ @options.update(args.pop) if args.last.is_a?(Hash)
17
+
18
+ if args.empty? or (not (args.last.is_a?(Class) or args.last.is_a?(Symbol)))
19
+ raise 'Class of target not defined'
20
+ end
21
+
22
+ @options[:target_class] = args.pop
23
+
24
+ target_name = if collection
25
+ :target_plural_name
26
+ else
27
+ :target_singular_name
28
+ end
29
+
30
+ unless args.empty?
31
+ @options[target_name] = args.first
32
+ else
33
+ @options[target_name] = if collection
34
+ target_class.to_s.demodulize.underscore.downcase.plural.intern
35
+ else
36
+ target_class.to_s.demodulize.underscore.downcase.intern
37
+ end
38
+ end
39
+
40
+ @options[:name] = options[target_name]
41
+ end
42
+
43
+ def [](key)
44
+ @options[key]
45
+ end
46
+
47
+ def []=(key, val)
48
+ @options[key] = val
49
+ end
50
+
51
+ def resolve_options
52
+ @options[:owner_pk], @options[:owner_pkclass] = owner_class.primary_key
53
+ @options[:target_pk], @options[:target_pkclass] = target_class.primary_key
54
+ end
55
+
56
+ # To avoid forward declarations, references to undefined
57
+ # (at the time of the creation of the relation) classes are
58
+ # stored as symbols. These symbols are resolved by this
59
+ # method.
60
+ #--
61
+ # FIXME: do something more elegant here.
62
+ #++
63
+
64
+ def resolve_target
65
+ if target_class.is_a?(Symbol)
66
+ c = owner_class.name.dup
67
+ c = "::" + c unless c =~ /::/
68
+ c.gsub!(/::.*$/, '::')
69
+ c << target_class.to_s
70
+ begin
71
+ klass = constant(c)
72
+ rescue
73
+ c = target_class
74
+ retry
75
+ end
76
+ @options[:target_class] = klass
77
+ end
78
+ end
79
+
80
+ def enchant
81
+ end
82
+
83
+ # Access the hash values as methods.
84
+
85
+ def method_missing(sym, *args)
86
+ return @options[sym]
87
+ end
88
+
89
+ class << self
90
+
91
+ def enchant(klass)
92
+ if klass.__meta[:relations]
93
+ for relation in klass.__meta[:relations]
94
+ relation.resolve_target
95
+ relation.resolve_options
96
+ relation.enchant
97
+ end
98
+ end
99
+ end
100
+
101
+ end
102
+
103
+ end
104
+
105
+ # Relation macros. These macros are used to define Entity
106
+ # relations.
107
+
108
+ module RelationMacros
109
+ def self.append_features(base)
110
+ super
111
+ base.extend(ClassMethods)
112
+ end
113
+
114
+ module ClassMethods
115
+
116
+ # === Examples
117
+ #
118
+ # belongs_to Article
119
+ # belongs_to :article, Article
120
+ # belongs_to :article, Article, :view => 'lala'
121
+
122
+ def belongs_to(*args)
123
+ require 'og/relation/belongs_to'
124
+ meta :relations, Og::BelongsTo.new(args, :owner_class => self)
125
+ end
126
+
127
+ # === Examples
128
+ #
129
+ # refers_to Topic
130
+
131
+ def refers_to(*args)
132
+ require 'og/relation/refers_to'
133
+ meta :relations, Og::RefersTo.new(args, :owner_class => self)
134
+ end
135
+
136
+ # === Examples
137
+ #
138
+ # has_one User
139
+
140
+ def has_one(*args)
141
+ require 'og/relation/has_one'
142
+ meta :relations, Og::HasOne.new(args, :owner_class => self)
143
+ end
144
+
145
+ # === Examples
146
+ #
147
+ # has_many Comment
148
+ # has_many :comments, Comment
149
+
150
+ def has_many(*args)
151
+ require 'og/relation/has_many'
152
+ meta :relations, Og::HasMany.new(args, :owner_class => self, :collection => true)
153
+ end
154
+
155
+ def joins_many(*args)
156
+ require 'og/relation/joins_many'
157
+ meta :relations, Og::JoinsMany.new(args, :owner_class => self, :collection => true)
158
+ end
159
+
160
+ def many_to_many(*args)
161
+ require 'og/relation/many_to_many'
162
+ meta :relations, Og::ManyToMany.new(args, :owner_class => self, :collection => true)
163
+ end
164
+
165
+ def inspect_relations
166
+ __meta[:relations]
167
+ end
168
+ alias_method :relations, :inspect_relations
169
+
170
+ def inspect_relation(name)
171
+ __meta[:relations].find { |r| r[:name] == name }
172
+ end
173
+ alias_method :relation, :inspect_relation
174
+
175
+ end
176
+ end
177
+
178
+ end
@@ -0,0 +1,14 @@
1
+ require 'og/relation/refers_to'
2
+
3
+ module Og
4
+
5
+ class BelongsTo < RefersTo
6
+
7
+ def enchant
8
+ super
9
+ target_class.meta :descendants, [owner_class, foreign_key]
10
+ end
11
+
12
+ end
13
+
14
+ end
@@ -0,0 +1,62 @@
1
+ require 'facet/string/singular'
2
+ require 'facet/string/demodulize'
3
+ require 'facet/string/underscore'
4
+
5
+ require 'og/relation'
6
+ require 'og/collection'
7
+
8
+ module Og
9
+
10
+ class HasManyCollection < Collection
11
+ end
12
+
13
+ # A 'has_many' relation. There should be a respective
14
+ # 'belongs_to' relation.
15
+ #
16
+ # === Examples
17
+ #
18
+ # article.comments << Comment.new
19
+ # article.comments.size
20
+
21
+ class HasMany < Relation
22
+
23
+ def enchant
24
+ self[:owner_singular_name] = owner_class.to_s.demodulize.underscore.downcase
25
+ self[:target_singular_name] = target_plural_name.to_s.singular
26
+ self[:foreign_key] = "#{foreign_name || owner_singular_name}_#{owner_pk}"
27
+
28
+ owner_class.module_eval %{
29
+ attr_accessor :#{target_plural_name}
30
+
31
+ def #{target_plural_name}(options = nil)
32
+ unless @#{target_plural_name}
33
+ @#{target_plural_name} = HasManyCollection.new(
34
+ self,
35
+ :add_#{target_singular_name},
36
+ :find_#{target_plural_name},
37
+ options
38
+ )
39
+ end
40
+
41
+ @#{target_plural_name}.reload(options) if options and options[:reload]
42
+ @#{target_plural_name}
43
+ end
44
+
45
+ def add_#{target_singular_name}(obj)
46
+ obj.#{foreign_key} = @#{owner_pk}
47
+ obj.save
48
+ end
49
+
50
+ def find_#{target_plural_name}(options = {})
51
+ find_options = {
52
+ :condition => "#{foreign_key} = \#\{@#{owner_pk}\}"
53
+ }
54
+ find_options.update(options) if options
55
+ #{target_class}.find(find_options)
56
+ end
57
+ }
58
+ end
59
+
60
+ end
61
+
62
+ end
@@ -0,0 +1,17 @@
1
+ require 'og/relation/refers_to'
2
+
3
+ module Og
4
+
5
+ # A 'has_one' relation.
6
+ #
7
+ # === Examples
8
+ #
9
+ # user.profile = Profile.new
10
+ # user.profile
11
+ # user.profile(true) # reload
12
+ # user.profile(:reload => true)
13
+
14
+ class HasOne < RefersTo
15
+ end
16
+
17
+ end
@@ -0,0 +1,69 @@
1
+ require 'facet/string/singular'
2
+ require 'facet/string/demodulize'
3
+ require 'facet/string/underscore'
4
+
5
+ require 'og/relation'
6
+ require 'og/collection'
7
+
8
+ module Og
9
+
10
+ class JoinsManyCollection < Collection
11
+ end
12
+
13
+ # A 'joins_many' relation.
14
+ # This objects is associated with an other using an intermediate
15
+ # join table.
16
+ #
17
+ # === Examples
18
+ #
19
+ # joins_many Category
20
+ # joins_many :categories, Category
21
+
22
+ class JoinsMany < Relation
23
+
24
+ def enchant
25
+ self[:owner_singular_name] = owner_class.to_s.demodulize.underscore.downcase
26
+ self[:target_singular_name] = target_plural_name.to_s.singular
27
+
28
+ store = owner_class.ogmanager.store
29
+ join_table, oidx, tidx = store.join_table(owner_class, target_class)
30
+ owner_class.meta :join_tables, join_table
31
+
32
+ owner_class.module_eval %{
33
+ attr_accessor :#{target_plural_name}
34
+
35
+ def #{target_plural_name}(options = nil)
36
+ reload = options and options[:reload]
37
+
38
+ unless @#{target_plural_name}
39
+ @#{target_plural_name} = JoinsManyCollection.new(
40
+ self,
41
+ :add_#{target_singular_name},
42
+ :find_#{target_plural_name}
43
+ )
44
+ end
45
+
46
+ @#{target_plural_name}.reload(options) if options and options[:reload]
47
+ @#{target_plural_name}
48
+ end
49
+
50
+ def add_#{target_singular_name}(obj)
51
+ obj.save
52
+ obj.class.ogmanager.store.join(self, obj, "#{join_table}")
53
+ end
54
+
55
+ def find_#{target_plural_name}(options = {})
56
+ find_options = {
57
+ :join_table => "#{join_table}",
58
+ :join_condition => "#{join_table}.key#{tidx}=#{store.table(target_class)}.oid",
59
+ :condition => "#{join_table}.key#{oidx}=\#\{@#{owner_pk}\}"
60
+ }
61
+ find_options.update(options) if options
62
+ #{target_class}.find(find_options)
63
+ end
64
+ }
65
+ end
66
+
67
+ end
68
+
69
+ end