nitro 0.5.0 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. data/ChangeLog +4 -2201
  2. data/ChangeLog.1 +2344 -0
  3. data/README +4 -4
  4. data/RELEASES +22 -0
  5. data/bin/new_app.rb +17 -3
  6. data/bin/proto/README +34 -0
  7. data/bin/proto/apache.conf +1 -0
  8. data/bin/proto/app.rb +20 -0
  9. data/bin/proto/config.rb +77 -0
  10. data/bin/proto/root/index.xhtml +43 -0
  11. data/bin/proto/root/style.css +218 -0
  12. data/bin/proto/root/style.xsl +130 -0
  13. data/examples/blog/app.rb +1 -2
  14. data/examples/blog/config.rb +20 -18
  15. data/examples/blog/env.rb +22 -0
  16. data/examples/blog/lib/blog.rb +43 -15
  17. data/examples/blog/root/entry_form.xhtml +1 -1
  18. data/examples/blog/root/index.xhtml +5 -0
  19. data/examples/blog/root/login.xhtml +2 -0
  20. data/examples/blog/root/m/nitro.gif +0 -0
  21. data/examples/blog/root/style.css +83 -0
  22. data/examples/blog/root/style.xsl +7 -3
  23. data/examples/og/run.rb +41 -2
  24. data/examples/tiny/app.rb +1 -2
  25. data/examples/tiny/root/index.xhtml +8 -2
  26. data/examples/tiny/root/nitro-small.png +0 -0
  27. data/lib/glue.rb +1 -1
  28. data/lib/glue/property.rb +9 -3
  29. data/lib/nitro/application.rb +18 -1
  30. data/lib/nitro/builders/form.rb +84 -0
  31. data/lib/nitro/builders/rss.rb +4 -5
  32. data/lib/nitro/builders/table.rb +23 -0
  33. data/lib/nitro/filters.rb +157 -0
  34. data/lib/nitro/l10n.rb +11 -3
  35. data/lib/nitro/scaffold.rb +1 -1
  36. data/lib/nitro/server/render.rb +101 -4
  37. data/lib/nitro/server/shaders.rb +17 -5
  38. data/lib/nitro/service.rb +5 -5
  39. data/lib/nitro/ui/pager.rb +35 -11
  40. data/lib/nitro/version.rb +2 -2
  41. data/lib/og.rb +25 -17
  42. data/lib/og/backend.rb +15 -3
  43. data/lib/og/backends/mysql.rb +30 -3
  44. data/lib/og/backends/psql.rb +44 -3
  45. data/lib/og/meta.rb +117 -10
  46. data/lib/og/version.rb +1 -1
  47. data/lib/xsl/base.xsl +75 -6
  48. data/lib/xsl/ui.xsl +51 -0
  49. data/test/nitro/ui/tc_pager.rb +6 -0
  50. metadata +23 -2
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 155 2004-11-13 20:32:12Z gmosx $
5
+ # $Id: backend.rb 185 2004-12-10 13:29:09Z gmosx $
6
6
 
7
7
  require "yaml"
8
8
 
@@ -16,15 +16,27 @@ module Og
16
16
  #
17
17
  module Utils
18
18
 
19
- # The name of the SQL table where objects of this class are stored.
19
+ # Encode the name of the klass as an sql safe string.
20
20
  # The Module separators are replaced with _ and NOT stripped out so
21
21
  # that we can convert back to the original notation if needed.
22
22
  # The leading module if available is removed.
23
23
  #
24
+ def self.encode(klass)
25
+ "#{klass.name.gsub(/^.*::/, "")}".gsub(/::/, "_").downcase
26
+ end
27
+
28
+ # The name of the SQL table where objects of this class are stored.
29
+ #
24
30
  def self.table(klass)
25
- return "_#{klass.name.gsub(/^.*::/, "")}".gsub(/::/, "_").downcase
31
+ "_#{encode(klass)}"
26
32
  end
27
33
 
34
+ # The name of the join table for the two given classes.
35
+ #
36
+ def self.join_table(klass1, klass2)
37
+ "_j_#{Og::Utils.encode(klass1)}_#{Og::Utils.encode(klass2)}"
38
+ end
39
+
28
40
  # Returns the props that will be included in the insert query.
29
41
  # For some backends the oid should be stripped.
30
42
  #
@@ -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 159 2004-11-18 10:18:30Z gmosx $
6
+ # $Id: mysql.rb 185 2004-12-10 13:29:09Z gmosx $
7
7
 
8
8
  require "mysql"
9
9
 
@@ -302,14 +302,41 @@ class MysqlBackend < Og::Backend
302
302
 
303
303
  # Create indices
304
304
 
305
- if klass.__meta
306
- for data in klass.__meta[:sql_index]
305
+ if klass.__meta and indices = klass.__meta[:sql_index]
306
+ for data in indices
307
307
  idx, options = *data
308
308
  idx = idx.to_s
309
309
  pre_sql, post_sql = options[:pre], options[:post]
310
310
  idxname = idx.gsub(/ /, "").gsub(/,/, "_").gsub(/\(.*\)/, "")
311
311
  exec "CREATE #{pre_sql} INDEX #{klass::DBTABLE}_#{idxname}_idx #{post_sql} ON #{klass::DBTABLE} (#{idx})"
312
312
  end
313
+ end
314
+
315
+ # Create join tables if needed. Join tables are used in
316
+ # 'many_to_many' relations.
317
+
318
+ if klass.__meta and joins = klass.__meta[:sql_join]
319
+ for data in joins
320
+ # the class to join to and some options.
321
+ join_class, options = *data
322
+
323
+ # gmosx: dont use DBTABLE here, perhaps the join class
324
+ # is not managed yet.
325
+ join_table = "#{Og::Utils.join_table(klass, join_class)}"
326
+ join_src = "#{Og::Utils.encode(klass)}_oid"
327
+ join_dst = "#{Og::Utils.encode(join_class)}_oid"
328
+ begin
329
+ exec "CREATE TABLE #{join_table} ( key1 integer, key2 integer )"
330
+ exec "CREATE INDEX #{join_table}_key1_idx ON #{join_table} (key1)"
331
+ exec "CREATE INDEX #{join_table}_key2_idx ON #{join_table} (key2)"
332
+ rescue => ex
333
+ if ex.errno == 1050 # table already exists.
334
+ $log.debug "Join table already exists" if $DBG
335
+ else
336
+ raise
337
+ end
338
+ end
339
+ end
313
340
  end
314
341
  end
315
342
 
@@ -2,7 +2,7 @@
2
2
  # * George Moschovitis <gm@navel.gr>
3
3
  #
4
4
  # (c) 2004 Navel, all rights reserved.
5
- # $Id: psql.rb 159 2004-11-18 10:18:30Z gmosx $
5
+ # $Id: psql.rb 185 2004-12-10 13:29:09Z gmosx $
6
6
 
7
7
  require "postgres"
8
8
 
@@ -268,8 +268,8 @@ class PsqlBackend < Og::Backend
268
268
 
269
269
  # Create indices
270
270
 
271
- if klass.__meta
272
- for data in klass.__meta[:sql_index]
271
+ if klass.__meta and indices = klass.__meta[:sql_index]
272
+ for data in indices
273
273
  idx, options = *data
274
274
  idx = idx.to_s
275
275
  pre_sql, post_sql = options[:pre], options[:post]
@@ -304,6 +304,47 @@ class PsqlBackend < Og::Backend
304
304
  raise
305
305
  end
306
306
  end
307
+
308
+ # Create join tables if needed. Join tables are used in
309
+ # 'many_to_many' relations.
310
+
311
+ if klass.__meta and joins = klass.__meta[:sql_join]
312
+ for data in joins
313
+ # the class to join to and some options.
314
+ join_class, options = *data
315
+
316
+ # gmosx: dont use DBTABLE here, perhaps the join class
317
+ # is not managed yet.
318
+ join_table = "#{Og::Utils.join_table(klass, join_class)}"
319
+ join_src = "#{Og::Utils.encode(klass)}_oid"
320
+ join_dst = "#{Og::Utils.encode(join_class)}_oid"
321
+ begin
322
+ exec "CREATE TABLE #{join_table} ( key1 integer, key2 integer )"
323
+ exec "CREATE INDEX #{join_table}_key1_idx ON #{join_table} (key1)"
324
+ exec "CREATE INDEX #{join_table}_key2_idx ON #{join_table} (key2)"
325
+ rescue => ex
326
+ # gmosx: any idea how to better test this?
327
+ if ex.to_s =~ /relation .* already exists/i
328
+ $log.debug "Join table already exists" if $DBG
329
+ else
330
+ raise
331
+ end
332
+ end
333
+ end
334
+ end
335
+
336
+ begin
337
+ exec(sql)
338
+ $log.info "Created join table '#{join_table}'."
339
+ rescue => ex
340
+ # gmosx: any idea how to better test this?
341
+ if ex.to_s =~ /relation .* already exists/i
342
+ $log.debug "Join table already exists" if $DBG
343
+ else
344
+ raise
345
+ end
346
+ end
347
+
307
348
  end
308
349
 
309
350
  # Drop the managed object table
data/lib/og/meta.rb CHANGED
@@ -2,9 +2,10 @@
2
2
  # * George Moschovitis <gm@navel.gr>
3
3
  #
4
4
  # (c) 2004 Navel, all rights reserved.
5
- # $Id: meta.rb 159 2004-11-18 10:18:30Z gmosx $
5
+ # $Id: meta.rb 185 2004-12-10 13:29:09Z gmosx $
6
6
 
7
7
  require 'og/backend'
8
+ require 'glue/inflector'
8
9
 
9
10
  module Og
10
11
 
@@ -68,15 +69,13 @@ module MetaLanguage
68
69
  }
69
70
  end
70
71
 
71
- # Implements a 'has_many' relation.
72
+ # Implements a 'has_one' relation.
72
73
  # Automatically enchants the calling class with helper methods.
73
74
  #
74
- # NOT IMPLEMENTED.
75
- #
76
75
  # Example:
77
76
  #
78
77
  # class MyObject
79
- # has_many AnotherObject, :children
78
+ # has_one :children, AnotherObject
80
79
  # end
81
80
  #
82
81
  # creates the code:
@@ -84,10 +83,23 @@ module MetaLanguage
84
83
  # def children; ... end
85
84
  #
86
85
  def has_one(klass, name, options = {})
86
+ # linkback is the property of the child object that 'links back'
87
+ # to this object.
88
+ linkback = options[:linkback] || "#{MetaUtils.expand(self)}_oid"
89
+
87
90
  module_eval %{
91
+ @@og_descendants ||= {}
92
+ @@og_descendants[#{klass}] = :#{linkback}
93
+
94
+ unless defined?(og_descendants)
95
+ def self.og_descendants
96
+ @@og_descendants
97
+ end
98
+ end
99
+
88
100
  def #{name}(extrasql = nil)
89
- $og.select_one("article_oid=\#\@oid \#\{extrasql\}", #{klass})
90
- end
101
+ $og.select_one("SELECT * FROM #{Utils.table(klass)} WHERE #{linkback}=\#\@oid \#\{extrasql\}", #{klass})
102
+ end
91
103
  }
92
104
  end
93
105
 
@@ -97,7 +109,7 @@ module MetaLanguage
97
109
  # Example:
98
110
  #
99
111
  # class MyObject
100
- # has_many AnotherObject, :children
112
+ # has_many :children, AnotherObject
101
113
  # end
102
114
  #
103
115
  # creates the code:
@@ -129,11 +141,106 @@ module MetaLanguage
129
141
  }
130
142
  end
131
143
 
144
+ # Implements a 'many_to_many' relation.
145
+ # Two objects are associated using an intermediate join table.
146
+ # Automatically enchants the calling class with helper methods.
147
+ #
148
+ # Example:
149
+ #
150
+ # class Article
151
+ # many_to_many :children, Categories
152
+ # end
153
+ #
154
+ # article.categories
155
+ # article.del_category
156
+ # article.add_category
157
+ # article.clear_categories
158
+ #
159
+ # category.articles
160
+ # ...
161
+ #
162
+ #--
163
+ # FIXME: make more compatible with other enchant methods.
164
+ #++
165
+ def many_to_many(klass, options = {})
166
+ name1 = options[:name1] || G::Inflector.name(self)
167
+ pname1 = options[:list_name1] || G::Inflector.plural_name(self)
168
+ name2 = options[:name2] || G::Inflector.name(klass)
169
+ pname2 = options[:list_name2] || G::Inflector.plural_name(klass)
170
+
171
+ # exit if the class is allready indirectly 'enchanted' from the
172
+ # other class of the many_to_many relation.
173
+ return if self.respond_to?(name1)
174
+
175
+ # Add some metadata to the class to allow for automatic join table
176
+ # calculation.
177
+ meta :sql_join, [klass, options]
178
+
179
+ # gmosx, FIXME: should I update descendants here ?
180
+
181
+ # enchant this class
182
+
183
+ module_eval %{
184
+ def #{pname2}(extrasql = nil)
185
+ $og.select("SELECT d.* FROM #{Utils.table(klass)} AS d, #{Utils.join_table(self, klass)} AS j WHERE j.key1=\#\@oid AND j.key2=d.oid \#\{extrasql\}", #{klass})
186
+ end
187
+
188
+ def #{pname2}_count(extrasql = nil)
189
+ $og.select("SELECT COUNT(*) FROM #{Utils.table(klass)} AS d, #{Utils.join_table(self, klass)} AS j WHERE j.key1=\#\@oid AND j.key2=d.oid \#\{extrasql\}", #{klass})
190
+ end
191
+
192
+ def add_#{name2}(obj, extra = nil)
193
+ $og.exec("INSERT INTO #{Utils.join_table(self, klass)} (key1, key2) VALUES (\#\@oid, \#\{obj.oid\})")
194
+ end
195
+
196
+ def del_#{name2}(obj_or_oid, extra = nil)
197
+ $og.exec("DELETE FROM #{Utils.join_table(self, klass)} WHERE key2=\#\{obj_or_oid.to_i\}")
198
+ end
199
+ alias_method :delete_#{name2}, :del_#{name2}
200
+
201
+ def clear_#{pname2}
202
+ $og.exec("DELETE FROM #{Utils.join_table(self, klass)} WHERE key1=\#\@oid")
203
+ end
204
+ }
205
+
206
+ # indirectly enchant the other class of the relation.
207
+
208
+ klass.module_eval %{
209
+ def #{pname1}(extrasql = nil)
210
+ $og.select("SELECT s.* FROM #{Utils.table(self)} AS s, #{Utils.join_table(self, klass)} AS j WHERE j.key2=\#\@oid AND j.key1=s.oid \#\{extrasql\}", #{self})
211
+ end
212
+
213
+ def #{pname1}_count(extrasql = nil)
214
+ $og.select("SELECT COUNT(*) FROM #{Utils.table(self)} AS s, #{Utils.join_table(self, klass)} AS j WHERE j.key2=\#\@oid AND j.key1=s.oid \#\{extrasql\}", #{self})
215
+ end
216
+
217
+ def add_#{name1}(obj, extra = nil)
218
+ $og.exec("INSERT INTO #{Utils.join_table(self, klass)} (key1, key2) VALUES (\#\{obj.oid\}, \#\@oid)")
219
+ end
220
+
221
+ def del_#{name1}(obj_or_oid, extra = nil)
222
+ $og.exec("DELETE FROM #{Utils.join_table(self, klass)} WHERE key1=\#\{obj_or_oid.to_i\}")
223
+ end
224
+ alias_method :delete_#{name1}, :del_#{name1}
225
+
226
+ def clear_#{pname1}
227
+ $og.exec("DELETE FROM #{Utils.join_table(self, klass)} WHERE key2=\#\@oid")
228
+ end
229
+ }
230
+ end
231
+ alias :has_and_belongs_to_many :many_to_many
232
+
132
233
  end
133
234
 
134
235
  end # module
135
236
 
136
- class Module # :nodoc: all
137
- include Og::MetaLanguage
237
+ # Include the meta-language extensions into Module. If the flag is
238
+ # false the developer is responsible for including the MetaLanguage
239
+ # module where needed.
240
+ #
241
+ if $og_include_meta_language
242
+ class Module # :nodoc: all
243
+ include Og::MetaLanguage
244
+ end
138
245
  end
139
246
 
data/lib/og/version.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$
5
+ # $Id: version.rb 175 2004-11-26 16:11:27Z gmosx $
6
6
 
7
7
  # The version of Og.
8
8
  $og_version = '0.5.0'
data/lib/xsl/base.xsl CHANGED
@@ -54,19 +54,28 @@ author: gmosx
54
54
  <xsl:apply-templates/>
55
55
  </xsl:template>
56
56
 
57
- <!-- create a new, nested output buffer NOT WORKING -->
57
+ <!-- create a new, nested output buffer -->
58
58
  <xsl:template name="x:ob-start" match="x:ob-start">
59
59
  <ruby>
60
- <![CDATA[__out_buffers = [] unless __out_buffers
61
- __out_buffers.push(__out)
62
- __out = ""]]>
60
+ @out_buffers = [] unless @out_buffers
61
+ @out_buffers.push(@out)
62
+ @out = ""
63
63
  </ruby>
64
64
  </xsl:template>
65
65
 
66
- <!-- close a nested output buffer NOT WORKING -->
66
+ <!-- close a nested output buffer -->
67
67
  <xsl:template name="x:ob-end" match="x:ob-end">
68
68
  <ruby>
69
- <![CDATA[__out == __out_buffers.pop()]]>
69
+ @out = @out_buffers.pop()
70
+ </ruby>
71
+ </xsl:template>
72
+
73
+ <!-- close a nested output buffer and write to the parent buffer -->
74
+ <xsl:template name="x:ob-write-end" match="x:ob-write-end">
75
+ <ruby>
76
+ __nested_buffer = @out
77
+ @out = @out_buffers.pop()
78
+ @out += __nested_buffer
70
79
  </ruby>
71
80
  </xsl:template>
72
81
 
@@ -135,4 +144,64 @@ author: gmosx
135
144
  </script>
136
145
  </xsl:template>
137
146
 
147
+ <xsl:template name="x:pager-first" match="x:pager-first">
148
+ <ruby>unless @pager.page == @pager.first_page</ruby>
149
+ <a>
150
+ <xsl:attribute name="href">#{@pager.target_uri(@pager.first_page)}</xsl:attribute>
151
+ <xsl:apply-templates />
152
+ </a>
153
+ <ruby>end</ruby>
154
+ </xsl:template>
155
+
156
+ <xsl:template name="x:pager-prev" match="x:pager-prev">
157
+ <ruby>unless @pager.page == @pager.first_page</ruby>
158
+ <a>
159
+ <xsl:attribute name="href">#{@pager.target_uri(@pager.previous_page)}</xsl:attribute>
160
+ <xsl:apply-templates />
161
+ </a>
162
+ <ruby>end</ruby>
163
+ </xsl:template>
164
+
165
+ <xsl:template name="x:pager-next" match="x:pager-next">
166
+ <ruby>unless @pager.page == @pager.last_page</ruby>
167
+ <a>
168
+ <xsl:attribute name="href">#{@pager.target_uri(@pager.next_page)}</xsl:attribute>
169
+ <xsl:apply-templates />
170
+ </a>
171
+ <ruby>end</ruby>
172
+ </xsl:template>
173
+
174
+ <xsl:template name="x:pager-last" match="x:pager-last">
175
+ <ruby>unless @pager.page == @pager.last_page</ruby>
176
+ <a>
177
+ <xsl:attribute name="href">#{@pager.target_uri(@pager.last_page)}</xsl:attribute>
178
+ <xsl:apply-templates />
179
+ </a>
180
+ <ruby>end</ruby>
181
+ </xsl:template>
182
+
183
+ <xsl:template name="x:pager-pages" match="x:pager-pages">
184
+ <ruby>
185
+ for i in @pager.nav_range()
186
+ if i == @pager.page
187
+ @out += %|<xsl:apply-templates select="x:pager-selected" />|
188
+ else
189
+ @out += %|<xsl:apply-templates select="x:pager-page" />|
190
+ end
191
+ end
192
+ </ruby>
193
+ </xsl:template>
194
+
195
+ <xsl:template name="x:pager-selected" match="x:pager-selected">
196
+ <xsl:apply-templates />
197
+ </xsl:template>
198
+
199
+ <xsl:template name="x:pager-page" match="x:pager-page">
200
+ <xsl:param name="index"><xsl:value-of select="@index"/></xsl:param>
201
+ <a>
202
+ <xsl:attribute name="href">#{@pager.target_uri(i)}</xsl:attribute>
203
+ <xsl:apply-templates />
204
+ </a>
205
+ </xsl:template>
206
+
138
207
  </xsl:stylesheet>
data/lib/xsl/ui.xsl ADDED
@@ -0,0 +1,51 @@
1
+ <?xml version="1.0" ?>
2
+
3
+ <!--
4
+ author: gmosx
5
+ -->
6
+
7
+ <!DOCTYPE shader
8
+ [
9
+ <!ENTITY nbsp "<![CDATA[&nbsp;]]>">
10
+ <!ENTITY copy "<![CDATA[&copy;]]>">
11
+ <!ENTITY euro "<![CDATA[&euro;]]>">
12
+ <!ENTITY laquo "<![CDATA[&laquo;]]>">
13
+ <!ENTITY raquo "<![CDATA[&raquo;]]>">
14
+ ]>
15
+
16
+ <xsl:stylesheet
17
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
18
+ xmlns:x="http://www.navel.gr/xml/pager.xsd"
19
+ exclude-result-prefixes="x"
20
+ version="1.0">
21
+
22
+ <xsl:template name="x:pager-first" match="x:pager-first">
23
+ <xsl:apply-templates />
24
+ <a href="#{target_uri(first_page())}">
25
+ <xsl:apply-templates />
26
+ </a>
27
+ </xsl:template>
28
+
29
+ <xsl:template name="x:pager-prev" match="x:pager-prev">
30
+ <xsl:apply-templates />
31
+ <a href="#{target_uri(previous_page())}">
32
+ <xsl:apply-templates />
33
+ </a>
34
+ </xsl:template>
35
+
36
+ <xsl:template name="x:pager-next" match="x:pager-next">
37
+ <xsl:apply-templates />
38
+ <a href="#{target_uri(next_page())}">
39
+ <xsl:apply-templates />
40
+ </a>
41
+ </xsl:template>
42
+
43
+ <xsl:template name="x:pager-last" match="x:pager-last">
44
+ <xsl:apply-templates />
45
+ <a href="#{target_uri(first_page())}">
46
+ <xsl:apply-templates />
47
+ </a>
48
+ </xsl:template>
49
+
50
+ </xsl:stylesheet>
51
+