nitro 0.4.1 → 0.5.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 (84) hide show
  1. data/AUTHORS +9 -1
  2. data/ChangeLog +107 -1
  3. data/README +1 -1
  4. data/RELEASES +14 -0
  5. data/Rakefile +73 -28
  6. data/bin/cluster.rb +2 -2
  7. data/examples/blog/app.rb +2 -2
  8. data/examples/blog/config.rb +14 -15
  9. data/examples/blog/lib/blog.rb +13 -20
  10. data/examples/blog/root/entry_form.xhtml +0 -1
  11. data/examples/blog/root/m/rss.gif +0 -0
  12. data/examples/blog/root/style.css +17 -0
  13. data/examples/blog/root/style.xsl +17 -5
  14. data/examples/blog/root/view_entry.xml +12 -0
  15. data/examples/og/run.rb +2 -3
  16. data/examples/tiny/config.rb +7 -8
  17. data/lib/glue.rb +52 -0
  18. data/lib/{nitro/utils → glue}/array.rb +2 -2
  19. data/lib/{nitro/utils → glue}/cache.rb +2 -2
  20. data/lib/{nitro/utils → glue}/hash.rb +2 -2
  21. data/lib/glue/inflector.rb +91 -0
  22. data/lib/{nitro → glue}/logger.rb +1 -1
  23. data/lib/{nitro/macros.rb → glue/macro.rb} +1 -1
  24. data/lib/{nitro → glue}/mixins.rb +3 -4
  25. data/lib/{nitro/utils → glue}/number.rb +3 -3
  26. data/lib/{nitro/utils → glue}/pool.rb +2 -2
  27. data/lib/{nitro/properties.rb → glue/property.rb} +8 -8
  28. data/lib/{nitro/utils → glue}/string.rb +3 -2
  29. data/lib/{nitro/utils → glue}/time.rb +3 -3
  30. data/lib/nitro.rb +2 -43
  31. data/lib/nitro/application.rb +2 -2
  32. data/lib/nitro/builders/rss.rb +43 -0
  33. data/lib/nitro/config.rb +13 -4
  34. data/lib/nitro/{utils/html.rb → html.rb} +2 -2
  35. data/lib/nitro/{utils/http.rb → http.rb} +1 -1
  36. data/lib/nitro/{utils/mail.rb → mail.rb} +1 -1
  37. data/lib/nitro/scaffold.rb +80 -0
  38. data/lib/nitro/server/appserver.rb +2 -2
  39. data/lib/nitro/server/cluster.rb +2 -2
  40. data/lib/nitro/server/dispatcher.rb +2 -5
  41. data/lib/nitro/server/filters/autologin.rb +2 -2
  42. data/lib/nitro/server/fragment.rb +5 -5
  43. data/lib/nitro/server/handlers.rb +3 -3
  44. data/lib/nitro/server/render.rb +145 -22
  45. data/lib/nitro/server/request.rb +7 -7
  46. data/lib/nitro/server/requestpart.rb +4 -4
  47. data/lib/nitro/server/script.rb +4 -4
  48. data/lib/nitro/server/server.rb +2 -2
  49. data/lib/nitro/server/session.rb +4 -4
  50. data/lib/nitro/server/webrick.rb +2 -2
  51. data/lib/nitro/service.rb +2 -1
  52. data/lib/nitro/sitemap.rb +3 -3
  53. data/lib/nitro/{utils/uri.rb → uri.rb} +3 -3
  54. data/lib/nitro/version.rb +2 -2
  55. data/lib/og.rb +8 -8
  56. data/lib/og/backends/mysql.rb +16 -12
  57. data/lib/og/backends/psql.rb +6 -2
  58. data/lib/og/connection.rb +4 -4
  59. data/lib/og/meta.rb +7 -1
  60. data/lib/og/version.rb +8 -0
  61. data/lib/xsl/base.xsl +10 -0
  62. data/test/{n/utils → glue}/tc_cache.rb +3 -3
  63. data/test/{n/utils → glue}/tc_hash.rb +2 -3
  64. data/test/{n/utils/tc_number.rb → glue/tc_numbers.rb} +3 -4
  65. data/test/{n → glue}/tc_properties.rb +2 -2
  66. data/test/glue/tc_strings.rb +103 -0
  67. data/test/{n → nitro}/server/tc_cookie.rb +0 -0
  68. data/test/{n → nitro}/server/tc_filters.rb +0 -0
  69. data/test/{n → nitro}/server/tc_request.rb +1 -1
  70. data/test/{n → nitro}/server/tc_requestpart.rb +0 -0
  71. data/test/{n → nitro}/server/tc_session.rb +0 -0
  72. data/test/{n → nitro}/tc_events.rb +0 -0
  73. data/test/{n/utils → nitro}/tc_html.rb +1 -1
  74. data/test/{n/utils → nitro}/tc_http.rb +1 -1
  75. data/test/{n → nitro}/tc_sitemap.rb +1 -1
  76. data/test/{n/utils → nitro}/tc_uri.rb +1 -1
  77. data/test/{n → nitro}/ui/tc_pager.rb +1 -1
  78. data/test/{n/tc_og.rb → tc_og.rb} +5 -2
  79. metadata +48 -44
  80. data/examples/blog/log/app.log +0 -117
  81. data/examples/tiny/log/app.log +0 -23
  82. data/lib/nitro/utils/gfx.rb +0 -107
  83. data/lib/nitro/utils/template.rb +0 -36
  84. data/test/n/utils/tc_strings.rb +0 -104
@@ -12,47 +12,6 @@
12
12
  # * George Moschovitis <gm@navel.gr>
13
13
  #
14
14
  # (c) 2004 Navel, all rights reserved.
15
- # $Id: nitro.rb 155 2004-11-13 20:32:12Z gmosx $
15
+ # $Id: nitro.rb 167 2004-11-23 14:03:10Z gmosx $
16
16
 
17
- # we want readable code
18
-
19
- require "English"
20
- require "pp"
21
-
22
- class NilClass
23
- # quite usefull for error tolerant apps.
24
- # a bit dangerous? Will have to rethink this.
25
- #
26
- def empty?
27
- return true
28
- end
29
- end
30
-
31
- class Class
32
- #--
33
- # gmosx: is this really needed?
34
- #++
35
- def to_i()
36
- return self.hash()
37
- end
38
- end
39
-
40
- module Kernel
41
- # pretty prints an exception/error object
42
- # usefull for helpfull debug messages
43
- #
44
- # Input:
45
- # The Exception/StandardError object
46
- #
47
- # Output:
48
- # the pretty printed string
49
- #
50
- def pp_exception(ex)
51
- return %{#{ex.message}\n\tBACKTRACE:\n\t#{ex.backtrace.join("\n\t")}\n\tLOGGED FROM:\n\t#{caller[0]}}
52
- end
53
-
54
- end
55
-
56
- # predefine some comonly used objects
57
-
58
- EMPTY_STRING = ""
17
+ require 'glue'
@@ -9,12 +9,12 @@
9
9
  # Elias Karakoulakis <ekarak@ktismata.com>
10
10
  #
11
11
  # (c) 2004 Navel, all rights reserved.
12
- # $Id: application.rb 155 2004-11-13 20:32:12Z gmosx $
12
+ # $Id: application.rb 167 2004-11-23 14:03:10Z gmosx $
13
13
 
14
14
  require 'optparse'
15
15
  require 'ostruct'
16
16
 
17
- require "nitro/logger"
17
+ require "glue/logger"
18
18
  require "nitro"
19
19
 
20
20
  module N
@@ -0,0 +1,43 @@
1
+ # code:
2
+ # * George Moschovitis <gm@navel.gr>
3
+ #
4
+ # (c) 2004 Navel, all rights reserved.
5
+ # $Id$
6
+
7
+ require 'rss/0.9'
8
+
9
+ module N
10
+
11
+ # = RssBuilder
12
+ #
13
+ # Build RSS represenations of ruby object collections.
14
+ # Utilize duck typing to grab the attributes to render.
15
+ #--
16
+ # TODO: add more options here, 1.0/2.0 support and more.
17
+ #++
18
+ module RssBuilder
19
+ include RSS
20
+
21
+ def self.render(objects)
22
+ channel = RSS::Rss::Channel.new
23
+ channel.description = 'Syndication'
24
+ channel.link = $srv_url
25
+
26
+ for obj in objects
27
+ item = Rss::Channel::Item.new
28
+ item.title = obj.title if obj.respond_to?(:title)
29
+ item.description = G::StringUtils.head(obj.body, 256) if obj.respond_to?(:body)
30
+ item.link = "#$srv_url/#{obj.view_uri}" if obj.respond_to?(:view_uri)
31
+ channel.items << item
32
+ end
33
+
34
+ rss = Rss.new '0.9'
35
+ rss.channel = channel
36
+
37
+ return rss.to_s
38
+ end
39
+
40
+ end
41
+
42
+ end # module
43
+
@@ -6,10 +6,10 @@
6
6
  # * George Moschovitis <gm@navel.gr>
7
7
  #
8
8
  # (c) 2004 Navel, all rights reserved.
9
- # $Id: config.rb 155 2004-11-13 20:32:12Z gmosx $
9
+ # $Id: config.rb 167 2004-11-23 14:03:10Z gmosx $
10
10
 
11
- require 'nitro/logger'
12
- require 'nitro/utils/hash'
11
+ require 'glue/logger'
12
+ require 'glue/hash'
13
13
  require 'nitro/version'
14
14
  require 'nitro/service'
15
15
  require 'nitro/server/shaders'
@@ -45,6 +45,15 @@ $error_page_url = nil
45
45
  # default encoding for the app.
46
46
  $encoding = 'iso-8859-1'
47
47
 
48
+ # Default template extesnion.
49
+ $template_ext = 'xhtml'
50
+
51
+ # Default xml template extension.
52
+ $xml_template_ext = 'xml'
53
+
54
+ # Default template.
55
+ $index_template = 'index.xhtml'
56
+
48
57
  # default content type.
49
58
  $default_content_type = 'text/html'
50
59
 
@@ -53,7 +62,7 @@ $default_content_type = 'text/html'
53
62
  $services = { :index => N::Service }
54
63
 
55
64
  # The service method map.
56
- $methods = N::SafeHash.new
65
+ $methods = G::SafeHash.new
57
66
 
58
67
  # The shader. The default shader is very simple, here
59
68
  # is a typical example of a production shader pipeline:
@@ -4,7 +4,7 @@
4
4
  # * Elias Karakoulakis <ekarak@ktismata.com>
5
5
  #
6
6
  # (c) 2004 Navel, all rights reserved.
7
- # $Id: html.rb 152 2004-11-13 20:02:35Z gmosx $
7
+ # $Id: html.rb 167 2004-11-23 14:03:10Z gmosx $
8
8
 
9
9
  require "uri"
10
10
  require "cgi"
@@ -141,7 +141,7 @@ module HtmlUtils
141
141
  # convert plain newlines into line breaks <br/>
142
142
 
143
143
  def self.convert_newlines(string)
144
- return nil unless N::StringUtils.valid?(string)
144
+ return nil unless G::StringUtils.valid?(string)
145
145
  xstring = string.gsub(/\n/, "<br/>")
146
146
  return xstring;
147
147
  end
@@ -3,7 +3,7 @@
3
3
  # * Elias Karakoulakis <ekarak@ktismata.com>
4
4
  #
5
5
  # (c) 2004 Navel, all rights reserved.
6
- # $Id: http.rb 152 2004-11-13 20:02:35Z gmosx $
6
+ # $Id: http.rb 164 2004-11-18 11:47:50Z gmosx $
7
7
 
8
8
  require "uri"
9
9
  require "cgi"
@@ -2,7 +2,7 @@
2
2
  # * George Moschovitis <gm@navel.gr>
3
3
  #
4
4
  # (c) 2004 Navel, all rights reserved.
5
- # $Id: mail.rb 152 2004-11-13 20:02:35Z gmosx $
5
+ # $Id: mail.rb 164 2004-11-18 11:47:50Z gmosx $
6
6
 
7
7
  require "net/smtp"
8
8
 
@@ -0,0 +1,80 @@
1
+ # code:
2
+ # * George Moschovitis <gm@navel.gr>
3
+ #
4
+ # (c) 2004 Navel, all rights reserved.
5
+ # $Id$
6
+
7
+ require 'glue/inflector'
8
+
9
+ module N
10
+
11
+ module Scaffolding
12
+
13
+ # Ruby is sometimes VERY surprising, the following trick is needed
14
+ # to include singleton methods in other classes.
15
+ #
16
+ def self.append_features(base)
17
+ super
18
+ base.extend(SingletonMethods)
19
+ end
20
+
21
+ module SingletonMethods
22
+ # Enchant the caller with a number of default methods.
23
+ # Override the automatically generated methods as needed.
24
+ #
25
+ def scaffold(klass, options = {})
26
+
27
+ oid = options[:oid] || 'oid'
28
+ name = options[:name] || G::Inflector.name(klass.name)
29
+ list_name = options[:list_name] || G::Inflector.plural_name(name)
30
+ suffix = "_#{name}"
31
+
32
+ # Add methods to the scaffolded class.
33
+
34
+ klass.module_eval <<-"end_eval", __FILE__, __LINE__
35
+
36
+ def view_uri
37
+ "view#{suffix}?oid=\#\{@oid\}"
38
+ end
39
+
40
+ end_eval
41
+
42
+ # Add methods to the service.
43
+
44
+ if options[:index]
45
+ module_eval <<-"end_eval", __FILE__, __LINE__
46
+
47
+ def index
48
+ list#{suffix}
49
+ end
50
+
51
+ end_eval
52
+ end
53
+
54
+ module_eval <<-"end_eval", __FILE__, __LINE__
55
+
56
+ # TODO: add pager support here!
57
+ def list#{suffix}
58
+ @#{list_name} = #{klass}.all('ORDER BY oid')
59
+ end
60
+
61
+ def view#{suffix}
62
+ @#{name} = #{klass}[@params['#{oid}']]
63
+ end
64
+
65
+ def save#{suffix}
66
+ end
67
+
68
+ def del#{suffix}
69
+ #{klass}.delete(@params['#{oid}'])
70
+ end
71
+ alias_method :delete#{suffix}, :del#{suffix}
72
+
73
+ end_eval
74
+
75
+ end
76
+ end
77
+
78
+ end
79
+
80
+ end # module
@@ -2,7 +2,7 @@
2
2
  # * George Moschovitis <gm@navel.gr>
3
3
  #
4
4
  # (c) 2004 Navel, all rights reserved.
5
- # $Id: appserver.rb 155 2004-11-13 20:32:12Z gmosx $
5
+ # $Id: appserver.rb 167 2004-11-23 14:03:10Z gmosx $
6
6
 
7
7
  require "drb"
8
8
 
@@ -26,7 +26,7 @@ module AppServerMixin
26
26
  $sessions = DRbObject.new(nil, $drb_sessions_cluster)
27
27
  else
28
28
  # NoCluster mode: use standard Ruby onjects.
29
- $lm = N::SafeHash.new
29
+ $lm = G::SafeHash.new
30
30
  $sessions = N::SessionManager.new
31
31
  end
32
32
 
@@ -2,7 +2,7 @@
2
2
  # * George Moschovitis <gm@navel.gr>
3
3
  #
4
4
  # (c) 2004 Navel, all rights reserved.
5
- # $Id: cluster.rb 155 2004-11-13 20:32:12Z gmosx $
5
+ # $Id: cluster.rb 167 2004-11-23 14:03:10Z gmosx $
6
6
 
7
7
  $:.unshift "lib"
8
8
 
@@ -11,7 +11,7 @@ require "monitor"
11
11
 
12
12
  require "nitro/application"
13
13
  require "nitro/server"
14
- require "nitro/utils/cache"
14
+ require "glue/cache"
15
15
  require "nitro/server/session"
16
16
 
17
17
  module N
@@ -2,7 +2,7 @@
2
2
  # * George Moschovitis <gm@navel.gr>
3
3
  #
4
4
  # (c) 2004 Navel, all rights reserved.
5
- # $Id: dispatcher.rb 155 2004-11-13 20:32:12Z gmosx $
5
+ # $Id: dispatcher.rb 167 2004-11-23 14:03:10Z gmosx $
6
6
 
7
7
  require 'nitro/server/render'
8
8
 
@@ -19,16 +19,13 @@ module Dispatcher
19
19
 
20
20
  session = create_session(request, response)
21
21
  render(request.request_uri.path, request, response, session)
22
-
23
- unless response.header['Content-Type']
24
- response.header['Content-Type'] = $default_content_type
25
- end
26
22
  response.body = @out
27
23
  rescue Exception, StandardError => e
28
24
  $log.error "error while handling the request #{request.request_uri}"
29
25
  $log.error pp_exception(e)
30
26
 
31
27
  if $error_page_url
28
+ # gmosx: SOS: TEST ME!
32
29
  # internal redirect to error page.
33
30
  request.request_uri.path = $error_page_url
34
31
  retry
@@ -2,9 +2,9 @@
2
2
  # * George Moschovitis
3
3
  #
4
4
  # (c) 2004 Navel, all rights reserved.
5
- # $Id: autologin.rb 155 2004-11-13 20:32:12Z gmosx $
5
+ # $Id: autologin.rb 167 2004-11-23 14:03:10Z gmosx $
6
6
 
7
- require "nitro/utils/string"
7
+ require "glue/string"
8
8
  require "nitro/server/filters"
9
9
 
10
10
  require_part "users"
@@ -2,10 +2,10 @@
2
2
  # * George Moschovitis <gm@navel.gr>
3
3
  #
4
4
  # (c) 2004 Navel, all rights reserved.
5
- # $Id: fragment.rb 155 2004-11-13 20:32:12Z gmosx $
5
+ # $Id: fragment.rb 167 2004-11-23 14:03:10Z gmosx $
6
6
 
7
- require "nitro/utils/cache"
8
- require "nitro/mixins"
7
+ require "glue/cache"
8
+ require "glue/mixins"
9
9
 
10
10
  module N
11
11
 
@@ -28,8 +28,8 @@ module N
28
28
  # - can run background cron scripts over the fragments (compression)
29
29
  #
30
30
  class Fragment
31
- include N::Expirable
32
- include N::LRUCache::Item
31
+ include G::Expirable
32
+ include G::LRUCache::Item
33
33
 
34
34
  # precompiled flags for fragment key "customization"
35
35
 
@@ -2,9 +2,9 @@
2
2
  # * George Moschovitis <gm@navel.gr>
3
3
  #
4
4
  # (c) 2004 Navel, all rights reserved.
5
- # $Id: handlers.rb 155 2004-11-13 20:32:12Z gmosx $
5
+ # $Id: handlers.rb 167 2004-11-23 14:03:10Z gmosx $
6
6
 
7
- require "nitro/utils/cache"
7
+ require "glue/cache"
8
8
  require "nitro/server/filters"
9
9
 
10
10
  module N
@@ -50,7 +50,7 @@ class ScriptHandler < Handler
50
50
 
51
51
  # cache the compiled page scripts to optimize future references.
52
52
  # use a thread safe cache.
53
- @@compiled_script_cache = N::SafeHash.new()
53
+ @@compiled_script_cache = G::SafeHash.new()
54
54
 
55
55
  # dont allow 2 threads to compile the same script. In fact dont allow
56
56
  # two threads to compile in parallel.
@@ -2,7 +2,7 @@
2
2
  # * George Moschovitis <gm@navel.gr>
3
3
  #
4
4
  # (c) 2004 Navel, all rights reserved.
5
- # $Id: render.rb 152 2004-11-13 20:02:35Z gmosx $
5
+ # $Id: render.rb 167 2004-11-23 14:03:10Z gmosx $
6
6
 
7
7
  module N
8
8
 
@@ -23,6 +23,14 @@ module RenderUtils
23
23
  # /blog -> blog, index, nil
24
24
  #
25
25
  def self.split_path(path)
26
+ # paths that start with rest/xxx are REST requests.
27
+ # FIXME: better chack here!
28
+ if path.slice!(/rest\//)
29
+ api = :rest
30
+ else
31
+ api = :http
32
+ end
33
+
26
34
  parts = path.split('/')
27
35
 
28
36
  case parts.size
@@ -45,58 +53,91 @@ module RenderUtils
45
53
  meth = parts[2]
46
54
  end
47
55
 
48
- return base, render_class, meth
56
+ # p '--', api, base, render_class, meth, '--'
57
+
58
+ return api, base, render_class, meth
49
59
  end
50
60
 
51
- # Transform an xhtml file to ruby rendering code.
61
+ # Given the method try find the matching template.
62
+ # Can search for xhtml or xml templates.
63
+ # Returns nil if no template file is found.
52
64
  #
53
- def self.transform_xhtml(path)
65
+ def self.template_for_method(base, meth, ext = $template_ext)
66
+ # attempt to find a template of the form
67
+ # base/meth.xhtml
68
+ path = "#$root_dir/#{base}/#{meth}.#{ext}".squeeze('/')
69
+
70
+ unless File.exist?(path)
71
+ # attempt to find a template of the form
72
+ # base/meth/index.xhtml
73
+ path = "#$root_dir/#{base}/#{meth}/#{$index_template}".squeeze('/')
74
+
75
+ unless File.exist?(path)
76
+ # No template found!
77
+ path = nil
78
+ end
79
+ end
80
+
81
+ return path
82
+ end
83
+
84
+ # Transform a template to ruby rendering code.
85
+ #
86
+ def self.transform_template(path)
54
87
  $log.debug "Transforming '#{path}'" if $DBG
55
88
 
56
89
  text = File.read(path)
57
90
  hash, text = $shader.process(path, text)
91
+
58
92
  return text
59
93
  end
94
+
60
95
 
61
- # Compile a rendering method.
96
+ # Compile a HTTP method.
62
97
  #
63
- def self.compile_method(klass, base, meth)
64
- $log.debug "Compiling '#{klass}:#{meth}'" if $DBG
98
+ def self.compile_http_method(klass, base, meth)
99
+ $log.debug "Compiling HTTP method '#{klass}:#{meth}'" if $DBG
65
100
 
66
- xhtml_path = "#$root_dir/#{base}/#{meth}.xhtml".squeeze('/')
101
+ valid = false
67
102
 
68
103
  code = %{
69
104
  def __#{meth}
105
+ @response.header['Content-Type'] = 'text/html'
70
106
  @out ||= ''
71
107
  }
72
108
 
73
109
  if klass.instance_methods.include?(meth)
110
+ valid = true
74
111
  code << %{
75
112
  #{meth}();
76
113
  }
77
114
  end
78
115
 
79
- if klass.instance_methods.include?("#{meth}_xhtml")
116
+ if klass.instance_methods.include?("#{meth}__xhtml")
117
+ valid = true
80
118
  code << %{
81
- #{meth}_xhtml();
119
+ #{meth}__xhtml();
82
120
  }
83
121
  end
84
122
 
85
- if xhtml_exists = File.exist?(xhtml_path)
123
+ if template = template_for_method(base, meth)
124
+ valid = true
86
125
  code << %{
87
126
  __#{meth}_xhtml();
88
127
  }
89
128
  end
90
129
 
130
+ raise "Invalid method '#{meth}' for service '#{klass}'!" unless valid
131
+
91
132
  code << %{
92
133
  redirect_referer if @out.empty?
93
134
  end
94
135
  }
95
136
 
96
- if xhtml_exists = File.exist?(xhtml_path)
137
+ if template
97
138
  code << %{
98
139
  def __#{meth}_xhtml
99
- #{transform_xhtml(xhtml_path)}
140
+ #{transform_template(template)}
100
141
  end
101
142
  }
102
143
  end
@@ -105,6 +146,60 @@ module RenderUtils
105
146
 
106
147
  return "__#{meth}"
107
148
  end
149
+
150
+ # Compile a REST method.
151
+ #
152
+ def self.compile_rest_method(klass, base, meth)
153
+ $log.debug "Compiling REST method '#{klass}:#{meth}'" if $DBG
154
+
155
+ valid = false
156
+
157
+ code = %{
158
+ def __rest_#{meth}
159
+ @response.header['Content-Type'] = 'text/xml'
160
+ @out ||= ''
161
+ }
162
+
163
+ if klass.instance_methods.include?(meth)
164
+ valid = true
165
+ code << %{
166
+ #{meth}();
167
+ }
168
+ end
169
+
170
+ if klass.instance_methods.include?("#{meth}__xml")
171
+ valid = true
172
+ code << %{
173
+ #{meth}__xml();
174
+ }
175
+ end
176
+
177
+ if template = template_for_method(base, meth, 'xml')
178
+ valid = true
179
+ code << %{
180
+ __#{meth}_xml();
181
+ }
182
+ end
183
+
184
+ raise "Invalid method '#{meth}' for service #{klass}!" unless valid
185
+
186
+ code << %{
187
+ end
188
+ }
189
+
190
+ if template
191
+ code << %{
192
+ def __#{meth}_xml
193
+ #{transform_template(template)}
194
+ end
195
+ }
196
+ end
197
+
198
+ klass.class_eval(code)
199
+
200
+ return "__rest_#{meth}"
201
+ end
202
+
108
203
 
109
204
  end
110
205
 
@@ -128,6 +223,11 @@ module Render
128
223
  # user session.
129
224
  attr_accessor :session
130
225
 
226
+ # An array holding the rendering errors for this
227
+ # request.
228
+ #
229
+ attr_accessor :rendering_errors
230
+
131
231
  def initialize(base_path = '', request = nil, response = nil, session = nil)
132
232
  @base_path = base_path
133
233
  @request = request
@@ -150,17 +250,34 @@ module Render
150
250
  base, render_class, meth = $methods[path]
151
251
 
152
252
  unless meth
153
- base, render_class, meth = RenderUtils.split_path(path)
154
- meth = RenderUtils.compile_method(render_class, base, meth)
253
+ api, base, render_class, meth = RenderUtils.split_path(path)
254
+
255
+ raise "Invalid service!" unless render_class
256
+
257
+ case api
258
+ when :http
259
+ meth = RenderUtils.compile_http_method(render_class, base, meth)
260
+ when :rest
261
+ meth = RenderUtils.compile_rest_method(render_class, base, meth)
262
+ end
263
+
155
264
  $methods[path] = [base, render_class, meth] unless $reload_scripts
156
265
  end
157
266
 
158
- if self.class == render_class
159
- self.send(meth)
160
- else
161
- r = render_class.new(base, @request, @response, @session)
162
- r.send(meth)
163
- @out = r.out
267
+ begin
268
+ if self.class == render_class
269
+ self.send(meth)
270
+ else
271
+ r = render_class.new(base, @request, @response, @session)
272
+ r.send(meth)
273
+ @out = r.out
274
+ end
275
+ rescue Exception, StandardError => e
276
+ log_error "error while handling '#{path}'."
277
+ log_error pp_exception(e)
278
+ # more fault tolerant, only flags the erroneous box with
279
+ # errorm not the full page.
280
+ @out << '(error)'
164
281
  end
165
282
 
166
283
  # stop the filter pipeline
@@ -177,7 +294,6 @@ module Render
177
294
  #
178
295
  def redirect(url, status = 303)
179
296
  begin
180
- # url = "#$srv_url/#{url}".squeeze('/') unless url =~ /^http/
181
297
  @response.status = status
182
298
  @response.set_redirect(status, url)
183
299
  rescue Exception, StandardError => ex
@@ -194,6 +310,13 @@ module Render
194
310
  redirect(@request.referer, status)
195
311
  end
196
312
 
313
+ # Log a rendering error.
314
+ #
315
+ def log_error(str)
316
+ @rendering_errors ||= []
317
+ @rendering_errors << str
318
+ $log.error str
319
+ end
197
320
  end
198
321
 
199
322
  end # module