nitro 0.15.0 → 0.16.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 (111) hide show
  1. data/CHANGELOG +218 -0
  2. data/INSTALL +3 -0
  3. data/README +4 -2
  4. data/Rakefile +150 -8
  5. data/benchmark/bench.rb +1 -1
  6. data/doc/AUTHORS +2 -8
  7. data/doc/RELEASES +63 -1
  8. data/examples/ajax/controller.rb +2 -2
  9. data/examples/ajax/public/index.xhtml +3 -1
  10. data/examples/ajax/run.rb +3 -3
  11. data/examples/blog/README +8 -0
  12. data/examples/blog/cache/entriesadmintrue +3 -0
  13. data/examples/blog/run.rb +38 -40
  14. data/examples/blog/src/blog.rb +2 -1
  15. data/examples/blog/src/controller.rb +40 -20
  16. data/examples/blog/src/mailer.rb +2 -2
  17. data/examples/blog/src/models/blog.rb +2 -1
  18. data/examples/blog/src/models/content.rb +4 -33
  19. data/examples/blog/src/views/error.xhtml +1 -1
  20. data/examples/blog/src/xsl/style.xsl +1 -1
  21. data/examples/blog/test/tc_blog.rb +43 -0
  22. data/examples/flash/run.rb +2 -2
  23. data/examples/no_xsl_blog/lib/blog.rb +1 -1
  24. data/examples/no_xsl_blog/lib/blog/controller.rb +26 -17
  25. data/examples/no_xsl_blog/lib/blog/model.rb +3 -3
  26. data/examples/no_xsl_blog/lib/blog/template.rb +1 -1
  27. data/examples/no_xsl_blog/lib/content.rb +3 -7
  28. data/examples/no_xsl_blog/run.rb +34 -34
  29. data/examples/tiny/public/deep/dir/hello.xhtml +2 -0
  30. data/examples/tiny/run.rb +2 -2
  31. data/examples/wee_style/run.rb +5 -3
  32. data/examples/why_wiki/run.rb +5 -3
  33. data/install.rb +1 -1
  34. data/lib/nitro.rb +10 -9
  35. data/lib/nitro/adapters/cgi.rb +27 -2
  36. data/lib/nitro/adapters/fastcgi.rb +6 -2
  37. data/lib/nitro/adapters/webrick.rb +11 -9
  38. data/lib/nitro/buffering.rb +2 -2
  39. data/lib/nitro/builders/atom.rb +78 -0
  40. data/lib/nitro/builders/form.rb +2 -2
  41. data/lib/nitro/builders/rss.rb +4 -4
  42. data/lib/nitro/builders/table.rb +2 -2
  43. data/lib/nitro/builders/xhtml.rb +5 -8
  44. data/lib/nitro/builders/xml.rb +38 -14
  45. data/lib/nitro/caching.rb +2 -2
  46. data/lib/nitro/caching/actions.rb +2 -2
  47. data/lib/nitro/caching/fragments.rb +2 -2
  48. data/lib/nitro/caching/invalidation.rb +2 -28
  49. data/lib/nitro/caching/output.rb +3 -3
  50. data/lib/nitro/caching/stores.rb +4 -4
  51. data/lib/nitro/conf.rb +11 -6
  52. data/lib/nitro/context.rb +2 -2
  53. data/lib/nitro/controller.rb +12 -7
  54. data/lib/nitro/cookie.rb +2 -2
  55. data/lib/nitro/dispatcher.rb +33 -40
  56. data/lib/nitro/environment.rb +1 -1
  57. data/lib/nitro/localization.rb +5 -7
  58. data/lib/nitro/mail.rb +2 -2
  59. data/lib/nitro/markup.rb +5 -5
  60. data/lib/nitro/output.rb +2 -2
  61. data/lib/nitro/part.rb +8 -5
  62. data/lib/nitro/render.rb +46 -45
  63. data/lib/nitro/request.rb +7 -6
  64. data/lib/nitro/response.rb +14 -5
  65. data/lib/nitro/routing.rb +2 -2
  66. data/lib/nitro/runner.rb +57 -17
  67. data/lib/nitro/scaffold.rb +14 -8
  68. data/lib/nitro/session.rb +7 -4
  69. data/lib/nitro/session/drb.rb +2 -2
  70. data/lib/nitro/session/drbserver.rb +2 -2
  71. data/lib/nitro/session/memory.rb +2 -2
  72. data/lib/nitro/shaders.rb +8 -7
  73. data/lib/nitro/simple.rb +4 -1
  74. data/lib/nitro/template.rb +8 -8
  75. data/lib/nitro/testing.rb +6 -0
  76. data/lib/nitro/testing/assertions.rb +102 -0
  77. data/lib/nitro/testing/context.rb +52 -0
  78. data/lib/nitro/testing/testcase.rb +55 -0
  79. data/lib/nitro/ui/pager.rb +3 -3
  80. data/lib/nitro/ui/popup.rb +8 -13
  81. data/lib/nitro/ui/tabs.rb +4 -10
  82. data/lib/nitro/uri.rb +7 -7
  83. data/proto/doc/README +1 -0
  84. data/proto/public/cgi.rb +5 -0
  85. data/proto/run.rb +2 -4
  86. data/test/nitro/adapters/tc_cgi.rb +1 -1
  87. data/test/nitro/adapters/tc_webrick.rb +1 -2
  88. data/test/nitro/builders/tc_atom.rb +26 -0
  89. data/test/nitro/builders/tc_rss.rb +3 -2
  90. data/test/nitro/builders/tc_table.rb +1 -1
  91. data/test/nitro/builders/tc_xhtml.rb +4 -3
  92. data/test/nitro/builders/tc_xml.rb +7 -7
  93. data/test/nitro/tc_context.rb +1 -1
  94. data/test/nitro/tc_controller.rb +5 -3
  95. data/test/nitro/tc_dispatcher.rb +19 -18
  96. data/test/nitro/tc_localization.rb +1 -1
  97. data/test/nitro/tc_mail.rb +1 -1
  98. data/test/nitro/tc_session.rb +1 -1
  99. data/test/nitro/tc_template.rb +1 -1
  100. data/test/nitro/tc_uri.rb +3 -4
  101. data/test/nitro/ui/tc_pager.rb +7 -7
  102. data/test/public/blog/inc1.xhtml +2 -0
  103. data/test/public/blog/inc2.xhtml +1 -0
  104. data/test/public/blog/list.xhtml +3 -0
  105. metadata +180 -203
  106. data/examples/blog/cache/entriesadmin +0 -12
  107. data/lib/nitro/cluster.rb +0 -218
  108. data/lib/nitro/component.rb +0 -15
  109. data/lib/nitro/filters.rb +0 -215
  110. data/lib/nitro/ui/date-select.rb +0 -69
  111. data/test/nitro/tc_filters.rb +0 -111
@@ -1,6 +1,6 @@
1
1
  # * George Moschovitis <gm@navel.gr>
2
- # (c) 2004-2005 Navel, all rights reserved.
3
- # $Id$
2
+ # (c) 2005 Navel, all rights reserved.
3
+ # $Id: render.rb 20 2005-04-15 15:18:36Z gmosx $
4
4
 
5
5
  require 'sync'
6
6
 
@@ -11,7 +11,7 @@ require 'glue/object'
11
11
  require 'nitro/shaders'
12
12
  require 'nitro/buffering'
13
13
 
14
- module N
14
+ module Nitro
15
15
 
16
16
  # Raise this exception to stop rendering.
17
17
 
@@ -89,13 +89,10 @@ module Rendering
89
89
 
90
90
  def self.compile_action(klass, action, template_root)
91
91
  @@sync.synchronize do
92
- action = action.to_s.split('__')
93
- action.shift
94
- api = action.shift
95
- action = action.join('__')
96
-
97
- # dummy, api, action = action.to_s.split('__')
98
-
92
+ Aspects.include_advice_modules(klass)
93
+
94
+ action = action.to_s.gsub(/_action$/, '')
95
+
99
96
  # This is not a controller action.
100
97
 
101
98
  return false unless action
@@ -105,18 +102,14 @@ module Rendering
105
102
  valid = false
106
103
 
107
104
  code = %{
108
- def __#{api}__#{action}
109
- old_action_name = @action_name
105
+ def #{action}_action
106
+ @parent_action_name = @action_name
110
107
  @action_name = '#{action}'
111
108
  }
112
-
113
- # call 'before' filter chain.
114
-
115
- if klass.respond_to?(:before_filters)
116
- code << %{
117
- #{klass.gen_filters_call_code(action, klass.before_filters)}
118
- }
119
- end
109
+
110
+ # Inject the pre advices.
111
+
112
+ code << Aspects.gen_advice_code(action, klass.advices, :pre)
120
113
 
121
114
  # call the action
122
115
 
@@ -134,37 +127,33 @@ module Rendering
134
127
  }
135
128
  end
136
129
 
137
- # call the programmatically generated template if exists.
138
-
139
- if klass.action_methods.include?("#{action}__#{api}")
140
- valid = true
141
- code << %{
142
- return unless #{action}__#{api}();
143
- }
144
- end
145
-
146
- # call the template if exists.
130
+ # Try to call the template method if it exists. It is a nice
131
+ # practice to put output related code in this method instead
132
+ # of the main action so that this method can be overloaded
133
+ # separately.
134
+ #
135
+ # If no template method exists, try to convert an external
136
+ # template file into a template method. It is an even better
137
+ # practice to place the output related code in an external
138
+ # template file.
147
139
 
148
- if template = template_for_action(template_root, action)
140
+ if (template = template_for_action(template_root, action)) or
141
+ klass.instance_methods.include?("#{action}_template")
149
142
  valid = true
150
143
  code << %{
151
- return unless __#{api}__#{action}__template();
144
+ return unless #{action}_template;
152
145
  }
153
146
  end
154
147
 
155
148
  # raise "Invalid action '#{action}' for '#{klass}'!" unless valid
156
149
  return false unless valid
157
150
 
158
- # call 'after' filter chain.
151
+ # Inject the post advices.
159
152
 
160
- if klass.respond_to?(:after_filters)
161
- code << %{
162
- #{klass.gen_filters_call_code(action, klass.after_filters)}
163
- }
164
- end
153
+ code << Aspects.gen_advice_code(action, klass.advices, :post)
165
154
 
166
155
  code << %{
167
- @action_name = old_action_name
156
+ @action_name = @parent_action_name
168
157
 
169
158
  redirect_referer if @out.empty?
170
159
  end
@@ -172,15 +161,22 @@ module Rendering
172
161
 
173
162
  if template
174
163
  code << %{
175
- def __#{api}__#{action}__template
164
+ def #{action}_template
176
165
  #{transform_template(template, Rendering.shader)}
177
166
  end
178
167
  }
179
168
  end
180
169
 
181
- # puts '---', code, '---'
170
+ # puts '---', klass, '==', code, '---'
171
+
172
+ where = "Action: #{action}"
173
+ where += ", Template: #{template}" if template
182
174
 
183
- klass.class_eval(code)
175
+ begin
176
+ klass.class_eval(code, where)
177
+ rescue SyntaxError => e
178
+ p e
179
+ end
184
180
  end
185
181
 
186
182
  return true
@@ -196,10 +192,14 @@ end
196
192
 
197
193
  module Render
198
194
 
199
- # The outbut buffer. The output of a script/action is accumulated
195
+ # The output buffer. The output of a script/action is accumulated
200
196
  # in this buffer.
201
197
 
202
198
  attr_accessor :out
199
+
200
+ # A nice alias
201
+
202
+ alias_method :body, :out
203
203
 
204
204
  # The context.
205
205
 
@@ -237,9 +237,10 @@ module Render
237
237
  def render(path)
238
238
  Logger.debug "Rendering '#{path}'." if $DBG
239
239
 
240
- klass, action, content_type, base = @context.dispatcher.dispatch(path, @context)
240
+ klass, action, base = @context.dispatcher.dispatch(path, @context)
241
241
 
242
- @context.content_type = content_type
242
+ # FIXME:
243
+ @context.content_type = klass.instance_variable_get('@content_type') || 'text/html'
243
244
 
244
245
  raise 'No controller for action' unless klass
245
246
 
@@ -1,11 +1,12 @@
1
1
  # * George Moschovitis <gm@navel.gr>
2
2
  # (c) 2004-2005 Navel, all rights reserved.
3
- # $Id: nitro.rb 167 2004-11-23 14:03:10Z gmosx $
3
+ # $Id: request.rb 9 2005-04-13 00:08:20Z nasis $
4
4
 
5
- module N
5
+ module Nitro
6
6
 
7
7
  # Encapsulates a request. This is an abstract request
8
- # typically extended by sub-classes.
8
+ # typically extended by sub-classes. This module
9
+ # is included in Context
9
10
 
10
11
  module Request
11
12
 
@@ -51,7 +52,7 @@ module Request
51
52
 
52
53
  # The path is the uri without the query string.
53
54
 
54
- def path
55
+ def path
55
56
  path = uri ? uri.split('?').first : ''
56
57
  end
57
58
 
@@ -91,7 +92,7 @@ module Request
91
92
  end
92
93
 
93
94
  # The remote IP address. REMOTE_ADDR is the standard
94
- # but will fail if the user is behind a proxy.
95
+ # but will fail if the user is behind a proxy.
95
96
  # HTTP_CLIENT_IP and/or HTTP_X_FORWARDED_FOR are set by
96
97
  # proxies so check for these before falling back to
97
98
  # REMOTE_ADDR. HTTP_X_FORWARDED_FOR may be a comma-delimited
@@ -101,7 +102,7 @@ module Request
101
102
  def remote_ip
102
103
  return @headers['HTTP_CLIENT_IP'] if @headers.include?('HTTP_CLIENT_IP')
103
104
 
104
- if @headers.include?('HTTP_X_FORWARDED_FOR') then
105
+ if @headers.include?('HTTP_X_FORWARDED_FOR') then
105
106
  remote_ips = @headers['HTTP_X_FORWARDED_FOR'].split(',').reject do |ip|
106
107
  ip =~ /^unknown$|^(10|172\.16|192\.168)\./i
107
108
  end
@@ -1,10 +1,10 @@
1
1
  # * George Moschovitis <gm@navel.gr>
2
2
  # (c) 2004-2005 Navel, all rights reserved.
3
- # $Id: nitro.rb 167 2004-11-23 14:03:10Z gmosx $
3
+ # $Id: response.rb 1 2005-04-11 11:04:30Z gmosx $
4
4
 
5
- module N
5
+ module Nitro
6
6
 
7
- # HTTP Response.
7
+ # HTTP Response. This module is included in Context.
8
8
 
9
9
  module Response
10
10
 
@@ -27,9 +27,18 @@ module Response
27
27
  # Add a cookie to the response. Better use this
28
28
  # method to avoid precreating the cookies array
29
29
  # for every request.
30
+ #
31
+ # === Examples
32
+ #
33
+ # add_cookie('nsid', 'gmosx')
34
+ # add_cookie(Cookie.new('nsid', 'gmosx')
30
35
 
31
- def add_cookie(cookie)
32
- (@response_cookies ||= []) << cookie
36
+ def add_cookie(cookie, value = nil)
37
+ if value
38
+ (@response_cookies ||= []) << Cookie.new(cookie, value)
39
+ else
40
+ (@response_cookies ||= []) << cookie
41
+ end
33
42
  end
34
43
  alias_method :send_cookie, :add_cookie
35
44
 
@@ -1,8 +1,8 @@
1
1
  # * George Moschovitis <gm@navel.gr>
2
2
  # (c) 2004-2005 Navel, all rights reserved.
3
- # $Id: routing.rb 271 2005-03-07 17:56:45Z gmosx $
3
+ # $Id: routing.rb 1 2005-04-11 11:04:30Z gmosx $
4
4
 
5
- module N
5
+ module Nitro
6
6
 
7
7
  # Router mixin.
8
8
 
@@ -1,15 +1,16 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
3
  # * George Moschovitis <gm@navel.gr>
4
+ # * James Britt <james_b@neurogami.com>
4
5
  # (c) 2004-2005 Navel, all rights reserved.
5
- # $Id$
6
+ # $Id: runner.rb 9 2005-04-13 00:08:20Z nasis $
6
7
 
7
8
  require 'optparse'
8
9
 
9
10
  require 'glue/misc'
10
11
  require 'nitro/conf'
11
12
 
12
- module N
13
+ module Nitro
13
14
 
14
15
  # The Runner is a helper class that encapsulates a web
15
16
  # application and is responsible for launching the
@@ -126,15 +127,20 @@ class Runner
126
127
  Logger.set(Logger.new('log/app.log'))
127
128
  end
128
129
 
130
+ opts.on('--apache-cgi', 'Run as CGI (Apache)') do
131
+ @server = :cgi
132
+ Logger.set(Logger.new('log/app.log'))
133
+ end
134
+
129
135
  opts.on('-C', '--console', 'Start a console attached to an instance of the application.') do
130
136
  if RUBY_PLATFORM =~ /mswin32/
131
- irb_name = 'irb.bat'
132
- else
133
- irb_name = 'irb'
137
+ irb_name = 'irb.bat'
138
+ else
139
+ irb_name = 'irb'
134
140
  end
135
141
  ENV['NITRO_INVOKE'] = 'irb'
136
142
  conf_file = File.basename(caller.last.split(':').first)
137
- exec "#{irb_name} -r #{conf_file} -r irb/completion --noinspect"
143
+ exec "#{irb_name} -r #{conf_file} -r irb/completion --noinspect"
138
144
  exit
139
145
  end
140
146
 
@@ -187,6 +193,8 @@ class Runner
187
193
 
188
194
  if 'fcgi_proc' == ENV['NITRO_INVOKE']
189
195
  invoke_fcgi_proc(conf)
196
+ elsif 'cgi_proc' == ENV['NITRO_INVOKE']
197
+ invoke_cgi_proc(conf)
190
198
  elsif 'irb' == ENV['NITRO_INVOKE']
191
199
  invoke_irb(conf)
192
200
  else
@@ -218,6 +226,11 @@ class Runner
218
226
  FastCGI.start(conf)
219
227
  end
220
228
 
229
+ def invoke_cgi_proc(conf)
230
+ require 'nitro/adapters/cgi'
231
+ Cgi.start(conf)
232
+ end
233
+
221
234
  def invoke_irb(conf)
222
235
  $conf = conf
223
236
  end
@@ -244,17 +257,20 @@ class Runner
244
257
  puts "\n==> Listening at #{conf.host}:#{conf.port}.\n\n"
245
258
 
246
259
  case @server
247
- when :webrick
248
- require 'nitro/adapters/webrick'
249
- Webrick.start(conf)
250
-
251
- when :lhttpd
252
- require 'nitro/adapters/fastcgi'
253
- `lighttpd -f conf/lhttpd.conf`
254
-
255
- when :apache
256
- require 'nitro/adapters/fastcgi'
257
- `apachectl -d #{Dir.pwd} -f conf/apache.conf -k start`
260
+ when :webrick
261
+ require 'nitro/adapters/webrick'
262
+ Webrick.start(conf)
263
+
264
+ when :lhttpd
265
+ require 'nitro/adapters/fastcgi'
266
+ `lighttpd -f conf/lhttpd.conf`
267
+
268
+ when :apache
269
+ require 'nitro/adapters/fastcgi'
270
+ `apachectl -d #{Dir.pwd} -f conf/apache.conf -k start`
271
+
272
+ when :cgi
273
+ require 'nitro/adapters/cgi'
258
274
  end
259
275
 
260
276
  when :stop
@@ -279,4 +295,28 @@ class Runner
279
295
 
280
296
  end
281
297
 
298
+ # Helper method to start applications.
299
+ #
300
+ # === Example
301
+ #
302
+ # Nitro.run do |conf|
303
+ # conf.port = 8080
304
+ # conf.template_root = 'root'
305
+ # end
306
+ #
307
+ # Nitro.run do |conf|
308
+ # conf.update(
309
+ # :template_root => root,
310
+ # :port => 8080
311
+ # )
312
+ # end
313
+
314
+ def self.run(conf = nil)
315
+ runner = Runner.new.setup
316
+ conf ||= Conf.new({})
317
+ $nitro_environment = conf
318
+ yield(conf) if block_given?
319
+ runner.run(conf)
320
+ end
321
+
282
322
  end
@@ -1,10 +1,16 @@
1
1
  # * George Moschovitis <gm@navel.gr>
2
2
  # (c) 2004-2005 Navel, all rights reserved.
3
- # $Id: scaffold.rb 335 2005-03-31 14:02:02Z gmosx $
3
+ # $Id: scaffold.rb 1 2005-04-11 11:04:30Z gmosx $
4
4
 
5
5
  require 'glue/inflector'
6
6
 
7
- module N
7
+ module Nitro
8
+
9
+ # The scaffolder adds default actions to a Controller.
10
+ #--
11
+ # FIXME: handle controller base in generated routes.
12
+ # FIXME: better handle templates (check if action exists).
13
+ #++
8
14
 
9
15
  module Scaffolding
10
16
 
@@ -21,16 +27,16 @@ module Scaffolding
21
27
  def scaffold(klass, options = {})
22
28
 
23
29
  oid = options[:oid] || 'oid'
24
- name = options[:name] || N::Inflector.name(klass.name)
25
- list_name = options[:list_name] || N::Inflector.plural_name(name)
30
+ name = options[:name] || Inflector.name(klass.name)
31
+ list_name = options[:list_name] || Inflector.plural_name(name)
26
32
  options[:nosuffix] ? suffix = nil : suffix = "_#{name}"
27
33
 
28
34
  # Add methods to the scaffolded class.
29
35
 
30
36
  klass.module_eval %{
31
37
  def view_uri
32
- # "view#{suffix}?oid=\#\{@oid\}"
33
- "view#{suffix}/\#\{@oid\}"
38
+ "view#{suffix}?oid=\#\{@oid\}"
39
+ # "view#{suffix}/\#\{@oid\}"
34
40
  end
35
41
  }
36
42
 
@@ -86,7 +92,7 @@ module Scaffolding
86
92
  def list#{suffix}
87
93
  @#{list_name} = #{klass}.all('ORDER BY oid')
88
94
  }
89
- unless Rendering.template_for_action(self.template_root, "form#{suffix}")
95
+ unless Rendering.template_for_action(self.template_root, "list#{suffix}")
90
96
  code << %{
91
97
  o.ul {
92
98
  for item in @#{list_name}
@@ -102,7 +108,7 @@ module Scaffolding
102
108
  # @#{name} = #{klass}[@context['#{oid}']]
103
109
  @#{name} = #{klass}[@#{oid}]
104
110
  end
105
- action :view#{suffix}, :route => \%r\{view#{suffix}/(.*)\}, 'oid' => 1
111
+ action :view#{suffix}, :route => \%r\{#{@base}/view#{suffix}/(.*)\}, 'oid' => 1
106
112
 
107
113
  def save#{suffix}
108
114
  if oid = request['oid']
@@ -1,6 +1,6 @@
1
1
  # * George Moschovitis <gm@navel.gr>
2
2
  # (c) 2004-2005 Navel, all rights reserved.
3
- # $Id$
3
+ # $Id: session.rb 1 2005-04-11 11:04:30Z gmosx $
4
4
 
5
5
  require 'md5'
6
6
  require 'webrick'
@@ -9,7 +9,7 @@ require 'glue/hash'
9
9
  require 'glue/attribute'
10
10
  require 'nitro/cookie'
11
11
 
12
- module N
12
+ module Nitro
13
13
 
14
14
  # A web application session.
15
15
  #
@@ -35,7 +35,7 @@ class Session < Hash
35
35
  # The sessions store. By default sessions are
36
36
  # stored in memory.
37
37
 
38
- cattr_accessor :store; @@store = N::SafeHash.new
38
+ cattr_accessor :store; @@store = Glue::SafeHash.new
39
39
 
40
40
  # Set the session store. The following options are
41
41
  # available:
@@ -47,7 +47,10 @@ class Session < Hash
47
47
  # * :file (not available yet)
48
48
 
49
49
  def self.store_type=(store_type)
50
- require "nitro/session/#{store_type}"
50
+ # gmosx: RDoc complains about this, so lets use an
51
+ # eval, AAAAAAAARGH!
52
+ # require "nitro/session/#{store_type}"
53
+ eval %{ require 'nitro/session/#{store_type}' }
51
54
  end
52
55
 
53
56
  # Lookup the session in the store by using the session