og 0.6.0 → 0.7.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.
- data/ChangeLog +183 -0
- data/ChangeLog.1 +2344 -0
- data/README.og +4 -3
- data/RELEASES.og +15 -0
- data/Rakefile +135 -0
- data/examples/og/README +7 -0
- data/examples/og/mock_example.rb +58 -0
- data/examples/og/run.rb +9 -5
- data/lib/glue/property.rb +166 -107
- data/lib/glue/property.rb.old +307 -0
- data/lib/og.rb +17 -6
- data/lib/og/backend.rb +34 -4
- data/lib/og/backends/mysql.rb +3 -17
- data/lib/og/backends/psql.rb +5 -17
- data/lib/og/meta.rb +41 -26
- data/lib/og/mock.rb +223 -0
- data/lib/og/version.rb +2 -2
- data/test/og/tc_lifecycle.rb +107 -0
- data/test/tc_og.rb +31 -4
- metadata +22 -14
@@ -0,0 +1,307 @@
|
|
1
|
+
# code:
|
2
|
+
# * George Moschovitis <gm@navel.gr>
|
3
|
+
# design:
|
4
|
+
# * Anastastios Koutoumanos <ak@navel.gr>
|
5
|
+
# * Elias Karakoulakis <ekarak@ktismata.com>
|
6
|
+
#
|
7
|
+
# (c) 2004 Navel, all rights reserved.
|
8
|
+
# $Id: property.rb 185 2004-12-10 13:29:09Z gmosx $
|
9
|
+
|
10
|
+
require "glue/array"
|
11
|
+
require "glue/hash"
|
12
|
+
|
13
|
+
module G
|
14
|
+
|
15
|
+
# = Property
|
16
|
+
#
|
17
|
+
# Ruby attributes are typeless and generally this is good. Some times
|
18
|
+
# we need extra metadata though, for example in relational mapping,
|
19
|
+
# or web form population.
|
20
|
+
#
|
21
|
+
# Only Fixnums, Strings, Floats, Times, Booleans are converted.
|
22
|
+
#
|
23
|
+
# The default = methods do not force the types. A special
|
24
|
+
# __force_set method should be used instead.
|
25
|
+
#
|
26
|
+
#--
|
27
|
+
# TODO:
|
28
|
+
# Inject only the really needd methods into Module.
|
29
|
+
# Perhaps a sync is needed in evals (!!!!)
|
30
|
+
#++
|
31
|
+
#
|
32
|
+
class Property
|
33
|
+
# the symbol of the property
|
34
|
+
attr_accessor :symbol
|
35
|
+
# the string representation of the symbol
|
36
|
+
attr_accessor :name
|
37
|
+
# the class of the property
|
38
|
+
attr_accessor :klass
|
39
|
+
# additional metadata (like sql declaratio, sql index, etc)
|
40
|
+
attr_accessor :meta
|
41
|
+
|
42
|
+
def initialize(symbol, klass, meta = {})
|
43
|
+
@symbol, @klass = symbol, klass
|
44
|
+
@meta = meta
|
45
|
+
@name = @symbol.to_s()
|
46
|
+
end
|
47
|
+
|
48
|
+
def ==(other)
|
49
|
+
return @symbol == other.symbol
|
50
|
+
end
|
51
|
+
|
52
|
+
def to_s
|
53
|
+
return name
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
end # module
|
58
|
+
|
59
|
+
class Module
|
60
|
+
|
61
|
+
# Define a property (== typed attribute)
|
62
|
+
# This works like Ruby's standard attr method, ie creates
|
63
|
+
# only one property.
|
64
|
+
#
|
65
|
+
# Use the prop_reader, prop_writer, prop_accessor methods
|
66
|
+
# for multiple properties.
|
67
|
+
#
|
68
|
+
# Examples:
|
69
|
+
# prop String, :name, :sql => "char(32), :sql_index => "name(32)"
|
70
|
+
# --> creates only writer.
|
71
|
+
# prop Fixnum, :oid, writer = true, :sql => "integer PRIMARY KEY"
|
72
|
+
# --> creates reader and writer.
|
73
|
+
#
|
74
|
+
def prop(*params)
|
75
|
+
meta = {}
|
76
|
+
klass = Object
|
77
|
+
|
78
|
+
for param in params
|
79
|
+
if param.is_a?(Class)
|
80
|
+
klass = param
|
81
|
+
elsif param.is_a?(Symbol)
|
82
|
+
symbol = param
|
83
|
+
elsif param.is_a?(TrueClass) or param.is_a?(TrueClass)
|
84
|
+
writer = param
|
85
|
+
elsif param.is_a?(Hash)
|
86
|
+
# the meta hash.
|
87
|
+
meta = param
|
88
|
+
else
|
89
|
+
raise "Error when defining property!"
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
unless self.methods.include?(:__props)
|
94
|
+
eval %{
|
95
|
+
# Properties
|
96
|
+
# An array is used to enforce order.
|
97
|
+
def __props
|
98
|
+
@__props
|
99
|
+
end
|
100
|
+
|
101
|
+
def __props=(props)
|
102
|
+
@__props = props
|
103
|
+
end
|
104
|
+
|
105
|
+
def __meta
|
106
|
+
@__meta
|
107
|
+
end
|
108
|
+
|
109
|
+
def __meta=(meta)
|
110
|
+
@__meta = meta
|
111
|
+
end
|
112
|
+
}
|
113
|
+
end
|
114
|
+
|
115
|
+
@__props = G::SafeArray.new() unless @__props
|
116
|
+
|
117
|
+
property = G::Property.new(symbol, klass, meta)
|
118
|
+
|
119
|
+
reader = meta[:reader] || true
|
120
|
+
writer = writer || meta[:writer] || false
|
121
|
+
|
122
|
+
__add_prop(property, reader, writer)
|
123
|
+
end
|
124
|
+
|
125
|
+
# Helper method. Accepts a collection of symbols and generates
|
126
|
+
# properties. Only generates reader.
|
127
|
+
#
|
128
|
+
# Example:
|
129
|
+
# prop_reader String, :name, :title, :body, :sql => "char(32)"
|
130
|
+
#
|
131
|
+
def prop_reader(*params)
|
132
|
+
meta = {}
|
133
|
+
klass = Object
|
134
|
+
symbols = []
|
135
|
+
|
136
|
+
for param in params
|
137
|
+
if param.is_a?(Class)
|
138
|
+
klass = param
|
139
|
+
elsif param.is_a?(Symbol)
|
140
|
+
symbols << param
|
141
|
+
elsif param.is_a?(Hash)
|
142
|
+
# the meta hash.
|
143
|
+
meta = param
|
144
|
+
else
|
145
|
+
raise "Error when defining property!"
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
meta[:reader] = true
|
150
|
+
meta[:writer] = false
|
151
|
+
|
152
|
+
for symbol in symbols
|
153
|
+
prop(klass, symbol, meta)
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
# Helper method. Accepts a collection of symbols and generates
|
158
|
+
# properties. Only generates writer.
|
159
|
+
#
|
160
|
+
# Example:
|
161
|
+
# prop_writer String, :name, :title, :body, :sql => "char(32)"
|
162
|
+
#
|
163
|
+
def prop_writer(*params)
|
164
|
+
meta = {}
|
165
|
+
klass = Object
|
166
|
+
symbols = []
|
167
|
+
|
168
|
+
for param in params
|
169
|
+
if param.is_a?(Class)
|
170
|
+
klass = param
|
171
|
+
elsif param.is_a?(Symbol)
|
172
|
+
symbols << param
|
173
|
+
elsif param.is_a?(Hash)
|
174
|
+
# the meta hash.
|
175
|
+
meta = param
|
176
|
+
else
|
177
|
+
raise "Error when defining property!"
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
meta[:reader] = false
|
182
|
+
meta[:writer] = true
|
183
|
+
|
184
|
+
for symbol in symbols
|
185
|
+
prop(klass, symbol, meta)
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
# Helper method. Accepts a collection of symbols and generates
|
190
|
+
# properties. Generates reader and writer.
|
191
|
+
#
|
192
|
+
# Example:
|
193
|
+
# prop_accessor String, :name, :title, :body, :sql => "char(32)"
|
194
|
+
#
|
195
|
+
def prop_accessor(*params)
|
196
|
+
meta = {}
|
197
|
+
klass = Object
|
198
|
+
symbols = []
|
199
|
+
|
200
|
+
for param in params
|
201
|
+
if param.is_a?(Class)
|
202
|
+
klass = param
|
203
|
+
elsif param.is_a?(Symbol)
|
204
|
+
symbols << param
|
205
|
+
elsif param.is_a?(Hash)
|
206
|
+
# the meta hash.
|
207
|
+
meta = param
|
208
|
+
else
|
209
|
+
raise "Error when defining property!"
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
meta[:reader] = true
|
214
|
+
meta[:writer] = true
|
215
|
+
|
216
|
+
for symbol in symbols
|
217
|
+
prop(klass, symbol, meta)
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
# Add the property
|
222
|
+
#
|
223
|
+
def __add_prop(prop, reader = true, writer = true)
|
224
|
+
if idx = @__props.index(prop)
|
225
|
+
# override in case of duplicates. Keep the order of the props.
|
226
|
+
@__props[idx] = prop
|
227
|
+
else
|
228
|
+
@__props << prop
|
229
|
+
end
|
230
|
+
|
231
|
+
# Precompile the property read/write methods
|
232
|
+
|
233
|
+
s, klass = prop.symbol, prop.klass
|
234
|
+
|
235
|
+
if reader
|
236
|
+
module_eval %{
|
237
|
+
def #{s}
|
238
|
+
return @#{s}
|
239
|
+
end
|
240
|
+
}
|
241
|
+
end
|
242
|
+
|
243
|
+
# gmosx: __force_xxx reuses xxx= to allow for easier
|
244
|
+
# overrides.
|
245
|
+
if writer
|
246
|
+
module_eval %{
|
247
|
+
def #{s}=(val)
|
248
|
+
@#{s} = val
|
249
|
+
end
|
250
|
+
|
251
|
+
def __force_#{s}(val)
|
252
|
+
self.#{s}=(} + case klass.name
|
253
|
+
when Fixnum.name
|
254
|
+
"val.to_i()"
|
255
|
+
when String.name
|
256
|
+
"val.to_s()"
|
257
|
+
when Float.name
|
258
|
+
"val.to_f()"
|
259
|
+
when Time.name
|
260
|
+
"Time.parse(val.to_s())"
|
261
|
+
when TrueClass.name, FalseClass.name
|
262
|
+
"val.to_i() > 0"
|
263
|
+
else
|
264
|
+
"val"
|
265
|
+
end + %{)
|
266
|
+
end
|
267
|
+
}
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
# Attach metadata
|
272
|
+
#
|
273
|
+
def meta(key, val)
|
274
|
+
@__meta = G::SafeHash.new unless @__meta
|
275
|
+
|
276
|
+
@__meta[key] = [] unless @__meta[key]
|
277
|
+
|
278
|
+
# guard against duplicates, no need to keep order.
|
279
|
+
@__meta[key].delete_if { |v| val == v }
|
280
|
+
@__meta[key] << val
|
281
|
+
end
|
282
|
+
|
283
|
+
# This method is typically called before including other
|
284
|
+
# modules to preserve properties order.
|
285
|
+
#
|
286
|
+
def inherit_meta(mod = superclass)
|
287
|
+
# concat props.
|
288
|
+
if mod.__props
|
289
|
+
@__props = G::SafeArray.new unless @__props
|
290
|
+
|
291
|
+
mod.__props.each { |p|
|
292
|
+
__add_prop(p)
|
293
|
+
}
|
294
|
+
end
|
295
|
+
|
296
|
+
# concat metadata
|
297
|
+
if mod.__meta
|
298
|
+
mod.__meta.each { |k, val|
|
299
|
+
val.each { |v|
|
300
|
+
meta(k, v)
|
301
|
+
} if val
|
302
|
+
}
|
303
|
+
end
|
304
|
+
end
|
305
|
+
|
306
|
+
end
|
307
|
+
|
data/lib/og.rb
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
# * George Moschovitis <gm@navel.gr>
|
3
3
|
#
|
4
4
|
# (c) 2004 Navel, all rights reserved.
|
5
|
-
# $Id: og.rb
|
5
|
+
# $Id: og.rb 197 2004-12-21 13:50:17Z gmosx $
|
6
6
|
|
7
7
|
require "glue/property"
|
8
8
|
require "glue/array"
|
@@ -28,6 +28,11 @@ $og_auto_manage_classes = true
|
|
28
28
|
# If true, automatically include the Og meta-language into Module.
|
29
29
|
$og_include_meta_language = true
|
30
30
|
|
31
|
+
# Attach the following prefix to all generated SQL table names.
|
32
|
+
# Usefull on hosting scenarios where you have to run multiple
|
33
|
+
# web applications/sites on a single database.
|
34
|
+
$og_table_prefix = nil
|
35
|
+
|
31
36
|
require "og/meta"
|
32
37
|
|
33
38
|
# = Og
|
@@ -169,7 +174,10 @@ class Database
|
|
169
174
|
@config[:connection_count].times do
|
170
175
|
@connection_pool << Og::Connection.new(self)
|
171
176
|
end
|
172
|
-
|
177
|
+
|
178
|
+
# gmosx, FIXME: this automanage code is not elegant and slow
|
179
|
+
# should probably recode this, along with glue/property.rb
|
180
|
+
#
|
173
181
|
if $og_auto_manage_classes
|
174
182
|
# automatically manage classes with properties and metadata.
|
175
183
|
# gmosx: Any idea how to optimize this?
|
@@ -286,8 +294,6 @@ class Database
|
|
286
294
|
Og::Utils.eval_og_oid(klass) unless klass.instance_methods.include?(:oid)
|
287
295
|
|
288
296
|
klass.class_eval %{
|
289
|
-
inherit_meta(superclass) if superclass
|
290
|
-
|
291
297
|
DBTABLE = "#{Og::Utils.table(klass)}"
|
292
298
|
DBSEQ = "#{Og::Utils.table(klass)}_oids_seq"
|
293
299
|
|
@@ -311,7 +317,12 @@ class Database
|
|
311
317
|
# class and its instances.
|
312
318
|
#
|
313
319
|
def enchant(klass)
|
314
|
-
klass.
|
320
|
+
klass.module_eval <<-"end_eval", __FILE__, __LINE__
|
321
|
+
def self.create(*params)
|
322
|
+
obj = #{klass}.new(*params)
|
323
|
+
obj.save!
|
324
|
+
end
|
325
|
+
|
315
326
|
def self.save(obj)
|
316
327
|
$og << obj
|
317
328
|
end
|
@@ -362,7 +373,7 @@ class Database
|
|
362
373
|
def delete!
|
363
374
|
$og.delete(@oid, #{klass})
|
364
375
|
end
|
365
|
-
|
376
|
+
end_eval
|
366
377
|
end
|
367
378
|
|
368
379
|
# Automatically wrap connection methods.
|
data/lib/og/backend.rb
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
# * George Moschovitis <gm@navel.gr>
|
3
3
|
#
|
4
4
|
# (c) 2004 Navel, all rights reserved.
|
5
|
-
# $Id: backend.rb
|
5
|
+
# $Id: backend.rb 197 2004-12-21 13:50:17Z gmosx $
|
6
6
|
|
7
7
|
require "yaml"
|
8
8
|
|
@@ -28,13 +28,13 @@ module Utils
|
|
28
28
|
# The name of the SQL table where objects of this class are stored.
|
29
29
|
#
|
30
30
|
def self.table(klass)
|
31
|
-
"_#{encode(klass)}"
|
31
|
+
"_#{$og_table_prefix}#{encode(klass)}"
|
32
32
|
end
|
33
33
|
|
34
34
|
# The name of the join table for the two given classes.
|
35
35
|
#
|
36
36
|
def self.join_table(klass1, klass2)
|
37
|
-
"
|
37
|
+
"_#{$og_table_prefix}j_#{Og::Utils.encode(klass1)}_#{Og::Utils.encode(klass2)}"
|
38
38
|
end
|
39
39
|
|
40
40
|
# Returns the props that will be included in the insert query.
|
@@ -232,7 +232,37 @@ class Backend
|
|
232
232
|
def rollback
|
233
233
|
exec "ROLLBACK"
|
234
234
|
end
|
235
|
-
|
235
|
+
|
236
|
+
# Create the fields that correpsond to the klass properties.
|
237
|
+
# The generated fields array is used in create_table.
|
238
|
+
# If the property has an :sql metadata this overrides the default mapping.
|
239
|
+
# If the property has an :extra_sql metadata the extra sql is appended
|
240
|
+
# after the default mapping.
|
241
|
+
#
|
242
|
+
def create_fields(klass, typemap)
|
243
|
+
fields = []
|
244
|
+
|
245
|
+
klass.__props.each do |p|
|
246
|
+
klass.sql_index(p.symbol) if p.meta[:sql_index]
|
247
|
+
|
248
|
+
field = "#{p.symbol}"
|
249
|
+
|
250
|
+
if p.meta and p.meta[:sql]
|
251
|
+
field << " #{p.meta[:sql]}"
|
252
|
+
else
|
253
|
+
field << " #{typemap[p.klass]}"
|
254
|
+
# attach extra sql
|
255
|
+
if p.meta and extra_sql = p.meta[:extra_sql]
|
256
|
+
field << " #{extra_sql}"
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
fields << field
|
261
|
+
end
|
262
|
+
|
263
|
+
return fields
|
264
|
+
end
|
265
|
+
|
236
266
|
# Create the managed object table. The properties of the
|
237
267
|
# object are mapped to the table columns. Additional sql relations
|
238
268
|
# and constrains are created (indicices, sequences, etc).
|
data/lib/og/backends/mysql.rb
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
# * Elias Athanasopoulos <elathan@navel.gr>
|
4
4
|
#
|
5
5
|
# (c) 2004 Navel, all rights reserved.
|
6
|
-
# $Id: mysql.rb
|
6
|
+
# $Id: mysql.rb 194 2004-12-20 20:23:57Z gmosx $
|
7
7
|
|
8
8
|
require "mysql"
|
9
9
|
|
@@ -263,21 +263,7 @@ class MysqlBackend < Og::Backend
|
|
263
263
|
# and constrains are created (indicices, sequences, etc).
|
264
264
|
#
|
265
265
|
def create_table(klass)
|
266
|
-
fields =
|
267
|
-
|
268
|
-
klass.__props.each do |p|
|
269
|
-
klass.sql_index(p.symbol) if p.meta[:sql_index]
|
270
|
-
|
271
|
-
field = "#{p.symbol}"
|
272
|
-
|
273
|
-
if p.meta and p.meta[:sql]
|
274
|
-
field << " #{p.meta[:sql]}"
|
275
|
-
else
|
276
|
-
field << " #{TYPEMAP[p.klass]}"
|
277
|
-
end
|
278
|
-
|
279
|
-
fields << field
|
280
|
-
end
|
266
|
+
fields = create_fields(klass, TYPEMAP)
|
281
267
|
|
282
268
|
sql = "CREATE TABLE #{klass::DBTABLE} (#{fields.join(', ')}"
|
283
269
|
|
@@ -326,7 +312,7 @@ class MysqlBackend < Og::Backend
|
|
326
312
|
join_src = "#{Og::Utils.encode(klass)}_oid"
|
327
313
|
join_dst = "#{Og::Utils.encode(join_class)}_oid"
|
328
314
|
begin
|
329
|
-
exec "CREATE TABLE #{join_table} ( key1 integer, key2 integer )"
|
315
|
+
exec "CREATE TABLE #{join_table} ( key1 integer NOT NULL, key2 integer NOT NULL )"
|
330
316
|
exec "CREATE INDEX #{join_table}_key1_idx ON #{join_table} (key1)"
|
331
317
|
exec "CREATE INDEX #{join_table}_key2_idx ON #{join_table} (key2)"
|
332
318
|
rescue => ex
|