merge forward to current rails/master

This commit is contained in:
Sven Fuchs
2008-07-16 03:41:11 +02:00
247 changed files with 7561 additions and 3337 deletions

View File

@@ -1,5 +1,62 @@
*Edge*
* Get buffer for fragment cache from template's @output_buffer [Josh Peek]
* Set config.action_view.warn_cache_misses = true to receive a warning if you perform an action that results in an expensive disk operation that could be cached [Josh Peek]
* Refactor template preloading. New abstractions include Renderable mixins and a refactored Template class [Josh Peek]
* Changed ActionView::TemplateHandler#render API method signature to render(template, local_assigns = {}) [Josh Peek]
* Changed PrototypeHelper#submit_to_remote to PrototypeHelper#button_to_remote to stay consistent with link_to_remote (submit_to_remote still works as an alias) #8994 [clemens]
* Add :recursive option to javascript_include_tag and stylesheet_link_tag to be used along with :all. #480 [Damian Janowski]
* Allow users to disable the use of the Accept header [Michael Koziarski]
The accept header is poorly implemented by browsers and causes strange
errors when used on public sites where crawlers make requests too. You
can use formatted urls (e.g. /people/1.xml) to support API clients in a
much simpler way.
To disable the header you need to set:
config.action_controller.use_accept_header = false
* Do not stat template files in production mode before rendering. You will no longer be able to modify templates in production mode without restarting the server [Josh Peek]
* Deprecated TemplateHandler line offset [Josh Peek]
* Allow caches_action to accept cache store options. #416. [José Valim]. Example:
caches_action :index, :redirected, :if => Proc.new { |c| !c.request.format.json? }, :expires_in => 1.hour
* Remove define_javascript_functions, javascript_include_tag and friends are far superior. [Michael Koziarski]
* Deprecate :use_full_path render option. The supplying the option no longer has an effect [Josh Peek]
* Add :as option to render a collection of partials with a custom local variable name. #509 [Simon Jefford, Pratik Naik]
render :partial => 'other_people', :collection => @people, :as => :person
This will let you access objects of @people as 'person' local variable inside 'other_people' partial template.
* time_zone_select: support for regexp matching of priority zones. Resolves #195 [Ernie Miller]
* Made ActionView::Base#render_file private [Josh Peek]
* Refactor and simplify the implementation of assert_redirected_to. Arguments are now normalised relative to the controller being tested, not the root of the application. [Michael Koziarski]
This could cause some erroneous test failures if you were redirecting between controllers
in different namespaces and wrote your assertions relative to the root of the application.
* Remove follow_redirect from controller functional tests.
If you want to follow redirects you can use integration tests. The functional test
version was only useful if you were using redirect_to :id=>...
* Fix polymorphic_url with singleton resources. #461 [Tammer Saleh]
* Replaced TemplateFinder abstraction with ViewLoadPaths [Josh Peek]
* Added block-call style to link_to [Sam Stephenson/DHH]. Example:

View File

@@ -49,12 +49,14 @@ Rake::RDocTask.new { |rdoc|
rdoc.title = "Action Pack -- On rails from request to response"
rdoc.options << '--line-numbers' << '--inline-source'
rdoc.options << '--charset' << 'utf-8'
rdoc.template = "#{ENV['template']}.rb" if ENV['template']
rdoc.template = ENV['template'] ? "#{ENV['template']}.rb" : '../doc/template/horo'
if ENV['DOC_FILES']
rdoc.rdoc_files.include(ENV['DOC_FILES'].split(/,\s*/))
else
rdoc.rdoc_files.include('README', 'RUNNING_UNIT_TESTS', 'CHANGELOG')
rdoc.rdoc_files.include('lib/**/*.rb')
rdoc.rdoc_files.include(Dir['lib/**/*.rb'] -
Dir['lib/*/vendor/**/*.rb'])
rdoc.rdoc_files.exclude('lib/actionpack.rb')
end
}
@@ -132,13 +134,13 @@ task :update_js => [ :update_scriptaculous ]
desc "Publish the API documentation"
task :pgem => [:package] do
Rake::SshFilePublisher.new("davidhh@wrath.rubyonrails.org", "public_html/gems/gems", "pkg", "#{PKG_FILE_NAME}.gem").upload
`ssh davidhh@wrath.rubyonrails.org './gemupdate.sh'`
Rake::SshFilePublisher.new("wrath.rubyonrails.org", "public_html/gems/gems", "pkg", "#{PKG_FILE_NAME}.gem").upload
`ssh wrath.rubyonrails.org './gemupdate.sh'`
end
desc "Publish the API documentation"
task :pdoc => [:rdoc] do
Rake::SshDirPublisher.new("davidhh@wrath.rubyonrails.org", "public_html/ap", "doc").upload
Rake::SshDirPublisher.new("wrath.rubyonrails.org", "public_html/ap", "doc").upload
end
desc "Publish the release files to RubyForge."

View File

@@ -56,74 +56,24 @@ module ActionController
# # assert that the redirection was to the named route login_url
# assert_redirected_to login_url
#
# # assert that the redirection was to the url for @customer
# assert_redirected_to @customer
#
def assert_redirected_to(options = {}, message=nil)
clean_backtrace do
assert_response(:redirect, message)
return true if options == @response.redirected_to
ActionController::Routing::Routes.reload if ActionController::Routing::Routes.empty?
# Support partial arguments for hash redirections
if options.is_a?(Hash) && @response.redirected_to.is_a?(Hash)
return true if options.all? {|(key, value)| @response.redirected_to[key] == value}
end
redirected_to_after_normalisation = normalize_argument_to_redirection(@response.redirected_to)
options_after_normalisation = normalize_argument_to_redirection(options)
begin
url = {}
original = { :expected => options, :actual => @response.redirected_to.is_a?(Symbol) ? @response.redirected_to : @response.redirected_to.dup }
original.each do |key, value|
if value.is_a?(Symbol)
value = @controller.respond_to?(value, true) ? @controller.send(value) : @controller.send("hash_for_#{value}_url")
end
unless value.is_a?(Hash)
request = case value
when NilClass then nil
when /^\w+:\/\// then recognized_request_for(%r{^(\w+://.*?(/|$|\?))(.*)$} =~ value ? $3 : nil)
else recognized_request_for(value)
end
value = request.path_parameters if request
end
if value.is_a?(Hash) # stringify 2 levels of hash keys
if name = value.delete(:use_route)
route = ActionController::Routing::Routes.named_routes[name]
value.update(route.parameter_shell)
end
value.stringify_keys!
value.values.select { |v| v.is_a?(Hash) }.collect { |v| v.stringify_keys! }
if key == :expected && value['controller'] == @controller.controller_name && original[:actual].is_a?(Hash)
original[:actual].stringify_keys!
value.delete('controller') if original[:actual]['controller'].nil? || original[:actual]['controller'] == value['controller']
end
end
if value.respond_to?(:[]) && value['controller']
value['controller'] = value['controller'].to_s
if key == :actual && value['controller'].first != '/' && !value['controller'].include?('/')
new_controller_path = ActionController::Routing.controller_relative_to(value['controller'], @controller.class.controller_path)
value['controller'] = new_controller_path if value['controller'] != new_controller_path && ActionController::Routing.possible_controllers.include?(new_controller_path) && @response.redirected_to.is_a?(Hash)
end
value['controller'] = value['controller'][1..-1] if value['controller'].first == '/' # strip leading hash
end
url[key] = value
end
@response_diff = url[:actual].diff(url[:expected]) if url[:actual]
msg = build_message(message, "expected a redirect to <?>, found one to <?>, a difference of <?> ", url[:expected], url[:actual], @response_diff)
assert_block(msg) do
url[:expected].keys.all? do |k|
if k == :controller then url[:expected][k] == ActionController::Routing.controller_relative_to(url[:actual][k], @controller.class.controller_path)
else parameterize(url[:expected][k]) == parameterize(url[:actual][k])
end
end
end
rescue ActionController::RoutingError # routing failed us, so match the strings only.
msg = build_message(message, "expected a redirect to <?>, found one to <?>", options, @response.redirect_url)
url_regexp = %r{^(\w+://.*?(/|$|\?))(.*)$}
eurl, epath, url, path = [options, @response.redirect_url].collect do |url|
u, p = (url_regexp =~ url) ? [$1, $3] : [nil, url]
[u, (p.first == '/') ? p : '/' + p]
end.flatten
assert_equal(eurl, url, msg) if eurl && url
assert_equal(epath, path, msg) if epath && path
if redirected_to_after_normalisation != options_after_normalisation
flunk "Expected response to be a redirect to <#{options_after_normalisation}> but was a redirect to <#{redirected_to_after_normalisation}>"
end
end
end
@@ -137,36 +87,37 @@ module ActionController
#
def assert_template(expected = nil, message=nil)
clean_backtrace do
rendered = expected ? @response.rendered_file(!expected.include?('/')) : @response.rendered_file
rendered = @response.rendered_template
msg = build_message(message, "expecting <?> but rendering with <?>", expected, rendered)
assert_block(msg) do
if expected.nil?
!@response.rendered_with_file?
@response.rendered_template.nil?
else
expected == rendered
rendered.to_s.match(expected)
end
end
end
end
private
# Recognizes the route for a given path.
def recognized_request_for(path, request_method = nil)
path = "/#{path}" unless path.first == '/'
# Assume given controller
request = ActionController::TestRequest.new({}, {}, nil)
request.env["REQUEST_METHOD"] = request_method.to_s.upcase if request_method
request.path = path
ActionController::Routing::Routes.recognize(request)
request
end
# Proxy to to_param if the object will respond to it.
def parameterize(value)
value.respond_to?(:to_param) ? value.to_param : value
end
def normalize_argument_to_redirection(fragment)
after_routing = @controller.url_for(fragment)
if after_routing =~ %r{^\w+://.*}
after_routing
else
# FIXME - this should probably get removed.
if after_routing.first != '/'
after_routing = '/' + after_routing
end
@request.protocol + @request.host_with_port + after_routing
end
end
end
end
end

View File

@@ -340,6 +340,16 @@ module ActionController #:nodoc:
cattr_accessor :optimise_named_routes
self.optimise_named_routes = true
# Indicates whether the response format should be determined by examining the Accept HTTP header,
# or by using the simpler params + ajax rules.
#
# If this is set to +true+ (the default) then +respond_to+ and +Request#format+ will take the Accept
# header into account. If it is set to false then the request format will be determined solely
# by examining params[:format]. If params format is missing, the format will be either HTML or
# Javascript depending on whether the request is an AJAX request.
cattr_accessor :use_accept_header
self.use_accept_header = true
# Controls whether request forgergy protection is turned on or not. Turned off by default only in test mode.
class_inheritable_accessor :allow_forgery_protection
self.allow_forgery_protection = true
@@ -402,7 +412,7 @@ module ActionController #:nodoc:
# More methods can be hidden using <tt>hide_actions</tt>.
def hidden_actions
unless read_inheritable_attribute(:hidden_actions)
write_inheritable_attribute(:hidden_actions, ActionController::Base.public_instance_methods.map(&:to_s))
write_inheritable_attribute(:hidden_actions, ActionController::Base.public_instance_methods.map { |m| m.to_s })
end
read_inheritable_attribute(:hidden_actions)
@@ -410,18 +420,18 @@ module ActionController #:nodoc:
# Hide each of the given methods from being callable as actions.
def hide_action(*names)
write_inheritable_attribute(:hidden_actions, hidden_actions | names.map(&:to_s))
write_inheritable_attribute(:hidden_actions, hidden_actions | names.map { |name| name.to_s })
end
## View load paths determine the bases from which template references can be made. So a call to
## render("test/template") will be looked up in the view load paths array and the closest match will be
## returned.
# View load paths determine the bases from which template references can be made. So a call to
# render("test/template") will be looked up in the view load paths array and the closest match will be
# returned.
def view_paths
@view_paths || superclass.view_paths
end
def view_paths=(value)
@view_paths = ActionView::ViewLoadPaths.new(Array(value)) if value
@view_paths = ActionView::Base.process_view_paths(value) if value
end
# Adds a view_path to the front of the view_paths array.
@@ -603,7 +613,8 @@ module ActionController #:nodoc:
#
# This takes the current URL as is and only exchanges the action. In contrast, <tt>url_for :action => 'print'</tt>
# would have slashed-off the path components after the changed action.
def url_for(options = {}) #:doc:
def url_for(options = {})
options ||= {}
case options
when String
options
@@ -641,7 +652,7 @@ module ActionController #:nodoc:
end
def view_paths=(value)
@template.view_paths = ViewLoadPaths.new(value)
@template.view_paths = ActionView::Base.process_view_paths(value)
end
# Adds a view_path to the front of the view_paths array.
@@ -702,6 +713,9 @@ module ActionController #:nodoc:
# # builds the complete response.
# render :partial => "person", :collection => @winners
#
# # Renders a collection of partials but with a custom local variable name
# render :partial => "admin_person", :collection => @winners, :as => :person
#
# # Renders the same collection of partials, but also renders the
# # person_divider partial between each person partial.
# render :partial => "person", :collection => @winners, :spacer_template => "person_divider"
@@ -733,6 +747,9 @@ module ActionController #:nodoc:
# # Renders the template located in [TEMPLATE_ROOT]/weblog/show.r(html|xml) (in Rails, app/views/weblog/show.erb)
# render :template => "weblog/show"
#
# # Renders the template with a local variable
# render :template => "weblog/show", :locals => {:customer => Customer.new}
#
# === Rendering a file
#
# File rendering works just like action rendering except that it takes a filesystem path. By default, the path
@@ -852,22 +869,21 @@ module ActionController #:nodoc:
else
if file = options[:file]
render_for_file(file, options[:status], options[:use_full_path], options[:locals] || {})
render_for_file(file, options[:status], nil, options[:locals] || {})
elsif template = options[:template]
render_for_file(template, options[:status], true)
render_for_file(template, options[:status], true, options[:locals] || {})
elsif inline = options[:inline]
add_variables_to_assigns
tmpl = ActionView::InlineTemplate.new(@template, options[:inline], options[:locals], options[:type])
render_for_text(@template.render_template(tmpl), options[:status])
render_for_text(@template.render(options), options[:status])
elsif action_name = options[:action]
template = default_template_name(action_name.to_s)
if options[:layout] && !template_exempt_from_layout?(template)
render_with_a_layout(:file => template, :status => options[:status], :use_full_path => true, :layout => true)
render_with_a_layout(:file => template, :status => options[:status], :layout => true)
else
render_with_no_layout(:file => template, :status => options[:status], :use_full_path => true)
render_with_no_layout(:file => template, :status => options[:status])
end
elsif xml = options[:xml]
@@ -887,12 +903,12 @@ module ActionController #:nodoc:
if collection = options[:collection]
render_for_text(
@template.send!(:render_partial_collection, partial, collection,
options[:spacer_template], options[:locals]), options[:status]
options[:spacer_template], options[:locals], options[:as]), options[:status]
)
else
render_for_text(
@template.send!(:render_partial, partial,
ActionView::Base::ObjectWrapper.new(options[:object]), options[:locals]), options[:status]
options[:object], options[:locals]), options[:status]
)
end
@@ -1037,29 +1053,31 @@ module ActionController #:nodoc:
status = 302
end
response.redirected_to= options
logger.info("Redirected to #{options}") if logger && logger.info?
case options
when %r{^\w+://.*}
raise DoubleRenderError if performed?
logger.info("Redirected to #{options}") if logger && logger.info?
response.redirect(options, interpret_status(status))
response.redirected_to = options
@performed_redirect = true
redirect_to_full_url(options, status)
when String
redirect_to(request.protocol + request.host_with_port + options, :status=>status)
redirect_to_full_url(request.protocol + request.host_with_port + options, status)
when :back
request.env["HTTP_REFERER"] ? redirect_to(request.env["HTTP_REFERER"], :status=>status) : raise(RedirectBackError)
when Hash
redirect_to(url_for(options), :status=>status)
response.redirected_to = options
if referer = request.headers["Referer"]
redirect_to(referer, :status=>status)
else
raise RedirectBackError
end
else
redirect_to(url_for(options), :status=>status)
redirect_to_full_url(url_for(options), status)
end
end
def redirect_to_full_url(url, status)
raise DoubleRenderError if performed?
response.redirect(url, interpret_status(status))
@performed_redirect = true
end
# Sets a HTTP 1.1 Cache-Control header. Defaults to issuing a "private" instruction, so that
# intermediate caches shouldn't cache the response.
#
@@ -1092,10 +1110,10 @@ module ActionController #:nodoc:
private
def render_for_file(template_path, status = nil, use_full_path = false, locals = {}) #:nodoc:
def render_for_file(template_path, status = nil, use_full_path = nil, locals = {}) #:nodoc:
add_variables_to_assigns
logger.info("Rendering #{template_path}" + (status ? " (#{status})" : '')) if logger
render_for_text(@template.render_file(template_path, use_full_path, locals), status)
render_for_text(@template.render(:file => template_path, :locals => locals), status)
end
def render_for_text(text = nil, status = nil, append_response = false) #:nodoc:
@@ -1183,7 +1201,7 @@ module ActionController #:nodoc:
end
def self.action_methods
@action_methods ||= Set.new(public_instance_methods.map(&:to_s)) - hidden_actions
@action_methods ||= Set.new(public_instance_methods.map { |m| m.to_s }) - hidden_actions
end
def add_variables_to_assigns
@@ -1230,8 +1248,8 @@ module ActionController #:nodoc:
end
def template_exempt_from_layout?(template_name = default_template_name)
template_name = @template.send(:template_file_from_name, template_name) if @template
@@exempt_from_layout.any? { |ext| template_name.to_s =~ ext }
template_name = @template.pick_template(template_name).to_s if @template
@@exempt_from_layout.any? { |ext| template_name =~ ext }
end
def default_template_name(action_name = self.action_name)

View File

@@ -27,13 +27,15 @@ module ActionController #:nodoc:
# You can set modify the default action cache path by passing a :cache_path option. This will be passed directly to ActionCachePath.path_for. This is handy
# for actions with multiple possible routes that should be cached differently. If a block is given, it is called with the current controller instance.
#
# And you can also use :if to pass a Proc that specifies when the action should be cached.
# And you can also use :if (or :unless) to pass a Proc that specifies when the action should be cached.
#
# Finally, if you are using memcached, you can also pass :expires_in.
#
# class ListsController < ApplicationController
# before_filter :authenticate, :except => :public
# caches_page :public
# caches_action :index, :if => Proc.new { |c| !c.request.format.json? } # cache if is not a JSON request
# caches_action :show, :cache_path => { :project => 1 }
# caches_action :show, :cache_path => { :project => 1 }, :expires_in => 1.hour
# caches_action :feed, :cache_path => Proc.new { |controller|
# controller.params[:user_id] ?
# controller.send(:user_list_url, c.params[:user_id], c.params[:id]) :
@@ -56,8 +58,10 @@ module ActionController #:nodoc:
def caches_action(*actions)
return unless cache_configured?
options = actions.extract_options!
cache_filter = ActionCacheFilter.new(:layout => options.delete(:layout), :cache_path => options.delete(:cache_path))
around_filter(cache_filter, {:only => actions}.merge(options))
filter_options = { :only => actions, :if => options.delete(:if), :unless => options.delete(:unless) }
cache_filter = ActionCacheFilter.new(:layout => options.delete(:layout), :cache_path => options.delete(:cache_path), :store_options => options)
around_filter(cache_filter, filter_options)
end
end
@@ -80,8 +84,8 @@ module ActionController #:nodoc:
end
def before(controller)
cache_path = ActionCachePath.new(controller, path_options_for(controller, @options))
if cache = controller.read_fragment(cache_path.path)
cache_path = ActionCachePath.new(controller, path_options_for(controller, @options.slice(:cache_path)))
if cache = controller.read_fragment(cache_path.path, @options[:store_options])
controller.rendered_action_cache = true
set_content_type!(controller, cache_path.extension)
options = { :text => cache }
@@ -96,7 +100,7 @@ module ActionController #:nodoc:
def after(controller)
return if controller.rendered_action_cache || !caching_allowed(controller)
action_content = cache_layout? ? content_for_layout(controller) : controller.response.body
controller.write_fragment(controller.action_cache_path.path, action_content)
controller.write_fragment(controller.action_cache_path.path, action_content, @options[:store_options])
end
private
@@ -162,10 +166,7 @@ module ActionController #:nodoc:
# If there's no extension in the path, check request.format
if extension.nil?
extension = request.format.to_sym.to_s
if extension=='all'
extension = nil
end
extension = request.cache_format
end
extension
end

View File

@@ -60,17 +60,17 @@ module ActionController #:nodoc:
ActiveSupport::Cache.expand_cache_key(key.is_a?(Hash) ? url_for(key).split("://").last : key, :views)
end
def fragment_for(block, name = {}, options = nil) #:nodoc:
unless perform_caching then block.call; return end
buffer = yield
if cache = read_fragment(name, options)
buffer.concat(cache)
def fragment_for(buffer, name = {}, options = nil, &block) #:nodoc:
if perform_caching
if cache = read_fragment(name, options)
buffer.concat(cache)
else
pos = buffer.length
block.call
write_fragment(name, buffer[pos..-1], options)
end
else
pos = buffer.length
block.call
write_fragment(name, buffer[pos..-1], options)
end
end

View File

@@ -7,6 +7,225 @@ module ActionController #:nodoc:
end
end
class FilterChain < ActiveSupport::Callbacks::CallbackChain #:nodoc:
def append_filter_to_chain(filters, filter_type, &block)
pos = find_filter_append_position(filters, filter_type)
update_filter_chain(filters, filter_type, pos, &block)
end
def prepend_filter_to_chain(filters, filter_type, &block)
pos = find_filter_prepend_position(filters, filter_type)
update_filter_chain(filters, filter_type, pos, &block)
end
def create_filters(filters, filter_type, &block)
filters, conditions = extract_options(filters, &block)
filters.map! { |filter| find_or_create_filter(filter, filter_type, conditions) }
filters
end
def skip_filter_in_chain(*filters, &test)
filters, conditions = extract_options(filters)
filters.each do |filter|
if callback = find(filter) then delete(callback) end
end if conditions.empty?
update_filter_in_chain(filters, :skip => conditions, &test)
end
private
def update_filter_chain(filters, filter_type, pos, &block)
new_filters = create_filters(filters, filter_type, &block)
insert(pos, new_filters).flatten!
end
def find_filter_append_position(filters, filter_type)
# appending an after filter puts it at the end of the call chain
# before and around filters go before the first after filter in the chain
unless filter_type == :after
each_with_index do |f,i|
return i if f.after?
end
end
return -1
end
def find_filter_prepend_position(filters, filter_type)
# prepending a before or around filter puts it at the front of the call chain
# after filters go before the first after filter in the chain
if filter_type == :after
each_with_index do |f,i|
return i if f.after?
end
return -1
end
return 0
end
def find_or_create_filter(filter, filter_type, options = {})
update_filter_in_chain([filter], options)
if found_filter = find(filter) { |f| f.type == filter_type }
found_filter
else
filter_kind = case
when filter.respond_to?(:before) && filter_type == :before
:before
when filter.respond_to?(:after) && filter_type == :after
:after
else
:filter
end
case filter_type
when :before
BeforeFilter.new(filter_kind, filter, options)
when :after
AfterFilter.new(filter_kind, filter, options)
else
AroundFilter.new(filter_kind, filter, options)
end
end
end
def update_filter_in_chain(filters, options, &test)
filters.map! { |f| block_given? ? find(f, &test) : find(f) }
filters.compact!
map! do |filter|
if filters.include?(filter)
new_filter = filter.dup
new_filter.update_options!(options)
new_filter
else
filter
end
end
end
end
class Filter < ActiveSupport::Callbacks::Callback #:nodoc:
def initialize(kind, method, options = {})
super
update_options! options
end
def before?
self.class == BeforeFilter
end
def after?
self.class == AfterFilter
end
def around?
self.class == AroundFilter
end
# Make sets of strings from :only/:except options
def update_options!(other)
if other
convert_only_and_except_options_to_sets_of_strings(other)
if other[:skip]
convert_only_and_except_options_to_sets_of_strings(other[:skip])
end
end
options.update(other)
end
private
def should_not_skip?(controller)
if options[:skip]
!included_in_action?(controller, options[:skip])
else
true
end
end
def included_in_action?(controller, options)
if options[:only]
options[:only].include?(controller.action_name)
elsif options[:except]
!options[:except].include?(controller.action_name)
else
true
end
end
def should_run_callback?(controller)
should_not_skip?(controller) && included_in_action?(controller, options) && super
end
def convert_only_and_except_options_to_sets_of_strings(opts)
[:only, :except].each do |key|
if values = opts[key]
opts[key] = Array(values).map(&:to_s).to_set
end
end
end
end
class AroundFilter < Filter #:nodoc:
def type
:around
end
def call(controller, &block)
if should_run_callback?(controller)
method = filter_responds_to_before_and_after? ? around_proc : self.method
# For around_filter do |controller, action|
if method.is_a?(Proc) && method.arity == 2
evaluate_method(method, controller, block)
else
evaluate_method(method, controller, &block)
end
else
block.call
end
end
private
def filter_responds_to_before_and_after?
method.respond_to?(:before) && method.respond_to?(:after)
end
def around_proc
Proc.new do |controller, action|
method.before(controller)
if controller.send!(:performed?)
controller.send!(:halt_filter_chain, method, :rendered_or_redirected)
else
begin
action.call
ensure
method.after(controller)
end
end
end
end
end
class BeforeFilter < Filter #:nodoc:
def type
:before
end
def call(controller, &block)
super
if controller.send!(:performed?)
controller.send!(:halt_filter_chain, method, :rendered_or_redirected)
end
end
end
class AfterFilter < Filter #:nodoc:
def type
:after
end
end
# Filters enable controllers to run shared pre- and post-processing code for its actions. These filters can be used to do
# authentication, caching, or auditing before the intended action is performed. Or to do localization or output
# compression after the action has been performed. Filters have access to the request, response, and all the instance
@@ -245,201 +464,6 @@ module ActionController #:nodoc:
# filter and controller action will not be run. If +before+ renders or redirects,
# the second half of +around+ and will still run but +after+ and the
# action will not. If +around+ fails to yield, +after+ will not be run.
class FilterChain < ActiveSupport::Callbacks::CallbackChain #:nodoc:
def append_filter_to_chain(filters, filter_type, &block)
pos = find_filter_append_position(filters, filter_type)
update_filter_chain(filters, filter_type, pos, &block)
end
def prepend_filter_to_chain(filters, filter_type, &block)
pos = find_filter_prepend_position(filters, filter_type)
update_filter_chain(filters, filter_type, pos, &block)
end
def create_filters(filters, filter_type, &block)
filters, conditions = extract_options(filters, &block)
filters.map! { |filter| find_or_create_filter(filter, filter_type, conditions) }
filters
end
def skip_filter_in_chain(*filters, &test)
filters, conditions = extract_options(filters)
filters.each do |filter|
if callback = find(filter) then delete(callback) end
end if conditions.empty?
update_filter_in_chain(filters, :skip => conditions, &test)
end
private
def update_filter_chain(filters, filter_type, pos, &block)
new_filters = create_filters(filters, filter_type, &block)
insert(pos, new_filters).flatten!
end
def find_filter_append_position(filters, filter_type)
# appending an after filter puts it at the end of the call chain
# before and around filters go before the first after filter in the chain
unless filter_type == :after
each_with_index do |f,i|
return i if f.after?
end
end
return -1
end
def find_filter_prepend_position(filters, filter_type)
# prepending a before or around filter puts it at the front of the call chain
# after filters go before the first after filter in the chain
if filter_type == :after
each_with_index do |f,i|
return i if f.after?
end
return -1
end
return 0
end
def find_or_create_filter(filter, filter_type, options = {})
update_filter_in_chain([filter], options)
if found_filter = find(filter) { |f| f.type == filter_type }
found_filter
else
filter_kind = case
when filter.respond_to?(:before) && filter_type == :before
:before
when filter.respond_to?(:after) && filter_type == :after
:after
else
:filter
end
case filter_type
when :before
BeforeFilter.new(filter_kind, filter, options)
when :after
AfterFilter.new(filter_kind, filter, options)
else
AroundFilter.new(filter_kind, filter, options)
end
end
end
def update_filter_in_chain(filters, options, &test)
filters.map! { |f| block_given? ? find(f, &test) : find(f) }
filters.compact!
map! do |filter|
if filters.include?(filter)
new_filter = filter.dup
new_filter.options.merge!(options)
new_filter
else
filter
end
end
end
end
class Filter < ActiveSupport::Callbacks::Callback #:nodoc:
def before?
self.class == BeforeFilter
end
def after?
self.class == AfterFilter
end
def around?
self.class == AroundFilter
end
private
def should_not_skip?(controller)
if options[:skip]
!included_in_action?(controller, options[:skip])
else
true
end
end
def included_in_action?(controller, options)
if options[:only]
Array(options[:only]).map(&:to_s).include?(controller.action_name)
elsif options[:except]
!Array(options[:except]).map(&:to_s).include?(controller.action_name)
else
true
end
end
def should_run_callback?(controller)
should_not_skip?(controller) && included_in_action?(controller, options) && super
end
end
class AroundFilter < Filter #:nodoc:
def type
:around
end
def call(controller, &block)
if should_run_callback?(controller)
method = filter_responds_to_before_and_after? ? around_proc : self.method
# For around_filter do |controller, action|
if method.is_a?(Proc) && method.arity == 2
evaluate_method(method, controller, block)
else
evaluate_method(method, controller, &block)
end
else
block.call
end
end
private
def filter_responds_to_before_and_after?
method.respond_to?(:before) && method.respond_to?(:after)
end
def around_proc
Proc.new do |controller, action|
method.before(controller)
if controller.send!(:performed?)
controller.send!(:halt_filter_chain, method, :rendered_or_redirected)
else
begin
action.call
ensure
method.after(controller)
end
end
end
end
end
class BeforeFilter < Filter #:nodoc:
def type
:before
end
def call(controller, &block)
super
if controller.send!(:performed?)
controller.send!(:halt_filter_chain, method, :rendered_or_redirected)
end
end
end
class AfterFilter < Filter #:nodoc:
def type
:after
end
end
module ClassMethods
# The passed <tt>filters</tt> will be appended to the filter_chain and
# will execute before the action on this controller is performed.

View File

@@ -254,7 +254,7 @@ module ActionController #:nodoc:
@template.instance_variable_set("@content_for_layout", content_for_layout)
response.layout = layout
status = template_with_options ? options[:status] : nil
render_for_text(@template.render_file(layout, true), status)
render_for_text(@template.render(layout), status)
else
render_with_no_layout(options, extra_options, &block)
end
@@ -304,7 +304,7 @@ module ActionController #:nodoc:
end
def layout_directory?(layout_name)
@template.view_paths.find_template_file_for_path("#{File.join('layouts', layout_name)}.#{@template.template_format}.erb") ? true : false
@template.file_exists?("#{File.join('layouts', layout_name)}.#{@template.template_format}")
end
end
end

View File

@@ -114,7 +114,11 @@ module ActionController #:nodoc:
@request = controller.request
@response = controller.response
@mime_type_priority = Array(Mime::Type.lookup_by_extension(@request.parameters[:format]) || @request.accepts)
if ActionController::Base.use_accept_header
@mime_type_priority = Array(Mime::Type.lookup_by_extension(@request.parameters[:format]) || @request.accepts)
else
@mime_type_priority = [@request.format]
end
@order = []
@responses = {}

View File

@@ -72,57 +72,61 @@ module Mime
end
def parse(accept_header)
# keep track of creation order to keep the subsequent sort stable
list = []
accept_header.split(/,/).each_with_index do |header, index|
params, q = header.split(/;\s*q=/)
if params
params.strip!
list << AcceptItem.new(index, params, q) unless params.empty?
end
end
list.sort!
# Take care of the broken text/xml entry by renaming or deleting it
text_xml = list.index("text/xml")
app_xml = list.index(Mime::XML.to_s)
if text_xml && app_xml
# set the q value to the max of the two
list[app_xml].q = [list[text_xml].q, list[app_xml].q].max
# make sure app_xml is ahead of text_xml in the list
if app_xml > text_xml
list[app_xml], list[text_xml] = list[text_xml], list[app_xml]
app_xml, text_xml = text_xml, app_xml
end
# delete text_xml from the list
list.delete_at(text_xml)
elsif text_xml
list[text_xml].name = Mime::XML.to_s
end
# Look for more specific XML-based types and sort them ahead of app/xml
if app_xml
idx = app_xml
app_xml_type = list[app_xml]
while(idx < list.length)
type = list[idx]
break if type.q < app_xml_type.q
if type.name =~ /\+xml$/
list[app_xml], list[idx] = list[idx], list[app_xml]
app_xml = idx
if accept_header !~ /,/
[Mime::Type.lookup(accept_header)]
else
# keep track of creation order to keep the subsequent sort stable
list = []
accept_header.split(/,/).each_with_index do |header, index|
params, q = header.split(/;\s*q=/)
if params
params.strip!
list << AcceptItem.new(index, params, q) unless params.empty?
end
idx += 1
end
end
list.sort!
list.map! { |i| Mime::Type.lookup(i.name) }.uniq!
list
# Take care of the broken text/xml entry by renaming or deleting it
text_xml = list.index("text/xml")
app_xml = list.index(Mime::XML.to_s)
if text_xml && app_xml
# set the q value to the max of the two
list[app_xml].q = [list[text_xml].q, list[app_xml].q].max
# make sure app_xml is ahead of text_xml in the list
if app_xml > text_xml
list[app_xml], list[text_xml] = list[text_xml], list[app_xml]
app_xml, text_xml = text_xml, app_xml
end
# delete text_xml from the list
list.delete_at(text_xml)
elsif text_xml
list[text_xml].name = Mime::XML.to_s
end
# Look for more specific XML-based types and sort them ahead of app/xml
if app_xml
idx = app_xml
app_xml_type = list[app_xml]
while(idx < list.length)
type = list[idx]
break if type.q < app_xml_type.q
if type.name =~ /\+xml$/
list[app_xml], list[idx] = list[idx], list[app_xml]
app_xml = idx
end
idx += 1
end
end
list.map! { |i| Mime::Type.lookup(i.name) }.uniq!
list
end
end
end

View File

@@ -17,4 +17,5 @@ Mime::Type.register "multipart/form-data", :multipart_form
Mime::Type.register "application/x-www-form-urlencoded", :url_encoded_form
# http://www.ietf.org/rfc/rfc4627.txt
Mime::Type.register "application/json", :json, %w( text/x-json )
# http://www.json.org/JSONRequest.html
Mime::Type.register "application/json", :json, %w( text/x-json application/jsonrequest )

View File

@@ -48,6 +48,9 @@ module ActionController
#
# # calls post_url(post)
# polymorphic_url(post) # => "http://example.com/posts/1"
# polymorphic_url([blog, post]) # => "http://example.com/blogs/1/posts/1"
# polymorphic_url([:admin, blog, post]) # => "http://example.com/admin/blogs/1/posts/1"
# polymorphic_url([user, :blog, post]) # => "http://example.com/users/1/blog/posts/1"
#
# ==== Options
#
@@ -83,8 +86,6 @@ module ActionController
else [ record_or_hash_or_array ]
end
args << format if format
inflection =
case
when options[:action].to_s == "new"
@@ -96,6 +97,9 @@ module ActionController
else
:singular
end
args.delete_if {|arg| arg.is_a?(Symbol) || arg.is_a?(String)}
args << format if format
named_route = build_named_route_call(record_or_hash_or_array, namespace, inflection, options)
send!(named_route, *args)
@@ -136,11 +140,19 @@ module ActionController
else
record = records.pop
route = records.inject("") do |string, parent|
string << "#{RecordIdentifier.send!("singular_class_name", parent)}_"
if parent.is_a?(Symbol) || parent.is_a?(String)
string << "#{parent}_"
else
string << "#{RecordIdentifier.send!("singular_class_name", parent)}_"
end
end
end
route << "#{RecordIdentifier.send!("#{inflection}_class_name", record)}_"
if record.is_a?(Symbol) || record.is_a?(String)
route << "#{record}_"
else
route << "#{RecordIdentifier.send!("#{inflection}_class_name", record)}_"
end
action_prefix(options) + namespace + route + routing_type(options).to_s
end
@@ -163,16 +175,17 @@ module ActionController
end
end
# Remove the first symbols from the array and return the url prefix
# implied by those symbols.
def extract_namespace(record_or_hash_or_array)
returning "" do |namespace|
if record_or_hash_or_array.is_a?(Array)
record_or_hash_or_array.delete_if do |record_or_namespace|
if record_or_namespace.is_a?(String) || record_or_namespace.is_a?(Symbol)
namespace << "#{record_or_namespace}_"
end
end
end
return "" unless record_or_hash_or_array.is_a?(Array)
namespace_keys = []
while (key = record_or_hash_or_array.first) && key.is_a?(String) || key.is_a?(Symbol)
namespace_keys << record_or_hash_or_array.shift
end
namespace_keys.map {|k| "#{k}_"}.join
end
end
end

View File

@@ -24,6 +24,19 @@ module ActionController #:nodoc:
super()
end
%w[ AUTH_TYPE CONTENT_TYPE GATEWAY_INTERFACE PATH_INFO
PATH_TRANSLATED QUERY_STRING REMOTE_HOST
REMOTE_IDENT REMOTE_USER SCRIPT_NAME
SERVER_NAME SERVER_PROTOCOL
HTTP_ACCEPT HTTP_ACCEPT_CHARSET HTTP_ACCEPT_ENCODING
HTTP_ACCEPT_LANGUAGE HTTP_CACHE_CONTROL HTTP_FROM HTTP_HOST
HTTP_NEGOTIATE HTTP_PRAGMA HTTP_REFERER HTTP_USER_AGENT ].each do |env|
define_method(env.sub(/^HTTP_/n, '').downcase) do
@env[env]
end
end
# The request body is an IO input stream. If the RAW_POST_DATA environment
# variable is already set, wrap it in a StringIO.
def body
@@ -35,7 +48,7 @@ module ActionController #:nodoc:
end
def key?(key)
@env.key? key
@env.key?(key)
end
def query_parameters
@@ -85,6 +98,18 @@ module ActionController #:nodoc:
@env['REMOTE_ADDR']
end
def request_method
@env['REQUEST_METHOD'].downcase.to_sym
end
def server_port
@env['SERVER_PORT'].to_i
end
def server_software
@env['SERVER_SOFTWARE'].split("/").first
end
def session
unless defined?(@session)
if @session_options == false
@@ -178,9 +203,9 @@ end_msg
normalize_headers(@headers)
if [204, 304].include?(@status.to_i)
@headers.delete "Content-Type"
[status.to_i, @headers.to_hash, []]
[status, @headers.to_hash, []]
else
[status.to_i, @headers.to_hash, self]
[status, @headers.to_hash, self]
end
end
alias to_a out
@@ -225,8 +250,8 @@ end_msg
headers['Content-Language'] = options.delete('language') if options['language']
headers['Expires'] = options.delete('expires') if options['expires']
@status = options.delete('Status') if options['Status']
@status ||= 200
@status = options['Status'] || "200 OK"
# Convert 'cookie' header to 'Set-Cookie' headers.
# Because Set-Cookie header can appear more the once in the response body,
# we store it in a line break seperated string that will be translated to

View File

@@ -82,21 +82,34 @@ module ActionController
# Returns the accepted MIME type for the request
def accepts
@accepts ||=
if @env['HTTP_ACCEPT'].to_s.strip.empty?
[ content_type, Mime::ALL ].compact # make sure content_type being nil is not included
else
Mime::Type.parse(@env['HTTP_ACCEPT'])
begin
header = @env['HTTP_ACCEPT'].to_s.strip
if header.empty?
[content_type, Mime::ALL].compact
else
Mime::Type.parse(header)
end
end
end
# Returns the Mime type for the format used in the request. If there is no format available, the first of the
# accept types will be used. Examples:
# Returns the Mime type for the format used in the request.
#
# GET /posts/5.xml | request.format => Mime::XML
# GET /posts/5.xhtml | request.format => Mime::HTML
# GET /posts/5 | request.format => request.accepts.first (usually Mime::HTML for browsers)
# GET /posts/5 | request.format => Mime::HTML or MIME::JS, or request.accepts.first depending on the value of <tt>ActionController::Base.use_accept_header</tt>
def format
@format ||= parameters[:format] ? Mime::Type.lookup_by_extension(parameters[:format]) : accepts.first
@format ||= begin
if parameters[:format]
Mime::Type.lookup_by_extension(parameters[:format])
elsif ActionController::Base.use_accept_header
accepts.first
elsif xhr?
Mime::Type.lookup_by_extension("js")
else
Mime::Type.lookup_by_extension("html")
end
end
end
@@ -116,6 +129,26 @@ module ActionController
@format = Mime::Type.lookup_by_extension(parameters[:format])
end
# Returns a symbolized version of the <tt>:format</tt> parameter of the request.
# If no format is given it returns <tt>:js</tt>for AJAX requests and <tt>:html</tt>
# otherwise.
def template_format
parameter_format = parameters[:format]
if parameter_format
parameter_format.to_sym
elsif xhr?
:js
else
:html
end
end
def cache_format
parameter_format = parameters[:format]
parameter_format && parameter_format.to_sym
end
# Returns true if the request's "X-Requested-With" header contains
# "XMLHttpRequest". (The Prototype Javascript library sends this header with
# every Ajax request.)

View File

@@ -178,7 +178,7 @@ module ActionController #:nodoc:
@template.instance_variable_set("@rescues_path", File.dirname(rescues_path("stub")))
@template.send!(:assign_variables_from_controller)
@template.instance_variable_set("@contents", @template.render_file(template_path_for_local_rescue(exception), false))
@template.instance_variable_set("@contents", @template.render(:file => template_path_for_local_rescue(exception), :use_full_path => false))
response.content_type = Mime::HTML
render_for_file(rescues_path("layout"), response_code_for_rescue(exception))

View File

@@ -72,7 +72,7 @@ module ActionController
end
def conditions
@conditions = @options[:conditions] || {}
@conditions ||= @options[:conditions] || {}
end
def path
@@ -80,9 +80,9 @@ module ActionController
end
def new_path
new_action = self.options[:path_names][:new] if self.options[:path_names]
new_action = self.options[:path_names][:new] if self.options[:path_names]
new_action ||= Base.resources_path_names[:new]
@new_path ||= "#{path}/#{new_action}"
@new_path ||= "#{path}/#{new_action}"
end
def member_path

View File

@@ -88,6 +88,10 @@ module ActionController
#
# map.connect ':controller/:action/:id', :action => 'show', :defaults => { :page => 'Dashboard' }
#
# Note: The default routes, as provided by the Rails generator, make all actions in every
# controller accessible via GET requests. You should consider removing them or commenting
# them out if you're using named routes and resources.
#
# == Named routes
#
# Routes can be named with the syntax <tt>map.name_of_route options</tt>,

View File

@@ -67,10 +67,9 @@ module ActionController
options = options.dup
if options[:namespace]
options[:controller] = "#{options[:path_prefix]}/#{options[:controller]}"
options[:controller] = "#{options.delete(:namespace).sub(/\/$/, '')}/#{options[:controller]}"
options.delete(:path_prefix)
options.delete(:name_prefix)
options.delete(:namespace)
end
requirements = (options.delete(:requirements) || {}).dup

View File

@@ -6,6 +6,6 @@
</h1>
<pre><%=h @exception.clean_message %></pre>
<%= render_file(@rescues_path + "/_trace.erb", false) %>
<%= render(:file => @rescues_path + "/_trace.erb", :use_full_path => false) %>
<%= render_file(@rescues_path + "/_request_and_response.erb", false) %>
<%= render(:file => @rescues_path + "/_request_and_response.erb", :use_full_path => false) %>

View File

@@ -15,7 +15,7 @@
<% @real_exception = @exception
@exception = @exception.original_exception || @exception %>
<%= render_file(@rescues_path + "/_trace.erb", false) %>
<%= render(:file => @rescues_path + "/_trace.erb", :use_full_path => false) %>
<% @exception = @real_exception %>
<%= render_file(@rescues_path + "/_request_and_response.erb", false) %>
<%= render(:file => @rescues_path + "/_request_and_response.erb", :use_full_path => false) %>

View File

@@ -205,21 +205,10 @@ module ActionController #:nodoc:
p.match(redirect_url) != nil
end
# Returns the template path of the file which was used to
# render this response (or nil)
def rendered_file(with_controller=false)
unless template.first_render.nil?
unless with_controller
template.first_render
else
template.first_render.split('/').last || template.first_render
end
end
end
# Was this template rendered by a file?
def rendered_with_file?
!rendered_file.nil?
# Returns the template of the file which was used to
# render this response (or nil)
def rendered_template
template._first_render
end
# A shortcut to the flash. Returns an empyt hash if no session flash exists.
@@ -404,15 +393,6 @@ module ActionController #:nodoc:
end
alias xhr :xml_http_request
def follow_redirect
redirected_controller = @response.redirected_to[:controller]
if redirected_controller && redirected_controller != @controller.controller_name
raise "Can't follow redirects outside of current controller (from #{@controller.controller_name} to #{redirected_controller})"
end
get(@response.redirected_to.delete(:action), @response.redirected_to.stringify_keys)
end
def assigns(key = nil)
if key.nil?
@response.template.assigns

View File

@@ -17,7 +17,7 @@ module HTML #:nodoc:
@root = Node.new(nil)
node_stack = [ @root ]
while token = tokenizer.next
node = Node.parse(node_stack.last, tokenizer.line, tokenizer.position, token)
node = Node.parse(node_stack.last, tokenizer.line, tokenizer.position, token, strict)
node_stack.last.children << node unless node.tag? && node.closing == :close
if node.tag?

View File

@@ -21,12 +21,14 @@
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#++
require 'action_view/template_handlers'
require 'action_view/template_file'
require 'action_view/view_load_paths'
require 'action_view/renderable'
require 'action_view/renderable_partial'
require 'action_view/template'
require 'action_view/partial_template'
require 'action_view/inline_template'
require 'action_view/paths'
require 'action_view/base'
require 'action_view/partials'

View File

@@ -3,6 +3,12 @@ module ActionView #:nodoc:
end
class MissingTemplate < ActionViewError #:nodoc:
def initialize(paths, path, template_format = nil)
full_template_path = path.include?('.') ? path : "#{path}.erb"
display_paths = paths.join(':')
template_type = (path =~ /layouts/i) ? 'layout' : 'template'
super("Missing #{template_type} #{full_template_path} in view path #{display_paths}")
end
end
# Action View templates can be written in three ways. If the template file has a <tt>.erb</tt> (or <tt>.rhtml</tt>) extension then it uses a mixture of ERb
@@ -153,20 +159,19 @@ module ActionView #:nodoc:
class Base
include ERB::Util
attr_accessor :base_path, :assigns, :template_extension, :first_render
attr_accessor :base_path, :assigns, :template_extension
attr_accessor :controller
attr_accessor :_first_render, :_last_render
attr_writer :template_format
attr_accessor :current_render_extension
attr_accessor :output_buffer
# Specify trim mode for the ERB compiler. Defaults to '-'.
# See ERb documentation for suitable values.
@@erb_trim_mode = '-'
cattr_accessor :erb_trim_mode
class << self
delegate :erb_trim_mode=, :to => 'ActionView::TemplateHandlers::ERB'
end
# Specify whether file modification times should be checked to see if a template needs recompilation
# Specify whether templates should be cached. Otherwise the file we be read everytime it is accessed.
@@cache_template_loading = false
cattr_accessor :cache_template_loading
@@ -180,6 +185,10 @@ module ActionView #:nodoc:
@@debug_rjs = false
cattr_accessor :debug_rjs
# A warning will be displayed whenever an action results in a cache miss on your view paths.
@@warn_cache_misses = false
cattr_accessor :warn_cache_misses
attr_internal :request
delegate :request_forgery_protection_token, :template, :params, :session, :cookies, :response, :headers,
@@ -190,19 +199,10 @@ module ActionView #:nodoc:
end
include CompiledTemplates
# Maps inline templates to their method names
cattr_accessor :method_names
@@method_names = {}
# Map method names to the names passed in local assigns so far
@@template_args = {}
# Cache public asset paths
cattr_reader :computed_public_paths
@@computed_public_paths = {}
class ObjectWrapper < Struct.new(:value) #:nodoc:
end
def self.helper_modules #:nodoc:
helpers = []
Dir.entries(File.expand_path("#{File.dirname(__FILE__)}/helpers")).sort.each do |file|
@@ -216,6 +216,10 @@ module ActionView #:nodoc:
return helpers
end
def self.process_view_paths(value)
ActionView::PathSet.new(Array(value))
end
def initialize(view_paths = [], assigns_for_first_render = {}, controller = nil)#:nodoc:
@assigns = assigns_for_first_render
@assigns_added = nil
@@ -226,39 +230,20 @@ module ActionView #:nodoc:
attr_reader :view_paths
def view_paths=(paths)
@view_paths = ViewLoadPaths.new(Array(paths))
end
# Renders the template present at <tt>template_path</tt>. If <tt>use_full_path</tt> is set to true,
# it's relative to the view_paths array, otherwise it's absolute. The hash in <tt>local_assigns</tt>
# is made available as local variables.
def render_file(template_path, use_full_path = true, local_assigns = {}) #:nodoc:
if defined?(ActionMailer) && defined?(ActionMailer::Base) && controller.is_a?(ActionMailer::Base) && !template_path.include?("/")
raise ActionViewError, <<-END_ERROR
Due to changes in ActionMailer, you need to provide the mailer_name along with the template name.
render "user_mailer/signup"
render :file => "user_mailer/signup"
If you are rendering a subtemplate, you must now use controller-like partial syntax:
render :partial => 'signup' # no mailer_name necessary
END_ERROR
end
Template.new(self, template_path, use_full_path, local_assigns).render_template
@view_paths = self.class.process_view_paths(paths)
end
# Renders the template present at <tt>template_path</tt> (relative to the view_paths array).
# The hash in <tt>local_assigns</tt> is made available as local variables.
def render(options = {}, local_assigns = {}, &block) #:nodoc:
local_assigns ||= {}
if options.is_a?(String)
render_file(options, true, local_assigns)
render_file(options, nil, local_assigns)
elsif options == :update
update_page(&block)
elsif options.is_a?(Hash)
use_full_path = options[:use_full_path]
options = options.reverse_merge(:locals => {}, :use_full_path => true)
options = options.reverse_merge(:locals => {})
if partial_layout = options.delete(:layout)
if block_given?
@@ -271,59 +256,112 @@ If you are rendering a subtemplate, you must now use controller-like partial syn
end
end
elsif options[:file]
render_file(options[:file], use_full_path || false, options[:locals])
render_file(options[:file], nil, options[:locals])
elsif options[:partial] && options[:collection]
render_partial_collection(options[:partial], options[:collection], options[:spacer_template], options[:locals])
render_partial_collection(options[:partial], options[:collection], options[:spacer_template], options[:locals], options[:as])
elsif options[:partial]
render_partial(options[:partial], ActionView::Base::ObjectWrapper.new(options[:object]), options[:locals])
render_partial(options[:partial], options[:object], options[:locals])
elsif options[:inline]
template = InlineTemplate.new(self, options[:inline], options[:locals], options[:type])
render_template(template)
render_inline(options[:inline], options[:locals], options[:type])
end
end
end
def render_template(template) #:nodoc:
template.render_template
end
# Returns true is the file may be rendered implicitly.
def file_public?(template_path)#:nodoc:
template_path.split('/').last[0,1] != '_'
end
# Returns a symbolized version of the <tt>:format</tt> parameter of the request,
# or <tt>:html</tt> by default.
#
# EXCEPTION: If the <tt>:format</tt> parameter is not set, the Accept header will be examined for
# whether it contains the JavaScript mime type as its first priority. If that's the case,
# it will be used. This ensures that Ajax applications can use the same URL to support both
# JavaScript and non-JavaScript users.
# The format to be used when choosing between multiple templates with
# the same name but differing formats. See +Request#template_format+
# for more details.
def template_format
return @template_format if @template_format
if controller && controller.respond_to?(:request)
parameter_format = controller.request.parameters[:format]
accept_format = controller.request.accepts.first
case
when parameter_format.blank? && accept_format != :js
@template_format = :html
when parameter_format.blank? && accept_format == :js
@template_format = :js
else
@template_format = parameter_format.to_sym
end
@template_format = controller.request.template_format
else
@template_format = :html
end
end
def file_exists?(template_path)
view_paths.template_exists?(template_file_from_name(template_path))
pick_template(template_path) ? true : false
rescue MissingTemplate
false
end
# Gets the extension for an existing template with the given template_path.
# Returns the format with the extension if that template exists.
#
# pick_template('users/show')
# # => 'users/show.html.erb'
#
# pick_template('users/legacy')
# # => 'users/legacy.rhtml'
#
def pick_template(template_path)
path = template_path.sub(/^\//, '')
if m = path.match(/(.*)\.(\w+)$/)
template_file_name, template_file_extension = m[1], m[2]
else
template_file_name = path
end
# OPTIMIZE: Checks to lookup template in view path
if template = self.view_paths["#{template_file_name}.#{template_format}"]
template
elsif template = self.view_paths[template_file_name]
template
elsif _first_render && template = self.view_paths["#{template_file_name}.#{_first_render.format_and_extension}"]
template
elsif template_format == :js && template = self.view_paths["#{template_file_name}.html"]
@template_format = :html
template
else
template = Template.new(template_path, view_paths)
if self.class.warn_cache_misses && logger = ActionController::Base.logger
logger.debug "[PERFORMANCE] Rendering a template that was " +
"not found in view path. Templates outside the view path are " +
"not cached and result in expensive disk operations. Move this " +
"file into #{view_paths.join(':')} or add the folder to your " +
"view path list"
end
template
end
end
private
# Renders the template present at <tt>template_path</tt>. The hash in <tt>local_assigns</tt>
# is made available as local variables.
def render_file(template_path, use_full_path = nil, local_assigns = {}) #:nodoc:
unless use_full_path == nil
ActiveSupport::Deprecation.warn("use_full_path option has been deprecated and has no affect.", caller)
end
if defined?(ActionMailer) && defined?(ActionMailer::Base) && controller.is_a?(ActionMailer::Base) && !template_path.include?("/")
raise ActionViewError, <<-END_ERROR
Due to changes in ActionMailer, you need to provide the mailer_name along with the template name.
render "user_mailer/signup"
render :file => "user_mailer/signup"
If you are rendering a subtemplate, you must now use controller-like partial syntax:
render :partial => 'signup' # no mailer_name necessary
END_ERROR
end
template = pick_template(template_path)
template.render_template(self, local_assigns)
end
def render_inline(text, local_assigns = {}, type = nil)
InlineTemplate.new(text, type).render(self, local_assigns)
end
def wrap_content_for_layout(content)
original_content_for_layout, @content_for_layout = @content_for_layout, content
yield
@@ -344,42 +382,10 @@ If you are rendering a subtemplate, you must now use controller-like partial syn
@assigns.each { |key, value| instance_variable_set("@#{key}", value) }
end
def execute(template)
send(template.method, template.locals) do |*names|
def execute(template, local_assigns = {})
send(template.method(local_assigns), local_assigns) do |*names|
instance_variable_get "@content_for_#{names.first || 'layout'}"
end
end
def template_file_from_name(template_name)
template_name = TemplateFile.from_path(template_name)
pick_template_extension(template_name) unless template_name.extension
end
# Gets the extension for an existing template with the given template_path.
# Returns the format with the extension if that template exists.
#
# pick_template_extension('users/show')
# # => 'html.erb'
#
# pick_template_extension('users/legacy')
# # => "rhtml"
#
def pick_template_extension(file)
if f = self.view_paths.find_template_file_for_path(file.dup_with_extension(template_format)) || file_from_first_render(file)
f
elsif template_format == :js && f = self.view_paths.find_template_file_for_path(file.dup_with_extension(:html))
@template_format = :html
f
else
nil
end
end
# Determine the template extension from the <tt>@first_render</tt> filename
def file_from_first_render(file)
if extension = File.basename(@first_render.to_s)[/^[^.]+\.(.+)$/, 1]
file.dup_with_extension(extension)
end
end
end
end

View File

@@ -209,6 +209,10 @@ module ActionView
# Note that the default javascript files will be included first. So Prototype and Scriptaculous are available to
# all subsequently included files.
#
# If you want Rails to search in all the subdirectories under javascripts, you should explicitly set <tt>:recursive</tt>:
#
# javascript_include_tag :all, :recursive => true
#
# == Caching multiple javascripts into one
#
# You can also cache multiple javascripts into one file, which requires less HTTP connections to download and can better be
@@ -235,18 +239,23 @@ module ActionView
#
# javascript_include_tag "prototype", "cart", "checkout", :cache => "shop" # when ActionController::Base.perform_caching is true =>
# <script type="text/javascript" src="/javascripts/shop.js"></script>
#
# The <tt>:recursive</tt> option is also available for caching:
#
# javascript_include_tag :all, :cache => true, :recursive => true
def javascript_include_tag(*sources)
options = sources.extract_options!.stringify_keys
cache = options.delete("cache")
recursive = options.delete("recursive")
if ActionController::Base.perform_caching && cache
joined_javascript_name = (cache == true ? "all" : cache) + ".js"
joined_javascript_path = File.join(JAVASCRIPTS_DIR, joined_javascript_name)
write_asset_file_contents(joined_javascript_path, compute_javascript_paths(sources))
write_asset_file_contents(joined_javascript_path, compute_javascript_paths(sources, recursive)) unless File.exists?(joined_javascript_path)
javascript_src_tag(joined_javascript_name, options)
else
expand_javascript_sources(sources).collect { |source| javascript_src_tag(source, options) }.join("\n")
expand_javascript_sources(sources, recursive).collect { |source| javascript_src_tag(source, options) }.join("\n")
end
end
@@ -332,13 +341,17 @@ module ActionView
# <link href="/stylesheets/random.styles" media="screen" rel="stylesheet" type="text/css" />
# <link href="/css/stylish.css" media="screen" rel="stylesheet" type="text/css" />
#
# You can also include all styles in the stylesheet directory using <tt>:all</tt> as the source:
# You can also include all styles in the stylesheets directory using <tt>:all</tt> as the source:
#
# stylesheet_link_tag :all # =>
# <link href="/stylesheets/style1.css" media="screen" rel="stylesheet" type="text/css" />
# <link href="/stylesheets/styleB.css" media="screen" rel="stylesheet" type="text/css" />
# <link href="/stylesheets/styleX2.css" media="screen" rel="stylesheet" type="text/css" />
#
# If you want Rails to search in all the subdirectories under stylesheets, you should explicitly set <tt>:recursive</tt>:
#
# stylesheet_link_tag :all, :recursive => true
#
# == Caching multiple stylesheets into one
#
# You can also cache multiple stylesheets into one file, which requires less HTTP connections and can better be
@@ -362,18 +375,23 @@ module ActionView
#
# stylesheet_link_tag "shop", "cart", "checkout", :cache => "payment" # when ActionController::Base.perform_caching is true =>
# <link href="/stylesheets/payment.css" media="screen" rel="stylesheet" type="text/css" />
#
# The <tt>:recursive</tt> option is also available for caching:
#
# stylesheet_link_tag :all, :cache => true, :recursive => true
def stylesheet_link_tag(*sources)
options = sources.extract_options!.stringify_keys
cache = options.delete("cache")
recursive = options.delete("recursive")
if ActionController::Base.perform_caching && cache
joined_stylesheet_name = (cache == true ? "all" : cache) + ".css"
joined_stylesheet_path = File.join(STYLESHEETS_DIR, joined_stylesheet_name)
write_asset_file_contents(joined_stylesheet_path, compute_stylesheet_paths(sources))
write_asset_file_contents(joined_stylesheet_path, compute_stylesheet_paths(sources, recursive)) unless File.exists?(joined_stylesheet_path)
stylesheet_tag(joined_stylesheet_name, options)
else
expand_stylesheet_sources(sources).collect { |source| stylesheet_tag(source, options) }.join("\n")
expand_stylesheet_sources(sources, recursive).collect { |source| stylesheet_tag(source, options) }.join("\n")
end
end
@@ -556,18 +574,19 @@ module ActionView
tag("link", { "rel" => "stylesheet", "type" => Mime::CSS, "media" => "screen", "href" => html_escape(path_to_stylesheet(source)) }.merge(options), false, false)
end
def compute_javascript_paths(sources)
expand_javascript_sources(sources).collect { |source| compute_public_path(source, 'javascripts', 'js', false) }
def compute_javascript_paths(*args)
expand_javascript_sources(*args).collect { |source| compute_public_path(source, 'javascripts', 'js', false) }
end
def compute_stylesheet_paths(sources)
expand_stylesheet_sources(sources).collect { |source| compute_public_path(source, 'stylesheets', 'css', false) }
def compute_stylesheet_paths(*args)
expand_stylesheet_sources(*args).collect { |source| compute_public_path(source, 'stylesheets', 'css', false) }
end
def expand_javascript_sources(sources)
def expand_javascript_sources(sources, recursive = false)
if sources.include?(:all)
all_javascript_files = Dir[File.join(JAVASCRIPTS_DIR, '*.js')].collect { |file| File.basename(file).gsub(/\.\w+$/, '') }.sort
@@all_javascript_sources ||= ((determine_source(:defaults, @@javascript_expansions).dup & all_javascript_files) + all_javascript_files).uniq
all_javascript_files = collect_asset_files(JAVASCRIPTS_DIR, ('**' if recursive), '*.js')
@@all_javascript_sources ||= {}
@@all_javascript_sources[recursive] ||= ((determine_source(:defaults, @@javascript_expansions).dup & all_javascript_files) + all_javascript_files).uniq
else
expanded_sources = sources.collect do |source|
determine_source(source, @@javascript_expansions)
@@ -577,9 +596,10 @@ module ActionView
end
end
def expand_stylesheet_sources(sources)
def expand_stylesheet_sources(sources, recursive)
if sources.first == :all
@@all_stylesheet_sources ||= Dir[File.join(STYLESHEETS_DIR, '*.css')].collect { |file| File.basename(file).gsub(/\.\w+$/, '') }.sort
@@all_stylesheet_sources ||= {}
@@all_stylesheet_sources[recursive] ||= collect_asset_files(STYLESHEETS_DIR, ('**' if recursive), '*.css')
else
sources.collect do |source|
determine_source(source, @@stylesheet_expansions)
@@ -601,10 +621,16 @@ module ActionView
end
def write_asset_file_contents(joined_asset_path, asset_paths)
unless file_exist?(joined_asset_path)
FileUtils.mkdir_p(File.dirname(joined_asset_path))
File.open(joined_asset_path, "w+") { |cache| cache.write(join_asset_file_contents(asset_paths)) }
end
FileUtils.mkdir_p(File.dirname(joined_asset_path))
File.open(joined_asset_path, "w+") { |cache| cache.write(join_asset_file_contents(asset_paths)) }
end
def collect_asset_files(*path)
dir = path.first
Dir[File.join(*path.compact)].collect do |file|
file[-(file.size - dir.size - 1)..-1].sub(/\.\w+$/, '')
end.sort
end
end
end

View File

@@ -32,8 +32,7 @@ module ActionView
# <i>Topics listed alphabetically</i>
# <% end %>
def cache(name = {}, options = nil, &block)
handler = Template.handler_class_for_extension(current_render_extension.to_sym)
handler.new(@controller).cache_fragment(block, name, options)
@controller.fragment_for(output_buffer, name, options, &block)
end
end
end

View File

@@ -31,10 +31,12 @@ module ActionView
# </body></html>
#
def capture(*args, &block)
if output_buffer
# Return captured buffer in erb.
if block_called_from_erb?(block)
with_output_buffer { block.call(*args) }
else
block.call(*args)
# Return block result otherwise, but protect buffer also.
with_output_buffer { return block.call(*args) }
end
end
@@ -117,6 +119,7 @@ module ActionView
ivar = "@content_for_#{name}"
content = capture(&block) if block_given?
instance_variable_set(ivar, "#{instance_variable_get(ivar)}#{content}")
nil
end
private

View File

@@ -158,13 +158,16 @@ module ActionView
# Note: If the day is not included as an option but the month is, the day will be set to the 1st to ensure that all month
# choices are valid.
def date_select(object_name, method, options = {}, html_options = {})
InstanceTag.new(object_name, method, self, nil, options.delete(:object)).to_date_select_tag(options, html_options)
InstanceTag.new(object_name, method, self, options.delete(:object)).to_date_select_tag(options, html_options)
end
# Returns a set of select tags (one for hour, minute and optionally second) pre-selected for accessing a specified
# time-based attribute (identified by +method+) on an object assigned to the template (identified by +object+).
# You can include the seconds with <tt>:include_seconds</tt>.
#
#
# This method will also generate 3 input hidden tags, for the actual year, month and day unless the option
# <tt>:ignore_date</tt> is set to +true+.
#
# If anything is passed in the html_options hash it will be applied to every select tag in the set.
#
# ==== Examples
@@ -193,7 +196,7 @@ module ActionView
# Note: If the day is not included as an option but the month is, the day will be set to the 1st to ensure that all month
# choices are valid.
def time_select(object_name, method, options = {}, html_options = {})
InstanceTag.new(object_name, method, self, nil, options.delete(:object)).to_time_select_tag(options, html_options)
InstanceTag.new(object_name, method, self, options.delete(:object)).to_time_select_tag(options, html_options)
end
# Returns a set of select tags (one for year, month, day, hour, and minute) pre-selected for accessing a specified datetime-based
@@ -219,7 +222,7 @@ module ActionView
#
# The selects are prepared for multi-parameter assignment to an Active Record object.
def datetime_select(object_name, method, options = {}, html_options = {})
InstanceTag.new(object_name, method, self, nil, options.delete(:object)).to_datetime_select_tag(options, html_options)
InstanceTag.new(object_name, method, self, options.delete(:object)).to_datetime_select_tag(options, html_options)
end
# Returns a set of html select-tags (one for year, month, day, hour, and minute) pre-selected with the +datetime+.
@@ -558,23 +561,32 @@ module ActionView
# select_year(2006, :start_year => 2000, :end_year => 2010)
#
def select_year(date, options = {}, html_options = {})
val = date ? (date.kind_of?(Fixnum) ? date : date.year) : ''
if options[:use_hidden]
hidden_html(options[:field_name] || 'year', val, options)
if !date || date == 0
value = ''
middle_year = Date.today.year
elsif date.kind_of?(Fixnum)
value = middle_year = date
else
year_options = []
y = date ? (date.kind_of?(Fixnum) ? (y = (date == 0) ? Date.today.year : date) : date.year) : Date.today.year
value = middle_year = date.year
end
if options[:use_hidden]
hidden_html(options[:field_name] || 'year', value, options)
else
year_options = ''
start_year = options[:start_year] || middle_year - 5
end_year = options[:end_year] || middle_year + 5
step_val = start_year < end_year ? 1 : -1
start_year, end_year = (options[:start_year] || y-5), (options[:end_year] || y+5)
step_val = start_year < end_year ? 1 : -1
start_year.step(end_year, step_val) do |year|
year_options << ((val == year) ?
content_tag(:option, year, :value => year, :selected => "selected") :
content_tag(:option, year, :value => year)
)
if value == year
year_options << content_tag(:option, year, :value => year, :selected => "selected")
else
year_options << content_tag(:option, year, :value => year)
end
year_options << "\n"
end
select_html(options[:field_name] || 'year', year_options.join, options, html_options)
select_html(options[:field_name] || 'year', year_options, options, html_options)
end
end
@@ -659,7 +671,7 @@ module ActionView
order.reverse.each do |param|
# Send hidden fields for discarded elements once output has started
# This ensures AR can reconstruct valid dates using ParseDate
next if discard[param] && date_or_time_select.empty?
next if discard[param] && (date_or_time_select.empty? || options[:ignore_date])
date_or_time_select.insert(0, self.send("select_#{param}", datetime, options_with_prefix(position[param], options.merge(:use_hidden => discard[param])), html_options))
date_or_time_select.insert(0,
@@ -708,15 +720,15 @@ module ActionView
class FormBuilder
def date_select(method, options = {}, html_options = {})
@template.date_select(@object_name, method, options.merge(:object => @object))
@template.date_select(@object_name, method, options.merge(:object => @object), html_options)
end
def time_select(method, options = {}, html_options = {})
@template.time_select(@object_name, method, options.merge(:object => @object))
@template.time_select(@object_name, method, options.merge(:object => @object), html_options)
end
def datetime_select(method, options = {}, html_options = {})
@template.datetime_select(@object_name, method, options.merge(:object => @object))
@template.datetime_select(@object_name, method, options.merge(:object => @object), html_options)
end
end
end

View File

@@ -333,7 +333,7 @@ module ActionView
# # => <label for="post_title" class="title_label">A short title</label>
#
def label(object_name, method, text = nil, options = {})
InstanceTag.new(object_name, method, self, nil, options.delete(:object)).to_label_tag(text, options)
InstanceTag.new(object_name, method, self, options.delete(:object)).to_label_tag(text, options)
end
# Returns an input tag of the "text" type tailored for accessing a specified attribute (identified by +method+) on an object
@@ -355,7 +355,7 @@ module ActionView
# # => <input type="text" id="snippet_code" name="snippet[code]" size="20" value="#{@snippet.code}" class="code_input" />
#
def text_field(object_name, method, options = {})
InstanceTag.new(object_name, method, self, nil, options.delete(:object)).to_input_field_tag("text", options)
InstanceTag.new(object_name, method, self, options.delete(:object)).to_input_field_tag("text", options)
end
# Returns an input tag of the "password" type tailored for accessing a specified attribute (identified by +method+) on an object
@@ -377,7 +377,7 @@ module ActionView
# # => <input type="text" id="account_pin" name="account[pin]" size="20" value="#{@account.pin}" class="form_input" />
#
def password_field(object_name, method, options = {})
InstanceTag.new(object_name, method, self, nil, options.delete(:object)).to_input_field_tag("password", options)
InstanceTag.new(object_name, method, self, options.delete(:object)).to_input_field_tag("password", options)
end
# Returns a hidden input tag tailored for accessing a specified attribute (identified by +method+) on an object
@@ -395,7 +395,7 @@ module ActionView
# hidden_field(:user, :token)
# # => <input type="hidden" id="user_token" name="user[token]" value="#{@user.token}" />
def hidden_field(object_name, method, options = {})
InstanceTag.new(object_name, method, self, nil, options.delete(:object)).to_input_field_tag("hidden", options)
InstanceTag.new(object_name, method, self, options.delete(:object)).to_input_field_tag("hidden", options)
end
# Returns an file upload input tag tailored for accessing a specified attribute (identified by +method+) on an object
@@ -414,7 +414,7 @@ module ActionView
# # => <input type="file" id="attachment_file" name="attachment[file]" class="file_input" />
#
def file_field(object_name, method, options = {})
InstanceTag.new(object_name, method, self, nil, options.delete(:object)).to_input_field_tag("file", options)
InstanceTag.new(object_name, method, self, options.delete(:object)).to_input_field_tag("file", options)
end
# Returns a textarea opening and closing tag set tailored for accessing a specified attribute (identified by +method+)
@@ -442,7 +442,7 @@ module ActionView
# # #{@entry.body}
# # </textarea>
def text_area(object_name, method, options = {})
InstanceTag.new(object_name, method, self, nil, options.delete(:object)).to_text_area_tag(options)
InstanceTag.new(object_name, method, self, options.delete(:object)).to_text_area_tag(options)
end
# Returns a checkbox tag tailored for accessing a specified attribute (identified by +method+) on an object
@@ -468,7 +468,7 @@ module ActionView
# # <input name="eula[accepted]" type="hidden" value="no" />
#
def check_box(object_name, method, options = {}, checked_value = "1", unchecked_value = "0")
InstanceTag.new(object_name, method, self, nil, options.delete(:object)).to_check_box_tag(options, checked_value, unchecked_value)
InstanceTag.new(object_name, method, self, options.delete(:object)).to_check_box_tag(options, checked_value, unchecked_value)
end
# Returns a radio button tag for accessing a specified attribute (identified by +method+) on an object
@@ -488,7 +488,7 @@ module ActionView
# # => <input type="radio" id="user_receive_newsletter_yes" name="user[receive_newsletter]" value="yes" />
# # <input type="radio" id="user_receive_newsletter_no" name="user[receive_newsletter]" value="no" checked="checked" />
def radio_button(object_name, method, tag_value, options = {})
InstanceTag.new(object_name, method, self, nil, options.delete(:object)).to_radio_button_tag(tag_value, options)
InstanceTag.new(object_name, method, self, options.delete(:object)).to_radio_button_tag(tag_value, options)
end
end
@@ -501,9 +501,9 @@ module ActionView
DEFAULT_RADIO_OPTIONS = { }.freeze unless const_defined?(:DEFAULT_RADIO_OPTIONS)
DEFAULT_TEXT_AREA_OPTIONS = { "cols" => 40, "rows" => 20 }.freeze unless const_defined?(:DEFAULT_TEXT_AREA_OPTIONS)
def initialize(object_name, method_name, template_object, local_binding = nil, object = nil)
def initialize(object_name, method_name, template_object, object = nil)
@object_name, @method_name = object_name.to_s.dup, method_name.to_s.dup
@template_object, @local_binding = template_object, local_binding
@template_object= template_object
@object = object
if @object_name.sub!(/\[\]$/,"")
if object ||= @template_object.instance_variable_get("@#{Regexp.last_match.pre_match}") and object.respond_to?(:to_param)
@@ -601,7 +601,11 @@ module ActionView
end
def object
@object || (@template_object.instance_variable_get("@#{@object_name}") rescue nil)
@object || @template_object.instance_variable_get("@#{@object_name}")
rescue NameError
# As @object_name may contain the nested syntax (item[subobject]) we
# need to fallback to nil.
nil
end
def value(object)

View File

@@ -96,7 +96,7 @@ module ActionView
# By default, <tt>post.person_id</tt> is the selected option. Specify <tt>:selected => value</tt> to use a different selection
# or <tt>:selected => nil</tt> to leave all options unselected.
def select(object, method, choices, options = {}, html_options = {})
InstanceTag.new(object, method, self, nil, options.delete(:object)).to_select_tag(choices, options, html_options)
InstanceTag.new(object, method, self, options.delete(:object)).to_select_tag(choices, options, html_options)
end
# Returns <tt><select></tt> and <tt><option></tt> tags for the collection of existing return values of
@@ -130,12 +130,12 @@ module ActionView
# <option value="3">M. Clark</option>
# </select>
def collection_select(object, method, collection, value_method, text_method, options = {}, html_options = {})
InstanceTag.new(object, method, self, nil, options.delete(:object)).to_collection_select_tag(collection, value_method, text_method, options, html_options)
InstanceTag.new(object, method, self, options.delete(:object)).to_collection_select_tag(collection, value_method, text_method, options, html_options)
end
# Return select and option tags for the given object and method, using country_options_for_select to generate the list of option tags.
def country_select(object, method, priority_countries = nil, options = {}, html_options = {})
InstanceTag.new(object, method, self, nil, options.delete(:object)).to_country_select_tag(priority_countries, options, html_options)
InstanceTag.new(object, method, self, options.delete(:object)).to_country_select_tag(priority_countries, options, html_options)
end
# Return select and option tags for the given object and method, using
@@ -150,7 +150,8 @@ module ActionView
# You can also supply an array of TimeZone objects
# as +priority_zones+, so that they will be listed above the rest of the
# (long) list. (You can use TimeZone.us_zones as a convenience for
# obtaining a list of the US time zones.)
# obtaining a list of the US time zones, or a Regexp to select the zones
# of your choice)
#
# Finally, this method supports a <tt>:default</tt> option, which selects
# a default TimeZone if the object's time zone is +nil+.
@@ -164,9 +165,11 @@ module ActionView
#
# time_zone_select( "user", 'time_zone', [ TimeZone['Alaska'], TimeZone['Hawaii'] ])
#
# time_zone_select( "user", 'time_zone', /Australia/)
#
# time_zone_select( "user", "time_zone", TZInfo::Timezone.all.sort, :model => TZInfo::Timezone)
def time_zone_select(object, method, priority_zones = nil, options = {}, html_options = {})
InstanceTag.new(object, method, self, nil, options.delete(:object)).to_time_zone_select_tag(priority_zones, options, html_options)
InstanceTag.new(object, method, self, options.delete(:object)).to_time_zone_select_tag(priority_zones, options, html_options)
end
# Accepts a container (hash, array, enumerable, your type) and returns a string of option tags. Given a container
@@ -292,7 +295,8 @@ module ActionView
# selected option tag. You can also supply an array of TimeZone objects
# as +priority_zones+, so that they will be listed above the rest of the
# (long) list. (You can use TimeZone.us_zones as a convenience for
# obtaining a list of the US time zones.)
# obtaining a list of the US time zones, or a Regexp to select the zones
# of your choice)
#
# The +selected+ parameter must be either +nil+, or a string that names
# a TimeZone.
@@ -311,6 +315,9 @@ module ActionView
convert_zones = lambda { |list| list.map { |z| [ z.to_s, z.name ] } }
if priority_zones
if priority_zones.is_a?(Regexp)
priority_zones = model.all.find_all {|z| z =~ priority_zones}
end
zone_options += options_for_select(convert_zones[priority_zones], selected)
zone_options += "<option value=\"\" disabled=\"disabled\">-------------</option>\n"
@@ -438,19 +445,19 @@ module ActionView
class FormBuilder
def select(method, choices, options = {}, html_options = {})
@template.select(@object_name, method, choices, options.merge(:object => @object), html_options)
@template.select(@object_name, method, choices, objectify_options(options), @default_options.merge(html_options))
end
def collection_select(method, collection, value_method, text_method, options = {}, html_options = {})
@template.collection_select(@object_name, method, collection, value_method, text_method, options.merge(:object => @object), html_options)
@template.collection_select(@object_name, method, collection, value_method, text_method, objectify_options(options), @default_options.merge(html_options))
end
def country_select(method, priority_countries = nil, options = {}, html_options = {})
@template.country_select(@object_name, method, priority_countries, options.merge(:object => @object), html_options)
@template.country_select(@object_name, method, priority_countries, objectify_options(options), @default_options.merge(html_options))
end
def time_zone_select(method, priority_zones = nil, options = {}, html_options = {})
@template.time_zone_select(@object_name, method, priority_zones, options.merge(:object => @object), html_options)
@template.time_zone_select(@object_name, method, priority_zones, objectify_options(options), @default_options.merge(html_options))
end
end
end

View File

@@ -6,7 +6,7 @@ module ActionView
# Provides a number of methods for creating form tags that doesn't rely on an Active Record object assigned to the template like
# FormHelper does. Instead, you provide the names and values manually.
#
# NOTE: The HTML options <tt>disabled</tt>, <tt>readonly</tt>, and <tt>multiple</tt> can all be treated as booleans. So specifying
# NOTE: The HTML options <tt>disabled</tt>, <tt>readonly</tt>, and <tt>multiple</tt> can all be treated as booleans. So specifying
# <tt>:disabled => true</tt> will give <tt>disabled="disabled"</tt>.
module FormTagHelper
# Starts a form tag that points the action to an url configured with <tt>url_for_options</tt> just like
@@ -20,15 +20,15 @@ module ActionView
# * A list of parameters to feed to the URL the form will be posted to.
#
# ==== Examples
# form_tag('/posts')
# form_tag('/posts')
# # => <form action="/posts" method="post">
#
# form_tag('/posts/1', :method => :put)
# form_tag('/posts/1', :method => :put)
# # => <form action="/posts/1" method="put">
#
# form_tag('/upload', :multipart => true)
# form_tag('/upload', :multipart => true)
# # => <form action="/upload" method="post" enctype="multipart/form-data">
#
#
# <% form_tag '/posts' do -%>
# <div><%= submit_tag 'Save' %></div>
# <% end -%>
@@ -88,7 +88,7 @@ module ActionView
# * <tt>:size</tt> - The number of visible characters that will fit in the input.
# * <tt>:maxlength</tt> - The maximum number of characters that the browser will allow the user to enter.
# * Any other key creates standard HTML attributes for the tag.
#
#
# ==== Examples
# text_field_tag 'name'
# # => <input id="name" name="name" type="text" />
@@ -146,13 +146,13 @@ module ActionView
# # => <input id="token" name="token" type="hidden" value="VUBJKB23UIVI1UU1VOBVI@" />
#
# hidden_field_tag 'collected_input', '', :onchange => "alert('Input collected!')"
# # => <input id="collected_input" name="collected_input" onchange="alert('Input collected!')"
# # => <input id="collected_input" name="collected_input" onchange="alert('Input collected!')"
# # type="hidden" value="" />
def hidden_field_tag(name, value = nil, options = {})
text_field_tag(name, value, options.stringify_keys.update("type" => "hidden"))
end
# Creates a file upload field. If you are using file uploads then you will also need
# Creates a file upload field. If you are using file uploads then you will also need
# to set the multipart option for the form tag:
#
# <%= form_tag { :action => "post" }, { :multipart => true } %>
@@ -160,7 +160,7 @@ module ActionView
# <%= submit_tag %>
# <%= end_form_tag %>
#
# The specified URL will then be passed a File object containing the selected file, or if the field
# The specified URL will then be passed a File object containing the selected file, or if the field
# was left blank, a StringIO object.
#
# ==== Options
@@ -181,7 +181,7 @@ module ActionView
# # => <input id="resume" name="resume" type="file" value="~/resume.doc" />
#
# file_field_tag 'user_pic', :accept => 'image/png,image/gif,image/jpeg'
# # => <input accept="image/png,image/gif,image/jpeg" id="user_pic" name="user_pic" type="file" />
# # => <input accept="image/png,image/gif,image/jpeg" id="user_pic" name="user_pic" type="file" />
#
# file_field_tag 'file', :accept => 'text/html', :class => 'upload', :value => 'index.html'
# # => <input accept="text/html" class="upload" id="file" name="file" type="file" value="index.html" />
@@ -286,7 +286,7 @@ module ActionView
tag :input, html_options
end
# Creates a radio button; use groups of radio buttons named the same to allow users to
# Creates a radio button; use groups of radio buttons named the same to allow users to
# select from a group of options.
#
# ==== Options
@@ -313,14 +313,14 @@ module ActionView
tag :input, html_options
end
# Creates a submit button with the text <tt>value</tt> as the caption.
# Creates a submit button with the text <tt>value</tt> as the caption.
#
# ==== Options
# * <tt>:confirm => 'question?'</tt> - This will add a JavaScript confirm
# prompt with the question specified. If the user accepts, the form is
# processed normally, otherwise no action is taken.
# * <tt>:disabled</tt> - If true, the user will not be able to use this input.
# * <tt>:disable_with</tt> - Value of this parameter will be used as the value for a disabled version
# * <tt>:disable_with</tt> - Value of this parameter will be used as the value for a disabled version
# of the submit button when the form is submitted.
# * Any other key creates standard HTML options for the tag.
#
@@ -335,7 +335,7 @@ module ActionView
# # => <input disabled="disabled" name="commit" type="submit" value="Save edits" />
#
# submit_tag "Complete sale", :disable_with => "Please wait..."
# # => <input name="commit" onclick="this.disabled=true;this.value='Please wait...';this.form.submit();"
# # => <input name="commit" onclick="this.disabled=true;this.value='Please wait...';this.form.submit();"
# # type="submit" value="Complete sale" />
#
# submit_tag nil, :class => "form_submit"
@@ -346,27 +346,29 @@ module ActionView
# # name="commit" type="submit" value="Edit" />
def submit_tag(value = "Save changes", options = {})
options.stringify_keys!
if disable_with = options.delete("disable_with")
disable_with = "this.value='#{disable_with}'"
disable_with << ";#{options.delete('onclick')}" if options['onclick']
options["onclick"] = [
"this.setAttribute('originalValue', this.value)",
"this.disabled=true",
"this.value='#{disable_with}'",
"#{options["onclick"]}",
disable_with,
"result = (this.form.onsubmit ? (this.form.onsubmit() ? this.form.submit() : false) : this.form.submit())",
"if (result == false) { this.value = this.getAttribute('originalValue'); this.disabled = false }",
"return result;",
].join(";")
end
if confirm = options.delete("confirm")
options["onclick"] ||= ''
options["onclick"] += "return #{confirm_javascript_function(confirm)};"
end
tag :input, { "type" => "submit", "name" => "commit", "value" => value }.update(options.stringify_keys)
end
# Displays an image which when clicked will submit the form.
#
# <tt>source</tt> is passed to AssetTagHelper#image_path
@@ -412,7 +414,7 @@ module ActionView
concat(content)
concat("</fieldset>")
end
private
def html_options_for_form(url_for_options, options, *parameters_for_url)
returning options.stringify_keys do |html_options|
@@ -420,7 +422,7 @@ module ActionView
html_options["action"] = url_for(url_for_options, *parameters_for_url)
end
end
def extra_tags_for_form(html_options)
case method = html_options.delete("method").to_s
when /^get$/i # must be case-insentive, but can't use downcase as might be nil
@@ -434,12 +436,12 @@ module ActionView
content_tag(:div, tag(:input, :type => "hidden", :name => "_method", :value => method) + token_tag, :style => 'margin:0;padding:0')
end
end
def form_tag_html(html_options)
extra_tags = extra_tags_for_form(html_options)
tag(:form, html_options, true) + extra_tags
end
def form_tag_in_block(html_options, &block)
content = capture(&block)
concat(form_tag_html(html_options))

View File

@@ -4,10 +4,10 @@ require 'action_view/helpers/prototype_helper'
module ActionView
module Helpers
# Provides functionality for working with JavaScript in your views.
#
#
# == Ajax, controls and visual effects
#
# * For information on using Ajax, see
#
# * For information on using Ajax, see
# ActionView::Helpers::PrototypeHelper.
# * For information on using controls and visual effects, see
# ActionView::Helpers::ScriptaculousHelper.
@@ -20,22 +20,22 @@ module ActionView
# and ActionView::Helpers::ScriptaculousHelper), you must do one of the
# following:
#
# * Use <tt><%= javascript_include_tag :defaults %></tt> in the HEAD
# section of your page (recommended): This function will return
# * Use <tt><%= javascript_include_tag :defaults %></tt> in the HEAD
# section of your page (recommended): This function will return
# references to the JavaScript files created by the +rails+ command in
# your <tt>public/javascripts</tt> directory. Using it is recommended as
# the browser can then cache the libraries instead of fetching all the
# the browser can then cache the libraries instead of fetching all the
# functions anew on every request.
# * Use <tt><%= javascript_include_tag 'prototype' %></tt>: As above, but
# * Use <tt><%= javascript_include_tag 'prototype' %></tt>: As above, but
# will only include the Prototype core library, which means you are able
# to use all basic AJAX functionality. For the Scriptaculous-based
# JavaScript helpers, like visual effects, autocompletion, drag and drop
# to use all basic AJAX functionality. For the Scriptaculous-based
# JavaScript helpers, like visual effects, autocompletion, drag and drop
# and so on, you should use the method described above.
# * Use <tt><%= define_javascript_functions %></tt>: this will copy all the
# JavaScript support functions within a single script block. Not
# recommended.
#
# For documentation on +javascript_include_tag+ see
# For documentation on +javascript_include_tag+ see
# ActionView::Helpers::AssetTagHelper.
module JavaScriptHelper
unless const_defined? :JAVASCRIPT_PATH
@@ -43,13 +43,13 @@ module ActionView
end
include PrototypeHelper
# Returns a link that will trigger a JavaScript +function+ using the
# Returns a link that will trigger a JavaScript +function+ using the
# onclick handler and return false after the fact.
#
# The +function+ argument can be omitted in favor of an +update_page+
# block, which evaluates to a string when the template is rendered
# (instead of making an Ajax request first).
# (instead of making an Ajax request first).
#
# Examples:
# link_to_function "Greeting", "alert('Hello world!')"
@@ -70,36 +70,31 @@ module ActionView
# <a href="#" id="more_link" onclick="try {
# $(&quot;details&quot;).visualEffect(&quot;toggle_blind&quot;);
# $(&quot;more_link&quot;).update(&quot;Show me less&quot;);
# }
# catch (e) {
# alert('RJS error:\n\n' + e.toString());
# }
# catch (e) {
# alert('RJS error:\n\n' + e.toString());
# alert('$(\&quot;details\&quot;).visualEffect(\&quot;toggle_blind\&quot;);
# \n$(\&quot;more_link\&quot;).update(\&quot;Show me less\&quot;);');
# throw e
# throw e
# };
# return false;">Show me more</a>
#
def link_to_function(name, *args, &block)
html_options = args.extract_options!
function = args[0] || ''
html_options = args.extract_options!.symbolize_keys
html_options.symbolize_keys!
function = update_page(&block) if block_given?
content_tag(
"a", name,
html_options.merge({
:href => html_options[:href] || "#",
:onclick => (html_options[:onclick] ? "#{html_options[:onclick]}; " : "") + "#{function}; return false;"
})
)
function = block_given? ? update_page(&block) : args[0] || ''
onclick = "#{"#{html_options[:onclick]}; " if html_options[:onclick]}#{function}; return false;"
href = html_options[:href] || '#'
content_tag(:a, name, html_options.merge(:href => href, :onclick => onclick))
end
# Returns a button that'll trigger a JavaScript +function+ using the
# Returns a button that'll trigger a JavaScript +function+ using the
# onclick handler.
#
# The +function+ argument can be omitted in favor of an +update_page+
# block, which evaluates to a string when the template is rendered
# (instead of making an Ajax request first).
# (instead of making an Ajax request first).
#
# Examples:
# button_to_function "Greeting", "alert('Hello world!')"
@@ -111,45 +106,30 @@ module ActionView
# page[:details].visual_effect :toggle_slide
# end
def button_to_function(name, *args, &block)
html_options = args.extract_options!
function = args[0] || ''
html_options = args.extract_options!.symbolize_keys
html_options.symbolize_keys!
function = update_page(&block) if block_given?
tag(:input, html_options.merge({
:type => "button", :value => name,
:onclick => (html_options[:onclick] ? "#{html_options[:onclick]}; " : "") + "#{function};"
}))
function = block_given? ? update_page(&block) : args[0] || ''
onclick = "#{"#{html_options[:onclick]}; " if html_options[:onclick]}#{function};"
tag(:input, html_options.merge(:type => 'button', :value => name, :onclick => onclick))
end
# Includes the Action Pack JavaScript libraries inside a single <script>
# tag. The function first includes prototype.js and then its core extensions,
# (determined by filenames starting with "prototype").
# Afterwards, any additional scripts will be included in undefined order.
#
# Note: The recommended approach is to copy the contents of
# lib/action_view/helpers/javascripts/ into your application's
# public/javascripts/ directory, and use +javascript_include_tag+ to
# create remote <script> links.
def define_javascript_functions
javascript = "<script type=\"#{Mime::JS}\">"
# load prototype.js and its extensions first
prototype_libs = Dir.glob(File.join(JAVASCRIPT_PATH, 'prototype*')).sort.reverse
prototype_libs.each do |filename|
javascript << "\n" << IO.read(filename)
end
# load other libraries
(Dir.glob(File.join(JAVASCRIPT_PATH, '*')) - prototype_libs).each do |filename|
javascript << "\n" << IO.read(filename)
end
javascript << '</script>'
end
JS_ESCAPE_MAP = {
'\\' => '\\\\',
'</' => '<\/',
"\r\n" => '\n',
"\n" => '\n',
"\r" => '\n',
'"' => '\\"',
"'" => "\\'" }
# Escape carrier returns and single and double quotes for JavaScript segments.
def escape_javascript(javascript)
(javascript || '').gsub('\\','\0\0').gsub('</','<\/').gsub(/\r\n|\n|\r/, "\\n").gsub(/["']/) { |m| "\\#{m}" }
if javascript
javascript.gsub(/(\\|<\/|\r\n|[\n\r"'])/) { JS_ESCAPE_MAP[$1] }
else
''
end
end
# Returns a JavaScript tag with the +content+ inside. Example:
@@ -163,7 +143,7 @@ module ActionView
# </script>
#
# +html_options+ may be a hash of attributes for the <script> tag. Example:
# javascript_tag "alert('All is good')", :defer => 'defer'
# javascript_tag "alert('All is good')", :defer => 'defer'
# # => <script defer="defer" type="text/javascript">alert('All is good')</script>
#
# Instead of passing the content as an argument, you can also use a block
@@ -180,30 +160,35 @@ module ActionView
content_or_options_with_block
end
tag = content_tag("script", javascript_cdata_section(content), html_options.merge(:type => Mime::JS))
tag = content_tag(:script, javascript_cdata_section(content), html_options.merge(:type => Mime::JS))
block_given? ? concat(tag) : tag
if block_called_from_erb?(block)
concat(tag)
else
tag
end
end
def javascript_cdata_section(content) #:nodoc:
"\n//#{cdata_section("\n#{content}\n//")}\n"
end
protected
def options_for_javascript(options)
'{' + options.map {|k, v| "#{k}:#{v}"}.sort.join(', ') + '}'
if options.empty?
'{}'
else
"{#{options.keys.map { |k| "#{k}:#{options[k]}" }.sort.join(', ')}}"
end
end
def array_or_string_for_javascript(option)
js_option = if option.kind_of?(Array)
if option.kind_of?(Array)
"['#{option.join('\',\'')}']"
elsif !option.nil?
"'#{option}'"
end
js_option
end
end
JavascriptHelper = JavaScriptHelper unless const_defined? :JavascriptHelper
end
end

File diff suppressed because it is too large Load Diff

View File

@@ -12,14 +12,14 @@ module ActionView
BOOLEAN_ATTRIBUTES = %w(disabled readonly multiple).to_set
BOOLEAN_ATTRIBUTES.merge(BOOLEAN_ATTRIBUTES.map(&:to_sym))
# Returns an empty HTML tag of type +name+ which by default is XHTML
# compliant. Set +open+ to true to create an open tag compatible
# with HTML 4.0 and below. Add HTML attributes by passing an attributes
# Returns an empty HTML tag of type +name+ which by default is XHTML
# compliant. Set +open+ to true to create an open tag compatible
# with HTML 4.0 and below. Add HTML attributes by passing an attributes
# hash to +options+. Set +escape+ to false to disable attribute value
# escaping.
#
# ==== Options
# The +options+ hash is used with attributes with no value like (<tt>disabled</tt> and
# The +options+ hash is used with attributes with no value like (<tt>disabled</tt> and
# <tt>readonly</tt>), which you can give a value of true in the +options+ hash. You can use
# symbols or strings for the attribute names.
#
@@ -30,7 +30,7 @@ module ActionView
# tag("br", nil, true)
# # => <br>
#
# tag("input", { :type => 'text', :disabled => true })
# tag("input", { :type => 'text', :disabled => true })
# # => <input type="text" disabled="disabled" />
#
# tag("img", { :src => "open & shut.png" })
@@ -43,13 +43,13 @@ module ActionView
end
# Returns an HTML block tag of type +name+ surrounding the +content+. Add
# HTML attributes by passing an attributes hash to +options+.
# HTML attributes by passing an attributes hash to +options+.
# Instead of passing the content as an argument, you can also use a block
# in which case, you pass your +options+ as the second parameter.
# Set escape to false to disable attribute value escaping.
#
# ==== Options
# The +options+ hash is used with attributes with no value like (<tt>disabled</tt> and
# The +options+ hash is used with attributes with no value like (<tt>disabled</tt> and
# <tt>readonly</tt>), which you can give a value of true in the +options+ hash. You can use
# symbols or strings for the attribute names.
#
@@ -68,7 +68,13 @@ module ActionView
def content_tag(name, content_or_options_with_block = nil, options = nil, escape = true, &block)
if block_given?
options = content_or_options_with_block if content_or_options_with_block.is_a?(Hash)
concat(content_tag_string(name, capture(&block), options, escape))
content_tag = content_tag_string(name, capture(&block), options, escape)
if block_called_from_erb?(block)
concat(content_tag)
else
content_tag
end
else
content_tag_string(name, content_or_options_with_block, options, escape)
end
@@ -102,6 +108,22 @@ module ActionView
end
private
BLOCK_CALLED_FROM_ERB = 'defined? __in_erb_template'
if RUBY_VERSION < '1.9.0'
# Check whether we're called from an erb template.
# We'd return a string in any other case, but erb <%= ... %>
# can't take an <% end %> later on, so we have to use <% ... %>
# and implicitly concat.
def block_called_from_erb?(block)
block && eval(BLOCK_CALLED_FROM_ERB, block)
end
else
def block_called_from_erb?(block)
block && eval(BLOCK_CALLED_FROM_ERB, block.binding)
end
end
def content_tag_string(name, content, options, escape = true)
tag_options = tag_options(options, escape) if options
"<#{name}#{tag_options}>#{content}</#{name}>"

View File

@@ -27,14 +27,10 @@ module ActionView
# %>
def concat(string, unused_binding = nil)
if unused_binding
ActiveSupport::Deprecation.warn("The binding argument of #concat is no longer needed. Please remove it from your views and helpers.")
ActiveSupport::Deprecation.warn("The binding argument of #concat is no longer needed. Please remove it from your views and helpers.", caller)
end
if output_buffer && string
output_buffer << string
else
string
end
output_buffer << string
end
if RUBY_VERSION < '1.9'
@@ -472,7 +468,7 @@ module ActionView
[-\w]+ # subdomain or domain
(?:\.[-\w]+)* # remaining subdomains or domain
(?::\d+)? # port
(?:/(?:(?:[~\w\+@%=\(\)-]|(?:[,.;:][^\s$]))+)?)* # path
(?:/(?:(?:[~\w\+@%=\(\)-]|(?:[,.;:'][^\s$]))+)?)* # path
(?:\?[\w\+@%&=.;-]+)? # query string
(?:\#[\w\-]*)? # trailing anchor
)

View File

@@ -63,17 +63,15 @@ module ActionView
# # calls @workshop.to_s
# # => /workshops/5
def url_for(options = {})
options ||= {}
case options
when Hash
show_path = options[:host].nil? ? true : false
options = { :only_path => show_path }.update(options.symbolize_keys)
options = { :only_path => options[:host].nil? }.update(options.symbolize_keys)
escape = options.key?(:escape) ? options.delete(:escape) : true
url = @controller.send(:url_for, options)
when String
escape = true
url = options
when NilClass
url = @controller.send(:url_for, nil)
else
escape = false
url = polymorphic_path(options)
@@ -468,7 +466,7 @@ module ActionView
email_address_obfuscated.gsub!(/\./, html_options.delete("replace_dot")) if html_options.has_key?("replace_dot")
if encode == "javascript"
"document.write('#{content_tag("a", name || email_address, html_options.merge({ "href" => "mailto:"+email_address+extras }))}');".each_byte do |c|
"document.write('#{content_tag("a", name || email_address_obfuscated, html_options.merge({ "href" => "mailto:"+email_address+extras }))}');".each_byte do |c|
string << sprintf("%%%x", c)
end
"<script type=\"#{Mime::JS}\">eval(unescape('#{string}'))</script>"
@@ -535,7 +533,7 @@ module ActionView
when method
"#{method_javascript_function(method, url, href)}return false;"
when popup
popup_javascript_function(popup) + 'return false;'
"#{popup_javascript_function(popup)}return false;"
else
html_options["onclick"]
end

View File

@@ -1,17 +1,19 @@
module ActionView #:nodoc:
class InlineTemplate < Template #:nodoc:
def initialize(view, source, locals = {}, type = nil)
@view = view
class InlineTemplate #:nodoc:
include Renderable
attr_reader :source, :extension, :method_segment
def initialize(source, type = nil)
@source = source
@extension = type
@locals = locals || {}
@handler = self.class.handler_class_for_extension(@extension).new(@view)
@method_segment = "inline_#{@source.hash.abs}"
end
def method_key
@source
end
private
# Always recompile inline templates
def recompile?(local_assigns)
true
end
end
end

View File

@@ -1,70 +0,0 @@
module ActionView #:nodoc:
class PartialTemplate < Template #:nodoc:
attr_reader :variable_name, :object
def initialize(view, partial_path, object = nil, locals = {})
@view_controller = view.controller if view.respond_to?(:controller)
set_path_and_variable_name!(partial_path)
super(view, @path, true, locals)
add_object_to_local_assigns!(object)
# This is needed here in order to compile template with knowledge of 'counter'
initialize_counter!
# Prepare early. This is a performance optimization for partial collections
prepare!
end
def render
ActionController::Base.benchmark("Rendered #{@path.path_without_format_and_extension}", Logger::DEBUG, false) do
@handler.render(self)
end
end
def render_member(object)
@locals[:object] = @locals[@variable_name] = object
template = render_template
@locals[@counter_name] += 1
@locals.delete(@variable_name)
@locals.delete(:object)
template
end
def counter=(num)
@locals[@counter_name] = num
end
private
def add_object_to_local_assigns!(object)
@locals[:object] ||=
@locals[@variable_name] ||=
if object.is_a?(ActionView::Base::ObjectWrapper)
object.value
else
object
end || @view_controller.instance_variable_get("@#{variable_name}")
end
def set_path_and_variable_name!(partial_path)
if partial_path.include?('/')
@variable_name = File.basename(partial_path)
@path = "#{File.dirname(partial_path)}/_#{@variable_name}"
elsif @view_controller
@variable_name = partial_path
@path = "#{@view_controller.class.controller_path}/_#{@variable_name}"
else
@variable_name = partial_path
@path = "_#{@variable_name}"
end
@variable_name = @variable_name.sub(/\..*$/, '').to_sym
end
def initialize_counter!
@counter_name ||= "#{@variable_name}_counter".to_sym
@locals[@counter_name] = 0
end
end
end

View File

@@ -104,10 +104,11 @@ module ActionView
module Partials
private
def render_partial(partial_path, object_assigns = nil, local_assigns = {}) #:nodoc:
local_assigns ||= {}
case partial_path
when String, Symbol, NilClass
# Render the template
ActionView::PartialTemplate.new(self, partial_path, object_assigns, local_assigns).render_template
pick_template(find_partial_path(partial_path)).render_partial(self, object_assigns, local_assigns)
when ActionView::Helpers::FormBuilder
builder_partial_path = partial_path.class.to_s.demodulize.underscore.sub(/_builder$/, '')
render_partial(builder_partial_path, object_assigns, (local_assigns || {}).merge(builder_partial_path.to_sym => partial_path))
@@ -123,35 +124,33 @@ module ActionView
end
end
def render_partial_collection(partial_path, collection, partial_spacer_template = nil, local_assigns = {}) #:nodoc:
def render_partial_collection(partial_path, collection, partial_spacer_template = nil, local_assigns = {}, as = nil) #:nodoc:
return " " if collection.empty?
local_assigns = local_assigns ? local_assigns.clone : {}
spacer = partial_spacer_template ? render(:partial => partial_spacer_template) : ''
_paths = {}
_templates = {}
if partial_path.nil?
render_partial_collection_with_unknown_partial_path(collection, local_assigns)
else
render_partial_collection_with_known_partial_path(collection, partial_path, local_assigns)
index = 0
collection.map do |object|
_partial_path ||= partial_path || ActionController::RecordIdentifier.partial_path(object, controller.class.controller_path)
path = _paths[_partial_path] ||= find_partial_path(_partial_path)
template = _templates[path] ||= pick_template(path)
local_assigns[template.counter_name] = index
result = template.render_partial(self, object, local_assigns, as)
index += 1
result
end.join(spacer)
end
def render_partial_collection_with_known_partial_path(collection, partial_path, local_assigns)
template = ActionView::PartialTemplate.new(self, partial_path, nil, local_assigns)
collection.map do |element|
template.render_member(element)
end
end
def render_partial_collection_with_unknown_partial_path(collection, local_assigns)
templates = Hash.new
i = 0
collection.map do |element|
partial_path = ActionController::RecordIdentifier.partial_path(element, controller.class.controller_path)
template = templates[partial_path] ||= ActionView::PartialTemplate.new(self, partial_path, nil, local_assigns)
template.counter = i
i += 1
template.render_member(element)
def find_partial_path(partial_path)
if partial_path.include?('/')
"#{File.dirname(partial_path)}/_#{File.basename(partial_path)}"
elsif respond_to?(:controller)
"#{controller.class.controller_path}/_#{partial_path}"
else
"_#{partial_path}"
end
end
end

View File

@@ -0,0 +1,96 @@
module ActionView #:nodoc:
class PathSet < Array #:nodoc:
def self.type_cast(obj)
if obj.is_a?(String)
if Base.warn_cache_misses && defined?(Rails) && Rails.initialized?
Rails.logger.debug "[PERFORMANCE] Processing view path during a " +
"request. This an expense disk operation that should be done at " +
"boot. You can manually process this view path with " +
"ActionView::Base.process_view_paths(#{obj.inspect}) and set it " +
"as your view path"
end
Path.new(obj)
else
obj
end
end
class Path #:nodoc:
attr_reader :path, :paths
delegate :to_s, :to_str, :inspect, :to => :path
def initialize(path)
@path = path.freeze
reload!
end
def ==(path)
to_str == path.to_str
end
def [](path)
@paths[path]
end
# Rebuild load path directory cache
def reload!
@paths = {}
templates_in_path do |template|
@paths[template.path] = template
@paths[template.path_without_extension] ||= template
end
@paths.freeze
end
private
def templates_in_path
(Dir.glob("#{@path}/**/*/**") | Dir.glob("#{@path}/**")).each do |file|
unless File.directory?(file)
template = Template.new(file.split("#{self}/").last, self)
# Eager load memoized methods and freeze cached template
template.freeze if Base.cache_template_loading
yield template
end
end
end
end
def initialize(*args)
super(*args).map! { |obj| self.class.type_cast(obj) }
end
def reload!
each { |path| path.reload! }
end
def <<(obj)
super(self.class.type_cast(obj))
end
def push(*objs)
delete_paths!(objs)
super(*objs.map { |obj| self.class.type_cast(obj) })
end
def unshift(*objs)
delete_paths!(objs)
super(*objs.map { |obj| self.class.type_cast(obj) })
end
def [](template_path)
each do |path|
if template = path[template_path]
return template
end
end
nil
end
private
def delete_paths!(paths)
paths.each { |p1| delete_if { |p2| p1.to_s == p2.to_s } }
end
end
end

View File

@@ -0,0 +1,78 @@
module ActionView
module Renderable
# NOTE: The template that this mixin is beening include into is frozen
# So you can not set or modify any instance variables
def self.included(base)
@@mutex = Mutex.new
end
include ActiveSupport::Memoizable
def handler
Template.handler_class_for_extension(extension)
end
memoize :handler
def compiled_source
handler.new(nil).compile(self) if handler.compilable?
end
memoize :compiled_source
def render(view, local_assigns = {})
view._first_render ||= self
view._last_render = self
view.send(:evaluate_assigns)
compile(local_assigns) if handler.compilable?
handler.new(view).render(self, local_assigns)
end
def method(local_assigns)
if local_assigns && local_assigns.any?
local_assigns_keys = "locals_#{local_assigns.keys.map { |k| k.to_s }.sort.join('_')}"
end
['_run', extension, method_segment, local_assigns_keys].compact.join('_').to_sym
end
private
# Compile and evaluate the template's code
def compile(local_assigns)
render_symbol = method(local_assigns)
@@mutex.synchronize do
return false unless recompile?(render_symbol)
locals_code = local_assigns.keys.map { |key| "#{key} = local_assigns[:#{key}];" }.join
source = <<-end_src
def #{render_symbol}(local_assigns)
old_output_buffer = output_buffer;#{locals_code};#{compiled_source}
ensure
self.output_buffer = old_output_buffer
end
end_src
begin
file_name = respond_to?(:filename) ? filename : 'compiled-template'
ActionView::Base::CompiledTemplates.module_eval(source, file_name, 0)
rescue Exception => e # errors from template code
if logger = ActionController::Base.logger
logger.debug "ERROR: compiling #{render_symbol} RAISED #{e}"
logger.debug "Function body: #{source}"
logger.debug "Backtrace: #{e.backtrace.join("\n")}"
end
raise ActionView::TemplateError.new(self, {}, e)
end
end
end
# Method to check whether template compilation is necessary.
# The template will be compiled if the file has not been compiled yet, or
# if local_assigns has a new key, which isn't supported by the compiled code yet.
def recompile?(symbol)
meth = Base::CompiledTemplates.instance_method(template.method) rescue nil
!(meth && Base.cache_template_loading)
end
end
end

View File

@@ -0,0 +1,36 @@
module ActionView
module RenderablePartial
# NOTE: The template that this mixin is beening include into is frozen
# So you can not set or modify any instance variables
include ActiveSupport::Memoizable
def variable_name
name.sub(/\A_/, '').to_sym
end
memoize :variable_name
def counter_name
"#{variable_name}_counter".to_sym
end
memoize :counter_name
def render(view, local_assigns = {})
ActionController::Base.benchmark("Rendered #{path_without_format_and_extension}", Logger::DEBUG, false) do
super
end
end
def render_partial(view, object = nil, local_assigns = {}, as = nil)
object ||= local_assigns[:object] ||
local_assigns[variable_name] ||
view.controller.instance_variable_get("@#{variable_name}") if view.respond_to?(:controller)
# Ensure correct object is reassigned to other accessors
local_assigns[:object] = local_assigns[variable_name] = object
local_assigns[as] = object if as
render_template(view, local_assigns)
end
end
end

View File

@@ -1,94 +1,96 @@
module ActionView #:nodoc:
class Template #:nodoc:
class Template
extend TemplateHandlers
include ActiveSupport::Memoizable
include Renderable
attr_accessor :locals
attr_reader :handler, :path, :extension, :filename, :method
attr_accessor :filename, :load_path, :base_path, :name, :format, :extension
delegate :to_s, :to => :path
def initialize(view, path, use_full_path, locals = {})
@view = view
@paths = view.view_paths
def initialize(template_path, load_paths = [])
template_path = template_path.dup
@base_path, @name, @format, @extension = split(template_path)
@base_path.to_s.gsub!(/\/$/, '') # Push to split method
@load_path, @filename = find_full_path(template_path, load_paths)
@original_path = path
@path = TemplateFile.from_path(path, !use_full_path)
@view.first_render ||= @path.to_s
@source = nil # Don't read the source until we know that it is required
set_extension_and_file_name(use_full_path)
@locals = locals || {}
@handler = self.class.handler_class_for_extension(@extension).new(@view)
# Extend with partial super powers
extend RenderablePartial if @name =~ /^_/
end
def render_template
render
def format_and_extension
(extensions = [format, extension].compact.join(".")).blank? ? nil : extensions
end
memoize :format_and_extension
def path
[base_path, [name, format, extension].compact.join('.')].compact.join('/')
end
memoize :path
def path_without_extension
[base_path, [name, format].compact.join('.')].compact.join('/')
end
memoize :path_without_extension
def path_without_format_and_extension
[base_path, name].compact.join('/')
end
memoize :path_without_format_and_extension
def source
File.read(filename)
end
memoize :source
def method_segment
segment = File.expand_path(filename)
segment.sub!(/^#{Regexp.escape(File.expand_path(RAILS_ROOT))}/, '') if defined?(RAILS_ROOT)
segment.gsub!(/([^a-zA-Z0-9_])/) { $1.ord }
end
memoize :method_segment
def render_template(view, local_assigns = {})
render(view, local_assigns)
rescue Exception => e
raise e unless filename
if TemplateError === e
e.sub_template_of(filename)
raise e
else
raise TemplateError.new(self, @view.assigns, e)
end
end
def render
prepare!
@handler.render(self)
end
def path_without_extension
@path.path_without_extension
end
def source
@source ||= File.read(self.filename)
end
def method_key
@filename
end
def base_path_for_exception
(@paths.find_load_path_for_path(@path) || @paths.first).to_s
end
def prepare!
@view.send :evaluate_assigns
@view.current_render_extension = @extension
if @handler.compilable?
@handler.compile_template(self) # compile the given template, if necessary
@method = @view.method_names[method_key] # Set the method name for this template and run it
raise TemplateError.new(self, view.assigns, e)
end
end
private
def set_extension_and_file_name(use_full_path)
@extension = @path.extension
if use_full_path
unless @extension
@path = @view.send(:template_file_from_name, @path)
raise_missing_template_exception unless @path
@extension = @path.extension
end
if @path = @paths.find_template_file_for_path(path)
@filename = @path.full_path
@extension = @path.extension
end
else
@filename = @path.full_path
end
raise_missing_template_exception if @filename.blank?
def valid_extension?(extension)
Template.template_handler_extensions.include?(extension)
end
def raise_missing_template_exception
full_template_path = @original_path.include?('.') ? @original_path : "#{@original_path}.#{@view.template_format}.erb"
display_paths = @paths.join(':')
template_type = (@original_path =~ /layouts/i) ? 'layout' : 'template'
raise(MissingTemplate, "Missing #{template_type} #{full_template_path} in view path #{display_paths}")
def find_full_path(path, load_paths)
load_paths = Array(load_paths) + [nil]
load_paths.each do |load_path|
file = [load_path, path].compact.join('/')
return load_path, file if File.exist?(file)
end
raise MissingTemplate.new(load_paths, path)
end
# Returns file split into an array
# [base_path, name, format, extension]
def split(file)
if m = file.match(/^(.*\/)?([^\.]+)\.?(\w+)?\.?(\w+)?\.?(\w+)?$/)
if m[5] # Mulipart formats
[m[1], m[2], "#{m[3]}.#{m[4]}", m[5]]
elsif m[4] # Single format
[m[1], m[2], m[3], m[4]]
else
if valid_extension?(m[3]) # No format
[m[1], m[2], nil, m[3]]
else # No extension
[m[1], m[2], m[3], nil]
end
end
end
end
end
end

View File

@@ -7,7 +7,7 @@ module ActionView
attr_reader :original_exception
def initialize(template, assigns, original_exception)
@base_path = template.base_path_for_exception
@base_path = template.base_path
@assigns, @source, @original_exception = assigns.dup, template.source, original_exception
@file_path = template.filename
@backtrace = compute_backtrace
@@ -105,6 +105,6 @@ module ActionView
end
if defined?(Exception::TraceSubstitutions)
Exception::TraceSubstitutions << [/:in\s+`_run_(html|xml).*'\s*$/, '']
Exception::TraceSubstitutions << [/:in\s+`_run_.*'\s*$/, '']
Exception::TraceSubstitutions << [%r{^\s*#{Regexp.escape RAILS_ROOT}/}, ''] if defined?(RAILS_ROOT)
end

View File

@@ -1,88 +0,0 @@
module ActionView #:nodoc:
# TemplateFile abstracts the pattern of querying a file path for its
# path with or without its extension. The path is only the partial path
# from the load path root e.g. "hello/index.html.erb" not
# "app/views/hello/index.html.erb"
class TemplateFile
def self.from_path(path, use_full_path = false)
path.is_a?(self) ? path : new(path, use_full_path)
end
def self.from_full_path(load_path, full_path)
file = new(full_path.split(load_path).last)
file.load_path = load_path
file.freeze
end
attr_accessor :load_path, :base_path, :name, :format, :extension
delegate :to_s, :inspect, :to => :path
def initialize(path, use_full_path = false)
path = path.dup
# Clear the forward slash in the beginning unless using full path
trim_forward_slash!(path) unless use_full_path
@base_path, @name, @format, @extension = split(path)
end
def freeze
@load_path.freeze
@base_path.freeze
@name.freeze
@format.freeze
@extension.freeze
super
end
def format_and_extension
extensions = [format, extension].compact.join(".")
extensions.blank? ? nil : extensions
end
def full_path
if load_path
"#{load_path}/#{path}"
else
path
end
end
def path
base_path.to_s + [name, format, extension].compact.join(".")
end
def path_without_extension
base_path.to_s + [name, format].compact.join(".")
end
def path_without_format_and_extension
"#{base_path}#{name}"
end
def dup_with_extension(extension)
file = dup
file.extension = extension ? extension.to_s : nil
file
end
private
def trim_forward_slash!(path)
path.sub!(/^\//, '')
end
# Returns file split into an array
# [base_path, name, format, extension]
def split(file)
if m = file.match(/^(.*\/)?(\w+)\.?(\w+)?\.?(\w+)?\.?(\w+)?$/)
if m[5] # Mulipart formats
[m[1], m[2], "#{m[3]}.#{m[4]}", m[5]]
elsif m[4] # Single format
[m[1], m[2], m[3], m[4]]
else # No format
[m[1], m[2], nil, m[3]]
end
end
end
end
end

View File

@@ -1,9 +1,5 @@
module ActionView
class TemplateHandler
def self.line_offset
0
end
def self.compilable?
false
end
@@ -12,7 +8,7 @@ module ActionView
@view = view
end
def render(template)
def render(template, local_assigns = {})
end
def compile(template)
@@ -21,13 +17,5 @@ module ActionView
def compilable?
self.class.compilable?
end
def line_offset
self.class.line_offset
end
# Called by CacheHelper#cache
def cache_fragment(block, name = {}, options = nil)
end
end
end

View File

@@ -5,23 +5,13 @@ module ActionView
class Builder < TemplateHandler
include Compilable
def self.line_offset
2
end
def compile(template)
content_type_handler = (@view.send!(:controller).respond_to?(:response) ? "controller.response" : "controller")
"#{content_type_handler}.content_type ||= Mime::XML\n" +
"xml = ::Builder::XmlMarkup.new(:indent => 2)\n" +
# ActionMailer does not have a response
"controller.respond_to?(:response) && controller.response.content_type ||= Mime::XML;" +
"xml = ::Builder::XmlMarkup.new(:indent => 2);" +
"self.output_buffer = xml.target!;" +
template.source +
"\nxml.target!\n"
end
def cache_fragment(block, name = {}, options = nil)
@view.fragment_for(block, name, options) do
eval('xml.target!', block.binding)
end
";xml.target!;"
end
end
end

View File

@@ -1,21 +1,8 @@
module ActionView
module TemplateHandlers
module Compilable
def self.included(base)
base.extend ClassMethod
# Map method names to their compile time
base.cattr_accessor :compile_time
base.compile_time = {}
# Map method names to the names passed in local assigns so far
base.cattr_accessor :template_args
base.template_args = {}
# Count the number of inline templates
base.cattr_accessor :inline_template_count
base.inline_template_count = 0
end
module ClassMethod
@@ -24,105 +11,10 @@ module ActionView
true
end
end
def render(template)
@view.send :execute, template
def render(template, local_assigns = {})
@view.send(:execute, template, local_assigns)
end
# Compile and evaluate the template's code
def compile_template(template)
return unless compile_template?(template)
render_symbol = assign_method_name(template)
render_source = create_template_source(template, render_symbol)
line_offset = self.template_args[render_symbol].size + self.line_offset
begin
file_name = template.filename || 'compiled-template'
ActionView::Base::CompiledTemplates.module_eval(render_source, file_name, -line_offset)
rescue Exception => e # errors from template code
if @view.logger
@view.logger.debug "ERROR: compiling #{render_symbol} RAISED #{e}"
@view.logger.debug "Function body: #{render_source}"
@view.logger.debug "Backtrace: #{e.backtrace.join("\n")}"
end
raise ActionView::TemplateError.new(template, @view.assigns, e)
end
self.compile_time[render_symbol] = Time.now
# logger.debug "Compiled template #{file_name || template}\n ==> #{render_symbol}" if logger
end
private
# Method to check whether template compilation is necessary.
# The template will be compiled if the inline template or file has not been compiled yet,
# if local_assigns has a new key, which isn't supported by the compiled code yet,
# or if the file has changed on disk and checking file mods hasn't been disabled.
def compile_template?(template)
method_key = template.method_key
render_symbol = @view.method_names[method_key]
compile_time = self.compile_time[render_symbol]
if compile_time && supports_local_assigns?(render_symbol, template.locals)
if template.filename && !@view.cache_template_loading
template_changed_since?(template.filename, compile_time)
end
else
true
end
end
def assign_method_name(template)
@view.method_names[template.method_key] ||= compiled_method_name(template)
end
def compiled_method_name(template)
['_run', self.class.to_s.demodulize.underscore, compiled_method_name_file_path_segment(template.filename)].compact.join('_').to_sym
end
def compiled_method_name_file_path_segment(file_name)
if file_name
s = File.expand_path(file_name)
s.sub!(/^#{Regexp.escape(File.expand_path(RAILS_ROOT))}/, '') if defined?(RAILS_ROOT)
s.gsub!(/([^a-zA-Z0-9_])/) { $1.ord }
s
else
(self.inline_template_count += 1).to_s
end
end
# Method to create the source code for a given template.
def create_template_source(template, render_symbol)
body = compile(template)
self.template_args[render_symbol] ||= {}
locals_keys = self.template_args[render_symbol].keys | template.locals.keys
self.template_args[render_symbol] = locals_keys.inject({}) { |h, k| h[k] = true; h }
locals_code = ""
locals_keys.each do |key|
locals_code << "#{key} = local_assigns[:#{key}]\n"
end
"def #{render_symbol}(local_assigns)\nold_output_buffer = output_buffer;#{locals_code}#{body}\nensure\nself.output_buffer = old_output_buffer\nend"
end
# Return true if the given template was compiled for a superset of the keys in local_assigns
def supports_local_assigns?(render_symbol, local_assigns)
local_assigns.empty? ||
((args = self.template_args[render_symbol]) && local_assigns.all? { |k,_| args.has_key?(k) })
end
# Method to handle checking a whether a template has changed since last compile; isolated so that templates
# not stored on the file system can hook and extend appropriately.
def template_changed_since?(file_name, compile_time)
lstat = File.lstat(file_name)
compile_time < lstat.mtime ||
(lstat.symlink? && compile_time < File.stat(file_name).mtime)
end
end
end
end

View File

@@ -42,12 +42,14 @@ module ActionView
class ERB < TemplateHandler
include Compilable
def compile(template)
::ERB.new(template.source, nil, @view.erb_trim_mode, '@output_buffer').src
end
# Specify trim mode for the ERB compiler. Defaults to '-'.
# See ERb documentation for suitable values.
cattr_accessor :erb_trim_mode
self.erb_trim_mode = '-'
def cache_fragment(block, name = {}, options = nil) #:nodoc:
@view.fragment_for(block, name, options) { @view.response.template.output_buffer ||= '' }
def compile(template)
src = ::ERB.new(template.source, nil, erb_trim_mode, '@output_buffer').src
"__in_erb_template=true;#{src}"
end
end
end

View File

@@ -3,24 +3,9 @@ module ActionView
class RJS < TemplateHandler
include Compilable
def self.line_offset
2
end
def compile(template)
"controller.response.content_type ||= Mime::JS\n" +
"update_page do |page|\n#{template.source}\nend"
end
def cache_fragment(block, name = {}, options = nil) #:nodoc:
@view.fragment_for(block, name, options) do
begin
debug_mode, ActionView::Base.debug_rjs = ActionView::Base.debug_rjs, false
eval('page.to_s', block.binding)
ensure
ActionView::Base.debug_rjs = debug_mode
end
end
"controller.response.content_type ||= Mime::JS;" +
"update_page do |page|;#{template.source}\nend"
end
end
end

View File

@@ -1,103 +0,0 @@
module ActionView #:nodoc:
class ViewLoadPaths < Array #:nodoc:
def self.type_cast(obj)
obj.is_a?(String) ? LoadPath.new(obj) : obj
end
class LoadPath #:nodoc:
attr_reader :path, :paths
delegate :to_s, :inspect, :to => :path
def initialize(path)
@path = path.freeze
reload!
end
def eql?(view_path)
view_path.is_a?(ViewPath) && @path == view_path.path
end
def hash
@path.hash
end
# Rebuild load path directory cache
def reload!
@paths = {}
files.each do |file|
@paths[file.path] = file
@paths[file.path_without_extension] ||= file
end
@paths.freeze
end
# Tries to find the extension for the template name.
# If it does not it exist, tries again without the format extension
# find_template_file_for_partial_path('users/show') => 'html.erb'
# find_template_file_for_partial_path('users/legacy') => 'rhtml'
def find_template_file_for_partial_path(file)
@paths[file.path] || @paths[file.path_without_extension] || @paths[file.path_without_format_and_extension]
end
private
# Get all the files and directories in the path
def files_in_path
Dir.glob("#{@path}/**/*/**") | Dir.glob("#{@path}/**")
end
# Create an array of all the files within the path
def files
files_in_path.map do |file|
TemplateFile.from_full_path(@path, file) unless File.directory?(file)
end.compact
end
end
def initialize(*args)
super(*args).map! { |obj| self.class.type_cast(obj) }
end
def reload!
each { |path| path.reload! }
end
def <<(obj)
super(self.class.type_cast(obj))
end
def push(*objs)
delete_paths!(objs)
super(*objs.map { |obj| self.class.type_cast(obj) })
end
def unshift(*objs)
delete_paths!(objs)
super(*objs.map { |obj| self.class.type_cast(obj) })
end
def template_exists?(file)
find_load_path_for_path(file) ? true : false
end
def find_load_path_for_path(file)
find { |path| path.paths[file.to_s] }
end
def find_template_file_for_path(file)
file = TemplateFile.from_path(file)
each do |path|
if f = path.find_template_file_for_partial_path(file)
return f
end
end
nil
end
private
def delete_paths!(paths)
paths.each { |p1| delete_if { |p2| p1.to_s == p2.to_s } }
end
end
end

View File

@@ -22,6 +22,9 @@ ActiveSupport::Deprecation.debug = true
ActionController::Base.logger = nil
ActionController::Routing::Routes.reload rescue nil
ActionView::Base.cache_template_loading = true
FIXTURE_LOAD_PATH = File.join(File.dirname(__FILE__), 'fixtures')
ActionController::Base.view_paths = FIXTURE_LOAD_PATH
# Wrap tests that use Mocha and skip if unavailable.
def uses_mocha(test_name)

View File

@@ -30,7 +30,6 @@ end
$stderr.flush
# Define the rest of the connector
class ActiveRecordTestConnector
class << self
@@ -48,46 +47,45 @@ class ActiveRecordTestConnector
end
private
def setup_connection
if Object.const_defined?(:ActiveRecord)
defaults = { :database => ':memory:' }
begin
options = defaults.merge :adapter => 'sqlite3', :timeout => 500
ActiveRecord::Base.establish_connection(options)
ActiveRecord::Base.configurations = { 'sqlite3_ar_integration' => options }
ActiveRecord::Base.connection
rescue Exception # errors from establishing a connection
$stderr.puts 'SQLite 3 unavailable; trying SQLite 2.'
options = defaults.merge :adapter => 'sqlite'
ActiveRecord::Base.establish_connection(options)
ActiveRecord::Base.configurations = { 'sqlite2_ar_integration' => options }
ActiveRecord::Base.connection
end
def setup_connection
if Object.const_defined?(:ActiveRecord)
defaults = { :database => ':memory:' }
begin
options = defaults.merge :adapter => 'sqlite3', :timeout => 500
ActiveRecord::Base.establish_connection(options)
ActiveRecord::Base.configurations = { 'sqlite3_ar_integration' => options }
ActiveRecord::Base.connection
rescue Exception # errors from establishing a connection
$stderr.puts 'SQLite 3 unavailable; trying SQLite 2.'
options = defaults.merge :adapter => 'sqlite'
ActiveRecord::Base.establish_connection(options)
ActiveRecord::Base.configurations = { 'sqlite2_ar_integration' => options }
ActiveRecord::Base.connection
Object.send(:const_set, :QUOTED_TYPE, ActiveRecord::Base.connection.quote_column_name('type')) unless Object.const_defined?(:QUOTED_TYPE)
else
raise "Can't setup connection since ActiveRecord isn't loaded."
end
Object.send(:const_set, :QUOTED_TYPE, ActiveRecord::Base.connection.quote_column_name('type')) unless Object.const_defined?(:QUOTED_TYPE)
else
raise "Can't setup connection since ActiveRecord isn't loaded."
end
end
# Load actionpack sqlite tables
def load_schema
File.read(File.dirname(__FILE__) + "/fixtures/db_definitions/sqlite.sql").split(';').each do |sql|
ActiveRecord::Base.connection.execute(sql) unless sql.blank?
# Load actionpack sqlite tables
def load_schema
File.read(File.dirname(__FILE__) + "/fixtures/db_definitions/sqlite.sql").split(';').each do |sql|
ActiveRecord::Base.connection.execute(sql) unless sql.blank?
end
end
end
def require_fixture_models
Dir.glob(File.dirname(__FILE__) + "/fixtures/*.rb").each {|f| require f}
end
def require_fixture_models
Dir.glob(File.dirname(__FILE__) + "/fixtures/*.rb").each {|f| require f}
end
end
end
class ActiveRecordTestCase < ActiveSupport::TestCase
# Set our fixture path
if ActiveRecordTestConnector.able_to_connect
self.fixture_path = "#{File.dirname(__FILE__)}/fixtures/"
self.fixture_path = [FIXTURE_LOAD_PATH]
self.use_transactional_fixtures = false
end

View File

@@ -40,11 +40,10 @@ class RenderPartialWithRecordIdentificationController < ActionController::Base
render :partial => @developers
end
end
RenderPartialWithRecordIdentificationController.view_paths = [ File.dirname(__FILE__) + "/../fixtures/" ]
class RenderPartialWithRecordIdentificationTest < ActiveRecordTestCase
fixtures :developers, :projects, :developers_projects, :topics, :replies, :companies, :mascots
def setup
@controller = RenderPartialWithRecordIdentificationController.new
@request = ActionController::TestRequest.new
@@ -55,26 +54,31 @@ class RenderPartialWithRecordIdentificationTest < ActiveRecordTestCase
def test_rendering_partial_with_has_many_and_belongs_to_association
get :render_with_has_many_and_belongs_to_association
assert_template 'projects/_project'
assert_equal 'Active RecordActive Controller', @response.body
end
def test_rendering_partial_with_has_many_association
get :render_with_has_many_association
assert_template 'replies/_reply'
assert_equal 'Birdman is better!', @response.body
end
def test_rendering_partial_with_named_scope
get :render_with_named_scope
assert_template 'replies/_reply'
assert_equal 'Birdman is better!Nuh uh!', @response.body
end
def test_render_with_record
get :render_with_record
assert_template 'developers/_developer'
assert_equal 'David', @response.body
end
def test_render_with_record_collection
get :render_with_record_collection
assert_template 'developers/_developer'
assert_equal 'DavidJamisfixture_3fixture_4fixture_5fixture_6fixture_7fixture_8fixture_9fixture_10Jamis', @response.body
end
def test_rendering_partial_with_has_one_association
@@ -116,7 +120,6 @@ class RenderPartialWithRecordIdentificationController < ActionController::Base
render :partial => @developers
end
end
RenderPartialWithRecordIdentificationController.view_paths = [ File.dirname(__FILE__) + "/../fixtures/" ]
class Game < Struct.new(:name, :id)
def to_param
@@ -134,7 +137,6 @@ module Fun
render :partial => [ Game.new("Pong"), Game.new("Tank") ]
end
end
NestedController.view_paths = [ File.dirname(__FILE__) + "/../fixtures/" ]
module Serious
class NestedDeeperController < ActionController::Base
@@ -146,7 +148,6 @@ module Fun
render :partial => [ Game.new("Chess"), Game.new("Sudoku"), Game.new("Solitaire") ]
end
end
NestedDeeperController.view_paths = [ File.dirname(__FILE__) + "/../fixtures/" ]
end
end
@@ -161,13 +162,14 @@ class RenderPartialWithRecordIdentificationAndNestedControllersTest < ActiveReco
def test_render_with_record_in_nested_controller
get :render_with_record_in_nested_controller
assert_template 'fun/games/_game'
assert_equal 'Pong', @response.body
end
def test_render_with_record_collection_in_nested_controller
get :render_with_record_collection_in_nested_controller
assert_template 'fun/games/_game'
assert_equal 'PongTank', @response.body
end
end
class RenderPartialWithRecordIdentificationAndNestedDeeperControllersTest < ActiveRecordTestCase
@@ -181,11 +183,12 @@ class RenderPartialWithRecordIdentificationAndNestedDeeperControllersTest < Acti
def test_render_with_record_in_deeper_nested_controller
get :render_with_record_in_deeper_nested_controller
assert_template 'fun/serious/games/_game'
assert_equal 'Chess', @response.body
end
def test_render_with_record_collection_in_deeper_nested_controller
get :render_with_record_collection_in_deeper_nested_controller
assert_template 'fun/serious/games/_game'
assert_equal 'ChessSudokuSolitaire', @response.body
end
end
end

View File

@@ -157,21 +157,13 @@ module Admin
def redirect_to_fellow_controller
redirect_to :controller => 'user'
end
def redirect_to_top_level_named_route
redirect_to top_level_url(:id => "foo")
end
end
end
# ---------------------------------------------------------------------------
# tell the controller where to find its templates but start from parent
# directory of test_request_response to simulate the behaviour of a
# production environment
ActionPackAssertionsController.view_paths = [ File.dirname(__FILE__) + "/../fixtures/" ]
# a test case to exercise the new capabilities TestRequest & TestResponse
class ActionPackAssertionsControllerTest < Test::Unit::TestCase
# let's get this party started
@@ -232,7 +224,6 @@ class ActionPackAssertionsControllerTest < Test::Unit::TestCase
process :redirect_to_named_route
assert_redirected_to 'http://test.host/route_one'
assert_redirected_to route_one_url
assert_redirected_to :route_one_url
end
end
@@ -253,9 +244,6 @@ class ActionPackAssertionsControllerTest < Test::Unit::TestCase
assert_raise(Test::Unit::AssertionFailedError) do
assert_redirected_to route_two_url
end
assert_raise(Test::Unit::AssertionFailedError) do
assert_redirected_to :route_two_url
end
end
end
@@ -340,11 +328,11 @@ class ActionPackAssertionsControllerTest < Test::Unit::TestCase
# check if we were rendered by a file-based template?
def test_rendered_action
process :nothing
assert !@response.rendered_with_file?
assert_nil @response.rendered_template
process :hello_world
assert @response.rendered_with_file?
assert 'hello_world', @response.rendered_file
assert @response.rendered_template
assert 'hello_world', @response.rendered_template.to_s
end
# check the redirection location
@@ -419,22 +407,6 @@ class ActionPackAssertionsControllerTest < Test::Unit::TestCase
assert_equal "Mr. David", @response.body
end
def test_follow_redirect
process :redirect_to_action
assert_redirected_to :action => "flash_me"
follow_redirect
assert_equal 1, @request.parameters["id"].to_i
assert "Inconceivable!", @response.body
end
def test_follow_redirect_outside_current_action
process :redirect_to_controller
assert_redirected_to :controller => "elsewhere", :action => "flash_me"
assert_raises(RuntimeError, "Can't follow redirects outside of current controller (elsewhere)") { follow_redirect }
end
def test_assert_redirection_fails_with_incorrect_controller
process :redirect_to_controller
@@ -448,14 +420,16 @@ class ActionPackAssertionsControllerTest < Test::Unit::TestCase
assert_redirected_to :controller => 'action_pack_assertions', :action => "flash_me", :id => 1, :params => { :panda => 'fun' }
end
def test_redirected_to_url_leadling_slash
def test_redirected_to_url_leading_slash
process :redirect_to_path
assert_redirected_to '/some/path'
end
def test_redirected_to_url_no_leadling_slash
process :redirect_to_path
assert_redirected_to 'some/path'
end
def test_redirected_to_url_full_url
process :redirect_to_path
assert_redirected_to 'http://test.host/some/path'
@@ -475,7 +449,7 @@ class ActionPackAssertionsControllerTest < Test::Unit::TestCase
def test_redirected_to_with_nested_controller
@controller = Admin::InnerModuleController.new
get :redirect_to_absolute_controller
assert_redirected_to :controller => 'content'
assert_redirected_to :controller => '/content'
get :redirect_to_fellow_controller
assert_redirected_to :controller => 'admin/user'
@@ -533,7 +507,6 @@ class ActionPackHeaderTest < Test::Unit::TestCase
assert_equal('application/pdf; charset=utf-8', @response.headers['type'])
end
def test_render_text_with_custom_content_type
get :render_text_with_custom_content_type
assert_equal 'application/rss+xml; charset=utf-8', @response.headers['type']

View File

@@ -1,7 +1,6 @@
require 'abstract_unit'
class Address
def Address.count(conditions = nil, join = nil)
nil
end
@@ -20,8 +19,6 @@ class AddressesTestController < ActionController::Base
def self.controller_path; "addresses"; end
end
AddressesTestController.view_paths = [ File.dirname(__FILE__) + "/../fixtures/" ]
class AddressesTest < Test::Unit::TestCase
def setup
@controller = AddressesTestController.new

View File

@@ -6,7 +6,6 @@ CACHE_DIR = 'test_cache'
FILE_STORE_PATH = File.join(File.dirname(__FILE__), '/../temp/', CACHE_DIR)
ActionController::Base.page_cache_directory = FILE_STORE_PATH
ActionController::Base.cache_store = :file_store, FILE_STORE_PATH
ActionController::Base.view_paths = [ File.dirname(__FILE__) + '/../fixtures/' ]
class PageCachingTestController < ActionController::Base
caches_page :ok, :no_content, :if => Proc.new { |c| !c.request.format.json? }
@@ -131,8 +130,7 @@ class PageCachingTest < Test::Unit::TestCase
end
def test_page_caching_conditional_options
@request.env['HTTP_ACCEPT'] = 'application/json'
get :ok
get :ok, :format=>'json'
assert_page_not_cached :ok
end
@@ -152,7 +150,7 @@ end
class ActionCachingTestController < ActionController::Base
caches_action :index, :redirected, :forbidden, :if => Proc.new { |c| !c.request.format.json? }
caches_action :index, :redirected, :forbidden, :if => Proc.new { |c| !c.request.format.json? }, :expires_in => 1.hour
caches_action :show, :cache_path => 'http://test.host/custom/show'
caches_action :edit, :cache_path => Proc.new { |c| c.params[:id] ? "http://test.host/#{c.params[:id]};edit" : "http://test.host/edit" }
caches_action :with_layout
@@ -188,6 +186,7 @@ class ActionCachingTestController < ActionController::Base
expire_action :controller => 'action_caching_test', :action => 'index'
render :nothing => true
end
def expire_xml
expire_action :controller => 'action_caching_test', :action => 'index', :format => 'xml'
render :nothing => true
@@ -218,6 +217,7 @@ class ActionCachingMockController
Object.new.instance_eval(<<-EVAL)
def path; '#{@mock_path}' end
def format; 'all' end
def cache_format; nil end
self
EVAL
end
@@ -284,9 +284,19 @@ class ActionCacheTest < Test::Unit::TestCase
end
def test_action_cache_conditional_options
old_use_accept_header = ActionController::Base.use_accept_header
ActionController::Base.use_accept_header = true
@request.env['HTTP_ACCEPT'] = 'application/json'
get :index
assert !fragment_exist?('hostname.com/action_caching_test')
ActionController::Base.use_accept_header = old_use_accept_header
end
def test_action_cache_with_store_options
MockTime.expects(:now).returns(12345).once
@controller.expects(:read_fragment).with('hostname.com/action_caching_test', :expires_in => 1.hour).once
@controller.expects(:write_fragment).with('hostname.com/action_caching_test', '12345.0', :expires_in => 1.hour).once
get :index
end
def test_action_cache_with_custom_cache_path
@@ -406,12 +416,6 @@ class ActionCacheTest < Test::Unit::TestCase
assert_equal 'application/xml', @response.content_type
reset!
@request.env['HTTP_ACCEPT'] = "application/xml"
get :index
assert_equal cached_time, @response.body
assert_equal 'application/xml', @response.content_type
reset!
get :expire_xml
reset!
@@ -551,7 +555,7 @@ class FragmentCachingTest < Test::Unit::TestCase
fragment_computed = false
buffer = 'generated till now -> '
@controller.fragment_for(Proc.new { fragment_computed = true }, 'expensive') { buffer }
@controller.fragment_for(buffer, 'expensive') { fragment_computed = true }
assert fragment_computed
assert_equal 'generated till now -> ', buffer
@@ -562,50 +566,11 @@ class FragmentCachingTest < Test::Unit::TestCase
fragment_computed = false
buffer = 'generated till now -> '
@controller.fragment_for(Proc.new { fragment_computed = true }, 'expensive') { buffer}
@controller.fragment_for(buffer, 'expensive') { fragment_computed = true }
assert !fragment_computed
assert_equal 'generated till now -> fragment content', buffer
end
def test_cache_erb_fragment
@store.write('views/expensive', 'fragment content')
@controller.response.template.output_buffer = 'generated till now -> '
assert_equal( 'generated till now -> fragment content',
ActionView::TemplateHandlers::ERB.new(@controller).cache_fragment(Proc.new{ }, 'expensive'))
end
def test_cache_rxml_fragment
@store.write('views/expensive', 'fragment content')
xml = 'generated till now -> '
class << xml; def target!; to_s; end; end
assert_equal( 'generated till now -> fragment content',
ActionView::TemplateHandlers::Builder.new(@controller).cache_fragment(Proc.new{ }, 'expensive'))
end
def test_cache_rjs_fragment
@store.write('views/expensive', 'fragment content')
page = 'generated till now -> '
assert_equal( 'generated till now -> fragment content',
ActionView::TemplateHandlers::RJS.new(@controller).cache_fragment(Proc.new{ }, 'expensive'))
end
def test_cache_rjs_fragment_debug_mode_does_not_interfere
@store.write('views/expensive', 'fragment content')
page = 'generated till now -> '
begin
debug_mode, ActionView::Base.debug_rjs = ActionView::Base.debug_rjs, true
assert_equal( 'generated till now -> fragment content',
ActionView::TemplateHandlers::RJS.new(@controller).cache_fragment(Proc.new{ }, 'expensive'))
assert ActionView::Base.debug_rjs
ensure
ActionView::Base.debug_rjs = debug_mode
end
end
end
@@ -631,8 +596,6 @@ class FunctionalCachingController < ActionController::Base
end
end
FunctionalCachingController.view_paths = [ File.dirname(__FILE__) + "/../fixtures/" ]
class FunctionalFragmentCachingTest < Test::Unit::TestCase
def setup
ActionController::Base.perform_caching = true
@@ -642,6 +605,7 @@ class FunctionalFragmentCachingTest < Test::Unit::TestCase
@request = ActionController::TestRequest.new
@response = ActionController::TestResponse.new
end
def test_fragment_caching
get :fragment_cached
assert_response :success
@@ -661,6 +625,14 @@ CACHED
assert_match "Fragment caching in a partial", @store.read('views/test.host/functional_caching/html_fragment_cached_with_partial')
end
def test_render_inline_before_fragment_caching
get :inline_fragment_cached
assert_response :success
assert_match /Some inline content/, @response.body
assert_match /Some cached content/, @response.body
assert_match "Some cached content", @store.read('views/test.host/functional_caching/inline_fragment_cached')
end
def test_fragment_caching_in_rjs_partials
xhr :get, :js_fragment_cached_with_partial
assert_response :success

View File

@@ -23,8 +23,6 @@ class CaptureController < ActionController::Base
def rescue_action(e) raise end
end
CaptureController.view_paths = [ File.dirname(__FILE__) + "/../fixtures/" ]
class CaptureTest < Test::Unit::TestCase
def setup
@controller = CaptureController.new

View File

@@ -3,18 +3,58 @@ require 'action_controller/cgi_process'
class BaseCgiTest < Test::Unit::TestCase
def setup
@request_hash = {"HTTP_MAX_FORWARDS"=>"10", "SERVER_NAME"=>"glu.ttono.us:8007", "FCGI_ROLE"=>"RESPONDER", "HTTP_X_FORWARDED_HOST"=>"glu.ttono.us", "HTTP_ACCEPT_ENCODING"=>"gzip, deflate", "HTTP_USER_AGENT"=>"Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/312.5.1 (KHTML, like Gecko) Safari/312.3.1", "PATH_INFO"=>"", "HTTP_ACCEPT_LANGUAGE"=>"en", "HTTP_HOST"=>"glu.ttono.us:8007", "SERVER_PROTOCOL"=>"HTTP/1.1", "REDIRECT_URI"=>"/dispatch.fcgi", "SCRIPT_NAME"=>"/dispatch.fcgi", "SERVER_ADDR"=>"207.7.108.53", "REMOTE_ADDR"=>"207.7.108.53", "SERVER_SOFTWARE"=>"lighttpd/1.4.5", "HTTP_COOKIE"=>"_session_id=c84ace84796670c052c6ceb2451fb0f2; is_admin=yes", "HTTP_X_FORWARDED_SERVER"=>"glu.ttono.us", "REQUEST_URI"=>"/admin", "DOCUMENT_ROOT"=>"/home/kevinc/sites/typo/public", "SERVER_PORT"=>"8007", "QUERY_STRING"=>"", "REMOTE_PORT"=>"63137", "GATEWAY_INTERFACE"=>"CGI/1.1", "HTTP_X_FORWARDED_FOR"=>"65.88.180.234", "HTTP_ACCEPT"=>"*/*", "SCRIPT_FILENAME"=>"/home/kevinc/sites/typo/public/dispatch.fcgi", "REDIRECT_STATUS"=>"200", "REQUEST_METHOD"=>"GET"}
@request_hash = {
"HTTP_MAX_FORWARDS" => "10",
"SERVER_NAME" => "glu.ttono.us:8007",
"FCGI_ROLE" => "RESPONDER",
"AUTH_TYPE" => "Basic",
"HTTP_X_FORWARDED_HOST" => "glu.ttono.us",
"HTTP_ACCEPT_CHARSET" => "UTF-8",
"HTTP_ACCEPT_ENCODING" => "gzip, deflate",
"HTTP_CACHE_CONTROL" => "no-cache, max-age=0",
"HTTP_PRAGMA" => "no-cache",
"HTTP_USER_AGENT" => "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en)",
"PATH_INFO" => "/homepage/",
"HTTP_ACCEPT_LANGUAGE" => "en",
"HTTP_NEGOTIATE" => "trans",
"HTTP_HOST" => "glu.ttono.us:8007",
"HTTP_REFERER" => "http://www.google.com/search?q=glu.ttono.us",
"HTTP_FROM" => "googlebot",
"SERVER_PROTOCOL" => "HTTP/1.1",
"REDIRECT_URI" => "/dispatch.fcgi",
"SCRIPT_NAME" => "/dispatch.fcgi",
"SERVER_ADDR" => "207.7.108.53",
"REMOTE_ADDR" => "207.7.108.53",
"REMOTE_HOST" => "google.com",
"REMOTE_IDENT" => "kevin",
"REMOTE_USER" => "kevin",
"SERVER_SOFTWARE" => "lighttpd/1.4.5",
"HTTP_COOKIE" => "_session_id=c84ace84796670c052c6ceb2451fb0f2; is_admin=yes",
"HTTP_X_FORWARDED_SERVER" => "glu.ttono.us",
"REQUEST_URI" => "/admin",
"DOCUMENT_ROOT" => "/home/kevinc/sites/typo/public",
"PATH_TRANSLATED" => "/home/kevinc/sites/typo/public/homepage/",
"SERVER_PORT" => "8007",
"QUERY_STRING" => "",
"REMOTE_PORT" => "63137",
"GATEWAY_INTERFACE" => "CGI/1.1",
"HTTP_X_FORWARDED_FOR" => "65.88.180.234",
"HTTP_ACCEPT" => "*/*",
"SCRIPT_FILENAME" => "/home/kevinc/sites/typo/public/dispatch.fcgi",
"REDIRECT_STATUS" => "200",
"REQUEST_METHOD" => "GET"
}
# some Nokia phone browsers omit the space after the semicolon separator.
# some developers have grown accustomed to using comma in cookie values.
@alt_cookie_fmt_request_hash = {"HTTP_COOKIE"=>"_session_id=c84ace847,96670c052c6ceb2451fb0f2;is_admin=yes"}
@fake_cgi = Struct.new(:env_table).new(@request_hash)
@request = ActionController::CgiRequest.new(@fake_cgi)
@cgi = CGI.new
@cgi.stubs(:env_table).returns(@request_hash)
@request = ActionController::CgiRequest.new(@cgi)
end
def default_test; end
end
class CgiRequestTest < BaseCgiTest
def test_proxy_request
assert_equal 'glu.ttono.us', @request.host_with_port
@@ -71,6 +111,37 @@ class CgiRequestTest < BaseCgiTest
assert_equal "[2001:1234:5678:9abc:def0::dead:beef]", @request.host
end
def test_cgi_environment_variables
assert_equal "Basic", @request.auth_type
assert_equal 0, @request.content_length
assert_equal nil, @request.content_type
assert_equal "CGI/1.1", @request.gateway_interface
assert_equal "*/*", @request.accept
assert_equal "UTF-8", @request.accept_charset
assert_equal "gzip, deflate", @request.accept_encoding
assert_equal "en", @request.accept_language
assert_equal "no-cache, max-age=0", @request.cache_control
assert_equal "googlebot", @request.from
assert_equal "glu.ttono.us", @request.host
assert_equal "trans", @request.negotiate
assert_equal "no-cache", @request.pragma
assert_equal "http://www.google.com/search?q=glu.ttono.us", @request.referer
assert_equal "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en)", @request.user_agent
assert_equal "/homepage/", @request.path_info
assert_equal "/home/kevinc/sites/typo/public/homepage/", @request.path_translated
assert_equal "", @request.query_string
assert_equal "207.7.108.53", @request.remote_addr
assert_equal "google.com", @request.remote_host
assert_equal "kevin", @request.remote_ident
assert_equal "kevin", @request.remote_user
assert_equal :get, @request.request_method
assert_equal "/dispatch.fcgi", @request.script_name
assert_equal "glu.ttono.us:8007", @request.server_name
assert_equal 8007, @request.server_port
assert_equal "HTTP/1.1", @request.server_protocol
assert_equal "lighttpd", @request.server_software
end
def test_cookie_syntax_resilience
cookies = CGI::Cookie::parse(@request_hash["HTTP_COOKIE"]);
assert_equal ["c84ace84796670c052c6ceb2451fb0f2"], cookies["_session_id"], cookies.inspect
@@ -82,7 +153,6 @@ class CgiRequestTest < BaseCgiTest
end
end
class CgiRequestParamsParsingTest < BaseCgiTest
def test_doesnt_break_when_content_type_has_charset
data = 'flamenco=love'
@@ -98,7 +168,6 @@ class CgiRequestParamsParsingTest < BaseCgiTest
end
end
class CgiRequestNeedsRewoundTest < BaseCgiTest
def test_body_should_be_rewound
data = 'foo'
@@ -119,8 +188,8 @@ uses_mocha 'CGI Response' do
class CgiResponseTest < BaseCgiTest
def setup
super
@fake_cgi.expects(:header).returns("HTTP/1.0 200 OK\nContent-Type: text/html\n")
@response = ActionController::CgiResponse.new(@fake_cgi)
@cgi.expects(:header).returns("HTTP/1.0 200 OK\nContent-Type: text/html\n")
@response = ActionController::CgiResponse.new(@cgi)
@output = StringIO.new('')
end
@@ -132,7 +201,7 @@ uses_mocha 'CGI Response' do
end
def test_head_request
@fake_cgi.env_table['REQUEST_METHOD'] = 'HEAD'
@cgi.env_table['REQUEST_METHOD'] = 'HEAD'
@response.body = "Hello, World!"
@response.out(@output)

View File

@@ -119,7 +119,7 @@ class ComponentsTest < Test::Unit::TestCase
def test_component_redirect_redirects
get :calling_redirected
assert_redirected_to :action => "being_called"
assert_redirected_to :controller=>"callee", :action => "being_called"
end
def test_component_multiple_redirect_redirects

View File

@@ -13,12 +13,12 @@ class ContentTypeController < ActionController::Base
def render_content_type_from_render
render :text => "hello world!", :content_type => Mime::RSS
end
def render_charset_from_body
response.charset = "utf-16"
render :text => "hello world!"
end
def render_default_for_rhtml
end
@@ -45,8 +45,6 @@ class ContentTypeController < ActionController::Base
def rescue_action(e) raise end
end
ContentTypeController.view_paths = [ File.dirname(__FILE__) + "/../fixtures/" ]
class ContentTypeTest < Test::Unit::TestCase
def setup
@controller = ContentTypeController.new
@@ -68,7 +66,7 @@ class ContentTypeTest < Test::Unit::TestCase
def test_render_changed_charset_default
ContentTypeController.default_charset = "utf-16"
get :render_defaults
assert_equal "utf-16", @response.charset
assert_equal "utf-16", @response.charset
assert_equal Mime::HTML, @response.content_type
ContentTypeController.default_charset = "utf-8"
end
@@ -76,13 +74,13 @@ class ContentTypeTest < Test::Unit::TestCase
def test_content_type_from_body
get :render_content_type_from_body
assert_equal "application/rss+xml", @response.content_type
assert_equal "utf-8", @response.charset
assert_equal "utf-8", @response.charset
end
def test_content_type_from_render
get :render_content_type_from_render
assert_equal "application/rss+xml", @response.content_type
assert_equal "utf-8", @response.charset
assert_equal "utf-8", @response.charset
end
def test_charset_from_body
@@ -94,27 +92,41 @@ class ContentTypeTest < Test::Unit::TestCase
def test_default_for_rhtml
get :render_default_for_rhtml
assert_equal Mime::HTML, @response.content_type
assert_equal "utf-8", @response.charset
assert_equal "utf-8", @response.charset
end
def test_default_for_rxml
get :render_default_for_rxml
assert_equal Mime::XML, @response.content_type
assert_equal "utf-8", @response.charset
assert_equal "utf-8", @response.charset
end
def test_default_for_rjs
xhr :post, :render_default_for_rjs
assert_equal Mime::JS, @response.content_type
assert_equal "utf-8", @response.charset
assert_equal "utf-8", @response.charset
end
def test_change_for_rxml
get :render_change_for_rxml
assert_equal Mime::HTML, @response.content_type
assert_equal "utf-8", @response.charset
assert_equal "utf-8", @response.charset
end
end
class AcceptBasedContentTypeTest < ActionController::TestCase
tests ContentTypeController
def setup
ActionController::Base.use_accept_header = true
end
def teardown
ActionController::Base.use_accept_header = false
end
def test_render_default_content_types_for_respond_to
@request.env["HTTP_ACCEPT"] = Mime::HTML.to_s
get :render_default_content_types_for_respond_to
@@ -130,7 +142,7 @@ class ContentTypeTest < Test::Unit::TestCase
get :render_default_content_types_for_respond_to
assert_equal Mime::XML, @response.content_type
end
def test_render_default_content_types_for_respond_to_with_overwrite
@request.env["HTTP_ACCEPT"] = Mime::RSS.to_s
get :render_default_content_types_for_respond_to

View File

@@ -1,45 +0,0 @@
require 'abstract_unit'
class CustomHandler < ActionView::TemplateHandler
def initialize( view )
@view = view
end
def render( template )
[ template.source,
template.locals,
@view ]
end
end
class CustomHandlerTest < Test::Unit::TestCase
def setup
ActionView::Template.register_template_handler "foo", CustomHandler
ActionView::Template.register_template_handler :foo2, CustomHandler
@view = ActionView::Base.new
end
def test_custom_render
template = ActionView::InlineTemplate.new(@view, "hello <%= one %>", { :one => "two" }, "foo")
result = @view.render_template(template)
assert_equal(
[ "hello <%= one %>", { :one => "two" }, @view ],
result )
end
def test_custom_render2
template = ActionView::InlineTemplate.new(@view, "hello <%= one %>", { :one => "two" }, "foo2")
result = @view.render_template(template)
assert_equal(
[ "hello <%= one %>", { :one => "two" }, @view ],
result )
end
def test_unhandled_extension
# uses the ERb handler by default if the extension isn't recognized
template = ActionView::InlineTemplate.new(@view, "hello <%= one %>", { :one => "two" }, "bar")
result = @view.render_template(template)
assert_equal "hello two", result
end
end

View File

@@ -2,7 +2,6 @@ require 'abstract_unit'
class DeprecatedBaseMethodsTest < Test::Unit::TestCase
class Target < ActionController::Base
def home_url(greeting)
"http://example.com/#{greeting}"
end
@@ -14,8 +13,6 @@ class DeprecatedBaseMethodsTest < Test::Unit::TestCase
def rescue_action(e) raise e end
end
Target.view_paths = [ File.dirname(__FILE__) + "/../../fixtures" ]
def setup
@request = ActionController::TestRequest.new
@response = ActionController::TestResponse.new

View File

@@ -120,4 +120,29 @@ HTML
assert doc.find(:tag => "div", :attributes => { :id => "map" }, :content => "")
assert doc.find(:tag => "div", :attributes => { :id => "map" }, :content => nil)
end
def test_parse_invalid_document
assert_nothing_raised do
doc = HTML::Document.new("<html>
<table>
<tr>
<td style=\"color: #FFFFFF; height: 17px; onclick=\"window.location.href='http://www.rmeinc.com/about_rme.aspx'\" style=\"cursor:pointer; height: 17px;\"; nowrap onclick=\"window.location.href='http://www.rmeinc.com/about_rme.aspx'\" onmouseout=\"this.bgColor='#0066cc'; this.style.color='#FFFFFF'\" onmouseover=\"this.bgColor='#ffffff'; this.style.color='#0033cc'\">About Us</td>
</tr>
</table>
</html>")
end
end
def test_invalid_document_raises_exception_when_strict
assert_raises RuntimeError do
doc = HTML::Document.new("<html>
<table>
<tr>
<td style=\"color: #FFFFFF; height: 17px; onclick=\"window.location.href='http://www.rmeinc.com/about_rme.aspx'\" style=\"cursor:pointer; height: 17px;\"; nowrap onclick=\"window.location.href='http://www.rmeinc.com/about_rme.aspx'\" onmouseout=\"this.bgColor='#0066cc'; this.style.color='#FFFFFF'\" onmouseover=\"this.bgColor='#ffffff'; this.style.color='#0033cc'\">About Us</td>
</tr>
</table>
</html>", true)
end
end
end

View File

@@ -34,8 +34,8 @@ end
class MabView < ActionView::TemplateHandler
def initialize(view)
end
def render(template)
def render(template, local_assigns)
template.source
end
end
@@ -63,6 +63,7 @@ class LayoutAutoDiscoveryTest < Test::Unit::TestCase
end
def test_third_party_template_library_auto_discovers_layout
ThirdPartyTemplateLibraryController.view_paths.reload!
@controller = ThirdPartyTemplateLibraryController.new
get :hello
assert_equal 'layouts/third_party_template_library', @controller.active_layout

View File

@@ -107,7 +107,7 @@ class RespondToController < ActionController::Base
type.any(:js, :xml) { render :text => "Either JS or XML" }
end
end
def handle_any_any
respond_to do |type|
type.html { render :text => 'HTML' }
@@ -120,12 +120,12 @@ class RespondToController < ActionController::Base
type.html
type.js
end
end
def iphone_with_html_response_type
end
def iphone_with_html_response_type
Mime::Type.register_alias("text/html", :iphone)
request.format = :iphone if request.env["HTTP_ACCEPT"] == "text/iphone"
respond_to do |type|
type.html { @type = "Firefox" }
type.iphone { @type = "iPhone" }
@@ -138,7 +138,7 @@ class RespondToController < ActionController::Base
def iphone_with_html_response_type_without_layout
Mime::Type.register_alias("text/html", :iphone)
request.format = "iphone" if request.env["HTTP_ACCEPT"] == "text/iphone"
respond_to do |type|
type.html { @type = "Firefox"; render :action => "iphone_with_html_response_type" }
type.iphone { @type = "iPhone" ; render :action => "iphone_with_html_response_type" }
@@ -162,10 +162,9 @@ class RespondToController < ActionController::Base
end
end
RespondToController.view_paths = [ File.dirname(__FILE__) + "/../fixtures/" ]
class MimeControllerTest < Test::Unit::TestCase
def setup
ActionController::Base.use_accept_header = true
@request = ActionController::TestRequest.new
@response = ActionController::TestResponse.new
@@ -173,6 +172,10 @@ class MimeControllerTest < Test::Unit::TestCase
@request.host = "www.example.com"
end
def teardown
ActionController::Base.use_accept_header = false
end
def test_html
@request.env["HTTP_ACCEPT"] = "text/html"
get :js_or_html
@@ -247,7 +250,7 @@ class MimeControllerTest < Test::Unit::TestCase
get :just_xml
assert_equal 'XML', @response.body
end
def test_using_defaults
@request.env["HTTP_ACCEPT"] = "*/*"
get :using_defaults
@@ -347,12 +350,12 @@ class MimeControllerTest < Test::Unit::TestCase
get :handle_any_any
assert_equal 'HTML', @response.body
end
def test_handle_any_any_parameter_format
get :handle_any_any, {:format=>'html'}
assert_equal 'HTML', @response.body
end
def test_handle_any_any_explicit_html
@request.env["HTTP_ACCEPT"] = "text/html"
get :handle_any_any
@@ -364,7 +367,7 @@ class MimeControllerTest < Test::Unit::TestCase
get :handle_any_any
assert_equal 'Whatever you ask for, I got it', @response.body
end
def test_handle_any_any_xml
@request.env["HTTP_ACCEPT"] = "text/xml"
get :handle_any_any
@@ -445,31 +448,31 @@ class MimeControllerTest < Test::Unit::TestCase
get :using_defaults, :format => "xml"
assert_equal "using_defaults - xml", @response.body
end
end
def test_format_with_custom_response_type
get :iphone_with_html_response_type
assert_equal '<html><div id="html">Hello future from Firefox!</div></html>', @response.body
assert_equal '<html><div id="html">Hello future from Firefox!</div></html>', @response.body
get :iphone_with_html_response_type, :format => "iphone"
assert_equal "text/html", @response.content_type
assert_equal '<html><div id="iphone">Hello iPhone future from iPhone!</div></html>', @response.body
end
end
def test_format_with_custom_response_type_and_request_headers
@request.env["HTTP_ACCEPT"] = "text/iphone"
get :iphone_with_html_response_type
assert_equal '<html><div id="iphone">Hello iPhone future from iPhone!</div></html>', @response.body
assert_equal "text/html", @response.content_type
end
end
def test_format_with_custom_response_type_and_request_headers_with_only_one_layout_present
get :iphone_with_html_response_type_without_layout
assert_equal '<html><div id="html_missing">Hello future from Firefox!</div></html>', @response.body
assert_equal '<html><div id="html_missing">Hello future from Firefox!</div></html>', @response.body
@request.env["HTTP_ACCEPT"] = "text/iphone"
assert_raises(ActionView::MissingTemplate) { get :iphone_with_html_response_type_without_layout }
end
end
end
class AbstractPostController < ActionController::Base
@@ -497,7 +500,7 @@ class PostController < AbstractPostController
end
end
class SuperPostController < PostController
class SuperPostController < PostController
def index
respond_to do |type|
type.html
@@ -514,25 +517,24 @@ class MimeControllerLayoutsTest < Test::Unit::TestCase
@controller = PostController.new
@request.host = "www.example.com"
end
def test_missing_layout_renders_properly
get :index
assert_equal '<html><div id="html">Hello Firefox</div></html>', @response.body
assert_equal '<html><div id="html">Hello Firefox</div></html>', @response.body
@request.env["HTTP_ACCEPT"] = "text/iphone"
get :index
assert_equal 'Hello iPhone', @response.body
end
def test_format_with_inherited_layouts
@controller = SuperPostController.new
get :index
assert_equal 'Super Firefox', @response.body
@request.env["HTTP_ACCEPT"] = "text/iphone"
get :index
assert_equal '<html><div id="super_iphone">Super iPhone</div></html>', @response.body
end
end

View File

@@ -45,11 +45,11 @@ class NewRenderTestController < ActionController::Base
def render_action_hello_world_as_symbol
render :action => :hello_world
end
def render_text_hello_world
render :text => "hello world"
end
def render_text_hello_world_with_layout
@variable_for_layout = ", I'm here!"
render :text => "hello world", :layout => true
@@ -68,7 +68,7 @@ class NewRenderTestController < ActionController::Base
path = File.join(File.dirname(__FILE__), '../fixtures/test/render_file_with_ivar.erb')
render :file => path
end
def render_file_from_template
@secret = 'in the sauce'
@path = File.expand_path(File.join(File.dirname(__FILE__), '../fixtures/test/render_file_with_ivar.erb'))
@@ -76,17 +76,17 @@ class NewRenderTestController < ActionController::Base
def render_file_with_locals
path = File.join(File.dirname(__FILE__), '../fixtures/test/render_file_with_locals.erb')
render :file => path, :locals => {:secret => 'in the sauce'}
render :file => path, :locals => {:secret => 'in the sauce'}
end
def render_file_not_using_full_path
@secret = 'in the sauce'
render :file => 'test/render_file_with_ivar', :use_full_path => true
render :file => 'test/render_file_with_ivar'
end
def render_file_not_using_full_path_with_dot_in_path
@secret = 'in the sauce'
render :file => 'test/dot.directory/render_file_with_ivar', :use_full_path => true
render :file => 'test/dot.directory/render_file_with_ivar'
end
def render_xml_hello
@@ -105,7 +105,7 @@ class NewRenderTestController < ActionController::Base
def layout_test_with_different_layout
render :action => "hello_world", :layout => "standard"
end
def rendering_without_layout
render :action => "hello_world", :layout => false
end
@@ -113,11 +113,11 @@ class NewRenderTestController < ActionController::Base
def layout_overriding_layout
render :action => "hello_world", :layout => "standard"
end
def rendering_nothing_on_layout
render :nothing => true
end
def builder_layout_test
render :action => "hello"
end
@@ -135,9 +135,9 @@ class NewRenderTestController < ActionController::Base
def partial_only_with_layout
render :partial => "partial_only", :layout => true
end
def partial_with_locals
render :partial => "customer", :locals => { :customer => Customer.new("david") }
render :partial => "customer", :locals => { :customer => Customer.new("david") }
end
def partial_with_form_builder
@@ -151,11 +151,15 @@ class NewRenderTestController < ActionController::Base
def partial_collection
render :partial => "customer", :collection => [ Customer.new("david"), Customer.new("mary") ]
end
def partial_collection_with_as
render :partial => "customer_with_var", :collection => [ Customer.new("david"), Customer.new("mary") ], :as => :customer
end
def partial_collection_with_spacer
render :partial => "customer", :spacer_template => "partial_only", :collection => [ Customer.new("david"), Customer.new("mary") ]
end
def partial_collection_with_counter
render :partial => "customer_counter", :collection => [ Customer.new("david"), Customer.new("mary") ]
end
@@ -186,33 +190,33 @@ class NewRenderTestController < ActionController::Base
def empty_partial_collection
render :partial => "customer", :collection => []
end
def partial_with_hash_object
render :partial => "hash_object", :object => {:first_name => "Sam"}
end
def partial_hash_collection
render :partial => "hash_object", :collection => [ {:first_name => "Pratik"}, {:first_name => "Amy"} ]
end
def partial_hash_collection_with_locals
render :partial => "hash_greeting", :collection => [ {:first_name => "Pratik"}, {:first_name => "Amy"} ], :locals => { :greeting => "Hola" }
end
def partial_with_implicit_local_assignment
@customer = Customer.new("Marcel")
render :partial => "customer"
end
def missing_partial
render :partial => 'thisFileIsntHere'
end
def hello_in_a_string
@customers = [ Customer.new("david"), Customer.new("mary") ]
render :text => "How's there? " << render_to_string(:template => "test/list")
end
def render_to_string_with_assigns
@before = "i'm before the render"
render_to_string :text => "foo"
@@ -222,18 +226,18 @@ class NewRenderTestController < ActionController::Base
def render_to_string_with_partial
@partial_only = render_to_string :partial => "partial_only"
@partial_with_locals = render_to_string :partial => "customer", :locals => { :customer => Customer.new("david") }
render :action => "test/hello_world"
end
def render_to_string_with_exception
render_to_string :file => "exception that will not be caught - this will certainly not work", :use_full_path => true
@partial_with_locals = render_to_string :partial => "customer", :locals => { :customer => Customer.new("david") }
render :action => "test/hello_world"
end
def render_to_string_with_exception
render_to_string :file => "exception that will not be caught - this will certainly not work"
end
def render_to_string_with_caught_exception
@before = "i'm before the render"
begin
render_to_string :file => "exception that will be caught- hope my future instance vars still work!", :use_full_path => true
render_to_string :file => "exception that will be caught- hope my future instance vars still work!"
rescue
end
@after = "i'm after the render"
@@ -268,6 +272,10 @@ class NewRenderTestController < ActionController::Base
render :template => "test/hello_world"
end
def render_with_explicit_template_with_locals
render :template => "test/render_file_with_locals", :locals => { :secret => 'area51' }
end
def double_render
render :text => "hello"
render :text => "world"
@@ -282,7 +290,7 @@ class NewRenderTestController < ActionController::Base
render :text => "hello"
redirect_to :action => "double_render"
end
def render_to_string_and_render
@stuff = render_to_string :text => "here is some cached stuff"
render :text => "Hi web users! #{@stuff}"
@@ -329,7 +337,7 @@ class NewRenderTestController < ActionController::Base
def render_with_location
render :xml => "<hello/>", :location => "http://example.com", :status => 201
end
def render_with_object_location
customer = Customer.new("Some guy", 1)
render :xml => "<customer/>", :location => customer_url(customer), :status => :created
@@ -341,12 +349,12 @@ class NewRenderTestController < ActionController::Base
"<i-am-xml/>"
end
end.new
render :xml => to_xmlable
end
helper NewRenderTestHelper
helper do
helper do
def rjs_helper_method(value)
page.visual_effect :highlight, value
end
@@ -383,7 +391,7 @@ class NewRenderTestController < ActionController::Base
page.visual_effect :highlight, 'balance'
end
end
def update_page_with_instance_variables
@money = '$37,000,000.00'
@div_id = 'balance'
@@ -426,12 +434,12 @@ class NewRenderTestController < ActionController::Base
def render_using_layout_around_block_in_main_layout_and_within_content_for_layout
render :action => "using_layout_around_block"
end
def rescue_action(e) raise end
private
def determine_layout
case action_name
case action_name
when "hello_world", "layout_test", "rendering_without_layout",
"rendering_nothing_on_layout", "render_text_hello_world",
"render_text_hello_world_with_layout",
@@ -443,7 +451,7 @@ class NewRenderTestController < ActionController::Base
"render_js_with_explicit_template",
"render_js_with_explicit_action_template",
"delete_with_js", "update_page", "update_page_with_instance_variables"
"layouts/standard"
when "builder_layout_test"
"layouts/builder"
@@ -457,9 +465,6 @@ class NewRenderTestController < ActionController::Base
end
end
NewRenderTestController.view_paths = [ File.dirname(__FILE__) + "/../fixtures/" ]
Fun::GamesController.view_paths = [ File.dirname(__FILE__) + "/../fixtures/" ]
class NewRenderTest < Test::Unit::TestCase
def setup
@controller = NewRenderTestController.new
@@ -481,6 +486,11 @@ class NewRenderTest < Test::Unit::TestCase
assert_equal "<html>Hello world!</html>", @response.body
end
def test_renders_default_template_for_missing_action
get :'hyphen-ated'
assert_template 'test/hyphen-ated'
end
def test_do_with_render
get :render_hello_world
assert_template "test/hello_world"
@@ -527,7 +537,7 @@ class NewRenderTest < Test::Unit::TestCase
end
def test_render_file_not_using_full_path
get :render_file_not_using_full_path
get :render_file_not_using_full_path
assert_equal "The secret is in the sauce\n", @response.body
end
@@ -540,7 +550,7 @@ class NewRenderTest < Test::Unit::TestCase
get :render_file_with_locals
assert_equal "The secret is in the sauce\n", @response.body
end
def test_render_file_from_template
get :render_file_from_template
assert_equal "The secret is in the sauce\n", @response.body
@@ -597,8 +607,7 @@ EOS
end
def test_render_with_default_from_accept_header
@request.env["HTTP_ACCEPT"] = "text/javascript"
get :greeting
xhr :get, :greeting
assert_equal "$(\"body\").visualEffect(\"highlight\");", @response.body
end
@@ -661,7 +670,7 @@ EOS
assert_not_deprecated { get :hello_in_a_string }
assert_equal "How's there? goodbyeHello: davidHello: marygoodbye\n", @response.body
end
def test_render_to_string_doesnt_break_assigns
get :render_to_string_with_assigns
assert_equal "i'm before the render", assigns(:before)
@@ -672,12 +681,12 @@ EOS
get :render_to_string_with_partial
assert_equal "only partial", assigns(:partial_only)
assert_equal "Hello: david", assigns(:partial_with_locals)
end
end
def test_bad_render_to_string_still_throws_exception
assert_raises(ActionView::MissingTemplate) { get :render_to_string_with_exception }
end
def test_render_to_string_that_throws_caught_exception_doesnt_break_assigns
assert_nothing_raised { get :render_to_string_with_caught_exception }
assert_equal "i'm before the render", assigns(:before)
@@ -715,7 +724,7 @@ EOS
def test_render_and_redirect
assert_raises(ActionController::DoubleRenderError) { get :render_and_redirect }
end
# specify the one exception to double render rule - render_to_string followed by render
def test_render_to_string_and_render
get :render_to_string_and_render
@@ -736,7 +745,7 @@ EOS
get :partials_list
assert_equal "goodbyeHello: davidHello: marygoodbye\n", @response.body
end
def test_partial_with_locals
get :partial_with_locals
assert_equal "Hello: david", @response.body
@@ -758,17 +767,22 @@ EOS
get :partial_collection
assert_equal "Hello: davidHello: mary", @response.body
end
def test_partial_collection_with_as
get :partial_collection_with_as
assert_equal "david david davidmary mary mary", @response.body
end
def test_partial_collection_with_counter
get :partial_collection_with_counter
assert_equal "david0mary1", @response.body
end
def test_partial_collection_with_locals
get :partial_collection_with_locals
assert_equal "Bonjour: davidBonjour: mary", @response.body
end
def test_partial_collection_with_spacer
get :partial_collection_with_spacer
assert_equal "Hello: davidonly partialHello: mary", @response.body
@@ -793,12 +807,12 @@ EOS
get :partial_with_hash_object
assert_equal "Sam\nmaS\n", @response.body
end
def test_hash_partial_collection
get :partial_hash_collection
assert_equal "Pratik\nkitarP\nAmy\nymA\n", @response.body
end
def test_partial_hash_collection_with_locals
get :partial_hash_collection_with_locals
assert_equal "Hola: PratikHola: Amy", @response.body
@@ -808,25 +822,30 @@ EOS
get :partial_with_implicit_local_assignment
assert_equal "Hello: Marcel", @response.body
end
def test_render_missing_partial_template
assert_raises(ActionView::MissingTemplate) do
get :missing_partial
end
end
def test_render_text_with_assigns
get :render_text_with_assigns
assert_equal "world", assigns["hello"]
end
def test_template_with_locals
get :render_with_explicit_template_with_locals
assert_equal "The secret is area51\n", @response.body
end
def test_update_page
get :update_page
assert_template nil
assert_equal 'text/javascript; charset=utf-8', @response.headers['type']
assert_equal 2, @response.body.split($/).length
end
def test_update_page_with_instance_variables
get :update_page_with_instance_variables
assert_template nil
@@ -834,7 +853,7 @@ EOS
assert_match /balance/, @response.body
assert_match /\$37/, @response.body
end
def test_yield_content_for
assert_not_deprecated { get :yield_content_for }
assert_equal "<title>Putting stuff in the title!</title>\n\nGreat stuff!\n", @response.body
@@ -906,12 +925,12 @@ EOS
get :render_with_location
assert_equal "http://example.com", @response.headers["Location"]
end
def test_rendering_xml_should_call_to_xml_if_possible
get :render_with_to_xml
assert_equal "<i-am-xml/>", @response.body
end
def test_rendering_with_object_location_should_set_header_with_url_for
ActionController::Routing::Routes.draw do |map|
map.resources :customers
@@ -941,5 +960,4 @@ EOS
get :render_using_layout_around_block_in_main_layout_and_within_content_for_layout
assert_equal "Before (Anthony)\nInside from first block in layout\nAfter\nBefore (David)\nInside from block\nAfter\nBefore (Ramm)\nInside from second block in layout\nAfter\n", @response.body
end
end

View File

@@ -118,6 +118,39 @@ uses_mocha 'polymorphic URL helpers' do
polymorphic_url([:site, :admin, @article, @response, @tag])
end
def test_nesting_with_array_ending_in_singleton_resource
expects(:article_response_url).with(@article)
polymorphic_url([@article, :response])
end
def test_nesting_with_array_containing_singleton_resource
@tag = Tag.new
@tag.save
expects(:article_response_tag_url).with(@article, @tag)
polymorphic_url([@article, :response, @tag])
end
def test_nesting_with_array_containing_namespace_and_singleton_resource
@tag = Tag.new
@tag.save
expects(:admin_article_response_tag_url).with(@article, @tag)
polymorphic_url([:admin, @article, :response, @tag])
end
def test_nesting_with_array_containing_singleton_resource_and_format
@tag = Tag.new
@tag.save
expects(:formatted_article_response_tag_url).with(@article, @tag, :pdf)
formatted_polymorphic_url([@article, :response, @tag, :pdf])
end
def test_nesting_with_array_containing_singleton_resource_and_format_option
@tag = Tag.new
@tag.save
expects(:article_response_tag_url).with(@article, @tag, :pdf)
polymorphic_url([@article, :response, @tag], :format => :pdf)
end
# TODO: Needs to be updated to correctly know about whether the object is in a hash or not
def xtest_with_hash
expects(:article_url).with(@article)

View File

@@ -7,22 +7,33 @@ class BaseRackTest < Test::Unit::TestCase
"HTTP_MAX_FORWARDS" => "10",
"SERVER_NAME" => "glu.ttono.us:8007",
"FCGI_ROLE" => "RESPONDER",
"AUTH_TYPE" => "Basic",
"HTTP_X_FORWARDED_HOST" => "glu.ttono.us",
"HTTP_ACCEPT_CHARSET" => "UTF-8",
"HTTP_ACCEPT_ENCODING" => "gzip, deflate",
"HTTP_CACHE_CONTROL" => "no-cache, max-age=0",
"HTTP_PRAGMA" => "no-cache",
"HTTP_USER_AGENT" => "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en)",
"PATH_INFO" => "",
"PATH_INFO" => "/homepage/",
"HTTP_ACCEPT_LANGUAGE" => "en",
"HTTP_NEGOTIATE" => "trans",
"HTTP_HOST" => "glu.ttono.us:8007",
"HTTP_REFERER" => "http://www.google.com/search?q=glu.ttono.us",
"HTTP_FROM" => "googlebot",
"SERVER_PROTOCOL" => "HTTP/1.1",
"REDIRECT_URI" => "/dispatch.fcgi",
"SCRIPT_NAME" => "/dispatch.fcgi",
"SERVER_ADDR" => "207.7.108.53",
"REMOTE_ADDR" => "207.7.108.53",
"REMOTE_HOST" => "google.com",
"REMOTE_IDENT" => "kevin",
"REMOTE_USER" => "kevin",
"SERVER_SOFTWARE" => "lighttpd/1.4.5",
"HTTP_COOKIE" => "_session_id=c84ace84796670c052c6ceb2451fb0f2; is_admin=yes",
"HTTP_X_FORWARDED_SERVER" => "glu.ttono.us",
"REQUEST_URI" => "/admin",
"DOCUMENT_ROOT" => "/home/kevinc/sites/typo/public",
"PATH_TRANSLATED" => "/home/kevinc/sites/typo/public/homepage/",
"SERVER_PORT" => "8007",
"QUERY_STRING" => "",
"REMOTE_PORT" => "63137",
@@ -42,7 +53,6 @@ class BaseRackTest < Test::Unit::TestCase
def default_test; end
end
class RackRequestTest < BaseRackTest
def test_proxy_request
assert_equal 'glu.ttono.us', @request.host_with_port
@@ -99,6 +109,37 @@ class RackRequestTest < BaseRackTest
assert_equal "[2001:1234:5678:9abc:def0::dead:beef]", @request.host
end
def test_cgi_environment_variables
assert_equal "Basic", @request.auth_type
assert_equal 0, @request.content_length
assert_equal nil, @request.content_type
assert_equal "CGI/1.1", @request.gateway_interface
assert_equal "*/*", @request.accept
assert_equal "UTF-8", @request.accept_charset
assert_equal "gzip, deflate", @request.accept_encoding
assert_equal "en", @request.accept_language
assert_equal "no-cache, max-age=0", @request.cache_control
assert_equal "googlebot", @request.from
assert_equal "glu.ttono.us", @request.host
assert_equal "trans", @request.negotiate
assert_equal "no-cache", @request.pragma
assert_equal "http://www.google.com/search?q=glu.ttono.us", @request.referer
assert_equal "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en)", @request.user_agent
assert_equal "/homepage/", @request.path_info
assert_equal "/home/kevinc/sites/typo/public/homepage/", @request.path_translated
assert_equal "", @request.query_string
assert_equal "207.7.108.53", @request.remote_addr
assert_equal "google.com", @request.remote_host
assert_equal "kevin", @request.remote_ident
assert_equal "kevin", @request.remote_user
assert_equal :get, @request.request_method
assert_equal "/dispatch.fcgi", @request.script_name
assert_equal "glu.ttono.us:8007", @request.server_name
assert_equal 8007, @request.server_port
assert_equal "HTTP/1.1", @request.server_protocol
assert_equal "lighttpd", @request.server_software
end
def test_cookie_syntax_resilience
cookies = @request.cookies
assert_equal ["c84ace84796670c052c6ceb2451fb0f2"], cookies["_session_id"], cookies.inspect
@@ -110,7 +151,6 @@ class RackRequestTest < BaseRackTest
end
end
class RackRequestParamsParsingTest < BaseRackTest
def test_doesnt_break_when_content_type_has_charset
data = 'flamenco=love'
@@ -126,7 +166,6 @@ class RackRequestParamsParsingTest < BaseRackTest
end
end
class RackRequestNeedsRewoundTest < BaseRackTest
def test_body_should_be_rewound
data = 'foo'
@@ -143,7 +182,6 @@ class RackRequestNeedsRewoundTest < BaseRackTest
end
end
class RackResponseTest < BaseRackTest
def setup
super
@@ -155,7 +193,7 @@ class RackResponseTest < BaseRackTest
@response.body = "Hello, World!"
status, headers, body = @response.out(@output)
assert_equal 200, status
assert_equal "200 OK", status
assert_equal({"Content-Type" => "text/html", "Cache-Control" => "no-cache", "Set-Cookie" => []}, headers)
parts = []
@@ -169,7 +207,7 @@ class RackResponseTest < BaseRackTest
end
status, headers, body = @response.out(@output)
assert_equal 200, status
assert_equal "200 OK", status
assert_equal({"Content-Type" => "text/html", "Cache-Control" => "no-cache", "Set-Cookie" => []}, headers)
parts = []
@@ -184,7 +222,7 @@ class RackResponseTest < BaseRackTest
@response.body = "Hello, World!"
status, headers, body = @response.out(@output)
assert_equal 200, status
assert_equal "200 OK", status
assert_equal({
"Content-Type" => "text/html",
"Cache-Control" => "no-cache",

View File

@@ -168,21 +168,6 @@ class RedirectTest < Test::Unit::TestCase
assert_redirected_to :action => "other_host", :only_path => false, :host => 'other.test.host'
end
def test_redirect_error_with_pretty_diff
get :host_redirect
assert_response :redirect
begin
assert_redirected_to :action => "other_host", :only_path => true
rescue Test::Unit::AssertionFailedError => err
expected_msg, redirection_msg, diff_msg = err.message.scan(/<\{[^\}]+\}>/).collect { |s| s[2..-3] }
assert_match %r("only_path"=>false), redirection_msg
assert_match %r("host"=>"other.test.host"), redirection_msg
assert_match %r("action"=>"other_host"), redirection_msg
assert_match %r("only_path"=>false), diff_msg
assert_match %r("host"=>"other.test.host"), diff_msg
end
end
def test_module_redirect
get :module_redirect
assert_response :redirect
@@ -235,9 +220,16 @@ class RedirectTest < Test::Unit::TestCase
get :redirect_to_existing_record
assert_equal "http://test.host/workshops/5", redirect_to_url
assert_redirected_to Workshop.new(5, false)
get :redirect_to_new_record
assert_equal "http://test.host/workshops", redirect_to_url
assert_redirected_to Workshop.new(5, true)
end
def test_redirect_with_partial_params
get :module_redirect
assert_redirected_to :action => 'hello_world'
end
def test_redirect_to_nil
@@ -283,7 +275,7 @@ module ModuleTest
def test_module_redirect_using_options
get :module_redirect
assert_response :redirect
assert_redirected_to :controller => 'redirect', :action => "hello_world"
assert_redirected_to :controller => '/redirect', :action => "hello_world"
end
end
end

View File

@@ -23,11 +23,11 @@ class TestController < ActionController::Base
def render_hello_world_with_forward_slash
render :template => "/test/hello_world"
end
def render_template_in_top_directory
render :template => 'shared'
end
def render_template_in_top_directory_with_slash
render :template => '/shared'
end
@@ -86,7 +86,7 @@ class TestController < ActionController::Base
def render_nothing_with_appendix
render :text => "appended"
end
def render_invalid_args
render("test/hello")
end
@@ -101,12 +101,7 @@ class TestController < ActionController::Base
end
def render_line_offset
begin
render :inline => '<% raise %>', :locals => {:foo => 'bar'}
rescue => exc
end
line = exc.backtrace.first
render :text => line
render :inline => '<% raise %>', :locals => {:foo => 'bar'}
end
def heading
@@ -171,7 +166,7 @@ class TestController < ActionController::Base
def partial_dot_html
render :partial => 'partial.html.erb'
end
def partial_as_rjs
render :update do |page|
page.replace :foo, :partial => 'partial'
@@ -217,9 +212,6 @@ class TestController < ActionController::Base
end
end
TestController.view_paths = [ File.dirname(__FILE__) + "/../fixtures/" ]
Fun::GamesController.view_paths = [ File.dirname(__FILE__) + "/../fixtures/" ]
class RenderTest < Test::Unit::TestCase
def setup
@request = ActionController::TestRequest.new
@@ -241,23 +233,28 @@ class RenderTest < Test::Unit::TestCase
end
def test_line_offset
get :render_line_offset
line = @response.body
assert(line =~ %r{:(\d+):})
assert_equal "1", $1
begin
get :render_line_offset
flunk "the action should have raised an exception"
rescue RuntimeError => exc
line = exc.backtrace.first
assert(line =~ %r{:(\d+):})
assert_equal "1", $1,
"The line offset is wrong, perhaps the wrong exception has been raised, exception was: #{exc.inspect}"
end
end
def test_render_with_forward_slash
get :render_hello_world_with_forward_slash
assert_template "test/hello_world"
end
def test_render_in_top_directory
get :render_template_in_top_directory
assert_template "shared"
assert_equal "Elastica", @response.body
end
def test_render_in_top_directory_with_slash
get :render_template_in_top_directory_with_slash
assert_template "shared"
@@ -336,11 +333,11 @@ class RenderTest < Test::Unit::TestCase
assert_response 200
assert_equal 'appended', @response.body
end
def test_attempt_to_render_with_invalid_arguments
assert_raises(ActionController::RenderError) { get :render_invalid_args }
end
def test_attempt_to_access_object_method
assert_raises(ActionController::UnknownAction, "No action responded to [clone]") { get :clone }
end
@@ -467,17 +464,17 @@ class RenderTest < Test::Unit::TestCase
get :formatted_html_erb
assert_equal 'formatted html erb', @response.body
end
def test_should_render_formatted_xml_erb_template
get :formatted_xml_erb, :format => :xml
assert_equal '<test>passed formatted xml erb</test>', @response.body
end
def test_should_render_formatted_html_erb_template
get :formatted_xml_erb
assert_equal '<test>passed formatted html erb</test>', @response.body
end
def test_should_render_formatted_html_erb_template_with_faulty_accepts_header
@request.env["HTTP_ACCEPT"] = "image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, appliction/x-shockwave-flash, */*"
get :formatted_xml_erb
@@ -520,7 +517,6 @@ class RenderTest < Test::Unit::TestCase
end
protected
def etag_for(text)
%("#{Digest::MD5.hexdigest(text)}")
end

View File

@@ -386,7 +386,7 @@ class RequestTest < Test::Unit::TestCase
def test_nil_format
@request.instance_eval { @parameters = { :format => nil } }
@request.env["HTTP_ACCEPT"] = "text/javascript"
@request.env["HTTP_X_REQUESTED_WITH"] = "XMLHttpRequest"
assert_equal Mime::JS, @request.format
end
@@ -909,15 +909,21 @@ class LegacyXmlParamsParsingTest < XmlParamsParsingTest
end
class JsonParamsParsingTest < Test::Unit::TestCase
def test_hash_params
person = parse_body({:person => {:name => "David"}}.to_json)[:person]
def test_hash_params_for_application_json
person = parse_body({:person => {:name => "David"}}.to_json,'application/json')[:person]
assert_kind_of Hash, person
assert_equal 'David', person['name']
end
def test_hash_params_for_application_jsonrequest
person = parse_body({:person => {:name => "David"}}.to_json,'application/jsonrequest')[:person]
assert_kind_of Hash, person
assert_equal 'David', person['name']
end
private
def parse_body(body)
env = { 'CONTENT_TYPE' => 'application/json',
def parse_body(body,content_type)
env = { 'CONTENT_TYPE' => content_type,
'CONTENT_LENGTH' => body.size.to_s }
cgi = ActionController::Integration::Session::StubCGI.new(env, body)
ActionController::CgiRequest.new(cgi).request_parameters

View File

@@ -28,18 +28,16 @@ module Backoffice
end
class ResourcesTest < Test::Unit::TestCase
# The assertions in these tests are incompatible with the hash method
# optimisation. This could indicate user level problems
def setup
ActionController::Base.optimise_named_routes = false
end
def tear_down
def teardown
ActionController::Base.optimise_named_routes = true
end
def test_should_arrange_actions
resource = ActionController::Resources::Resource.new(:messages,
:collection => { :rss => :get, :reorder => :post, :csv => :post },
@@ -159,14 +157,14 @@ class ResourcesTest < Test::Unit::TestCase
def test_with_collection_actions_and_name_prefix
actions = { 'a' => :get, 'b' => :put, 'c' => :post, 'd' => :delete }
with_restful_routing :messages, :path_prefix => '/threads/:thread_id', :name_prefix => "thread_", :collection => actions do
assert_restful_routes_for :messages, :path_prefix => 'threads/1/', :name_prefix => 'thread_', :options => { :thread_id => '1' } do |options|
actions.each do |action, method|
assert_recognizes(options.merge(:action => action), :path => "/threads/1/messages/#{action}", :method => method)
end
end
assert_restful_named_routes_for :messages, :path_prefix => 'threads/1/', :name_prefix => 'thread_', :options => { :thread_id => '1' } do |options|
actions.keys.each do |action|
assert_named_route "/threads/1/messages/#{action}", "#{action}_thread_messages_path", :action => action
@@ -177,14 +175,14 @@ class ResourcesTest < Test::Unit::TestCase
def test_with_collection_action_and_name_prefix_and_formatted
actions = { 'a' => :get, 'b' => :put, 'c' => :post, 'd' => :delete }
with_restful_routing :messages, :path_prefix => '/threads/:thread_id', :name_prefix => "thread_", :collection => actions do
assert_restful_routes_for :messages, :path_prefix => 'threads/1/', :name_prefix => 'thread_', :options => { :thread_id => '1' } do |options|
actions.each do |action, method|
assert_recognizes(options.merge(:action => action, :format => 'xml'), :path => "/threads/1/messages/#{action}.xml", :method => method)
end
end
assert_restful_named_routes_for :messages, :path_prefix => 'threads/1/', :name_prefix => 'thread_', :options => { :thread_id => '1' } do |options|
actions.keys.each do |action|
assert_named_route "/threads/1/messages/#{action}.xml", "formatted_#{action}_thread_messages_path", :action => action, :format => 'xml'
@@ -279,7 +277,7 @@ class ResourcesTest < Test::Unit::TestCase
end
end
end
def test_with_new_action_with_name_prefix
with_restful_routing :messages, :new => { :preview => :post }, :path_prefix => '/threads/:thread_id', :name_prefix => 'thread_' do
preview_options = {:action => 'preview', :thread_id => '1'}
@@ -293,7 +291,7 @@ class ResourcesTest < Test::Unit::TestCase
end
end
end
def test_with_formatted_new_action_with_name_prefix
with_restful_routing :messages, :new => { :preview => :post }, :path_prefix => '/threads/:thread_id', :name_prefix => 'thread_' do
preview_options = {:action => 'preview', :thread_id => '1', :format => 'xml'}
@@ -307,7 +305,7 @@ class ResourcesTest < Test::Unit::TestCase
end
end
end
def test_override_new_method
with_restful_routing :messages do
assert_restful_routes_for :messages do |options|
@@ -524,9 +522,9 @@ class ResourcesTest < Test::Unit::TestCase
map.resources :messages, :collection => {:search => :get}, :new => {:preview => :any}, :name_prefix => 'thread_', :path_prefix => '/threads/:thread_id'
map.resource :account, :member => {:login => :get}, :new => {:preview => :any}, :name_prefix => 'admin_', :path_prefix => '/admin'
end
action_separator = ActionController::Base.resource_action_separator
assert_simply_restful_for :messages, :name_prefix => 'thread_', :path_prefix => 'threads/1/', :options => { :thread_id => '1' }
assert_named_route "/threads/1/messages#{action_separator}search", "search_thread_messages_path", {}
assert_named_route "/threads/1/messages/new", "new_thread_message_path", {}
@@ -623,7 +621,7 @@ class ResourcesTest < Test::Unit::TestCase
assert_simply_restful_for :products, :controller => "backoffice/products"
end
end
def test_nested_resources_using_namespace
with_routing do |set|
set.draw do |map|
@@ -795,7 +793,7 @@ class ResourcesTest < Test::Unit::TestCase
yield options[:options] if block_given?
end
def assert_singleton_routes_for(singleton_name, options = {})
options[:options] ||= {}
options[:options][:controller] = options[:controller] || singleton_name.to_s.pluralize
@@ -855,7 +853,7 @@ class ResourcesTest < Test::Unit::TestCase
actual = @controller.send(route, options) rescue $!.class.name
assert_equal expected, actual, "Error on route: #{route}(#{options.inspect})"
end
def assert_resource_methods(expected, resource, action_method, method)
assert_equal expected.length, resource.send("#{action_method}_methods")[method].size, "#{resource.send("#{action_method}_methods")[method].inspect}"
expected.each do |action|

View File

@@ -2039,6 +2039,26 @@ uses_mocha 'LegacyRouteSet, Route, RouteSet and RouteLoading' do
Object.send(:remove_const, :Api)
end
def test_namespace_with_path_prefix
Object.const_set(:Api, Module.new { |m| m.const_set(:ProductsController, Class.new) })
set.draw do |map|
map.namespace 'api', :path_prefix => 'prefix' do |api|
api.route 'inventory', :controller => "products", :action => 'inventory'
end
end
request.path = "/prefix/inventory"
request.method = :get
assert_nothing_raised { set.recognize(request) }
assert_equal("api/products", request.path_parameters[:controller])
assert_equal("inventory", request.path_parameters[:action])
ensure
Object.send(:remove_const, :Api)
end
def test_generate_finds_best_fit
set.draw do |map|
map.connect "/people", :controller => "people", :action => "index"

View File

@@ -1,13 +1,11 @@
require 'abstract_unit'
module TestFileUtils
def file_name() File.basename(__FILE__) end
def file_path() File.expand_path(__FILE__) end
def file_data() File.open(file_path, 'rb') { |f| f.read } end
end
class SendFileController < ActionController::Base
include TestFileUtils
layout "layouts/standard" # to make sure layouts don't interfere
@@ -21,8 +19,6 @@ class SendFileController < ActionController::Base
def rescue_action(e) raise end
end
SendFileController.view_paths = [ File.dirname(__FILE__) + "/../fixtures/" ]
class SendFileTest < Test::Unit::TestCase
include TestFileUtils

View File

@@ -566,24 +566,6 @@ XML
assert_raise(RuntimeError) { ActionController::TestUploadedFile.new('non_existent_file') }
end
def test_assert_follow_redirect_to_same_controller
with_foo_routing do |set|
get :redirect_to_same_controller
assert_response :redirect
assert_redirected_to :controller => 'test_test/test', :action => 'test_uri', :id => 5
assert_nothing_raised { follow_redirect }
end
end
def test_assert_follow_redirect_to_different_controller
with_foo_routing do |set|
get :redirect_to_different_controller
assert_response :redirect
assert_redirected_to :controller => 'fail', :id => 5
assert_raise(RuntimeError) { follow_redirect }
end
end
def test_redirect_url_only_cares_about_location_header
get :create
assert_response :created

View File

@@ -1,10 +1,6 @@
require 'abstract_unit'
class ViewLoadPathsTest < Test::Unit::TestCase
LOAD_PATH_ROOT = File.join(File.dirname(__FILE__), '..', 'fixtures')
ActionController::Base.view_paths = [LOAD_PATH_ROOT]
class TestController < ActionController::Base
def self.controller_path() "test" end
def rescue_action(e) raise end
@@ -16,7 +12,7 @@ class ViewLoadPathsTest < Test::Unit::TestCase
private
def add_view_path
prepend_view_path "#{LOAD_PATH_ROOT}/override"
prepend_view_path "#{FIXTURE_LOAD_PATH}/override"
end
end
@@ -47,35 +43,35 @@ class ViewLoadPathsTest < Test::Unit::TestCase
end
def test_template_load_path_was_set_correctly
assert_equal [ LOAD_PATH_ROOT ], @controller.view_paths.map(&:to_s)
assert_equal [FIXTURE_LOAD_PATH], @controller.view_paths
end
def test_controller_appends_view_path_correctly
@controller.append_view_path 'foo'
assert_equal [LOAD_PATH_ROOT, 'foo'], @controller.view_paths.map(&:to_s)
assert_equal [FIXTURE_LOAD_PATH, 'foo'], @controller.view_paths
@controller.append_view_path(%w(bar baz))
assert_equal [LOAD_PATH_ROOT, 'foo', 'bar', 'baz'], @controller.view_paths.map(&:to_s)
assert_equal [FIXTURE_LOAD_PATH, 'foo', 'bar', 'baz'], @controller.view_paths
@controller.append_view_path(LOAD_PATH_ROOT)
assert_equal ['foo', 'bar', 'baz', LOAD_PATH_ROOT], @controller.view_paths.map(&:to_s)
@controller.append_view_path(FIXTURE_LOAD_PATH)
assert_equal ['foo', 'bar', 'baz', FIXTURE_LOAD_PATH], @controller.view_paths
@controller.append_view_path([LOAD_PATH_ROOT])
assert_equal ['foo', 'bar', 'baz', LOAD_PATH_ROOT], @controller.view_paths.map(&:to_s)
@controller.append_view_path([FIXTURE_LOAD_PATH])
assert_equal ['foo', 'bar', 'baz', FIXTURE_LOAD_PATH], @controller.view_paths
end
def test_controller_prepends_view_path_correctly
@controller.prepend_view_path 'baz'
assert_equal ['baz', LOAD_PATH_ROOT], @controller.view_paths.map(&:to_s)
assert_equal ['baz', FIXTURE_LOAD_PATH], @controller.view_paths
@controller.prepend_view_path(%w(foo bar))
assert_equal ['foo', 'bar', 'baz', LOAD_PATH_ROOT], @controller.view_paths.map(&:to_s)
assert_equal ['foo', 'bar', 'baz', FIXTURE_LOAD_PATH], @controller.view_paths
@controller.prepend_view_path(LOAD_PATH_ROOT)
assert_equal [LOAD_PATH_ROOT, 'foo', 'bar', 'baz'], @controller.view_paths.map(&:to_s)
@controller.prepend_view_path(FIXTURE_LOAD_PATH)
assert_equal [FIXTURE_LOAD_PATH, 'foo', 'bar', 'baz'], @controller.view_paths
@controller.prepend_view_path([LOAD_PATH_ROOT])
assert_equal [LOAD_PATH_ROOT, 'foo', 'bar', 'baz'], @controller.view_paths.map(&:to_s)
@controller.prepend_view_path([FIXTURE_LOAD_PATH])
assert_equal [FIXTURE_LOAD_PATH, 'foo', 'bar', 'baz'], @controller.view_paths
end
def test_template_appends_view_path_correctly
@@ -83,10 +79,10 @@ class ViewLoadPathsTest < Test::Unit::TestCase
class_view_paths = TestController.view_paths
@controller.append_view_path 'foo'
assert_equal [LOAD_PATH_ROOT, 'foo'], @controller.view_paths.map(&:to_s)
assert_equal [FIXTURE_LOAD_PATH, 'foo'], @controller.view_paths
@controller.append_view_path(%w(bar baz))
assert_equal [LOAD_PATH_ROOT, 'foo', 'bar', 'baz'], @controller.view_paths.map(&:to_s)
assert_equal [FIXTURE_LOAD_PATH, 'foo', 'bar', 'baz'], @controller.view_paths
assert_equal class_view_paths, TestController.view_paths
end
@@ -95,10 +91,10 @@ class ViewLoadPathsTest < Test::Unit::TestCase
class_view_paths = TestController.view_paths
@controller.prepend_view_path 'baz'
assert_equal ['baz', LOAD_PATH_ROOT], @controller.view_paths.map(&:to_s)
assert_equal ['baz', FIXTURE_LOAD_PATH], @controller.view_paths
@controller.prepend_view_path(%w(foo bar))
assert_equal ['foo', 'bar', 'baz', LOAD_PATH_ROOT], @controller.view_paths.map(&:to_s)
assert_equal ['foo', 'bar', 'baz', FIXTURE_LOAD_PATH], @controller.view_paths
assert_equal class_view_paths, TestController.view_paths
end
@@ -109,7 +105,7 @@ class ViewLoadPathsTest < Test::Unit::TestCase
end
def test_view_paths_override
TestController.prepend_view_path "#{LOAD_PATH_ROOT}/override"
TestController.prepend_view_path "#{FIXTURE_LOAD_PATH}/override"
get :hello_world
assert_response :success
assert_equal "Hello overridden world!", @response.body
@@ -117,7 +113,7 @@ class ViewLoadPathsTest < Test::Unit::TestCase
def test_view_paths_override_for_layouts_in_controllers_with_a_module
@controller = Test::SubController.new
Test::SubController.view_paths = [ "#{LOAD_PATH_ROOT}/override", LOAD_PATH_ROOT, "#{LOAD_PATH_ROOT}/override2" ]
Test::SubController.view_paths = [ "#{FIXTURE_LOAD_PATH}/override", FIXTURE_LOAD_PATH, "#{FIXTURE_LOAD_PATH}/override2" ]
get :hello_world
assert_response :success
assert_equal "layout: Hello overridden world!", @response.body
@@ -140,26 +136,12 @@ class ViewLoadPathsTest < Test::Unit::TestCase
A.view_paths = ['a/path']
assert_equal ['a/path'], A.view_paths.map(&:to_s)
assert_equal ['a/path'], A.view_paths
assert_equal A.view_paths, B.view_paths
assert_equal original_load_paths, C.view_paths
C.view_paths = []
assert_nothing_raised { C.view_paths << 'c/path' }
assert_equal ['c/path'], C.view_paths.map(&:to_s)
end
def test_find_template_file_for_path
assert_equal "test/hello_world.erb", @controller.view_paths.find_template_file_for_path("test/hello_world.erb").to_s
assert_equal "test/hello.builder", @controller.view_paths.find_template_file_for_path("test/hello.builder").to_s
assert_equal nil, @controller.view_paths.find_template_file_for_path("test/missing.erb")
end
def test_view_paths_find_template_file_for_path
assert_equal "test/formatted_html_erb.html.erb", @controller.view_paths.find_template_file_for_path("test/formatted_html_erb.html").to_s
assert_equal "test/formatted_xml_erb.xml.erb", @controller.view_paths.find_template_file_for_path("test/formatted_xml_erb.xml").to_s
assert_equal "test/hello_world.erb", @controller.view_paths.find_template_file_for_path("test/hello_world.html").to_s
assert_equal "test/hello_world.erb", @controller.view_paths.find_template_file_for_path("test/hello_world.xml").to_s
assert_equal nil, @controller.view_paths.find_template_file_for_path("test/missing.html")
assert_equal ['c/path'], C.view_paths
end
end

View File

@@ -0,0 +1 @@
<%= developer.name %>

View File

@@ -0,0 +1 @@
<%= game.name %>

View File

@@ -0,0 +1 @@
<%= game.name %>

View File

@@ -0,0 +1,2 @@
<%= render :inline => 'Some inline content' %>
<% cache do %>Some cached content<% end %>

View File

@@ -0,0 +1 @@
<%= project.name %>

View File

@@ -0,0 +1 @@
// subdir js

View File

@@ -0,0 +1 @@
/* subdir.css */

View File

@@ -0,0 +1 @@
<%= reply.content %>

View File

@@ -0,0 +1 @@
<%= customer.name %> <%= object.name %> <%= customer_with_var.name %>

View File

@@ -0,0 +1 @@
<%= local_assigns.keys.map(&:to_s).sort.join(",") -%>

View File

@@ -1,4 +1,4 @@
xml.html do
xml.p "Hello #{@name}"
xml << render_file("test/greeting")
xml << render("test/greeting")
end

View File

@@ -0,0 +1 @@
Hello world!

View File

@@ -1,4 +1,4 @@
content_for :title do
'Putting stuff in the title!'
end
xml << "\nGreat stuff!"
xml << "\nGreat stuff!"

View File

@@ -83,6 +83,7 @@ class AssetTagHelperTest < ActionView::TestCase
%(javascript_include_tag("common.javascript", "/elsewhere/cools")) => %(<script src="/javascripts/common.javascript" type="text/javascript"></script>\n<script src="/elsewhere/cools.js" type="text/javascript"></script>),
%(javascript_include_tag(:defaults)) => %(<script src="/javascripts/prototype.js" type="text/javascript"></script>\n<script src="/javascripts/effects.js" type="text/javascript"></script>\n<script src="/javascripts/dragdrop.js" type="text/javascript"></script>\n<script src="/javascripts/controls.js" type="text/javascript"></script>\n<script src="/javascripts/application.js" type="text/javascript"></script>),
%(javascript_include_tag(:all)) => %(<script src="/javascripts/prototype.js" type="text/javascript"></script>\n<script src="/javascripts/effects.js" type="text/javascript"></script>\n<script src="/javascripts/dragdrop.js" type="text/javascript"></script>\n<script src="/javascripts/controls.js" type="text/javascript"></script>\n<script src="/javascripts/application.js" type="text/javascript"></script>\n<script src="/javascripts/bank.js" type="text/javascript"></script>\n<script src="/javascripts/robber.js" type="text/javascript"></script>\n<script src="/javascripts/version.1.0.js" type="text/javascript"></script>),
%(javascript_include_tag(:all, :recursive => true)) => %(<script src="/javascripts/prototype.js" type="text/javascript"></script>\n<script src="/javascripts/effects.js" type="text/javascript"></script>\n<script src="/javascripts/dragdrop.js" type="text/javascript"></script>\n<script src="/javascripts/controls.js" type="text/javascript"></script>\n<script src="/javascripts/application.js" type="text/javascript"></script>\n<script src="/javascripts/bank.js" type="text/javascript"></script>\n<script src="/javascripts/robber.js" type="text/javascript"></script>\n<script src="/javascripts/subdir/subdir.js" type="text/javascript"></script>\n<script src="/javascripts/version.1.0.js" type="text/javascript"></script>),
%(javascript_include_tag(:defaults, "test")) => %(<script src="/javascripts/prototype.js" type="text/javascript"></script>\n<script src="/javascripts/effects.js" type="text/javascript"></script>\n<script src="/javascripts/dragdrop.js" type="text/javascript"></script>\n<script src="/javascripts/controls.js" type="text/javascript"></script>\n<script src="/javascripts/test.js" type="text/javascript"></script>\n<script src="/javascripts/application.js" type="text/javascript"></script>),
%(javascript_include_tag("test", :defaults)) => %(<script src="/javascripts/test.js" type="text/javascript"></script>\n<script src="/javascripts/prototype.js" type="text/javascript"></script>\n<script src="/javascripts/effects.js" type="text/javascript"></script>\n<script src="/javascripts/dragdrop.js" type="text/javascript"></script>\n<script src="/javascripts/controls.js" type="text/javascript"></script>\n<script src="/javascripts/application.js" type="text/javascript"></script>)
}
@@ -108,6 +109,7 @@ class AssetTagHelperTest < ActionView::TestCase
%(stylesheet_link_tag("dir/file")) => %(<link href="/stylesheets/dir/file.css" media="screen" rel="stylesheet" type="text/css" />),
%(stylesheet_link_tag("style", :media => "all")) => %(<link href="/stylesheets/style.css" media="all" rel="stylesheet" type="text/css" />),
%(stylesheet_link_tag(:all)) => %(<link href="/stylesheets/bank.css" media="screen" rel="stylesheet" type="text/css" />\n<link href="/stylesheets/robber.css" media="screen" rel="stylesheet" type="text/css" />\n<link href="/stylesheets/version.1.0.css" media="screen" rel="stylesheet" type="text/css" />),
%(stylesheet_link_tag(:all, :recursive => true)) => %(<link href="/stylesheets/bank.css" media="screen" rel="stylesheet" type="text/css" />\n<link href="/stylesheets/robber.css" media="screen" rel="stylesheet" type="text/css" />\n<link href="/stylesheets/subdir/subdir.css" media="screen" rel="stylesheet" type="text/css" />\n<link href="/stylesheets/version.1.0.css" media="screen" rel="stylesheet" type="text/css" />),
%(stylesheet_link_tag(:all, :media => "all")) => %(<link href="/stylesheets/bank.css" media="all" rel="stylesheet" type="text/css" />\n<link href="/stylesheets/robber.css" media="all" rel="stylesheet" type="text/css" />\n<link href="/stylesheets/version.1.0.css" media="all" rel="stylesheet" type="text/css" />),
%(stylesheet_link_tag("random.styles", "/css/stylish")) => %(<link href="/stylesheets/random.styles" media="screen" rel="stylesheet" type="text/css" />\n<link href="/css/stylish.css" media="screen" rel="stylesheet" type="text/css" />),
%(stylesheet_link_tag("http://www.example.com/styles/style")) => %(<link href="http://www.example.com/styles/style.css" media="screen" rel="stylesheet" type="text/css" />)
@@ -333,8 +335,9 @@ class AssetTagHelperTest < ActionView::TestCase
ActionController::Base.asset_host = 'http://a%d.example.com'
ActionController::Base.perform_caching = true
hash = '/javascripts/cache/money.js'.hash % 4
assert_dom_equal(
%(<script src="http://a3.example.com/javascripts/cache/money.js" type="text/javascript"></script>),
%(<script src="http://a#{hash}.example.com/javascripts/cache/money.js" type="text/javascript"></script>),
javascript_include_tag(:all, :cache => "cache/money")
)
@@ -343,6 +346,27 @@ class AssetTagHelperTest < ActionView::TestCase
FileUtils.rm_f(File.join(ActionView::Helpers::AssetTagHelper::JAVASCRIPTS_DIR, 'cache', 'money.js'))
end
def test_caching_javascript_include_tag_with_all_and_recursive_puts_defaults_at_the_start_of_the_file
ENV["RAILS_ASSET_ID"] = ""
ActionController::Base.asset_host = 'http://a0.example.com'
ActionController::Base.perform_caching = true
assert_dom_equal(
%(<script src="http://a0.example.com/javascripts/combined.js" type="text/javascript"></script>),
javascript_include_tag(:all, :cache => "combined", :recursive => true)
)
assert File.exist?(File.join(ActionView::Helpers::AssetTagHelper::JAVASCRIPTS_DIR, 'combined.js'))
assert_equal(
%(// prototype js\n\n// effects js\n\n// dragdrop js\n\n// controls js\n\n// application js\n\n// bank js\n\n// robber js\n\n// subdir js\n\n\n// version.1.0 js),
IO.read(File.join(ActionView::Helpers::AssetTagHelper::JAVASCRIPTS_DIR, 'combined.js'))
)
ensure
FileUtils.rm_f(File.join(ActionView::Helpers::AssetTagHelper::JAVASCRIPTS_DIR, 'combined.js'))
end
def test_caching_javascript_include_tag_with_all_puts_defaults_at_the_start_of_the_file
ENV["RAILS_ASSET_ID"] = ""
ActionController::Base.asset_host = 'http://a0.example.com'
@@ -373,6 +397,11 @@ class AssetTagHelperTest < ActionView::TestCase
javascript_include_tag(:all, :cache => true)
)
assert_dom_equal(
%(<script src="/javascripts/prototype.js" type="text/javascript"></script>\n<script src="/javascripts/effects.js" type="text/javascript"></script>\n<script src="/javascripts/dragdrop.js" type="text/javascript"></script>\n<script src="/javascripts/controls.js" type="text/javascript"></script>\n<script src="/javascripts/application.js" type="text/javascript"></script>\n<script src="/javascripts/bank.js" type="text/javascript"></script>\n<script src="/javascripts/robber.js" type="text/javascript"></script>\n<script src="/javascripts/subdir/subdir.js" type="text/javascript"></script>\n<script src="/javascripts/version.1.0.js" type="text/javascript"></script>),
javascript_include_tag(:all, :cache => true, :recursive => true)
)
assert !File.exist?(File.join(ActionView::Helpers::AssetTagHelper::JAVASCRIPTS_DIR, 'all.js'))
assert_dom_equal(
@@ -380,6 +409,11 @@ class AssetTagHelperTest < ActionView::TestCase
javascript_include_tag(:all, :cache => "money")
)
assert_dom_equal(
%(<script src="/javascripts/prototype.js" type="text/javascript"></script>\n<script src="/javascripts/effects.js" type="text/javascript"></script>\n<script src="/javascripts/dragdrop.js" type="text/javascript"></script>\n<script src="/javascripts/controls.js" type="text/javascript"></script>\n<script src="/javascripts/application.js" type="text/javascript"></script>\n<script src="/javascripts/bank.js" type="text/javascript"></script>\n<script src="/javascripts/robber.js" type="text/javascript"></script>\n<script src="/javascripts/subdir/subdir.js" type="text/javascript"></script>\n<script src="/javascripts/version.1.0.js" type="text/javascript"></script>),
javascript_include_tag(:all, :cache => "money", :recursive => true)
)
assert !File.exist?(File.join(ActionView::Helpers::AssetTagHelper::JAVASCRIPTS_DIR, 'money.js'))
end
@@ -432,6 +466,11 @@ class AssetTagHelperTest < ActionView::TestCase
stylesheet_link_tag(:all, :cache => true)
)
assert_dom_equal(
%(<link href="/stylesheets/bank.css" media="screen" rel="stylesheet" type="text/css" />\n<link href="/stylesheets/robber.css" media="screen" rel="stylesheet" type="text/css" />\n<link href="/stylesheets/subdir/subdir.css" media="screen" rel="stylesheet" type="text/css" />\n<link href="/stylesheets/version.1.0.css" media="screen" rel="stylesheet" type="text/css" />),
stylesheet_link_tag(:all, :cache => true, :recursive => true)
)
assert !File.exist?(File.join(ActionView::Helpers::AssetTagHelper::STYLESHEETS_DIR, 'all.css'))
assert_dom_equal(
@@ -439,6 +478,11 @@ class AssetTagHelperTest < ActionView::TestCase
stylesheet_link_tag(:all, :cache => "money")
)
assert_dom_equal(
%(<link href="/stylesheets/bank.css" media="screen" rel="stylesheet" type="text/css" />\n<link href="/stylesheets/robber.css" media="screen" rel="stylesheet" type="text/css" />\n<link href="/stylesheets/subdir/subdir.css" media="screen" rel="stylesheet" type="text/css" />\n<link href="/stylesheets/version.1.0.css" media="screen" rel="stylesheet" type="text/css" />),
stylesheet_link_tag(:all, :cache => "money", :recursive => true)
)
assert !File.exist?(File.join(ActionView::Helpers::AssetTagHelper::STYLESHEETS_DIR, 'money.css'))
end
end

View File

@@ -1155,6 +1155,30 @@ class DateHelperTest < ActionView::TestCase
assert_dom_equal expected, date_select("post", "written_on", {}, :class => 'selector')
end
def test_date_select_with_html_options_within_fields_for
@post = Post.new
@post.written_on = Date.new(2004, 6, 15)
fields_for :post, @post do |f|
concat f.date_select(:written_on, {}, :class => 'selector')
end
expected = %{<select id="post_written_on_1i" name="post[written_on(1i)]" class="selector">\n}
expected << %{<option value="1999">1999</option>\n<option value="2000">2000</option>\n<option value="2001">2001</option>\n<option value="2002">2002</option>\n<option value="2003">2003</option>\n<option value="2004" selected="selected">2004</option>\n<option value="2005">2005</option>\n<option value="2006">2006</option>\n<option value="2007">2007</option>\n<option value="2008">2008</option>\n<option value="2009">2009</option>\n}
expected << "</select>\n"
expected << %{<select id="post_written_on_2i" name="post[written_on(2i)]" class="selector">\n}
expected << %{<option value="1">January</option>\n<option value="2">February</option>\n<option value="3">March</option>\n<option value="4">April</option>\n<option value="5">May</option>\n<option value="6" selected="selected">June</option>\n<option value="7">July</option>\n<option value="8">August</option>\n<option value="9">September</option>\n<option value="10">October</option>\n<option value="11">November</option>\n<option value="12">December</option>\n}
expected << "</select>\n"
expected << %{<select id="post_written_on_3i" name="post[written_on(3i)]" class="selector">\n}
expected << %{<option value="1">1</option>\n<option value="2">2</option>\n<option value="3">3</option>\n<option value="4">4</option>\n<option value="5">5</option>\n<option value="6">6</option>\n<option value="7">7</option>\n<option value="8">8</option>\n<option value="9">9</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15" selected="selected">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n}
expected << "</select>\n"
assert_dom_equal expected, output_buffer
end
def test_time_select
@post = Post.new
@post.written_on = Time.local(2004, 6, 15, 15, 16, 35)
@@ -1174,6 +1198,21 @@ class DateHelperTest < ActionView::TestCase
assert_dom_equal expected, time_select("post", "written_on")
end
def test_time_select_without_date_hidden_fields
@post = Post.new
@post.written_on = Time.local(2004, 6, 15, 15, 16, 35)
expected = %(<select id="post_written_on_4i" name="post[written_on(4i)]">\n)
0.upto(23) { |i| expected << %(<option value="#{leading_zero_on_single_digits(i)}"#{' selected="selected"' if i == 15}>#{leading_zero_on_single_digits(i)}</option>\n) }
expected << "</select>\n"
expected << " : "
expected << %(<select id="post_written_on_5i" name="post[written_on(5i)]">\n)
0.upto(59) { |i| expected << %(<option value="#{leading_zero_on_single_digits(i)}"#{' selected="selected"' if i == 16}>#{leading_zero_on_single_digits(i)}</option>\n) }
expected << "</select>\n"
assert_dom_equal expected, time_select("post", "written_on", :ignore_date => true)
end
def test_time_select_with_seconds
@post = Post.new
@post.written_on = Time.local(2004, 6, 15, 15, 16, 35)
@@ -1216,6 +1255,29 @@ class DateHelperTest < ActionView::TestCase
assert_dom_equal expected, time_select("post", "written_on", {}, :class => 'selector')
end
def test_time_select_with_html_options_within_fields_for
@post = Post.new
@post.written_on = Time.local(2004, 6, 15, 15, 16, 35)
fields_for :post, @post do |f|
concat f.time_select(:written_on, {}, :class => 'selector')
end
expected = %{<input type="hidden" id="post_written_on_1i" name="post[written_on(1i)]" value="2004" />\n}
expected << %{<input type="hidden" id="post_written_on_2i" name="post[written_on(2i)]" value="6" />\n}
expected << %{<input type="hidden" id="post_written_on_3i" name="post[written_on(3i)]" value="15" />\n}
expected << %(<select id="post_written_on_4i" name="post[written_on(4i)]" class="selector">\n)
0.upto(23) { |i| expected << %(<option value="#{leading_zero_on_single_digits(i)}"#{' selected="selected"' if i == 15}>#{leading_zero_on_single_digits(i)}</option>\n) }
expected << "</select>\n"
expected << " : "
expected << %(<select id="post_written_on_5i" name="post[written_on(5i)]" class="selector">\n)
0.upto(59) { |i| expected << %(<option value="#{leading_zero_on_single_digits(i)}"#{' selected="selected"' if i == 16}>#{leading_zero_on_single_digits(i)}</option>\n) }
expected << "</select>\n"
assert_dom_equal expected, output_buffer
end
def test_datetime_select
@post = Post.new
@post.updated_at = Time.local(2004, 6, 15, 16, 35)
@@ -1281,21 +1343,21 @@ class DateHelperTest < ActionView::TestCase
end
end
def test_datetime_select_within_fields_for
def test_datetime_select_with_html_options_within_fields_for
@post = Post.new
@post.updated_at = Time.local(2004, 6, 15, 16, 35)
fields_for :post, @post do |f|
concat f.datetime_select(:updated_at)
concat f.datetime_select(:updated_at, {}, :class => 'selector')
end
expected = "<select id='post_updated_at_1i' name='post[updated_at(1i)]'>\n<option value='1999'>1999</option>\n<option value='2000'>2000</option>\n<option value='2001'>2001</option>\n<option value='2002'>2002</option>\n<option value='2003'>2003</option>\n<option selected='selected' value='2004'>2004</option>\n<option value='2005'>2005</option>\n<option value='2006'>2006</option>\n<option value='2007'>2007</option>\n<option value='2008'>2008</option>\n<option value='2009'>2009</option>\n</select>\n"
expected << "<select id='post_updated_at_2i' name='post[updated_at(2i)]'>\n<option value='1'>January</option>\n<option value='2'>February</option>\n<option value='3'>March</option>\n<option value='4'>April</option>\n<option value='5'>May</option>\n<option selected='selected' value='6'>June</option>\n<option value='7'>July</option>\n<option value='8'>August</option>\n<option value='9'>September</option>\n<option value='10'>October</option>\n<option value='11'>November</option>\n<option value='12'>December</option>\n</select>\n"
expected << "<select id='post_updated_at_3i' name='post[updated_at(3i)]'>\n<option value='1'>1</option>\n<option value='2'>2</option>\n<option value='3'>3</option>\n<option value='4'>4</option>\n<option value='5'>5</option>\n<option value='6'>6</option>\n<option value='7'>7</option>\n<option value='8'>8</option>\n<option value='9'>9</option>\n<option value='10'>10</option>\n<option value='11'>11</option>\n<option value='12'>12</option>\n<option value='13'>13</option>\n<option value='14'>14</option>\n<option selected='selected' value='15'>15</option>\n<option value='16'>16</option>\n<option value='17'>17</option>\n<option value='18'>18</option>\n<option value='19'>19</option>\n<option value='20'>20</option>\n<option value='21'>21</option>\n<option value='22'>22</option>\n<option value='23'>23</option>\n<option value='24'>24</option>\n<option value='25'>25</option>\n<option value='26'>26</option>\n<option value='27'>27</option>\n<option value='28'>28</option>\n<option value='29'>29</option>\n<option value='30'>30</option>\n<option value='31'>31</option>\n</select>\n"
expected << " &mdash; <select id='post_updated_at_4i' name='post[updated_at(4i)]'>\n<option value='00'>00</option>\n<option value='01'>01</option>\n<option value='02'>02</option>\n<option value='03'>03</option>\n<option value='04'>04</option>\n<option value='05'>05</option>\n<option value='06'>06</option>\n<option value='07'>07</option>\n<option value='08'>08</option>\n<option value='09'>09</option>\n<option value='10'>10</option>\n<option value='11'>11</option>\n<option value='12'>12</option>\n<option value='13'>13</option>\n<option value='14'>14</option>\n<option value='15'>15</option>\n<option selected='selected' value='16'>16</option>\n<option value='17'>17</option>\n<option value='18'>18</option>\n<option value='19'>19</option>\n<option value='20'>20</option>\n<option value='21'>21</option>\n<option value='22'>22</option>\n<option value='23'>23</option>\n</select>\n"
expected << " : <select id='post_updated_at_5i' name='post[updated_at(5i)]'>\n<option value='00'>00</option>\n<option value='01'>01</option>\n<option value='02'>02</option>\n<option value='03'>03</option>\n<option value='04'>04</option>\n<option value='05'>05</option>\n<option value='06'>06</option>\n<option value='07'>07</option>\n<option value='08'>08</option>\n<option value='09'>09</option>\n<option value='10'>10</option>\n<option value='11'>11</option>\n<option value='12'>12</option>\n<option value='13'>13</option>\n<option value='14'>14</option>\n<option value='15'>15</option>\n<option value='16'>16</option>\n<option value='17'>17</option>\n<option value='18'>18</option>\n<option value='19'>19</option>\n<option value='20'>20</option>\n<option value='21'>21</option>\n<option value='22'>22</option>\n<option value='23'>23</option>\n<option value='24'>24</option>\n<option value='25'>25</option>\n<option value='26'>26</option>\n<option value='27'>27</option>\n<option value='28'>28</option>\n<option value='29'>29</option>\n<option value='30'>30</option>\n<option value='31'>31</option>\n<option value='32'>32</option>\n<option value='33'>33</option>\n<option value='34'>34</option>\n<option selected='selected' value='35'>35</option>\n<option value='36'>36</option>\n<option value='37'>37</option>\n<option value='38'>38</option>\n<option value='39'>39</option>\n<option value='40'>40</option>\n<option value='41'>41</option>\n<option value='42'>42</option>\n<option value='43'>43</option>\n<option value='44'>44</option>\n<option value='45'>45</option>\n<option value='46'>46</option>\n<option value='47'>47</option>\n<option value='48'>48</option>\n<option value='49'>49</option>\n<option value='50'>50</option>\n<option value='51'>51</option>\n<option value='52'>52</option>\n<option value='53'>53</option>\n<option value='54'>54</option>\n<option value='55'>55</option>\n<option value='56'>56</option>\n<option value='57'>57</option>\n<option value='58'>58</option>\n<option value='59'>59</option>\n</select>\n"
expected = "<select id='post_updated_at_1i' name='post[updated_at(1i)]' class='selector'>\n<option value='1999'>1999</option>\n<option value='2000'>2000</option>\n<option value='2001'>2001</option>\n<option value='2002'>2002</option>\n<option value='2003'>2003</option>\n<option selected='selected' value='2004'>2004</option>\n<option value='2005'>2005</option>\n<option value='2006'>2006</option>\n<option value='2007'>2007</option>\n<option value='2008'>2008</option>\n<option value='2009'>2009</option>\n</select>\n"
expected << "<select id='post_updated_at_2i' name='post[updated_at(2i)]' class='selector'>\n<option value='1'>January</option>\n<option value='2'>February</option>\n<option value='3'>March</option>\n<option value='4'>April</option>\n<option value='5'>May</option>\n<option selected='selected' value='6'>June</option>\n<option value='7'>July</option>\n<option value='8'>August</option>\n<option value='9'>September</option>\n<option value='10'>October</option>\n<option value='11'>November</option>\n<option value='12'>December</option>\n</select>\n"
expected << "<select id='post_updated_at_3i' name='post[updated_at(3i)]' class='selector'>\n<option value='1'>1</option>\n<option value='2'>2</option>\n<option value='3'>3</option>\n<option value='4'>4</option>\n<option value='5'>5</option>\n<option value='6'>6</option>\n<option value='7'>7</option>\n<option value='8'>8</option>\n<option value='9'>9</option>\n<option value='10'>10</option>\n<option value='11'>11</option>\n<option value='12'>12</option>\n<option value='13'>13</option>\n<option value='14'>14</option>\n<option selected='selected' value='15'>15</option>\n<option value='16'>16</option>\n<option value='17'>17</option>\n<option value='18'>18</option>\n<option value='19'>19</option>\n<option value='20'>20</option>\n<option value='21'>21</option>\n<option value='22'>22</option>\n<option value='23'>23</option>\n<option value='24'>24</option>\n<option value='25'>25</option>\n<option value='26'>26</option>\n<option value='27'>27</option>\n<option value='28'>28</option>\n<option value='29'>29</option>\n<option value='30'>30</option>\n<option value='31'>31</option>\n</select>\n"
expected << " &mdash; <select id='post_updated_at_4i' name='post[updated_at(4i)]' class='selector'>\n<option value='00'>00</option>\n<option value='01'>01</option>\n<option value='02'>02</option>\n<option value='03'>03</option>\n<option value='04'>04</option>\n<option value='05'>05</option>\n<option value='06'>06</option>\n<option value='07'>07</option>\n<option value='08'>08</option>\n<option value='09'>09</option>\n<option value='10'>10</option>\n<option value='11'>11</option>\n<option value='12'>12</option>\n<option value='13'>13</option>\n<option value='14'>14</option>\n<option value='15'>15</option>\n<option selected='selected' value='16'>16</option>\n<option value='17'>17</option>\n<option value='18'>18</option>\n<option value='19'>19</option>\n<option value='20'>20</option>\n<option value='21'>21</option>\n<option value='22'>22</option>\n<option value='23'>23</option>\n</select>\n"
expected << " : <select id='post_updated_at_5i' name='post[updated_at(5i)]' class='selector'>\n<option value='00'>00</option>\n<option value='01'>01</option>\n<option value='02'>02</option>\n<option value='03'>03</option>\n<option value='04'>04</option>\n<option value='05'>05</option>\n<option value='06'>06</option>\n<option value='07'>07</option>\n<option value='08'>08</option>\n<option value='09'>09</option>\n<option value='10'>10</option>\n<option value='11'>11</option>\n<option value='12'>12</option>\n<option value='13'>13</option>\n<option value='14'>14</option>\n<option value='15'>15</option>\n<option value='16'>16</option>\n<option value='17'>17</option>\n<option value='18'>18</option>\n<option value='19'>19</option>\n<option value='20'>20</option>\n<option value='21'>21</option>\n<option value='22'>22</option>\n<option value='23'>23</option>\n<option value='24'>24</option>\n<option value='25'>25</option>\n<option value='26'>26</option>\n<option value='27'>27</option>\n<option value='28'>28</option>\n<option value='29'>29</option>\n<option value='30'>30</option>\n<option value='31'>31</option>\n<option value='32'>32</option>\n<option value='33'>33</option>\n<option value='34'>34</option>\n<option selected='selected' value='35'>35</option>\n<option value='36'>36</option>\n<option value='37'>37</option>\n<option value='38'>38</option>\n<option value='39'>39</option>\n<option value='40'>40</option>\n<option value='41'>41</option>\n<option value='42'>42</option>\n<option value='43'>43</option>\n<option value='44'>44</option>\n<option value='45'>45</option>\n<option value='46'>46</option>\n<option value='47'>47</option>\n<option value='48'>48</option>\n<option value='49'>49</option>\n<option value='50'>50</option>\n<option value='51'>51</option>\n<option value='52'>52</option>\n<option value='53'>53</option>\n<option value='54'>54</option>\n<option value='55'>55</option>\n<option value='56'>56</option>\n<option value='57'>57</option>\n<option value='58'>58</option>\n<option value='59'>59</option>\n</select>\n"
assert_dom_equal(expected, output_buffer)
assert_dom_equal expected, output_buffer
end
def test_date_select_with_zero_value_and_no_start_year

File diff suppressed because it is too large Load Diff

View File

@@ -35,21 +35,23 @@ class FormTagHelperTest < ActionView::TestCase
expected = %(<form action="http://www.example.com" method="post"><div style='margin:0;padding:0'><input type="hidden" name="_method" value="put" /></div>)
assert_dom_equal expected, actual
end
def test_form_tag_with_method_delete
actual = form_tag({}, { :method => :delete })
expected = %(<form action="http://www.example.com" method="post"><div style='margin:0;padding:0'><input type="hidden" name="_method" value="delete" /></div>)
assert_dom_equal expected, actual
end
def test_form_tag_with_block
def test_form_tag_with_block_in_erb
__in_erb_template = ''
form_tag("http://example.com") { concat "Hello world!" }
expected = %(<form action="http://example.com" method="post">Hello world!</form>)
assert_dom_equal expected, output_buffer
end
def test_form_tag_with_block_and_method
def test_form_tag_with_block_and_method_in_erb
__in_erb_template = ''
form_tag("http://example.com", :method => :put) { concat "Hello world!" }
expected = %(<form action="http://example.com" method="post"><div style='margin:0;padding:0'><input type="hidden" name="_method" value="put" /></div>Hello world!</form>)
@@ -88,11 +90,11 @@ class FormTagHelperTest < ActionView::TestCase
actual = radio_button_tag("gender", "m") + radio_button_tag("gender", "f")
expected = %(<input id="gender_m" name="gender" type="radio" value="m" /><input id="gender_f" name="gender" type="radio" value="f" />)
assert_dom_equal expected, actual
actual = radio_button_tag("opinion", "-1") + radio_button_tag("opinion", "1")
expected = %(<input id="opinion_-1" name="opinion" type="radio" value="-1" /><input id="opinion_1" name="opinion" type="radio" value="1" />)
assert_dom_equal expected, actual
actual = radio_button_tag("person[gender]", "m")
expected = %(<input id="person_gender_m" name="person[gender]" type="radio" value="m" />)
assert_dom_equal expected, actual
@@ -103,13 +105,13 @@ class FormTagHelperTest < ActionView::TestCase
expected = %(<select id="people" name="people"><option>david</option></select>)
assert_dom_equal expected, actual
end
def test_select_tag_with_multiple
actual = select_tag "colors", "<option>Red</option><option>Blue</option><option>Green</option>", :multiple => :true
expected = %(<select id="colors" multiple="multiple" name="colors"><option>Red</option><option>Blue</option><option>Green</option></select>)
assert_dom_equal expected, actual
end
def test_select_tag_disabled
actual = select_tag "places", "<option>Home</option><option>Work</option><option>Pub</option>", :disabled => :true
expected = %(<select id="places" disabled="disabled" name="places"><option>Home</option><option>Work</option><option>Pub</option></select>)
@@ -145,37 +147,37 @@ class FormTagHelperTest < ActionView::TestCase
expected = %(<input class="admin" id="title" name="title" type="text" value="Hello!" />)
assert_dom_equal expected, actual
end
def test_text_field_tag_size_symbol
actual = text_field_tag "title", "Hello!", :size => 75
expected = %(<input id="title" name="title" size="75" type="text" value="Hello!" />)
assert_dom_equal expected, actual
end
def test_text_field_tag_size_string
actual = text_field_tag "title", "Hello!", "size" => "75"
expected = %(<input id="title" name="title" size="75" type="text" value="Hello!" />)
assert_dom_equal expected, actual
end
def test_text_field_tag_maxlength_symbol
actual = text_field_tag "title", "Hello!", :maxlength => 75
expected = %(<input id="title" name="title" maxlength="75" type="text" value="Hello!" />)
assert_dom_equal expected, actual
end
def test_text_field_tag_maxlength_string
actual = text_field_tag "title", "Hello!", "maxlength" => "75"
expected = %(<input id="title" name="title" maxlength="75" type="text" value="Hello!" />)
assert_dom_equal expected, actual
end
def test_text_field_disabled
actual = text_field_tag "title", "Hello!", :disabled => :true
expected = %(<input id="title" name="title" disabled="disabled" type="text" value="Hello!" />)
assert_dom_equal expected, actual
end
def test_text_field_tag_with_multiple_options
actual = text_field_tag "title", "Hello!", :size => 70, :maxlength => 80
expected = %(<input id="title" name="title" size="70" maxlength="80" type="text" value="Hello!" />)
@@ -220,18 +222,26 @@ class FormTagHelperTest < ActionView::TestCase
)
end
def test_submit_tag_with_no_onclick_options
assert_dom_equal(
%(<input name='commit' type='submit' value='Save' onclick="this.setAttribute('originalValue', this.value);this.disabled=true;this.value='Saving...';result = (this.form.onsubmit ? (this.form.onsubmit() ? this.form.submit() : false) : this.form.submit());if (result == false) { this.value = this.getAttribute('originalValue'); this.disabled = false };return result;" />),
submit_tag("Save", :disable_with => "Saving...")
)
end
def test_submit_tag_with_confirmation
assert_dom_equal(
%(<input name='commit' type='submit' value='Save' onclick="return confirm('Are you sure?');"/>),
submit_tag("Save", :confirm => "Are you sure?")
)
end
def test_pass
assert_equal 1, 1
end
def test_field_set_tag
def test_field_set_tag_in_erb
__in_erb_template = ''
field_set_tag("Your details") { concat "Hello world!" }
expected = %(<fieldset><legend>Your details</legend>Hello world!</fieldset>)

View File

@@ -3,13 +3,7 @@ require 'abstract_unit'
class JavaScriptHelperTest < ActionView::TestCase
tests ActionView::Helpers::JavaScriptHelper
def test_define_javascript_functions
# check if prototype.js is included first
assert_not_nil define_javascript_functions.split("\n")[1].match(/Prototype JavaScript framework/)
# check that scriptaculous.js is not in here, only needed if loaded remotely
assert_nil define_javascript_functions.split("\n")[1].match(/var Scriptaculous = \{/)
end
attr_accessor :output_buffer
def test_escape_javascript
assert_equal '', escape_javascript(nil)
@@ -48,7 +42,7 @@ class JavaScriptHelperTest < ActionView::TestCase
end
def test_link_to_function_with_href
assert_dom_equal %(<a href="http://example.com/" onclick="alert('Hello world!'); return false;">Greeting</a>),
assert_dom_equal %(<a href="http://example.com/" onclick="alert('Hello world!'); return false;">Greeting</a>),
link_to_function("Greeting", "alert('Hello world!')", :href => 'http://example.com/')
end
@@ -95,12 +89,14 @@ class JavaScriptHelperTest < ActionView::TestCase
javascript_tag("alert('hello')", :id => "the_js_tag")
end
def test_javascript_tag_with_block
def test_javascript_tag_with_block_in_erb
__in_erb_template = ''
javascript_tag { concat "alert('hello')" }
assert_dom_equal "<script type=\"text/javascript\">\n//<![CDATA[\nalert('hello')\n//]]>\n</script>", output_buffer
end
def test_javascript_tag_with_block_and_options
def test_javascript_tag_with_block_and_options_in_erb
__in_erb_template = ''
javascript_tag(:id => "the_js_tag") { concat "alert('hello')" }
assert_dom_equal "<script id=\"the_js_tag\" type=\"text/javascript\">\n//<![CDATA[\nalert('hello')\n//]]>\n</script>", output_buffer
end

View File

@@ -25,7 +25,7 @@ class Author::Nested < Author; end
class PrototypeHelperBaseTest < ActionView::TestCase
attr_accessor :template_format
attr_accessor :template_format, :output_buffer
def setup
@template = nil
@@ -54,7 +54,7 @@ class PrototypeHelperBaseTest < ActionView::TestCase
end
def create_generator
block = Proc.new { |*args| yield *args if block_given? }
block = Proc.new { |*args| yield *args if block_given? }
JavaScriptGenerator.new self, &block
end
end
@@ -70,7 +70,7 @@ class PrototypeHelperTest < PrototypeHelperBaseTest
assert_dom_equal %(<a class=\"fine\" href=\"#\" onclick=\"new Ajax.Request('http://www.example.com/whatnot', {asynchronous:true, evalScripts:true}); return false;\">Remote outauthor</a>),
link_to_remote("Remote outauthor", { :url => { :action => "whatnot" }}, { :class => "fine" })
assert_dom_equal %(<a href=\"#\" onclick=\"new Ajax.Request('http://www.example.com/whatnot', {asynchronous:true, evalScripts:true, onComplete:function(request){alert(request.responseText)}}); return false;\">Remote outauthor</a>),
link_to_remote("Remote outauthor", :complete => "alert(request.responseText)", :url => { :action => "whatnot" })
link_to_remote("Remote outauthor", :complete => "alert(request.responseText)", :url => { :action => "whatnot" })
assert_dom_equal %(<a href=\"#\" onclick=\"new Ajax.Request('http://www.example.com/whatnot', {asynchronous:true, evalScripts:true, onSuccess:function(request){alert(request.responseText)}}); return false;\">Remote outauthor</a>),
link_to_remote("Remote outauthor", :success => "alert(request.responseText)", :url => { :action => "whatnot" })
assert_dom_equal %(<a href=\"#\" onclick=\"new Ajax.Request('http://www.example.com/whatnot', {asynchronous:true, evalScripts:true, onFailure:function(request){alert(request.responseText)}}); return false;\">Remote outauthor</a>),
@@ -78,12 +78,12 @@ class PrototypeHelperTest < PrototypeHelperBaseTest
assert_dom_equal %(<a href=\"#\" onclick=\"new Ajax.Request('http://www.example.com/whatnot?a=10&amp;b=20', {asynchronous:true, evalScripts:true, onFailure:function(request){alert(request.responseText)}}); return false;\">Remote outauthor</a>),
link_to_remote("Remote outauthor", :failure => "alert(request.responseText)", :url => { :action => "whatnot", :a => '10', :b => '20' })
end
def test_link_to_remote_html_options
assert_dom_equal %(<a class=\"fine\" href=\"#\" onclick=\"new Ajax.Request('http://www.example.com/whatnot', {asynchronous:true, evalScripts:true}); return false;\">Remote outauthor</a>),
link_to_remote("Remote outauthor", { :url => { :action => "whatnot" }, :html => { :class => "fine" } })
end
def test_link_to_remote_url_quote_escaping
assert_dom_equal %(<a href="#" onclick="new Ajax.Request('http://www.example.com/whatnot\\\'s', {asynchronous:true, evalScripts:true}); return false;">Remote</a>),
link_to_remote("Remote", { :url => { :action => "whatnot's" } })
@@ -93,14 +93,14 @@ class PrototypeHelperTest < PrototypeHelperBaseTest
assert_dom_equal %(<script type="text/javascript">\n//<![CDATA[\nnew PeriodicalExecuter(function() {new Ajax.Updater('schremser_bier', 'http://www.example.com/mehr_bier', {asynchronous:true, evalScripts:true})}, 10)\n//]]>\n</script>),
periodically_call_remote(:update => "schremser_bier", :url => { :action => "mehr_bier" })
end
def test_periodically_call_remote_with_frequency
assert_dom_equal(
"<script type=\"text/javascript\">\n//<![CDATA[\nnew PeriodicalExecuter(function() {new Ajax.Request('http://www.example.com/', {asynchronous:true, evalScripts:true})}, 2)\n//]]>\n</script>",
periodically_call_remote(:frequency => 2)
)
end
def test_form_remote_tag
assert_dom_equal %(<form action=\"http://www.example.com/fast\" method=\"post\" onsubmit=\"new Ajax.Updater('glass_of_beer', 'http://www.example.com/fast', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;\">),
form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast })
@@ -117,21 +117,22 @@ class PrototypeHelperTest < PrototypeHelperBaseTest
form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }, :html => { :method => :put })
end
def test_form_remote_tag_with_block
def test_form_remote_tag_with_block_in_erb
__in_erb_template = ''
form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }) { concat "Hello world!" }
assert_dom_equal %(<form action=\"http://www.example.com/fast\" method=\"post\" onsubmit=\"new Ajax.Updater('glass_of_beer', 'http://www.example.com/fast', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;\">Hello world!</form>), output_buffer
end
def test_remote_form_for_with_record_identification_with_new_record
remote_form_for(@record, {:html => { :id => 'create-author' }}) {}
expected = %(<form action='#{authors_path}' onsubmit="new Ajax.Request('#{authors_path}', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;" class='new_author' id='create-author' method='post'></form>)
assert_dom_equal expected, output_buffer
end
def test_remote_form_for_with_record_identification_without_html_options
remote_form_for(@record) {}
expected = %(<form action='#{authors_path}' onsubmit="new Ajax.Request('#{authors_path}', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;" class='new_author' method='post' id='new_author'></form>)
assert_dom_equal expected, output_buffer
end
@@ -139,23 +140,23 @@ class PrototypeHelperTest < PrototypeHelperBaseTest
def test_remote_form_for_with_record_identification_with_existing_record
@record.save
remote_form_for(@record) {}
expected = %(<form action='#{author_path(@record)}' id='edit_author_1' method='post' onsubmit="new Ajax.Request('#{author_path(@record)}', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;" class='edit_author'><div style='margin:0;padding:0'><input name='_method' type='hidden' value='put' /></div></form>)
assert_dom_equal expected, output_buffer
end
def test_remote_form_for_with_new_object_in_list
remote_form_for([@author, @article]) {}
expected = %(<form action='#{author_articles_path(@author)}' onsubmit="new Ajax.Request('#{author_articles_path(@author)}', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;" class='new_article' method='post' id='new_article'></form>)
assert_dom_equal expected, output_buffer
end
def test_remote_form_for_with_existing_object_in_list
@author.save
@article.save
remote_form_for([@author, @article]) {}
expected = %(<form action='#{author_article_path(@author, @article)}' id='edit_article_1' method='post' onsubmit="new Ajax.Request('#{author_article_path(@author, @article)}', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;" class='edit_article'><div style='margin:0;padding:0'><input name='_method' type='hidden' value='put' /></div></form>)
assert_dom_equal expected, output_buffer
end
@@ -172,18 +173,18 @@ class PrototypeHelperTest < PrototypeHelperBaseTest
assert_dom_equal %(<form action=\"http://www.example.com/fast\" method=\"post\" onsubmit=\"new Ajax.Updater({success:'glass_of_beer',failure:'glass_of_water'}, 'http://www.example.com/fast', {asynchronous:true, evalScripts:true, on#{callback.to_s.capitalize}:function(request){monkeys();}, parameters:Form.serialize(this)}); return false;">),
form_remote_tag(:update => { :success => "glass_of_beer", :failure => "glass_of_water" }, :url => { :action => :fast }, callback=>"monkeys();")
end
#HTTP status codes 200 up to 599 have callbacks
#these should work
100.upto(599) do |callback|
assert_dom_equal %(<form action=\"http://www.example.com/fast\" method=\"post\" onsubmit=\"new Ajax.Updater('glass_of_beer', 'http://www.example.com/fast', {asynchronous:true, evalScripts:true, on#{callback.to_s.capitalize}:function(request){monkeys();}, parameters:Form.serialize(this)}); return false;">),
form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }, callback=>"monkeys();")
end
#test 200 and 404
assert_dom_equal %(<form action=\"http://www.example.com/fast\" method=\"post\" onsubmit=\"new Ajax.Updater('glass_of_beer', 'http://www.example.com/fast', {asynchronous:true, evalScripts:true, on200:function(request){monkeys();}, on404:function(request){bananas();}, parameters:Form.serialize(this)}); return false;">),
form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }, 200=>"monkeys();", 404=>"bananas();")
#these shouldn't
1.upto(99) do |callback|
assert_dom_equal %(<form action=\"http://www.example.com/fast\" method=\"post\" onsubmit=\"new Ajax.Updater('glass_of_beer', 'http://www.example.com/fast', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;">),
@@ -193,44 +194,44 @@ class PrototypeHelperTest < PrototypeHelperBaseTest
assert_dom_equal %(<form action=\"http://www.example.com/fast\" method=\"post\" onsubmit=\"new Ajax.Updater('glass_of_beer', 'http://www.example.com/fast', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;">),
form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }, callback=>"monkeys();")
end
#test ultimate combo
assert_dom_equal %(<form action=\"http://www.example.com/fast\" method=\"post\" onsubmit=\"new Ajax.Updater('glass_of_beer', 'http://www.example.com/fast', {asynchronous:true, evalScripts:true, on200:function(request){monkeys();}, on404:function(request){bananas();}, onComplete:function(request){c();}, onFailure:function(request){f();}, onLoading:function(request){c1()}, onSuccess:function(request){s()}, parameters:Form.serialize(this)}); return false;\">),
form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }, :loading => "c1()", :success => "s()", :failure => "f();", :complete => "c();", 200=>"monkeys();", 404=>"bananas();")
end
def test_submit_to_remote
def test_button_to_remote
assert_dom_equal %(<input name=\"More beer!\" onclick=\"new Ajax.Updater('empty_bottle', 'http://www.example.com/', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this.form)}); return false;\" type=\"button\" value=\"1000000\" />),
submit_to_remote("More beer!", 1_000_000, :update => "empty_bottle")
button_to_remote("More beer!", 1_000_000, :update => "empty_bottle")
end
def test_observe_field
assert_dom_equal %(<script type=\"text/javascript\">\n//<![CDATA[\nnew Form.Element.Observer('glass', 300, function(element, value) {new Ajax.Request('http://www.example.com/reorder_if_empty', {asynchronous:true, evalScripts:true, parameters:value})})\n//]]>\n</script>),
observe_field("glass", :frequency => 5.minutes, :url => { :action => "reorder_if_empty" })
end
def test_observe_field_using_with_option
expected = %(<script type=\"text/javascript\">\n//<![CDATA[\nnew Form.Element.Observer('glass', 300, function(element, value) {new Ajax.Request('http://www.example.com/check_value', {asynchronous:true, evalScripts:true, parameters:'id=' + encodeURIComponent(value)})})\n//]]>\n</script>)
assert_dom_equal expected, observe_field("glass", :frequency => 5.minutes, :url => { :action => "check_value" }, :with => 'id')
assert_dom_equal expected, observe_field("glass", :frequency => 5.minutes, :url => { :action => "check_value" }, :with => "'id=' + encodeURIComponent(value)")
end
def test_observe_field_using_json_in_with_option
expected = %(<script type=\"text/javascript\">\n//<![CDATA[\nnew Form.Element.Observer('glass', 300, function(element, value) {new Ajax.Request('http://www.example.com/check_value', {asynchronous:true, evalScripts:true, parameters:{'id':value}})})\n//]]>\n</script>)
assert_dom_equal expected, observe_field("glass", :frequency => 5.minutes, :url => { :action => "check_value" }, :with => "{'id':value}")
assert_dom_equal expected, observe_field("glass", :frequency => 5.minutes, :url => { :action => "check_value" }, :with => "{'id':value}")
end
def test_observe_field_using_function_for_callback
assert_dom_equal %(<script type=\"text/javascript\">\n//<![CDATA[\nnew Form.Element.Observer('glass', 300, function(element, value) {alert('Element changed')})\n//]]>\n</script>),
observe_field("glass", :frequency => 5.minutes, :function => "alert('Element changed')")
end
def test_observe_form
assert_dom_equal %(<script type=\"text/javascript\">\n//<![CDATA[\nnew Form.Observer('cart', 2, function(element, value) {new Ajax.Request('http://www.example.com/cart_changed', {asynchronous:true, evalScripts:true, parameters:value})})\n//]]>\n</script>),
observe_form("cart", :frequency => 2, :url => { :action => "cart_changed" })
end
def test_observe_form_using_function_for_callback
assert_dom_equal %(<script type=\"text/javascript\">\n//<![CDATA[\nnew Form.Observer('cart', 2, function(element, value) {alert('Form changed')})\n//]]>\n</script>),
observe_form("cart", :frequency => 2, :function => "alert('Form changed')")
@@ -245,7 +246,7 @@ class PrototypeHelperTest < PrototypeHelperBaseTest
block = Proc.new { |page| page.replace_html('foo', 'bar') }
assert_equal create_generator(&block).to_s, update_page(&block)
end
def test_update_page_tag
block = Proc.new { |page| page.replace_html('foo', 'bar') }
assert_equal javascript_tag(create_generator(&block).to_s), update_page_tag(&block)
@@ -261,15 +262,15 @@ class PrototypeHelperTest < PrototypeHelperBaseTest
def author_path(record)
"/authors/#{record.id}"
end
def authors_path
"/authors"
end
def author_articles_path(author)
"/authors/#{author.id}/articles"
end
def author_article_path(author, article)
"/authors/#{author.id}/articles/#{article.id}"
end
@@ -280,7 +281,7 @@ class JavaScriptGeneratorTest < PrototypeHelperBaseTest
super
@generator = create_generator
end
def test_insert_html_with_string
assert_equal 'new Insertion.Top("element", "\\u003Cp\\u003EThis is a test\\u003C/p\\u003E");',
@generator.insert_html(:top, 'element', '<p>This is a test</p>')
@@ -291,56 +292,56 @@ class JavaScriptGeneratorTest < PrototypeHelperBaseTest
assert_equal 'new Insertion.After("element", "\\u003Cp\u003EThis is a test\\u003C/p\u003E");',
@generator.insert_html(:after, 'element', '<p>This is a test</p>')
end
def test_replace_html_with_string
assert_equal 'Element.update("element", "\\u003Cp\\u003EThis is a test\\u003C/p\\u003E");',
@generator.replace_html('element', '<p>This is a test</p>')
end
def test_replace_element_with_string
assert_equal 'Element.replace("element", "\\u003Cdiv id=\"element\"\\u003E\\u003Cp\\u003EThis is a test\\u003C/p\\u003E\\u003C/div\\u003E");',
@generator.replace('element', '<div id="element"><p>This is a test</p></div>')
end
def test_remove
assert_equal 'Element.remove("foo");',
@generator.remove('foo')
assert_equal '["foo", "bar", "baz"].each(Element.remove);',
@generator.remove('foo', 'bar', 'baz')
end
def test_show
assert_equal 'Element.show("foo");',
@generator.show('foo')
assert_equal '["foo", "bar", "baz"].each(Element.show);',
@generator.show('foo', 'bar', 'baz')
@generator.show('foo', 'bar', 'baz')
end
def test_hide
assert_equal 'Element.hide("foo");',
@generator.hide('foo')
assert_equal '["foo", "bar", "baz"].each(Element.hide);',
@generator.hide('foo', 'bar', 'baz')
@generator.hide('foo', 'bar', 'baz')
end
def test_toggle
assert_equal 'Element.toggle("foo");',
@generator.toggle('foo')
assert_equal '["foo", "bar", "baz"].each(Element.toggle);',
@generator.toggle('foo', 'bar', 'baz')
@generator.toggle('foo', 'bar', 'baz')
end
def test_alert
assert_equal 'alert("hello");', @generator.alert('hello')
end
def test_redirect_to
assert_equal 'window.location.href = "http://www.example.com/welcome";',
@generator.redirect_to(:action => 'welcome')
assert_equal 'window.location.href = "http://www.example.com/welcome?a=b&c=d";',
@generator.redirect_to("http://www.example.com/welcome?a=b&c=d")
end
def test_reload
assert_equal 'window.location.reload();',
@generator.reload
@@ -350,16 +351,16 @@ class JavaScriptGeneratorTest < PrototypeHelperBaseTest
@generator.delay(20) do
@generator.hide('foo')
end
assert_equal "setTimeout(function() {\n;\nElement.hide(\"foo\");\n}, 20000);", @generator.to_s
end
def test_to_s
@generator.insert_html(:top, 'element', '<p>This is a test</p>')
@generator.insert_html(:bottom, 'element', '<p>This is a test</p>')
@generator.remove('foo', 'bar')
@generator.replace_html('baz', '<p>This is a test</p>')
assert_equal <<-EOS.chomp, @generator.to_s
new Insertion.Top("element", "\\u003Cp\\u003EThis is a test\\u003C/p\\u003E");
new Insertion.Bottom("element", "\\u003Cp\\u003EThis is a test\\u003C/p\\u003E");
@@ -381,12 +382,12 @@ Element.update("baz", "\\u003Cp\\u003EThis is a test\\u003C/p\\u003E");
@generator['hello'].hide
assert_equal %($("hello").hide();), @generator.to_s
end
def test_element_proxy_variable_access
@generator['hello']['style']
assert_equal %($("hello").style;), @generator.to_s
end
def test_element_proxy_variable_access_with_assignment
@generator['hello']['style']['color'] = 'red'
assert_equal %($("hello").style.color = "red";), @generator.to_s
@@ -401,7 +402,7 @@ Element.update("baz", "\\u003Cp\\u003EThis is a test\\u003C/p\\u003E");
@generator['hello'].hide("first").clean_whitespace
assert_equal %($("hello").hide("first").cleanWhitespace();), @generator.to_s
end
def test_select_access
assert_equal %($$("div.hello");), @generator.select('div.hello')
end
@@ -410,29 +411,29 @@ Element.update("baz", "\\u003Cp\\u003EThis is a test\\u003C/p\\u003E");
@generator.select('p.welcome b').first.hide
assert_equal %($$("p.welcome b").first().hide();), @generator.to_s
end
def test_visual_effect
assert_equal %(new Effect.Puff("blah",{});),
assert_equal %(new Effect.Puff("blah",{});),
@generator.visual_effect(:puff,'blah')
end
end
def test_visual_effect_toggle
assert_equal %(Effect.toggle("blah",'appear',{});),
assert_equal %(Effect.toggle("blah",'appear',{});),
@generator.visual_effect(:toggle_appear,'blah')
end
def test_sortable
assert_equal %(Sortable.create("blah", {onUpdate:function(){new Ajax.Request('http://www.example.com/order', {asynchronous:true, evalScripts:true, parameters:Sortable.serialize("blah")})}});),
assert_equal %(Sortable.create("blah", {onUpdate:function(){new Ajax.Request('http://www.example.com/order', {asynchronous:true, evalScripts:true, parameters:Sortable.serialize("blah")})}});),
@generator.sortable('blah', :url => { :action => "order" })
end
def test_draggable
assert_equal %(new Draggable("blah", {});),
assert_equal %(new Draggable("blah", {});),
@generator.draggable('blah')
end
def test_drop_receiving
assert_equal %(Droppables.add("blah", {onDrop:function(element){new Ajax.Request('http://www.example.com/order', {asynchronous:true, evalScripts:true, parameters:'id=' + encodeURIComponent(element.id)})}});),
assert_equal %(Droppables.add("blah", {onDrop:function(element){new Ajax.Request('http://www.example.com/order', {asynchronous:true, evalScripts:true, parameters:'id=' + encodeURIComponent(element.id)})}});),
@generator.drop_receiving('blah', :url => { :action => "order" })
end
@@ -534,7 +535,7 @@ return array.reverse();
});
EOS
end
def test_collection_proxy_with_find_all
@generator.select('p').find_all 'a' do |value, index|
@generator << '(value.className == "welcome")'
@@ -546,7 +547,7 @@ return (value.className == "welcome");
});
EOS
end
def test_collection_proxy_with_in_groups_of
@generator.select('p').in_groups_of('a', 3)
@generator.select('p').in_groups_of('a', 3, 'x')
@@ -555,13 +556,13 @@ var a = $$("p").inGroupsOf(3);
var a = $$("p").inGroupsOf(3, "x");
EOS
end
def test_collection_proxy_with_each_slice
@generator.select('p').each_slice('a', 3)
@generator.select('p').each_slice('a', 3) do |group, index|
group.reverse
end
assert_equal <<-EOS.strip, @generator.to_s
var a = $$("p").eachSlice(3);
var a = $$("p").eachSlice(3, function(value, index) {
@@ -569,7 +570,7 @@ return value.reverse();
});
EOS
end
def test_debug_rjs
ActionView::Base.debug_rjs = true
@generator['welcome'].replace_html 'Welcome'
@@ -577,7 +578,7 @@ return value.reverse();
ensure
ActionView::Base.debug_rjs = false
end
def test_literal
literal = @generator.literal("function() {}")
assert_equal "function() {}", literal.to_json
@@ -588,7 +589,7 @@ return value.reverse();
@generator.form.focus('my_field')
assert_equal "Form.focus(\"my_field\");", @generator.to_s
end
def test_call_with_block
@generator.call(:before)
@generator.call(:my_method) do |p|
@@ -601,7 +602,7 @@ return value.reverse();
end
assert_equal "before();\nmy_method(function() { $(\"one\").show();\n$(\"two\").hide(); });\nin_between();\nmy_method_with_arguments(true, \"hello\", function() { $(\"three\").visualEffect(\"highlight\"); });", @generator.to_s
end
def test_class_proxy_call_with_block
@generator.my_object.my_method do |p|
p[:one].show

View File

@@ -2,7 +2,7 @@ require 'abstract_unit'
class Post
def id
45
45
end
def body
"What a wonderful world!"
@@ -15,35 +15,36 @@ class RecordTagHelperTest < ActionView::TestCase
def setup
@post = Post.new
end
def test_content_tag_for
expected = %(<li class="post bar" id="post_45"></li>)
actual = content_tag_for(:li, @post, :class => 'bar') { }
assert_dom_equal expected, actual
end
def test_content_tag_for_prefix
expected = %(<ul class="post" id="archived_post_45"></ul>)
actual = content_tag_for(:ul, @post, :archived) { }
assert_dom_equal expected, actual
assert_dom_equal expected, actual
end
def test_content_tag_for_with_extra_html_tags
expected = %(<tr class="post bar" id="post_45" style='background-color: #f0f0f0'></tr>)
actual = content_tag_for(:tr, @post, {:class => "bar", :style => "background-color: #f0f0f0"}) { }
assert_dom_equal expected, actual
assert_dom_equal expected, actual
end
def test_block_works_with_content_tag_for
def test_block_works_with_content_tag_for_in_erb
__in_erb_template = ''
expected = %(<tr class="post" id="post_45">#{@post.body}</tr>)
actual = content_tag_for(:tr, @post) { concat @post.body }
assert_dom_equal expected, actual
assert_dom_equal expected, actual
end
def test_div_for
def test_div_for_in_erb
__in_erb_template = ''
expected = %(<div class="post bar" id="post_45">#{@post.body}</div>)
actual = div_for(@post, :class => "bar") { concat @post.body }
assert_dom_equal expected, actual
end
end
end

View File

@@ -0,0 +1,131 @@
require 'abstract_unit'
require 'controller/fake_models'
class ViewRenderTest < Test::Unit::TestCase
def setup
@assigns = { :secret => 'in the sauce' }
@view = ActionView::Base.new(ActionController::Base.view_paths, @assigns)
end
def test_render_file
assert_equal "Hello world!", @view.render("test/hello_world.erb")
end
def test_render_file_not_using_full_path
assert_equal "Hello world!", @view.render(:file => "test/hello_world.erb")
end
def test_render_file_without_specific_extension
assert_equal "Hello world!", @view.render("test/hello_world")
end
def test_render_file_with_full_path
template_path = File.join(File.dirname(__FILE__), '../fixtures/test/hello_world.erb')
assert_equal "Hello world!", @view.render(:file => template_path)
end
def test_render_file_with_instance_variables
assert_equal "The secret is in the sauce\n", @view.render("test/render_file_with_ivar.erb")
end
def test_render_file_with_locals
locals = { :secret => 'in the sauce' }
assert_equal "The secret is in the sauce\n", @view.render("test/render_file_with_locals.erb", locals)
end
def test_render_file_not_using_full_path_with_dot_in_path
assert_equal "The secret is in the sauce\n", @view.render("test/dot.directory/render_file_with_ivar")
end
def test_render_update
# TODO: You should not have to stub out template because template is self!
@view.instance_variable_set(:@template, @view)
assert_equal 'alert("Hello, World!");', @view.render(:update) { |page| page.alert('Hello, World!') }
end
def test_render_partial
assert_equal "only partial", @view.render(:partial => "test/partial_only")
end
def test_render_partial_with_errors
assert_raise(ActionView::TemplateError) { @view.render(:partial => "test/raise") }
end
def test_render_partial_collection
assert_equal "Hello: davidHello: mary", @view.render(:partial => "test/customer", :collection => [ Customer.new("david"), Customer.new("mary") ])
end
def test_render_partial_collection_as
assert_equal "david david davidmary mary mary",
@view.render(:partial => "test/customer_with_var", :collection => [ Customer.new("david"), Customer.new("mary") ], :as => :customer)
end
def test_render_partial_collection_without_as
assert_equal "local_inspector,local_inspector_counter,object",
@view.render(:partial => "test/local_inspector", :collection => [ Customer.new("mary") ])
end
# TODO: The reason for this test is unclear, improve documentation
def test_render_partial_and_fallback_to_layout
assert_equal "Before (Josh)\n\nAfter", @view.render(:partial => "test/layout_for_partial", :locals => { :name => "Josh" })
end
# TODO: The reason for this test is unclear, improve documentation
def test_render_js_partial_and_fallback_to_erb_layout
@view.template_format = :js
assert_equal "Before (Josh)\n\nAfter", @view.render(:partial => "test/layout_for_partial", :locals => { :name => "Josh" })
end
# TODO: The reason for this test is unclear, improve documentation
def test_render_missing_xml_partial_and_raise_missing_template
@view.template_format = :xml
assert_raise(ActionView::MissingTemplate) { @view.render(:partial => "test/layout_for_partial") }
end
def test_render_inline
assert_equal "Hello, World!", @view.render(:inline => "Hello, World!")
end
def test_render_inline_with_locals
assert_equal "Hello, Josh!", @view.render(:inline => "Hello, <%= name %>!", :locals => { :name => "Josh" })
end
def test_render_fallbacks_to_erb_for_unknown_types
assert_equal "Hello, World!", @view.render(:inline => "Hello, World!", :type => :foo)
end
class CustomHandler < ActionView::TemplateHandler
def render(template, local_assigns)
[template.source, local_assigns].inspect
end
end
def test_render_inline_with_custom_type
ActionView::Template.register_template_handler :foo, CustomHandler
assert_equal '["Hello, World!", {}]', @view.render(:inline => "Hello, World!", :type => :foo)
end
def test_render_inline_with_locals_and_custom_type
ActionView::Template.register_template_handler :foo, CustomHandler
assert_equal '["Hello, <%= name %>!", {:name=>"Josh"}]', @view.render(:inline => "Hello, <%= name %>!", :locals => { :name => "Josh" }, :type => :foo)
end
class CompilableCustomHandler < ActionView::TemplateHandler
include ActionView::TemplateHandlers::Compilable
def compile(template)
"@output_buffer = ''\n" +
"@output_buffer << 'source: #{template.source.inspect}'\n"
end
end
def test_render_inline_with_compilable_custom_type
ActionView::Template.register_template_handler :foo, CompilableCustomHandler
assert_equal 'source: "Hello, World!"', @view.render(:inline => "Hello, World!", :type => :foo)
end
def test_render_inline_with_locals_and_compilable_custom_type
ActionView::Template.register_template_handler :foo, CompilableCustomHandler
assert_equal 'source: "Hello, <%= name %>!"', @view.render(:inline => "Hello, <%= name %>!", :locals => { :name => "Josh" }, :type => :foo)
end
end

View File

@@ -33,23 +33,40 @@ class TagHelperTest < ActionView::TestCase
assert_equal content_tag("a", "Create", "href" => "create"),
content_tag("a", "Create", :href => "create")
end
def test_content_tag_with_block
def test_content_tag_with_block_in_erb
__in_erb_template = ''
content_tag(:div) { concat "Hello world!" }
assert_dom_equal "<div>Hello world!</div>", output_buffer
end
def test_content_tag_with_block_and_options
def test_content_tag_with_block_and_options_in_erb
__in_erb_template = ''
content_tag(:div, :class => "green") { concat "Hello world!" }
assert_dom_equal %(<div class="green">Hello world!</div>), output_buffer
end
def test_content_tag_with_block_and_options_outside_of_action_view
self.output_buffer = nil
assert_equal content_tag("a", "Create", :href => "create"),
content_tag("a", "href" => "create") { "Create" }
def test_content_tag_with_block_and_options_out_of_erb
assert_dom_equal %(<div class="green">Hello world!</div>), content_tag(:div, :class => "green") { "Hello world!" }
end
def test_content_tag_with_block_and_options_outside_out_of_erb
assert_equal content_tag("a", "Create", :href => "create"),
content_tag("a", "href" => "create") { "Create" }
end
def test_content_tag_nested_in_content_tag_out_of_erb
assert_equal content_tag("p", content_tag("b", "Hello")),
content_tag("p") { content_tag("b", "Hello") },
output_buffer
end
def test_content_tag_nested_in_content_tag_in_erb
__in_erb_template = true
content_tag("p") { concat content_tag("b", "Hello") }
assert_equal '<p><b>Hello</b></p>', output_buffer
end
def test_cdata_section
assert_equal "<![CDATA[<hello world>]]>", cdata_section("<hello world>")
end

View File

@@ -1,95 +0,0 @@
require 'abstract_unit'
class TemplateFileTest < Test::Unit::TestCase
LOAD_PATH_ROOT = File.join(File.dirname(__FILE__), '..', 'fixtures')
def setup
@template = ActionView::TemplateFile.new("test/hello_world.html.erb")
@another_template = ActionView::TemplateFile.new("test/hello_world.erb")
@file_only = ActionView::TemplateFile.new("hello_world.erb")
@full_path = ActionView::TemplateFile.new("/u/app/scales/config/../app/views/test/hello_world.erb", true)
@layout = ActionView::TemplateFile.new("layouts/hello")
@multipart = ActionView::TemplateFile.new("test_mailer/implicitly_multipart_example.text.html.erb")
end
def test_path
assert_equal "test/hello_world.html.erb", @template.path
assert_equal "test/hello_world.erb", @another_template.path
assert_equal "hello_world.erb", @file_only.path
assert_equal "/u/app/scales/config/../app/views/test/hello_world.erb", @full_path.path
assert_equal "layouts/hello", @layout.path
assert_equal "test_mailer/implicitly_multipart_example.text.html.erb", @multipart.path
end
def test_path_without_extension
assert_equal "test/hello_world.html", @template.path_without_extension
assert_equal "test/hello_world", @another_template.path_without_extension
assert_equal "hello_world", @file_only.path_without_extension
assert_equal "layouts/hello", @layout.path_without_extension
assert_equal "test_mailer/implicitly_multipart_example.text.html", @multipart.path_without_extension
end
def test_path_without_format_and_extension
assert_equal "test/hello_world", @template.path_without_format_and_extension
assert_equal "test/hello_world", @another_template.path_without_format_and_extension
assert_equal "hello_world", @file_only.path_without_format_and_extension
assert_equal "layouts/hello", @layout.path_without_format_and_extension
assert_equal "test_mailer/implicitly_multipart_example", @multipart.path_without_format_and_extension
end
def test_name
assert_equal "hello_world", @template.name
assert_equal "hello_world", @another_template.name
assert_equal "hello_world", @file_only.name
assert_equal "hello_world", @full_path.name
assert_equal "hello", @layout.name
assert_equal "implicitly_multipart_example", @multipart.name
end
def test_format
assert_equal "html", @template.format
assert_equal nil, @another_template.format
assert_equal nil, @layout.format
assert_equal "text.html", @multipart.format
end
def test_extension
assert_equal "erb", @template.extension
assert_equal "erb", @another_template.extension
assert_equal nil, @layout.extension
assert_equal "erb", @multipart.extension
end
def test_format_and_extension
assert_equal "html.erb", @template.format_and_extension
assert_equal "erb", @another_template.format_and_extension
assert_equal nil, @layout.format_and_extension
assert_equal "text.html.erb", @multipart.format_and_extension
end
def test_new_file_with_extension
file = @template.dup_with_extension(:haml)
assert_equal "test/hello_world.html", file.path_without_extension
assert_equal "haml", file.extension
assert_equal "test/hello_world.html.haml", file.path
file = @another_template.dup_with_extension(:haml)
assert_equal "test/hello_world", file.path_without_extension
assert_equal "haml", file.extension
assert_equal "test/hello_world.haml", file.path
file = @another_template.dup_with_extension(nil)
assert_equal "test/hello_world", file.path_without_extension
assert_equal nil, file.extension
assert_equal "test/hello_world", file.path
end
def test_freezes_entire_contents
@template.freeze
assert @template.frozen?
assert @template.base_path.frozen?
assert @template.name.frozen?
assert @template.format.frozen?
assert @template.extension.frozen?
end
end

Some files were not shown because too many files have changed in this diff Show More