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.
- data/CHANGELOG +187 -0
- data/INSTALL +5 -0
- data/README +11 -5
- data/doc/AUTHORS +11 -1
- data/doc/RELEASES +217 -0
- data/doc/tutorial.txt +1 -2
- data/lib/nitro.rb +9 -6
- data/lib/nitro/adapter/webrick.rb +13 -2
- data/lib/nitro/builder/form.rb +11 -9
- data/lib/nitro/builder/rss.rb +2 -2
- data/lib/nitro/builder/xhtml.rb +15 -0
- data/lib/nitro/caching.rb +15 -10
- data/lib/nitro/conf.rb +0 -5
- data/lib/nitro/controller.rb +118 -81
- data/lib/nitro/cookie.rb +6 -6
- data/lib/nitro/dispatcher.rb +62 -18
- data/lib/nitro/element.rb +4 -1
- data/lib/nitro/element/java_script.rb +15 -0
- data/lib/nitro/localization.rb +3 -4
- data/lib/nitro/markup.rb +4 -4
- data/lib/nitro/mixin/debug.rb +30 -0
- data/lib/nitro/mixin/helper.rb +14 -0
- data/lib/nitro/mixin/javascript.rb +137 -0
- data/lib/nitro/{ui → mixin}/pager.rb +110 -82
- data/lib/nitro/render.rb +20 -8
- data/lib/nitro/request.rb +6 -0
- data/lib/nitro/routing.rb +6 -5
- data/lib/nitro/runner.rb +21 -9
- data/lib/nitro/server.rb +95 -0
- data/lib/nitro/service.rb +0 -1
- data/lib/nitro/session.rb +4 -5
- data/lib/nitro/shaders.rb +2 -2
- data/lib/nitro/template.rb +1 -1
- data/lib/nitro/testing/assertions.rb +2 -4
- data/lib/nitro/testing/context.rb +4 -6
- data/proto/public/js/behaviour.js +254 -0
- data/proto/public/js/controls.js +446 -0
- data/proto/public/js/dragdrop.js +537 -0
- data/proto/public/js/effects.js +612 -0
- data/proto/public/js/prototype.js +644 -370
- data/proto/public/settings.xhtml +64 -0
- data/test/nitro/adapter/tc_cgi.rb +2 -2
- data/test/nitro/builder/tc_rss.rb +1 -1
- data/test/nitro/mixin/tc_pager.rb +35 -0
- data/test/nitro/tc_controller.rb +1 -1
- data/test/nitro/tc_cookie.rb +14 -0
- data/test/nitro/tc_dispatcher.rb +11 -6
- data/test/nitro/tc_server.rb +35 -0
- metadata +20 -15
- data/lib/nitro/builder/atom.rb +0 -74
- data/lib/nitro/part.rb +0 -22
- data/lib/nitro/simple.rb +0 -11
- data/lib/nitro/ui/popup.rb +0 -41
- data/lib/nitro/ui/tabs.rb +0 -25
- data/lib/nitro/uri.rb +0 -193
- data/test/nitro/builder/tc_atom.rb +0 -24
- data/test/nitro/tc_uri.rb +0 -97
- 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
|
19
|
-
@
|
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
|
+
|
data/lib/nitro/dispatcher.rb
CHANGED
@@ -1,14 +1,20 @@
|
|
1
|
-
|
1
|
+
require 'facet/object/special_class'
|
2
2
|
|
3
3
|
require 'nitro/controller'
|
4
4
|
require 'nitro/routing'
|
5
|
-
require 'nitro/
|
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 = {
|
49
|
+
controllers = { '/' => controllers }
|
44
50
|
else
|
45
|
-
controllers ||= {
|
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
|
-
#
|
63
|
-
#
|
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
|
-
|
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 =
|
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(
|
152
|
+
klass = controller_class_for(base)
|
109
153
|
action = 'index'
|
110
154
|
|
111
155
|
when 1
|
112
|
-
|
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(
|
163
|
+
klass = controller_class_for(base)
|
120
164
|
action = parts[0]
|
121
165
|
end
|
122
166
|
|
123
167
|
else
|
124
|
-
|
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(
|
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
|
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>
|
data/lib/nitro/localization.rb
CHANGED
@@ -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!(/"/, '"')
|
74
|
-
str.gsub!(/'/, ''')
|
73
|
+
# str.gsub!(/"/, '"')
|
74
|
+
# str.gsub!(/'/, ''')
|
75
75
|
str.gsub!(/</, '<')
|
76
76
|
str.gsub!(/>/, '>')
|
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(" ", " ")}</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>
|