nitro 0.11.0 → 0.12.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 +150 -0
- data/README +1 -1
- data/RELEASES +89 -0
- data/Rakefile +3 -3
- data/{AUTHORS → doc/AUTHORS} +0 -0
- data/{LICENSE → doc/LICENSE} +0 -0
- data/doc/bugs.txt +2 -1
- data/examples/README.windows +2 -2
- data/examples/blog/lib/blog/controller.rb +9 -8
- data/examples/blog/log/apache.error_log +71 -0
- data/{lib/xsl → examples/blog/root}/base.xsl +0 -0
- data/examples/blog/root/error.xhtml +56 -0
- data/examples/blog/root/index.xhtml +2 -2
- data/examples/blog/root/recent_posts.xhtml +1 -1
- data/examples/blog/root/style.xsl +4 -4
- data/examples/blog/run.rb +1 -2
- data/examples/no_xsl_blog/root/index.xhtml +2 -2
- data/examples/no_xsl_blog/root/recent_posts.xhtml +1 -1
- data/examples/why_wiki/run.rb +19 -19
- data/lib/nitro.rb +2 -21
- data/lib/nitro/adapters/webrick.rb +19 -3
- data/lib/nitro/context.rb +15 -1
- data/lib/nitro/controller.rb +84 -49
- data/lib/nitro/dispatcher.rb +30 -6
- data/lib/nitro/markup.rb +4 -2
- data/lib/nitro/render.rb +15 -11
- data/lib/nitro/routing.rb +33 -0
- data/lib/nitro/runner.rb +38 -3
- data/lib/nitro/scaffold.rb +7 -4
- data/lib/nitro/shaders.rb +11 -4
- data/lib/nitro/template.rb +140 -0
- data/lib/og.rb +25 -11
- data/lib/og/adapter.rb +141 -7
- data/lib/og/adapters/mysql.rb +41 -3
- data/lib/og/adapters/oracle.rb +4 -3
- data/lib/og/adapters/psql.rb +3 -3
- data/lib/og/adapters/sqlite.rb +3 -3
- data/lib/og/connection.rb +5 -1
- data/lib/og/database.rb +26 -12
- data/lib/og/enchant.rb +50 -16
- data/lib/og/meta.rb +15 -15
- data/lib/og/observer.rb +53 -0
- data/test/glue/tc_property_type_checking.rb +3 -0
- data/test/nitro/tc_controller.rb +1 -1
- data/test/nitro/tc_dispatcher.rb +1 -1
- data/test/nitro/tc_template.rb +32 -0
- data/test/og/tc_many_to_many.rb +62 -0
- data/test/og/tc_observer.rb +85 -0
- data/test/tc_og.rb +16 -2
- metadata +12 -14
- data/bin/cluster +0 -218
- data/examples/why_wiki/wiki.yml +0 -6
- data/examples/wiki.yml +0 -1
- data/lib/nitro/ui/select.rb +0 -40
- data/lib/nitro/ui/sitemap.rb +0 -183
- data/test/nitro/ui/tc_sitemap.rb +0 -37
data/lib/og/adapters/sqlite.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# * George Moschovitis <gm@navel.gr>
|
2
2
|
# (c) 2004-2005 Navel, all rights reserved.
|
3
|
-
# $Id: sqlite.rb
|
3
|
+
# $Id: sqlite.rb 270 2005-03-07 17:52:16Z gmosx $
|
4
4
|
|
5
5
|
require 'sqlite3'
|
6
6
|
require 'fileutils'
|
@@ -142,11 +142,11 @@ class SqliteAdapter < Adapter
|
|
142
142
|
if klass.__meta and joins = klass.__meta[:sql_join]
|
143
143
|
for data in joins
|
144
144
|
# the class to join to and some options.
|
145
|
-
join_class, options = *data
|
145
|
+
join_name, join_class, options = *data
|
146
146
|
|
147
147
|
# gmosx: dont use DBTABLE here, perhaps the join class
|
148
148
|
# is not managed yet.
|
149
|
-
join_table = "#{self.class.join_table(klass, join_class)}"
|
149
|
+
join_table = "#{self.class.join_table(klass, join_class, join_name)}"
|
150
150
|
join_src = "#{self.class.encode(klass)}_oid"
|
151
151
|
join_dst = "#{self.class.encode(join_class)}_oid"
|
152
152
|
begin
|
data/lib/og/connection.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# * George Moschovitis <gm@navel.gr>
|
2
2
|
# (c) 2004-2005 Navel, all rights reserved.
|
3
|
-
# $Id: connection.rb
|
3
|
+
# $Id: connection.rb 270 2005-03-07 17:52:16Z gmosx $
|
4
4
|
|
5
5
|
module Og;
|
6
6
|
|
@@ -270,6 +270,10 @@ class Connection
|
|
270
270
|
#
|
271
271
|
# obj_or_oid = Object or oid to delete.
|
272
272
|
# klass = Class of object (can be nil if an object is passed)
|
273
|
+
#
|
274
|
+
#--
|
275
|
+
# TODO: pre evaluate for symmetry to the other methods
|
276
|
+
#++
|
273
277
|
|
274
278
|
def delete(obj_or_oid, klass = nil, cascade = true)
|
275
279
|
oid = obj_or_oid.to_i
|
data/lib/og/database.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# * George Moschovitis <gm@navel.gr>
|
2
2
|
# (c) 2004-2005 Navel, all rights reserved.
|
3
|
-
# $Id: database.rb
|
3
|
+
# $Id: database.rb 270 2005-03-07 17:52:16Z gmosx $
|
4
4
|
|
5
5
|
require 'glue/logger'
|
6
6
|
require 'glue/attribute'
|
@@ -12,6 +12,7 @@ require 'glue/pool'
|
|
12
12
|
|
13
13
|
require 'og/enchant'
|
14
14
|
require 'og/meta'
|
15
|
+
require 'og/observer'
|
15
16
|
|
16
17
|
module Og
|
17
18
|
|
@@ -68,7 +69,6 @@ class Database
|
|
68
69
|
@managed_classes = N::SafeHash.new
|
69
70
|
|
70
71
|
@config[:connection_count].times do
|
71
|
-
# @connection_pool << Og::Connection.new(self)
|
72
72
|
@connection_pool << @adapter.new_connection(self)
|
73
73
|
end
|
74
74
|
|
@@ -148,11 +148,10 @@ class Database
|
|
148
148
|
end
|
149
149
|
alias_method :open, :connect
|
150
150
|
|
151
|
-
|
152
151
|
# Register a standard Ruby class as managed.
|
153
152
|
|
154
153
|
def manage(klass)
|
155
|
-
return if managed?(klass) or klass.ancestors.include?(
|
154
|
+
return if managed?(klass) or klass.ancestors.include?(Unmanageable)
|
156
155
|
|
157
156
|
@managed_classes[klass] = ManagedClassMeta.new(klass)
|
158
157
|
|
@@ -194,22 +193,31 @@ class Database
|
|
194
193
|
klass.class_eval %{
|
195
194
|
DBTABLE = "#{Adapter.table(klass)}"
|
196
195
|
DBSEQ = "#{Adapter.table(klass)}_oid_seq"
|
197
|
-
|
198
|
-
|
196
|
+
|
197
|
+
cattr_accessor :og_db
|
198
|
+
|
199
|
+
def to_i
|
199
200
|
@oid
|
200
201
|
end
|
201
202
|
}
|
202
203
|
|
204
|
+
# Set the adapter.
|
205
|
+
|
206
|
+
klass.og_db = self
|
207
|
+
|
208
|
+
# Add observer support.
|
209
|
+
|
210
|
+
klass.extend(Observable)
|
211
|
+
|
203
212
|
# Create the schema for this class if not available.
|
213
|
+
|
204
214
|
@adapter.create_table(klass, self) if Og.create_schema
|
205
215
|
|
206
|
-
#
|
207
|
-
#
|
208
|
-
#
|
216
|
+
# @adapter.eval_og_insert(klass, self)
|
217
|
+
# @adapter.eval_og_update(klass, self)
|
218
|
+
# @adapter.eval_og_read(klass, self)
|
209
219
|
|
210
|
-
@adapter.
|
211
|
-
@adapter.eval_og_update(klass, self)
|
212
|
-
@adapter.eval_og_read(klass, self)
|
220
|
+
@adapter.eval_lifecycle_methods(klass, self)
|
213
221
|
end
|
214
222
|
|
215
223
|
# Automatically wrap connection methods.
|
@@ -251,17 +259,23 @@ class Database
|
|
251
259
|
wrap_method :exec, 'sql'
|
252
260
|
|
253
261
|
class << self
|
262
|
+
|
263
|
+
# Create a new database.
|
264
|
+
|
254
265
|
def create_db!(config)
|
255
266
|
adapter = Adapter.for_name(config[:adapter])
|
256
267
|
adapter.create_db(config[:database], config[:user], config[:password])
|
257
268
|
end
|
258
269
|
alias_method :create!, :create_db!
|
259
270
|
|
271
|
+
# Drop an existing database.
|
272
|
+
|
260
273
|
def drop_db!(config)
|
261
274
|
adapter = Adapter.for_name(config[:adapter])
|
262
275
|
adapter.drop_db(config[:database], config[:user], config[:password])
|
263
276
|
end
|
264
277
|
alias_method :drop!, :drop_db!
|
278
|
+
|
265
279
|
end
|
266
280
|
end
|
267
281
|
|
data/lib/og/enchant.rb
CHANGED
@@ -10,54 +10,65 @@ module Enchant
|
|
10
10
|
# to the class and its instances.
|
11
11
|
|
12
12
|
def enchant(klass)
|
13
|
-
|
13
|
+
|
14
|
+
# Generate standard methods.
|
15
|
+
|
16
|
+
klass.module_eval %{
|
14
17
|
def self.create(*params, &block)
|
15
18
|
obj = #{klass}.new(*params, &block)
|
16
19
|
obj.save!
|
17
20
|
end
|
18
21
|
|
19
22
|
def self.save(obj)
|
20
|
-
|
23
|
+
@@og_db << obj
|
21
24
|
end
|
22
25
|
|
23
26
|
def self.load(oid_or_name)
|
24
|
-
|
27
|
+
@@og_db.load(oid_or_name, #{klass})
|
25
28
|
end
|
26
29
|
|
27
30
|
def self.get(oid_or_name)
|
28
|
-
|
31
|
+
@@og_db.load(oid_or_name, #{klass})
|
29
32
|
end
|
30
33
|
|
31
34
|
def self.[](oid_or_name)
|
32
|
-
|
35
|
+
@@og_db.load(oid_or_name, #{klass})
|
33
36
|
end
|
34
37
|
|
35
38
|
def self.load_all(extra_sql = nil)
|
36
|
-
|
39
|
+
@@og_db.load_all(#{klass}, extra_sql)
|
37
40
|
end
|
38
41
|
|
39
42
|
def self.all(extra_sql = nil)
|
40
|
-
|
43
|
+
@@og_db.load_all(#{klass}, extra_sql)
|
41
44
|
end
|
42
45
|
|
43
46
|
def self.count(sql = "SELECT COUNT(*) FROM #{klass::DBTABLE}")
|
44
|
-
|
47
|
+
@@og_db.count(sql, #{klass})
|
45
48
|
end
|
46
49
|
|
47
50
|
def self.select(sql)
|
48
|
-
|
51
|
+
@@og_db.select(sql, #{klass})
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.find(sql)
|
55
|
+
@@og_db.select(sql, #{klass})
|
49
56
|
end
|
50
57
|
|
51
58
|
def self.select_one(sql)
|
52
|
-
|
59
|
+
@@og_db.select_one(sql, #{klass})
|
60
|
+
end
|
61
|
+
|
62
|
+
def self.find_one(sql)
|
63
|
+
@@og_db.select_one(sql, #{klass})
|
53
64
|
end
|
54
65
|
|
55
66
|
def self.one(sql)
|
56
|
-
|
67
|
+
@@og_db.select_one(sql, #{klass})
|
57
68
|
end
|
58
69
|
|
59
70
|
def self.delete(obj_or_oid)
|
60
|
-
|
71
|
+
@@og_db.delete(obj_or_oid, #{klass})
|
61
72
|
end
|
62
73
|
|
63
74
|
def self.properties_and_relations
|
@@ -70,20 +81,43 @@ module Enchant
|
|
70
81
|
include Enumerable
|
71
82
|
|
72
83
|
def save
|
73
|
-
|
84
|
+
@@og_db << self
|
74
85
|
return self
|
75
86
|
end
|
76
87
|
alias_method :save!, :save
|
77
88
|
|
78
89
|
def update_properties(updatesql)
|
79
|
-
|
90
|
+
@@og_db.pupdate(updatesql, self.oid, #{klass})
|
80
91
|
end
|
81
92
|
alias_method :pupdate!, :update_properties
|
82
93
|
|
83
94
|
def delete!
|
84
|
-
|
95
|
+
@@og_db.delete(@oid, #{klass})
|
85
96
|
end
|
86
|
-
|
97
|
+
}
|
98
|
+
|
99
|
+
# Generate finder methods.
|
100
|
+
|
101
|
+
code = ''
|
102
|
+
|
103
|
+
for p in klass.__props
|
104
|
+
code << %{
|
105
|
+
def self.find_by_#{p.name}(val, operator = '=', extra_sql = nil)
|
106
|
+
}
|
107
|
+
|
108
|
+
val = klass.og_db.adapter.typecast[p.klass].gsub(/\:s\:/, 'val')
|
109
|
+
|
110
|
+
if p.meta[:unique]
|
111
|
+
code << %{@@og_db.select_one("#{p.name}\#\{operator\}#{val} \#\{extra_sql\}", #{klass})}
|
112
|
+
else
|
113
|
+
code << %{@@og_db.select("#{p.name}\#\{operator\}#{val} \#\{extra_sql\}", #{klass})}
|
114
|
+
end
|
115
|
+
code << %{
|
116
|
+
end;
|
117
|
+
}
|
118
|
+
end
|
119
|
+
|
120
|
+
klass.module_eval(code)
|
87
121
|
end
|
88
122
|
|
89
123
|
end
|
data/lib/og/meta.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# * George Moschovitis <gm@navel.gr>
|
2
2
|
# (c) 2004-2005 Navel, all rights reserved.
|
3
|
-
# $Id: meta.rb
|
3
|
+
# $Id: meta.rb 270 2005-03-07 17:52:16Z gmosx $
|
4
4
|
#--
|
5
5
|
# TODO:
|
6
6
|
# - precreate the meta sql statements as much as possible to
|
@@ -135,7 +135,7 @@ module MetaLanguage
|
|
135
135
|
# linkback is the property of the child object that 'links back'
|
136
136
|
# to this object.
|
137
137
|
|
138
|
-
linkback = options[:linkback] || "#{MetaUtils.expand(self)}_oid"
|
138
|
+
linkback = (options[:linkback].to_s || "#{MetaUtils.expand(self)}_oid").to_s
|
139
139
|
|
140
140
|
meta :descendants, klass, linkback
|
141
141
|
meta :props_and_relations, HasOne.new(name, klass, :linkback => linkback)
|
@@ -175,7 +175,7 @@ module MetaLanguage
|
|
175
175
|
# linkback is the property of the child object that 'links back'
|
176
176
|
# to this object.
|
177
177
|
|
178
|
-
linkback = options[:linkback] || "#{MetaUtils.expand(self)}_oid"
|
178
|
+
linkback = (options[:linkback] || "#{MetaUtils.expand(self)}_oid").to_s
|
179
179
|
|
180
180
|
# keep belongs to metadata, useful for
|
181
181
|
# reflection/scaffolding.
|
@@ -231,7 +231,7 @@ module MetaLanguage
|
|
231
231
|
def many_to_many(name, klass, options = {})
|
232
232
|
list_o = name.to_s
|
233
233
|
prop_o = N::Inflector.singularize(list_o)
|
234
|
-
list_m = options[:linkback] || N::Inflector.plural_name(self)
|
234
|
+
list_m = (options[:linkback] || N::Inflector.plural_name(self)).to_s
|
235
235
|
prop_m = N::Inflector.singularize(list_m)
|
236
236
|
|
237
237
|
# Exit if the class is allready indirectly 'enchanted' from the
|
@@ -242,7 +242,7 @@ module MetaLanguage
|
|
242
242
|
# Add some metadata to the class to allow for automatic join table
|
243
243
|
# calculation.
|
244
244
|
|
245
|
-
meta :sql_join, klass, options
|
245
|
+
meta :sql_join, name, klass, options
|
246
246
|
|
247
247
|
# FIXME: should add metadata for cascading delete.
|
248
248
|
|
@@ -253,25 +253,25 @@ module MetaLanguage
|
|
253
253
|
|
254
254
|
module_eval %{
|
255
255
|
def #{list_o}(extrasql = nil)
|
256
|
-
Og.db.select("SELECT d.* FROM #{Og::Adapter.table(klass)} d, #{Og::Adapter.join_table(self, klass)} j WHERE j.key1=\#\@oid AND j.key2=d.oid \#\{extrasql\}", #{klass})
|
256
|
+
Og.db.select("SELECT d.* FROM #{Og::Adapter.table(klass)} d, #{Og::Adapter.join_table(self, klass, name)} j WHERE j.key1=\#\@oid AND j.key2=d.oid \#\{extrasql\}", #{klass})
|
257
257
|
end
|
258
258
|
|
259
259
|
def #{list_o}_count(extrasql = nil)
|
260
|
-
Og.db.select("SELECT COUNT(*) FROM #{Og::Adapter.table(klass)} d, #{Og::Adapter.join_table(self, klass)} j WHERE j.key1=\#\@oid AND j.key2=d.oid \#\{extrasql\}", #{klass})
|
260
|
+
Og.db.select("SELECT COUNT(*) FROM #{Og::Adapter.table(klass)} d, #{Og::Adapter.join_table(self, klass, name)} j WHERE j.key1=\#\@oid AND j.key2=d.oid \#\{extrasql\}", #{klass})
|
261
261
|
end
|
262
262
|
|
263
263
|
def add_#{prop_o}(obj = nil)
|
264
264
|
yield(obj = #{klass}.new) unless obj
|
265
265
|
obj.save! unless obj.oid
|
266
|
-
Og.db.exec("INSERT INTO #{Og::Adapter.join_table(self, klass)} (key1, key2) VALUES (\#\@oid, \#\{obj.oid\})")
|
266
|
+
Og.db.exec("INSERT INTO #{Og::Adapter.join_table(self, klass, name)} (key1, key2) VALUES (\#\@oid, \#\{obj.oid\})")
|
267
267
|
end
|
268
268
|
|
269
269
|
def delete_#{prop_o}(obj_or_oid)
|
270
|
-
Og.db.exec("DELETE FROM #{Og::Adapter.join_table(self, klass)} WHERE key2=\#\{obj_or_oid.to_i\}")
|
270
|
+
Og.db.exec("DELETE FROM #{Og::Adapter.join_table(self, klass, name)} WHERE key2=\#\{obj_or_oid.to_i\}")
|
271
271
|
end
|
272
272
|
|
273
273
|
def clear_#{list_o}
|
274
|
-
Og.db.exec("DELETE FROM #{Og::Adapter.join_table(self, klass)} WHERE key1=\#\@oid")
|
274
|
+
Og.db.exec("DELETE FROM #{Og::Adapter.join_table(self, klass, name)} WHERE key1=\#\@oid")
|
275
275
|
end
|
276
276
|
}
|
277
277
|
|
@@ -279,25 +279,25 @@ module MetaLanguage
|
|
279
279
|
|
280
280
|
klass.module_eval %{
|
281
281
|
def #{list_m}(extrasql = nil)
|
282
|
-
Og.db.select("SELECT s.* FROM #{Og::Adapter.table(self)} s, #{Og::Adapter.join_table(self, klass)} j WHERE j.key2=\#\@oid AND j.key1=s.oid \#\{extrasql\}", #{self})
|
282
|
+
Og.db.select("SELECT s.* FROM #{Og::Adapter.table(self)} s, #{Og::Adapter.join_table(self, klass, name)} j WHERE j.key2=\#\@oid AND j.key1=s.oid \#\{extrasql\}", #{self})
|
283
283
|
end
|
284
284
|
|
285
285
|
def #{list_m}_count(extrasql = nil)
|
286
|
-
Og.db.select("SELECT COUNT(*) FROM #{Og::Adapter.table(self)} s, #{Og::Adapter.join_table(self, klass)} j WHERE j.key2=\#\@oid AND j.key1=s.oid \#\{extrasql\}", #{self})
|
286
|
+
Og.db.select("SELECT COUNT(*) FROM #{Og::Adapter.table(self)} s, #{Og::Adapter.join_table(self, klass, name)} j WHERE j.key2=\#\@oid AND j.key1=s.oid \#\{extrasql\}", #{self})
|
287
287
|
end
|
288
288
|
|
289
289
|
def add_#{prop_m}(obj = nil)
|
290
290
|
yield(obj = #{self}.new) unless obj
|
291
291
|
obj.save! unless obj.oid
|
292
|
-
Og.db.exec("INSERT INTO #{Og::Adapter.join_table(self, klass)} (key1, key2) VALUES (\#\{obj.oid\}, \#\@oid)")
|
292
|
+
Og.db.exec("INSERT INTO #{Og::Adapter.join_table(self, klass, name)} (key1, key2) VALUES (\#\{obj.oid\}, \#\@oid)")
|
293
293
|
end
|
294
294
|
|
295
295
|
def delete_#{prop_m}(obj_or_oid)
|
296
|
-
Og.db.exec("DELETE FROM #{Og::Adapter.join_table(self, klass)} WHERE key1=\#\{obj_or_oid.to_i\}")
|
296
|
+
Og.db.exec("DELETE FROM #{Og::Adapter.join_table(self, klass, name)} WHERE key1=\#\{obj_or_oid.to_i\}")
|
297
297
|
end
|
298
298
|
|
299
299
|
def clear_#{list_m}
|
300
|
-
Og.db.exec("DELETE FROM #{Og::Adapter.join_table(self, klass)} WHERE key2=\#\@oid")
|
300
|
+
Og.db.exec("DELETE FROM #{Og::Adapter.join_table(self, klass, name)} WHERE key2=\#\@oid")
|
301
301
|
end
|
302
302
|
}
|
303
303
|
end
|
data/lib/og/observer.rb
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
# * George Moschovitis <gm@navel.gr>
|
2
|
+
# (c) 2004-2005 Navel, all rights reserved.
|
3
|
+
# $Id: observer.rb 271 2005-03-07 17:56:45Z gmosx $
|
4
|
+
|
5
|
+
module Og
|
6
|
+
|
7
|
+
# Classes that include this module can be tracked by
|
8
|
+
# Observers. The observer mechanism utilizes duck typing
|
9
|
+
# so you can attach any class that responds to the
|
10
|
+
# Og lifycycle callback methods. However, classes extended
|
11
|
+
# from the Observer base class are typically used.
|
12
|
+
|
13
|
+
module Observable
|
14
|
+
def add_observer(*observer)
|
15
|
+
for o in observer.flatten
|
16
|
+
meta :og_observers, o
|
17
|
+
self.og_db.adapter.eval_lifecycle_methods(self, self.og_db)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# Observers are attached to managed classes to track their
|
23
|
+
# Lifecycle. This way, the 'polution' of the original class
|
24
|
+
# with excess responsibility is avoided.
|
25
|
+
#
|
26
|
+
# An observer can implement the standard Og lifecycle
|
27
|
+
# callbacks:
|
28
|
+
#
|
29
|
+
# * og_pre_read
|
30
|
+
# * og_post_read
|
31
|
+
# * og_pre_insert
|
32
|
+
# * og_post_insert
|
33
|
+
# * og_pre_update
|
34
|
+
# * og_post_update
|
35
|
+
# * og_pre_insert_update
|
36
|
+
# * og_post_insert_update
|
37
|
+
# * self.og_pre_delete
|
38
|
+
#
|
39
|
+
# Based on code from ActiveRecord (http://www.rubyonrails.com)
|
40
|
+
|
41
|
+
class Observer
|
42
|
+
include Singleton
|
43
|
+
|
44
|
+
# Attaches the observer to the supplied classes.
|
45
|
+
|
46
|
+
def self.observe(*classes)
|
47
|
+
for c in classes.flatten
|
48
|
+
c.meta :og_observers, self
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
data/test/nitro/tc_controller.rb
CHANGED