ramaze 2008.06 → 2008.11

Sign up to get free protection for your applications and to get access to all the features.
Files changed (184) hide show
  1. data/README.markdown +6 -6
  2. data/Rakefile +33 -3
  3. data/bin/ramaze +18 -0
  4. data/doc/CHANGELOG +960 -0
  5. data/doc/LEGAL +5 -1
  6. data/doc/meta/announcement.txt +20 -36
  7. data/doc/tutorial/todolist.html +421 -313
  8. data/doc/tutorial/todolist.mkd +33 -16
  9. data/examples/app/blog/spec/blog.rb +3 -3
  10. data/examples/app/rapaste/controller/paste.rb +8 -1
  11. data/examples/app/rapaste/model/paste.rb +3 -0
  12. data/examples/app/rapaste/spec/rapaste.rb +3 -1
  13. data/examples/app/rapaste/start.rb +3 -2
  14. data/examples/app/sourceview/public/sourceview.js +2 -2
  15. data/examples/app/todolist/spec/todolist.rb +6 -6
  16. data/examples/app/todolist/template/index.xhtml +1 -1
  17. data/examples/app/whywiki/spec/whywiki.rb +2 -2
  18. data/examples/app/wikore/spec/wikore.rb +2 -2
  19. data/examples/app/wikore/src/model.rb +4 -3
  20. data/examples/app/wiktacular/spec/wiktacular.rb +7 -7
  21. data/examples/basic/simple.rb +2 -2
  22. data/examples/helpers/paginate.rb +71 -0
  23. data/examples/misc/simple_auth.rb +20 -8
  24. data/lib/proto/controller/init.rb +10 -0
  25. data/lib/proto/controller/main.rb +1 -3
  26. data/lib/proto/model/init.rb +4 -0
  27. data/lib/proto/public/dispatch.fcgi +1 -1
  28. data/lib/proto/spec/main.rb +2 -1
  29. data/lib/proto/start.rb +3 -3
  30. data/lib/proto/start.ru +1 -1
  31. data/lib/proto/view/error.xhtml +4 -4
  32. data/lib/ramaze.rb +8 -3
  33. data/lib/ramaze/action.rb +6 -6
  34. data/lib/ramaze/adapter.rb +1 -6
  35. data/lib/ramaze/adapter/base.rb +30 -27
  36. data/lib/ramaze/adapter/cgi.rb +1 -0
  37. data/lib/ramaze/cache.rb +1 -3
  38. data/lib/ramaze/cache/memcached.rb +3 -5
  39. data/lib/ramaze/contrib/auto_params.rb +2 -2
  40. data/lib/ramaze/contrib/auto_params/get_args.rb +2 -1
  41. data/lib/ramaze/contrib/gems.rb +17 -18
  42. data/lib/ramaze/contrib/gzip_filter.rb +22 -9
  43. data/lib/ramaze/contrib/maruku_uv.rb +59 -0
  44. data/lib/ramaze/contrib/profiling.rb +1 -1
  45. data/lib/ramaze/contrib/rest.rb +16 -13
  46. data/lib/ramaze/contrib/sequel/create_join.rb +25 -0
  47. data/lib/ramaze/contrib/sequel/form_field.rb +129 -0
  48. data/lib/ramaze/contrib/sequel/image.rb +198 -0
  49. data/lib/ramaze/contrib/sequel/relation.rb +82 -0
  50. data/lib/ramaze/controller.rb +33 -34
  51. data/lib/ramaze/controller/resolve.rb +29 -9
  52. data/lib/ramaze/current.rb +60 -20
  53. data/lib/ramaze/current/request.rb +8 -7
  54. data/lib/ramaze/current/response.rb +15 -3
  55. data/lib/ramaze/current/session/flash.rb +8 -0
  56. data/lib/ramaze/dispatcher.rb +17 -9
  57. data/lib/ramaze/dispatcher/action.rb +4 -5
  58. data/lib/ramaze/dispatcher/directory.rb +1 -1
  59. data/lib/ramaze/dispatcher/error.rb +4 -4
  60. data/lib/ramaze/dispatcher/file.rb +4 -4
  61. data/lib/ramaze/gestalt.rb +15 -20
  62. data/lib/ramaze/helper/cgi.rb +7 -15
  63. data/lib/ramaze/helper/formatting.rb +41 -1
  64. data/lib/ramaze/helper/httpdigest.rb +20 -7
  65. data/lib/ramaze/helper/link.rb +4 -6
  66. data/lib/ramaze/helper/paginate.rb +233 -0
  67. data/lib/ramaze/helper/redirect.rb +1 -1
  68. data/lib/ramaze/helper/rest.rb +1 -1
  69. data/lib/ramaze/helper/thread.rb +17 -0
  70. data/lib/ramaze/helper/ultraviolet.rb +44 -0
  71. data/lib/ramaze/helper/user.rb +4 -9
  72. data/lib/ramaze/log.rb +2 -2
  73. data/lib/ramaze/log/analogger.rb +21 -23
  74. data/lib/ramaze/log/growl.rb +21 -23
  75. data/lib/ramaze/log/hub.rb +1 -1
  76. data/lib/ramaze/log/informer.rb +97 -99
  77. data/lib/ramaze/log/knotify.rb +14 -16
  78. data/lib/ramaze/log/logger.rb +11 -13
  79. data/lib/ramaze/log/logging.rb +61 -63
  80. data/lib/ramaze/log/rotatinginformer.rb +168 -0
  81. data/lib/ramaze/log/syslog.rb +41 -31
  82. data/lib/ramaze/log/xosd.rb +70 -72
  83. data/lib/ramaze/option.rb +9 -6
  84. data/lib/ramaze/option/holder.rb +5 -27
  85. data/lib/ramaze/reloader.rb +186 -0
  86. data/lib/ramaze/setup.rb +1 -1
  87. data/lib/ramaze/snippets.rb +13 -0
  88. data/lib/ramaze/snippets/array/put_within.rb +31 -24
  89. data/lib/ramaze/snippets/binding/locals.rb +23 -11
  90. data/lib/ramaze/snippets/dictionary.rb +2 -2
  91. data/lib/ramaze/snippets/fiber.rb +63 -0
  92. data/lib/ramaze/snippets/kernel/constant.rb +36 -21
  93. data/lib/ramaze/snippets/kernel/pretty_inspect.rb +12 -6
  94. data/lib/ramaze/snippets/numeric/filesize_format.rb +24 -17
  95. data/lib/ramaze/snippets/numeric/time.rb +63 -0
  96. data/lib/ramaze/snippets/object/__dir__.rb +29 -0
  97. data/lib/ramaze/snippets/object/acquire.rb +40 -0
  98. data/lib/ramaze/snippets/object/instance_variable_defined.rb +16 -5
  99. data/lib/ramaze/snippets/object/pretty.rb +14 -4
  100. data/lib/ramaze/snippets/object/scope.rb +14 -7
  101. data/lib/ramaze/snippets/ordered_set.rb +25 -14
  102. data/lib/ramaze/snippets/proc/locals.rb +17 -9
  103. data/lib/ramaze/snippets/ramaze/deprecated.rb +13 -0
  104. data/lib/ramaze/snippets/ramaze/fiber.rb +24 -0
  105. data/lib/ramaze/snippets/ramaze/state.rb +86 -0
  106. data/lib/ramaze/snippets/ramaze/struct.rb +45 -0
  107. data/lib/ramaze/snippets/string/camel_case.rb +13 -8
  108. data/lib/ramaze/snippets/string/color.rb +24 -20
  109. data/lib/ramaze/snippets/string/each.rb +14 -3
  110. data/lib/ramaze/snippets/string/end_with.rb +20 -0
  111. data/lib/ramaze/snippets/string/esc.rb +26 -21
  112. data/lib/ramaze/snippets/string/ord.rb +12 -6
  113. data/lib/ramaze/snippets/string/snake_case.rb +13 -7
  114. data/lib/ramaze/snippets/string/start_with.rb +16 -5
  115. data/lib/ramaze/snippets/string/unindent.rb +23 -15
  116. data/lib/ramaze/snippets/thread/into.rb +3 -3
  117. data/lib/ramaze/spec/helper/bacon.rb +5 -5
  118. data/lib/ramaze/spec/helper/mock_http.rb +1 -1
  119. data/lib/ramaze/spec/helper/pretty_output.rb +2 -2
  120. data/lib/ramaze/spec/helper/snippets.rb +8 -0
  121. data/lib/ramaze/template.rb +4 -1
  122. data/lib/ramaze/template/ezamar/textpow.syntax +34 -0
  123. data/lib/ramaze/template/maruku.rb +34 -0
  124. data/lib/ramaze/template/tagz.rb +2 -2
  125. data/lib/ramaze/template/xslt.rb +2 -2
  126. data/lib/ramaze/tool/create.rb +27 -53
  127. data/lib/ramaze/tool/localize.rb +8 -4
  128. data/lib/ramaze/tool/mime.rb +11 -1
  129. data/lib/ramaze/tool/project_creator.rb +110 -0
  130. data/lib/ramaze/trinity.rb +4 -1
  131. data/lib/ramaze/version.rb +1 -1
  132. data/lib/vendor/bacon.rb +323 -0
  133. data/rake_tasks/gem.rake +10 -1
  134. data/rake_tasks/maintenance.rake +40 -2
  135. data/rake_tasks/metric.rake +24 -0
  136. data/rake_tasks/release.rake +17 -4
  137. data/rake_tasks/spec.rake +1 -2
  138. data/ramaze.gemspec +549 -495
  139. data/spec/contrib/auto_params.rb +3 -3
  140. data/spec/contrib/profiling.rb +2 -2
  141. data/spec/examples/simple_auth.rb +2 -2
  142. data/spec/examples/templates/template_haml.rb +0 -2
  143. data/spec/ramaze/action/file_cache.rb +22 -0
  144. data/spec/ramaze/adapter.rb +2 -2
  145. data/spec/ramaze/controller/actionless_templates.rb +1 -1
  146. data/spec/ramaze/controller/subclass.rb +15 -0
  147. data/spec/ramaze/controller/template_resolving.rb +1 -1
  148. data/spec/ramaze/controller/view/bar.xhtml +1 -0
  149. data/spec/ramaze/controller/view/base/another.xhtml +1 -0
  150. data/spec/ramaze/current/session.rb +1 -1
  151. data/spec/ramaze/dispatcher/file.rb +2 -2
  152. data/spec/ramaze/helper/aspect.rb +26 -17
  153. data/spec/ramaze/helper/formatting.rb +13 -0
  154. data/spec/ramaze/log/informer.rb +10 -10
  155. data/spec/ramaze/log/syslog.rb +67 -4
  156. data/spec/ramaze/rewrite.rb +1 -1
  157. data/spec/ramaze/route.rb +1 -1
  158. data/spec/ramaze/struct.rb +47 -0
  159. data/spec/ramaze/template/markaby.rb +1 -1
  160. data/spec/ramaze/template/tagz.rb +1 -1
  161. data/spec/snippets/binding/locals.rb +9 -0
  162. data/spec/snippets/numeric/time.rb +12 -0
  163. data/spec/snippets/{kernel → object}/__dir__.rb +0 -0
  164. data/spec/snippets/{kernel → object}/acquire.rb +0 -0
  165. metadata +90 -81
  166. data/cache.yaml +0 -7
  167. data/examples/app/rammit/spec/rammit.rb +0 -31
  168. data/examples/app/rammit/src/controller/main.rb +0 -3
  169. data/examples/app/rammit/src/controller/page.rb +0 -16
  170. data/examples/app/rammit/src/model.rb +0 -33
  171. data/examples/app/rammit/start.rb +0 -8
  172. data/examples/app/rammit/template/index.xhtml +0 -14
  173. data/examples/app/rammit/template/page/view.xhtml +0 -4
  174. data/lib/ramaze/snippets/kernel/__dir__.rb +0 -23
  175. data/lib/ramaze/snippets/kernel/acquire.rb +0 -34
  176. data/lib/ramaze/snippets/object/thread_accessor.rb +0 -5
  177. data/lib/ramaze/snippets/ramaze/thread_accessor.rb +0 -58
  178. data/lib/ramaze/snippets/struct/fill.rb +0 -23
  179. data/lib/ramaze/snippets/struct/values_at.rb +0 -39
  180. data/lib/ramaze/snippets/symbol/to_proc.rb +0 -24
  181. data/lib/ramaze/sourcereload.rb +0 -176
  182. data/spec/snippets/struct/fill.rb +0 -26
  183. data/spec/snippets/struct/values_at.rb +0 -52
  184. data/spec/snippets/symbol/to_proc.rb +0 -13
@@ -0,0 +1,82 @@
1
+ # Copyright (c) 2008 Michael Fellinger m.fellinger@gmail.com
2
+ # All files in this distribution are subject to the terms of the Ruby license.
3
+
4
+ # Pretty DSL to express Sequel relations
5
+ #
6
+ # Usage:
7
+ # SequelRelation.relations do
8
+ # the User do
9
+ # has_many Article
10
+ # has_one Avatar
11
+ # end
12
+ #
13
+ # the Article do
14
+ # belongs_to User
15
+ # end
16
+ #
17
+ # the Avatar do
18
+ # belongs_to User
19
+ # end
20
+ # end
21
+
22
+ module SequelRelation
23
+ def self.relations(&block)
24
+ rema = RelationshipManager.new(&block)
25
+ rema.finalize
26
+ end
27
+
28
+ class RelationshipManager
29
+ TODO = {}
30
+
31
+ def initialize(&block)
32
+ instance_eval(&block)
33
+ end
34
+
35
+ def finalize
36
+ TODO.keys.each do |model|
37
+ model.create_table unless model.table_exists?
38
+ end
39
+
40
+ TODO.each do |model, instructions|
41
+ instructions.each do |args|
42
+ model.send(*args)
43
+ end
44
+ end
45
+
46
+ return # remove this line for debugging
47
+
48
+ pp TODO
49
+
50
+ TODO.keys.each do |model|
51
+ puts "the #{model}"
52
+ assoc = model.send(:association_reflections)
53
+ assoc.each do |key, reflection|
54
+ puts " #{reflection[:type]} => #{key}"
55
+ end
56
+ end
57
+ end
58
+
59
+ def the(left_model, &block)
60
+ @left = left_model
61
+ TODO[@left] = []
62
+ instance_eval(&block)
63
+ end
64
+
65
+ def belongs_to(model)
66
+ todo :belongs_to, model.to_s.downcase.to_sym
67
+ end
68
+
69
+ def has_many(model)
70
+ todo :create_join, model
71
+ todo :many_to_many, model.to_s.downcase.pluralize.to_sym
72
+ end
73
+
74
+ def has_one(model)
75
+ todo :belongs_to, model.to_s.downcase.to_sym
76
+ end
77
+
78
+ def todo(method, *args)
79
+ TODO[@left] << [method, *args]
80
+ end
81
+ end
82
+ end
@@ -85,7 +85,7 @@ module Ramaze
85
85
  def map(*syms)
86
86
  Global.mapping.delete_if{|k,v| v == self}
87
87
 
88
- syms.each do |sym|
88
+ syms.compact.each do |sym|
89
89
  Global.mapping[sym.to_s] = self
90
90
  end
91
91
  end
@@ -150,17 +150,10 @@ module Ramaze
150
150
  # Runs every given path through Controller::check_path
151
151
 
152
152
  def view_root *args
153
- if args.empty?
154
- @view_root
155
- else
156
- check_path("#{self}.view_root: '%s' doesn't exist", *args)
157
- @view_root = args.flatten
158
- end
159
- end
153
+ return @view_root if args.empty?
160
154
 
161
- def template_root(*args)
162
- Ramaze.deprecated("Controller::template_root", "Controller::view_root")
163
- view_root(*args)
155
+ check_path("#{self}.view_root: '%s' doesn't exist", *args)
156
+ @view_root = args.flatten
164
157
  end
165
158
 
166
159
  # This is used for template rerouting, takes action, optionally a
@@ -202,30 +195,36 @@ module Ramaze
202
195
 
203
196
  def template(this, *argv)
204
197
  case argv.first
205
- when Hash
206
- options, *ignored = argv
207
- controller = options[:controller] || options['controller']
208
- action = options[:action] || options['action']
209
- file = options[:file] || options['file']
210
- info = {}
211
- if file
212
- file = file.to_s
213
- unless Pathname(file).absolute?
214
- root = [view_root || Global.view_root].flatten.first
215
- file = File.join(root, file)
216
- end
217
- info[:file] = file
218
- else
219
- controller ||= self
220
- action = (action || 'index').to_s
221
- info[:controller] = controller
222
- info[:action] = action
198
+ when Hash
199
+ options, *ignored = argv
200
+ controller = options[:controller] || options['controller']
201
+ action = options[:action] || options['action']
202
+ file = options[:file] || options['file']
203
+ info = {}
204
+ if file
205
+ file = file.to_s
206
+ unless Pathname(file).absolute?
207
+ root = [view_root || Global.view_root].flatten.first
208
+ file = File.join(root, file)
223
209
  end
224
- trait "#{this}_template" => info
210
+ info[:file] = file
225
211
  else
226
- controller, action, *ignored = argv
227
- controller, action = self, controller unless action
228
- trait "#{this}_template" => {:controller => controller, :action => action}
212
+ controller ||= self
213
+ action = (action || 'index').to_s
214
+ info[:controller] = controller
215
+ info[:action] = action
216
+ end
217
+ trait "#{this}_template" => info
218
+ else
219
+ # Only explicitly set the controller to use, if it was explicitly given.
220
+ # This helps ensure that template mappings still work in subclasses
221
+ # of this controller.
222
+ first, second, *ignored = argv
223
+ if second
224
+ trait "#{this}_template" => {:controller => first, :action => second}
225
+ else
226
+ trait "#{this}_template" => {:action => first}
227
+ end
229
228
  end
230
229
  end
231
230
 
@@ -259,7 +258,7 @@ module Ramaze
259
258
 
260
259
  def handle path
261
260
  action = resolve(path)
262
- Thread.current[:controller] = action.controller
261
+ STATE[:controller] = action.controller
263
262
  action.render
264
263
  end
265
264
 
@@ -104,10 +104,13 @@ module Ramaze
104
104
 
105
105
  def resolve_action(path, *parameter)
106
106
  path, parameter = path.to_s, parameter.map{|e| e.to_s}
107
- if info = trait["#{path}_template"]
107
+ # Use ancestral_trait so if template is set in superclass, it is still found.
108
+ if info = ancestral_trait["#{path}_template"]
108
109
  template = info[:file]
109
110
  unless template
110
111
  controller, action = info.values_at :controller, :action
112
+ # Controller may not have been explicitly set, in which case use self.
113
+ controller ||= self
111
114
  template = controller.resolve_template(action)
112
115
  end
113
116
  end
@@ -154,15 +157,25 @@ module Ramaze
154
157
  end
155
158
  end
156
159
 
157
- # Based on methodname and arity, tries to find the right method on current controller.
160
+ # Based on methodname and arity, tries to find the right method on
161
+ # current controller.
158
162
  def resolve_method(name, *params)
159
- if method = [ name, name.gsub('__','/') ].find{|n|
160
- cached_action_methods.include?(n) }
163
+ cam = cached_action_methods
164
+
165
+ if cam.include?(name)
166
+ method = name
167
+ else
168
+ name = name.gsub(/__/, '/')
169
+ method = name if cam.include?(name)
170
+ end
171
+
172
+ if method
161
173
  arity = instance_method(method).arity
162
- if params.size == arity or arity < 0
174
+ if arity < 0 or params.size == arity
163
175
  return method, params
164
176
  end
165
177
  end
178
+
166
179
  return nil, []
167
180
  end
168
181
 
@@ -174,8 +187,7 @@ module Ramaze
174
187
 
175
188
  # methodnames that may be used for current controller.
176
189
  def action_methods
177
- ancs = relevant_ancestors + Helper::LOOKUP.to_a
178
-
190
+ ancs = relevant_ancestors + action_modules
179
191
  ancs.reverse.inject [] do |meths, anc|
180
192
  meths +
181
193
  anc.public_instance_methods(false).map{|im| im.to_s } -
@@ -183,6 +195,14 @@ module Ramaze
183
195
  end
184
196
  end
185
197
 
198
+ # Array of all modules (so including Ramaze helpers) that are included in
199
+ # this controller and where the module is also in the Helper::LOOKUP set.
200
+ # Hence this is the included modules whose public methods may be exposed
201
+ # as actions of this controller.
202
+ def action_modules
203
+ Helper::LOOKUP.find_all {|mod| self.include?(mod)}
204
+ end
205
+
186
206
  # Iterator that yields potential ways in which a given path could be mapped
187
207
  # to controller, action and params. It produces them in strict order, with
188
208
  # longest controller path favoured, then longest action path.
@@ -230,7 +250,7 @@ module Ramaze
230
250
  # Raises Ramaze::Error::NoFilter
231
251
  # TODO:
232
252
  # * is this called at all for anybody?
233
- # I think everybody does have filters.
253
+ # I think everybody has filters.
234
254
 
235
255
  def raise_no_filter(path)
236
256
  raise Ramaze::Error::NoFilter, "No Filter found for `#{path}'"
@@ -245,7 +265,7 @@ module Ramaze
245
265
  # Raises Ramaze::Error::NoAction
246
266
 
247
267
  def raise_no_action(controller, path)
248
- Thread.current[:controller] = controller
268
+ STATE[:controller] = controller
249
269
  raise Ramaze::Error::NoAction, "No Action found for `#{path}' on #{controller}"
250
270
  end
251
271
  end
@@ -3,6 +3,54 @@ require 'ramaze/current/response'
3
3
  require 'ramaze/current/session'
4
4
 
5
5
  module Ramaze
6
+ class Current
7
+ include Trinity
8
+ extend Trinity
9
+
10
+ def initialize(app)
11
+ @app = app
12
+ end
13
+
14
+ def call(env)
15
+ setup(env)
16
+ before_call
17
+ record
18
+
19
+ @app.call(env)
20
+ finish
21
+ ensure
22
+ after_call
23
+ end
24
+
25
+ def record
26
+ return unless filter = Global.record
27
+ request = Current.request
28
+ Record << request if filter.call(request)
29
+ end
30
+
31
+ def setup(env)
32
+ self.request = Request.new(env)
33
+ self.response = Response.new
34
+ self.session = Session.new
35
+ end
36
+
37
+ def finish
38
+ session.finish if session
39
+ response.finish
40
+ end
41
+
42
+ def self.call(env)
43
+ end
44
+
45
+ def before_call
46
+ end
47
+
48
+ def after_call
49
+ end
50
+ end
51
+ end
52
+ __END__
53
+
6
54
  module Current
7
55
  class << self
8
56
  include Trinity
@@ -35,35 +83,27 @@ module Ramaze
35
83
  end
36
84
 
37
85
  def before(&block)
38
- @before = block if block
39
- @before
86
+ @before = block_given? ? block : @before
40
87
  end
41
88
 
42
89
  def before_call
43
- if before
44
- begin
45
- before.call
46
- rescue Object => e
47
- Ramaze::Log.error e
48
- raise
49
- end
50
- end
90
+ return unless before
91
+ before.call
92
+ rescue Object => e
93
+ Ramaze::Log.error e
94
+ raise e
51
95
  end
52
96
 
53
97
  def after(&block)
54
- @after = block if block
55
- @after
98
+ @after = block_given? ? block : @after
56
99
  end
57
100
 
58
101
  def after_call
59
- if after
60
- begin
61
- after.call
62
- rescue Object => e
63
- Ramaze::Log.error e
64
- raise
65
- end
66
- end
102
+ return unless after
103
+ after.call
104
+ rescue Object => e
105
+ Ramaze::Log.error e
106
+ raise e
67
107
  end
68
108
  end
69
109
  end
@@ -11,7 +11,7 @@ module Ramaze
11
11
  class Request < ::Rack::Request
12
12
  class << self
13
13
 
14
- # get the current request out of Thread.current[:request]
14
+ # get the current request out of STATE[:request]
15
15
  #
16
16
  # You can call this from everywhere with Ramaze::Request.current
17
17
 
@@ -33,7 +33,11 @@ module Ramaze
33
33
  end
34
34
 
35
35
  def ip
36
- env['HTTP_X_FORWARDED_FOR'] || env['REMOTE_ADDR']
36
+ if addr = env['HTTP_X_FORWARDED_FOR']
37
+ addr.split(',').last.strip
38
+ else
39
+ env['REMOTE_ADDR']
40
+ end
37
41
  end
38
42
 
39
43
  # Request is from a local network?
@@ -48,7 +52,6 @@ module Ramaze
48
52
  # ++
49
53
 
50
54
  def local_net?(address = ip)
51
- address = address.to_s.split(',').first
52
55
  addr = IPAddr.new(address)
53
56
  LOCAL.find{|range| range.include?(addr) }
54
57
  rescue ArgumentError => ex
@@ -56,10 +59,8 @@ module Ramaze
56
59
  end
57
60
 
58
61
  def [](key, *rest)
59
- value = params[key.to_s]
60
- return value if rest.empty?
61
- keys = rest.flatten.map{|k| k.to_s}
62
- Array[value, *params.values_at(*keys)]
62
+ return params[key.to_s] if rest.empty?
63
+ [key, *rest].map{|k| params[k.to_s] }
63
64
  end
64
65
 
65
66
  def to_ivs(*args)
@@ -15,13 +15,25 @@ module Ramaze
15
15
  end
16
16
 
17
17
  # Build/replace this responses data
18
- def build(body = body, status = status, header = header)
18
+ def build(new_body = body, status = status, header = header)
19
19
  header.each do |key, value|
20
20
  self[key] = value
21
21
  end
22
22
 
23
- self.body, self.status = body, status
24
- self
23
+ self.body, self.status = new_body, status
24
+ end
25
+
26
+ def body=(obj)
27
+ if obj.respond_to?(:stat)
28
+ @length = obj.stat.size
29
+ @body = obj
30
+ elsif obj.respond_to?(:size)
31
+ @body = []
32
+ @length = 0
33
+ write(obj)
34
+ else
35
+ raise(ArgumentError, "Invalid body: %p" % obj)
36
+ end
25
37
  end
26
38
  end
27
39
  end
@@ -67,6 +67,14 @@ module Ramaze
67
67
  combined.empty?
68
68
  end
69
69
 
70
+ def merge!(hash)
71
+ current.merge!(hash)
72
+ end
73
+
74
+ def merge(hash)
75
+ current.merge(hash)
76
+ end
77
+
70
78
  private
71
79
 
72
80
  # Associated session object