nitro 0.40.0 → 0.41.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/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
|