nitro 0.28.0 → 0.29.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) hide show
  1. data/CHANGELOG +382 -0
  2. data/ProjectInfo +4 -4
  3. data/README +1 -1
  4. data/doc/AUTHORS +15 -15
  5. data/doc/MIGRATION +13 -0
  6. data/doc/RELEASES +102 -0
  7. data/lib/glue/sweeper.rb +1 -1
  8. data/lib/nitro.rb +38 -9
  9. data/lib/nitro/adapter/acgi.rb +1 -3
  10. data/lib/nitro/adapter/cgi.rb +1 -1
  11. data/lib/nitro/adapter/fastcgi.rb +1 -3
  12. data/lib/nitro/adapter/mongrel.rb +8 -6
  13. data/lib/nitro/adapter/webrick.rb +1 -2
  14. data/lib/nitro/cgi.rb +1 -1
  15. data/lib/nitro/compiler.rb +21 -40
  16. data/lib/nitro/compiler/elements.rb +72 -32
  17. data/lib/nitro/compiler/errors.rb +92 -42
  18. data/lib/nitro/compiler/include.rb +47 -17
  19. data/lib/nitro/compiler/morphing.rb +1 -3
  20. data/lib/nitro/compiler/script.rb +2 -2
  21. data/lib/nitro/context.rb +36 -0
  22. data/lib/nitro/controller.rb +140 -31
  23. data/lib/nitro/dispatcher.rb +27 -28
  24. data/lib/nitro/element.rb +52 -15
  25. data/lib/nitro/flash.rb +44 -0
  26. data/lib/nitro/helper/buffer.rb +0 -2
  27. data/lib/nitro/helper/form.rb +2 -2
  28. data/lib/nitro/helper/form/controls.rb +14 -3
  29. data/lib/nitro/helper/pager.rb +1 -1
  30. data/lib/nitro/helper/table.rb +4 -3
  31. data/lib/nitro/helper/xml.rb +1 -1
  32. data/lib/nitro/part.rb +20 -0
  33. data/lib/nitro/render.rb +44 -5
  34. data/lib/nitro/router.rb +81 -0
  35. data/lib/nitro/scaffolding.rb +24 -23
  36. data/lib/nitro/server.rb +12 -1
  37. data/lib/nitro/server/runner.rb +12 -0
  38. data/lib/nitro/session.rb +3 -12
  39. data/lib/nitro/session/drb.rb +2 -5
  40. data/lib/nitro/session/file.rb +2 -2
  41. data/lib/nitro/session/memcached.rb +14 -0
  42. data/lib/nitro/session/memory.rb +3 -26
  43. data/lib/nitro/session/og.rb +1 -1
  44. data/lib/nitro/test/assertions.rb +1 -1
  45. data/lib/nitro/test/context.rb +8 -2
  46. data/lib/nitro/test/testcase.rb +16 -7
  47. data/proto/public/error.xhtml +58 -21
  48. data/proto/public/js/controls.js +60 -15
  49. data/proto/public/js/dragdrop.js +105 -16
  50. data/proto/public/js/effects.js +19 -12
  51. data/proto/public/js/scriptaculous.js +1 -1
  52. data/proto/public/js/slider.js +2 -2
  53. data/proto/public/js/unittest.js +29 -20
  54. data/proto/public/scaffold/edit.xhtml +1 -1
  55. data/proto/public/scaffold/index.xhtml +2 -2
  56. data/proto/public/scaffold/list.xhtml +2 -2
  57. data/proto/public/scaffold/new.xhtml +1 -1
  58. data/proto/public/scaffold/search.xhtml +1 -1
  59. data/src/part/admin/controller.rb +5 -5
  60. data/src/part/admin/template/index.xhtml +2 -2
  61. data/test/nitro/compiler/tc_compiler.rb +23 -0
  62. data/test/nitro/helper/tc_table.rb +35 -0
  63. data/test/nitro/tc_cgi.rb +1 -1
  64. data/test/nitro/tc_controller.rb +3 -3
  65. data/test/nitro/tc_controller_aspect.rb +2 -0
  66. data/test/nitro/tc_dispatcher.rb +10 -1
  67. data/test/nitro/tc_flash.rb +14 -0
  68. data/test/nitro/tc_router.rb +58 -0
  69. data/test/nitro/tc_session.rb +26 -9
  70. metadata +13 -12
  71. data/lib/nitro/routing.rb +0 -41
  72. data/test/nitro/caching/tc_stores.rb +0 -17
  73. data/test/nitro/tc_table.rb +0 -66
@@ -10,6 +10,19 @@ For more help, send your question to the mailing list:
10
10
  http://rubyforge.org/mailman/listinfo/nitro-general
11
11
 
12
12
 
13
+ == 0.29.0 <- 0.28.0
14
+
15
+ 1. Please notice that Tag now resides in the Glue namespace, you
16
+ will probably have to update your tables.
17
+
18
+ 2. You have to be more careful with the hrefs you pass to
19
+ <render > and <?include ?>. Some times you have to pass
20
+ absolute paths (ie /this/is/my path) to get the correct
21
+ behaviour. Nitro is more strict in this version.
22
+
23
+ 3. The routing rule format has changed slightly.
24
+
25
+
13
26
  == 0.27.0 <- 0.26.0
14
27
 
15
28
  1. If you use a custom compiler pipeline, notice that the interface
@@ -1,3 +1,105 @@
1
+ == Version 0.29.0
2
+
3
+ A bold step towards maturity. Great care was taken to
4
+ fix reported bugs and fine tune many aspects of Nitro and Og.
5
+ As always some great new features where added. Special thanks fly
6
+ to Jonas Pfenniger, Bryan Sotto, Rob Pitt and Guillaume
7
+ Pierronnet for making this release possible.
8
+
9
+ Most notable changes:
10
+
11
+ * Greatly improved error detection and report. Nitro now provides
12
+ line exact error reports at compile or run time, in actions
13
+ or templates. Stay tuned for more improvements in error
14
+ handling.
15
+
16
+ * Nitro now supports a very useful url endoding/decoding system
17
+ along with a Camping inspired R operator. This new system allows
18
+ you to refer to controllers and actions in your code, without
19
+ bothering about the enforced nice urls and rewrite/routing
20
+ rules. This allows you to write more robust code.
21
+
22
+ Here are some examples:
23
+
24
+ redirect R(UsersController, :login, :name, 'gmosx')
25
+ <a href="#{R(ForaController, :delete, :id, 3)}">delete</a>
26
+
27
+ some more helpers and better integration of this feature
28
+ will be available soon.
29
+
30
+ * To better support the URL codec, a new router was implemented.
31
+ The new version is both more powerfull and faster. Here are
32
+ some examples:
33
+
34
+ r.add_route(%r{rewritten/url/(.*)}, :controller => IdController, :action => :register, :param => :name)
35
+ r.add_route(%r{another/zelo/(.*)/(.*)}, :controller => AdminController, :action => :kick, :params => [:name, :age])
36
+ r.add_route(%r{cool/(.*)_(.*).html}, :controller => AdminController, :action => :long, :params => [:name, :age])
37
+
38
+ * Og now supports calculations and aggregations. Here are some
39
+ examples:
40
+
41
+ User.min(:age)
42
+ User.average(:age)
43
+ User.maximum(:age)
44
+ User.min(:age, :group => :profession) # => [..] (aggregation)
45
+ User.sum(:age, :group => :role) # => [..]
46
+
47
+ and more!
48
+
49
+ * Improved template_root handling. Now Nitro automatically generates
50
+ a template_root stack for each controller / publishable object.
51
+ Of course the developer can fully customize this stack.
52
+ This is great for reusable modules of functionality (parts). Lets
53
+ say you have implemented a forum part. When you 'mount' the
54
+ forum controller a path relative to the mount point is pushed
55
+ in the template_root stack. When the dispatcher searches for
56
+ a template, it traverses the stack. In the described scenario
57
+ it first looks in the application template root, next in a template
58
+ root the points inside the part template root and then in the
59
+ proto dir template root. The proto dir template root is automatically
60
+ pushed as the last root in the stack. This system facilitates
61
+ 'object oriented sites'.
62
+
63
+ Use the following method to customize the template_root.
64
+
65
+ def self.setup_template_root(path)
66
+ ...
67
+ end
68
+
69
+ * Added support for JSP like application scoped (global)
70
+ variables.
71
+
72
+ def login
73
+ ...
74
+ global[:users] << current_user
75
+ application[:users] << current_user
76
+ ...
77
+ end
78
+
79
+ The global/application hash is backed by any of the available
80
+ cache stores.
81
+
82
+ * Improved Taggable mixin, now provides more helpers and supports
83
+ tag garbage collection through reference counting.
84
+
85
+ * Added a new store for the generalized caching system that is
86
+ backed by a MemCache server. Useful to extract the last ounch
87
+ of performance in a production environment.
88
+
89
+ * Fixes in the SCGI adapter.
90
+
91
+ * Many Og bug fixes and optimizations.
92
+
93
+ * More flexible static include compiler.
94
+
95
+ * Improved testing support.
96
+
97
+ * Integrated latest versions of Scriptaculous and Facets.
98
+
99
+ * Many, many bug fixes and small improvements throughout the
100
+ code.
101
+
102
+
1
103
  == Version 0.28.0
2
104
 
3
105
  A snapshot of the latest developments. As always, cool new
@@ -12,7 +12,7 @@ module Glue
12
12
  #++
13
13
 
14
14
  module Sweeper
15
- include Aspects
15
+ include Glue::Aspects
16
16
 
17
17
  before "sweep_affected(:insert)", :on => :og_insert
18
18
  before "sweep_affected(:update)", :on => :og_update
@@ -16,7 +16,7 @@ module Nitro
16
16
 
17
17
  # The version.
18
18
 
19
- Version = '0.28.0'
19
+ Version = '0.29.0'
20
20
 
21
21
  # Library path.
22
22
 
@@ -29,6 +29,10 @@ module Nitro
29
29
  # Add the src dir in the path.
30
30
 
31
31
  $LOAD_PATH.unshift File.join(LibPath, '..', 'src')
32
+
33
+ # Include the Glue namespace in Nitro
34
+
35
+ include Glue
32
36
  end
33
37
 
34
38
  #--
@@ -40,6 +44,7 @@ require 'nitro/controller'
40
44
  require 'nitro/dispatcher'
41
45
  require 'nitro/render'
42
46
  require 'nitro/server'
47
+ require 'nitro/part'
43
48
 
44
49
  unless $NITRO_NO_ENVIRONMENT
45
50
  # Setup up the proposed environment. You are free
@@ -49,18 +54,17 @@ unless $NITRO_NO_ENVIRONMENT
49
54
  #
50
55
  # before requiring nitro.
51
56
 
52
- # if $0 # mod_ruby set $0 to false
53
- # Put the start file dir in the path.
54
- Dir.chdir(File.dirname($0))
57
+ # Put the start file dir in the path.
55
58
 
56
- # Application code come here.
59
+ Dir.chdir(File.dirname($0))
57
60
 
58
- $LOAD_PATH.unshift 'src'
61
+ # Application code come here.
59
62
 
60
- # Library code come here.
63
+ $LOAD_PATH.unshift 'src'
61
64
 
62
- $LOAD_PATH.unshift 'lib'
63
- # end
65
+ # Library code come here.
66
+
67
+ $LOAD_PATH.unshift 'lib'
64
68
  end
65
69
 
66
70
  module Nitro
@@ -73,6 +77,31 @@ module Nitro
73
77
  Server.run(controller)
74
78
  end
75
79
  alias_method :start, :run
80
+
81
+ # A helper to get the current execution mode.
82
+
83
+ def mode
84
+ Runner.mode
85
+ end
86
+ alias_method :execution_mode, :mode
87
+
88
+
89
+ # A helper method.
90
+
91
+ def live?
92
+ Runner.mode == :live
93
+ end
94
+ alias_method :production?, :live?
95
+
76
96
  end
97
+
98
+ # Cache for application scoped (global) variables. This is a
99
+ # temporal store, will be moved to the actuall cache in
100
+ # Server.start
101
+
102
+ $global = $application = {}
77
103
 
78
104
  end
105
+
106
+
107
+ # * George Moschovitis <gm@navel.gr>
@@ -8,15 +8,13 @@ require 'nitro/context'
8
8
  require 'nitro/dispatcher'
9
9
  require 'nitro/cgi'
10
10
 
11
- require 'glue/flexob'
12
-
13
11
  # Speeds things up, more comaptible with OSX.
14
12
 
15
13
  Socket.do_not_reverse_lookup = true
16
14
 
17
15
  # No multi-threading.
18
16
 
19
- Og.thread_safe = false
17
+ Og.thread_safe = false if defined?(Og) and Og.respond_to?(:thread_safe)
20
18
 
21
19
  module Nitro
22
20
 
@@ -18,7 +18,7 @@ Socket.do_not_reverse_lookup = true
18
18
 
19
19
  # No multi-threading.
20
20
 
21
- Og.thread_safe = false
21
+ Og.thread_safe = false if defined?(Og) and Og.respond_to?(:thread_safe)
22
22
 
23
23
  module Nitro
24
24
 
@@ -5,15 +5,13 @@ require 'nitro/context'
5
5
  require 'nitro/dispatcher'
6
6
  require 'nitro/cgi'
7
7
 
8
- require 'glue/flexob'
9
-
10
8
  # Speeds things up, more comaptible with OSX.
11
9
 
12
10
  Socket.do_not_reverse_lookup = true
13
11
 
14
12
  # No multi-threading.
15
13
 
16
- Og.thread_safe = false
14
+ Og.thread_safe = false if defined?(Og) and Og.respond_to?(:thread_safe)
17
15
 
18
16
  module Nitro
19
17
 
@@ -1,8 +1,8 @@
1
1
  require 'stringio'
2
2
 
3
3
  require 'mongrel'
4
+ require 'mongrel/handlers'
4
5
 
5
- require 'glue/flexob'
6
6
  require 'nitro/cgi'
7
7
  require 'nitro/context'
8
8
  require 'nitro/dispatcher'
@@ -58,7 +58,8 @@ class Mongrel
58
58
 
59
59
  initialize_mongrel(server)
60
60
 
61
- @mongrel_thread = @mongrel.run
61
+ @mongrel.run
62
+ @mongrel_thread = @mongrel.acceptor
62
63
  @mongrel_thread.join
63
64
  end
64
65
 
@@ -93,7 +94,7 @@ class MongrelAdapter < ::Mongrel::HttpHandler
93
94
  attr_accessor :server
94
95
 
95
96
  STATUS_CODES = {
96
- 200 => "OK", "304" => "Not Modified",
97
+ "200" => "OK", "304" => "Not Modified",
97
98
  "404" => "Not found", "500" => "Server Error"
98
99
  }
99
100
 
@@ -112,12 +113,13 @@ class MongrelAdapter < ::Mongrel::HttpHandler
112
113
  rewrite(req)
113
114
  # TODO handle If-Modified-Since and add Last-Modified headers
114
115
  filename = [@server.public_root, req.path_info].join("/")
115
- File.open(filename, "r") { |f|
116
- # TODO look up mime type
116
+ ext = File.extname(filename)
117
+ content_type = ::Mongrel::DirHandler::MIME_TYPES[ext] || "text/plain"
118
+ File.open(filename, "rb") { |f|
117
119
  # TODO check whether path circumvents public_root directory?
118
120
  size = File.size(filename)
119
121
  res.socket << "HTTP/1.1 200 OK\r\n"
120
- res.socket << "Content-type: text/plain\r\n"
122
+ res.socket << "Content-type: #{content_type}\r\n"
121
123
  res.socket << "Content-length: #{size}\r\n"
122
124
  res.socket << "\r\n"
123
125
  res.socket << f.read # XXX inefficient for large files, may cause leaks
@@ -1,7 +1,6 @@
1
1
  require 'webrick'
2
2
  require 'stringio'
3
3
 
4
- require 'glue/flexob'
5
4
  require 'nitro/cgi'
6
5
  require 'nitro/context'
7
6
  require 'nitro/dispatcher'
@@ -141,8 +140,8 @@ class WebrickAdapter < WEBrick::HTTPServlet::AbstractServlet
141
140
  context.headers.update(req.meta_vars)
142
141
 
143
142
  # gmosx: make compatible with fastcgi.
143
+
144
144
  context.headers['REQUEST_URI'].slice!(/http:\/\/(.*?)\//)
145
- # context.headers['REQUEST_URI'] << '/'
146
145
  context.headers['REQUEST_URI'] = '/' + context.headers['REQUEST_URI']
147
146
 
148
147
  Cgi.parse_params(context)
@@ -70,7 +70,7 @@ class Cgi
70
70
  params[$1] = structure_param(params[$1], $2, val)
71
71
  elsif key =~ /(.+)\[\]$/
72
72
  params[$1] ||= Array.new
73
- params[$1] << val
73
+ params[$1] << val.to_s
74
74
  else
75
75
  params[key] = val.nil? ? nil : val
76
76
  end
@@ -1,7 +1,8 @@
1
1
  require 'glue/template'
2
2
 
3
- require 'nitro/compiler/elements'
4
3
  require 'nitro/compiler/errors'
4
+
5
+ require 'nitro/compiler/elements'
5
6
  require 'nitro/compiler/markup'
6
7
  require 'nitro/compiler/morphing'
7
8
  require 'nitro/compiler/script'
@@ -44,31 +45,17 @@ class Compiler
44
45
  @shared = {}
45
46
  end
46
47
 
48
+ # Traverse the template_root stack to find a template for
49
+ # this action.
50
+ #
47
51
  # Action names with double underscores (__) are converted
48
52
  # to subdirectories. Here are some example mappings:
49
53
  #
50
54
  # hello_world -> template_root/hello_world.xhtml
51
55
  # this__is__my__hello_world -> template_root/this/is/my/hello_world
52
56
 
53
- def template_for_action(action, ext = Template.extension)
54
- cklass = @controller
55
- template_root = nil
56
- checked_proto = nil
57
-
58
- # search for template in controller and its ancestors's template_root
59
- # if there is not an action defined in controller then also check in
60
- # PROTO_TEMPLATE_ROOT
61
-
62
- loop do
63
- if cklass.respond_to?(:template_root) && template_root = cklass.template_root
64
- cklass = cklass.superclass
65
- elsif !@controller.respond_to?(:action) && !checked_proto
66
- template_root = PROTO_TEMPLATE_ROOT
67
- checked_proto = true
68
- else
69
- return nil # no template found
70
- end
71
-
57
+ def template_for_action(action, ext = Glue::Template.extension)
58
+ for template_root in @controller.instance_variable_get(:@template_root)
72
59
  # attempt to find a template of the form
73
60
  # template_root/action.xhtml
74
61
 
@@ -78,9 +65,10 @@ class Compiler
78
65
  # attempt to find a template of the form
79
66
  # template_root/action/index.xhtml
80
67
 
81
- path = "#{template_root}/#{action.gsub(/__/, '/')}/#{Template.default}.#{ext}".squeeze('/')
68
+ path = "#{template_root}/#{action.gsub(/__/, '/')}/#{Glue::Template.default}.#{ext}".squeeze('/')
82
69
  return path if File.exist?(path)
83
70
  end
71
+ return nil
84
72
  end
85
73
  alias_method :template?, :template_for_action
86
74
 
@@ -100,7 +88,7 @@ class Compiler
100
88
  # Morphing, Elements and Markup compiler modules.
101
89
 
102
90
  def transform_template(template)
103
- template = StaticInclude.transform(template)
91
+ template = StaticInclude.transform(template, self)
104
92
  template = Morphing.transform(template, self)
105
93
  # template = LayoutCompiler.transform(template, self)
106
94
  template = Elements.transform(template, self)
@@ -124,12 +112,8 @@ class Compiler
124
112
  #{transform_template(template)}
125
113
  end
126
114
  }
127
-
128
- begin
129
- @controller.class_eval(code, path)
130
- rescue SyntaxError => e
131
- raise TemplateCompileError.new(code, template, e)
132
- end
115
+
116
+ @controller.class_eval(code, path)
133
117
  end
134
118
 
135
119
  # Compiles an action. The generated action combines the
@@ -150,7 +134,7 @@ class Compiler
150
134
  #
151
135
  # This generated method is called by the dispatcher.
152
136
  #
153
- # === Template root overloading
137
+ # === Glue::Template root overloading
154
138
  #
155
139
  # Nitro provides a nice method of template_root overloading
156
140
  # that allows you to use OOP principles with templates.
@@ -187,7 +171,7 @@ class Compiler
187
171
 
188
172
  # Inject the pre advices.
189
173
 
190
- code << Aspects.gen_advice_code(action, @controller.advices, :pre)
174
+ code << Glue::Aspects.gen_advice_code(action, @controller.advices, :pre)
191
175
 
192
176
  # Call the action
193
177
 
@@ -204,7 +188,7 @@ class Compiler
204
188
  # Try to resolve action parameters. Returns negative
205
189
  # numbers for arbitrary parameters.
206
190
 
207
- param_count = @controller.instance_method(action.intern).arity
191
+ param_count = @controller.instance_method(action.to_sym).arity
208
192
 
209
193
  if param_count != 0
210
194
  if param_count > 0
@@ -224,7 +208,7 @@ class Compiler
224
208
  end
225
209
  code << %{
226
210
  break if qs.index('=') and not is_hash
227
- params[i] = CGI.unescape(qs.split(/=/).last)
211
+ params[i] = CGI.unescape(qs.split(/=/).last || "")
228
212
  end
229
213
  end
230
214
  action_return_value = #{action}(*params)
@@ -283,7 +267,7 @@ class Compiler
283
267
 
284
268
  # Inject the post advices.
285
269
 
286
- code << Aspects.gen_advice_code(action, @controller.advices, :post)
270
+ code << Glue::Aspects.gen_advice_code(action, @controller.advices, :post)
287
271
 
288
272
  code << %{
289
273
  @action_name = @parent_action_name
@@ -292,11 +276,7 @@ class Compiler
292
276
 
293
277
  # First compile the action method.
294
278
 
295
- # begin
296
- @controller.class_eval(code)
297
- # rescue SyntaxError => e
298
- # raise ActionCompileError.new(code, action, e)
299
- # end
279
+ @controller.class_eval(code)
300
280
 
301
281
  unless @controller.respond_to?("#{action}_template")
302
282
  if template_path
@@ -329,12 +309,12 @@ class Compiler
329
309
  # Typically used to precompile css templates.
330
310
 
331
311
  def precompile(filename)
332
- src = File.join(Template.root, "#{filename}t")
312
+ src = File.join(Glue::Template.root, "#{filename}t")
333
313
  dst = File.join(Server.public_root, filename)
334
314
 
335
315
  if (!File.exist?(dst)) or (File.mtime(src) > File.mtime(dst))
336
316
  Logger.info "Compiling template '#{src}' to '#{dst}'."
337
- template = FileTemplate.new(src)
317
+ template = Glue::FileTemplate.new(src)
338
318
  File.open(dst, 'w') do |f|
339
319
  f << template.process
340
320
  end
@@ -349,3 +329,4 @@ end
349
329
 
350
330
  # * George Moschovitis <gm@navel.gr>
351
331
  # * Chris Farmiloe <chris.farmiloe@farmiloe.com>
332
+ # * Rob Pitt <rob@motionpath.co.uk>