nitro 0.5.0 → 0.6.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.
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
+