Merge branch 'master' of github.com:lifo/docrails
4
Gemfile
@ -2,7 +2,7 @@ path File.dirname(__FILE__)
|
||||
source 'http://rubygems.org'
|
||||
|
||||
gem "arel", :git => "git://github.com/rails/arel.git"
|
||||
gem "rails", "3.0.0.beta1"
|
||||
gem "rails", "3.0.0.beta2"
|
||||
|
||||
gem "rake", ">= 0.8.7"
|
||||
gem "mocha", ">= 0.9.8"
|
||||
@ -11,7 +11,7 @@ group :mri do
|
||||
if RUBY_VERSION < '1.9'
|
||||
gem "system_timer"
|
||||
gem "ruby-debug", ">= 0.10.3"
|
||||
elsif RUBY_VERSION < '1.9.2'
|
||||
elsif RUBY_VERSION < '1.9.2' && !ENV['CI']
|
||||
gem "ruby-debug19"
|
||||
end
|
||||
end
|
||||
|
@ -1 +1 @@
|
||||
3.0.0.beta1
|
||||
3.0.0.beta2
|
||||
|
@ -1,7 +1,15 @@
|
||||
*Rails 3.0 (pending)*
|
||||
*Rails 3.0.0 [beta 2] (April 1st, 2010)*
|
||||
|
||||
* Added interceptors and observers from Mail [ML]
|
||||
|
||||
ActionMailer::Base.register_interceptor calls Mail.register_interceptor
|
||||
ActionMailer::Base.register_observer calls Mail.register_observer
|
||||
|
||||
* Whole new API added with tests. See base.rb for full details. Old API is deprecated.
|
||||
|
||||
|
||||
*Rails 3.0.0 [beta 1] (February 4, 2010)*
|
||||
|
||||
* The Mail::Message class has helped methods for all the field types that return 'common' defaults for the common use case, so to get the subject, mail.subject will give you a string, mail.date will give you a DateTime object, mail.from will give you an array of address specs (mikel@test.lindsaar.net) etc. If you want to access the field object itself, call mail[:field_name] which will return the field object you want, which you can then chain, like mail[:from].formatted
|
||||
|
||||
* Mail#content_type now returns the content_type field as a string. If you want the mime type of a mail, then you call Mail#mime_type (eg, text/plain), if you want the parameters of the content type field, you call Mail#content_type_parameters which gives you a hash, eg {'format' => 'flowed', 'charset' => 'utf-8'}
|
||||
|
@ -3,7 +3,7 @@ module VERSION #:nodoc:
|
||||
MAJOR = 3
|
||||
MINOR = 0
|
||||
TINY = 0
|
||||
BUILD = "beta1"
|
||||
BUILD = "beta2"
|
||||
|
||||
STRING = [MAJOR, MINOR, TINY, BUILD].join('.')
|
||||
end
|
||||
|
@ -48,7 +48,7 @@ def formats
|
||||
@env["action_dispatch.request.formats"] ||=
|
||||
if parameters[:format]
|
||||
Array(Mime[parameters[:format]])
|
||||
elsif xhr? || (accept && !accept.include?(?,))
|
||||
elsif xhr? || (accept && accept !~ /,\s*\*\/\*/)
|
||||
accepts
|
||||
else
|
||||
[Mime::HTML]
|
||||
@ -87,4 +87,4 @@ def negotiate_mime(order)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -6,6 +6,7 @@ class Railtie < Rails::Railtie
|
||||
config.action_dispatch = ActiveSupport::OrderedOptions.new
|
||||
config.action_dispatch.x_sendfile_header = ""
|
||||
config.action_dispatch.ip_spoofing_check = true
|
||||
config.action_dispatch.show_exceptions = true
|
||||
|
||||
# Prepare dispatcher callbacks and run 'prepare' callbacks
|
||||
initializer "action_dispatch.prepare_dispatcher" do |app|
|
||||
|
@ -194,6 +194,21 @@ def match(*args)
|
||||
self
|
||||
end
|
||||
|
||||
def mount(app, options = nil)
|
||||
if options
|
||||
path = options.delete(:at)
|
||||
else
|
||||
options = app
|
||||
app, path = options.find { |k, v| k.respond_to?(:call) }
|
||||
options.delete(app) if app
|
||||
end
|
||||
|
||||
raise "A rack application must be specified" unless path
|
||||
|
||||
match(path, options.merge(:to => app, :anchor => false))
|
||||
self
|
||||
end
|
||||
|
||||
def default_url_options=(options)
|
||||
@set.default_url_options = options
|
||||
end
|
||||
@ -380,14 +395,13 @@ def self.default_actions
|
||||
[:index, :create, :new, :show, :update, :destroy, :edit]
|
||||
end
|
||||
|
||||
attr_reader :plural, :singular, :options
|
||||
attr_reader :controller, :path, :options
|
||||
|
||||
def initialize(entities, options = {})
|
||||
@name = entities.to_s
|
||||
@options = options
|
||||
|
||||
@plural = @name.pluralize
|
||||
@singular = @name.singularize
|
||||
@name = entities.to_s
|
||||
@path = options.delete(:path) || @name
|
||||
@controller = options.delete(:controller) || @name.to_s.pluralize
|
||||
@options = options
|
||||
end
|
||||
|
||||
def default_actions
|
||||
@ -417,8 +431,12 @@ def name
|
||||
options[:as] || @name
|
||||
end
|
||||
|
||||
def controller
|
||||
options[:controller] || plural
|
||||
def plural
|
||||
name.to_s.pluralize
|
||||
end
|
||||
|
||||
def singular
|
||||
name.to_s.singularize
|
||||
end
|
||||
|
||||
def member_name
|
||||
@ -509,7 +527,7 @@ def resource(*resources, &block)
|
||||
|
||||
resource = SingletonResource.new(resources.pop, options)
|
||||
|
||||
scope(:path => resource.name.to_s, :controller => resource.controller) do
|
||||
scope(:path => resource.path, :controller => resource.controller) do
|
||||
with_scope_level(:resource, resource) do
|
||||
|
||||
scope(:name_prefix => resource.name.to_s, :as => "") do
|
||||
@ -539,7 +557,7 @@ def resources(*resources, &block)
|
||||
|
||||
resource = Resource.new(resources.pop, options)
|
||||
|
||||
scope(:path => resource.name.to_s, :controller => resource.controller) do
|
||||
scope(:path => resource.path, :controller => resource.controller) do
|
||||
with_scope_level(:resources, resource) do
|
||||
yield if block_given?
|
||||
|
||||
@ -603,21 +621,6 @@ def nested
|
||||
end
|
||||
end
|
||||
|
||||
def mount(app, options = nil)
|
||||
if options
|
||||
path = options.delete(:at)
|
||||
else
|
||||
options = app
|
||||
app, path = options.find { |k, v| k.respond_to?(:call) }
|
||||
options.delete(app) if app
|
||||
end
|
||||
|
||||
raise "A rack application must be specified" unless path
|
||||
|
||||
match(path, options.merge(:to => app, :anchor => false))
|
||||
self
|
||||
end
|
||||
|
||||
def match(*args)
|
||||
options = args.extract_options!
|
||||
|
||||
|
@ -263,9 +263,7 @@ def process(method, path, parameters = nil, rack_environment = nil)
|
||||
"HTTP_HOST" => host,
|
||||
"REMOTE_ADDR" => remote_addr,
|
||||
"CONTENT_TYPE" => "application/x-www-form-urlencoded",
|
||||
"HTTP_ACCEPT" => accept,
|
||||
|
||||
"action_dispatch.show_exceptions" => false
|
||||
"HTTP_ACCEPT" => accept
|
||||
}
|
||||
|
||||
(rack_environment || {}).each do |key, value|
|
||||
|
@ -3,7 +3,7 @@ module VERSION #:nodoc:
|
||||
MAJOR = 3
|
||||
MINOR = 0
|
||||
TINY = 0
|
||||
BUILD = "beta1"
|
||||
BUILD = "beta2"
|
||||
|
||||
STRING = [MAJOR, MINOR, TINY, BUILD].join('.')
|
||||
end
|
||||
|
@ -168,6 +168,8 @@ module Subclasses
|
||||
remove_method :helpers
|
||||
attr_reader :helpers
|
||||
|
||||
class_attribute :_router
|
||||
|
||||
class << self
|
||||
delegate :erb_trim_mode=, :to => 'ActionView::Template::Handlers::ERB'
|
||||
delegate :logger, :to => 'ActionController::Base', :allow_nil => true
|
||||
@ -204,7 +206,10 @@ def initialize(lookup_context = nil, assigns_for_first_render = {}, controller =
|
||||
@assigns = assigns_for_first_render.each { |key, value| instance_variable_set("@#{key}", value) }
|
||||
@helpers = self.class.helpers || Module.new
|
||||
|
||||
@_controller = controller
|
||||
if @_controller = controller
|
||||
@_request = controller.request if controller.respond_to?(:request)
|
||||
end
|
||||
|
||||
@_config = ActiveSupport::InheritableOptions.new(controller.config) if controller && controller.respond_to?(:config)
|
||||
@_content_for = Hash.new { |h,k| h[k] = ActiveSupport::SafeBuffer.new }
|
||||
@_virtual_path = nil
|
||||
|
@ -29,16 +29,13 @@ module Helpers #:nodoc:
|
||||
autoload :TranslationHelper
|
||||
autoload :UrlHelper
|
||||
|
||||
def self.included(base)
|
||||
base.extend(ClassMethods)
|
||||
end
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
module ClassMethods
|
||||
include SanitizeHelper::ClassMethods
|
||||
included do
|
||||
extend SanitizeHelper::ClassMethods
|
||||
end
|
||||
|
||||
include ActiveSupport::Benchmarkable
|
||||
|
||||
include ActiveModelHelper
|
||||
include AssetTagHelper
|
||||
include AtomFeedHelper
|
||||
|
@ -96,6 +96,7 @@ module FormHelper
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
include FormTagHelper
|
||||
include UrlHelper
|
||||
|
||||
# Creates a form and a scope around a specific model object that is used
|
||||
# as a base for questioning about values for the fields.
|
||||
@ -120,7 +121,7 @@ module FormHelper
|
||||
# The generic way to call +form_for+ yields a form builder around a
|
||||
# model:
|
||||
#
|
||||
# <%= form_for :person, :url => { :action => "update" } do |f| %>
|
||||
# <%= form_for :person, :url => { :action => "create" } do |f| %>
|
||||
# <%= f.error_messages %>
|
||||
# First name: <%= f.text_field :first_name %><br />
|
||||
# Last name : <%= f.text_field :last_name %><br />
|
||||
@ -144,7 +145,7 @@ module FormHelper
|
||||
# If the instance variable is not <tt>@person</tt> you can pass the actual
|
||||
# record as the second argument:
|
||||
#
|
||||
# <%= form_for :person, person, :url => { :action => "update" } do |f| %>
|
||||
# <%= form_for :person, person, :url => { :action => "create" } do |f| %>
|
||||
# ...
|
||||
# <% end %>
|
||||
#
|
||||
@ -176,7 +177,7 @@ module FormHelper
|
||||
# possible to use both the stand-alone FormHelper methods and methods
|
||||
# from FormTagHelper. For example:
|
||||
#
|
||||
# <%= form_for :person, @person, :url => { :action => "update" } do |f| %>
|
||||
# <%= form_for :person, @person, :url => { :action => "create" } do |f| %>
|
||||
# First name: <%= f.text_field :first_name %>
|
||||
# Last name : <%= f.text_field :last_name %>
|
||||
# Biography : <%= text_area :person, :biography %>
|
||||
@ -264,7 +265,7 @@ module FormHelper
|
||||
# custom builder. For example, let's say you made a helper to
|
||||
# automatically add labels to form inputs.
|
||||
#
|
||||
# <%= form_for :person, @person, :url => { :action => "update" }, :builder => LabellingFormBuilder do |f| %>
|
||||
# <%= form_for :person, @person, :url => { :action => "create" }, :builder => LabellingFormBuilder do |f| %>
|
||||
# <%= f.text_field :first_name %>
|
||||
# <%= f.text_field :last_name %>
|
||||
# <%= text_area :person, :biography %>
|
||||
@ -341,7 +342,7 @@ def apply_form_for_options!(object_or_array, options) #:nodoc:
|
||||
#
|
||||
# === Generic Examples
|
||||
#
|
||||
# <%= form_for @person, :url => { :action => "update" } do |person_form| %>
|
||||
# <%= form_for @person do |person_form| %>
|
||||
# First name: <%= person_form.text_field :first_name %>
|
||||
# Last name : <%= person_form.text_field :last_name %>
|
||||
#
|
||||
@ -353,13 +354,13 @@ def apply_form_for_options!(object_or_array, options) #:nodoc:
|
||||
# ...or if you have an object that needs to be represented as a different
|
||||
# parameter, like a Client that acts as a Person:
|
||||
#
|
||||
# <%= fields_for :person, @client do |permission_fields| %>
|
||||
# <%= fields_for :person, @client, :url => { :action => "create" } do |permission_fields| %>
|
||||
# Admin?: <%= permission_fields.check_box :admin %>
|
||||
# <% end %>
|
||||
#
|
||||
# ...or if you don't have an object, just a name of the parameter:
|
||||
#
|
||||
# <%= fields_for :person do |permission_fields| %>
|
||||
# <%= fields_for :person, :url => { :action => "create" } do |permission_fields| %>
|
||||
# Admin?: <%= permission_fields.check_box :admin %>
|
||||
# <% end %>
|
||||
#
|
||||
@ -403,7 +404,7 @@ def apply_form_for_options!(object_or_array, options) #:nodoc:
|
||||
#
|
||||
# This model can now be used with a nested fields_for, like so:
|
||||
#
|
||||
# <%= form_for @person, :url => { :action => "update" } do |person_form| %>
|
||||
# <%= form_for @person do |person_form| %>
|
||||
# ...
|
||||
# <%= person_form.fields_for :address do |address_fields| %>
|
||||
# Street : <%= address_fields.text_field :street %>
|
||||
@ -432,7 +433,7 @@ def apply_form_for_options!(object_or_array, options) #:nodoc:
|
||||
# with a value that evaluates to +true+, you will destroy the associated
|
||||
# model (eg. 1, '1', true, or 'true'):
|
||||
#
|
||||
# <%= form_for @person, :url => { :action => "update" } do |person_form| %>
|
||||
# <%= form_for @person do |person_form| %>
|
||||
# ...
|
||||
# <%= person_form.fields_for :address do |address_fields| %>
|
||||
# ...
|
||||
@ -460,7 +461,7 @@ def apply_form_for_options!(object_or_array, options) #:nodoc:
|
||||
# the nested fields_for call will be repeated for each instance in the
|
||||
# collection:
|
||||
#
|
||||
# <%= form_for @person, :url => { :action => "update" } do |person_form| %>
|
||||
# <%= form_for @person do |person_form| %>
|
||||
# ...
|
||||
# <%= person_form.fields_for :projects do |project_fields| %>
|
||||
# <% if project_fields.object.active? %>
|
||||
@ -471,7 +472,7 @@ def apply_form_for_options!(object_or_array, options) #:nodoc:
|
||||
#
|
||||
# It's also possible to specify the instance to be used:
|
||||
#
|
||||
# <%= form_for @person, :url => { :action => "update" } do |person_form| %>
|
||||
# <%= form_for @person do |person_form| %>
|
||||
# ...
|
||||
# <% @person.projects.each do |project| %>
|
||||
# <% if project.active? %>
|
||||
@ -484,7 +485,7 @@ def apply_form_for_options!(object_or_array, options) #:nodoc:
|
||||
#
|
||||
# Or a collection to be used:
|
||||
#
|
||||
# <%= form_for @person, :url => { :action => "update" } do |person_form| %>
|
||||
# <%= form_for @person do |person_form| %>
|
||||
# ...
|
||||
# <%= person_form.fields_for :projects, @active_projects do |project_fields| %>
|
||||
# Name: <%= project_fields.text_field :name %>
|
||||
@ -513,7 +514,7 @@ def apply_form_for_options!(object_or_array, options) #:nodoc:
|
||||
# parameter with a value that evaluates to +true+
|
||||
# (eg. 1, '1', true, or 'true'):
|
||||
#
|
||||
# <%= form_for @person, :url => { :action => "update" } do |person_form| %>
|
||||
# <%= form_for @person do |person_form| %>
|
||||
# ...
|
||||
# <%= person_form.fields_for :projects do |project_fields| %>
|
||||
# Delete: <%= project_fields.check_box :_destroy %>
|
||||
|
@ -93,6 +93,10 @@ def form_tag(url_for_options = {}, options = {}, *parameters_for_url, &block)
|
||||
# # => <select disabled="disabled" id="destination" name="destination"><option>NYC</option>
|
||||
# # <option>Paris</option><option>Rome</option></select>
|
||||
def select_tag(name, option_tags = nil, options = {})
|
||||
if Array === option_tags
|
||||
ActiveSupport::Deprecation.warn 'Passing an array of option_tags to select_tag implicitly joins them without marking them as HTML-safe. Pass option_tags.join.html_safe instead.', caller
|
||||
end
|
||||
|
||||
html_name = (options[:multiple] == true && !name.to_s.ends_with?("[]")) ? "#{name}[]" : name
|
||||
if blank = options.delete(:include_blank)
|
||||
if blank.kind_of?(String)
|
||||
|
@ -273,8 +273,12 @@ def number_with_precision(number, *args)
|
||||
strip_insignificant_zeros = options.delete :strip_insignificant_zeros
|
||||
|
||||
if significant and precision > 0
|
||||
digits = (Math.log10(number) + 1).floor
|
||||
rounded_number = BigDecimal.new((number / 10 ** (digits - precision)).to_s).round.to_f * 10 ** (digits - precision)
|
||||
if number == 0
|
||||
digits, rounded_number = 1, 0
|
||||
else
|
||||
digits = (Math.log10(number) + 1).floor
|
||||
rounded_number = BigDecimal.new((number / 10 ** (digits - precision)).to_s).round.to_f * 10 ** (digits - precision)
|
||||
end
|
||||
precision = precision - digits
|
||||
precision = precision > 0 ? precision : 0 #don't let it be negative
|
||||
else
|
||||
|
@ -13,14 +13,15 @@ module UrlHelper
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
include ActionDispatch::Routing::UrlFor
|
||||
include JavaScriptHelper
|
||||
include TagHelper
|
||||
|
||||
# Need to map default url options to controller one.
|
||||
def default_url_options(*args) #:nodoc:
|
||||
controller.send(:default_url_options, *args)
|
||||
end
|
||||
|
||||
# def default_url_options(*args) #:nodoc:
|
||||
# controller.send(:default_url_options, *args)
|
||||
# end
|
||||
#
|
||||
def url_options
|
||||
return super unless controller.respond_to?(:url_options)
|
||||
controller.url_options
|
||||
end
|
||||
|
||||
@ -97,7 +98,7 @@ def url_for(options = {})
|
||||
when Hash
|
||||
options = { :only_path => options[:host].nil? }.update(options.symbolize_keys)
|
||||
escape = options.key?(:escape) ? options.delete(:escape) : false
|
||||
controller.send(:url_for, options)
|
||||
super
|
||||
when :back
|
||||
escape = false
|
||||
controller.request.env["HTTP_REFERER"] || 'javascript:history.back()'
|
||||
@ -119,13 +120,24 @@ def url_for(options = {})
|
||||
#
|
||||
# ==== Signatures
|
||||
#
|
||||
# link_to(name, options = {}, html_options = nil)
|
||||
# link_to(options = {}, html_options = nil) do
|
||||
# link_to(body, url, html_options = {})
|
||||
# # url is a String; you can use URL helpers like
|
||||
# # posts_path
|
||||
#
|
||||
# link_to(body, url_options = {}, html_options = {})
|
||||
# # url_options, except :confirm or :method,
|
||||
# # is passed to url_for
|
||||
#
|
||||
# link_to(options = {}, html_options = {}) do
|
||||
# # name
|
||||
# end
|
||||
#
|
||||
# link_to(url, html_options = {}) do
|
||||
# # name
|
||||
# end
|
||||
#
|
||||
# ==== Options
|
||||
# * <tt>:confirm => 'question?'</tt> - This will allow the unobtrusive JavaScript
|
||||
# * <tt>:confirm => 'question?'</tt> - This will allow the unobtrusive JavaScript
|
||||
# driver to prompt with the question specified. If the user accepts, the link is
|
||||
# processed normally, otherwise no action is taken.
|
||||
# * <tt>:method => symbol of HTTP verb</tt> - This modifier will dynamically
|
||||
@ -138,7 +150,11 @@ def url_for(options = {})
|
||||
# disabled clicking the link will have no effect. If you are relying on the
|
||||
# POST behavior, you should check for it in your controller's action by using
|
||||
# the request object's methods for <tt>post?</tt>, <tt>delete?</tt> or <tt>put?</tt>.
|
||||
# * The +html_options+ will accept a hash of html attributes for the link tag.
|
||||
# * <tt>:remote => true</tt> - This will allow the unobtrusive JavaScript
|
||||
# driver to make an Ajax request to the URL in question instead of following
|
||||
# the link. The drivers each provide mechanisms for listening for the
|
||||
# completion of the Ajax request and performing JavaScript operations once
|
||||
# they're complete
|
||||
#
|
||||
# ==== Examples
|
||||
# Because it relies on +url_for+, +link_to+ supports both older-style controller/action/id arguments
|
||||
@ -220,8 +236,8 @@ def link_to(*args, &block)
|
||||
options = args[1] || {}
|
||||
html_options = args[2]
|
||||
|
||||
url = url_for(options)
|
||||
html_options = convert_options_to_data_attributes(options, html_options)
|
||||
url = url_for(options)
|
||||
|
||||
if html_options
|
||||
html_options = html_options.stringify_keys
|
||||
@ -259,10 +275,10 @@ def link_to(*args, &block)
|
||||
# There are a few special +html_options+:
|
||||
# * <tt>:method</tt> - Specifies the anchor name to be appended to the path.
|
||||
# * <tt>:disabled</tt> - Specifies the anchor name to be appended to the path.
|
||||
# * <tt>:confirm</tt> - This will use the unobtrusive JavaScript driver to
|
||||
# * <tt>:confirm</tt> - This will use the unobtrusive JavaScript driver to
|
||||
# prompt with the question specified. If the user accepts, the link is
|
||||
# processed normally, otherwise no action is taken.
|
||||
# * <tt>:remote</tt> - If set to true, will allow the Unobtrusive JavaScript drivers to control the
|
||||
# * <tt>:remote</tt> - If set to true, will allow the Unobtrusive JavaScript drivers to control the
|
||||
# submit behaviour. By default this behaviour is an ajax submit.
|
||||
#
|
||||
# ==== Examples
|
||||
@ -282,7 +298,7 @@ def link_to(*args, &block)
|
||||
# # </form>"
|
||||
#
|
||||
#
|
||||
# <%= button_to('Destroy', 'http://www.example.com', :confirm => 'Are you sure?',
|
||||
# <%= button_to('Destroy', 'http://www.example.com', :confirm => 'Are you sure?',
|
||||
# :method => "delete", :remote => true, :disable_with => 'loading...') %>
|
||||
# # => "<form class='button-to' method='post' action='http://www.example.com' data-remote='true'>
|
||||
# # <div>
|
||||
@ -546,8 +562,14 @@ def mail_to(email_address, name = nil, html_options = {})
|
||||
# current_page?(:controller => 'library', :action => 'checkout')
|
||||
# # => false
|
||||
def current_page?(options)
|
||||
unless request
|
||||
raise "You cannot use helpers that need to determine the current " \
|
||||
"page unless your view context provides a Request object " \
|
||||
"in a #request method"
|
||||
end
|
||||
|
||||
url_string = CGI.unescapeHTML(url_for(options))
|
||||
request = controller.request
|
||||
|
||||
# We ignore any extra parameters in the request_uri if the
|
||||
# submitted url doesn't have any either. This lets the function
|
||||
# work with things like ?order=asc
|
||||
|
@ -179,7 +179,7 @@ class PartialRenderer
|
||||
|
||||
def initialize(view_context, options, block)
|
||||
@view = view_context
|
||||
@partial_names = PARTIAL_NAMES[@view.controller.class]
|
||||
@partial_names = PARTIAL_NAMES[@view.controller.class.name]
|
||||
|
||||
setup(options, block)
|
||||
end
|
||||
@ -300,7 +300,7 @@ def find_template(path=@path)
|
||||
end
|
||||
|
||||
def partial_path(object = @object)
|
||||
@partial_names[object.class] ||= begin
|
||||
@partial_names[object.class.name] ||= begin
|
||||
object = object.to_model if object.respond_to?(:to_model)
|
||||
|
||||
object.class.model_name.partial_path.dup.tap do |partial|
|
||||
|
@ -18,6 +18,14 @@ class Template
|
||||
|
||||
attr_reader :source, :identifier, :handler, :virtual_path, :formats
|
||||
|
||||
def self.finalizer_for(method_name)
|
||||
proc do
|
||||
ActionView::CompiledTemplates.module_eval do
|
||||
remove_possible_method method_name
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def initialize(source, identifier, handler, details)
|
||||
@source = source
|
||||
@identifier = identifier
|
||||
@ -98,6 +106,7 @@ def #{method_name}(local_assigns)
|
||||
|
||||
begin
|
||||
ActionView::CompiledTemplates.module_eval(source, identifier, line)
|
||||
ObjectSpace.define_finalizer(self, self.class.finalizer_for(method_name))
|
||||
method_name
|
||||
rescue Exception => e # errors from template code
|
||||
if logger = (view && view.logger)
|
||||
|
@ -142,8 +142,13 @@ def _assigns
|
||||
end
|
||||
end
|
||||
|
||||
def _router
|
||||
@controller._router if @controller.respond_to?(:_router)
|
||||
end
|
||||
|
||||
def method_missing(selector, *args)
|
||||
if @controller._router.named_routes.helpers.include?(selector)
|
||||
if @controller.respond_to?(:_router) &&
|
||||
@controller._router.named_routes.helpers.include?(selector)
|
||||
@controller.__send__(selector, *args)
|
||||
else
|
||||
super
|
||||
|
@ -57,6 +57,18 @@ def body_to_string(body)
|
||||
extend self
|
||||
end
|
||||
|
||||
module RenderERBUtils
|
||||
def render_erb(string)
|
||||
template = ActionView::Template.new(
|
||||
string.strip,
|
||||
"test template",
|
||||
ActionView::Template::Handlers::ERB,
|
||||
{})
|
||||
|
||||
template.render(self, {}).strip
|
||||
end
|
||||
end
|
||||
|
||||
module SetupOnce
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
@ -225,6 +237,14 @@ def assert_header(name, value)
|
||||
end
|
||||
end
|
||||
|
||||
class ActionController::Base
|
||||
def self.test_routes(&block)
|
||||
router = ActionDispatch::Routing::RouteSet.new
|
||||
router.draw(&block)
|
||||
include router.url_helpers
|
||||
end
|
||||
end
|
||||
|
||||
class ::ApplicationController < ActionController::Base
|
||||
end
|
||||
|
||||
|
@ -58,8 +58,9 @@ def self.matches?(request)
|
||||
get 'admin/accounts' => "queenbee#accounts"
|
||||
end
|
||||
|
||||
scope 'es' do
|
||||
resources :projects, :path_names => { :edit => 'cambiar' }, :as => 'projeto'
|
||||
scope 'pt', :name_prefix => 'pt' do
|
||||
resources :projects, :path_names => { :edit => 'editar' }, :path => 'projetos'
|
||||
resource :admin, :path_names => { :new => 'novo' }, :path => 'administrador'
|
||||
end
|
||||
|
||||
resources :projects, :controller => :project do
|
||||
@ -74,10 +75,14 @@ def self.matches?(request)
|
||||
resource :avatar, :controller => :avatar
|
||||
end
|
||||
|
||||
resources :images do
|
||||
resources :images, :as => :funny_images do
|
||||
post :revise, :on => :member
|
||||
end
|
||||
|
||||
resource :manager, :as => :super_manager do
|
||||
post :fire
|
||||
end
|
||||
|
||||
resources :people do
|
||||
nested do
|
||||
scope "/:access_token" do
|
||||
@ -144,7 +149,7 @@ def self.matches?(request)
|
||||
end
|
||||
|
||||
namespace :forum do
|
||||
resources :products, :as => '' do
|
||||
resources :products, :path => '' do
|
||||
resources :questions
|
||||
end
|
||||
end
|
||||
@ -430,15 +435,35 @@ def test_projects_companies
|
||||
end
|
||||
end
|
||||
|
||||
def test_project_manager
|
||||
with_test_routes do
|
||||
get '/projects/1/manager'
|
||||
assert_equal 'managers#show', @response.body
|
||||
assert_equal '/projects/1/manager', project_super_manager_path(:project_id => '1')
|
||||
|
||||
get '/projects/1/manager/new'
|
||||
assert_equal 'managers#new', @response.body
|
||||
assert_equal '/projects/1/manager/new', new_project_super_manager_path(:project_id => '1')
|
||||
|
||||
post '/projects/1/manager/fire'
|
||||
assert_equal 'managers#fire', @response.body
|
||||
assert_equal '/projects/1/manager/fire', fire_project_super_manager_path(:project_id => '1')
|
||||
end
|
||||
end
|
||||
|
||||
def test_project_images
|
||||
with_test_routes do
|
||||
get '/projects/1/images'
|
||||
assert_equal 'images#index', @response.body
|
||||
assert_equal '/projects/1/images', project_images_path(:project_id => '1')
|
||||
assert_equal '/projects/1/images', project_funny_images_path(:project_id => '1')
|
||||
|
||||
get '/projects/1/images/new'
|
||||
assert_equal 'images#new', @response.body
|
||||
assert_equal '/projects/1/images/new', new_project_funny_image_path(:project_id => '1')
|
||||
|
||||
post '/projects/1/images/1/revise'
|
||||
assert_equal 'images#revise', @response.body
|
||||
assert_equal '/projects/1/images/1/revise', revise_project_image_path(:project_id => '1', :id => '1')
|
||||
assert_equal '/projects/1/images/1/revise', revise_project_funny_image_path(:project_id => '1', :id => '1')
|
||||
end
|
||||
end
|
||||
|
||||
@ -552,11 +577,21 @@ def test_resources_for_uncountable_names
|
||||
|
||||
def test_path_names
|
||||
with_test_routes do
|
||||
get '/es/projeto'
|
||||
get '/pt/projetos'
|
||||
assert_equal 'projects#index', @response.body
|
||||
assert_equal '/pt/projetos', pt_projects_path
|
||||
|
||||
get '/es/projeto/1/cambiar'
|
||||
get '/pt/projetos/1/editar'
|
||||
assert_equal 'projects#edit', @response.body
|
||||
assert_equal '/pt/projetos/1/editar', edit_pt_project_path(1)
|
||||
|
||||
get '/pt/administrador'
|
||||
assert_equal 'admins#show', @response.body
|
||||
assert_equal '/pt/administrador', pt_admin_path
|
||||
|
||||
get '/pt/administrador/novo'
|
||||
assert_equal 'admins#new', @response.body
|
||||
assert_equal '/pt/administrador/novo', new_pt_admin_path
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -118,13 +118,12 @@ def setup
|
||||
setup_user
|
||||
|
||||
@response = ActionController::TestResponse.new
|
||||
end
|
||||
|
||||
@controller = Object.new
|
||||
def @controller.url_for(options)
|
||||
options = options.symbolize_keys
|
||||
def url_for(options)
|
||||
options = options.symbolize_keys
|
||||
|
||||
[options[:action], options[:id].to_param].compact.join('/')
|
||||
end
|
||||
[options[:action], options[:id].to_param].compact.join('/')
|
||||
end
|
||||
|
||||
def test_generic_input_tag
|
||||
|
@ -34,9 +34,7 @@ def setup
|
||||
)
|
||||
end
|
||||
|
||||
@controller = Class.new(BasicController) do
|
||||
def url_for(*args) "http://www.example.com" end
|
||||
end.new
|
||||
@controller = BasicController.new
|
||||
|
||||
@request = Class.new do
|
||||
def protocol() 'http://' end
|
||||
@ -49,6 +47,10 @@ def host_with_port() 'localhost' end
|
||||
ActionView::Helpers::AssetTagHelper::reset_javascript_include_default
|
||||
end
|
||||
|
||||
def url_for(*args)
|
||||
"http://www.example.com"
|
||||
end
|
||||
|
||||
def teardown
|
||||
config.perform_caching = false
|
||||
ENV.delete('RAILS_ASSET_ID')
|
||||
@ -893,25 +895,19 @@ class AssetTagHelperNonVhostTest < ActionView::TestCase
|
||||
|
||||
def setup
|
||||
super
|
||||
@controller = Class.new(BasicController) do
|
||||
def url_for(options)
|
||||
"http://www.example.com/collaboration/hieraki"
|
||||
end
|
||||
end.new
|
||||
|
||||
@controller = BasicController.new
|
||||
@controller.config.relative_url_root = "/collaboration/hieraki"
|
||||
|
||||
@request = Class.new do
|
||||
def protocol
|
||||
'gopher://'
|
||||
end
|
||||
end.new
|
||||
|
||||
@request = Struct.new(:protocol).new("gopher://")
|
||||
@controller.request = @request
|
||||
|
||||
ActionView::Helpers::AssetTagHelper::reset_javascript_include_default
|
||||
end
|
||||
|
||||
def url_for(options)
|
||||
"http://www.example.com/collaboration/hieraki"
|
||||
end
|
||||
|
||||
def test_should_compute_proper_path
|
||||
assert_dom_equal(%(<link href="http://www.example.com/collaboration/hieraki" rel="alternate" title="RSS" type="application/rss+xml" />), auto_discovery_link_tag)
|
||||
assert_dom_equal(%(/collaboration/hieraki/javascripts/xmlhr.js), javascript_path("xmlhr"))
|
||||
|
@ -1,20 +1,13 @@
|
||||
module ERBTest
|
||||
class ViewContext
|
||||
mock_controller = Class.new do
|
||||
include SharedTestRoutes.url_helpers
|
||||
end
|
||||
|
||||
include SharedTestRoutes.url_helpers
|
||||
include ActionView::Helpers::TagHelper
|
||||
include ActionView::Helpers::JavaScriptHelper
|
||||
include ActionView::Helpers::FormHelper
|
||||
|
||||
attr_accessor :output_buffer
|
||||
attr_accessor :output_buffer, :controller
|
||||
|
||||
def protect_against_forgery?() false end
|
||||
|
||||
define_method(:controller) do
|
||||
mock_controller.new
|
||||
end
|
||||
end
|
||||
|
||||
class BlockTestCase < ActiveSupport::TestCase
|
||||
|
@ -63,15 +63,15 @@ def @post.to_param; '123'; end
|
||||
@post.body = "Back to the hill and over it again!"
|
||||
@post.secret = 1
|
||||
@post.written_on = Date.new(2004, 6, 15)
|
||||
end
|
||||
|
||||
@controller = Class.new do
|
||||
attr_reader :url_for_options
|
||||
def url_for(options)
|
||||
@url_for_options = options
|
||||
"http://www.example.com"
|
||||
end
|
||||
def url_for(object)
|
||||
@url_for_options = object
|
||||
if object.is_a?(Hash)
|
||||
"http://www.example.com"
|
||||
else
|
||||
super
|
||||
end
|
||||
@controller = @controller.new
|
||||
end
|
||||
|
||||
def test_label
|
||||
@ -1348,8 +1348,8 @@ def test_form_for_with_string_url_option
|
||||
def test_form_for_with_hash_url_option
|
||||
form_for(:post, @post, :url => {:controller => 'controller', :action => 'action'}) do |f| end
|
||||
|
||||
assert_equal 'controller', @controller.url_for_options[:controller]
|
||||
assert_equal 'action', @controller.url_for_options[:action]
|
||||
assert_equal 'controller', @url_for_options[:controller]
|
||||
assert_equal 'action', @url_for_options[:action]
|
||||
end
|
||||
|
||||
def test_form_for_with_record_url_option
|
||||
|
@ -8,11 +8,15 @@ class FormTagHelperTest < ActionView::TestCase
|
||||
|
||||
def setup
|
||||
super
|
||||
@controller = Class.new(BasicController) do
|
||||
def url_for(options)
|
||||
"http://www.example.com"
|
||||
end
|
||||
end.new
|
||||
@controller = BasicController.new
|
||||
end
|
||||
|
||||
def url_for(options)
|
||||
if options.is_a?(Hash)
|
||||
"http://www.example.com"
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
VALID_HTML_ID = /^[A-Za-z][-_:.A-Za-z0-9]*$/ # see http://www.w3.org/TR/html4/types.html#type-name
|
||||
@ -158,6 +162,12 @@ def test_select_tag_with_include_blank_with_string
|
||||
assert_dom_equal expected, actual
|
||||
end
|
||||
|
||||
def test_select_tag_with_array_options
|
||||
assert_deprecated /array/ do
|
||||
select_tag "people", ["<option>david</option>"]
|
||||
end
|
||||
end
|
||||
|
||||
def test_text_area_tag_size_string
|
||||
actual = text_area_tag "body", "hello world", "size" => "20x40"
|
||||
expected = %(<textarea cols="20" id="body" name="body" rows="40">hello world</textarea>)
|
||||
|
@ -102,6 +102,9 @@ def test_number_with_precision
|
||||
assert_equal("3268", number_with_precision((32.6751 * 100.00), :precision => 0))
|
||||
assert_equal("112", number_with_precision(111.50, :precision => 0))
|
||||
assert_equal("1234567892", number_with_precision(1234567891.50, :precision => 0))
|
||||
assert_equal("0", number_with_precision(0, :precision => 0))
|
||||
assert_equal("0.00100", number_with_precision(0.001, :precision => 5))
|
||||
assert_equal("0.001", number_with_precision(0.00111, :precision => 3))
|
||||
end
|
||||
|
||||
def test_number_with_precision_with_custom_delimiter_and_separator
|
||||
@ -122,11 +125,17 @@ def test_number_with_precision_with_significant_digits
|
||||
assert_equal "53", number_with_precision(52.7923, :precision => 2, :significant => true )
|
||||
assert_equal "9775.00", number_with_precision(9775, :precision => 6, :significant => true )
|
||||
assert_equal "5.392900", number_with_precision(5.3929, :precision => 7, :significant => true )
|
||||
assert_equal "0.0", number_with_precision(0, :precision => 2, :significant => true )
|
||||
assert_equal "0", number_with_precision(0, :precision => 1, :significant => true )
|
||||
assert_equal "0.0001", number_with_precision(0.0001, :precision => 1, :significant => true )
|
||||
assert_equal "0.000100", number_with_precision(0.0001, :precision => 3, :significant => true )
|
||||
assert_equal "0.0001", number_with_precision(0.0001111, :precision => 1, :significant => true )
|
||||
end
|
||||
|
||||
def test_number_with_precision_with_strip_insignificant_zeros
|
||||
assert_equal "9775.43", number_with_precision(9775.43, :precision => 4, :strip_insignificant_zeros => true )
|
||||
assert_equal "9775.2", number_with_precision(9775.2, :precision => 6, :significant => true, :strip_insignificant_zeros => true )
|
||||
assert_equal "0", number_with_precision(0, :precision => 6, :significant => true, :strip_insignificant_zeros => true )
|
||||
end
|
||||
|
||||
def test_number_with_precision_with_significant_true_and_zero_precision
|
||||
|
@ -47,19 +47,18 @@ def update_details(details)
|
||||
def setup
|
||||
super
|
||||
@template = self
|
||||
@controller = Class.new do
|
||||
def url_for(options)
|
||||
if options.is_a?(String)
|
||||
options
|
||||
else
|
||||
url = "http://www.example.com/"
|
||||
url << options[:action].to_s if options and options[:action]
|
||||
url << "?a=#{options[:a]}" if options && options[:a]
|
||||
url << "&b=#{options[:b]}" if options && options[:a] && options[:b]
|
||||
url
|
||||
end
|
||||
end
|
||||
end.new
|
||||
end
|
||||
|
||||
def url_for(options)
|
||||
if options.is_a?(String)
|
||||
options
|
||||
else
|
||||
url = "http://www.example.com/"
|
||||
url << options[:action].to_s if options and options[:action]
|
||||
url << "?a=#{options[:a]}" if options && options[:a]
|
||||
url << "&b=#{options[:b]}" if options && options[:a] && options[:b]
|
||||
url
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
|
@ -281,6 +281,10 @@ def setup
|
||||
assert_equal ActionView::FileSystemResolver, view_paths.first.class
|
||||
setup_view(view_paths)
|
||||
end
|
||||
|
||||
def teardown
|
||||
GC.start
|
||||
end
|
||||
end
|
||||
|
||||
class LazyViewRenderTest < ActiveSupport::TestCase
|
||||
@ -294,4 +298,8 @@ def setup
|
||||
assert_equal ActionView::FileSystemResolver.new(FIXTURE_LOAD_PATH), view_paths.first
|
||||
setup_view(view_paths)
|
||||
end
|
||||
|
||||
def teardown
|
||||
GC.start
|
||||
end
|
||||
end
|
||||
|
@ -3,21 +3,16 @@
|
||||
class ScriptaculousHelperTest < ActionView::TestCase
|
||||
tests ActionView::Helpers::ScriptaculousHelper
|
||||
|
||||
def setup
|
||||
super
|
||||
@controller = Class.new do
|
||||
def url_for(options)
|
||||
url = "http://www.example.com/"
|
||||
url << options[:action].to_s if options and options[:action]
|
||||
url
|
||||
end
|
||||
end.new
|
||||
def url_for(options)
|
||||
url = "http://www.example.com/"
|
||||
url << options[:action].to_s if options and options[:action]
|
||||
url
|
||||
end
|
||||
|
||||
|
||||
def test_effect
|
||||
assert_equal "new Effect.Highlight(\"posts\",{});", visual_effect(:highlight, "posts")
|
||||
assert_equal "new Effect.Highlight(\"posts\",{});", visual_effect("highlight", :posts)
|
||||
assert_equal "new Effect.Highlight(\"posts\",{});", visual_effect(:highlight, :posts)
|
||||
assert_equal "new Effect.Highlight(\"posts\",{});", visual_effect(:highlight, :posts)
|
||||
assert_equal "new Effect.Fade(\"fademe\",{duration:4.0});", visual_effect(:fade, "fademe", :duration => 4.0)
|
||||
assert_equal "new Effect.Shake(element,{});", visual_effect(:shake)
|
||||
assert_equal "new Effect.DropOut(\"dropme\",{queue:'end'});", visual_effect(:drop_out, 'dropme', :queue => :end)
|
||||
@ -43,7 +38,7 @@ def test_effect
|
||||
assert ve[2].include?("scope:'test'")
|
||||
assert ve[2].include?("position:'end'")
|
||||
end
|
||||
|
||||
|
||||
def test_toggle_effects
|
||||
assert_equal "Effect.toggle(\"posts\",'appear',{});", visual_effect(:toggle_appear, "posts")
|
||||
assert_equal "Effect.toggle(\"posts\",'slide',{});", visual_effect(:toggle_slide, "posts")
|
||||
@ -52,26 +47,26 @@ def test_toggle_effects
|
||||
assert_equal "Effect.toggle(\"posts\",'slide',{});", visual_effect("toggle_slide", "posts")
|
||||
assert_equal "Effect.toggle(\"posts\",'blind',{});", visual_effect("toggle_blind", "posts")
|
||||
end
|
||||
|
||||
|
||||
|
||||
def test_sortable_element
|
||||
assert_dom_equal %(<script type=\"text/javascript\">\n//<![CDATA[\nSortable.create(\"mylist\", {onUpdate:function(){new Ajax.Request('http://www.example.com/order', {asynchronous:true, evalScripts:true, parameters:Sortable.serialize(\"mylist\")})}})\n//]]>\n</script>),
|
||||
assert_dom_equal %(<script type=\"text/javascript\">\n//<![CDATA[\nSortable.create(\"mylist\", {onUpdate:function(){new Ajax.Request('http://www.example.com/order', {asynchronous:true, evalScripts:true, parameters:Sortable.serialize(\"mylist\")})}})\n//]]>\n</script>),
|
||||
sortable_element("mylist", :url => { :action => "order" })
|
||||
assert_equal %(<script type=\"text/javascript\">\n//<![CDATA[\nSortable.create(\"mylist\", {constraint:'horizontal', onUpdate:function(){new Ajax.Request('http://www.example.com/order', {asynchronous:true, evalScripts:true, parameters:Sortable.serialize(\"mylist\")})}, tag:'div'})\n//]]>\n</script>),
|
||||
assert_equal %(<script type=\"text/javascript\">\n//<![CDATA[\nSortable.create(\"mylist\", {constraint:'horizontal', onUpdate:function(){new Ajax.Request('http://www.example.com/order', {asynchronous:true, evalScripts:true, parameters:Sortable.serialize(\"mylist\")})}, tag:'div'})\n//]]>\n</script>),
|
||||
sortable_element("mylist", :tag => "div", :constraint => "horizontal", :url => { :action => "order" })
|
||||
assert_dom_equal %|<script type=\"text/javascript\">\n//<![CDATA[\nSortable.create(\"mylist\", {constraint:'horizontal', containment:['list1','list2'], onUpdate:function(){new Ajax.Request('http://www.example.com/order', {asynchronous:true, evalScripts:true, parameters:Sortable.serialize(\"mylist\")})}})\n//]]>\n</script>|,
|
||||
assert_dom_equal %|<script type=\"text/javascript\">\n//<![CDATA[\nSortable.create(\"mylist\", {constraint:'horizontal', containment:['list1','list2'], onUpdate:function(){new Ajax.Request('http://www.example.com/order', {asynchronous:true, evalScripts:true, parameters:Sortable.serialize(\"mylist\")})}})\n//]]>\n</script>|,
|
||||
sortable_element("mylist", :containment => ['list1','list2'], :constraint => "horizontal", :url => { :action => "order" })
|
||||
assert_dom_equal %(<script type=\"text/javascript\">\n//<![CDATA[\nSortable.create(\"mylist\", {constraint:'horizontal', containment:'list1', onUpdate:function(){new Ajax.Request('http://www.example.com/order', {asynchronous:true, evalScripts:true, parameters:Sortable.serialize(\"mylist\")})}})\n//]]>\n</script>),
|
||||
assert_dom_equal %(<script type=\"text/javascript\">\n//<![CDATA[\nSortable.create(\"mylist\", {constraint:'horizontal', containment:'list1', onUpdate:function(){new Ajax.Request('http://www.example.com/order', {asynchronous:true, evalScripts:true, parameters:Sortable.serialize(\"mylist\")})}})\n//]]>\n</script>),
|
||||
sortable_element("mylist", :containment => 'list1', :constraint => "horizontal", :url => { :action => "order" })
|
||||
end
|
||||
|
||||
|
||||
def test_draggable_element
|
||||
assert_dom_equal %(<script type=\"text/javascript\">\n//<![CDATA[\nnew Draggable(\"product_13\", {})\n//]]>\n</script>),
|
||||
draggable_element("product_13")
|
||||
assert_equal %(<script type=\"text/javascript\">\n//<![CDATA[\nnew Draggable(\"product_13\", {revert:true})\n//]]>\n</script>),
|
||||
draggable_element("product_13", :revert => true)
|
||||
end
|
||||
|
||||
|
||||
def test_drop_receiving_element
|
||||
assert_dom_equal %(<script type=\"text/javascript\">\n//<![CDATA[\nDroppables.add(\"droptarget1\", {onDrop:function(element){new Ajax.Request('http://www.example.com/', {asynchronous:true, evalScripts:true, parameters:'id=' + encodeURIComponent(element.id)})}})\n//]]>\n</script>),
|
||||
drop_receiving_element("droptarget1")
|
||||
|
@ -3,58 +3,73 @@
|
||||
require 'active_support/ordered_options'
|
||||
require 'controller/fake_controllers'
|
||||
|
||||
class UrlHelperTest < ActionView::TestCase
|
||||
class UrlHelperTest < ActiveSupport::TestCase
|
||||
|
||||
def setup
|
||||
super
|
||||
@controller = Class.new(BasicController) do
|
||||
attr_accessor :url
|
||||
def url_for(options)
|
||||
url
|
||||
end
|
||||
end
|
||||
# In a few cases, the helper proxies to 'controller'
|
||||
# or request.
|
||||
#
|
||||
# In those cases, we'll set up a simple mock
|
||||
attr_accessor :controller, :request
|
||||
|
||||
@controller = @controller.new
|
||||
@request = @controller.request = ActionDispatch::TestRequest.new
|
||||
@controller.url = "http://www.example.com"
|
||||
routes = ActionDispatch::Routing::RouteSet.new
|
||||
routes.draw do
|
||||
match "/" => "foo#bar"
|
||||
match "/other" => "foo#other"
|
||||
end
|
||||
|
||||
include routes.url_helpers
|
||||
|
||||
include ActionView::Helpers::UrlHelper
|
||||
include ActionDispatch::Assertions::DomAssertions
|
||||
include ActionView::Context
|
||||
include RenderERBUtils
|
||||
|
||||
# self.default_url_options = {:host => "www.example.com"}
|
||||
|
||||
# TODO: This shouldn't be needed (see template.rb:53)
|
||||
def assigns
|
||||
{}
|
||||
end
|
||||
|
||||
def abcd(hash = {})
|
||||
hash_for(:a => :b, :c => :d).merge(hash)
|
||||
end
|
||||
|
||||
def hash_for(opts = {})
|
||||
{:controller => "foo", :action => "bar"}.merge(opts)
|
||||
end
|
||||
alias url_hash hash_for
|
||||
|
||||
def test_url_for_escapes_urls
|
||||
@controller.url = "http://www.example.com?a=b&c=d"
|
||||
assert_equal "http://www.example.com?a=b&c=d", url_for(:a => 'b', :c => 'd')
|
||||
assert_equal "http://www.example.com?a=b&c=d", url_for(:a => 'b', :c => 'd', :escape => true)
|
||||
assert_equal "http://www.example.com?a=b&c=d", url_for(:a => 'b', :c => 'd', :escape => false)
|
||||
assert_equal "/?a=b&c=d", url_for(abcd)
|
||||
assert_equal "/?a=b&c=d", url_for(abcd(:escape => true))
|
||||
assert_equal "/?a=b&c=d", url_for(abcd(:escape => false))
|
||||
end
|
||||
|
||||
def test_url_for_escaping_is_safety_aware
|
||||
assert url_for(:a => 'b', :c => 'd', :escape => true).html_safe?, "escaped urls should be html_safe?"
|
||||
assert !url_for(:a => 'b', :c => 'd', :escape => false).html_safe?, "non-escaped urls shouldn't be safe"
|
||||
assert url_for(abcd(:escape => true)).html_safe?, "escaped urls should be html_safe?"
|
||||
assert !url_for(abcd(:escape => false)).html_safe?, "non-escaped urls should not be html_safe?"
|
||||
end
|
||||
|
||||
def test_url_for_escapes_url_once
|
||||
@controller.url = "http://www.example.com?a=b&c=d"
|
||||
assert_equal "http://www.example.com?a=b&c=d", url_for("http://www.example.com?a=b&c=d")
|
||||
assert_equal "/?a=b&c=d", url_for("/?a=b&c=d")
|
||||
end
|
||||
|
||||
def test_url_for_with_back
|
||||
@request.env['HTTP_REFERER'] = 'http://www.example.com/referer'
|
||||
referer = 'http://www.example.com/referer'
|
||||
@controller = Struct.new(:request).new(Struct.new(:env).new({"HTTP_REFERER" => referer}))
|
||||
|
||||
assert_equal 'http://www.example.com/referer', url_for(:back)
|
||||
end
|
||||
|
||||
def test_url_for_with_back_and_no_referer
|
||||
@request.env['HOST_NAME'] = 'www.example.com'
|
||||
@request.env['PATH_INFO'] = '/weblog/show'
|
||||
@controller = Struct.new(:request).new(Struct.new(:env).new({}))
|
||||
assert_equal 'javascript:history.back()', url_for(:back)
|
||||
end
|
||||
|
||||
def test_url_for_from_hash_doesnt_escape_ampersand
|
||||
@controller = TestController.new
|
||||
@view = ActionView::Base.new
|
||||
@view.controller = @controller
|
||||
|
||||
path = @view.url_for(:controller => :cheeses, :foo => :bar, :baz => :quux)
|
||||
|
||||
assert_equal '/cheeses?baz=quux&foo=bar', sort_query_string_params(path)
|
||||
path = url_for(hash_for(:foo => :bar, :baz => :quux))
|
||||
assert_equal '/?baz=quux&foo=bar', sort_query_string_params(path)
|
||||
end
|
||||
|
||||
# todo: missing test cases
|
||||
@ -118,65 +133,54 @@ def test_link_tag_with_straight_url
|
||||
end
|
||||
|
||||
def test_link_tag_without_host_option
|
||||
ActionController::Base.class_eval { attr_accessor :url }
|
||||
url = {:controller => 'weblog', :action => 'show'}
|
||||
@controller = ActionController::Base.new
|
||||
@controller.request = ActionController::TestRequest.new
|
||||
assert_dom_equal(%q{<a href="/weblog/show">Test Link</a>}, link_to('Test Link', url))
|
||||
assert_dom_equal(%q{<a href="/">Test Link</a>}, link_to('Test Link', url_hash))
|
||||
end
|
||||
|
||||
def test_link_tag_with_host_option
|
||||
ActionController::Base.class_eval { attr_accessor :url }
|
||||
url = {:controller => 'weblog', :action => 'show', :host => 'www.example.com'}
|
||||
@controller = ActionController::Base.new
|
||||
@controller.request = ActionController::TestRequest.new
|
||||
assert_dom_equal(%q{<a href="http://www.example.com/weblog/show">Test Link</a>}, link_to('Test Link', url))
|
||||
hash = hash_for(:host => "www.example.com")
|
||||
expected = %q{<a href="http://www.example.com/">Test Link</a>}
|
||||
assert_dom_equal(expected, link_to('Test Link', hash))
|
||||
end
|
||||
|
||||
def test_link_tag_with_query
|
||||
assert_dom_equal "<a href=\"http://www.example.com?q1=v1&q2=v2\">Hello</a>", link_to("Hello", "http://www.example.com?q1=v1&q2=v2")
|
||||
expected = %{<a href="http://www.example.com?q1=v1&q2=v2">Hello</a>}
|
||||
assert_dom_equal expected, link_to("Hello", "http://www.example.com?q1=v1&q2=v2")
|
||||
end
|
||||
|
||||
def test_link_tag_with_query_and_no_name
|
||||
assert_dom_equal "<a href=\"http://www.example.com?q1=v1&q2=v2\">http://www.example.com?q1=v1&q2=v2</a>", link_to(nil, "http://www.example.com?q1=v1&q2=v2")
|
||||
link = link_to(nil, "http://www.example.com?q1=v1&q2=v2")
|
||||
expected = %{<a href="http://www.example.com?q1=v1&q2=v2">http://www.example.com?q1=v1&q2=v2</a>}
|
||||
assert_dom_equal expected, link
|
||||
end
|
||||
|
||||
def test_link_tag_with_back
|
||||
@request.env['HOST_NAME'] = 'www.example.com'
|
||||
@request.env['PATH_INFO'] = '/weblog/show'
|
||||
@request.env['HTTP_REFERER'] = 'http://www.example.com/referer'
|
||||
assert_dom_equal "<a href=\"http://www.example.com/referer\">go back</a>", link_to('go back', :back)
|
||||
env = {"HTTP_REFERER" => "http://www.example.com/referer"}
|
||||
@controller = Struct.new(:request).new(Struct.new(:env).new(env))
|
||||
expected = %{<a href="#{env["HTTP_REFERER"]}">go back</a>}
|
||||
assert_dom_equal expected, link_to('go back', :back)
|
||||
end
|
||||
|
||||
def test_link_tag_with_back_and_no_referer
|
||||
@request.env['HOST_NAME'] = 'www.example.com'
|
||||
@request.env['PATH_INFO'] = '/weblog/show'
|
||||
assert_dom_equal "<a href=\"javascript:history.back()\">go back</a>", link_to('go back', :back)
|
||||
end
|
||||
|
||||
def test_link_tag_with_back
|
||||
@request.env['HOST_NAME'] = 'www.example.com'
|
||||
@request.env['PATH_INFO'] = '/weblog/show'
|
||||
@request.env['HTTP_REFERER'] = 'http://www.example.com/referer'
|
||||
assert_dom_equal "<a href=\"http://www.example.com/referer\">go back</a>", link_to('go back', :back)
|
||||
end
|
||||
|
||||
def test_link_tag_with_back_and_no_referer
|
||||
@request.env['HOST_NAME'] = 'www.example.com'
|
||||
@request.env['PATH_INFO'] = '/weblog/show'
|
||||
assert_dom_equal "<a href=\"javascript:history.back()\">go back</a>", link_to('go back', :back)
|
||||
@controller = Struct.new(:request).new(Struct.new(:env).new({}))
|
||||
link = link_to('go back', :back)
|
||||
assert_dom_equal %{<a href="javascript:history.back()">go back</a>}, link
|
||||
end
|
||||
|
||||
def test_link_tag_with_img
|
||||
assert_dom_equal "<a href=\"http://www.example.com\"><img src='/favicon.jpg' alt=\"Favicon\" /></a>", link_to(image_tag("/favicon.jpg"), "http://www.example.com")
|
||||
link = link_to("<img src='/favicon.jpg' />".html_safe, "/")
|
||||
expected = %{<a href="/"><img src='/favicon.jpg' /></a>}
|
||||
assert_dom_equal expected, link
|
||||
end
|
||||
|
||||
def test_link_with_nil_html_options
|
||||
assert_dom_equal "<a href=\"http://www.example.com\">Hello</a>", link_to("Hello", {:action => 'myaction'}, nil)
|
||||
link = link_to("Hello", url_hash, nil)
|
||||
assert_dom_equal %{<a href="/">Hello</a>}, link
|
||||
end
|
||||
|
||||
def test_link_tag_with_custom_onclick
|
||||
assert_dom_equal "<a href=\"http://www.example.com\" onclick=\"alert('yay!')\">Hello</a>", link_to("Hello", "http://www.example.com", :onclick => "alert('yay!')")
|
||||
link = link_to("Hello", "http://www.example.com", :onclick => "alert('yay!')")
|
||||
expected = %{<a href="http://www.example.com" onclick="alert('yay!')">Hello</a>}
|
||||
assert_dom_equal expected, link
|
||||
end
|
||||
|
||||
def test_link_tag_with_javascript_confirm
|
||||
@ -238,91 +242,106 @@ def test_link_tag_using_delete_javascript_and_href_and_confirm
|
||||
end
|
||||
|
||||
def test_link_tag_using_block_in_erb
|
||||
output_buffer = link_to("http://example.com") { concat("Example site") }
|
||||
assert_equal '<a href="http://example.com">Example site</a>', output_buffer
|
||||
out = render_erb %{<%= link_to('/') do %>Example site<% end %>}
|
||||
assert_equal '<a href="/">Example site</a>', out
|
||||
end
|
||||
|
||||
def test_link_to_unless
|
||||
assert_equal "Showing", link_to_unless(true, "Showing", :action => "show", :controller => "weblog")
|
||||
assert_dom_equal "<a href=\"http://www.example.com\">Listing</a>", link_to_unless(false, "Listing", :action => "list", :controller => "weblog")
|
||||
assert_equal "Showing", link_to_unless(true, "Showing", :action => "show", :controller => "weblog", :id => 1)
|
||||
assert_equal "<strong>Showing</strong>", link_to_unless(true, "Showing", :action => "show", :controller => "weblog", :id => 1) { |name, options, html_options|
|
||||
"<strong>#{name}</strong>"
|
||||
}
|
||||
assert_equal "<strong>Showing</strong>", link_to_unless(true, "Showing", :action => "show", :controller => "weblog", :id => 1) { |name|
|
||||
"<strong>#{name}</strong>"
|
||||
}
|
||||
assert_equal "test", link_to_unless(true, "Showing", :action => "show", :controller => "weblog", :id => 1) {
|
||||
"test"
|
||||
}
|
||||
assert_equal "Showing", link_to_unless(true, "Showing", url_hash)
|
||||
|
||||
assert_dom_equal %{<a href="/">Listing</a>},
|
||||
link_to_unless(false, "Listing", url_hash)
|
||||
|
||||
assert_equal "Showing", link_to_unless(true, "Showing", url_hash)
|
||||
|
||||
assert_equal "<strong>Showing</strong>",
|
||||
link_to_unless(true, "Showing", url_hash) { |name|
|
||||
"<strong>#{name}</strong>"
|
||||
}
|
||||
|
||||
assert_equal "<strong>Showing</strong>",
|
||||
link_to_unless(true, "Showing", url_hash) { |name|
|
||||
"<strong>#{name}</strong>"
|
||||
}
|
||||
|
||||
assert_equal "test",
|
||||
link_to_unless(true, "Showing", url_hash) {
|
||||
"test"
|
||||
}
|
||||
end
|
||||
|
||||
def test_link_to_if
|
||||
assert_equal "Showing", link_to_if(false, "Showing", :action => "show", :controller => "weblog")
|
||||
assert_dom_equal "<a href=\"http://www.example.com\">Listing</a>", link_to_if(true, "Listing", :action => "list", :controller => "weblog")
|
||||
assert_equal "Showing", link_to_if(false, "Showing", :action => "show", :controller => "weblog", :id => 1)
|
||||
assert_equal "Showing", link_to_if(false, "Showing", url_hash)
|
||||
assert_dom_equal %{<a href="/">Listing</a>}, link_to_if(true, "Listing", url_hash)
|
||||
assert_equal "Showing", link_to_if(false, "Showing", url_hash)
|
||||
end
|
||||
|
||||
def request_for_url(url)
|
||||
env = Rack::MockRequest.env_for("http://www.example.com#{url}")
|
||||
ActionDispatch::Request.new(env)
|
||||
end
|
||||
|
||||
def test_current_page_with_simple_url
|
||||
@request.env['HTTP_HOST'] = 'www.example.com'
|
||||
@request.env['PATH_INFO'] = '/weblog/show'
|
||||
@controller.url = "http://www.example.com/weblog/show"
|
||||
assert current_page?({ :action => "show", :controller => "weblog" })
|
||||
assert current_page?("http://www.example.com/weblog/show")
|
||||
@request = request_for_url("/")
|
||||
assert current_page?(url_hash)
|
||||
assert current_page?("http://www.example.com/")
|
||||
end
|
||||
|
||||
def test_current_page_ignoring_params
|
||||
@request.env['HTTP_HOST'] = 'www.example.com'
|
||||
@request.env['PATH_INFO'] = '/weblog/show'
|
||||
@request.env['QUERY_STRING'] = 'order=desc&page=1'
|
||||
@controller.url = "http://www.example.com/weblog/show?order=desc&page=1"
|
||||
assert current_page?({ :action => "show", :controller => "weblog" })
|
||||
assert current_page?("http://www.example.com/weblog/show")
|
||||
@request = request_for_url("/?order=desc&page=1")
|
||||
|
||||
assert current_page?(url_hash)
|
||||
assert current_page?("http://www.example.com/")
|
||||
end
|
||||
|
||||
def test_current_page_with_params_that_match
|
||||
@request.env['HTTP_HOST'] = 'www.example.com'
|
||||
@request.env['PATH_INFO'] = '/weblog/show'
|
||||
@request.env['QUERY_STRING'] = 'order=desc&page=1'
|
||||
@controller.url = "http://www.example.com/weblog/show?order=desc&page=1"
|
||||
assert current_page?({ :action => "show", :controller => "weblog", :order => "desc", :page => "1" })
|
||||
assert current_page?("http://www.example.com/weblog/show?order=desc&page=1")
|
||||
@request = request_for_url("/?order=desc&page=1")
|
||||
|
||||
assert current_page?(hash_for(:order => "desc", :page => "1"))
|
||||
assert current_page?("http://www.example.com/?order=desc&page=1")
|
||||
end
|
||||
|
||||
def test_link_unless_current
|
||||
@request.env['HTTP_HOST'] = 'www.example.com'
|
||||
@request.env['PATH_INFO'] = '/weblog/show'
|
||||
@controller.url = "http://www.example.com/weblog/show"
|
||||
assert_equal "Showing", link_to_unless_current("Showing", { :action => "show", :controller => "weblog" })
|
||||
assert_equal "Showing", link_to_unless_current("Showing", "http://www.example.com/weblog/show")
|
||||
@request = request_for_url("/")
|
||||
|
||||
@request.env['QUERY_STRING'] = 'order=desc'
|
||||
@controller.url = "http://www.example.com/weblog/show"
|
||||
assert_equal "Showing", link_to_unless_current("Showing", { :action => "show", :controller => "weblog" })
|
||||
assert_equal "Showing", link_to_unless_current("Showing", "http://www.example.com/weblog/show")
|
||||
assert_equal "Showing",
|
||||
link_to_unless_current("Showing", url_hash)
|
||||
assert_equal "Showing",
|
||||
link_to_unless_current("Showing", "http://www.example.com/")
|
||||
|
||||
@request.env['QUERY_STRING'] = 'order=desc&page=1'
|
||||
@controller.url = "http://www.example.com/weblog/show?order=desc&page=1"
|
||||
assert_equal "Showing", link_to_unless_current("Showing", { :action => "show", :controller => "weblog", :order=>'desc', :page=>'1' })
|
||||
assert_equal "Showing", link_to_unless_current("Showing", "http://www.example.com/weblog/show?order=desc&page=1")
|
||||
assert_equal "Showing", link_to_unless_current("Showing", "http://www.example.com/weblog/show?order=desc&page=1")
|
||||
@request = request_for_url("/?order=desc")
|
||||
|
||||
@request.env['QUERY_STRING'] = 'order=desc'
|
||||
@controller.url = "http://www.example.com/weblog/show?order=asc"
|
||||
assert_equal "<a href=\"http://www.example.com/weblog/show?order=asc\">Showing</a>", link_to_unless_current("Showing", { :action => "show", :controller => "weblog" })
|
||||
assert_equal "<a href=\"http://www.example.com/weblog/show?order=asc\">Showing</a>", link_to_unless_current("Showing", "http://www.example.com/weblog/show?order=asc")
|
||||
assert_equal "Showing",
|
||||
link_to_unless_current("Showing", url_hash)
|
||||
assert_equal "Showing",
|
||||
link_to_unless_current("Showing", "http://www.example.com/")
|
||||
|
||||
@request.env['QUERY_STRING'] = 'order=desc&page=1'
|
||||
@controller.url = "http://www.example.com/weblog/show?order=desc&page=2"
|
||||
assert_equal "<a href=\"http://www.example.com/weblog/show?order=desc&page=2\">Showing</a>", link_to_unless_current("Showing", { :action => "show", :controller => "weblog" })
|
||||
assert_equal "<a href=\"http://www.example.com/weblog/show?order=desc&page=2\">Showing</a>", link_to_unless_current("Showing", "http://www.example.com/weblog/show?order=desc&page=2")
|
||||
@request = request_for_url("/?order=desc&page=1")
|
||||
|
||||
@request.env['QUERY_STRING'] = ''
|
||||
@controller.url = "http://www.example.com/weblog/list"
|
||||
assert_equal "<a href=\"http://www.example.com/weblog/list\">Listing</a>",
|
||||
link_to_unless_current("Listing", :action => "list", :controller => "weblog")
|
||||
assert_equal "<a href=\"http://www.example.com/weblog/list\">Listing</a>",
|
||||
link_to_unless_current("Listing", "http://www.example.com/weblog/list")
|
||||
assert_equal "Showing",
|
||||
link_to_unless_current("Showing", hash_for(:order=>'desc', :page=>'1'))
|
||||
assert_equal "Showing",
|
||||
link_to_unless_current("Showing", "http://www.example.com/?order=desc&page=1")
|
||||
|
||||
@request = request_for_url("/?order=desc")
|
||||
|
||||
assert_equal %{<a href="/?order=asc">Showing</a>},
|
||||
link_to_unless_current("Showing", hash_for(:order => :asc))
|
||||
assert_equal %{<a href="http://www.example.com/?order=asc">Showing</a>},
|
||||
link_to_unless_current("Showing", "http://www.example.com/?order=asc")
|
||||
|
||||
@request = request_for_url("/?order=desc")
|
||||
assert_equal %{<a href="/?order=desc&page=2\">Showing</a>},
|
||||
link_to_unless_current("Showing", hash_for(:order => "desc", :page => 2))
|
||||
assert_equal %{<a href="http://www.example.com/?order=desc&page=2">Showing</a>},
|
||||
link_to_unless_current("Showing", "http://www.example.com/?order=desc&page=2")
|
||||
|
||||
@request = request_for_url("/show")
|
||||
|
||||
assert_equal %{<a href="/">Listing</a>},
|
||||
link_to_unless_current("Listing", url_hash)
|
||||
assert_equal %{<a href="http://www.example.com/">Listing</a>},
|
||||
link_to_unless_current("Listing", "http://www.example.com/")
|
||||
end
|
||||
|
||||
def test_mail_to
|
||||
@ -352,7 +371,8 @@ def test_mail_with_options
|
||||
end
|
||||
|
||||
def test_mail_to_with_img
|
||||
assert_dom_equal %(<a href="mailto:feedback@example.com"><img src="/feedback.png" /></a>), mail_to('feedback@example.com', '<img src="/feedback.png" />'.html_safe)
|
||||
assert_dom_equal %(<a href="mailto:feedback@example.com"><img src="/feedback.png" /></a>),
|
||||
mail_to('feedback@example.com', '<img src="/feedback.png" />'.html_safe)
|
||||
end
|
||||
|
||||
def test_mail_to_with_hex
|
||||
@ -369,6 +389,7 @@ def test_mail_to_with_replace_options
|
||||
assert_dom_equal "<script type=\"text/javascript\">eval(decodeURIComponent('%64%6f%63%75%6d%65%6e%74%2e%77%72%69%74%65%28%27%3c%61%20%68%72%65%66%3d%22%6d%61%69%6c%74%6f%3a%6d%65%40%64%6f%6d%61%69%6e%2e%63%6f%6d%22%3e%6d%65%28%61%74%29%64%6f%6d%61%69%6e%28%64%6f%74%29%63%6f%6d%3c%2f%61%3e%27%29%3b'))</script>", mail_to("me@domain.com", nil, :encode => "javascript", :replace_at => "(at)", :replace_dot => "(dot)")
|
||||
end
|
||||
|
||||
# TODO: button_to looks at this ... why?
|
||||
def protect_against_forgery?
|
||||
false
|
||||
end
|
||||
@ -383,6 +404,15 @@ def sort_query_string_params(uri)
|
||||
|
||||
class UrlHelperControllerTest < ActionController::TestCase
|
||||
class UrlHelperController < ActionController::Base
|
||||
test_routes do |map|
|
||||
match 'url_helper_controller_test/url_helper/show_named_route',
|
||||
:to => 'url_helper_controller_test/url_helper#show_named_route',
|
||||
:as => :show_named_route
|
||||
|
||||
map.connect ":controller/:action/:id"
|
||||
# match "/:controller(/:action(/:id))"
|
||||
end
|
||||
|
||||
def show_url_for
|
||||
render :inline => "<%= url_for :controller => 'url_helper_controller_test/url_helper', :action => 'show_url_for' %>"
|
||||
end
|
||||
@ -406,17 +436,14 @@ def test_url_for_shows_only_path
|
||||
end
|
||||
|
||||
def test_named_route_url_shows_host_and_path
|
||||
with_url_helper_routing do
|
||||
get :show_named_route, :kind => 'url'
|
||||
assert_equal 'http://test.host/url_helper_controller_test/url_helper/show_named_route', @response.body
|
||||
end
|
||||
get :show_named_route, :kind => 'url'
|
||||
assert_equal 'http://test.host/url_helper_controller_test/url_helper/show_named_route',
|
||||
@response.body
|
||||
end
|
||||
|
||||
def test_named_route_path_shows_only_path
|
||||
with_url_helper_routing do
|
||||
get :show_named_route, :kind => 'path'
|
||||
assert_equal '/url_helper_controller_test/url_helper/show_named_route', @response.body
|
||||
end
|
||||
get :show_named_route, :kind => 'path'
|
||||
assert_equal '/url_helper_controller_test/url_helper/show_named_route', @response.body
|
||||
end
|
||||
|
||||
def test_url_for_nil_returns_current_path
|
||||
@ -431,24 +458,16 @@ def default_url_options(options = nil)
|
||||
end
|
||||
end
|
||||
|
||||
with_url_helper_routing do
|
||||
get :show_named_route, :kind => 'url'
|
||||
assert_equal 'http://testtwo.host/url_helper_controller_test/url_helper/show_named_route', @response.body
|
||||
end
|
||||
get :show_named_route, :kind => 'url'
|
||||
assert_equal 'http://testtwo.host/url_helper_controller_test/url_helper/show_named_route', @response.body
|
||||
end
|
||||
|
||||
protected
|
||||
def with_url_helper_routing
|
||||
with_routing do |set|
|
||||
set.draw do |map|
|
||||
match 'url_helper_controller_test/url_helper/show_named_route', :to => 'url_helper_controller_test/url_helper#show_named_route', :as => :show_named_route
|
||||
end
|
||||
yield
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class TasksController < ActionController::Base
|
||||
test_routes do
|
||||
resources :tasks
|
||||
end
|
||||
|
||||
def index
|
||||
render_default
|
||||
end
|
||||
@ -468,36 +487,19 @@ def render_default
|
||||
end
|
||||
|
||||
class LinkToUnlessCurrentWithControllerTest < ActionController::TestCase
|
||||
def setup
|
||||
super
|
||||
@controller = TasksController.new
|
||||
end
|
||||
tests TasksController
|
||||
|
||||
def test_link_to_unless_current_to_current
|
||||
with_restful_routing do
|
||||
get :index
|
||||
assert_equal "tasks\ntasks", @response.body
|
||||
end
|
||||
get :index
|
||||
assert_equal "tasks\ntasks", @response.body
|
||||
end
|
||||
|
||||
def test_link_to_unless_current_shows_link
|
||||
with_restful_routing do
|
||||
get :show, :id => 1
|
||||
assert_equal "<a href=\"/tasks\">tasks</a>\n" +
|
||||
"<a href=\"#{@request.protocol}#{@request.host_with_port}/tasks\">tasks</a>",
|
||||
@response.body
|
||||
end
|
||||
get :show, :id => 1
|
||||
assert_equal "<a href=\"/tasks\">tasks</a>\n" +
|
||||
"<a href=\"#{@request.protocol}#{@request.host_with_port}/tasks\">tasks</a>",
|
||||
@response.body
|
||||
end
|
||||
|
||||
protected
|
||||
def with_restful_routing
|
||||
with_routing do |set|
|
||||
set.draw do |map|
|
||||
resources :tasks
|
||||
end
|
||||
yield
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class Workshop
|
||||
@ -537,6 +539,12 @@ def to_s
|
||||
end
|
||||
|
||||
class WorkshopsController < ActionController::Base
|
||||
test_routes do
|
||||
resources :workshops do
|
||||
resources :sessions
|
||||
end
|
||||
end
|
||||
|
||||
def index
|
||||
@workshop = Workshop.new(nil)
|
||||
render :inline => "<%= url_for(@workshop) %>\n<%= link_to('Workshop', @workshop) %>"
|
||||
@ -551,6 +559,12 @@ def rescue_action(e) raise e end
|
||||
end
|
||||
|
||||
class SessionsController < ActionController::Base
|
||||
test_routes do
|
||||
resources :workshops do
|
||||
resources :sessions
|
||||
end
|
||||
end
|
||||
|
||||
def index
|
||||
@workshop = Workshop.new(params[:workshop_id])
|
||||
@session = Session.new(nil)
|
||||
@ -567,56 +581,31 @@ def rescue_action(e) raise e end
|
||||
end
|
||||
|
||||
class PolymorphicControllerTest < ActionController::TestCase
|
||||
def setup
|
||||
super
|
||||
@response = ActionController::TestResponse.new
|
||||
end
|
||||
|
||||
def test_new_resource
|
||||
@controller = WorkshopsController.new
|
||||
|
||||
with_restful_routing do
|
||||
get :index
|
||||
assert_equal "/workshops\n<a href=\"/workshops\">Workshop</a>", @response.body
|
||||
end
|
||||
get :index
|
||||
assert_equal "/workshops\n<a href=\"/workshops\">Workshop</a>", @response.body
|
||||
end
|
||||
|
||||
def test_existing_resource
|
||||
@controller = WorkshopsController.new
|
||||
|
||||
with_restful_routing do
|
||||
get :show, :id => 1
|
||||
assert_equal "/workshops/1\n<a href=\"/workshops/1\">Workshop</a>", @response.body
|
||||
end
|
||||
get :show, :id => 1
|
||||
assert_equal "/workshops/1\n<a href=\"/workshops/1\">Workshop</a>", @response.body
|
||||
end
|
||||
|
||||
def test_new_nested_resource
|
||||
@controller = SessionsController.new
|
||||
|
||||
with_restful_routing do
|
||||
get :index, :workshop_id => 1
|
||||
assert_equal "/workshops/1/sessions\n<a href=\"/workshops/1/sessions\">Session</a>", @response.body
|
||||
end
|
||||
get :index, :workshop_id => 1
|
||||
assert_equal "/workshops/1/sessions\n<a href=\"/workshops/1/sessions\">Session</a>", @response.body
|
||||
end
|
||||
|
||||
|
||||
def test_existing_nested_resource
|
||||
@controller = SessionsController.new
|
||||
|
||||
with_restful_routing do
|
||||
get :show, :workshop_id => 1, :id => 1
|
||||
assert_equal "/workshops/1/sessions/1\n<a href=\"/workshops/1/sessions/1\">Session</a>", @response.body
|
||||
end
|
||||
|
||||
get :show, :workshop_id => 1, :id => 1
|
||||
assert_equal "/workshops/1/sessions/1\n<a href=\"/workshops/1/sessions/1\">Session</a>", @response.body
|
||||
end
|
||||
|
||||
protected
|
||||
def with_restful_routing
|
||||
with_routing do |set|
|
||||
set.draw do |map|
|
||||
resources :workshops do
|
||||
resources :sessions
|
||||
end
|
||||
end
|
||||
yield
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -1,4 +1,19 @@
|
||||
*Edge*
|
||||
*Rails 3.0.0 [beta 2] (April 1st, 2010)*
|
||||
|
||||
* #new_record? and #destroyed? were removed from ActiveModel::Lint. Use
|
||||
persisted? instead. A model is persisted if it's not a new_record? and it was
|
||||
not destroyed? [MG]
|
||||
|
||||
* Added validations reflection in ActiveModel::Validations [JV]
|
||||
|
||||
Model.validators
|
||||
Model.validators_on(:field)
|
||||
|
||||
* #to_key was added to ActiveModel::Lint so we can generate DOM IDs for
|
||||
AMo objects with composite keys [MG]
|
||||
|
||||
|
||||
*Rails 3.0.0 [beta 1] (February 4, 2010)*
|
||||
|
||||
* ActiveModel::Observer#add_observer!
|
||||
|
||||
|
@ -1,22 +1,23 @@
|
||||
version = File.read(File.expand_path("../../RAILS_VERSION", __FILE__)).strip
|
||||
version = File.read(File.expand_path('../../RAILS_VERSION', __FILE__)).strip
|
||||
|
||||
Gem::Specification.new do |s|
|
||||
s.platform = Gem::Platform::RUBY
|
||||
s.name = 'activemodel'
|
||||
s.version = version
|
||||
s.summary = 'A toolkit for building modeling frameworks (part of Rails).'
|
||||
s.platform = Gem::Platform::RUBY
|
||||
s.name = 'activemodel'
|
||||
s.version = version
|
||||
s.summary = 'A toolkit for building modeling frameworks (part of Rails).'
|
||||
s.description = 'A toolkit for building modeling frameworks like Active Record and Active Resource. Rich support for attributes, callbacks, validations, observers, serialization, internationalization, and testing.'
|
||||
|
||||
s.required_ruby_version = '>= 1.8.7'
|
||||
|
||||
s.author = "David Heinemeier Hansson"
|
||||
s.email = "david@loudthinking.com"
|
||||
s.rubyforge_project = "activemodel"
|
||||
s.homepage = "http://www.rubyonrails.org"
|
||||
s.author = 'David Heinemeier Hansson'
|
||||
s.email = 'david@loudthinking.com'
|
||||
s.homepage = 'http://www.rubyonrails.org'
|
||||
s.rubyforge_project = 'activemodel'
|
||||
|
||||
s.files = Dir['CHANGELOG', 'MIT-LICENSE', 'README', 'lib/**/*']
|
||||
s.require_path = 'lib'
|
||||
|
||||
s.has_rdoc = true
|
||||
|
||||
s.add_dependency('activesupport', version)
|
||||
|
||||
s.require_path = 'lib'
|
||||
s.files = Dir["CHANGELOG", "MIT-LICENSE", "README", "lib/**/*"]
|
||||
end
|
||||
|
@ -91,17 +91,12 @@ module Dirty
|
||||
attribute_method_affix :prefix => 'reset_', :suffix => '!'
|
||||
end
|
||||
|
||||
def initialize(*)
|
||||
@changed_attributes = {}
|
||||
super
|
||||
end
|
||||
|
||||
# Do any attributes have unsaved changes?
|
||||
# person.changed? # => false
|
||||
# person.name = 'bob'
|
||||
# person.changed? # => true
|
||||
def changed?
|
||||
!@changed_attributes.empty?
|
||||
!changed_attributes.empty?
|
||||
end
|
||||
|
||||
# List of attributes with unsaved changes.
|
||||
@ -109,7 +104,7 @@ def changed?
|
||||
# person.name = 'bob'
|
||||
# person.changed # => ['name']
|
||||
def changed
|
||||
@changed_attributes.keys
|
||||
changed_attributes.keys
|
||||
end
|
||||
|
||||
# Map of changed attrs => [original value, new value].
|
||||
@ -130,19 +125,24 @@ def previous_changes
|
||||
end
|
||||
|
||||
private
|
||||
# Map of change <tt>attr => original value</tt>.
|
||||
def changed_attributes
|
||||
@changed_attributes ||= {}
|
||||
end
|
||||
|
||||
# Handle <tt>*_changed?</tt> for +method_missing+.
|
||||
def attribute_changed?(attr)
|
||||
@changed_attributes.include?(attr)
|
||||
changed_attributes.include?(attr)
|
||||
end
|
||||
|
||||
# Handle <tt>*_change</tt> for +method_missing+.
|
||||
def attribute_change(attr)
|
||||
[@changed_attributes[attr], __send__(attr)] if attribute_changed?(attr)
|
||||
[changed_attributes[attr], __send__(attr)] if attribute_changed?(attr)
|
||||
end
|
||||
|
||||
# Handle <tt>*_was</tt> for +method_missing+.
|
||||
def attribute_was(attr)
|
||||
attribute_changed?(attr) ? @changed_attributes[attr] : __send__(attr)
|
||||
attribute_changed?(attr) ? changed_attributes[attr] : __send__(attr)
|
||||
end
|
||||
|
||||
# Handle <tt>*_will_change!</tt> for +method_missing+.
|
||||
@ -153,12 +153,12 @@ def attribute_will_change!(attr)
|
||||
rescue TypeError, NoMethodError
|
||||
end
|
||||
|
||||
@changed_attributes[attr] = value
|
||||
changed_attributes[attr] = value
|
||||
end
|
||||
|
||||
# Handle <tt>reset_*!</tt> for +method_missing+.
|
||||
def reset_attribute!(attr)
|
||||
__send__("#{attr}=", @changed_attributes[attr]) if attribute_changed?(attr)
|
||||
__send__("#{attr}=", changed_attributes[attr]) if attribute_changed?(attr)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -1,3 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
require 'active_support/core_ext/array/wrap'
|
||||
require 'active_support/core_ext/string/inflections'
|
||||
require 'active_support/core_ext/object/blank'
|
||||
|
@ -3,7 +3,7 @@ module VERSION #:nodoc:
|
||||
MAJOR = 3
|
||||
MINOR = 0
|
||||
TINY = 0
|
||||
BUILD = "beta1"
|
||||
BUILD = "beta2"
|
||||
|
||||
STRING = [MAJOR, MINOR, TINY, BUILD].join('.')
|
||||
end
|
||||
|
@ -6,7 +6,6 @@ class DirtyModel
|
||||
define_attribute_methods [:name]
|
||||
|
||||
def initialize
|
||||
super
|
||||
@name = nil
|
||||
end
|
||||
|
||||
|
@ -1,3 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
require "cases/helper"
|
||||
require 'cases/tests_database'
|
||||
require 'models/person'
|
||||
@ -41,6 +43,14 @@ def test_errors_add_on_blank_generates_message_with_custom_default_message
|
||||
@person.errors.add_on_blank :title, 'custom'
|
||||
end
|
||||
|
||||
def test_full_message_encoding
|
||||
I18n.backend.store_translations('en', :errors => {
|
||||
:messages => { :too_short => '猫舌' }})
|
||||
Person.validates_length_of :title, :within => 3..5
|
||||
@person.valid?
|
||||
assert_equal ['Title 猫舌'], @person.errors.full_messages
|
||||
end
|
||||
|
||||
def test_errors_full_messages_translates_human_attribute_name_for_model_attributes
|
||||
@person.errors.add(:name, 'not found')
|
||||
Person.expects(:human_attribute_name).with(:name, :default => 'Name').returns("Person's name")
|
||||
|
@ -1,5 +1,15 @@
|
||||
*Rails 3.0.0 [Beta 2] (pending)*
|
||||
|
||||
* Add Relation extensions. [Pratik Naik]
|
||||
|
||||
users = User.where(:admin => true).extending(User::AdminPowers)
|
||||
|
||||
latest_users = User.order('created_at DESC') do
|
||||
def posts_count
|
||||
Post.count(:user_id => to_a.map(&:id))
|
||||
end
|
||||
end
|
||||
|
||||
* To prefix the table names of all models in a module, define self.table_name_prefix on the module. #4032 [Andrew White]
|
||||
|
||||
* Silenced "SHOW FIELDS" and "SET SQL_AUTO_IS_NULL=0" statements from the MySQL driver to improve log signal to noise ration in development [DHH]
|
||||
|
@ -6,6 +6,7 @@
|
||||
s.version = version
|
||||
s.summary = 'Object-relational mapper framework (part of Rails).'
|
||||
s.description = 'Databases on Rails. Build a persistent domain model by mapping database tables to Ruby classes. Strong conventions for associations, validations, aggregations, migrations, and testing come baked-in.'
|
||||
|
||||
s.required_ruby_version = '>= 1.8.7'
|
||||
|
||||
s.author = 'David Heinemeier Hansson'
|
||||
|
@ -1495,14 +1495,6 @@ def add_touch_callbacks(reflection, touch_attribute)
|
||||
# finder conditions.
|
||||
def configure_dependency_for_has_many(reflection, extra_conditions = nil)
|
||||
if reflection.options.include?(:dependent)
|
||||
# Add polymorphic type if the :as option is present
|
||||
dependent_conditions = []
|
||||
dependent_conditions << "#{reflection.primary_key_name} = \#{record.#{reflection.name}.send(:owner_quoted_id)}"
|
||||
dependent_conditions << "#{reflection.options[:as]}_type = '#{base_class.name}'" if reflection.options[:as]
|
||||
dependent_conditions << sanitize_sql(reflection.options[:conditions], reflection.table_name) if reflection.options[:conditions]
|
||||
dependent_conditions << extra_conditions if extra_conditions
|
||||
dependent_conditions = dependent_conditions.collect {|where| "(#{where})" }.join(" AND ")
|
||||
dependent_conditions = dependent_conditions.gsub('@', '\@')
|
||||
case reflection.options[:dependent]
|
||||
when :destroy
|
||||
method_name = "has_many_dependent_destroy_for_#{reflection.name}".to_sym
|
||||
@ -1511,51 +1503,30 @@ def configure_dependency_for_has_many(reflection, extra_conditions = nil)
|
||||
end
|
||||
before_destroy method_name
|
||||
when :delete_all
|
||||
# before_destroy do |record|
|
||||
# self.class.send(:delete_all_has_many_dependencies,
|
||||
# record,
|
||||
# "posts",
|
||||
# Post,
|
||||
# %@...@) # this is a string literal like %(...)
|
||||
# end
|
||||
# end
|
||||
module_eval <<-CALLBACK
|
||||
before_destroy do |record|
|
||||
self.class.send(:delete_all_has_many_dependencies,
|
||||
record,
|
||||
"#{reflection.name}",
|
||||
#{reflection.class_name},
|
||||
%@#{dependent_conditions}@)
|
||||
end
|
||||
CALLBACK
|
||||
before_destroy do |record|
|
||||
self.class.send(:delete_all_has_many_dependencies,
|
||||
record,
|
||||
reflection.name,
|
||||
reflection.klass,
|
||||
reflection.dependent_conditions(record, self.class, extra_conditions))
|
||||
end
|
||||
when :nullify
|
||||
# before_destroy do |record|
|
||||
# self.class.send(:nullify_has_many_dependencies,
|
||||
# record,
|
||||
# "posts",
|
||||
# Post,
|
||||
# "user_id",
|
||||
# %@...@) # this is a string literal like %(...)
|
||||
# end
|
||||
# end
|
||||
module_eval <<-CALLBACK
|
||||
before_destroy do |record|
|
||||
self.class.send(:nullify_has_many_dependencies,
|
||||
record,
|
||||
"#{reflection.name}",
|
||||
#{reflection.class_name},
|
||||
"#{reflection.primary_key_name}",
|
||||
%@#{dependent_conditions}@)
|
||||
before_destroy do |record|
|
||||
self.class.send(:nullify_has_many_dependencies,
|
||||
record,
|
||||
reflection.name,
|
||||
reflection.klass,
|
||||
reflection.primary_key_name,
|
||||
reflection.dependent_conditions(record, self.class, extra_conditions))
|
||||
end
|
||||
when :restrict
|
||||
method_name = "has_many_dependent_restrict_for_#{reflection.name}".to_sym
|
||||
define_method(method_name) do
|
||||
unless send(reflection.name).empty?
|
||||
raise DeleteRestrictionError.new(reflection)
|
||||
end
|
||||
CALLBACK
|
||||
when :restrict
|
||||
method_name = "has_many_dependent_restrict_for_#{reflection.name}".to_sym
|
||||
define_method(method_name) do
|
||||
unless send(reflection.name).empty?
|
||||
raise DeleteRestrictionError.new(reflection)
|
||||
end
|
||||
end
|
||||
before_destroy method_name
|
||||
end
|
||||
before_destroy method_name
|
||||
else
|
||||
raise ArgumentError, "The :dependent option expects either :destroy, :delete_all, :nullify or :restrict (#{reflection.options[:dependent].inspect})"
|
||||
end
|
||||
|
@ -135,7 +135,7 @@ def build_conditions
|
||||
def build_through_conditions
|
||||
conditions = @reflection.through_reflection.options[:conditions]
|
||||
if conditions.is_a?(Hash)
|
||||
interpolate_sql(sanitize_sql(conditions)).gsub(
|
||||
interpolate_sql(@reflection.through_reflection.klass.send(:sanitize_sql, conditions)).gsub(
|
||||
@reflection.quoted_table_name,
|
||||
@reflection.through_reflection.quoted_table_name)
|
||||
elsif conditions
|
||||
|
@ -23,7 +23,8 @@ module Format
|
||||
#
|
||||
# +name+ is the column's name, such as <tt>supplier_id</tt> in <tt>supplier_id int(11)</tt>.
|
||||
# +default+ is the type-casted default value, such as +new+ in <tt>sales_stage varchar(20) default 'new'</tt>.
|
||||
# +sql_type+ is only used to extract the column's length, if necessary. For example +60+ in <tt>company_name varchar(60)</tt>.
|
||||
# +sql_type+ is used to extract the column's length, if necessary. For example +60+ in <tt>company_name varchar(60)</tt>.
|
||||
# It will be mapped to one of the standard Rails SQL types in the <tt>type</tt> attribute.
|
||||
# +null+ determines if this column allows +NULL+ values.
|
||||
def initialize(name, default, sql_type = nil, null = true)
|
||||
@name, @sql_type, @null = name, sql_type, null
|
||||
|
@ -114,6 +114,12 @@ def simplified_type(field_type)
|
||||
# Object identifier types
|
||||
when /^oid$/
|
||||
:integer
|
||||
# UUID type
|
||||
when /^uuid$/
|
||||
:string
|
||||
# Small and big integer types
|
||||
when /^(?:small|big)int$/
|
||||
:integer
|
||||
# Pass through all types that are not specific to PostgreSQL.
|
||||
else
|
||||
super
|
||||
|
@ -8,16 +8,15 @@ module NamedScope
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
module ClassMethods
|
||||
# Returns a relation if invoked without any arguments.
|
||||
# Returns an anonymous scope.
|
||||
#
|
||||
# posts = Post.scoped
|
||||
# posts.size # Fires "select count(*) from posts" and returns the count
|
||||
# posts.each {|p| puts p.name } # Fires "select * from posts" and loads post objects
|
||||
#
|
||||
# Returns an anonymous named scope if any options are supplied.
|
||||
#
|
||||
# shirts = Shirt.scoped(:conditions => {:color => 'red'})
|
||||
# shirts = shirts.scoped(:include => :washing_instructions)
|
||||
# fruits = Fruit.scoped
|
||||
# fruits = fruits.where(:colour => 'red') if options[:red_only]
|
||||
# fruits = fruits.limit(10) if limited?
|
||||
#
|
||||
# Anonymous \scopes tend to be useful when procedurally generating complex queries, where passing
|
||||
# intermediate values (scopes) around as first-class objects is convenient.
|
||||
@ -25,7 +24,8 @@ module ClassMethods
|
||||
# You can define a scope that applies to all finders using ActiveRecord::Base.default_scope.
|
||||
def scoped(options = {}, &block)
|
||||
if options.present?
|
||||
Scope.init(self, options, &block)
|
||||
relation = scoped.apply_finder_options(options)
|
||||
block_given? ? relation.extending(Module.new(&block)) : relation
|
||||
else
|
||||
current_scoped_methods ? unscoped.merge(current_scoped_methods) : unscoped.clone
|
||||
end
|
||||
@ -36,21 +36,21 @@ def scopes
|
||||
end
|
||||
|
||||
# Adds a class method for retrieving and querying objects. A scope represents a narrowing of a database query,
|
||||
# such as <tt>:conditions => {:color => :red}, :select => 'shirts.*', :include => :washing_instructions</tt>.
|
||||
# such as <tt>where(:color => :red).select('shirts.*').includes(:washing_instructions)</tt>.
|
||||
#
|
||||
# class Shirt < ActiveRecord::Base
|
||||
# scope :red, :conditions => {:color => 'red'}
|
||||
# scope :dry_clean_only, :joins => :washing_instructions, :conditions => ['washing_instructions.dry_clean_only = ?', true]
|
||||
# scope :red, where(:color => 'red')
|
||||
# scope :dry_clean_only, joins(:washing_instructions).where('washing_instructions.dry_clean_only = ?', true)
|
||||
# end
|
||||
#
|
||||
# The above calls to <tt>scope</tt> define class methods Shirt.red and Shirt.dry_clean_only. Shirt.red,
|
||||
# in effect, represents the query <tt>Shirt.find(:all, :conditions => {:color => 'red'})</tt>.
|
||||
# in effect, represents the query <tt>Shirt.where(:color => 'red')</tt>.
|
||||
#
|
||||
# Unlike <tt>Shirt.find(...)</tt>, however, the object returned by Shirt.red is not an Array; it resembles the association object
|
||||
# constructed by a <tt>has_many</tt> declaration. For instance, you can invoke <tt>Shirt.red.find(:first)</tt>, <tt>Shirt.red.count</tt>,
|
||||
# <tt>Shirt.red.find(:all, :conditions => {:size => 'small'})</tt>. Also, just
|
||||
# as with the association objects, named \scopes act like an Array, implementing Enumerable; <tt>Shirt.red.each(&block)</tt>,
|
||||
# <tt>Shirt.red.first</tt>, and <tt>Shirt.red.inject(memo, &block)</tt> all behave as if Shirt.red really was an Array.
|
||||
# constructed by a <tt>has_many</tt> declaration. For instance, you can invoke <tt>Shirt.red.first</tt>, <tt>Shirt.red.count</tt>,
|
||||
# <tt>Shirt.red.where(:size => 'small')</tt>. Also, just as with the association objects, named \scopes act like an Array,
|
||||
# implementing Enumerable; <tt>Shirt.red.each(&block)</tt>, <tt>Shirt.red.first</tt>, and <tt>Shirt.red.inject(memo, &block)</tt>
|
||||
# all behave as if Shirt.red really was an Array.
|
||||
#
|
||||
# These named \scopes are composable. For instance, <tt>Shirt.red.dry_clean_only</tt> will produce all shirts that are both red and dry clean only.
|
||||
# Nested finds and calculations also work with these compositions: <tt>Shirt.red.dry_clean_only.count</tt> returns the number of garments
|
||||
@ -69,9 +69,7 @@ def scopes
|
||||
# Named \scopes can also be procedural:
|
||||
#
|
||||
# class Shirt < ActiveRecord::Base
|
||||
# scope :colored, lambda { |color|
|
||||
# { :conditions => { :color => color } }
|
||||
# }
|
||||
# scope :colored, lambda {|color| where(:color => color) }
|
||||
# end
|
||||
#
|
||||
# In this example, <tt>Shirt.colored('puce')</tt> finds all puce shirts.
|
||||
@ -79,26 +77,13 @@ def scopes
|
||||
# Named \scopes can also have extensions, just as with <tt>has_many</tt> declarations:
|
||||
#
|
||||
# class Shirt < ActiveRecord::Base
|
||||
# scope :red, :conditions => {:color => 'red'} do
|
||||
# scope :red, where(:color => 'red') do
|
||||
# def dom_id
|
||||
# 'red_shirts'
|
||||
# end
|
||||
# end
|
||||
# end
|
||||
#
|
||||
#
|
||||
# For testing complex named \scopes, you can examine the scoping options using the
|
||||
# <tt>proxy_options</tt> method on the proxy itself.
|
||||
#
|
||||
# class Shirt < ActiveRecord::Base
|
||||
# scope :colored, lambda { |color|
|
||||
# { :conditions => { :color => color } }
|
||||
# }
|
||||
# end
|
||||
#
|
||||
# expected_options = { :conditions => { :colored => 'red' } }
|
||||
# assert_equal expected_options, Shirt.colored('red').proxy_options
|
||||
def scope(name, options = {}, &block)
|
||||
def scope(name, scope_options = {}, &block)
|
||||
name = name.to_sym
|
||||
|
||||
if !scopes[name] && respond_to?(name, true)
|
||||
@ -106,17 +91,17 @@ def scope(name, options = {}, &block)
|
||||
"Overwriting existing method #{self.name}.#{name}."
|
||||
end
|
||||
|
||||
scopes[name] = lambda do |parent_scope, *args|
|
||||
Scope.init(parent_scope, case options
|
||||
when Hash, Relation
|
||||
options
|
||||
when Proc
|
||||
options.call(*args)
|
||||
end, &block)
|
||||
scopes[name] = lambda do |*args|
|
||||
options = scope_options.is_a?(Proc) ? scope_options.call(*args) : scope_options
|
||||
|
||||
relation = scoped
|
||||
relation = options.is_a?(Hash) ? relation.apply_finder_options(options) : scoped.merge(options) if options
|
||||
block_given? ? relation.extending(Module.new(&block)) : relation
|
||||
end
|
||||
|
||||
singleton_class.instance_eval do
|
||||
define_method name do |*args|
|
||||
scopes[name].call(self, *args)
|
||||
scopes[name].call(*args)
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -127,73 +112,5 @@ def named_scope(*args, &block)
|
||||
end
|
||||
end
|
||||
|
||||
class Scope < Relation
|
||||
attr_accessor :current_scoped_methods_when_defined
|
||||
|
||||
delegate :scopes, :with_scope, :with_exclusive_scope, :scoped_methods, :scoped, :to => :klass
|
||||
|
||||
def self.init(klass, options, &block)
|
||||
relation = new(klass, klass.arel_table)
|
||||
|
||||
scope = if options.is_a?(Hash)
|
||||
klass.scoped.apply_finder_options(options.except(:extend))
|
||||
else
|
||||
options ? klass.scoped.merge(options) : klass.scoped
|
||||
end
|
||||
|
||||
relation = relation.merge(scope)
|
||||
|
||||
Array.wrap(options[:extend]).each {|extension| relation.send(:extend, extension) } if options.is_a?(Hash)
|
||||
relation.send(:extend, Module.new(&block)) if block_given?
|
||||
|
||||
relation.current_scoped_methods_when_defined = klass.send(:current_scoped_methods)
|
||||
relation
|
||||
end
|
||||
|
||||
def first(*args)
|
||||
if args.first.kind_of?(Integer) || (loaded? && !args.first.kind_of?(Hash))
|
||||
to_a.first(*args)
|
||||
else
|
||||
args.first.present? ? apply_finder_options(args.first).first : super
|
||||
end
|
||||
end
|
||||
|
||||
def last(*args)
|
||||
if args.first.kind_of?(Integer) || (loaded? && !args.first.kind_of?(Hash))
|
||||
to_a.last(*args)
|
||||
else
|
||||
args.first.present? ? apply_finder_options(args.first).last : super
|
||||
end
|
||||
end
|
||||
|
||||
def ==(other)
|
||||
case other
|
||||
when Scope
|
||||
to_sql == other.to_sql
|
||||
when Relation
|
||||
other == self
|
||||
when Array
|
||||
to_a == other.to_a
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def method_missing(method, *args, &block)
|
||||
if klass.respond_to?(method)
|
||||
with_scope(self) do
|
||||
if current_scoped_methods_when_defined && !scoped_methods.include?(current_scoped_methods_when_defined) && !scopes.include?(method)
|
||||
with_scope(current_scoped_methods_when_defined) { klass.send(method, *args, &block) }
|
||||
else
|
||||
klass.send(method, *args, &block)
|
||||
end
|
||||
end
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
@ -84,7 +84,7 @@ namespace :db do
|
||||
end
|
||||
end
|
||||
when 'postgresql'
|
||||
@encoding = config[:encoding] || ENV['CHARSET'] || 'utf8'
|
||||
@encoding = config['encoding'] || ENV['CHARSET'] || 'utf8'
|
||||
schema_search_path = config['schema_search_path'] || 'public'
|
||||
first_in_schema_search_path = schema_search_path.split(',').first.strip
|
||||
begin
|
||||
|
@ -277,6 +277,17 @@ def validate?
|
||||
!options[:validate].nil? ? options[:validate] : (options[:autosave] == true || macro == :has_many)
|
||||
end
|
||||
|
||||
def dependent_conditions(record, base_class, extra_conditions)
|
||||
dependent_conditions = []
|
||||
dependent_conditions << "#{primary_key_name} = #{record.send(name).send(:owner_quoted_id)}"
|
||||
dependent_conditions << "#{options[:as]}_type = '#{base_class.name}'" if options[:as]
|
||||
dependent_conditions << klass.send(:sanitize_sql, options[:conditions]) if options[:conditions]
|
||||
dependent_conditions << extra_conditions if extra_conditions
|
||||
dependent_conditions = dependent_conditions.collect {|where| "(#{where})" }.join(" AND ")
|
||||
dependent_conditions = dependent_conditions.gsub('@', '\@')
|
||||
dependent_conditions
|
||||
end
|
||||
|
||||
private
|
||||
def derive_class_name
|
||||
class_name = name.to_s.camelize
|
||||
|
@ -13,8 +13,9 @@ class Relation
|
||||
delegate :insert, :to => :arel
|
||||
|
||||
attr_reader :table, :klass
|
||||
attr_accessor :extensions
|
||||
|
||||
def initialize(klass, table)
|
||||
def initialize(klass, table, &block)
|
||||
@klass, @table = klass, table
|
||||
|
||||
@implicit_readonly = nil
|
||||
@ -22,6 +23,9 @@ def initialize(klass, table)
|
||||
|
||||
SINGLE_VALUE_METHODS.each {|v| instance_variable_set(:"@#{v}_value", nil)}
|
||||
(ASSOCIATION_METHODS + MULTI_VALUE_METHODS).each {|v| instance_variable_set(:"@#{v}_values", [])}
|
||||
@extensions = []
|
||||
|
||||
apply_modules(Module.new(&block)) if block_given?
|
||||
end
|
||||
|
||||
def new(*args, &block)
|
||||
@ -307,11 +311,26 @@ def eager_loading?
|
||||
@should_eager_load ||= (@eager_load_values.any? || (@includes_values.any? && references_eager_loaded_tables?))
|
||||
end
|
||||
|
||||
def ==(other)
|
||||
case other
|
||||
when Relation
|
||||
other.to_sql == to_sql
|
||||
when Array
|
||||
to_a == other.to_a
|
||||
end
|
||||
end
|
||||
|
||||
def inspect
|
||||
to_a.inspect
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def method_missing(method, *args, &block)
|
||||
if Array.method_defined?(method)
|
||||
to_a.send(method, *args, &block)
|
||||
elsif @klass.scopes[method]
|
||||
merge(@klass.send(method, *args, &block))
|
||||
elsif @klass.respond_to?(method)
|
||||
@klass.send(:with_scope, self) { @klass.send(method, *args, &block) }
|
||||
elsif arel.respond_to?(method)
|
||||
|
@ -106,13 +106,29 @@ def find(*args, &block)
|
||||
# A convenience wrapper for <tt>find(:first, *args)</tt>. You can pass in all the
|
||||
# same arguments to this method as you can to <tt>find(:first)</tt>.
|
||||
def first(*args)
|
||||
args.any? ? apply_finder_options(args.first).first : find_first
|
||||
if args.any?
|
||||
if args.first.kind_of?(Integer) || (loaded? && !args.first.kind_of?(Hash))
|
||||
to_a.first(*args)
|
||||
else
|
||||
apply_finder_options(args.first).first
|
||||
end
|
||||
else
|
||||
find_first
|
||||
end
|
||||
end
|
||||
|
||||
# A convenience wrapper for <tt>find(:last, *args)</tt>. You can pass in all the
|
||||
# same arguments to this method as you can to <tt>find(:last)</tt>.
|
||||
def last(*args)
|
||||
args.any? ? apply_finder_options(args.first).last : find_last
|
||||
if args.any?
|
||||
if args.first.kind_of?(Integer) || (loaded? && !args.first.kind_of?(Hash))
|
||||
to_a.last(*args)
|
||||
else
|
||||
apply_finder_options(args.first).last
|
||||
end
|
||||
else
|
||||
find_last
|
||||
end
|
||||
end
|
||||
|
||||
# A convenience wrapper for <tt>find(:all, *args)</tt>. You can pass in all the
|
||||
|
@ -20,10 +20,12 @@ def build_from_hash(attributes, default_table)
|
||||
table = Arel::Table.new(table_name, :engine => @engine)
|
||||
end
|
||||
|
||||
attribute = table[column]
|
||||
unless attribute = table[column]
|
||||
raise StatementInvalid, "No attribute named `#{column}` exists for table `#{table.name}`"
|
||||
end
|
||||
|
||||
case value
|
||||
when Array, ActiveRecord::Associations::AssociationCollection, ActiveRecord::NamedScope::Scope
|
||||
when Array, ActiveRecord::Associations::AssociationCollection, ActiveRecord::Relation
|
||||
values = value.to_a
|
||||
attribute.in(values)
|
||||
when Range
|
||||
|
@ -10,8 +10,9 @@ module QueryMethods
|
||||
|
||||
next if [:where, :having].include?(query_method)
|
||||
class_eval <<-CEVAL
|
||||
def #{query_method}(*args)
|
||||
def #{query_method}(*args, &block)
|
||||
new_relation = clone
|
||||
new_relation.send(:apply_modules, Module.new(&block)) if block_given?
|
||||
value = Array.wrap(args.flatten).reject {|x| x.blank? }
|
||||
new_relation.#{query_method}_values += value if value.present?
|
||||
new_relation
|
||||
@ -21,8 +22,9 @@ def #{query_method}(*args)
|
||||
|
||||
[:where, :having].each do |query_method|
|
||||
class_eval <<-CEVAL
|
||||
def #{query_method}(*args)
|
||||
def #{query_method}(*args, &block)
|
||||
new_relation = clone
|
||||
new_relation.send(:apply_modules, Module.new(&block)) if block_given?
|
||||
value = build_where(*args)
|
||||
new_relation.#{query_method}_values += [*value] if value.present?
|
||||
new_relation
|
||||
@ -34,8 +36,9 @@ def #{query_method}(*args)
|
||||
attr_accessor :"#{query_method}_value"
|
||||
|
||||
class_eval <<-CEVAL
|
||||
def #{query_method}(value = true)
|
||||
def #{query_method}(value = true, &block)
|
||||
new_relation = clone
|
||||
new_relation.send(:apply_modules, Module.new(&block)) if block_given?
|
||||
new_relation.#{query_method}_value = value
|
||||
new_relation
|
||||
end
|
||||
@ -43,8 +46,16 @@ def #{query_method}(value = true)
|
||||
end
|
||||
end
|
||||
|
||||
def lock(locks = true)
|
||||
def extending(*modules)
|
||||
new_relation = clone
|
||||
new_relation.send :apply_modules, *modules
|
||||
new_relation
|
||||
end
|
||||
|
||||
def lock(locks = true, &block)
|
||||
relation = clone
|
||||
relation.send(:apply_modules, Module.new(&block)) if block_given?
|
||||
|
||||
case locks
|
||||
when String, TrueClass, NilClass
|
||||
clone.tap {|new_relation| new_relation.lock_value = locks || true }
|
||||
@ -191,6 +202,12 @@ def build_where(*args)
|
||||
|
||||
private
|
||||
|
||||
def apply_modules(modules)
|
||||
values = Array.wrap(modules)
|
||||
@extensions += values if values.present?
|
||||
values.each {|extension| extend(extension) }
|
||||
end
|
||||
|
||||
def reverse_sql_order(order_query)
|
||||
order_query.to_s.split(/,/).each { |s|
|
||||
if s.match(/\s(asc|ASC)$/)
|
||||
|
@ -6,10 +6,9 @@ def merge(r)
|
||||
merged_relation = clone
|
||||
return merged_relation unless r
|
||||
|
||||
(ActiveRecord::Relation::ASSOCIATION_METHODS + ActiveRecord::Relation::MULTI_VALUE_METHODS).reject {|m| [:joins, :where].include?(m)}.each do |method|
|
||||
unless (value = r.send(:"#{method}_values")).blank?
|
||||
merged_relation.send(:"#{method}_values=", value)
|
||||
end
|
||||
(Relation::ASSOCIATION_METHODS + Relation::MULTI_VALUE_METHODS).reject {|m| [:joins, :where].include?(m)}.each do |method|
|
||||
value = r.send(:"#{method}_values")
|
||||
merged_relation.send(:"#{method}_values=", value) if value.present?
|
||||
end
|
||||
|
||||
merged_relation = merged_relation.joins(r.joins_values)
|
||||
@ -26,7 +25,7 @@ def merge(r)
|
||||
|
||||
merged_relation.where_values = merged_wheres
|
||||
|
||||
ActiveRecord::Relation::SINGLE_VALUE_METHODS.reject {|m| m == :lock}.each do |method|
|
||||
Relation::SINGLE_VALUE_METHODS.reject {|m| m == :lock}.each do |method|
|
||||
unless (value = r.send(:"#{method}_value")).nil?
|
||||
merged_relation.send(:"#{method}_value=", value)
|
||||
end
|
||||
@ -34,6 +33,9 @@ def merge(r)
|
||||
|
||||
merged_relation.lock_value = r.lock_value unless merged_relation.lock_value
|
||||
|
||||
# Apply scope extension modules
|
||||
merged_relation.send :apply_modules, r.extensions
|
||||
|
||||
merged_relation
|
||||
end
|
||||
|
||||
@ -69,7 +71,7 @@ def only(*onlies)
|
||||
result
|
||||
end
|
||||
|
||||
VALID_FIND_OPTIONS = [ :conditions, :include, :joins, :limit, :offset,
|
||||
VALID_FIND_OPTIONS = [ :conditions, :include, :joins, :limit, :offset, :extend,
|
||||
:order, :select, :readonly, :group, :having, :from, :lock ]
|
||||
|
||||
def apply_finder_options(options)
|
||||
@ -84,6 +86,7 @@ def apply_finder_options(options)
|
||||
|
||||
relation = relation.where(options[:conditions]) if options.has_key?(:conditions)
|
||||
relation = relation.includes(options[:include]) if options.has_key?(:include)
|
||||
relation = relation.extending(options[:extend]) if options.has_key?(:extend)
|
||||
|
||||
relation
|
||||
end
|
||||
|
@ -3,7 +3,7 @@ module VERSION #:nodoc:
|
||||
MAJOR = 3
|
||||
MINOR = 0
|
||||
TINY = 0
|
||||
BUILD = "beta1"
|
||||
BUILD = "beta2"
|
||||
|
||||
STRING = [MAJOR, MINOR, TINY, BUILD].join('.')
|
||||
end
|
||||
|
@ -67,4 +67,21 @@ def test_has_default_should_return_false_for_blog_and_test_data_types
|
||||
assert !text_column.has_default?
|
||||
end
|
||||
end
|
||||
|
||||
if current_adapter?(:PostgreSQLAdapter)
|
||||
def test_bigint_column_should_map_to_integer
|
||||
bigint_column = ActiveRecord::ConnectionAdapters::PostgreSQLColumn.new('number', nil, "bigint")
|
||||
assert_equal bigint_column.type, :integer
|
||||
end
|
||||
|
||||
def test_smallint_column_should_map_to_integer
|
||||
smallint_column = ActiveRecord::ConnectionAdapters::PostgreSQLColumn.new('number', nil, "smallint")
|
||||
assert_equal smallint_column.type, :integer
|
||||
end
|
||||
|
||||
def test_uuid_column_should_map_to_string
|
||||
uuid_column = ActiveRecord::ConnectionAdapters::PostgreSQLColumn.new('unique_id', nil, "uuid")
|
||||
assert_equal uuid_column.type, :string
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -572,4 +572,20 @@ def test_except
|
||||
assert_equal Post.all, all_posts.all
|
||||
end
|
||||
|
||||
def test_anonymous_extension
|
||||
relation = Post.where(:author_id => 1).order('id ASC') do
|
||||
def author
|
||||
'lifo'
|
||||
end
|
||||
end
|
||||
|
||||
assert_equal "lifo", relation.author
|
||||
assert_equal "lifo", relation.limit(1).author
|
||||
end
|
||||
|
||||
def test_named_extension
|
||||
relation = Post.where(:author_id => 1).order('id ASC').extending(Post::NamedExtension)
|
||||
assert_equal "lifo", relation.author
|
||||
assert_equal "lifo", relation.limit(1).author
|
||||
end
|
||||
end
|
||||
|
@ -1,4 +1,10 @@
|
||||
class Post < ActiveRecord::Base
|
||||
module NamedExtension
|
||||
def author
|
||||
'lifo'
|
||||
end
|
||||
end
|
||||
|
||||
scope :containing_the_letter_a, where("body LIKE '%a%'")
|
||||
scope :ranked_by_comments, order("comments_count DESC")
|
||||
scope :limit_by, lambda {|l| limit(l) }
|
||||
|
@ -1,4 +1,4 @@
|
||||
*Edge*
|
||||
*Rails 3.0.0 [beta 1] (February 4, 2010)*
|
||||
|
||||
* Add support for errors in JSON format. #1956 [Fabien Jakimowicz]
|
||||
|
||||
|
@ -6,6 +6,7 @@
|
||||
s.version = version
|
||||
s.summary = 'REST modeling framework (part of Rails).'
|
||||
s.description = 'REST on Rails. Wrap your RESTful web app with Ruby classes and work with them like Active Record models.'
|
||||
|
||||
s.required_ruby_version = '>= 1.8.7'
|
||||
|
||||
s.author = 'David Heinemeier Hansson'
|
||||
|
@ -3,7 +3,7 @@ module VERSION #:nodoc:
|
||||
MAJOR = 3
|
||||
MINOR = 0
|
||||
TINY = 0
|
||||
BUILD = "beta1"
|
||||
BUILD = "beta2"
|
||||
|
||||
STRING = [MAJOR, MINOR, TINY, BUILD].join('.')
|
||||
end
|
||||
|
@ -1,4 +1,9 @@
|
||||
*Rails 3.0 (pending)*
|
||||
*Rails 3.0.0 [beta 2] (April 1st, 2010)*
|
||||
|
||||
* Reduced load time by deferring configuration of classes using
|
||||
ActiveSupport::on_load(:component_name) [YK]
|
||||
|
||||
* Rename #metaclass to #singleton_class now that ruby-core has decided [JK]
|
||||
|
||||
* New assertions assert_blank and assert_present. #4299 [Juanjo Bazan]
|
||||
|
||||
@ -7,7 +12,7 @@
|
||||
* JSON backend for YAJL. Preferred if available. #2666 [Brian Lopez]
|
||||
|
||||
|
||||
*Rails 3.0.0 [beta] (February 4, 2010)*
|
||||
*Rails 3.0.0 [beta 1] (February 4, 2010)*
|
||||
|
||||
* Introduce class_attribute to declare inheritable class attributes. Writing an attribute on a subclass behaves just like overriding the superclass reader method. Unifies and replaces most usage of cattr_accessor, class_inheritable_attribute, superclass_delegating_attribute, and extlib_inheritable_attribute. [Jeremy Kemper, Yehuda Katz]
|
||||
|
||||
|
@ -6,6 +6,7 @@
|
||||
s.version = version
|
||||
s.summary = 'A toolkit of support libraries and Ruby core extensions extracted from the Rails framework.'
|
||||
s.description = 'A toolkit of support libraries and Ruby core extensions extracted from the Rails framework. Rich support for multibyte strings, internationalization, time zones, and testing.'
|
||||
|
||||
s.required_ruby_version = '>= 1.8.7'
|
||||
|
||||
s.author = 'David Heinemeier Hansson'
|
||||
|
@ -50,7 +50,7 @@ def class_attribute(*attrs)
|
||||
singleton_class.send(:define_method, attr) { value }
|
||||
end
|
||||
|
||||
define_method(attr) { self.class.send(attr) }
|
||||
define_method(attr) { self.singleton_class.send(attr) }
|
||||
define_method(:"#{attr}?") { !!send(attr) }
|
||||
define_method(:"#{attr}=") do |value|
|
||||
singleton_class.remove_possible_method(attr)
|
||||
|
@ -194,7 +194,7 @@ def self.seconds_to_utc_offset(seconds, colon = true)
|
||||
# offset is the number of seconds that this time zone is offset from UTC
|
||||
# (GMT). Seconds were chosen as the offset unit because that is the unit that
|
||||
# Ruby uses to represent time zone offsets (see Time#utc_offset).
|
||||
def initialize(name, utc_offset, tzinfo = nil)
|
||||
def initialize(name, utc_offset = nil, tzinfo = nil)
|
||||
@name = name
|
||||
@utc_offset = utc_offset
|
||||
@tzinfo = tzinfo
|
||||
@ -202,8 +202,12 @@ def initialize(name, utc_offset, tzinfo = nil)
|
||||
end
|
||||
|
||||
def utc_offset
|
||||
@current_period ||= tzinfo.current_period
|
||||
@current_period.utc_offset
|
||||
if @utc_offset
|
||||
@utc_offset
|
||||
else
|
||||
@current_period ||= tzinfo.current_period
|
||||
@current_period.utc_offset
|
||||
end
|
||||
end
|
||||
|
||||
# Returns the offset of this time zone as a formatted string, of the
|
||||
@ -305,75 +309,29 @@ def period_for_local(time, dst=true)
|
||||
tzinfo.period_for_local(time, dst)
|
||||
end
|
||||
|
||||
# TODO: Preload instead of lazy load for thread safety
|
||||
def tzinfo
|
||||
@tzinfo ||= TimeZone.find_tzinfo(name)
|
||||
end
|
||||
|
||||
# TODO: Preload instead of lazy load for thread safety
|
||||
def self.find_tzinfo(name)
|
||||
require 'tzinfo' unless defined?(::TZInfo)
|
||||
@tzinfo ||= ::TZInfo::Timezone.get(MAPPING[name])
|
||||
::TZInfo::Timezone.get(MAPPING[name] || name)
|
||||
rescue TZInfo::InvalidTimezoneIdentifier
|
||||
nil
|
||||
end
|
||||
|
||||
unless const_defined?(:ZONES)
|
||||
ZONES = []
|
||||
ZONES_MAP = {}
|
||||
[[-39_600, "International Date Line West", "Midway Island", "Samoa" ],
|
||||
[-36_000, "Hawaii" ],
|
||||
[-32_400, "Alaska" ],
|
||||
[-28_800, "Pacific Time (US & Canada)", "Tijuana" ],
|
||||
[-25_200, "Mountain Time (US & Canada)", "Chihuahua", "Mazatlan",
|
||||
"Arizona" ],
|
||||
[-21_600, "Central Time (US & Canada)", "Saskatchewan", "Guadalajara",
|
||||
"Mexico City", "Monterrey", "Central America" ],
|
||||
[-18_000, "Eastern Time (US & Canada)", "Indiana (East)", "Bogota",
|
||||
"Lima", "Quito" ],
|
||||
[-16_200, "Caracas" ],
|
||||
[-14_400, "Atlantic Time (Canada)", "Georgetown", "La Paz", "Santiago" ],
|
||||
[-12_600, "Newfoundland" ],
|
||||
[-10_800, "Brasilia", "Buenos Aires", "Greenland" ],
|
||||
[ -7_200, "Mid-Atlantic" ],
|
||||
[ -3_600, "Azores", "Cape Verde Is." ],
|
||||
[ 0, "Dublin", "Edinburgh", "Lisbon", "London", "Casablanca",
|
||||
"Monrovia", "UTC" ],
|
||||
[ 3_600, "Belgrade", "Bratislava", "Budapest", "Ljubljana", "Prague",
|
||||
"Sarajevo", "Skopje", "Warsaw", "Zagreb", "Brussels",
|
||||
"Copenhagen", "Madrid", "Paris", "Amsterdam", "Berlin",
|
||||
"Bern", "Rome", "Stockholm", "Vienna",
|
||||
"West Central Africa" ],
|
||||
[ 7_200, "Bucharest", "Cairo", "Helsinki", "Kyiv", "Riga", "Sofia",
|
||||
"Tallinn", "Vilnius", "Athens", "Istanbul", "Minsk",
|
||||
"Jerusalem", "Harare", "Pretoria" ],
|
||||
[ 10_800, "Moscow", "St. Petersburg", "Volgograd", "Kuwait", "Riyadh",
|
||||
"Nairobi", "Baghdad" ],
|
||||
[ 12_600, "Tehran" ],
|
||||
[ 14_400, "Abu Dhabi", "Muscat", "Baku", "Tbilisi", "Yerevan" ],
|
||||
[ 16_200, "Kabul" ],
|
||||
[ 18_000, "Ekaterinburg", "Islamabad", "Karachi", "Tashkent" ],
|
||||
[ 19_800, "Chennai", "Kolkata", "Mumbai", "New Delhi", "Sri Jayawardenepura" ],
|
||||
[ 20_700, "Kathmandu" ],
|
||||
[ 21_600, "Astana", "Dhaka", "Almaty",
|
||||
"Novosibirsk" ],
|
||||
[ 23_400, "Rangoon" ],
|
||||
[ 25_200, "Bangkok", "Hanoi", "Jakarta", "Krasnoyarsk" ],
|
||||
[ 28_800, "Beijing", "Chongqing", "Hong Kong", "Urumqi",
|
||||
"Kuala Lumpur", "Singapore", "Taipei", "Perth", "Irkutsk",
|
||||
"Ulaan Bataar" ],
|
||||
[ 32_400, "Seoul", "Osaka", "Sapporo", "Tokyo", "Yakutsk" ],
|
||||
[ 34_200, "Darwin", "Adelaide" ],
|
||||
[ 36_000, "Canberra", "Melbourne", "Sydney", "Brisbane", "Hobart",
|
||||
"Vladivostok", "Guam", "Port Moresby" ],
|
||||
[ 39_600, "Magadan", "Solomon Is.", "New Caledonia" ],
|
||||
[ 43_200, "Fiji", "Kamchatka", "Marshall Is.", "Auckland",
|
||||
"Wellington" ],
|
||||
[ 46_800, "Nuku'alofa" ]].
|
||||
each do |offset, *places|
|
||||
places.each do |place|
|
||||
place.freeze
|
||||
zone = new(place, offset)
|
||||
ZONES << zone
|
||||
ZONES_MAP[place] = zone
|
||||
end
|
||||
MAPPING.each_key do |place|
|
||||
place.freeze
|
||||
zone = new(place)
|
||||
ZONES << zone
|
||||
ZONES_MAP[place] = zone
|
||||
end
|
||||
ZONES.sort!
|
||||
ZONES.freeze
|
||||
ZONES_MAP.freeze
|
||||
|
||||
US_ZONES = ZONES.find_all { |z| z.name =~ /US|Arizona|Indiana|Hawaii|Alaska/ }
|
||||
US_ZONES.freeze
|
||||
@ -404,7 +362,7 @@ def all
|
||||
def [](arg)
|
||||
case arg
|
||||
when String
|
||||
ZONES_MAP[arg]
|
||||
ZONES_MAP[arg] ||= lookup(arg)
|
||||
when Numeric, ActiveSupport::Duration
|
||||
arg *= 3600 if arg.abs <= 13
|
||||
all.find { |z| z.utc_offset == arg.to_i }
|
||||
@ -418,6 +376,12 @@ def [](arg)
|
||||
def us_zones
|
||||
US_ZONES
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def lookup(name)
|
||||
(tzinfo = find_tzinfo(name)) && create(tzinfo.name.freeze)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -3,7 +3,7 @@ module VERSION #:nodoc:
|
||||
MAJOR = 3
|
||||
MINOR = 0
|
||||
TINY = 0
|
||||
BUILD = "beta1"
|
||||
BUILD = "beta2"
|
||||
|
||||
STRING = [MAJOR, MINOR, TINY, BUILD].join('.')
|
||||
end
|
||||
|
@ -59,4 +59,10 @@ def setup
|
||||
object = Class.new { class_attribute :setting, :instance_writer => false }.new
|
||||
assert_raise(NoMethodError) { object.setting = 'boom' }
|
||||
end
|
||||
|
||||
test 'works well with singleton classes' do
|
||||
object = @klass.new
|
||||
object.singleton_class.setting = 'foo'
|
||||
assert_equal 'foo', object.setting
|
||||
end
|
||||
end
|
||||
|
@ -75,6 +75,14 @@ def test_now_enforces_fall_dst_rules
|
||||
end
|
||||
end
|
||||
|
||||
def test_unknown_timezones_delegation_to_tzinfo
|
||||
zone = ActiveSupport::TimeZone['America/Montevideo']
|
||||
assert_equal ActiveSupport::TimeZone, zone.class
|
||||
assert_equal zone.object_id, ActiveSupport::TimeZone['America/Montevideo'].object_id
|
||||
assert_equal Time.utc(2010, 1, 31, 22), zone.utc_to_local(Time.utc(2010, 2)) # daylight saving offset -0200
|
||||
assert_equal Time.utc(2010, 3, 31, 21), zone.utc_to_local(Time.utc(2010, 4)) # standard offset -0300
|
||||
end
|
||||
|
||||
def test_today
|
||||
Time.stubs(:now).returns(Time.utc(2000, 1, 1, 4, 59, 59)) # 1 sec before midnight Jan 1 EST
|
||||
assert_equal Date.new(1999, 12, 31), ActiveSupport::TimeZone['Eastern Time (US & Canada)'].today
|
||||
|
@ -6,7 +6,8 @@
|
||||
s.version = version
|
||||
s.summary = 'Full-stack web application framework.'
|
||||
s.description = 'Ruby on Rails is a full-stack web framework optimized for programmer happiness and sustainable productivity. It encourages beautiful code by favoring convention over configuration.'
|
||||
s.required_ruby_version = '>= 1.8.7'
|
||||
|
||||
s.required_ruby_version = '>= 1.8.7'
|
||||
s.required_rubygems_version = ">= 1.3.6"
|
||||
|
||||
s.author = 'David Heinemeier Hansson'
|
||||
@ -17,11 +18,11 @@
|
||||
s.files = []
|
||||
s.require_path = []
|
||||
|
||||
s.add_dependency('activesupport', version)
|
||||
s.add_dependency('actionpack', version)
|
||||
s.add_dependency('activerecord', version)
|
||||
s.add_dependency('activeresource', version)
|
||||
s.add_dependency('actionmailer', version)
|
||||
s.add_dependency('railties', version)
|
||||
s.add_dependency('bundler', '>= 0.9.8')
|
||||
s.add_dependency('activesupport', version)
|
||||
s.add_dependency('actionpack', version)
|
||||
s.add_dependency('activerecord', version)
|
||||
s.add_dependency('activeresource', version)
|
||||
s.add_dependency('actionmailer', version)
|
||||
s.add_dependency('railties', version)
|
||||
s.add_dependency('bundler', '>= 0.9.14')
|
||||
end
|
||||
|
@ -1,27 +0,0 @@
|
||||
Gem::Specification.new do |s|
|
||||
s.platform = Gem::Platform::RUBY
|
||||
s.name = 'rails3b'
|
||||
s.version = '3.0.1'
|
||||
s.summary = 'Just the Rails 3 beta dependencies. Works around prerelease RubyGems bug in versions before 1.3.6.'
|
||||
s.required_ruby_version = '>= 1.8.7'
|
||||
|
||||
s.author = 'Jeremy Kemper'
|
||||
s.email = 'jeremy@bitsweat.net'
|
||||
|
||||
s.files = []
|
||||
s.require_path = []
|
||||
|
||||
s.add_dependency('mail', '~> 2.1.2')
|
||||
s.add_dependency('text-format', '~> 1.0.0')
|
||||
s.add_dependency('rack', '~> 1.1.0')
|
||||
s.add_dependency('rack-test', '~> 0.5.0')
|
||||
s.add_dependency('rack-mount', '= 0.4.7')
|
||||
s.add_dependency('erubis', '~> 2.6.5')
|
||||
s.add_dependency('i18n', '~> 0.3.0')
|
||||
s.add_dependency('tzinfo', '~> 0.3.16')
|
||||
s.add_dependency('builder', '~> 2.1.2')
|
||||
s.add_dependency('memcache-client', '~> 1.7.5')
|
||||
s.add_dependency('bundler', '>= 0.9.8')
|
||||
s.add_dependency('rake', '>= 0.8.3')
|
||||
s.add_dependency('thor', '~> 0.13')
|
||||
end
|
@ -1,4 +1,18 @@
|
||||
*Edge*
|
||||
*Rails 3.0.0 [beta 2] (April 1st, 2010)*
|
||||
|
||||
* Session store configuration has changed [YK & CL]
|
||||
|
||||
config.session_store :cookie_store, {:key => "..."}
|
||||
config.cookie_secret = "fdsfhisdghfidugnfdlg"
|
||||
|
||||
* railtie_name and engine_name are deprecated. You can now add any object to
|
||||
the configuration object: config.your_plugin = {} [JK]
|
||||
|
||||
* Added config.generators.templates to provide alternative paths for the generators
|
||||
to look for templates [JV]
|
||||
|
||||
|
||||
*Rails 3.0.0 [beta 1] (February 4, 2010)*
|
||||
|
||||
* Added "rake about" as a replacement for script/about [DHH]
|
||||
|
||||
|
Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 33 KiB |
Before Width: | Height: | Size: 337 B After Width: | Height: | Size: 337 B |
Before Width: | Height: | Size: 60 B After Width: | Height: | Size: 60 B |
Before Width: | Height: | Size: 53 KiB After Width: | Height: | Size: 53 KiB |
Before Width: | Height: | Size: 628 B After Width: | Height: | Size: 628 B |
Before Width: | Height: | Size: 384 B After Width: | Height: | Size: 384 B |
0
railties/guides/images/credits_pic_blank.gif → railties/guides/assets/images/credits_pic_blank.gif
Before Width: | Height: | Size: 613 B After Width: | Height: | Size: 613 B |
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 41 KiB |
Before Width: | Height: | Size: 4.9 KiB After Width: | Height: | Size: 4.9 KiB |
Before Width: | Height: | Size: 7.8 KiB After Width: | Height: | Size: 7.8 KiB |
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 43 B After Width: | Height: | Size: 43 B |
Before Width: | Height: | Size: 44 B After Width: | Height: | Size: 44 B |
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 45 B After Width: | Height: | Size: 45 B |
Before Width: | Height: | Size: 62 KiB After Width: | Height: | Size: 62 KiB |
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 38 KiB |
Before Width: | Height: | Size: 98 KiB After Width: | Height: | Size: 98 KiB |
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 38 KiB |
Before Width: | Height: | Size: 90 KiB After Width: | Height: | Size: 90 KiB |
Before Width: | Height: | Size: 882 B After Width: | Height: | Size: 882 B |
Before Width: | Height: | Size: 44 B After Width: | Height: | Size: 44 B |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 329 B After Width: | Height: | Size: 329 B |
0
railties/guides/images/icons/callouts/10.png → railties/guides/assets/images/icons/callouts/10.png
Before Width: | Height: | Size: 361 B After Width: | Height: | Size: 361 B |
0
railties/guides/images/icons/callouts/11.png → railties/guides/assets/images/icons/callouts/11.png
Before Width: | Height: | Size: 565 B After Width: | Height: | Size: 565 B |