merb-core 1.1.0.rc1 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -372,15 +372,12 @@ class Merb::BootLoader::Dependencies < Merb::BootLoader
372
372
  # :api: plugin
373
373
  def self.run
374
374
  set_encoding
375
- # this is crucial: load init file with all the preferences
376
- # then environment init file, then start enabling specific
377
- # components, load dependencies and update logger.
375
+ load_dependencies
378
376
  unless Merb::disabled?(:initfile)
379
377
  load_initfile
380
378
  load_env_config
381
379
  end
382
380
  expand_ruby_path
383
- load_dependencies
384
381
  update_logger
385
382
  nil
386
383
  end
@@ -1036,7 +1033,6 @@ class Merb::BootLoader::LoadClasses < Merb::BootLoader
1036
1033
  error_map = {}
1037
1034
 
1038
1035
  klasses.each do |klass|
1039
- klasses.delete(klass)
1040
1036
  begin
1041
1037
  load_file klass
1042
1038
  rescue NameError => ne
@@ -1044,6 +1040,7 @@ class Merb::BootLoader::LoadClasses < Merb::BootLoader
1044
1040
  failed_classes.push(klass)
1045
1041
  end
1046
1042
  end
1043
+ klasses.clear
1047
1044
 
1048
1045
  # Keep list of classes unique
1049
1046
  failed_classes.each { |k| klasses.push(k) unless klasses.include?(k) }
@@ -1317,6 +1314,8 @@ class Merb::BootLoader::RackUpApplication < Merb::BootLoader
1317
1314
  Merb::Config[:app] = eval("::Rack::Builder.new {( #{rackup_code}\n )}.to_app", TOPLEVEL_BINDING, Merb::Config[:rackup])
1318
1315
  else
1319
1316
  Merb::Config[:app] = ::Rack::Builder.new {
1317
+ use Rack::Head # handle head requests
1318
+ use Merb::Rack::ContentLength # report content length
1320
1319
  if prefix = ::Merb::Config[:path_prefix]
1321
1320
  use Merb::Rack::PathPrefix, prefix
1322
1321
  end
@@ -173,6 +173,9 @@ module Merb
173
173
  config[:bind_fail_fatal] = dev_mode
174
174
  end
175
175
 
176
+ # Set mutex to dispatcher
177
+ ::Merb::Dispatcher.use_mutex = config[:use_mutex]
178
+
176
179
  @configuration = config
177
180
  end
178
181
 
@@ -7,94 +7,109 @@
7
7
  # +request_fresh?+ that is used after setting of
8
8
  # last modification time or ETag:
9
9
  #
10
- # ==== Example
10
+ #
11
+ # @example
12
+ # def show
13
+ # self.etag = Digest::SHA1.hexdigest(calculate_cache_key(params))
11
14
  #
12
- # def show
13
- # self.etag = Digest::SHA1.hexdigest(calculate_cache_key(params))
14
- #
15
- # if request_fresh?
16
- # self.status = 304
17
- # return ''
18
- # else
19
- # @product = Product.get(params[:id])
20
- # display @product
15
+ # if request_fresh?
16
+ # self.status = 304
17
+ # return ''
18
+ # else
19
+ # @product = Product.get(params[:id])
20
+ # display @product
21
+ # end
21
22
  # end
22
- # end
23
23
  module Merb::ConditionalGetMixin
24
24
 
25
- # Sets ETag response header by calling
26
- # #to_s on the argument.
25
+ # Sets ETag response header by calling #to_s on the argument
26
+ #
27
+ # @param tag [#to_s] value of ETag header
27
28
  #
28
- # ==== Parameters
29
- # tag<~to_s>::
30
- # value of ETag header enclosed in double quotes
31
- # as required by the RFC
29
+ # @return [String] value of ETag header enclosed in double quotes as required by the RFC
32
30
  #
33
- # :api: public
31
+ # @api public
34
32
  def etag=(tag)
35
33
  headers[Merb::Const::ETAG] = %("#{tag}")
36
34
  end
37
35
 
38
- # ==== Returns
39
- # <String>::
40
- # Value of ETag response header or nil if it's not set.
36
+ # Value of the ETag header
37
+ #
38
+ # @return [String] Value of ETag response header if set.
39
+ # @return [nil] If ETag header not set.
41
40
  #
42
- # :api: public
41
+ # @api public
43
42
  def etag
44
43
  headers[Merb::Const::ETAG]
45
44
  end
46
45
 
47
- # ==== Returns
48
- # <Boolean>::
49
- # true if ETag response header equals If-None-Match request header,
50
- # false otherwise
46
+ # Test to see if the request's Etag matches the one supplied locally
51
47
  #
52
- # :api: public
48
+ # @return [true] if ETag response header equals If-None-Match request header
49
+ # @return [true] if it does not.
50
+ #
51
+ # @api public
53
52
  def etag_matches?(tag = self.etag)
54
53
  tag == self.request.if_none_match
55
54
  end
56
55
 
57
- # Sets Last-Modified response header.
56
+ # Sets Last-Modified response header
57
+ #
58
+ # @param time [Time,DateTime] The last modified time of the resource
58
59
  #
59
- # ==== Parameters
60
- # tag<Time>::
61
- # resource modification timestamp converted into format
62
- # required by the RFC
60
+ # @return [String] The last modified time of the resource in the format required by the RFC
63
61
  #
64
- # :api: public
62
+ # @api public
65
63
  def last_modified=(time)
66
64
  time = time.to_time if time.is_a?(DateTime)
67
65
  # time.utc.strftime("%a, %d %b %Y %X") if we could rely on locale being American
68
66
  headers[Merb::Const::LAST_MODIFIED] = time.httpdate
69
67
  end
70
68
 
71
- # ==== Returns
72
- # <String>::
73
- # Value of Last-Modified response header or nil if it's not set.
69
+ # Value of the Last-Modified header
70
+ #
71
+ # @return [Time] Value of Last-Modified response header if set.
72
+ # @return [nil] If Last-Modified not set.
74
73
  #
75
- # :api: public
74
+ # @api public
76
75
  def last_modified
77
76
  last_mod = headers[Merb::Const::LAST_MODIFIED]
78
77
  Time.rfc2822(last_mod) if last_mod
79
78
  end
80
79
 
81
- # ==== Returns
82
- # <Boolean>::
83
- # true if Last-Modified response header is < than
84
- # If-Modified-Since request header value, false otherwise.
80
+ # Test to see if the request's If-Modified-Since is satisfied
85
81
  #
86
- # :api: public
82
+ # @param time [Time] Time to test if the If-Modified-Since header against
83
+ #
84
+ # @return [true] Last-Modified response header is < than If-Modified-Since request header
85
+ # @return [false] otherwise
86
+ #
87
+ # @api public
87
88
  def not_modified?(time = self.last_modified)
88
- request.if_modified_since && time && time <= request.if_modified_since
89
+ if !request.if_modified_since.nil? and !time.nil?
90
+ time <= request.if_modified_since
91
+ else
92
+ false
93
+ end
89
94
  end
90
95
 
91
- # ==== Returns
92
- # <Boolean>::
93
- # true if either ETag matches or entity is not modified,
94
- # so request is fresh; false otherwise
96
+ # Tests freshness of response using all supplied validators
97
+ #
98
+ # A response with no validators is always stale.
95
99
  #
96
- # :api: public
100
+ # @return [true] ETag matches and entity is not modified
101
+ # @return [false] One or more validators failed, or none were supplied
102
+ #
103
+ # @api public
97
104
  def request_fresh?
98
- etag_matches?(self.etag) || not_modified?(self.last_modified)
105
+ # make sure we have something to compare too.
106
+ return false unless last_modified or etag
107
+
108
+ fresh = true
109
+
110
+ # only check if we have set the right headers
111
+ fresh &&= etag_matches?(self.etag) if etag
112
+ fresh &&= not_modified?(self.last_modified) if last_modified
113
+ fresh
99
114
  end
100
115
  end
@@ -124,6 +124,10 @@ module Merb
124
124
  # Shorthand for common usage :message => {:error => "..."}
125
125
  # :success<String>::
126
126
  # Shorthand for common usage :message => {:success => "..."}
127
+ # :status<String, Symbol>::
128
+ # Status code to set for the response. Can be any valid redirect
129
+ # status. Has precedence over the :permanent parameter, which is
130
+ # retained for convenience.
127
131
  #
128
132
  # ==== Returns
129
133
  # String:: Explanation of redirect.
@@ -141,7 +145,11 @@ module Merb
141
145
  opts = default_redirect_options.merge(opts)
142
146
 
143
147
  url = handle_redirect_messages(url,opts)
144
- self.status = opts[:permanent] ? 301 : 302
148
+
149
+ _status = opts[:status] if opts[:status]
150
+ _status ||= opts[:permanent] ? 301 : 302
151
+ self.status = _status
152
+
145
153
  Merb.logger.info("Redirecting to: #{url} (#{self.status})")
146
154
  headers['Location'] = url
147
155
  "<html><body>You are being <a href=\"#{url}\">redirected</a>.</body></html>"
@@ -187,6 +187,10 @@ module Merb::Template
187
187
  require 'erubis'
188
188
 
189
189
  class Erubis
190
+ # Fixing bug in Erubis
191
+ # http://rubyforge.org/tracker/index.php?func=detail&aid=21825&group_id=1320&atid=5201
192
+ XmlHelper = ::Erubis::XmlHelper
193
+
190
194
  # ==== Parameters
191
195
  # io<#path>:: An IO containing the full path of the template.
192
196
  # name<String>:: The name of the method that will be created.
@@ -18,8 +18,6 @@ module Merb
18
18
  @@work_queue
19
19
  end
20
20
 
21
- Merb::Dispatcher.use_mutex = ::Merb::Config[:use_mutex]
22
-
23
21
  # Dispatch the rack environment. ControllerExceptions are rescued here
24
22
  # and redispatched.
25
23
  #
@@ -127,12 +127,17 @@ module Merb
127
127
  else
128
128
  data = body
129
129
  end
130
+
130
131
  unless key_memo.include?(name) && name !~ /\[\]/
131
132
  paramhsh = normalize_params(paramhsh,name,data)
132
133
  end
133
- key_memo << name
134
+
135
+ # Prevent from double processing files but process other params
136
+ key_memo << name if filename && !filename.empty?
137
+
134
138
  break if buf.empty? || content_length == -1
135
139
  }
140
+
136
141
  paramhsh
137
142
  end
138
143
 
@@ -6,6 +6,9 @@ module Merb
6
6
  # :api: private
7
7
  attr_accessor :_fingerprint
8
8
 
9
+ # Determines how many times to try generating a unique session key before we give up
10
+ GENERATE_MAX_TRIES = 100
11
+
9
12
  # The class attribute :store holds a reference to an object that implements
10
13
  # the following interface:
11
14
  #
@@ -54,7 +57,17 @@ module Merb
54
57
  #
55
58
  # :api: private
56
59
  def generate
57
- session = new(Merb::SessionMixin.rand_uuid)
60
+
61
+ # make sure we generate a unique session uuid
62
+ sid = nil
63
+ GENERATE_MAX_TRIES.times do |i|
64
+ sid = Merb::SessionMixin.rand_uuid
65
+ data = store.retrieve_session(sid) rescue nil
66
+ break if data.nil?
67
+ raise "Unable to Generate Unique Session key" if i == (GENERATE_MAX_TRIES-1)
68
+ end
69
+
70
+ session = new(sid)
58
71
  session.needs_new_cookie = true
59
72
  session
60
73
  end
@@ -83,16 +83,20 @@ module Merb
83
83
 
84
84
  begin
85
85
  response.status = status.to_i
86
+ response.send_status(body.respond_to?(:length) ? body.length : nil)
87
+
86
88
  headers.each { |k, vs|
87
89
  Array(vs).each { |v|
88
90
  response.header[k] = v
89
91
  }
90
92
  }
93
+ response.send_header
91
94
 
92
95
  body.each { |part|
93
- response.body << part
96
+ response.write(part)
97
+ response.socket.flush
94
98
  }
95
- response.finished
99
+ response.done = true
96
100
  ensure
97
101
  body.close if body.respond_to? :close
98
102
  end
@@ -1,6 +1,5 @@
1
1
  module Merb::Test::MultipartRequestHelper
2
2
  require 'rubygems'
3
- gem "mime-types"
4
3
  require 'mime/types'
5
4
 
6
5
  class Param
@@ -1,3 +1,3 @@
1
1
  module Merb
2
- VERSION = '1.1.0.rc1'.freeze
2
+ VERSION = '1.1.0'.freeze
3
3
  end
@@ -3,9 +3,9 @@ require File.join(File.dirname(__FILE__), "spec_helper")
3
3
  Controllers = Merb::Test::Fixtures::Controllers
4
4
 
5
5
  describe Merb::Controller, "#etag=" do
6
-
6
+
7
7
  before do
8
- Merb.push_path(:layout, File.dirname(__FILE__) / "controllers" / "views" / "layouts")
8
+ Merb.push_path(:layout, File.dirname(__FILE__) / "controllers" / "views" / "layouts")
9
9
  Merb::Router.prepare do
10
10
  default_routes
11
11
  end
@@ -21,7 +21,7 @@ end
21
21
 
22
22
  describe Merb::Controller, "#last_modified=" do
23
23
  before do
24
- Merb.push_path(:layout, File.dirname(__FILE__) / "controllers" / "views" / "layouts")
24
+ Merb.push_path(:layout, File.dirname(__FILE__) / "controllers" / "views" / "layouts")
25
25
  Merb::Router.prepare do
26
26
  default_routes
27
27
  end
@@ -53,7 +53,7 @@ describe Merb::Controller, "#modified_since?" do
53
53
  @controller = dispatch_to(Merb::Test::Fixtures::Controllers::ConditionalGet,
54
54
  :sets_last_modified, {}, { Merb::Const::HTTP_IF_MODIFIED_SINCE => Time.at(7000).httpdate })
55
55
  end
56
-
56
+
57
57
  it 'return true when response Last-Modified header value <= request If-Modified-Since header' do
58
58
  @controller.not_modified?(Time.at(5000)).should be(true)
59
59
  @controller.not_modified?(Time.at(6999)).should be(true)
@@ -67,35 +67,100 @@ end
67
67
 
68
68
 
69
69
  describe Merb::Controller, "#request_fresh?" do
70
+ it "returns false if no headers are supplied" do
71
+ @controller = dispatch_to(Merb::Test::Fixtures::Controllers::ConditionalGet,
72
+ :superfresh, {}, {})
73
+ @controller.request_fresh?.should be(false)
74
+ end
75
+
76
+ it "returns false if no validation information is supplied by the action and no headers are sent" do
77
+ @controller = dispatch_to(Merb::Test::Fixtures::Controllers::ConditionalGet,
78
+ :sets_nothing, {}, {})
79
+ @controller.request_fresh?.should be(false)
80
+ end
81
+
82
+ it "returns false if no validation information is supplied by the action and an ETag header is sent" do
83
+ env = { Merb::Const::HTTP_IF_NONE_MATCH => '"39791e6fb09"' }
84
+ @controller = dispatch_to(Merb::Test::Fixtures::Controllers::ConditionalGet,
85
+ :sets_nothing, {}, env)
86
+ @controller.request_fresh?.should be(false)
87
+ end
88
+
89
+ it "returns false if no validation information is supplied by the action and an If-Modified-Since header is sent" do
90
+ env = { Merb::Const::HTTP_IF_MODIFIED_SINCE => Time.at(7000).httpdate }
91
+ @controller = dispatch_to(Merb::Test::Fixtures::Controllers::ConditionalGet,
92
+ :sets_nothing, {}, env)
93
+ @controller.request_fresh?.should be(false)
94
+ end
95
+
96
+ it "returns false if no validation information is supplied by the action and both headers are sent" do
97
+ env = { 'HTTP_IF_MODIFIED_SINCE' => Time.at(7000).httpdate, Merb::Const::HTTP_IF_NONE_MATCH => '"39791e6fb09"' }
98
+ @controller = dispatch_to(Merb::Test::Fixtures::Controllers::ConditionalGet,
99
+ :sets_nothing, {}, env)
100
+
101
+ @controller.request_fresh?.should be(false)
102
+ end
103
+
104
+
70
105
  it 'return true when ETag matches' do
71
- env = { 'HTTP_IF_MODIFIED_SINCE' => Time.at(8000).httpdate, Merb::Const::HTTP_IF_NONE_MATCH => '"39791e6fb09"' }
106
+ env = { Merb::Const::HTTP_IF_NONE_MATCH => '"39791e6fb09"' }
72
107
  @controller = dispatch_to(Merb::Test::Fixtures::Controllers::ConditionalGet,
73
108
  :sets_etag, {}, env)
74
109
 
75
110
  @controller.request_fresh?.should be(true)
76
111
  end
77
112
 
113
+ it 'return false when no If-None-Match is sent, but an ETag is set' do
114
+ @controller = dispatch_to(Merb::Test::Fixtures::Controllers::ConditionalGet,
115
+ :sets_etag, {}, {})
116
+
117
+ @controller.request_fresh?.should be(false)
118
+ end
119
+
78
120
  it 'return true when entity is not modified since date given in request header' do
79
121
  env = { Merb::Const::HTTP_IF_MODIFIED_SINCE => Time.at(7000).httpdate }
80
122
  @controller = dispatch_to(Merb::Test::Fixtures::Controllers::ConditionalGet,
81
123
  :sets_last_modified, {}, env)
82
-
124
+
83
125
  @controller.request_fresh?.should be(true)
84
126
  end
85
127
 
128
+ it 'return false when a Last-Modified is set, but no header is sent' do
129
+ @controller = dispatch_to(Merb::Test::Fixtures::Controllers::ConditionalGet,
130
+ :sets_last_modified, {}, {})
131
+
132
+ @controller.request_fresh?.should be(false)
133
+ end
134
+
86
135
  it 'return true when both etag and last modification date satisfy request freshness' do
87
- env = { 'HTTP_IF_MODIFIED_SINCE' => Time.at(7000).httpdate, Merb::Const::HTTP_IF_NONE_MATCH => '"39791e6fb09"' }
136
+ env = { 'HTTP_IF_MODIFIED_SINCE' => Time.at(7000).httpdate, Merb::Const::HTTP_IF_NONE_MATCH => '"39791e6fb09"' }
88
137
  @controller = dispatch_to(Merb::Test::Fixtures::Controllers::ConditionalGet,
89
138
  :superfresh, {}, env)
90
-
139
+
91
140
  @controller.request_fresh?.should be(true)
92
141
  end
93
142
 
143
+ it 'return false if etag satisfies but the last modification date does not satisfy request freshness' do
144
+ env = { 'HTTP_IF_MODIFIED_SINCE' => Time.at(6999).httpdate, Merb::Const::HTTP_IF_NONE_MATCH => '"39791e6fb09"' }
145
+ @controller = dispatch_to(Merb::Test::Fixtures::Controllers::ConditionalGet,
146
+ :superfresh, {}, env)
147
+
148
+ @controller.request_fresh?.should be(false)
149
+ end
150
+
151
+ it 'return false if etag does not satisfy but the last modification date does satisfy request freshness' do
152
+ env = { 'HTTP_IF_MODIFIED_SINCE' => Time.at(7000).httpdate, Merb::Const::HTTP_IF_NONE_MATCH => '"wrong"' }
153
+ @controller = dispatch_to(Merb::Test::Fixtures::Controllers::ConditionalGet,
154
+ :superfresh, {}, env)
155
+
156
+ @controller.request_fresh?.should be(false)
157
+ end
158
+
94
159
  it 'return false when neither etag nor last modification date satisfy request freshness' do
95
- env = { 'HTTP_IF_MODIFIED_SINCE' => Time.at(7000).httpdate, Merb::Const::HTTP_IF_NONE_MATCH => '"39791e6fb09"' }
160
+ env = { 'HTTP_IF_MODIFIED_SINCE' => Time.at(7000).httpdate, Merb::Const::HTTP_IF_NONE_MATCH => '"39791e6fb09"' }
96
161
  @controller = dispatch_to(Merb::Test::Fixtures::Controllers::ConditionalGet,
97
162
  :stale, {}, env)
98
-
163
+
99
164
  @controller.request_fresh?.should be(false)
100
- end
165
+ end
101
166
  end
@@ -30,6 +30,10 @@ module Merb::Test::Fixtures
30
30
 
31
31
  "can has stale request"
32
32
  end
33
+
34
+ def sets_nothing
35
+ "can has nothing"
36
+ end
33
37
  end
34
38
  end
35
39
  end
@@ -21,6 +21,18 @@ module Merb::Test::Fixtures::Controllers
21
21
  end
22
22
  end
23
23
 
24
+ class PermanentAndStatusRedirect < Testing
25
+ def index
26
+ redirect("/", :permanent => true, :status => 302)
27
+ end
28
+ end
29
+
30
+ class WithStatusRedirect < Testing
31
+ def index
32
+ redirect("/", :status => 307)
33
+ end
34
+ end
35
+
24
36
  class RedirectWithMessage < Testing
25
37
  def index
26
38
  redirect("/", :message => { :notice => "what?" })
@@ -57,4 +69,4 @@ module Merb::Test::Fixtures::Controllers
57
69
  message[:notice]
58
70
  end
59
71
  end
60
- end
72
+ end
@@ -19,6 +19,18 @@ describe Merb::Controller, " redirects" do
19
19
  @controller.headers["Location"].should == "/"
20
20
  end
21
21
 
22
+ it "recirect with :permanent and :stauts use :status" do
23
+ @controller = dispatch_to(Merb::Test::Fixtures::Controllers::PermanentAndStatusRedirect, :index)
24
+ @controller.status.should == 302
25
+ @controller.headers["Location"].should == "/"
26
+ end
27
+
28
+ it "redirect with status" do
29
+ @controller = dispatch_to(Merb::Test::Fixtures::Controllers::WithStatusRedirect, :index)
30
+ @controller.status.should == 307
31
+ @controller.headers["Location"].should == "/"
32
+ end
33
+
22
34
  it "redirects with messages" do
23
35
  @controller = dispatch_to(Merb::Test::Fixtures::Controllers::RedirectWithMessage, :index)
24
36
  @controller.status.should == 302
@@ -0,0 +1,18 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "spec_helper"))
2
+
3
+ describe Merb::Config do
4
+
5
+ it "should set Dispatcher.use_mutex to true by default" do
6
+ lambda {
7
+ startup_merb
8
+ Merb::Dispatcher.use_mutex.should be_true
9
+ }
10
+ end
11
+
12
+ it "should set Dispatcher.use_mutex to value in config" do
13
+ lambda {
14
+ startup_merb({:use_mutex => false})
15
+ Merb::Dispatcher.use_mutex.should be_false
16
+ }
17
+ end
18
+ end
@@ -1,13 +1,23 @@
1
1
  require File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "spec_helper"))
2
2
  startup_merb
3
3
 
4
+ module Merb::MultipartRequestSpecHelper
5
+ def fake_file(read = nil, filename = 'sample.txt', path = 'sample.txt')
6
+ read ||= 'This is a text file with some small content in it.'
7
+ Struct.new(:read, :filename, :path).new(read, filename, path)
8
+ end
9
+ end
10
+
4
11
  describe Merb::Request do
12
+ include Merb::MultipartRequestSpecHelper
13
+
5
14
  it "should handle file upload for multipart/form-data posts" do
6
- file = Struct.new(:read, :filename, :path).
7
- new("This is a text file with some small content in it.", "sample.txt", "sample.txt")
8
- m = Merb::Test::MultipartRequestHelper::Post.new :file => file
15
+ file = fake_file
16
+ m = Merb::Test::MultipartRequestHelper::Post.new(:file => file)
9
17
  body, head = m.to_multipart
10
- request = fake_request({:request_method => "POST", :content_type => head, :content_length => body.length}, :req => body)
18
+ request = fake_request({:request_method => "POST",
19
+ :content_type => head,
20
+ :content_length => body.length}, :req => body)
11
21
  request.params[:file].should_not be_nil
12
22
  request.params[:file][:tempfile].class.should == Tempfile
13
23
  request.params[:file][:content_type].should == 'text/plain'
@@ -15,23 +25,22 @@ describe Merb::Request do
15
25
  end
16
26
 
17
27
  it "should correctly format multipart posts which contain multiple parameters" do
18
- file = Struct.new(:read, :filename, :path).
19
- new("This is a text file with some small content in it.", "sample.txt", "sample.txt")
20
- params = {:model => {:description1 => 'foo', :description2 => 'bar', :file => file}}
21
-
28
+ params = {:model => {:description1 => 'foo', :description2 => 'bar', :file => fake_file}}
22
29
  m = Merb::Test::MultipartRequestHelper::Post.new params
23
30
  body, head = m.to_multipart
24
31
  body.split('----------0xKhTmLbOuNdArY').size.should eql(5)
25
32
  end
26
33
 
27
34
  it "should correctly format multipart posts which contain an array as parameter" do
28
- struct = Struct.new(:read, :filename, :path)
29
- file = struct.new("This is a text file with some small content in it.", "sample.txt", "sample.txt")
30
- file2 = struct.new("This is another text file", "sample2.txt", "sample2.txt")
31
- params = {:model => {:description1 => 'foo', :description2 => 'bar', :child_attributes => [
32
- { :file => file },
33
- { :file => file2 }
34
- ]}}
35
+ file = fake_file
36
+ file2 = fake_file("This is another text file", "sample2.txt", "sample2.txt")
37
+ params = {:model => {:description1 => 'foo',
38
+ :description2 => 'bar',
39
+ :child_attributes => [
40
+ { :file => file },
41
+ { :file => file2 }
42
+ ]
43
+ }}
35
44
 
36
45
  m = Merb::Test::MultipartRequestHelper::Post.new params
37
46
  body, head = m.to_multipart
@@ -42,8 +51,7 @@ describe Merb::Request do
42
51
  end
43
52
 
44
53
  it "should accept env['rack.input'] as IO object (instead of StringIO)" do
45
- file = Struct.new(:read, :filename, :path).
46
- new("This is a text file with some small content in it.", "sample.txt", "sample.txt")
54
+ file = fake_file
47
55
  m = Merb::Test::MultipartRequestHelper::Post.new :file => file
48
56
  body, head = m.to_multipart
49
57
 
@@ -66,5 +74,16 @@ describe Merb::Request do
66
74
  request = fake_request({:request_method => "GET", :content_type => 'multipart/form-data, boundary=----------0xKhTmLbOuNdArY', :content_length => 0}, :req => '')
67
75
  running {request.params}.should_not raise_error
68
76
  end
69
-
77
+
78
+ it "should handle multiple occurences of one parameter" do
79
+ m = Merb::Test::MultipartRequestHelper::Post.new :file => fake_file
80
+ m.push_params({:checkbox => 0})
81
+ m.push_params({:checkbox => 1})
82
+ body, head = m.to_multipart
83
+ request = fake_request({:request_method => "POST",
84
+ :content_type => head,
85
+ :content_length => body.length}, :req => body)
86
+ request.params[:file].should_not be_nil
87
+ request.params[:checkbox].should eql '1'
88
+ end
70
89
  end
@@ -2,6 +2,36 @@ require File.join(File.dirname(__FILE__), "spec_helper")
2
2
  startup_merb(:session_store => "memory")
3
3
  require File.join(File.dirname(__FILE__), "controllers", "sessions")
4
4
 
5
+ describe Merb::MemorySession, "container" do
6
+
7
+ it "should always generate unique session" do
8
+ # Fix session id generation
9
+ Merb::SessionMixin.stub!(:rand_uuid).and_return(1, 1, 2)
10
+
11
+ s1 = Merb::MemorySession.generate
12
+ s1.store.store_session(s1.session_id, {:foo => 'bar'})
13
+ s1.session_id.should eql 1
14
+
15
+ s2 = Merb::MemorySession.generate
16
+ s2.session_id.should eql 2
17
+ # Cleanup
18
+ s1.store.delete_session(1)
19
+ s2.store.delete_session(2)
20
+ end
21
+
22
+ it "should raise exception if unable to generate unique ID" do
23
+ # Fix session id generation
24
+ Merb::SessionMixin.stub!(:rand_uuid).and_return(1, 1)
25
+
26
+ s1 = Merb::MemorySession.generate
27
+ s1.store.store_session(s1.session_id, {:foo => 'bar'})
28
+
29
+ lambda { s2 = Merb::MemorySession.generate }.should raise_error
30
+
31
+ s1.store.delete_session(1)
32
+ end
33
+ end
34
+
5
35
  describe Merb::MemorySession do
6
36
 
7
37
  before do
@@ -23,4 +53,4 @@ describe Merb::MemorySession, "mixed into Merb::Controller" do
23
53
 
24
54
  it_should_behave_like "All session-stores mixed into Merb::Controller"
25
55
 
26
- end
56
+ end
metadata CHANGED
@@ -1,13 +1,12 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: merb-core
3
3
  version: !ruby/object:Gem::Version
4
- prerelease: true
4
+ prerelease: false
5
5
  segments:
6
6
  - 1
7
7
  - 1
8
8
  - 0
9
- - rc1
10
- version: 1.1.0.rc1
9
+ version: 1.1.0
11
10
  platform: ruby
12
11
  authors:
13
12
  - Ezra Zygmuntowicz
@@ -15,7 +14,7 @@ autorequire:
15
14
  bindir: bin
16
15
  cert_chain: []
17
16
 
18
- date: 2010-03-14 00:00:00 +00:00
17
+ date: 2010-03-22 00:00:00 +00:00
19
18
  default_executable: merb
20
19
  dependencies:
21
20
  - !ruby/object:Gem::Dependency
@@ -388,6 +387,7 @@ files:
388
387
  - spec/public/controller/spec_helper.rb
389
388
  - spec/public/controller/streaming_spec.rb
390
389
  - spec/public/controller/url_spec.rb
390
+ - spec/public/core/config_spec.rb
391
391
  - spec/public/core/merb_core_spec.rb
392
392
  - spec/public/core_ext/kernel_spec.rb
393
393
  - spec/public/core_ext/spec_helper.rb
@@ -2400,13 +2400,11 @@ required_ruby_version: !ruby/object:Gem::Requirement
2400
2400
  version: "0"
2401
2401
  required_rubygems_version: !ruby/object:Gem::Requirement
2402
2402
  requirements:
2403
- - - ">"
2403
+ - - ">="
2404
2404
  - !ruby/object:Gem::Version
2405
2405
  segments:
2406
- - 1
2407
- - 3
2408
- - 1
2409
- version: 1.3.1
2406
+ - 0
2407
+ version: "0"
2410
2408
  requirements: []
2411
2409
 
2412
2410
  rubyforge_project: