ramaze 2008.06 → 2008.11

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.
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