nitro 0.19.0 → 0.20.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 (58) hide show
  1. data/CHANGELOG +187 -0
  2. data/INSTALL +5 -0
  3. data/README +11 -5
  4. data/doc/AUTHORS +11 -1
  5. data/doc/RELEASES +217 -0
  6. data/doc/tutorial.txt +1 -2
  7. data/lib/nitro.rb +9 -6
  8. data/lib/nitro/adapter/webrick.rb +13 -2
  9. data/lib/nitro/builder/form.rb +11 -9
  10. data/lib/nitro/builder/rss.rb +2 -2
  11. data/lib/nitro/builder/xhtml.rb +15 -0
  12. data/lib/nitro/caching.rb +15 -10
  13. data/lib/nitro/conf.rb +0 -5
  14. data/lib/nitro/controller.rb +118 -81
  15. data/lib/nitro/cookie.rb +6 -6
  16. data/lib/nitro/dispatcher.rb +62 -18
  17. data/lib/nitro/element.rb +4 -1
  18. data/lib/nitro/element/java_script.rb +15 -0
  19. data/lib/nitro/localization.rb +3 -4
  20. data/lib/nitro/markup.rb +4 -4
  21. data/lib/nitro/mixin/debug.rb +30 -0
  22. data/lib/nitro/mixin/helper.rb +14 -0
  23. data/lib/nitro/mixin/javascript.rb +137 -0
  24. data/lib/nitro/{ui → mixin}/pager.rb +110 -82
  25. data/lib/nitro/render.rb +20 -8
  26. data/lib/nitro/request.rb +6 -0
  27. data/lib/nitro/routing.rb +6 -5
  28. data/lib/nitro/runner.rb +21 -9
  29. data/lib/nitro/server.rb +95 -0
  30. data/lib/nitro/service.rb +0 -1
  31. data/lib/nitro/session.rb +4 -5
  32. data/lib/nitro/shaders.rb +2 -2
  33. data/lib/nitro/template.rb +1 -1
  34. data/lib/nitro/testing/assertions.rb +2 -4
  35. data/lib/nitro/testing/context.rb +4 -6
  36. data/proto/public/js/behaviour.js +254 -0
  37. data/proto/public/js/controls.js +446 -0
  38. data/proto/public/js/dragdrop.js +537 -0
  39. data/proto/public/js/effects.js +612 -0
  40. data/proto/public/js/prototype.js +644 -370
  41. data/proto/public/settings.xhtml +64 -0
  42. data/test/nitro/adapter/tc_cgi.rb +2 -2
  43. data/test/nitro/builder/tc_rss.rb +1 -1
  44. data/test/nitro/mixin/tc_pager.rb +35 -0
  45. data/test/nitro/tc_controller.rb +1 -1
  46. data/test/nitro/tc_cookie.rb +14 -0
  47. data/test/nitro/tc_dispatcher.rb +11 -6
  48. data/test/nitro/tc_server.rb +35 -0
  49. metadata +20 -15
  50. data/lib/nitro/builder/atom.rb +0 -74
  51. data/lib/nitro/part.rb +0 -22
  52. data/lib/nitro/simple.rb +0 -11
  53. data/lib/nitro/ui/popup.rb +0 -41
  54. data/lib/nitro/ui/tabs.rb +0 -25
  55. data/lib/nitro/uri.rb +0 -193
  56. data/test/nitro/builder/tc_atom.rb +0 -24
  57. data/test/nitro/tc_uri.rb +0 -97
  58. data/test/nitro/ui/tc_pager.rb +0 -49
data/lib/nitro/cookie.rb CHANGED
@@ -1,7 +1,3 @@
1
- # * George Moschovitis <gm@navel.gr>
2
- # (c) 2004-2005 Navel, all rights reserved.
3
- # $Id: cookie.rb 1 2005-04-11 11:04:30Z gmosx $
4
-
5
1
  module Nitro
6
2
 
7
3
  # Encapsulates a HTTP Cookie.
@@ -15,8 +11,9 @@ class Cookie
15
11
  def initialize(name, value)
16
12
  @name = name
17
13
  @value = value
18
- @version = 0 # Netscape Cookie
19
- @domain = @path = @secure = @comment = @max_age =
14
+ @version = 0 # Netscape Cookie
15
+ @path = '/' # gmosx: KEEP this!
16
+ @domain = @secure = @comment = @max_age =
20
17
  @expires = @comment_url = @discard = @port = nil
21
18
  end
22
19
 
@@ -44,3 +41,6 @@ class Cookie
44
41
  end
45
42
 
46
43
  end
44
+
45
+ # * George Moschovitis <gm@navel.gr>
46
+
@@ -1,14 +1,20 @@
1
- module Nitro
1
+ require 'facet/object/special_class'
2
2
 
3
3
  require 'nitro/controller'
4
4
  require 'nitro/routing'
5
- require 'nitro/simple'
5
+ require 'nitro/mixin/helper'
6
+
7
+ module Nitro
6
8
 
7
9
  # The Dispatcher manages a set of controllers.
8
10
 
9
11
  class Dispatcher
10
12
 
11
13
  include Router
14
+
15
+ unless const_defined?('ROOT')
16
+ ROOT = '/'
17
+ end
12
18
 
13
19
  # The public root directory. The files in this
14
20
  # directory are published by the web server.
@@ -40,16 +46,21 @@ class Dispatcher
40
46
  @template_root = @public_root
41
47
 
42
48
  if controllers and controllers.is_a?(Class) and controllers.ancestors.include?(Controller)
43
- controllers = { :root => controllers }
49
+ controllers = { '/' => controllers }
44
50
  else
45
- controllers ||= { :root => SimpleController }
51
+ controllers ||= { '/' => SimpleController }
46
52
  end
47
53
 
48
54
  mount(controllers)
49
55
  end
50
56
 
57
+ # A published object is exposed through a REST interface.
58
+ # Only the public non standard methods of the object are
59
+ # accessible. Published objects implement the Controller
60
+ # part of MVC.
61
+ #
51
62
  # Process the given hash and mount the
52
- # defined controllers.
63
+ # defined classes (controllers).
53
64
  #
54
65
  # Input:
55
66
  #
@@ -59,16 +70,44 @@ class Dispatcher
59
70
  #
60
71
  # === Examples
61
72
  #
62
- # dispatcher.mount(
63
- # :root => MainController, # mounts /
64
- # 'users' => UsersController # mounts /users
73
+ # disp.mount(
74
+ # '/' => MainController, # mounts /
75
+ # '/users' => UsersController # mounts /users
65
76
  # )
77
+ # disp.publish '/' => MainController
66
78
 
67
79
  def add_controller(controllers)
80
+ for c in controllers.values
81
+ unless (c.ancestors.include?(Controller) or c.ancestors.include?(Publishable))
82
+ c.send :include, Publishable
83
+ end
84
+
85
+ auto_mixin(c)
86
+ end
87
+
68
88
  (@controllers ||= {}).update(controllers)
69
- update_routes
89
+
90
+ update_routes()
70
91
  end
71
92
  alias_method :mount, :add_controller
93
+ alias_method :publish, :add_controller
94
+
95
+ # Call this method to automatically include helpers in the
96
+ # Controllers. For each Controller 'XxxController' the
97
+ # default helper 'Helper' and the auto mixin
98
+ # 'XxxControllerMixin' (if it exists) are included.
99
+
100
+ def auto_mixin(c)
101
+ c.helper(Helper)
102
+
103
+ begin
104
+ if helper = Module.by_name("#{c}Mixin")
105
+ c.helper(helper)
106
+ end
107
+ rescue NameError
108
+ # The auto helper is not defined.
109
+ end
110
+ end
72
111
 
73
112
  # Update the routes. Typically called after a new
74
113
  # Controller is mounted.
@@ -76,7 +115,7 @@ class Dispatcher
76
115
  def update_routes
77
116
  @routes = []
78
117
  @controllers.each do |base, c|
79
- base = (base == :root ? '' : "/#{base}")
118
+ base = '' if base == '/'
80
119
  c.action_metadata.each do |action, meta|
81
120
  if route = meta[:route]
82
121
  @routes << [route, "#{base}/#{action}", *meta.params.keys]
@@ -94,6 +133,11 @@ class Dispatcher
94
133
  #
95
134
  # [:context]
96
135
  # The dispatching context.
136
+ #
137
+ #--
138
+ # FIXME: this is a critical method that should be optimized
139
+ # watch out for excessive String creation.
140
+ #++
97
141
 
98
142
  def dispatch(path, context = nil)
99
143
  path = route(path, context)
@@ -105,31 +149,31 @@ class Dispatcher
105
149
  when 0
106
150
  # / -> root.index
107
151
  base = '/'
108
- klass = controller_class_for(:root, context)
152
+ klass = controller_class_for(base)
109
153
  action = 'index'
110
154
 
111
155
  when 1
112
- if klass = controller_class_for(parts[0], context)
156
+ base = "/#{parts[0]}"
157
+ if klass = controller_class_for(base)
113
158
  # controller/ -> controller.index
114
- base = "/#{parts[0]}"
115
159
  action = 'index'
116
160
  else
117
161
  # action/ -> root.action
118
162
  base = '/'
119
- klass = controller_class_for(:root, context)
163
+ klass = controller_class_for(base)
120
164
  action = parts[0]
121
165
  end
122
166
 
123
167
  else
124
- if klass = controller_class_for(parts[0], context)
168
+ base = "/#{parts[0]}"
169
+ if klass = controller_class_for(base)
125
170
  # controller/action -> controller.action
126
- base = "/#{parts[0]}"
127
171
  parts.shift
128
172
  action = parts.join('__')
129
173
  else
130
174
  # action/ -> root.action
131
175
  base = '/'
132
- klass = controller_class_for(:root, context)
176
+ klass = controller_class_for(base)
133
177
  action = parts.join('__')
134
178
  end
135
179
  end
@@ -141,7 +185,7 @@ class Dispatcher
141
185
  # Get the controller for the given key.
142
186
  # Also handles reloading of controllers.
143
187
 
144
- def controller_class_for(key, context)
188
+ def controller_class_for(key)
145
189
  klass = @controllers[key]
146
190
 
147
191
  if klass and (:full == Rendering.reload)
data/lib/nitro/element.rb CHANGED
@@ -144,10 +144,13 @@ class ElementProcessor # :nodoc: all
144
144
  def render(source)
145
145
  listener = Listener.new
146
146
  REXML::Document.parse_stream(source, listener)
147
- # gmosx, FIXME: optimize this, how?
147
+ # gmosx, FIXME: optimize this, how?
148
148
  listener.buffer.gsub! /<(.*) ([^>]*)><\/\1>/, '<\1 \2 />'
149
+ listener.buffer.gsub! /<(.*)><\/\1>/, '<\1 />'
149
150
  return listener.buffer
150
151
  end
151
152
  end
152
153
 
153
154
  end
155
+
156
+ # * George Moschovitis <gm@navel.gr>
@@ -0,0 +1,15 @@
1
+ require 'nitro/element'
2
+
3
+ class JavaScript < Nitro::Element
4
+ def render
5
+ %~
6
+ <script type="text/javascript" language="javascript">
7
+ // <![CDATA[
8
+ #{content}
9
+ // ]]>
10
+ </script>
11
+ ~
12
+ end
13
+ end
14
+
15
+ # * George Moschovitis <gm@navel.gr>
@@ -1,7 +1,3 @@
1
- # * George Moschovitis <gm@navel.gr>
2
- # (c) 2004-2005 Navel, all rights reserved.
3
- # $Id: localization.rb 17 2005-04-14 16:03:40Z gmosx $
4
-
5
1
  require 'yaml'
6
2
 
7
3
  require 'glue/aspects'
@@ -152,3 +148,6 @@ class LocalizationShader < Shader
152
148
  end
153
149
 
154
150
  end
151
+
152
+ # * George Moschovitis <gm@navel.gr>
153
+
data/lib/nitro/markup.rb CHANGED
@@ -70,11 +70,11 @@ end
70
70
  module Markup
71
71
  def self.expand_html!(str)
72
72
  return unless str
73
- str.gsub!(/"/, '&quot;')
74
- str.gsub!(/'/, '&#39;')
73
+ # str.gsub!(/"/, '&quot;')
74
+ # str.gsub!(/'/, '&#39;')
75
75
  str.gsub!(/</, '&lt;')
76
76
  str.gsub!(/>/, '&gt;')
77
- str.gsub!(/\r\n/, ' <br />')
77
+ # str.gsub!(/\r\n/, ' <br />')
78
78
  return str
79
79
  end
80
80
 
@@ -135,7 +135,7 @@ class MarkupShader < Shader
135
135
 
136
136
  def process(hash, text)
137
137
  # handle strings
138
- text.gsub!(/\#\{\{(.*?)\}\}/, '#{RedCloth.new(\1).to_html}')
138
+ text.gsub!(/\#\{\{(.*?)\}\}/, '#{RedCloth.new(Markup.expand(\1)).to_html}')
139
139
 
140
140
  process_next(hash, text)
141
141
  end
@@ -0,0 +1,30 @@
1
+ module Nitro
2
+
3
+ # A collection of useful debuging methods.
4
+
5
+ module DebugMixin
6
+
7
+ private
8
+
9
+ # Returns a <pre>-tag set with the +object+ dumped by YAML.
10
+ # Very readable way to inspect an object.
11
+ #--
12
+ # TODO: make safe html.
13
+ #++
14
+
15
+ def debug(object)
16
+ begin
17
+ Marshal::dump(object)
18
+ "<pre class='debug_dump'>#{object.to_yaml.gsub(" ", "&nbsp; ")}</pre>"
19
+ rescue Object
20
+ # Object couldn't be dumped, perhaps because of singleton
21
+ # methods, this is the fallback.
22
+ "<code class='debug_dump'>#{object.inspect}</code>"
23
+ end
24
+ end
25
+
26
+ end
27
+
28
+ end
29
+
30
+ # * George Moschovitis <gm@navel.gr>
@@ -0,0 +1,14 @@
1
+ require 'nitro/mixin/debug'
2
+
3
+ module Nitro
4
+
5
+ # This mixin is included by default in all Controllers.
6
+ # This is the place to add general purpose utility methods to
7
+ # be shared accross all Controllers.
8
+
9
+ module Helper
10
+ include DebugMixin
11
+ # This is an open module, extend in your application.
12
+ end
13
+
14
+ end
@@ -0,0 +1,137 @@
1
+ module Nitro
2
+
3
+ # A collection of useful Javascript helpers. This modules
4
+ # integrates helpers for the following javascript libraries:
5
+ #
6
+ # * behaviour.js
7
+ # * prototype.js
8
+ # * effects.js
9
+ # * dragdrop.js
10
+ # * controls.js
11
+
12
+ module JavascriptMixin
13
+
14
+ private
15
+
16
+ unless const_defined? :DEFAULT_JAVASCRIPT_FILES
17
+ DEFAULT_JAVASCRIPT_FILES = [
18
+ 'js/behaviour.js',
19
+ 'js/prototype.js',
20
+ 'js/effects.js',
21
+ 'js/dragdrop.js',
22
+ 'js/controls.js'
23
+ ]
24
+ end
25
+
26
+ # :section: behaviour.js
27
+
28
+ def behaviour(id, js)
29
+ @_behaviours ||= []
30
+ @_behaviours << [id, js]
31
+ end
32
+
33
+ # :section: prototype.js
34
+
35
+ def live_request(id, options = {})
36
+ if href = options.delete(:href)
37
+ behaviour "##{id}", %{
38
+ el.onclick = function() {
39
+ new Ajax.Request('#{href}', #{hash_to_js(options)});
40
+ return false;
41
+ }
42
+ }
43
+ else
44
+ behaviour "##{id}", %{
45
+ el.onclick = function() {
46
+ new Ajax.Request(el.href, #{hash_to_js(options)});
47
+ return false;
48
+ }
49
+ }
50
+ end
51
+ end
52
+ alias_method :live, :live_request
53
+ alias_method :async, :live_request
54
+
55
+ # :section: script.aculo.us dragdrop.js
56
+
57
+ # Make the element dragable.
58
+
59
+ def draggable(id, options = {})
60
+ @_javascript ||= ''
61
+ @_javascript << "\nnew Draggable('#{id}', #{hash_to_js(options)});"
62
+ end
63
+
64
+ # :section: script.aculo.us controls.js
65
+
66
+ # Add autocomplete functionality to a text field.
67
+
68
+ def auto_complete(id, options = {})
69
+ update = options[:update] || "#{id}_auto_complete"
70
+ url = options[:url] || "#{id}_auto_complete"
71
+ @_javascript ||= ''
72
+ @_javascript << "\nnew Ajax.Autocompleter('#{id}', '#{update}', '#{url}');"
73
+
74
+ # Turn off the browser's autocomplete functionality to avoid
75
+ # interference.
76
+
77
+ behaviour "##{id}", %{
78
+ el.autocomplete = 'off';
79
+ }
80
+ end
81
+
82
+ # :section: general javascript helpers.
83
+
84
+ # Include external javascript file.
85
+
86
+ def include_script(files = DEFAULT_JAVASCRIPT_FILES)
87
+ code = ''
88
+
89
+ for file in [files].flatten
90
+ code << %|<script src="#{file}" type="text/javascript">//</script>|
91
+ end
92
+
93
+ return code
94
+ end
95
+
96
+ # Escape carrier returns and single and double quotes for JavaScript segments.
97
+
98
+ def escape_javascript(js)
99
+ (js || '').gsub(/\r\n|\n|\r/, "\\n").gsub(/["']/) { |m| "\\#{m}" }
100
+ end
101
+
102
+ # Converts a Ruby hash to a Javascript hash.
103
+
104
+ def hash_to_js(options)
105
+ '{' + options.map {|k, v| "#{k}:#{v}"}.join(', ') + '}'
106
+ end
107
+
108
+ # Emits the aggregated helper javascript.
109
+ #--
110
+ # FIXME: refactor this!
111
+ #++
112
+
113
+ def helper_script
114
+ code = %|<script type="text/javascript">\n|
115
+ unless @_behaviours.empty?
116
+ code << %|var _behaviours = {\n|
117
+ compo = []
118
+ for id, js in @_behaviours
119
+ compo << %|'#{id}': function(el) { #{js} \n }|
120
+ end
121
+ code << compo.join(',')
122
+ code << %|
123
+ }
124
+ Behaviour.register(_behaviours);
125
+ |
126
+ end
127
+ code << %|
128
+ #@_javascript
129
+ </script>
130
+ |
131
+ end
132
+
133
+ end
134
+
135
+ end
136
+
137
+ # * George Moschovitis <gm@navel.gr>