nitro 0.8.0 → 0.9.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (198) hide show
  1. data/AUTHORS +3 -4
  2. data/ChangeLog +418 -0
  3. data/LICENSE +1 -1
  4. data/README +157 -89
  5. data/RELEASES +50 -0
  6. data/Rakefile +5 -7
  7. data/benchmark/nitro/bench.rb +5 -0
  8. data/benchmark/nitro/simple-webrick-n-200.txt +44 -0
  9. data/benchmark/nitro/static-webrick-n-200.txt +43 -0
  10. data/benchmark/nitro/tiny-lhttpd-n-200-c-5.txt +43 -0
  11. data/benchmark/nitro/tiny-webrick-n-200-c-5.txt +44 -0
  12. data/benchmark/nitro/tiny-webrick-n-200.txt +44 -0
  13. data/benchmark/nitro/tiny2-webrick-n-200.txt +44 -0
  14. data/{lib/nitro/server/cluster.rb → bin/cluster} +26 -30
  15. data/bin/proto/README +2 -2
  16. data/bin/proto/{apache.conf → conf/apache.conf} +0 -0
  17. data/bin/proto/conf/app.conf.rb +22 -0
  18. data/bin/proto/conf/lhttpd.conf +236 -0
  19. data/bin/proto/ctl +4 -0
  20. data/bin/proto/lib/README +5 -0
  21. data/bin/proto/log/README +3 -0
  22. data/bin/proto/root/fcgi.rb +6 -0
  23. data/bin/proto/root/index.xhtml +65 -7
  24. data/bin/proto/root/m/nitro.png +0 -0
  25. data/examples/blog/README +7 -5
  26. data/examples/blog/{apache.conf → conf/apache.conf} +0 -0
  27. data/examples/blog/conf/app.conf.rb +56 -0
  28. data/examples/blog/conf/lhttpd.conf +236 -0
  29. data/examples/blog/ctl +4 -0
  30. data/examples/blog/lib/blog.rb +11 -136
  31. data/examples/blog/lib/blog/controller.rb +99 -0
  32. data/examples/blog/lib/blog/model.rb +39 -0
  33. data/examples/blog/log/README +3 -0
  34. data/examples/blog/root/comments.xhtml +2 -2
  35. data/examples/blog/root/fcgi.rb +6 -0
  36. data/examples/blog/root/index.xhtml +4 -5
  37. data/examples/blog/root/login.xhtml +2 -2
  38. data/examples/blog/root/style.xsl +9 -9
  39. data/examples/blog/root/view_entry.xhtml +2 -2
  40. data/examples/flash/conf/app.conf.rb +23 -0
  41. data/examples/flash/ctl +4 -0
  42. data/examples/flash/log/README +3 -0
  43. data/examples/flash/root/index.xhtml +0 -9
  44. data/examples/flash/root/show_inline_text.xhtml +10 -5
  45. data/examples/no_xsl_blog/README +12 -0
  46. data/examples/no_xsl_blog/conf/apache.conf +0 -0
  47. data/examples/no_xsl_blog/conf/app.conf.rb +57 -0
  48. data/examples/no_xsl_blog/conf/lhttpd.conf +236 -0
  49. data/examples/no_xsl_blog/ctl +4 -0
  50. data/examples/no_xsl_blog/lib/blog.rb +20 -0
  51. data/examples/no_xsl_blog/lib/blog/controller.rb +102 -0
  52. data/examples/no_xsl_blog/lib/blog/model.rb +39 -0
  53. data/examples/no_xsl_blog/lib/blog/template.rb +134 -0
  54. data/examples/no_xsl_blog/log/README +3 -0
  55. data/examples/no_xsl_blog/root/comments.xhtml +41 -0
  56. data/examples/no_xsl_blog/root/entry_form.xhtml +22 -0
  57. data/examples/no_xsl_blog/root/fcgi.rb +6 -0
  58. data/examples/no_xsl_blog/root/index.xhtml +39 -0
  59. data/examples/no_xsl_blog/root/login.xhtml +21 -0
  60. data/examples/no_xsl_blog/root/m/bubbles.gif +0 -0
  61. data/examples/no_xsl_blog/root/m/comments_curve.gif +0 -0
  62. data/examples/no_xsl_blog/root/m/down.gif +0 -0
  63. data/examples/no_xsl_blog/root/m/footer_bg.gif +0 -0
  64. data/examples/no_xsl_blog/root/m/garrow.gif +0 -0
  65. data/examples/no_xsl_blog/root/m/gbull.gif +0 -0
  66. data/examples/no_xsl_blog/root/m/grbull.gif +0 -0
  67. data/examples/no_xsl_blog/root/m/h1_bg.gif +0 -0
  68. data/examples/no_xsl_blog/root/m/header_bg.gif +0 -0
  69. data/examples/no_xsl_blog/root/m/nitro.gif +0 -0
  70. data/examples/no_xsl_blog/root/m/obull.gif +0 -0
  71. data/examples/no_xsl_blog/root/m/page_bg.gif +0 -0
  72. data/examples/no_xsl_blog/root/m/rss.gif +0 -0
  73. data/examples/no_xsl_blog/root/m/side_title_bg.gif +0 -0
  74. data/examples/no_xsl_blog/root/m/sidebar_bg.gif +0 -0
  75. data/examples/no_xsl_blog/root/recent_posts.xhtml +14 -0
  76. data/examples/no_xsl_blog/root/style.css +301 -0
  77. data/examples/no_xsl_blog/root/view_entry.xhtml +25 -0
  78. data/examples/no_xsl_blog/root/view_entry.xml +12 -0
  79. data/examples/og/run.rb +2 -2
  80. data/examples/tiny/README +2 -2
  81. data/examples/tiny/conf/apache.conf +5 -0
  82. data/examples/tiny/conf/app.conf.rb +21 -0
  83. data/examples/tiny/conf/lhttpd.conf +236 -0
  84. data/examples/tiny/ctl +4 -0
  85. data/examples/tiny/log/README +3 -0
  86. data/examples/tiny/root/fcgi.rb +6 -0
  87. data/examples/tiny/root/index.xhtml +7 -4
  88. data/examples/tiny/root/nitro.png +0 -0
  89. data/lib/glue.rb +13 -9
  90. data/lib/glue/array.rb +1 -1
  91. data/lib/glue/cache.rb +1 -1
  92. data/lib/glue/flexob.rb +12 -0
  93. data/lib/glue/hash.rb +1 -1
  94. data/lib/glue/inflector.rb +2 -2
  95. data/lib/glue/logger.rb +4 -8
  96. data/lib/glue/misc.rb +14 -0
  97. data/lib/glue/number.rb +1 -1
  98. data/lib/glue/object.rb +26 -0
  99. data/lib/glue/pool.rb +1 -1
  100. data/lib/glue/property.rb +84 -91
  101. data/lib/glue/string.rb +1 -1
  102. data/lib/glue/time.rb +1 -1
  103. data/lib/glue/validation.rb +1 -1
  104. data/lib/nitro.rb +18 -6
  105. data/lib/nitro/adaptors/cgi.rb +291 -0
  106. data/lib/nitro/adaptors/fastcgi.rb +42 -0
  107. data/lib/nitro/adaptors/runner.rb +123 -0
  108. data/lib/nitro/adaptors/webrick.rb +110 -0
  109. data/lib/nitro/buffering.rb +43 -0
  110. data/lib/nitro/builders/form.rb +1 -1
  111. data/lib/nitro/builders/rss.rb +1 -1
  112. data/{bin → lib/nitro}/cluster.rb +26 -30
  113. data/lib/nitro/context.rb +82 -0
  114. data/lib/nitro/controller.rb +50 -0
  115. data/lib/nitro/cookie.rb +46 -0
  116. data/lib/nitro/dispatcher.rb +105 -0
  117. data/lib/nitro/filters.rb +9 -10
  118. data/lib/nitro/localization.rb +42 -0
  119. data/lib/nitro/mail.rb +11 -14
  120. data/lib/nitro/render.rb +275 -0
  121. data/lib/nitro/request.rb +128 -0
  122. data/lib/nitro/response.rb +38 -0
  123. data/lib/nitro/scaffold.rb +11 -11
  124. data/lib/nitro/session.rb +84 -0
  125. data/lib/nitro/{server/shaders.rb → shaders.rb} +56 -36
  126. data/lib/nitro/ui/pager.rb +23 -26
  127. data/lib/nitro/{sitemap.rb → ui/sitemap.rb} +4 -12
  128. data/lib/nitro/uri.rb +1 -1
  129. data/lib/nitro/version.rb +10 -8
  130. data/lib/og.rb +66 -65
  131. data/lib/og/backend.rb +1 -1
  132. data/lib/og/backends/mysql.rb +48 -52
  133. data/lib/og/backends/psql.rb +34 -37
  134. data/lib/og/connection.rb +15 -15
  135. data/lib/og/enchant.rb +16 -9
  136. data/lib/og/meta.rb +127 -54
  137. data/lib/og/mock.rb +18 -18
  138. data/lib/og/version.rb +6 -4
  139. data/lib/parts/content.rb +4 -8
  140. data/test/glue/tc_logger.rb +3 -0
  141. data/test/glue/tc_property.rb +19 -3
  142. data/test/nitro/adaptors/tc_cgi.rb +63 -0
  143. data/test/nitro/adaptors/tc_webrick.rb +15 -0
  144. data/test/nitro/builders/tc_xml.rb +2 -2
  145. data/test/nitro/tc_context.rb +13 -0
  146. data/test/nitro/tc_controller.rb +47 -0
  147. data/test/nitro/tc_dispatcher.rb +64 -0
  148. data/test/nitro/tc_session.rb +20 -0
  149. data/test/nitro/{tc_sitemap.rb → ui/tc_sitemap.rb} +1 -1
  150. data/test/root/blog/list.xhtml +6 -0
  151. data/test/tc_og.rb +41 -4
  152. metadata +115 -59
  153. data/bin/proto/app.rb +0 -20
  154. data/bin/proto/config.rb +0 -77
  155. data/examples/blog/app.rb +0 -21
  156. data/examples/blog/config.rb +0 -95
  157. data/examples/blog/env.rb +0 -22
  158. data/examples/flash/README +0 -34
  159. data/examples/flash/app.rb +0 -20
  160. data/examples/flash/config.rb +0 -38
  161. data/examples/flash/lib/flash.rb +0 -40
  162. data/examples/flash/tmp.swf +0 -0
  163. data/examples/tiny/app.rb +0 -19
  164. data/examples/tiny/config.rb +0 -29
  165. data/examples/tiny/root/nitro-small.png +0 -0
  166. data/lib/nitro/application.rb +0 -217
  167. data/lib/nitro/config.rb +0 -128
  168. data/lib/nitro/events.rb +0 -122
  169. data/lib/nitro/html.rb +0 -151
  170. data/lib/nitro/http.rb +0 -102
  171. data/lib/nitro/l10n.rb +0 -30
  172. data/lib/nitro/server.rb +0 -59
  173. data/lib/nitro/server/appserver.rb +0 -67
  174. data/lib/nitro/server/cookie.rb +0 -87
  175. data/lib/nitro/server/dispatcher.rb +0 -62
  176. data/lib/nitro/server/filters.rb +0 -75
  177. data/lib/nitro/server/filters/autologin.rb +0 -51
  178. data/lib/nitro/server/fragment.rb +0 -70
  179. data/lib/nitro/server/handlers.rb +0 -127
  180. data/lib/nitro/server/render.rb +0 -426
  181. data/lib/nitro/server/request.rb +0 -658
  182. data/lib/nitro/server/requestpart.rb +0 -54
  183. data/lib/nitro/server/script.rb +0 -387
  184. data/lib/nitro/server/server.rb +0 -57
  185. data/lib/nitro/server/session.rb +0 -220
  186. data/lib/nitro/server/user.rb +0 -46
  187. data/lib/nitro/server/webrick.rb +0 -180
  188. data/lib/nitro/service.rb +0 -26
  189. data/lib/xsl/ui.xsl +0 -51
  190. data/lib/xsl/xforms.xsl +0 -28
  191. data/test/nitro/server/tc_cookie.rb +0 -34
  192. data/test/nitro/server/tc_filters.rb +0 -38
  193. data/test/nitro/server/tc_request.rb +0 -70
  194. data/test/nitro/server/tc_requestpart.rb +0 -28
  195. data/test/nitro/server/tc_session.rb +0 -34
  196. data/test/nitro/tc_events.rb +0 -44
  197. data/test/nitro/tc_html.rb +0 -79
  198. data/test/nitro/tc_http.rb +0 -18
@@ -1,17 +1,15 @@
1
- # code:
2
- # * George Moschovitis <gm@navel.gr>
3
- #
4
- # (c) 2004 Navel, all rights reserved.
5
- # $Id: connection.rb 167 2004-11-23 14:03:10Z gmosx $
1
+ #--
2
+ # George Moschovitis <gm@navel.gr>
3
+ # (c) 2004-2005 Navel, all rights reserved.
4
+ # $Id: connection.rb 248 2005-01-31 13:38:34Z gmosx $
5
+ #++
6
6
 
7
7
  class Og;
8
8
 
9
- require "glue/property"
10
- require "glue/array"
11
- require "glue/time"
9
+ require 'glue/property'
10
+ require 'glue/array'
11
+ require 'glue/time'
12
12
 
13
- # = Connection
14
- #
15
13
  # A Connection to the Database. This file defines the skeleton
16
14
  # functionality. A backend specific implementation file (driver)
17
15
  # implements all methods.
@@ -20,20 +18,23 @@ require "glue/time"
20
18
  #
21
19
  # - support caching.
22
20
  # - support prepared statements.
23
- #
21
+
24
22
  class Connection
25
23
  # The frontend (Og) contains useful strucutres.
24
+
26
25
  attr_reader :og
27
26
 
28
27
  # The backend
28
+
29
29
  attr_reader :db
30
30
 
31
31
  # If set to true, the select methods deserialize the
32
32
  # resultset to create entities.
33
+
33
34
  attr_accessor :deserialize
34
35
 
35
36
  # Initialize a connection to the database
36
- #
37
+
37
38
  def initialize(og)
38
39
  @og = og
39
40
  @db = @og.config[:backend].new(@og.config)
@@ -189,9 +190,8 @@ class Connection
189
190
  # TODO: implement this as stored procedure? naaah.
190
191
  transaction do |tx|
191
192
  tx.exec "DELETE FROM #{klass::DBTABLE} WHERE oid=#{oid}"
192
-
193
- if cascade and klass.respond_to?(:og_descendants)
194
- klass.og_descendants.each do |dclass, linkback|
193
+ if cascade and klass.__meta.include?(:has)
194
+ klass.__meta[:has].each do |dclass, linkback|
195
195
  tx.exec "DELETE FROM #{dclass::DBTABLE} WHERE #{linkback}=#{oid}"
196
196
  end
197
197
  end
@@ -1,20 +1,18 @@
1
- # code:
2
1
  # * George Moschovitis <gm@navel.gr>
3
- #
4
- # (c) 2004 Navel, all rights reserved.
2
+ # (c) 2004-2005 Navel, all rights reserved.
5
3
  # $Id: meta.rb 198 2004-12-22 11:26:59Z gmosx $
6
4
 
7
5
  class Og
8
6
 
9
7
  module Enchant
10
8
 
11
- # Enchant a managed class. Add useful DB related methods to the
12
- # class and its instances.
13
- #
9
+ # Enchant a managed class. Add useful DB related methods
10
+ # to the class and its instances.
11
+
14
12
  def enchant(klass)
15
13
  klass.module_eval <<-"end_eval", __FILE__, __LINE__
16
- def self.create(*params)
17
- obj = #{klass}.new(*params)
14
+ def self.create(*params, &block)
15
+ obj = #{klass}.new(*params, &block)
18
16
  obj.save!
19
17
  end
20
18
 
@@ -26,6 +24,10 @@ module Enchant
26
24
  Og.db.load(oid_or_name, #{klass})
27
25
  end
28
26
 
27
+ def self.get(oid_or_name)
28
+ Og.db.load(oid_or_name, #{klass})
29
+ end
30
+
29
31
  def self.[](oid_or_name)
30
32
  Og.db.load(oid_or_name, #{klass})
31
33
  end
@@ -57,6 +59,11 @@ module Enchant
57
59
  def self.delete(obj_or_oid)
58
60
  Og.db.delete(obj_or_oid, #{klass})
59
61
  end
62
+
63
+ def each(&block)
64
+ all.each(&block)
65
+ end
66
+ include Enumerable
60
67
 
61
68
  def save
62
69
  Og.db << self
@@ -77,4 +84,4 @@ module Enchant
77
84
 
78
85
  end
79
86
 
80
- end # namespace
87
+ end
@@ -1,8 +1,6 @@
1
- # code:
2
1
  # * George Moschovitis <gm@navel.gr>
3
- #
4
- # (c) 2004 Navel, all rights reserved.
5
- # $Id: meta.rb 198 2004-12-22 11:26:59Z gmosx $
2
+ # (c) 2004-2005 Navel, all rights reserved.
3
+ # $Id: meta.rb 248 2005-01-31 13:38:34Z gmosx $
6
4
 
7
5
  require 'og/backend'
8
6
  require 'glue/inflector'
@@ -12,18 +10,42 @@ class Og
12
10
  # = MetaUtils
13
11
  #
14
12
  # Some useful meta-language utilities.
15
- #
13
+
16
14
  module MetaUtils # :nodoc: all
17
15
 
18
- # Conver the klass to a string representation
16
+ # Convert the klass to a string representation
19
17
  # The leading module if available is removed.
20
18
  #--
21
19
  # gmosx, FIXME: unify with the ogutils.encode method?
22
20
  #++
21
+
23
22
  def self.expand(klass)
24
23
  return klass.name.gsub(/^.*::/, '').gsub(/::/, '_').downcase
25
24
  end
26
25
 
26
+ # Infer the target klass for a relation. When defining
27
+ # relations, tha target class is typically given. Some times
28
+ # in order to avoid forward declarations a symbol is given instead
29
+ # of a class. Other times on class is given at all, and
30
+ # the inflection mechanism is used to infer the class name.
31
+
32
+ def self.resolve_class(name, klass)
33
+ klass ||= N::Inflector.camelize(name)
34
+
35
+ return klass if klass.is_a?(Class)
36
+
37
+ unless klass.is_a?(String) or klass.is_a?(Symbol)
38
+ raise 'Invalid class definition'
39
+ end
40
+
41
+ unless Object.const_get(klass.intern)
42
+ # Forward declaration.
43
+ Object.class_eval("class #{klass}; end")
44
+ end
45
+
46
+ return Object.const_get(klass)
47
+ end
48
+
27
49
  end
28
50
 
29
51
  # = MetaLanguage
@@ -33,11 +55,12 @@ end
33
55
  # from the excellent ActiveRecord library.
34
56
  #
35
57
  # Many more useful relations will be available soon.
36
- #
58
+
37
59
  module MetaLanguage
38
60
 
39
- # Defines an SQL index.
40
- #
61
+ # Defines an SQL index. Useful for defining indiced
62
+ # over multiple columns.
63
+
41
64
  def sql_index(index, options = {})
42
65
  meta :sql_index, [index, options]
43
66
  end
@@ -56,12 +79,14 @@ module MetaLanguage
56
79
  # prop_accessor Fixnum, :parent_oid
57
80
  # def parent; ... end
58
81
  # def parent=(obj_or_oid); ... end
59
- #
82
+
60
83
  def belongs_to(name, klass, options = {})
61
84
  prop_eval = "prop_accessor Fixnum, :#{name}_oid"
62
85
  prop_eval << ", :sql => '#{options[:sql]}'" if options[:sql]
63
86
  prop_eval << ", :extra_sql => '#{options[:extra_sql]}'" if options[:extra_sql]
64
87
 
88
+ meta :belongs_to, klass
89
+
65
90
  module_eval %{
66
91
  #{prop_eval}
67
92
 
@@ -81,31 +106,31 @@ module MetaLanguage
81
106
  # Example:
82
107
  #
83
108
  # class MyObject
84
- # has_one AnotherObject
109
+ # has_one :child, TheClass
110
+ # has_one :article
85
111
  # end
86
112
  #
87
113
  # creates the code:
88
114
  #
89
115
  # ...
90
- #
91
- def has_one(name, klass, options = {})
116
+
117
+ def has_one(name, klass = nil, options = {})
118
+
92
119
  # linkback is the property of the child object that 'links back'
93
120
  # to this object.
121
+
94
122
  linkback = options[:linkback] || "#{MetaUtils.expand(self)}_oid"
95
123
 
124
+ meta :has, [klass, linkback]
125
+
96
126
  module_eval %{
97
- @@og_descendants ||= {}
98
- @@og_descendants[#{klass}] = :#{linkback}
99
-
100
- unless defined?(og_descendants)
101
- def self.og_descendants
102
- @@og_descendants
103
- end
104
- end
105
-
106
127
  def #{name}(extrasql = nil)
107
- Og.db.select_one("SELECT * FROM #{Og::Backend.table(klass)} WHERE #{linkback}=\#\@oid \#\{extrasql\}", #{klass})
128
+ Og.db.select_one("SELECT * FROM #{Backend.table(klass)} WHERE #{linkback}=\#\@oid \#\{extrasql\}", #{klass})
108
129
  end
130
+
131
+ def delete_#{name}(extrasql = nil)
132
+ Og.db.exec("DELETE FROM #{Backend.table(klass)} WHERE #{linkback}=\#\@oid \#\{extrasql\}")
133
+ end
109
134
  }
110
135
  end
111
136
 
@@ -121,36 +146,37 @@ module MetaLanguage
121
146
  # creates the code:
122
147
  #
123
148
  # def children; ... end
124
- #
149
+
125
150
  def has_many(name, klass, options = {})
126
151
  name_s = N::Inflector.singularize(name.to_s)
127
152
 
128
153
  # linkback is the property of the child object that 'links back'
129
154
  # to this object.
155
+
130
156
  linkback = options[:linkback] || "#{MetaUtils.expand(self)}_oid"
131
157
 
158
+ # keep belongs to metadata, useful for
159
+ # reflection/scaffolding.
160
+
161
+ meta :has, [klass, linkback]
162
+
132
163
  module_eval %{
133
- @@og_descendants ||= {}
134
- @@og_descendants[#{klass}] = :#{linkback}
135
-
136
- unless defined?(og_descendants)
137
- def self.og_descendants
138
- @@og_descendants
139
- end
140
- end
141
-
142
164
  def #{name}(extrasql = nil)
143
- Og.db.select("SELECT * FROM #{Og::Backend.table(klass)} WHERE #{linkback}=\#\@oid \#\{extrasql\}", #{klass})
165
+ Og.db.select("SELECT * FROM #{Backend.table(klass)} WHERE #{linkback}=\#\@oid \#\{extrasql\}", #{klass})
144
166
  end
145
167
 
146
168
  def #{name}_count(extrasql = nil)
147
- Og.db.count("SELECT COUNT(*) FROM #{Og::Backend.table(klass)} WHERE #{linkback}=\#\@oid \#\{extrasql\}")
169
+ Og.db.count("SELECT COUNT(*) FROM #{Backend.table(klass)} WHERE #{linkback}=\#\@oid \#\{extrasql\}")
148
170
  end
149
171
 
150
172
  def add_#{name_s}(obj, extra = nil)
151
173
  obj.#{linkback} = @oid
152
174
  obj.save!
153
175
  end
176
+
177
+ def delete_all_#{name}(extrasql = nil)
178
+ Og.db.exec("DELETE FROM #{Backend.table(klass)} WHERE #{linkback}=\#\@oid \#\{extrasql\}")
179
+ end
154
180
  }
155
181
  end
156
182
 
@@ -173,10 +199,10 @@ module MetaLanguage
173
199
  #
174
200
  # category.articles
175
201
  # ...
176
- #
177
202
  #--
178
203
  # FIXME: make more compatible with other enchant methods.
179
204
  #++
205
+
180
206
  def many_to_many(name, klass, options = {})
181
207
  list_o = name.to_s
182
208
  prop_o = N::Inflector.singularize(list_o)
@@ -185,36 +211,38 @@ module MetaLanguage
185
211
 
186
212
  # exit if the class is allready indirectly 'enchanted' from the
187
213
  # other class of the many_to_many relation.
214
+
188
215
  return if self.respond_to?(prop_m)
189
216
 
190
217
  # Add some metadata to the class to allow for automatic join table
191
218
  # calculation.
219
+
192
220
  meta :sql_join, [klass, options]
193
221
 
194
- # gmosx, FIXME: should I update descendants here ?
222
+ meta :many_to_many, klass
223
+ klass.meta :many_to_many, self
195
224
 
196
225
  # enchant this class
197
226
 
198
227
  module_eval %{
199
228
  def #{list_o}(extrasql = nil)
200
- Og.db.select("SELECT d.* FROM #{Og::Backend.table(klass)} AS d, #{Og::Backend.join_table(self, klass)} AS j WHERE j.key1=\#\@oid AND j.key2=d.oid \#\{extrasql\}", #{klass})
229
+ Og.db.select("SELECT d.* FROM #{Backend.table(klass)} AS d, #{Backend.join_table(self, klass)} AS j WHERE j.key1=\#\@oid AND j.key2=d.oid \#\{extrasql\}", #{klass})
201
230
  end
202
231
 
203
232
  def #{list_o}_count(extrasql = nil)
204
- Og.db.select("SELECT COUNT(*) FROM #{Og::Backend.table(klass)} AS d, #{Og::Backend.join_table(self, klass)} AS j WHERE j.key1=\#\@oid AND j.key2=d.oid \#\{extrasql\}", #{klass})
233
+ Og.db.select("SELECT COUNT(*) FROM #{Backend.table(klass)} AS d, #{Backend.join_table(self, klass)} AS j WHERE j.key1=\#\@oid AND j.key2=d.oid \#\{extrasql\}", #{klass})
205
234
  end
206
235
 
207
236
  def add_#{prop_o}(obj, extra = nil)
208
- Og.db.exec("INSERT INTO #{Og::Backend.join_table(self, klass)} (key1, key2) VALUES (\#\@oid, \#\{obj.oid\})")
237
+ Og.db.exec("INSERT INTO #{Backend.join_table(self, klass)} (key1, key2) VALUES (\#\@oid, \#\{obj.oid\})")
209
238
  end
210
239
 
211
- def del_#{prop_o}(obj_or_oid, extra = nil)
212
- Og.db.exec("DELETE FROM #{Og::Backend.join_table(self, klass)} WHERE key2=\#\{obj_or_oid.to_i\}")
240
+ def delete_#{prop_o}(obj_or_oid, extra = nil)
241
+ Og.db.exec("DELETE FROM #{Backend.join_table(self, klass)} WHERE key2=\#\{obj_or_oid.to_i\}")
213
242
  end
214
- alias_method :delete_#{prop_o}, :del_#{prop_o}
215
243
 
216
244
  def clear_#{list_o}
217
- Og.db.exec("DELETE FROM #{Og::Backend.join_table(self, klass)} WHERE key1=\#\@oid")
245
+ Og.db.exec("DELETE FROM #{Backend.join_table(self, klass)} WHERE key1=\#\@oid")
218
246
  end
219
247
  }
220
248
 
@@ -222,40 +250,85 @@ module MetaLanguage
222
250
 
223
251
  klass.module_eval %{
224
252
  def #{list_m}(extrasql = nil)
225
- Og.db.select("SELECT s.* FROM #{Og::Backend.table(self)} AS s, #{Og::Backend.join_table(self, klass)} AS j WHERE j.key2=\#\@oid AND j.key1=s.oid \#\{extrasql\}", #{self})
253
+ Og.db.select("SELECT s.* FROM #{Backend.table(self)} AS s, #{Backend.join_table(self, klass)} AS j WHERE j.key2=\#\@oid AND j.key1=s.oid \#\{extrasql\}", #{self})
226
254
  end
227
255
 
228
256
  def #{list_m}_count(extrasql = nil)
229
- Og.db.select("SELECT COUNT(*) FROM #{Og::Backend.table(self)} AS s, #{Og::Backend.join_table(self, klass)} AS j WHERE j.key2=\#\@oid AND j.key1=s.oid \#\{extrasql\}", #{self})
257
+ Og.db.select("SELECT COUNT(*) FROM #{Backend.table(self)} AS s, #{Backend.join_table(self, klass)} AS j WHERE j.key2=\#\@oid AND j.key1=s.oid \#\{extrasql\}", #{self})
230
258
  end
231
259
 
232
260
  def add_#{prop_m}(obj, extra = nil)
233
- Og.db.exec("INSERT INTO #{Og::Backend.join_table(self, klass)} (key1, key2) VALUES (\#\{obj.oid\}, \#\@oid)")
261
+ Og.db.exec("INSERT INTO #{Backend.join_table(self, klass)} (key1, key2) VALUES (\#\{obj.oid\}, \#\@oid)")
234
262
  end
235
263
 
236
- def del_#{prop_m}(obj_or_oid, extra = nil)
237
- Og.db.exec("DELETE FROM #{Og::Backend.join_table(self, klass)} WHERE key1=\#\{obj_or_oid.to_i\}")
264
+ def delete_#{prop_m}(obj_or_oid, extra = nil)
265
+ Og.db.exec("DELETE FROM #{Backend.join_table(self, klass)} WHERE key1=\#\{obj_or_oid.to_i\}")
238
266
  end
239
- alias_method :delete_#{prop_m}, :del_#{prop_m}
240
267
 
241
268
  def clear_#{list_m}
242
- Og.db.exec("DELETE FROM #{Og::Backend.join_table(self, klass)} WHERE key2=\#\@oid")
269
+ Og.db.exec("DELETE FROM #{Backend.join_table(self, klass)} WHERE key2=\#\@oid")
243
270
  end
244
271
  }
245
272
  end
246
273
  alias :has_and_belongs_to_many :many_to_many
247
274
 
275
+ # Implements a 'refers_to' relation.
276
+ # This is a one-way version of the 'has_one'/'belongs_to'
277
+ # relations. The target object cannot link back to the source
278
+ # object.
279
+ # This is in fact EXACTLY the same as belongs_to with a
280
+ # different name (!!!!)
281
+ #
282
+ # Automatically enchants the calling class with helper methods.
283
+ #
284
+ #
285
+ # Example:
286
+ #
287
+ # class MyObject
288
+ # refers_to article, Article
289
+ # end
290
+ #
291
+ # creates the code:
292
+ #
293
+ # prop_accessor Fixnum, :article_oid
294
+ # def article; ... end
295
+ # def article=(obj_or_oid); ... end
296
+
297
+ def refers_to(name, klass, options = {})
298
+ prop_eval = "prop_accessor Fixnum, :#{name}_oid"
299
+ prop_eval << ", :sql => '#{options[:sql]}'" if options[:sql]
300
+ prop_eval << ", :extra_sql => '#{options[:extra_sql]}'" if options[:extra_sql]
301
+
302
+ meta :refers_to, klass
303
+ klass.meta :has, [self, "#{name}_oid"]
304
+
305
+ module_eval %{
306
+ #{prop_eval}
307
+
308
+ def #{name}
309
+ Og.db.load_by_oid(@#{name}_oid, #{klass})
310
+ end
311
+
312
+ def #{name}=(obj_or_oid)
313
+ @#{name}_oid = obj_or_oid.to_i
314
+ end
315
+ }
316
+ end
317
+
248
318
  end
249
319
 
250
- end # namespace
320
+ end
251
321
 
252
322
  # Include the meta-language extensions into Module. If the flag is
253
323
  # false the developer is responsible for including the MetaLanguage
254
324
  # module where needed.
255
- #
325
+ #
326
+ # By default this is FALSE, to avoid polution of the Module object.
327
+ # However if you include a prop_accessor or a managed Mixin in your
328
+ # object MetaLanguage gets automatically extended in the class.
329
+
256
330
  if Og.include_meta_language
257
331
  class Module # :nodoc: all
258
332
  include Og::MetaLanguage
259
333
  end
260
334
  end
261
-