actionpack 1.3.1 → 1.4.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of actionpack might be problematic. Click here for more details.

data/CHANGELOG CHANGED
@@ -1,3 +1,67 @@
1
+ *1.4.0* (January 25th, 2005)
2
+
3
+ * Fixed problems with ActiveRecordStore under the development environment in Rails
4
+
5
+ * Fixed the ordering of attributes in the xml-decleration of Builder #540 [woeye]
6
+
7
+ * Added @request.raw_post as a convenience access to @request.env['RAW_POST_DATA'] #534 [Tobias Luetke]
8
+
9
+ * Added support for automatic id-based indexing for lists of items #532 [dblack]. Example:
10
+
11
+ <% @students.each do |@student| %>
12
+ <%= text_field "student[]", "first_name", :size => "20" %>
13
+ <%= text_field "student[]", "last_name" %>
14
+ <%= text_field "student[]", "grade", :size => "5" %>
15
+ <% end %>
16
+
17
+ ...would produce, for say David Black with id 123 and a grace of C+:
18
+
19
+ <input id="student_123_first_name" name="student[123][first_name]" size="20" size="30" type="text" value="David" />
20
+ <input id="student_123_last_name" name="student[123][last_name]" size="30" type="text" value="Black" />
21
+ <input id="student_123_grade" name="student[123][grade]" size="5" type="text" value="C+" />
22
+
23
+ * Added :application_prefix to url_for and friends that makes it easier to setup Rails in non-vhost environments #516 [Jamis Buck]
24
+
25
+ * Added :encode option to mail_to that'll allow you to masquarede the email address behind javascript or hex encoding #494 [Lucas Carlson]
26
+
27
+ * Fixed that the content-header was being set to application/octet_stream instead of application/octet-stream on send_date/file [Alexey]
28
+
29
+ * Removed the need for passing the binding when using CacheHelper#cache
30
+
31
+ * Added TestResponse#binary_content that'll return as a string the data sent through send_data/send_file for testing #500 [Alexey]
32
+
33
+ * Added @request.env['RAW_POST_DATA'] for people who need access to the data before Ruby's CGI has parsed it #505 [bitsweat]
34
+
35
+ * Fixed that a default fragment store wan't being set to MemoryStore as intended.
36
+
37
+ * Fixed that all redirect and render calls now return true, so you can use the pattern of "do and return". Example:
38
+
39
+ def show
40
+ redirect_to(:action => "login") and return unless @person.authenticated?
41
+ render_text "I won't happen unless the person is authenticated"
42
+ end
43
+
44
+ * Added that renders and redirects called in before_filters will have the same effect as returning false: stopping the chain. Example:
45
+
46
+ class WeblogController
47
+ before_filter { |c| c.send(:redirect_to_url("http://www.farfaraway.com")}) }
48
+
49
+ def hello
50
+ render_text "I will never be called"
51
+ end
52
+ end
53
+
54
+
55
+ * Added that only one render or redirect can happen per action. The first call wins and subsequent calls are ignored. Example:
56
+
57
+ def do_something
58
+ redirect_to :action => "elsewhere"
59
+ render_action "overthere"
60
+ end
61
+
62
+ Only the redirect happens. The rendering call is simply ignored.
63
+
64
+
1
65
  *1.3.1* (January 18th, 2005)
2
66
 
3
67
  * Fixed a bug where cookies wouldn't be set if a symbol was used instead of a string as the key
data/install.rb CHANGED
@@ -19,7 +19,8 @@ unless $sitedir
19
19
  end
20
20
 
21
21
  makedirs = %w{ action_controller/assertions action_controller/cgi_ext
22
- action_controller/session action_controller/support action_controller/support/core_ext
22
+ action_controller/session action_controller/support action_controller/support/core_ext
23
+ action_controller/support/core_ext/hash action_controller/support/core_ext/numeric action_controller/support/core_ext/string
23
24
  action_controller/templates action_controller/templates/rescues
24
25
  action_controller/templates/scaffolds
25
26
  action_view/helpers action_view/vendor action_view/vendor/builder
@@ -41,6 +42,7 @@ files = %w-
41
42
  action_controller/cgi_ext/cgi_ext.rb
42
43
  action_controller/cgi_ext/cgi_methods.rb
43
44
  action_controller/cgi_ext/cookie_performance_fix.rb
45
+ action_controller/cgi_ext/raw_post_data_fix.rb
44
46
  action_controller/caching.rb
45
47
  action_controller/cgi_process.rb
46
48
  action_controller/cookies.rb
@@ -61,8 +63,15 @@ files = %w-
61
63
  action_controller/support/class_inheritable_attributes.rb
62
64
  action_controller/support/class_attribute_accessors.rb
63
65
  action_controller/support/clean_logger.rb
64
- action_controller/support/core_ext/hash_ext.rb
65
- action_controller/support/core_ext.rb
66
+ action_controller/support/core_ext/hash/keys.rb
67
+ action_controller/support/core_ext/hash.rb
68
+ action_controller/support/core_ext/object_and_class.rb
69
+ action_controller/support/core_ext/numeric/bytes.rb
70
+ action_controller/support/core_ext/numeric/time.rb
71
+ action_controller/support/core_ext/numeric.rb
72
+ action_controller/support/core_ext/string/inflections.rb
73
+ action_controller/support/core_ext/string.rb
74
+ active_record/support/core_ext.rb
66
75
  action_controller/support/inflector.rb
67
76
  action_controller/support/binding_of_caller.rb
68
77
  action_controller/support/breakpoint.rb
@@ -163,6 +163,17 @@ module ActionController #:nodoc:
163
163
  # For more examples of redirecting options, have a look at the unit test in test/controller/url_test.rb. It's very readable and will give
164
164
  # you an excellent understanding of the different options and what they do.
165
165
  #
166
+ # == Calling multiple redirects or renders
167
+ #
168
+ # The rule for handling calls of multiple redirects and renders is that the first call wins. So in the following example:
169
+ #
170
+ # def do_something
171
+ # redirect_to :action => "elsewhere"
172
+ # render_action "overthere"
173
+ # end
174
+ #
175
+ # Only the redirect happens. The rendering call is simply ignored.
176
+ #
166
177
  # == Environments
167
178
  #
168
179
  # Action Controller works out of the box with CGI, FastCGI, and mod_ruby. CGI and mod_ruby controllers are triggered just the same using:
@@ -178,7 +189,7 @@ module ActionController #:nodoc:
178
189
  DEFAULT_RENDER_STATUS_CODE = "200 OK"
179
190
 
180
191
  DEFAULT_SEND_FILE_OPTIONS = {
181
- :type => 'application/octet_stream'.freeze,
192
+ :type => 'application/octet-stream'.freeze,
182
193
  :disposition => 'attachment'.freeze,
183
194
  :stream => true,
184
195
  :buffer_size => 4096
@@ -385,11 +396,11 @@ module ActionController #:nodoc:
385
396
  # considerably faster than rendering through the template engine.
386
397
  # Use block for response body if provided (useful for deferred rendering or streaming output).
387
398
  def render_text(text = nil, status = nil, &block) #:doc:
399
+ return if performed?
388
400
  add_variables_to_assigns
389
401
  @response.headers["Status"] = status || DEFAULT_RENDER_STATUS_CODE
390
402
  @response.body = block_given? ? block : text
391
403
  @performed_render = true
392
- return false
393
404
  end
394
405
 
395
406
  # Renders an empty response that can be used when the request is only interested in triggering an effect. Do note that good
@@ -541,10 +552,10 @@ module ActionController #:nodoc:
541
552
  # <tt>redirect_to_url "http://www.rubyonrails.org"</tt>. If the resource has moved permanently, it's possible to pass true as the
542
553
  # second parameter and the browser will get "301 Moved Permanently" instead of "302 Found".
543
554
  def redirect_to_url(url, permanently = false) #:doc:
555
+ return if performed?
544
556
  logger.info("Redirected to #{url}") unless logger.nil?
545
557
  @response.redirect(url, permanently)
546
558
  @performed_redirect = true
547
- return false
548
559
  end
549
560
 
550
561
  # Resets the session by clearsing out all the objects stored within and initializing a new session object.
@@ -594,13 +605,17 @@ module ActionController #:nodoc:
594
605
  def perform_action
595
606
  if action_methods.include?(action_name) || action_methods.include?('method_missing')
596
607
  send(action_name)
597
- render unless @performed_render || @performed_redirect
608
+ render unless performed?
598
609
  elsif template_exists? && template_public?
599
610
  render
600
611
  else
601
612
  raise UnknownAction, "No action responded to #{action_name}", caller
602
613
  end
603
614
  end
615
+
616
+ def performed?
617
+ @performed_render || @performed_redirect
618
+ end
604
619
 
605
620
  def action_methods
606
621
  action_controller_classes = self.class.ancestors.reject{ |a| [Object, Kernel].include?(a) }
@@ -193,7 +193,7 @@ module ActionController #:nodoc:
193
193
  # parties. The caching is doing using the cache helper available in the Action View. A template with caching might look something like:
194
194
  #
195
195
  # <b>Hello <%= @name %></b>
196
- # <% cache(binding) do %>
196
+ # <% cache do %>
197
197
  # All the topics in the system:
198
198
  # <%= render_collection_of_partials "topic", Topic.find_all %>
199
199
  # <% end %>
@@ -203,7 +203,7 @@ module ActionController #:nodoc:
203
203
  # if you need to cache multiple fragments per action or if the action itself is cached using <tt>caches_action</tt>. So instead we should
204
204
  # qualify the name of the action used with something like:
205
205
  #
206
- # <% cache(binding, :action => "list", :action_suffix => "all_topics") do %>
206
+ # <% cache(:action => "list", :action_suffix => "all_topics") do %>
207
207
  #
208
208
  # That would result in a name such as "/topics/list/all_topics", which wouldn't conflict with any action cache and neither with another
209
209
  # fragment using a different suffix. Note that the URL doesn't have to really exist or be callable. We're just using the url_for system
@@ -241,22 +241,22 @@ module ActionController #:nodoc:
241
241
  def self.append_features(base) #:nodoc:
242
242
  super
243
243
  base.class_eval do
244
- @@cache_store = MemoryStore.new
244
+ @@fragment_cache_store = MemoryStore.new
245
245
  cattr_accessor :fragment_cache_store
246
246
  end
247
247
  end
248
248
 
249
249
  # Called by CacheHelper#cache
250
- def cache_erb_fragment(binding, name = {}, options = {})
251
- unless perform_caching then yield; return end
250
+ def cache_erb_fragment(block, name = {}, options = {})
251
+ unless perform_caching then block.call; return end
252
252
 
253
- buffer = eval("_erbout", binding)
253
+ buffer = eval("_erbout", block.binding)
254
254
 
255
255
  if cache = read_fragment(name, options)
256
256
  buffer.concat(cache)
257
257
  else
258
258
  pos = buffer.length
259
- yield
259
+ block.call
260
260
  write_fragment(name, buffer[pos..-1], options)
261
261
  end
262
262
  end
@@ -0,0 +1,46 @@
1
+ class CGI #:nodoc:
2
+ # Add @request.env['RAW_POST_DATA'] for the vegans.
3
+ module QueryExtension
4
+ # Initialize the data from the query.
5
+ #
6
+ # Handles multipart forms (in particular, forms that involve file uploads).
7
+ # Reads query parameters in the @params field, and cookies into @cookies.
8
+ def initialize_query()
9
+ if boundary = multipart_form_boundary
10
+ @multipart = true
11
+ @params = read_multipart(boundary, Integer(env_table['CONTENT_LENGTH']))
12
+ else
13
+ @multipart = false
14
+ @params = CGI::parse(read_query_params)
15
+ end
16
+
17
+ @cookies = CGI::Cookie::parse((env_table['HTTP_COOKIE'] or env_table['COOKIE']))
18
+ end
19
+
20
+ private
21
+ MULTIPART_FORM_BOUNDARY_RE = %r|\Amultipart/form-data.*boundary=\"?([^\";,]+)\"?|n #"
22
+
23
+ def multipart_form_boundary
24
+ if env_table['REQUEST_METHOD'] == 'POST'
25
+ MULTIPART_FORM_BOUNDARY_RE.match(env_table['CONTENT_TYPE']).to_a.pop
26
+ end
27
+ end
28
+
29
+ def read_query_params
30
+ case env_table['REQUEST_METHOD']
31
+ when 'GET', 'HEAD'
32
+ if defined? MOD_RUBY
33
+ Apache::request.args or ''
34
+ else
35
+ env_table['QUERY_STRING'] or ''
36
+ end
37
+ when 'POST'
38
+ stdinput.binmode if stdinput.respond_to?(:binmode)
39
+ content = stdinput.read(Integer(env_table['CONTENT_LENGTH'])) or ''
40
+ env_table['RAW_POST_DATA'] = content.freeze
41
+ else
42
+ read_from_cmdline
43
+ end
44
+ end
45
+ end # module QueryExtension
46
+ end
@@ -1,5 +1,6 @@
1
1
  require 'action_controller/cgi_ext/cgi_ext'
2
2
  require 'action_controller/cgi_ext/cookie_performance_fix'
3
+ require 'action_controller/cgi_ext/raw_post_data_fix'
3
4
  require 'action_controller/session/drb_store'
4
5
  require 'action_controller/session/active_record_store'
5
6
  require 'action_controller/session/mem_cache_store'
@@ -78,8 +78,9 @@ module ActionController #:nodoc:
78
78
  inherited_without_model(child)
79
79
  return if child.controller_name == "application" # otherwise the ApplicationController in Rails will include itself
80
80
  begin
81
- child.model(Inflector.singularize(child.controller_name))
82
- rescue LoadError
81
+ Object.const_get(child.controller_name.singularize.classify)
82
+ child.model(child.controller_name.singularize)
83
+ rescue NameError, LoadError
83
84
  # No neither singular or plural model available for this controller
84
85
  end
85
86
  end
@@ -12,9 +12,9 @@ module ActionController #:nodoc:
12
12
  #
13
13
  # Filters have access to the request, response, and all the instance variables set by other filters in the chain
14
14
  # or by the action (in the case of after filters). Additionally, it's possible for a pre-processing <tt>before_filter</tt>
15
- # to halt the processing before the intended action is processed by returning false. This is especially useful for
16
- # filters like authentication where you're not interested in allowing the action to be performed if the proper
17
- # credentials are not in order.
15
+ # to halt the processing before the intended action is processed by returning false or performing a redirect or render.
16
+ # This is especially useful for filters like authentication where you're not interested in allowing the action to be
17
+ # performed if the proper credentials are not in order.
18
18
  #
19
19
  # == Filter inheritance
20
20
  #
@@ -290,7 +290,7 @@ module ActionController #:nodoc:
290
290
  end
291
291
 
292
292
  def perform_action_with_filters
293
- return if before_action == false
293
+ return if before_action == false || performed?
294
294
  perform_action_without_filters
295
295
  after_action
296
296
  end
@@ -96,7 +96,7 @@ module ActionController #:nodoc:
96
96
  inherited_without_helper(child)
97
97
  begin
98
98
  child.helper(child.controller_name)
99
- rescue LoadError, StandardError
99
+ rescue ArgumentError, LoadError
100
100
  # No default helper available for this controller
101
101
  end
102
102
  end
@@ -29,7 +29,8 @@ module ActionController
29
29
  def head?
30
30
  method == :head
31
31
  end
32
-
32
+
33
+
33
34
  # Determine originating IP address. REMOTE_ADDR is the standard
34
35
  # but will fail if the user is behind a proxy. HTTP_CLIENT_IP and/or
35
36
  # HTTP_X_FORWARDED_FOR are set by proxies so check for these before
@@ -53,40 +54,47 @@ module ActionController
53
54
  # Returns the domain part of a host, such as rubyonrails.org in "www.rubyonrails.org". You can specify
54
55
  # a different <tt>tld_length</tt>, such as 2 to catch rubyonrails.co.uk in "www.rubyonrails.co.uk".
55
56
  def domain(tld_length = 1)
56
- host.split(".").last(1 + tld_length).join(".")
57
+ host.split('.').last(1 + tld_length).join('.')
57
58
  end
58
59
 
59
60
  # Returns all the subdomains as an array, so ["dev", "www"] would be returned for "dev.www.rubyonrails.org".
60
61
  # You can specify a different <tt>tld_length</tt>, such as 2 to catch ["www"] instead of ["www", "rubyonrails"]
61
62
  # in "www.rubyonrails.co.uk".
62
63
  def subdomains(tld_length = 1)
63
- parts = host.split(".")
64
+ parts = host.split('.')
64
65
  parts - parts.last(1 + tld_length)
65
66
  end
66
67
 
68
+ # Recieve the raw post data.
69
+ # This is useful for services such as REST, XMLRPC and SOAP
70
+ # which communicate over HTTP POST but don't use the traditional parameter format.
71
+ def raw_post
72
+ env['RAW_POST_DATA']
73
+ end
74
+
67
75
  def request_uri
68
- env["REQUEST_URI"]
76
+ env['REQUEST_URI']
69
77
  end
70
78
 
71
79
  def protocol
72
- port == 443 ? "https://" : "http://"
80
+ port == 443 ? 'https://' : 'http://'
73
81
  end
74
82
 
75
83
  def ssl?
76
- protocol == "https://"
84
+ protocol == 'https://'
77
85
  end
78
86
 
79
87
  def path
80
- request_uri ? request_uri.split("?").first : ""
88
+ request_uri ? request_uri.split('?').first : ''
81
89
  end
82
90
 
83
91
  def port
84
- env["SERVER_PORT"].to_i
92
+ env['SERVER_PORT'].to_i
85
93
  end
86
94
 
87
95
  # Returns a string like ":8080" if the port is not 80 or 443 while on https.
88
96
  def port_string
89
- (protocol == "http://" && port == 80) || (protocol == "https://" && port == 443) ? "" : ":#{port}"
97
+ (protocol == 'http://' && port == 80) || (protocol == 'https://' && port == 443) ? '' : ":#{port}"
90
98
  end
91
99
 
92
100
  def host_with_port
@@ -1,85 +1,83 @@
1
- begin
2
- require 'simplecc'
3
- rescue LoadError
4
- class Continuation #:nodoc:
5
- def self.create(*args, &block)
6
- cc = nil; result = callcc {|c| cc = c; block.call(cc) if block and args.empty?}
7
- result ||= args
8
- return *[cc, *result]
9
- end
10
- end
11
- end
12
-
13
- class Binding #:nodoc:
14
- # This method returns the binding of the method that called your
15
- # method. It will raise an Exception when you're not inside a method.
16
- #
17
- # It's used like this:
18
- # def inc_counter(amount = 1)
19
- # Binding.of_caller do |binding|
20
- # # Create a lambda that will increase the variable 'counter'
21
- # # in the caller of this method when called.
22
- # inc = eval("lambda { |arg| counter += arg }", binding)
23
- # # We can refer to amount from inside this block safely.
24
- # inc.call(amount)
25
- # end
26
- # # No other statements can go here. Put them inside the block.
27
- # end
28
- # counter = 0
29
- # 2.times { inc_counter }
30
- # counter # => 2
31
- #
32
- # Binding.of_caller must be the last statement in the method.
33
- # This means that you will have to put everything you want to
34
- # do after the call to Binding.of_caller into the block of it.
35
- # This should be no problem however, because Ruby has closures.
36
- # If you don't do this an Exception will be raised. Because of
37
- # the way that Binding.of_caller is implemented it has to be
38
- # done this way.
39
- def self.of_caller(&block)
40
- old_critical = Thread.critical
41
- Thread.critical = true
42
- count = 0
43
- cc, result, error, extra_data = Continuation.create(nil, nil)
44
- error.call if error
45
-
46
- tracer = lambda do |*args|
47
- type, context, extra_data = args[0], args[4], args
48
- if type == "return"
49
- count += 1
50
- # First this method and then calling one will return --
51
- # the trace event of the second event gets the context
52
- # of the method which called the method that called this
53
- # method.
54
- if count == 2
55
- # It would be nice if we could restore the trace_func
56
- # that was set before we swapped in our own one, but
57
- # this is impossible without overloading set_trace_func
58
- # in current Ruby.
59
- set_trace_func(nil)
60
- cc.call(eval("binding", context), nil, extra_data)
61
- end
62
- elsif type == "line" then
63
- nil
64
- elsif type == "c-return" and extra_data[3] == :set_trace_func then
65
- nil
66
- else
67
- set_trace_func(nil)
68
- error_msg = "Binding.of_caller used in non-method context or " +
69
- "trailing statements of method using it aren't in the block."
70
- cc.call(nil, lambda { raise(ArgumentError, error_msg) }, nil)
71
- end
72
- end
73
-
74
- unless result
75
- set_trace_func(tracer)
76
- return nil
77
- else
78
- Thread.critical = old_critical
79
- case block.arity
80
- when 1 then yield(result)
81
- else yield(result, extra_data)
82
- end
83
- end
84
- end
85
- end
1
+ begin
2
+ require 'simplecc'
3
+ rescue LoadError
4
+ class Continuation; end # :nodoc: # for RDoc
5
+ def Continuation.create(*args, &block) # :nodoc:
6
+ cc = nil; result = callcc {|c| cc = c; block.call(cc) if block and args.empty?}
7
+ result ||= args
8
+ return *[cc, *result]
9
+ end
10
+ end
11
+
12
+ class Binding; end # for RDoc
13
+ # This method returns the binding of the method that called your
14
+ # method. It will raise an Exception when you're not inside a method.
15
+ #
16
+ # It's used like this:
17
+ # def inc_counter(amount = 1)
18
+ # Binding.of_caller do |binding|
19
+ # # Create a lambda that will increase the variable 'counter'
20
+ # # in the caller of this method when called.
21
+ # inc = eval("lambda { |arg| counter += arg }", binding)
22
+ # # We can refer to amount from inside this block safely.
23
+ # inc.call(amount)
24
+ # end
25
+ # # No other statements can go here. Put them inside the block.
26
+ # end
27
+ # counter = 0
28
+ # 2.times { inc_counter }
29
+ # counter # => 2
30
+ #
31
+ # Binding.of_caller must be the last statement in the method.
32
+ # This means that you will have to put everything you want to
33
+ # do after the call to Binding.of_caller into the block of it.
34
+ # This should be no problem however, because Ruby has closures.
35
+ # If you don't do this an Exception will be raised. Because of
36
+ # the way that Binding.of_caller is implemented it has to be
37
+ # done this way.
38
+ def Binding.of_caller(&block)
39
+ old_critical = Thread.critical
40
+ Thread.critical = true
41
+ count = 0
42
+ cc, result, error, extra_data = Continuation.create(nil, nil)
43
+ error.call if error
44
+
45
+ tracer = lambda do |*args|
46
+ type, context, extra_data = args[0], args[4], args
47
+ if type == "return"
48
+ count += 1
49
+ # First this method and then calling one will return --
50
+ # the trace event of the second event gets the context
51
+ # of the method which called the method that called this
52
+ # method.
53
+ if count == 2
54
+ # It would be nice if we could restore the trace_func
55
+ # that was set before we swapped in our own one, but
56
+ # this is impossible without overloading set_trace_func
57
+ # in current Ruby.
58
+ set_trace_func(nil)
59
+ cc.call(eval("binding", context), nil, extra_data)
60
+ end
61
+ elsif type == "line" then
62
+ nil
63
+ elsif type == "c-return" and extra_data[3] == :set_trace_func then
64
+ nil
65
+ else
66
+ set_trace_func(nil)
67
+ error_msg = "Binding.of_caller used in non-method context or " +
68
+ "trailing statements of method using it aren't in the block."
69
+ cc.call(nil, lambda { raise(ArgumentError, error_msg) }, nil)
70
+ end
71
+ end
72
+
73
+ unless result
74
+ set_trace_func(tracer)
75
+ return nil
76
+ else
77
+ Thread.critical = old_critical
78
+ case block.arity
79
+ when 1 then yield(result)
80
+ else yield(result, extra_data)
81
+ end
82
+ end
83
+ end
@@ -16,11 +16,14 @@
16
16
  # license please contact me.
17
17
 
18
18
  require 'irb'
19
- # require 'binding_of_caller' <- Needs this
19
+ require File.dirname(__FILE__) + '/binding_of_caller'
20
20
  require 'drb'
21
21
  require 'drb/acl'
22
22
 
23
23
  module Breakpoint
24
+ id = %q$Id: breakpoint.rb 41 2005-01-22 20:22:10Z flgr $
25
+ Version = id.split(" ")[2].to_i
26
+
24
27
  extend self
25
28
 
26
29
  # This will pop up an interactive ruby session at a
@@ -114,10 +117,10 @@ module Breakpoint
114
117
  end
115
118
  end
116
119
 
117
- module CommandBundle #:nodoc:
120
+ module CommandBundle
118
121
  # Proxy to a Breakpoint client. Lets you directly execute code
119
122
  # in the context of the client.
120
- class Client#:nodoc:
123
+ class Client
121
124
  def initialize(eval_handler) # :nodoc:
122
125
  @eval_handler = eval_handler
123
126
  end
@@ -133,15 +136,23 @@ module Breakpoint
133
136
  end
134
137
 
135
138
  # Will execute the specified statement at the client.
136
- def method_missing(method, *args)
137
- if args.empty?
138
- result = eval("#{method}")
139
+ def method_missing(method, *args, &block)
140
+ if args.empty? and not block
141
+ result = eval "#{method}"
139
142
  else
140
- result = eval("#{method}(*Marshal.load(#{Marshal.dump(args).inspect}))")
141
- end
142
-
143
- unless [true, false, nil].include?(result)
144
- result.extend(DRbUndumped) if result
143
+ # This is a bit ugly. The alternative would be using an
144
+ # eval context instead of an eval handler for executing
145
+ # the code at the client. The problem with that approach
146
+ # is that we would have to handle special expressions
147
+ # like "self", "nil" or constants ourself which is hard.
148
+ remote = eval %{
149
+ result = lambda { |block, *args| #{method}(*args, &block) }
150
+ def result.call_with_block(*args, &block)
151
+ call(block, *args)
152
+ end
153
+ result
154
+ }
155
+ remote.call_with_block(*args, &block)
145
156
  end
146
157
 
147
158
  return result
@@ -175,6 +186,7 @@ module Breakpoint
175
186
  # client.File.open("temp.txt", "w") { |f| f.puts "Hello" }
176
187
  def client()
177
188
  if Breakpoint.use_drb? then
189
+ sleep(0.5) until Breakpoint.drb_service.eval_handler
178
190
  Client.new(Breakpoint.drb_service.eval_handler)
179
191
  else
180
192
  Client.new(lambda { |code| eval(code, TOPLEVEL_BINDING) })
@@ -205,7 +217,7 @@ module Breakpoint
205
217
  # These exceptions will be raised on failed asserts
206
218
  # if Breakpoint.asserts_cause_exceptions is set to
207
219
  # true.
208
- class FailedAssertError < RuntimeError#:nodoc:
220
+ class FailedAssertError < RuntimeError
209
221
  end
210
222
 
211
223
  # This asserts that the block evaluates to true.
@@ -279,7 +291,7 @@ module Breakpoint
279
291
  @collision_handler.call
280
292
  end
281
293
 
282
- def ping; end
294
+ def ping() end
283
295
 
284
296
  def add_breakpoint(context, message)
285
297
  workspace = IRB::WorkSpace.new(context)
@@ -290,31 +302,7 @@ module Breakpoint
290
302
  @handler.call(workspace, message)
291
303
  end
292
304
 
293
- def register_handler(&block)
294
- @handler = block
295
- end
296
-
297
- def unregister_handler
298
- @handler = nil
299
- end
300
-
301
- attr_reader :eval_handler
302
-
303
- def register_eval_handler(&block)
304
- @eval_handler = block
305
- end
306
-
307
- def unregister_eval_handler
308
- @eval_handler = lambda { }
309
- end
310
-
311
- def register_collision_handler(&block)
312
- @collision_handler = block
313
- end
314
-
315
- def unregister_collision_handler
316
- @collision_handler = lambda { }
317
- end
305
+ attr_accessor :handler, :eval_handler, :collision_handler
318
306
  end
319
307
 
320
308
  # Will run Breakpoint in DRb mode. This will spawn a server
@@ -359,7 +347,8 @@ module Breakpoint
359
347
  #
360
348
  # Detailed information about running DRb through firewalls is
361
349
  # available at http://www.rubygarden.org/ruby?DrbTutorial
362
- def activate_drb(uri = nil, allowed_hosts = ['localhost', '127.0.0.1', '::1'], ignore_collisions = false) #:nodoc:
350
+ def activate_drb(uri = nil, allowed_hosts = ['localhost', '127.0.0.1', '::1'],
351
+ ignore_collisions = false)
363
352
 
364
353
  return false if @use_drb
365
354
 
@@ -402,7 +391,7 @@ module Breakpoint
402
391
  end
403
392
 
404
393
  # Deactivates a running Breakpoint service.
405
- def deactivate_drb #:nodoc:
394
+ def deactivate_drb
406
395
  @service.stop_service unless @service.nil?
407
396
  @service = nil
408
397
  @use_drb = false
@@ -411,14 +400,12 @@ module Breakpoint
411
400
 
412
401
  # Returns true when Breakpoints are used over DRb.
413
402
  # Breakpoint.activate_drb causes this to be true.
414
- def use_drb? #:nodoc:
403
+ def use_drb?
415
404
  @use_drb == true
416
405
  end
417
406
  end
418
407
 
419
408
  module IRB # :nodoc:
420
- def IRB.parse_opts() end
421
-
422
409
  class << self; remove_method :start; end
423
410
  def self.start(ap_path = nil, main_context = nil, workspace = nil)
424
411
  $0 = File::basename(ap_path, ".rb") if ap_path
@@ -442,7 +429,11 @@ module IRB # :nodoc:
442
429
  @CONF[:MAIN_CONTEXT] = irb.context
443
430
 
444
431
  old_sigint = trap("SIGINT") do
445
- irb.signal_handle
432
+ begin
433
+ irb.signal_handle
434
+ rescue RubyLex::TerminateLineInput
435
+ # ignored
436
+ end
446
437
  end
447
438
 
448
439
  catch(:IRB_EXIT) do
@@ -466,7 +457,7 @@ module IRB # :nodoc:
466
457
  end
467
458
  end
468
459
 
469
- class Context#:nodoc:
460
+ class Context
470
461
  alias :old_evaluate :evaluate
471
462
  def evaluate(line, line_no)
472
463
  if line.chomp == "exit" then
@@ -477,7 +468,7 @@ module IRB # :nodoc:
477
468
  end
478
469
  end
479
470
 
480
- class WorkSpace#:nodoc:
471
+ class WorkSpace
481
472
  alias :old_evaluate :evaluate
482
473
 
483
474
  def evaluate(*args)
@@ -495,7 +486,7 @@ module IRB # :nodoc:
495
486
  end
496
487
  end
497
488
 
498
- module InputCompletor#:nodoc:
489
+ module InputCompletor
499
490
  def self.eval(code, context, *more)
500
491
  # Big hack, this assumes that InputCompletor
501
492
  # will only call eval() when it wants code
@@ -506,9 +497,9 @@ module IRB # :nodoc:
506
497
  end
507
498
 
508
499
  module DRb # :nodoc:
509
- class DRbObject#:nodoc:
510
- undef :inspect
511
- undef :clone
500
+ class DRbObject
501
+ undef :inspect if method_defined?(:inspect)
502
+ undef :clone if method_defined?(:clone)
512
503
  end
513
504
  end
514
505
 
@@ -524,4 +515,4 @@ def assert(&block)
524
515
  Binding.of_caller do |context|
525
516
  Breakpoint.assert(context, &block)
526
517
  end
527
- end
518
+ end
@@ -0,0 +1,24 @@
1
+ class Object #:nodoc:
2
+ def remove_subclasses_of(superclass)
3
+ subclasses_of(superclass).each { |subclass| Object.send(:remove_const, subclass) rescue nil }
4
+ end
5
+
6
+ def subclasses_of(superclass)
7
+ subclasses = []
8
+ ObjectSpace.each_object(Class) do |k|
9
+ next if !k.ancestors.include?(superclass) || superclass == k || k.to_s.include?("::") || subclasses.include?(k.to_s)
10
+ subclasses << k.to_s
11
+ end
12
+ subclasses
13
+ end
14
+ end
15
+
16
+ class Class #:nodoc:
17
+ def remove_subclasses
18
+ Object.remove_subclasses_of(self)
19
+ end
20
+
21
+ def subclasses
22
+ Object.subclasses_of(self)
23
+ end
24
+ end
@@ -9,14 +9,19 @@ module Dependencies
9
9
  @@mechanism = :load
10
10
  mattr_accessor :mechanism
11
11
 
12
+ def load?
13
+ mechanism == :load
14
+ end
15
+
12
16
  def depend_on(file_name, swallow_load_errors = false)
13
17
  if !loaded.include?(file_name)
14
18
  loaded << file_name
15
-
16
19
  begin
17
20
  require_or_load(file_name)
18
21
  rescue LoadError
19
22
  raise unless swallow_load_errors
23
+ rescue Object => e
24
+ raise ScriptError, "#{e.message}"
20
25
  end
21
26
  end
22
27
  end
@@ -29,12 +34,16 @@ module Dependencies
29
34
  self.loaded = [ ]
30
35
  end
31
36
 
32
- private
33
- def require_or_load(file_name)
34
- mechanism == :load ? silence_warnings { load("#{file_name}.rb") } : require(file_name)
35
- end
37
+ def require_or_load(file_name)
38
+ load? ? load("#{file_name}.rb") : require(file_name)
39
+ end
40
+
41
+ def remove_subclasses_for(*classes)
42
+ classes.each { |klass| klass.remove_subclasses }
43
+ end
36
44
  end
37
45
 
46
+ Object.send(:define_method, :require_or_load) { |file_name| Dependencies.require_or_load(file_name) } unless Object.respond_to?(:require_or_load)
38
47
  Object.send(:define_method, :require_dependency) { |file_name| Dependencies.depend_on(file_name) } unless Object.respond_to?(:require_dependency)
39
48
  Object.send(:define_method, :require_association) { |file_name| Dependencies.associate_with(file_name) } unless Object.respond_to?(:require_association)
40
49
 
@@ -42,16 +51,12 @@ class Object #:nodoc:
42
51
  class << self
43
52
  # Use const_missing to autoload associations so we don't have to
44
53
  # require_association when using single-table inheritance.
45
- unless respond_to?(:pre_dependency_const_missing)
46
- alias_method :pre_dependency_const_missing, :const_missing
47
-
48
- def const_missing(class_id)
49
- begin
50
- require_dependency(Inflector.underscore(Inflector.demodulize(class_id.to_s)))
51
- return Object.const_get(class_id) if Object.const_defined?(class_id)
52
- rescue LoadError
53
- pre_dependency_const_missing(class_id)
54
- end
54
+ def const_missing(class_id)
55
+ begin
56
+ require_or_load(class_id.to_s.demodulize.underscore)
57
+ if Object.const_defined?(class_id) then return Object.const_get(class_id) else raise LoadError end
58
+ rescue LoadError
59
+ raise NameError, "uninitialized constant #{class_id}"
55
60
  end
56
61
  end
57
62
  end
@@ -191,6 +191,23 @@ module ActionController #:nodoc:
191
191
  headers['cookie'].inject({}) { |hash, cookie| hash[cookie.name] = cookie; hash }
192
192
  end
193
193
 
194
+ # Returns binary content (downloadable file), converted to a String
195
+ def binary_content
196
+ raise "Response body is not a Proc: #{body.inspect}" unless body.kind_of?(Proc)
197
+ require 'stringio'
198
+
199
+ sio = StringIO.new
200
+
201
+ begin
202
+ $stdout = sio
203
+ body.call
204
+ ensure
205
+ $stdout = STDOUT
206
+ end
207
+
208
+ sio.rewind
209
+ sio.read
210
+ end
194
211
  end
195
212
 
196
213
  class TestSession #:nodoc:
@@ -1,7 +1,7 @@
1
1
  module ActionController
2
2
  # Rewrites urls for Base.redirect_to and Base.url_for in the controller.
3
3
  class UrlRewriter #:nodoc:
4
- VALID_OPTIONS = [:action, :action_prefix, :action_suffix, :module, :controller, :controller_prefix, :anchor, :params, :path_params, :id, :only_path, :overwrite_params, :host, :protocol ]
4
+ VALID_OPTIONS = [:action, :action_prefix, :action_suffix, :application_prefix, :module, :controller, :controller_prefix, :anchor, :params, :path_params, :id, :only_path, :overwrite_params, :host, :protocol ]
5
5
 
6
6
  def initialize(request, controller, action)
7
7
  @request, @controller, @action = request, controller, action
@@ -41,6 +41,7 @@ module ActionController
41
41
  rewritten_url << (options[:protocol] || @request.protocol) unless options[:only_path]
42
42
  rewritten_url << (options[:host] || @request.host_with_port) unless options[:only_path]
43
43
 
44
+ rewritten_url << options[:application_prefix] if options[:application_prefix]
44
45
  rewritten_url << path
45
46
  rewritten_url << build_query_string(new_parameters(options)) if options[:params] || options[:overwrite_params]
46
47
  rewritten_url << "##{options[:anchor]}" if options[:anchor]
@@ -2,8 +2,8 @@ module ActionView
2
2
  module Helpers
3
3
  # See ActionController::Caching::Fragments for usage instructions.
4
4
  module CacheHelper
5
- def cache(binding, name = {})
6
- @controller.cache_erb_fragment(binding, name) { yield }
5
+ def cache(name = {}, &block)
6
+ @controller.cache_erb_fragment(block, name)
7
7
  end
8
8
  end
9
9
  end
@@ -137,6 +137,9 @@ module ActionView
137
137
  def initialize(object_name, method_name, template_object, local_binding = nil)
138
138
  @object_name, @method_name = object_name, method_name
139
139
  @template_object, @local_binding = template_object, local_binding
140
+ if @object_name.sub!(/\[\]$/,"")
141
+ @auto_index = @template_object.instance_variable_get("@#{Regexp.last_match.pre_match}").id
142
+ end
140
143
  end
141
144
 
142
145
  def to_input_field_tag(field_type, options = {})
@@ -214,6 +217,9 @@ module ActionView
214
217
  options['name'] = tag_name_with_index(options["index"]) unless options.has_key? "name"
215
218
  options['id'] = tag_id_with_index(options["index"]) unless options.has_key? "id"
216
219
  options.delete("index")
220
+ elsif @auto_index
221
+ options['name'] = tag_name_with_index(@auto_index) unless options.has_key? "name"
222
+ options['id'] = tag_id_with_index(@auto_index) unless options.has_key? "id"
217
223
  else
218
224
  options['name'] = tag_name unless options.has_key? "name"
219
225
  options['id'] = tag_id unless options.has_key? "id"
@@ -91,8 +91,35 @@ module ActionView
91
91
 
92
92
  # Creates a link tag for starting an email to the specified <tt>email_address</tt>, which is also used as the name of the
93
93
  # link unless +name+ is specified. Additional HTML options, such as class or id, can be passed in the <tt>html_options</tt> hash.
94
+ #
95
+ # You can also make it difficult for spiders to harvest email address by obfuscating them.
96
+ # Examples:
97
+ # * mail_to "me@domain.com", "My email", :encode => "javascript"
98
+ # => <script type="text/javascript" language="javascript">eval(unescape('%64%6f%63%75%6d%65%6e%74%2e%77%72%69%74%65%28%27%3c%61%20%68%72%65%66%3d%22%6d%61%69%6c%74%6f%3a%6d%65%40%64%6f%6d%61%69%6e%2e%63%6f%6d%22%3e%4d%79%20%65%6d%61%69%6c%3c%2f%61%3e%27%29%3b'))</script>
99
+ # * mail_to "me@domain.com", "My email", :encode => "hex"
100
+ # => <a href="mailto:%6d%65@%64%6f%6d%61%69%6e.%63%6f%6d">My email</a>
94
101
  def mail_to(email_address, name = nil, html_options = {})
95
- content_tag "a", name || email_address, html_options.merge({ "href" => "mailto:#{email_address}" })
102
+ encode = html_options[:encode]
103
+ html_options.delete(:encode)
104
+ string = ''
105
+ if encode == 'javascript'
106
+ tmp = "document.write('#{content_tag("a", name || email_address, html_options.merge({ "href" => "mailto:"+email_address.to_s }))}');"
107
+ for i in 0...tmp.length
108
+ string << sprintf("%%%x",tmp[i])
109
+ end
110
+ "<script type=\"text/javascript\" language=\"javascript\">eval(unescape('#{string}'))</script>"
111
+ elsif encode == 'hex'
112
+ for i in 0...email_address.length
113
+ if email_address[i,1] =~ /\w/
114
+ string << sprintf("%%%x",email_address[i])
115
+ else
116
+ string << email_address[i,1]
117
+ end
118
+ end
119
+ content_tag "a", name || email_address, html_options.merge({ "href" => "mailto:#{string}" })
120
+ else
121
+ content_tag "a", name || email_address, html_options.merge({ "href" => "mailto:#{email_address}" })
122
+ end
96
123
  end
97
124
 
98
125
  private
@@ -221,7 +221,7 @@ module Builder
221
221
  # For example:
222
222
  #
223
223
  # xml.instruct!
224
- # #=> <?xml encoding="UTF-8" version="1.0"?>
224
+ # #=> <?xml version="1.0" encoding="UTF-8"?>
225
225
  # xml.instruct! :aaa, :bbb=>"ccc"
226
226
  # #=> <?aaa bbb="ccc"?>
227
227
  #
@@ -231,7 +231,12 @@ module Builder
231
231
  a = { :version=>"1.0", :encoding=>"UTF-8" }
232
232
  attrs = a.merge attrs
233
233
  end
234
- _special("<?#{directive_tag}", "?>", nil, attrs)
234
+ _special(
235
+ "<?#{directive_tag}",
236
+ "?>",
237
+ nil,
238
+ attrs,
239
+ [:version, :encoding, :standalone])
235
240
  end
236
241
 
237
242
  private
@@ -245,11 +250,11 @@ module Builder
245
250
  end
246
251
 
247
252
  # Insert special instruction.
248
- def _special(open, close, data=nil, attrs=nil)
253
+ def _special(open, close, data=nil, attrs=nil, order=[])
249
254
  _indent
250
255
  @target << open
251
256
  @target << data if data
252
- _insert_attributes(attrs) if attrs
257
+ _insert_attributes(attrs, order) if attrs
253
258
  @target << close
254
259
  _newline
255
260
  end
@@ -269,10 +274,14 @@ module Builder
269
274
  end
270
275
 
271
276
  # Insert the attributes (given in the hash).
272
- def _insert_attributes(attrs)
277
+ def _insert_attributes(attrs, order=[])
273
278
  return if attrs.nil?
279
+ order.each do |k|
280
+ v = attrs[k]
281
+ @target << %{ #{k}="#{v}"} if v
282
+ end
274
283
  attrs.each do |k, v|
275
- @target << %{ #{k}="#{v}"}
284
+ @target << %{ #{k}="#{v}"} unless order.member?(k)
276
285
  end
277
286
  end
278
287
 
data/rakefile CHANGED
@@ -8,7 +8,7 @@ require 'rake/contrib/rubyforgepublisher'
8
8
 
9
9
  PKG_BUILD = ENV['PKG_BUILD'] ? '.' + ENV['PKG_BUILD'] : ''
10
10
  PKG_NAME = 'actionpack'
11
- PKG_VERSION = '1.3.1' + PKG_BUILD
11
+ PKG_VERSION = '1.4.0' + PKG_BUILD
12
12
  PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}"
13
13
 
14
14
  desc "Default Task"
@@ -14,6 +14,20 @@ class FilterTest < Test::Unit::TestCase
14
14
  @ran_filter << "ensure_login"
15
15
  end
16
16
  end
17
+
18
+ class RenderingController < ActionController::Base
19
+ before_filter :render_something_else
20
+
21
+ def show
22
+ @ran_action = true
23
+ render_text "ran action"
24
+ end
25
+
26
+ private
27
+ def render_something_else
28
+ render_text "something else"
29
+ end
30
+ end
17
31
 
18
32
  class ConditionalFilterController < ActionController::Base
19
33
  def show
@@ -264,6 +278,12 @@ class FilterTest < Test::Unit::TestCase
264
278
  " after appended aroundfilter after aroundfilter after procfilter ",
265
279
  MixedFilterController.execution_log
266
280
  end
281
+
282
+ def test_rendering_breaks_filtering_chain
283
+ response = test_process(RenderingController)
284
+ assert_equal "something else", response.body
285
+ assert !response.template.assigns["ran_action"]
286
+ end
267
287
 
268
288
  private
269
289
  def test_process(controller, action = "show")
@@ -0,0 +1,31 @@
1
+ require 'test/unit'
2
+ require 'cgi'
3
+ require 'stringio'
4
+ require File.dirname(__FILE__) + '/../../lib/action_controller/cgi_ext/raw_post_data_fix'
5
+
6
+ class RawPostDataTest < Test::Unit::TestCase
7
+ def setup
8
+ ENV['REQUEST_METHOD'] = 'POST'
9
+ ENV['CONTENT_TYPE'] = ''
10
+ ENV['CONTENT_LENGTH'] = '0'
11
+ end
12
+
13
+ def test_raw_post_data
14
+ process_raw "action=create_customer&full_name=David%20Heinemeier%20Hansson&customerId=1"
15
+ end
16
+
17
+ private
18
+ def process_raw(query_string)
19
+ old_stdin = $stdin
20
+ begin
21
+ $stdin = StringIO.new(query_string.dup)
22
+ ENV['CONTENT_LENGTH'] = $stdin.size.to_s
23
+ CGI.new
24
+ assert_not_nil ENV['RAW_POST_DATA']
25
+ assert ENV['RAW_POST_DATA'].frozen?
26
+ assert_equal query_string, ENV['RAW_POST_DATA']
27
+ ensure
28
+ $stdin = old_stdin
29
+ end
30
+ end
31
+ end
@@ -453,4 +453,25 @@ class UrlTest < Test::Unit::TestCase
453
453
  url.rewrite({ :controller => "msg", :action_prefix => "allous", :action => "new" })
454
454
  )
455
455
  end
456
+
457
+ def test_clean_application_prefix
458
+ assert_equal "http://www.singlefile.com/namespace/library/books/ISBN/0743536703/show",
459
+ @library_url.rewrite(:application_prefix => "/namespace")
460
+ end
461
+
462
+ def test_clean_application_prefix_with_controller_prefix
463
+ assert_equal "http://www.singlefile.com/namespace/shop/",
464
+ @library_url.rewrite(:application_prefix => "/namespace",
465
+ :controller_prefix => "shop" )
466
+ end
467
+
468
+ def test_blank_application_prefix
469
+ assert_equal "http://www.singlefile.com/library/books/ISBN/0743536703/show",
470
+ @library_url.rewrite(:application_prefix => "")
471
+ end
472
+
473
+ def test_nil_application_prefix
474
+ assert_equal "http://www.singlefile.com/library/books/ISBN/0743536703/show",
475
+ @library_url.rewrite(:application_prefix => nil)
476
+ end
456
477
  end
@@ -18,6 +18,8 @@ class FormHelperTest < Test::Unit::TestCase
18
18
  @post = Post.new
19
19
  def @post.errors() Class.new{ def on(field) field == "author_name" end }.new end
20
20
 
21
+ def @post.id; 123; end
22
+
21
23
  @post.title = "Hello World"
22
24
  @post.author_name = ""
23
25
  @post.body = "Back to the hill and over it again!"
@@ -136,4 +138,28 @@ class FormHelperTest < Test::Unit::TestCase
136
138
  check_box("post", "secret", "id" => "i mean it")
137
139
  )
138
140
  end
141
+
142
+ def test_auto_index
143
+ pid = @post.id
144
+ assert_equal(
145
+ "<input id=\"post_#{pid}_title\" name=\"post[#{pid}][title]\" size=\"30\" type=\"text\" value=\"Hello World\" />", text_field("post[]","title")
146
+ )
147
+ assert_equal(
148
+ "<textarea cols=\"40\" id=\"post_#{pid}_body\" name=\"post[#{pid}][body]\" rows=\"20\" wrap=\"virtual\">Back to the hill and over it again!</textarea>",
149
+ text_area("post[]", "body")
150
+ )
151
+ assert_equal(
152
+ "<input checked=\"checked\" id=\"post_#{pid}_secret\" name=\"post[#{pid}][secret]\" type=\"checkbox\" value=\"1\" /><input name=\"post[#{pid}][secret]\" type=\"hidden\" value=\"0\" />",
153
+ check_box("post[]", "secret")
154
+ )
155
+ assert_equal(
156
+ "<input checked=\"checked\" id=\"post_#{pid}_title\" name=\"post[#{pid}][title]\" size=\"30\" type=\"radio\" value=\"Hello World\" />",
157
+ radio_button("post[]", "title", "Hello World")
158
+ )
159
+ assert_equal("<input id=\"post_#{pid}_title\" name=\"post[#{pid}][title]\" size=\"30\" type=\"radio\" value=\"Goodbye World\" />",
160
+ radio_button("post[]", "title", "Goodbye World")
161
+ )
162
+
163
+ end
164
+
139
165
  end
@@ -14,5 +14,17 @@ class TagHelperTest < Test::Unit::TestCase
14
14
  assert_equal "<a href=\"create\">Create</a>", content_tag("a", "Create", "href" => "create")
15
15
  end
16
16
 
17
+ def test_mail_to_with_javascript
18
+ assert_equal "<script type=\"text/javascript\" language=\"javascript\">eval(unescape('%64%6f%63%75%6d%65%6e%74%2e%77%72%69%74%65%28%27%3c%61%20%68%72%65%66%3d%22%6d%61%69%6c%74%6f%3a%6d%65%40%64%6f%6d%61%69%6e%2e%63%6f%6d%22%3e%4d%79%20%65%6d%61%69%6c%3c%2f%61%3e%27%29%3b'))</script>", mail_to("me@domain.com", "My email", :encode => "javascript")
19
+ end
20
+
21
+ def test_mail_to_with_hex
22
+ assert_equal "<a href=\"mailto:%6d%65@%64%6f%6d%61%69%6e.%63%6f%6d\">My email</a>", mail_to("me@domain.com", "My email", :encode => "hex")
23
+ end
24
+
25
+ def test_mail_to
26
+ assert_equal "<a href=\"mailto:me@domain.com\">My email</a>", mail_to("me@domain.com", "My email")
27
+ end
28
+
17
29
  # FIXME: Test form tag
18
30
  end
metadata CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.8.4
3
3
  specification_version: 1
4
4
  name: actionpack
5
5
  version: !ruby/object:Gem::Version
6
- version: 1.3.1
7
- date: 2005-01-18
6
+ version: 1.4.0
7
+ date: 2005-01-25
8
8
  summary: Web-flow and rendering framework putting the VC in MVC.
9
9
  require_paths:
10
10
  - lib
@@ -67,6 +67,7 @@ files:
67
67
  - lib/action_controller/cgi_ext/cgi_ext.rb
68
68
  - lib/action_controller/cgi_ext/cgi_methods.rb
69
69
  - lib/action_controller/cgi_ext/cookie_performance_fix.rb
70
+ - lib/action_controller/cgi_ext/raw_post_data_fix.rb
70
71
  - lib/action_controller/session/active_record_store.rb
71
72
  - lib/action_controller/session/drb_server.rb
72
73
  - lib/action_controller/session/drb_store.rb
@@ -86,6 +87,7 @@ files:
86
87
  - lib/action_controller/support/core_ext/hash.rb
87
88
  - lib/action_controller/support/core_ext/numeric
88
89
  - lib/action_controller/support/core_ext/numeric.rb
90
+ - lib/action_controller/support/core_ext/object_and_class.rb
89
91
  - lib/action_controller/support/core_ext/string
90
92
  - lib/action_controller/support/core_ext/string.rb
91
93
  - lib/action_controller/support/core_ext/hash/keys.rb
@@ -137,6 +139,7 @@ files:
137
139
  - test/controller/flash_test.rb
138
140
  - test/controller/helper_test.rb
139
141
  - test/controller/layout_test.rb
142
+ - test/controller/raw_post_test.rb
140
143
  - test/controller/redirect_test.rb
141
144
  - test/controller/render_test.rb
142
145
  - test/controller/request_test.rb