nitro 0.15.0 → 0.16.0

Sign up to get free protection for your applications and to get access to all the features.
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