nitro 0.40.0 → 0.41.0
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/nitro +4 -4
- data/doc/MIGRATION +7 -0
- data/doc/RELEASES +29 -0
- data/doc/TODO +2 -0
- data/lib/glue/webfile.rb +9 -9
- data/lib/nitro/cgi.rb +9 -3
- data/lib/nitro/compiler/elements.rb +8 -0
- data/lib/nitro/compiler/morphing.rb +5 -1
- data/lib/nitro/helper.rb +1 -0
- data/lib/nitro/helper/pager.rb +9 -3
- data/lib/nitro/publishable.rb +9 -1
- data/lib/nitro/render.rb +36 -0
- data/lib/nitro/scaffold/model.rb +3 -3
- data/lib/nitro/server/runner.rb +12 -10
- data/lib/nitro/session.rb +0 -1
- data/lib/nitro/template.rb +16 -15
- data/lib/nitro/util/encode_url.rb +112 -0
- data/lib/nitro/version.rb +1 -1
- data/lib/part/admin/controller.rb +1 -1
- data/lib/part/admin/og/controller.rb +1 -1
- data/test/nitro/tc_cgi.rb +0 -3
- data/test/nitro/tc_helper.rb +11 -0
- data/test/nitro/tc_render.rb +64 -0
- data/test/nitro/tc_template.rb +42 -5
- data/test/nitro/util/tc_encode_url.rb +62 -0
- metadata +9 -5
data/bin/nitro
CHANGED
@@ -84,7 +84,7 @@ class NitroCommand < Console::Command
|
|
84
84
|
ENV['NITRO_INVOKE'] = 'irb'
|
85
85
|
|
86
86
|
if f = application_file
|
87
|
-
ENV['
|
87
|
+
ENV['NITRO_MODE'] = $DBG ? 'debug' : 'live'
|
88
88
|
exec "#{irb_name} -r #{f} -r irb/completion --noinspect"
|
89
89
|
end
|
90
90
|
|
@@ -114,18 +114,18 @@ class NitroCommand < Console::Command
|
|
114
114
|
|
115
115
|
def __debug
|
116
116
|
ARGV.delete('--debug')
|
117
|
-
ENV['
|
117
|
+
ENV['NITRO_MODE'] = 'debug'
|
118
118
|
end
|
119
119
|
alias __devel __debug
|
120
120
|
|
121
121
|
def __stage
|
122
122
|
ARGV.delete('--stage')
|
123
|
-
ENV['
|
123
|
+
ENV['NITRO_MODE'] = 'stage'
|
124
124
|
end
|
125
125
|
|
126
126
|
def __live
|
127
127
|
ARGV.delete('--live')
|
128
|
-
ENV['
|
128
|
+
ENV['NITRO_MODE'] = 'live'
|
129
129
|
end
|
130
130
|
alias __production __live
|
131
131
|
|
data/doc/MIGRATION
CHANGED
@@ -10,6 +10,13 @@ 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.41.0 <- 0.40.0
|
14
|
+
|
15
|
+
This release is backwards compatible with 0.40.0. But please
|
16
|
+
prefer to use the NITRO_MODE env variable instead of the
|
17
|
+
deprecated CONFIGURATION_MODE env variable.
|
18
|
+
|
19
|
+
|
13
20
|
== 0.40.0 <- 0.31.0
|
14
21
|
|
15
22
|
This version was in the making for ages, so there are some changes
|
data/doc/RELEASES
CHANGED
@@ -1,3 +1,32 @@
|
|
1
|
+
== Version 0.41.0
|
2
|
+
|
3
|
+
This is a bug fix release. As it fixes some important bugs of the
|
4
|
+
previous release, including a DOS vulnurability you are strongly
|
5
|
+
advised to update your version. However, you will also find
|
6
|
+
a couple of new features:
|
7
|
+
|
8
|
+
* Extended entity .finder method can now handle relations.
|
9
|
+
|
10
|
+
Post.find_by_title_and_forum_name(title,forumName)
|
11
|
+
|
12
|
+
class Forum
|
13
|
+
property :name, String
|
14
|
+
has_many :posts, Post
|
15
|
+
end
|
16
|
+
|
17
|
+
class Post
|
18
|
+
property :title, String
|
19
|
+
property :message, String
|
20
|
+
belongs_to :forum, Forum
|
21
|
+
end
|
22
|
+
|
23
|
+
'forum' is the :forum from belongs_to, 'name' is a property from the
|
24
|
+
relations. It creates a SQL subquery to find the correct forum_oid.
|
25
|
+
|
26
|
+
* Added a simple call/answer mechanism that may be useful in some
|
27
|
+
cases. Will be improved in future versions.
|
28
|
+
|
29
|
+
|
1
30
|
== Version 0.40.0
|
2
31
|
|
3
32
|
This is the biggest release yet! Tons of new wonderful features,
|
data/doc/TODO
CHANGED
data/lib/glue/webfile.rb
CHANGED
@@ -14,7 +14,7 @@ module Glue
|
|
14
14
|
# File.join(Uploads.public_root, request.user.name, 'icon.png')
|
15
15
|
# end
|
16
16
|
#
|
17
|
-
#
|
17
|
+
# attr_accessor :file, WebFile, :magick => { :small => '64x64', :medium => '96x96' }
|
18
18
|
# end
|
19
19
|
#--
|
20
20
|
# TODO: webfile_path customization sucks, should be improved!
|
@@ -99,12 +99,12 @@ class WebFile
|
|
99
99
|
}
|
100
100
|
else
|
101
101
|
code << %{
|
102
|
-
path = File.join(WebFile.upload_root, param.original_filename)
|
102
|
+
path = File.join(WebFile.upload_root, WebFile.sanitize(param.original_filename))
|
103
103
|
}
|
104
104
|
end
|
105
105
|
|
106
106
|
code << %{
|
107
|
-
@#{name} =
|
107
|
+
@#{name} = path
|
108
108
|
@#{name}_size = param.size
|
109
109
|
|
110
110
|
real_path = #{name}_real_path
|
@@ -144,15 +144,15 @@ class WebFile
|
|
144
144
|
end
|
145
145
|
end
|
146
146
|
|
147
|
-
# Sanitize a filename.
|
148
|
-
|
149
|
-
# TODO: implement me!
|
150
|
-
#++
|
147
|
+
# Sanitize a filename. You can override this method to make
|
148
|
+
# this suit your needs.
|
151
149
|
|
152
150
|
def self.sanitize(filename)
|
153
|
-
filename
|
151
|
+
ext = File::extname(filename)
|
152
|
+
base = File::basename(filename, ext).gsub(/[\\\/\? !@$\(\)]/, '-')[0..64]
|
153
|
+
return "#{base}.#{ext}"
|
154
154
|
end
|
155
|
-
|
155
|
+
|
156
156
|
end
|
157
157
|
|
158
158
|
# An alias, implies thumbnailing.
|
data/lib/nitro/cgi.rb
CHANGED
@@ -214,8 +214,11 @@ class Cgi
|
|
214
214
|
|
215
215
|
params = Hash.new()
|
216
216
|
boundary = "--" + boundary
|
217
|
+
quoted_boundary = Regexp.quote(boundary, "n")
|
217
218
|
buf = ""
|
218
|
-
|
219
|
+
boundary_end=""
|
220
|
+
|
221
|
+
# start multipart/form-data
|
219
222
|
input.binmode if defined? input.binmode
|
220
223
|
boundary_size = boundary.size + EOL.size
|
221
224
|
content_length -= boundary_size
|
@@ -234,6 +237,7 @@ class Cgi
|
|
234
237
|
body = Tempfile.new("CGI")
|
235
238
|
else
|
236
239
|
begin
|
240
|
+
require "stringio"
|
237
241
|
body = StringIO.new
|
238
242
|
rescue LoadError
|
239
243
|
body = Tempfile.new("CGI")
|
@@ -241,7 +245,7 @@ class Cgi
|
|
241
245
|
end
|
242
246
|
body.binmode if defined? body.binmode
|
243
247
|
|
244
|
-
until head and /#{
|
248
|
+
until head and /#{quoted_boundary}(?:#{EOL}|--)/n.match(buf)
|
245
249
|
|
246
250
|
if (not head) and /#{EOL}#{EOL}/n.match(buf)
|
247
251
|
buf = buf.sub(/\A((?:.|\n)*?#{EOL})#{EOL}/n) do
|
@@ -268,11 +272,12 @@ class Cgi
|
|
268
272
|
content_length -= c.size
|
269
273
|
end
|
270
274
|
|
271
|
-
buf = buf.sub(/\A((?:.|\n)*?)(?:[\r\n]{1,2})?#{
|
275
|
+
buf = buf.sub(/\A((?:.|\n)*?)(?:[\r\n]{1,2})?#{quoted_boundary}([\r\n]{1,2}|--)/n) do
|
272
276
|
body.print $1
|
273
277
|
if "--" == $2
|
274
278
|
content_length = -1
|
275
279
|
end
|
280
|
+
boundary_end = $2.dup
|
276
281
|
""
|
277
282
|
end
|
278
283
|
|
@@ -308,6 +313,7 @@ class Cgi
|
|
308
313
|
break if buf.size == 0
|
309
314
|
break if content_length === -1
|
310
315
|
end
|
316
|
+
raise EOFError, "bad boundary end of body" unless boundary_end =~ /--/
|
311
317
|
|
312
318
|
return params
|
313
319
|
end
|
@@ -139,11 +139,19 @@ class Elements # :nodoc: all
|
|
139
139
|
@buffer << "<?#{name}#{attributes}?>"
|
140
140
|
end
|
141
141
|
|
142
|
+
def cdata(content)
|
143
|
+
@buffer << "<![CDATA[#{content}]]>"
|
144
|
+
end
|
145
|
+
|
142
146
|
def comment(c)
|
143
147
|
unless Template.strip_xml_comments
|
144
148
|
@buffer << "<!--#{c}-->"
|
145
149
|
end
|
146
150
|
end
|
151
|
+
|
152
|
+
def doctype(name, pub_sys, long_name, uri)
|
153
|
+
@buffer << "<!DOCTYPE #{name} #{pub_sys} #{long_name} #{uri}>\n"
|
154
|
+
end
|
147
155
|
end
|
148
156
|
|
149
157
|
class << self
|
@@ -202,6 +202,10 @@ class Morphing
|
|
202
202
|
@buffer << "<?#{name}#{attributes}?>"
|
203
203
|
end
|
204
204
|
|
205
|
+
def cdata(content)
|
206
|
+
@buffer << "<![CDATA[#{content}]]>"
|
207
|
+
end
|
208
|
+
|
205
209
|
def comment(c)
|
206
210
|
unless Nitro::Template.strip_xml_comments
|
207
211
|
@buffer << "<!--#{c}-->"
|
@@ -209,7 +213,7 @@ class Morphing
|
|
209
213
|
end
|
210
214
|
|
211
215
|
def doctype(name, pub_sys, long_name, uri)
|
212
|
-
@buffer << "<!DOCTYPE #{name} #{pub_sys} #{long_name} #{uri}
|
216
|
+
@buffer << "<!DOCTYPE #{name} #{pub_sys} #{long_name} #{uri}>\n"
|
213
217
|
end
|
214
218
|
end
|
215
219
|
|
data/lib/nitro/helper.rb
CHANGED
@@ -70,6 +70,7 @@ module Helpers
|
|
70
70
|
raise "helper #{modname} not found (module not defined), check name"
|
71
71
|
end
|
72
72
|
symbols = mod.instance_methods.collect { |m| m.to_sym }
|
73
|
+
|
73
74
|
self.send(:include, mod)
|
74
75
|
self.send(:private, *symbols)
|
75
76
|
self.send(:private, mod.to_s[/[^:]+$/].to_sym)
|
data/lib/nitro/helper/pager.rb
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
require 'glue/uri'
|
2
1
|
require 'glue/configuration'
|
3
2
|
|
4
3
|
require 'og/collection'
|
@@ -232,8 +231,15 @@ private
|
|
232
231
|
# Generate the target URI.
|
233
232
|
|
234
233
|
def target_uri(page)
|
235
|
-
|
236
|
-
|
234
|
+
uri = @request.uri.to_s
|
235
|
+
|
236
|
+
if uri =~ /[?;]#{@key}=(\d*)/
|
237
|
+
return uri.gsub(/([?;]#{@key}=)\d*/) { |m| "#$1#{page}" }
|
238
|
+
elsif uri =~ /\?/
|
239
|
+
return "#{uri};#{@key}=#{page}"
|
240
|
+
else
|
241
|
+
return "#{uri}?#{@key}=#{page}"
|
242
|
+
end
|
237
243
|
end
|
238
244
|
|
239
245
|
end
|
data/lib/nitro/publishable.rb
CHANGED
@@ -12,6 +12,8 @@ require 'nitro/flash'
|
|
12
12
|
require 'nitro/helper'
|
13
13
|
require 'nitro/compiler'
|
14
14
|
|
15
|
+
require 'nitro/util/encode_url'
|
16
|
+
|
15
17
|
module Nitro
|
16
18
|
|
17
19
|
# Include this Mixin to a class to make objects of this class
|
@@ -64,6 +66,8 @@ module Publishable
|
|
64
66
|
end
|
65
67
|
end
|
66
68
|
|
69
|
+
base.helper(EncodeUrl)
|
70
|
+
|
67
71
|
# Aliases an action
|
68
72
|
#--
|
69
73
|
# gmosx, FIXME: better implementation needed.
|
@@ -80,6 +84,9 @@ module Publishable
|
|
80
84
|
# Return the 'action' methods for this Controller.
|
81
85
|
# Some dangerous methods from ancestors are removed.
|
82
86
|
# All private methods are ignored.
|
87
|
+
#--
|
88
|
+
# gmosx, TODO: maybe we should optimize this method.
|
89
|
+
#++
|
83
90
|
|
84
91
|
base.module_eval do
|
85
92
|
def self.action_methods
|
@@ -217,7 +224,7 @@ private
|
|
217
224
|
cookie.expires = Time.now
|
218
225
|
@context.add_cookie(cookie)
|
219
226
|
end
|
220
|
-
|
227
|
+
=begin
|
221
228
|
# Encode controller, action, params into a valid url.
|
222
229
|
# Automatically respects nice urls and routing.
|
223
230
|
#
|
@@ -314,6 +321,7 @@ private
|
|
314
321
|
return "#{request.host_url}#{encode_url(*args)}"
|
315
322
|
end
|
316
323
|
alias RA encode_absolute_url
|
324
|
+
=end
|
317
325
|
|
318
326
|
# Allows instances of Publishable classes to know where they
|
319
327
|
# are mounted.
|
data/lib/nitro/render.rb
CHANGED
@@ -238,6 +238,42 @@ private
|
|
238
238
|
end
|
239
239
|
alias_method :redirect_to_home, :redirect_home
|
240
240
|
|
241
|
+
# :section: Seaside style call/answer methods.
|
242
|
+
|
243
|
+
# Call redirects to the given url but push the original
|
244
|
+
# url in a callstack, so that the target can return by
|
245
|
+
# executing answer.
|
246
|
+
#
|
247
|
+
# === Example
|
248
|
+
#
|
249
|
+
# caller:
|
250
|
+
# color, type = call 'utils/select_color'
|
251
|
+
#
|
252
|
+
# target:
|
253
|
+
# answer color, type
|
254
|
+
#--
|
255
|
+
# FIXME: dont use yet, you have to encode the branch to
|
256
|
+
# make this safe for use.
|
257
|
+
#++
|
258
|
+
|
259
|
+
def call(url, status = 303)
|
260
|
+
(session[:CALL_STACK] ||= []) << request.uri
|
261
|
+
redirect(url, status)
|
262
|
+
end
|
263
|
+
|
264
|
+
# Returns from a call by poping the callstack.
|
265
|
+
#--
|
266
|
+
# FIXME: don't use yet.
|
267
|
+
#++
|
268
|
+
|
269
|
+
def answer(index = 0, status = 303)
|
270
|
+
if stack = session[:CALL_STACK] and not stack.empty?
|
271
|
+
redirect(stack.pop, status)
|
272
|
+
else
|
273
|
+
raise 'Cannot answer, call stack is empty'
|
274
|
+
end
|
275
|
+
end
|
276
|
+
|
241
277
|
# Log a rendering error.
|
242
278
|
|
243
279
|
def log_error(error, path, full = true)
|
data/lib/nitro/scaffold/model.rb
CHANGED
@@ -86,14 +86,14 @@ module Scaffold
|
|
86
86
|
#{controller}
|
87
87
|
}
|
88
88
|
|
89
|
-
if defined?
|
90
|
-
self.extend(
|
89
|
+
if defined? OgAdminController
|
90
|
+
self.extend(OgAdminHelper)
|
91
91
|
|
92
92
|
# to_edit_href
|
93
93
|
# ex: admin/update/Article/23
|
94
94
|
|
95
95
|
define_instance_method klass, :to_edit_href, %{
|
96
|
-
"\#{
|
96
|
+
"\#{OgAdminController.mount_path}/update/#{class_to_name(klass)}/\#{oid}"
|
97
97
|
}
|
98
98
|
|
99
99
|
# to_admin_href
|
data/lib/nitro/server/runner.rb
CHANGED
@@ -221,7 +221,7 @@ class Runner
|
|
221
221
|
# Setup in debug mode.
|
222
222
|
|
223
223
|
def setup_debug
|
224
|
-
$DBG
|
224
|
+
$DBG.nil? ? true : $DBG
|
225
225
|
Compiler.reload = true
|
226
226
|
autoreload(3)
|
227
227
|
Caching.caching_enabled = false
|
@@ -230,16 +230,17 @@ class Runner
|
|
230
230
|
end
|
231
231
|
|
232
232
|
def setup_stage
|
233
|
-
$DBG
|
233
|
+
$DBG.nil? ? false : $DBG
|
234
234
|
Compiler.reload = true
|
235
|
-
autoreload(3)
|
236
|
-
|
235
|
+
autoreload(3)
|
236
|
+
|
237
|
+
# load_external_configuration(:stage)
|
237
238
|
|
238
|
-
|
239
|
+
Logger.set(Configuration.log)
|
239
240
|
end
|
240
241
|
|
241
242
|
def setup_live
|
242
|
-
$DBG
|
243
|
+
$DBG.nil? ? false : $DBG
|
243
244
|
|
244
245
|
# Enable the reloading even on live apps by default.
|
245
246
|
# But have a longer thread sleep time.
|
@@ -247,11 +248,12 @@ class Runner
|
|
247
248
|
# reloading (Compiler.reload = false)
|
248
249
|
|
249
250
|
Compiler.reload = true
|
250
|
-
autoreload(2 * 60)
|
251
|
-
|
251
|
+
autoreload(2 * 60)
|
252
|
+
|
253
|
+
# load_external_configuration(:live)
|
254
|
+
# load_external_configuration(:production)
|
252
255
|
|
253
|
-
|
254
|
-
# load_external_configuration(:production)
|
256
|
+
Logger.set(Configuration.log)
|
255
257
|
end
|
256
258
|
alias_method :setup_production, :setup_live
|
257
259
|
|
data/lib/nitro/session.rb
CHANGED
data/lib/nitro/template.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'digest/md5'
|
1
2
|
require 'ostruct'
|
2
3
|
require 'facets/more/openobject'
|
3
4
|
require 'glue/configuration'
|
@@ -13,8 +14,9 @@ module TemplateMixin
|
|
13
14
|
|
14
15
|
# Set some pretty safe delimiters for templates.
|
15
16
|
|
16
|
-
|
17
|
-
|
17
|
+
DELIM_HSH = Digest::MD5.hexdigest(Kernel.rand.to_s)
|
18
|
+
START_DELIM = "<<NITRO_TEMPLATE_DELIMETER#{DELIM_HSH}\n"
|
19
|
+
END_DELIM = "\nNITRO_TEMPLATE_DELIMETER#{DELIM_HSH}\n"
|
18
20
|
|
19
21
|
# Convert a template to actual Ruby code, ready to be
|
20
22
|
# evaluated.
|
@@ -39,7 +41,7 @@ module TemplateMixin
|
|
39
41
|
|
40
42
|
# Strip the xml header! (interracts with the following gsub!)
|
41
43
|
|
42
|
-
text.gsub!(/<\?xml.*\?>/,
|
44
|
+
text.gsub!(/<\?xml.*\?>/, '')
|
43
45
|
|
44
46
|
# Transform include instructions <include href="xxx" />
|
45
47
|
# must be transformed before the processinc instructions.
|
@@ -49,16 +51,12 @@ module TemplateMixin
|
|
49
51
|
# add load_statically_included fixes.
|
50
52
|
#++
|
51
53
|
|
52
|
-
text.gsub!(/<include
|
53
|
-
"<?r File.read( '\#{@dispatcher.root}/#$1' ?>"
|
54
|
-
end
|
54
|
+
text.gsub!(/<include\s+href=["'](.*?)["']\s+\/>/, %[<?r File.read("\#{@dispatcher.root}/\\1") ?>])
|
55
55
|
|
56
56
|
# xform render/inject instructions <render href="xxx" />
|
57
57
|
# must be transformed before the processinc instructions.
|
58
58
|
|
59
|
-
text.gsub!(/<(render|inject)
|
60
|
-
"<?r render '#$2' ?>"
|
61
|
-
end
|
59
|
+
text.gsub!(/<(?:render|inject)\s+href=["'](.*?)["']\s+\/>/, %[<?r render "\\1" ?>])
|
62
60
|
|
63
61
|
# Remove <root> elements. typically removed by xslt but lets
|
64
62
|
# play it safe. The <root> element is typically added to
|
@@ -69,20 +67,23 @@ module TemplateMixin
|
|
69
67
|
# Transform the processing instructions, use <?r as
|
70
68
|
# a marker.
|
71
69
|
|
72
|
-
text.gsub!(
|
73
|
-
text.gsub!(/<\?r(\s?)/, "#{END_DELIM}; ")
|
70
|
+
text.gsub!(/<\?r\s+(.*?)\s+\?>/m, "#{END_DELIM}; \\1; #{buffer} << #{START_DELIM}")
|
71
|
+
#text.gsub!(/<\?r(\s?)/, "#{END_DELIM}; ")
|
72
|
+
#text.gsub!(/\?>/, "; #{buffer} << #{START_DELIM}")
|
74
73
|
|
75
74
|
# Transform alternative code tags.
|
76
75
|
# (very useful in xsl stylesheets)
|
77
76
|
|
78
|
-
text.gsub!(
|
79
|
-
text.gsub!(
|
77
|
+
text.gsub!(/<ruby>(.*?)<\/ruby>/m, "#{END_DELIM}; \\1; #{buffer} << #{START_DELIM}")
|
78
|
+
#text.gsub!(/<\/ruby>/, "; #{buffer} << #{START_DELIM}")
|
79
|
+
#text.gsub!(/<ruby>/, "#{END_DELIM}; ")
|
80
80
|
|
81
81
|
# Also handle erb/asp/jsp style tags. Those tags
|
82
82
|
# *cannot* be used with an xslt stylesheet.
|
83
83
|
|
84
|
-
text.gsub!(
|
85
|
-
text.gsub!(
|
84
|
+
text.gsub!(/<%(.*?)%>/m, "#{END_DELIM}; \\1; #{buffer} << #{START_DELIM}")
|
85
|
+
#text.gsub!(/%>/, "; #{buffer} << #{START_DELIM}")
|
86
|
+
#text.gsub!(/<%/, "#{END_DELIM}; ")
|
86
87
|
|
87
88
|
# Alterative versions of interpolation.
|
88
89
|
# (very useful in xsl stylesheets)
|
@@ -0,0 +1,112 @@
|
|
1
|
+
module Nitro
|
2
|
+
|
3
|
+
# A collection of intelligent url encoding methods.
|
4
|
+
|
5
|
+
module EncodeUrl
|
6
|
+
|
7
|
+
private
|
8
|
+
|
9
|
+
# Encode controller, action, params into a valid url.
|
10
|
+
# Automatically respects nice urls and routing.
|
11
|
+
#
|
12
|
+
# Handles parameters either as a hash or as an array.
|
13
|
+
# Use the array method to pass parameters to 'nice' actions.
|
14
|
+
#
|
15
|
+
# Pass Controller, action, and (param_name, param_value)
|
16
|
+
# pairs.
|
17
|
+
#
|
18
|
+
# === Examples
|
19
|
+
#
|
20
|
+
# encode_url ForaController, :post, :title, 'Hello', :body, 'World'
|
21
|
+
# encode_url :post, :title, 'Hello', :body, 'World' # => implies controller == self
|
22
|
+
# encode_url :kick, :oid, 4
|
23
|
+
# encode_url article # => article.to_href
|
24
|
+
#
|
25
|
+
# Alternatively you can pass options with a hash:
|
26
|
+
#
|
27
|
+
# encode_url :controller => ForaController, :action => :delete, :params => { :title => 'Hello' }
|
28
|
+
# encode_url :action => :delete
|
29
|
+
#--
|
30
|
+
# FIXME: better implementation? optimize this?
|
31
|
+
# TODO: move elsewhere.
|
32
|
+
#++
|
33
|
+
|
34
|
+
def encode_url(*args)
|
35
|
+
f = args.first
|
36
|
+
|
37
|
+
# A standard url as string, return as is.
|
38
|
+
|
39
|
+
if f.is_a? String
|
40
|
+
return f
|
41
|
+
end
|
42
|
+
|
43
|
+
# If the passed param is an object that responds to :to_href
|
44
|
+
# returns the url to this object.
|
45
|
+
|
46
|
+
if f.respond_to? :to_href
|
47
|
+
return args.first.to_href
|
48
|
+
end
|
49
|
+
|
50
|
+
if f.is_a? Symbol
|
51
|
+
# no controller passed, try to use self as controller.
|
52
|
+
if self.is_a? Nitro::Controller
|
53
|
+
args.unshift(self.class)
|
54
|
+
else
|
55
|
+
raise 'No controller passed to encode_url'
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# Try to encode using the router.
|
60
|
+
|
61
|
+
if url = Context.current.dispatcher.encode_route(*args)
|
62
|
+
return url
|
63
|
+
end
|
64
|
+
|
65
|
+
# No routing rule, manual encoding.
|
66
|
+
|
67
|
+
controller = args.shift
|
68
|
+
action = args.shift.to_sym
|
69
|
+
|
70
|
+
if action == :index
|
71
|
+
url = "#{controller.mount_path}"
|
72
|
+
else
|
73
|
+
mount_path = controller.mount_path
|
74
|
+
mount_path = nil if mount_path == '/'
|
75
|
+
url = "#{mount_path}/#{action}"
|
76
|
+
end
|
77
|
+
|
78
|
+
unless args.empty?
|
79
|
+
if controller.respond_to_action_or_template? action
|
80
|
+
param_count = controller.instance_method(action).arity
|
81
|
+
if param_count != 0
|
82
|
+
param_count.times do
|
83
|
+
args.shift # name
|
84
|
+
url << "/#{CGI.escape(args.shift.to_s)}"
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
unless args.empty?
|
90
|
+
url << '?'
|
91
|
+
params = []
|
92
|
+
(args.size / 2).times do
|
93
|
+
params << "#{args.shift}=#{args.shift}"
|
94
|
+
end
|
95
|
+
url << params.join(';')
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
return url
|
100
|
+
end
|
101
|
+
alias R encode_url
|
102
|
+
|
103
|
+
# Just like encode_url, but generates an absolute url instead.
|
104
|
+
|
105
|
+
def encode_absolute_url(*args)
|
106
|
+
return "#{request.host_url}#{encode_url(*args)}"
|
107
|
+
end
|
108
|
+
alias RA encode_absolute_url
|
109
|
+
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|
data/lib/nitro/version.rb
CHANGED
data/test/nitro/tc_cgi.rb
CHANGED
@@ -100,14 +100,12 @@ class TestAdapterCgi < Test::Unit::TestCase # :nodoc: all
|
|
100
100
|
params = Cgi.parse_query_string(qs)
|
101
101
|
assert_equal 2, params.size
|
102
102
|
arr = params['arr']
|
103
|
-
assert_equal Array, arr.class
|
104
103
|
assert_equal 3, arr.size
|
105
104
|
|
106
105
|
qs = 'other=1;user.name=gmosx;user.password=hello'
|
107
106
|
params = Cgi.parse_query_string(qs)
|
108
107
|
assert_equal 2, params.size
|
109
108
|
u = params['user']
|
110
|
-
assert_equal Hash, u.class
|
111
109
|
assert_equal 'gmosx', u['name']
|
112
110
|
assert_equal 'hello', u['password']
|
113
111
|
|
@@ -122,7 +120,6 @@ class TestAdapterCgi < Test::Unit::TestCase # :nodoc: all
|
|
122
120
|
params = Cgi.parse_query_string(qs)
|
123
121
|
assert_equal 2, params.size
|
124
122
|
u = params['user']
|
125
|
-
assert_equal Hash, u.class
|
126
123
|
assert_equal 'gmosx', u['name']
|
127
124
|
assert_equal 'hello', u['password']
|
128
125
|
end
|
data/test/nitro/tc_helper.rb
CHANGED
@@ -21,6 +21,12 @@ module AnotherHelper
|
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
24
|
+
module Funny
|
25
|
+
def funny_world
|
26
|
+
return 1
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
24
30
|
class MyBase < Base
|
25
31
|
helper :my
|
26
32
|
helper AnotherHelper
|
@@ -32,5 +38,10 @@ class TC_Helper < Test::Unit::TestCase # :nodoc: all
|
|
32
38
|
assert MyBase.private_instance_methods.include?('hello_world')
|
33
39
|
assert !MyBase.public_instance_methods.include?('bye_world')
|
34
40
|
assert MyBase.private_instance_methods.include?('bye_world')
|
41
|
+
|
42
|
+
# test a bug.
|
43
|
+
MyBase.helper(Funny)
|
44
|
+
assert !MyBase.public_instance_methods.include?('funny_world')
|
45
|
+
assert MyBase.private_instance_methods.include?('funny_world')
|
35
46
|
end
|
36
47
|
end
|
data/test/nitro/tc_render.rb
CHANGED
@@ -4,6 +4,8 @@ require 'test/unit'
|
|
4
4
|
|
5
5
|
require 'nitro'
|
6
6
|
require 'nitro/render'
|
7
|
+
require 'nitro/session'
|
8
|
+
require 'nitro/context'
|
7
9
|
require 'facet/mock'
|
8
10
|
|
9
11
|
class TestRender < Test::Unit::TestCase # :nodoc: all
|
@@ -17,6 +19,60 @@ class TestRender < Test::Unit::TestCase # :nodoc: all
|
|
17
19
|
class TestController < Controller
|
18
20
|
end
|
19
21
|
|
22
|
+
class CallController < Controller
|
23
|
+
def return_session
|
24
|
+
session[:CALL_STACK].inspect
|
25
|
+
end
|
26
|
+
|
27
|
+
def needs_login
|
28
|
+
call "login"
|
29
|
+
end
|
30
|
+
|
31
|
+
def login
|
32
|
+
answer()
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
@@session = Session.new
|
37
|
+
def handle_request(url, value)
|
38
|
+
conf = OpenStruct.new
|
39
|
+
disp = Nitro::Dispatcher.new('/' => CallController)
|
40
|
+
conf.dispatcher = disp
|
41
|
+
@ctx = Nitro::Context.new(conf)
|
42
|
+
@ctx.headers = { 'REQUEST_METHOD' => 'GET' }
|
43
|
+
@ctx.params = {}
|
44
|
+
@ctx.instance_variable_set '@session', @@session
|
45
|
+
|
46
|
+
if value[:in]
|
47
|
+
@ctx.in = value.delete(:in)
|
48
|
+
@ctx.headers['CONTENT_LENGTH'] = value.delete(:in_size) || @ctx.in.size
|
49
|
+
end
|
50
|
+
|
51
|
+
if value[:method]
|
52
|
+
@ctx.headers['REQUEST_METHOD'] = value[:method].to_s
|
53
|
+
end
|
54
|
+
|
55
|
+
if value['CONTENT_TYPE']
|
56
|
+
@ctx.headers['CONTENT_TYPE'] = value.delete('CONTENT_TYPE')
|
57
|
+
end
|
58
|
+
|
59
|
+
@ctx.headers['REQUEST_URI'] = url
|
60
|
+
|
61
|
+
if (!@ctx.query_string || @ctx.query_string.empty?) and @ctx.uri =~ /\?/
|
62
|
+
@ctx.headers['QUERY_STRING'] = @ctx.uri.split('?').last
|
63
|
+
end
|
64
|
+
|
65
|
+
Nitro::Cgi.parse_params(@ctx)
|
66
|
+
Nitro::Cgi.parse_cookies(@ctx)
|
67
|
+
|
68
|
+
@ctx.render url
|
69
|
+
|
70
|
+
#retrieve the stuff from @out again as a hash
|
71
|
+
result = @ctx.out
|
72
|
+
|
73
|
+
return result
|
74
|
+
end
|
75
|
+
|
20
76
|
def setup
|
21
77
|
ctx = ContextMock.new
|
22
78
|
@controller = TestController.new(ctx)
|
@@ -52,4 +108,12 @@ class TestRender < Test::Unit::TestCase # :nodoc: all
|
|
52
108
|
rescue Nitro::RenderExit
|
53
109
|
end
|
54
110
|
end
|
111
|
+
|
112
|
+
def test_call
|
113
|
+
handle_request('/needs_login', {})
|
114
|
+
assert_equal ['/needs_login'], eval(handle_request('/return_session', {}))
|
115
|
+
handle_request('/login', {})
|
116
|
+
assert_equal [], eval(handle_request('/return_session', {}))
|
117
|
+
end
|
118
|
+
|
55
119
|
end
|
data/test/nitro/tc_template.rb
CHANGED
@@ -6,13 +6,13 @@ require 'nitro/template'
|
|
6
6
|
|
7
7
|
class TestTemplate < Test::Unit::TestCase # :nodoc: all
|
8
8
|
include Nitro
|
9
|
-
|
9
|
+
|
10
10
|
def test_all
|
11
11
|
template = %q{
|
12
12
|
Hello #{user}
|
13
13
|
|
14
14
|
dont forget the following todo items:
|
15
|
-
|
15
|
+
|
16
16
|
<?r for item in items ?>
|
17
17
|
<li>#{item}</li>
|
18
18
|
<?r end ?>
|
@@ -26,9 +26,46 @@ class TestTemplate < Test::Unit::TestCase # :nodoc: all
|
|
26
26
|
|
27
27
|
assert_match %r{\<li\>nitro\</li\>}, out
|
28
28
|
assert_match %r{\<li\>really\</li\>}, out
|
29
|
-
assert_match %r{Hello gmosx}, out
|
30
|
-
|
29
|
+
assert_match %r{Hello gmosx}, out
|
30
|
+
|
31
31
|
# TODO: add test for static inclusion.
|
32
|
-
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_interpolation
|
36
|
+
template = %q[
|
37
|
+
<% user1 = 'one' %>
|
38
|
+
<%
|
39
|
+
user2 = 'two'
|
40
|
+
%>
|
41
|
+
<?r user3 = 'three' ?>
|
42
|
+
<?r
|
43
|
+
user4 = 'four'
|
44
|
+
?>
|
45
|
+
<ruby>user5 = 'five'</ruby>
|
46
|
+
<ruby>
|
47
|
+
user6 = 'six'
|
48
|
+
</ruby>
|
49
|
+
user1: #\user1\
|
50
|
+
user2: #{user2}
|
51
|
+
user3: #{ user3 }
|
52
|
+
user4: #\ user4\
|
53
|
+
user5: #\user5 \
|
54
|
+
user6: #\ user6\
|
55
|
+
]
|
56
|
+
|
57
|
+
out = ''
|
58
|
+
Nitro::Template.process(template, :out, binding)
|
59
|
+
|
60
|
+
{
|
61
|
+
:user1 => 'one',
|
62
|
+
:user2 => 'two',
|
63
|
+
:user3 => 'three',
|
64
|
+
:user4 => 'four',
|
65
|
+
:user5 => 'five',
|
66
|
+
:user6 => 'six'
|
67
|
+
}.each do |key, val|
|
68
|
+
assert_match "#{key}: #{val}", out
|
69
|
+
end
|
33
70
|
end
|
34
71
|
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '..', 'CONFIG.rb')
|
2
|
+
|
3
|
+
require 'test/unit'
|
4
|
+
require 'ostruct'
|
5
|
+
|
6
|
+
require 'glue'
|
7
|
+
require 'glue/logger'
|
8
|
+
require 'nitro'
|
9
|
+
require 'nitro/util/encode_url'
|
10
|
+
|
11
|
+
class TC_EncodeUrl < Test::Unit::TestCase # :nodoc: all
|
12
|
+
include Nitro
|
13
|
+
|
14
|
+
class FirstController < Controller
|
15
|
+
def list
|
16
|
+
end
|
17
|
+
public :encode_url
|
18
|
+
end
|
19
|
+
|
20
|
+
class SecondController < Controller
|
21
|
+
attr_reader :aqflag, :tflag
|
22
|
+
|
23
|
+
def self.setup_template_root(path)
|
24
|
+
@template_root << File.expand_path(File.join(Nitro::LibPath, "../test/public/#{path}"))
|
25
|
+
end
|
26
|
+
|
27
|
+
def list
|
28
|
+
@aqflag = true
|
29
|
+
end
|
30
|
+
|
31
|
+
def another(oid)
|
32
|
+
# nop
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
class TestEncoder
|
37
|
+
include Nitro::EncodeUrl
|
38
|
+
public :encode_url
|
39
|
+
end
|
40
|
+
|
41
|
+
def setup
|
42
|
+
@disp = Dispatcher.new '/first' => FirstController,
|
43
|
+
'/second' => SecondController
|
44
|
+
@conf = OpenStruct.new
|
45
|
+
@conf.dispatcher = @disp
|
46
|
+
Thread.current[:CURRENT_CONTEXT] = @conf
|
47
|
+
end
|
48
|
+
|
49
|
+
def test_encode
|
50
|
+
t = TestEncoder.new
|
51
|
+
|
52
|
+
assert_equal 'test', t.encode_url('test')
|
53
|
+
assert_equal '/first/list', t.encode_url(FirstController, :list)
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
def test_controller_encode
|
58
|
+
t = FirstController.new(@conf)
|
59
|
+
|
60
|
+
assert_equal '/first/list', t.encode_url(:list)
|
61
|
+
end
|
62
|
+
end
|
metadata
CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.0
|
|
3
3
|
specification_version: 1
|
4
4
|
name: nitro
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.
|
7
|
-
date: 2006-
|
6
|
+
version: 0.41.0
|
7
|
+
date: 2006-12-12 12:36:44 +02:00
|
8
8
|
summary: Everything you need to create Web 2.0 applications with Ruby and Javascript
|
9
9
|
require_paths:
|
10
10
|
- lib
|
@@ -76,6 +76,7 @@ files:
|
|
76
76
|
- lib/nitro/test
|
77
77
|
- lib/nitro/test.rb
|
78
78
|
- lib/nitro/version.rb
|
79
|
+
- lib/nitro/util
|
79
80
|
- lib/nitro/adapter/cgi.rb
|
80
81
|
- lib/nitro/adapter/console.rb
|
81
82
|
- lib/nitro/adapter/fastcgi.rb
|
@@ -160,6 +161,7 @@ files:
|
|
160
161
|
- lib/nitro/test/assertions.rb
|
161
162
|
- lib/nitro/test/context.rb
|
162
163
|
- lib/nitro/test/testcase.rb
|
164
|
+
- lib/nitro/util/encode_url.rb
|
163
165
|
- lib/part/admin.rb
|
164
166
|
- lib/part/admin
|
165
167
|
- lib/part/admin/controller.rb
|
@@ -201,6 +203,7 @@ files:
|
|
201
203
|
- test/nitro/tc_server.rb
|
202
204
|
- test/nitro/tc_session.rb
|
203
205
|
- test/nitro/tc_template.rb
|
206
|
+
- test/nitro/util
|
204
207
|
- test/nitro/adapter/raw_post1.bin
|
205
208
|
- test/nitro/adapter/tc_webrick.rb
|
206
209
|
- test/nitro/cgi/tc_cookie.rb
|
@@ -212,6 +215,7 @@ files:
|
|
212
215
|
- test/nitro/helper/tc_pager.rb
|
213
216
|
- test/nitro/helper/tc_table.rb
|
214
217
|
- test/nitro/helper/tc_xhtml.rb
|
218
|
+
- test/nitro/util/tc_encode_url.rb
|
215
219
|
- test/public/blog
|
216
220
|
- test/public/dummy_mailer
|
217
221
|
- test/public/blog/another
|
@@ -279,7 +283,7 @@ dependencies:
|
|
279
283
|
requirements:
|
280
284
|
- - "="
|
281
285
|
- !ruby/object:Gem::Version
|
282
|
-
version: 0.
|
286
|
+
version: 0.41.0
|
283
287
|
version:
|
284
288
|
- !ruby/object:Gem::Dependency
|
285
289
|
name: gen
|
@@ -288,7 +292,7 @@ dependencies:
|
|
288
292
|
requirements:
|
289
293
|
- - "="
|
290
294
|
- !ruby/object:Gem::Version
|
291
|
-
version: 0.
|
295
|
+
version: 0.41.0
|
292
296
|
version:
|
293
297
|
- !ruby/object:Gem::Dependency
|
294
298
|
name: glue
|
@@ -297,7 +301,7 @@ dependencies:
|
|
297
301
|
requirements:
|
298
302
|
- - "="
|
299
303
|
- !ruby/object:Gem::Version
|
300
|
-
version: 0.
|
304
|
+
version: 0.41.0
|
301
305
|
version:
|
302
306
|
- !ruby/object:Gem::Dependency
|
303
307
|
name: RedCloth
|