merb-core 1.1.0.rc1 → 1.1.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.
@@ -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: