nitro 0.30.0 → 0.31.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -199,8 +199,6 @@ class WebrickAdapter < WEBrick::HTTPServlet::AbstractServlet
199
199
 
200
200
  def handle(req, res)
201
201
  unless handle_file(req, res)
202
- path = req.request_uri.path
203
-
204
202
  begin
205
203
  path = req.request_uri.path
206
204
 
data/lib/nitro/caching.rb CHANGED
@@ -1,4 +1,3 @@
1
- require 'glue/attribute'
2
1
  require 'glue/configuration'
3
2
  require 'glue/sweeper'
4
3
 
@@ -1,7 +1,6 @@
1
1
  require 'fileutils'
2
2
 
3
3
  require 'glue/configuration'
4
- require 'glue/attribute'
5
4
  require 'glue/cache/memory'
6
5
 
7
6
  module Nitro
@@ -20,11 +19,11 @@ module Caching
20
19
  setting :cache, :default => Glue::MemoryCache.new, :doc => 'The cache used to store the fragments'
21
20
 
22
21
  def self.get(name, options = {})
23
- return @@cache.get(name, options)
22
+ return self.cache.get(name, options)
24
23
  end
25
24
 
26
25
  def self.put(name, content = nil, options = {})
27
- @@cache.put(name, content, options)
26
+ self.cache.put(name, content, options)
28
27
  return content
29
28
  end
30
29
 
@@ -6,6 +6,8 @@ module Nitro
6
6
 
7
7
  module Caching
8
8
 
9
+ setting :output_cache_root, :default => 'public', :doc => 'The directory where cached pages are generated'
10
+
9
11
  # The Output caching subsystem stores whole pages in the
10
12
  # filesystem to be served directly be the front web server
11
13
  # (Lighttpd, Apache, etc) for optimal performance.
@@ -22,9 +24,6 @@ module Caching
22
24
 
23
25
  def self.included(base) # :nodoc:
24
26
  base.extend(ClassMethods)
25
- base.module_eval do
26
- cattr_accessor :output_cache_root, 'public'
27
- end
28
27
  end
29
28
 
30
29
  module ClassMethods
@@ -54,7 +53,7 @@ module Caching
54
53
  filename = ((path.empty? || path == '/') ? 'index.html' : path.dup)
55
54
  # filename.gsub!(/\/$/, '')
56
55
  filename << '/index.html' unless (filename.split('/').last || filename).include? '.'
57
- return output_cache_root + '/' + filename
56
+ return Caching.output_cache_root + '/' + filename
58
57
  end
59
58
 
60
59
  end
data/lib/nitro/cgi.rb CHANGED
@@ -1,5 +1,7 @@
1
1
  require 'cgi'
2
2
 
3
+ require 'stringio'
4
+
3
5
  require 'glue/configuration'
4
6
  require 'nitro/cgi/http'
5
7
 
@@ -21,10 +23,22 @@ class Cgi
21
23
 
22
24
  # Process a CGI request. This is a general method reused by
23
25
  # many adapters.
26
+ #--
27
+ # A CGI request is process-based so there is no need for Og
28
+ # connection cleanup.
29
+ #++
24
30
 
25
31
  def self.process(server, cgi, inp, out)
26
32
  context = Context.new(server)
27
33
 
34
+ unless inp.respond_to?(:rewind)
35
+ # The module Request#raw_body requires a rewind method,
36
+ # so if the input stream doesn't have one, *cough* FCgi,
37
+ # we convert it to a StringIO.
38
+
39
+ inp = StringIO.new(inp.read.to_s) # if read returns nil, to_s makes it ""
40
+ end
41
+
28
42
  context.in = inp
29
43
  context.headers = cgi.env
30
44
 
@@ -64,7 +64,7 @@ module Request
64
64
  # www.nitroproject.org: request.domain # => 'nitroproject.org'
65
65
  # www.nitroproject.co.uk: request.domain(2) # => 'nitroproject.co.uk'
66
66
 
67
- def domain(tld_length = 1)
67
+ def domain tld_length = 1
68
68
  host.split('.').last(1 + tld_length).join('.')
69
69
  end
70
70
 
@@ -74,7 +74,7 @@ module Request
74
74
  #
75
75
  # my.name.nitroproject.org: request.subdomains # => ['my', 'name']
76
76
 
77
- def subdomains(tld_length = 1)
77
+ def subdomains tld_length = 1
78
78
  parts = host.split('.')
79
79
  parts[0..-(tld_length+2)]
80
80
  end
@@ -104,7 +104,7 @@ module Request
104
104
  # if request.get?
105
105
 
106
106
  def method
107
- @headers['REQUEST_METHOD'].downcase.intern
107
+ @headers['REQUEST_METHOD'].downcase.to_sym
108
108
  end
109
109
 
110
110
  #--
@@ -176,6 +176,7 @@ module Request
176
176
  def referer
177
177
  return @headers['HTTP_REFERER'] || '/'
178
178
  end
179
+ alias referrer referer
179
180
 
180
181
  # The content_length
181
182
 
@@ -242,19 +243,19 @@ module Request
242
243
 
243
244
  # Lookup a query parameter.
244
245
 
245
- def [](param)
246
+ def [] param
246
247
  @params[param]
247
248
  end
248
249
 
249
250
  # Set a query parameter.
250
251
 
251
- def []=(param, value)
252
+ def []= param, value
252
253
  @params[param] = value
253
254
  end
254
255
 
255
256
  # Check if a boolean param (checkbox) is true.
256
257
 
257
- def true?(param)
258
+ def true? param
258
259
  @params[param] == 'on'
259
260
  end
260
261
  alias_method :enabled?, :true?
@@ -262,19 +263,19 @@ module Request
262
263
 
263
264
  # Check if a boolean param (checkbox) is false.
264
265
 
265
- def false?(param)
266
+ def false? param
266
267
  !true?(param)
267
268
  end
268
269
 
269
270
  # Fetch a parameter with default value.
270
271
 
271
- def fetch(param, default = nil)
272
+ def fetch param, default = nil
272
273
  @params.fetch(param, default)
273
274
  end
274
275
 
275
276
  # Check if a param is available.
276
277
 
277
- def has_key?(key)
278
+ def has_key? key
278
279
  @params.has_key?(key)
279
280
  end
280
281
  alias_method :has_param?, :has_key?
@@ -0,0 +1,45 @@
1
+ require 'nitro/render'
2
+
3
+ module Nitro
4
+
5
+ module Render
6
+
7
+ # Send a file download to the client.
8
+ #
9
+ # Like render and redirect, the action is exited upon calling
10
+ #
11
+ # [+fname+] That name of the file
12
+ # [+path+] Specifying true mean fname contains the full path.
13
+ # The default, false, uses Server.public_root as the path.
14
+ #
15
+ # [+return+] true on success, false on failure
16
+ #
17
+ # === Examples
18
+ #
19
+ # require 'nitro/cgi/sendfile'
20
+ # class MyController < Nitro:Controller
21
+ # def download(fname)
22
+ # sendfile(fname)
23
+ # end
24
+ # end
25
+ #
26
+ # class MyController < Nitro:Controller
27
+ # def download()
28
+ # sendfile('/etc/password', true)
29
+ # end
30
+ # end
31
+
32
+ def sendfile(fname=nil, fullpath=false)
33
+ fname = fullpath ? fname : "#{Server.public_root}/#{fname}"
34
+ f = File.open(fname, "rb")
35
+ @context.response_headers["Cache-control"] = 'private'
36
+ @context.response_headers["Content-Length"] = "#{File.size?(f) || 0}"
37
+ @context.response_headers["Content-Type"] = 'application/force-download'
38
+ @context.out = f
39
+ raise RenderExit
40
+ end
41
+
42
+ end
43
+
44
+ end
45
+
@@ -258,7 +258,7 @@ class Compiler
258
258
  end
259
259
 
260
260
  # Concatenate some extracted parameters.
261
- params.concat(context.params.values)
261
+ # params.concat(context.params.values)
262
262
 
263
263
  # Fill the array with nils for the missing params.
264
264
  (#{param_count} - params.size).times { params << nil }
@@ -10,7 +10,7 @@ require 'facet/ormsupport'
10
10
  # or something.
11
11
  #++
12
12
 
13
- class Exception
13
+ class Exception # :nodoc: all
14
14
 
15
15
  # Radius of the source code to display arround the error line.
16
16
 
@@ -45,7 +45,7 @@ class Exception
45
45
  source = File.read(file)
46
46
 
47
47
  if file =~ /\.xhtml$/
48
- source = Compiler.new.transform_template(source)
48
+ source = Compiler.new(Nitro::Controller).transform_template(:action, source)
49
49
  no -= 2
50
50
  end
51
51
 
@@ -105,7 +105,7 @@ class Exception
105
105
 
106
106
  def source_for_backtrace(indent = 0)
107
107
  backtrace.inject([]) do |sources, step|
108
- sources << source_extract(indent,step)
108
+ sources << source_extract(step, indent)
109
109
  end
110
110
  end
111
111
 
data/lib/nitro/context.rb CHANGED
@@ -63,6 +63,11 @@ class Context
63
63
  # initialize the output buffer.
64
64
 
65
65
  @out ||= OutputBuffer.new
66
+
67
+ # Store this instance in a thread local variable for easy
68
+ # access.
69
+
70
+ Thread.current[:CURRENT_CONTEXT] = self
66
71
  end
67
72
 
68
73
 
@@ -162,7 +167,17 @@ class Context
162
167
  alias_method :is_top?, :is_top_level?
163
168
  alias_method :in_top_level?, :is_top_level?
164
169
  alias_method :top_level?, :is_top_level?
165
-
170
+
171
+ class << self
172
+
173
+ # Returns the context for the current thread.
174
+
175
+ def current
176
+ Thread.current[:CURRENT_CONTEXT]
177
+ end
178
+
179
+ end
180
+
166
181
  end
167
182
 
168
183
  end
@@ -46,6 +46,22 @@ module Publishable
46
46
  include ::Aspects
47
47
  include Flashing
48
48
  include Helpers
49
+
50
+ # The collection of 'models' ie classes that are linked
51
+ # to this Publishable/Controller.
52
+
53
+ ann :self, :models => []
54
+
55
+ # This is a helper that 'links' one or more classes to this
56
+ # controller. In practice it annotates each class with the
57
+ # controller and stores the controller's list of 'models'.
58
+
59
+ def self.model *classes
60
+ for c in classes
61
+ c.ann :self, :controller => self
62
+ self.ann.self.models! << c
63
+ end
64
+ end
49
65
  end
50
66
 
51
67
  # Aliases an action
@@ -171,7 +187,7 @@ private
171
187
 
172
188
  # Cookie helpers.
173
189
  #--
174
- # TODO: move elsewhere.
190
+ # TODO: move elsewhere, probably to a default helper.
175
191
  #++
176
192
 
177
193
  def cookies
@@ -207,13 +223,34 @@ private
207
223
  # encode_url ForaController, :post, :title, 'Hello', :body, 'World'
208
224
  # encode_url :post, :title, 'Hello', :body, 'World' # => implies controller == self
209
225
  # encode_url :kick, :oid, 4
226
+ # encode_url article # => article.to_href
227
+ #
228
+ # Alternatively you can pass options with a hash:
229
+ #
230
+ # encode_url :controller => ForaController, :action => :delete, :params => { :title => 'Hello' }
231
+ # encode_url :action => :delete
210
232
  #--
211
233
  # FIXME: better implementation? optimize this?
212
234
  # TODO: move elsewhere.
213
235
  #++
214
236
 
215
- def encode_url(*args)
216
- if args.first.is_a?(Symbol) or args.first.is_a?(String)
237
+ def encode_url *args
238
+ f = args.first
239
+
240
+ # A standard url as string, return as is.
241
+
242
+ if f.is_a? String
243
+ return f
244
+ end
245
+
246
+ # If the passed param is an object that responds to :to_href
247
+ # returns the url to this object.
248
+
249
+ if f.respond_to? :to_href
250
+ return args.first.to_href
251
+ end
252
+
253
+ if f.is_a? Symbol
217
254
  # no controller passed, imply controller == self!
218
255
  args.unshift(self.class)
219
256
  end
@@ -278,10 +315,10 @@ class Controller
278
315
 
279
316
  # This callback is called after the Controller is mounted.
280
317
 
281
- def self.mounted(path)
318
+ def self.mounted path
282
319
  # Resolve aspects.
283
320
 
284
- ::Aspects.include_advice_modules(self)
321
+ Aspects.include_advice_modules(self)
285
322
 
286
323
  # The scaffolding code is compiled after the mount, so
287
324
  # that template roots are finalized.
@@ -289,6 +326,24 @@ class Controller
289
326
  compile_scaffolding_code()
290
327
  end
291
328
 
329
+ # Returns the current controller from the context thread local
330
+ # variable.
331
+
332
+ def self.current
333
+ Thread.current[:CURRENT_CONTROLLER]
334
+ end
335
+
336
+ #--
337
+ # Replaces the current controller (helper for render).
338
+ # This is an internal method.
339
+ #++
340
+
341
+ def self.replace_current controller # :nodoc:
342
+ old = Thread.current[:CURRENT_CONTROLLER]
343
+ Thread.current[:CURRENT_CONTROLLER] = controller
344
+ return old
345
+ end
346
+
292
347
  end
293
348
 
294
349
  end
@@ -128,7 +128,7 @@ class Dispatcher
128
128
  for m in c.action_methods
129
129
  m = m.to_sym
130
130
  if route = c.ann(m).route and (!route.nil?)
131
- add_route(route.first, :controller => c, :action => m, :params => route.last)
131
+ add_rule(route.first, :controller => c, :action => m, :params => route.last)
132
132
  end
133
133
  end
134
134
  end
@@ -168,6 +168,7 @@ class Dispatcher
168
168
  return klass, "#{action}_action", klass.mount_path
169
169
  end
170
170
 
171
+ path = path.sub(/#{Router.strip_path}/, '') if Router.strip_path
171
172
  parts = path.split('/')
172
173
  parts.shift # get rid of the leading '/'.
173
174
 
data/lib/nitro/helper.rb CHANGED
@@ -1,8 +1,6 @@
1
1
  require 'facet/kernel/constant'
2
2
  require 'facet/string/camelize'
3
3
 
4
- require 'glue/attribute'
5
-
6
4
  module Nitro
7
5
 
8
6
  # Helpers are standard Ruby modules that contain utility
@@ -90,6 +90,10 @@ module FormHelper
90
90
  # for this form. If you pass a class an empty object is
91
91
  # instantiated.
92
92
  #
93
+ # * :action = The action of this form. The parameter is
94
+ # passed through the R operator (encode_url) to support
95
+ # advanced url encoding.
96
+ #
93
97
  # === Example
94
98
  #
95
99
  # #{form(:object => @owner, :action => :save_profile) do |f|
@@ -120,7 +124,7 @@ module FormHelper
120
124
  b = FormXmlBuilder.new('', options)
121
125
 
122
126
  b << '<form'
123
- b << %| action="#{options[:action]}"| if options[:action]
127
+ b << %| action="#{R options[:action]}"| if options[:action]
124
128
  b << %| method="#{options[:method]}"| if options[:method]
125
129
  b << %| enctype="#{options[:enctype]}"| if options[:enctype]
126
130
  b << '>'
@@ -28,7 +28,7 @@ private
28
28
  # filename. Override if you don't like the defaults.
29
29
 
30
30
  def name_to_jsfile(name)
31
- "js/#{name}.js"
31
+ "/js/#{name}.js"
32
32
  end
33
33
  end
34
34