提交 207fa596 编写于 作者: X Xavier Noria

Merge remote branch 'rails/master'

Conflicts:
	actionpack/lib/abstract_controller/base.rb
......@@ -5,6 +5,7 @@ gem "rails", :path => File.dirname(__FILE__)
gem "rake", ">= 0.8.7"
gem "mocha", ">= 0.9.8"
gem "rdoc", "2.2"
mri = !defined?(RUBY_ENGINE) || RUBY_ENGINE == "ruby"
if mri && RUBY_VERSION < '1.9'
......@@ -44,10 +45,6 @@ elsif RUBY_ENGINE == "jruby"
end
end
group :documentation do
gem 'rdoc', '2.1'
end
if ENV['CI']
gem "nokogiri", ">= 1.4.0"
......
gem 'rdoc', '= 2.2'
require 'rdoc'
require 'rake'
require 'rake/rdoctask'
require 'rake/gempackagetask'
......@@ -68,7 +71,15 @@ Rake::RDocTask.new do |rdoc|
rdoc.options << '--charset' << 'utf-8'
rdoc.options << '--main' << 'railties/README'
rdoc.template = ENV['template'] ? "#{ENV['template']}.rb" : './doc/template/horo'
# Workaround: RDoc assumes that rdoc.template can be required, and that
# rdoc.template.upcase is a constant living in RDoc::Generator::HTML
# which holds the actual template class.
#
# We put 'doc/template' in the load path to be able to set the template
# to the string 'horo' and thus meet those RDoc's assumptions.
$:.unshift('doc/template')
rdoc.template = ENV['template'] ? "#{ENV['template']}.rb" : 'horo'
rdoc.rdoc_files.include('railties/CHANGELOG')
rdoc.rdoc_files.include('railties/MIT-LICENSE')
......@@ -117,7 +128,7 @@ end
desc "Publish API docs for Rails as a whole and for each component"
task :pdoc => :rdoc do
require 'rake/contrib/sshpublisher'
Rake::SshDirPublisher.new("wrath.rubyonrails.org", "public_html/api", "doc/rdoc").upload
Rake::SshDirPublisher.new("rails@api.rubyonrails.org", "public_html/api", "doc/rdoc").upload
PROJECTS.each do |project|
system %(cd #{project} && #{$0} pdoc)
end
......
require 'rubygems'
gem 'rdoc', '= 2.2'
require 'rdoc'
require 'rake'
require 'rake/testtask'
require 'rake/rdoctask'
......@@ -53,5 +54,5 @@ end
desc "Publish the API documentation"
task :pdoc => [:rdoc] do
require 'rake/contrib/sshpublisher'
Rake::SshDirPublisher.new("wrath.rubyonrails.org", "public_html/am", "doc").upload
Rake::SshDirPublisher.new("rails@api.rubyonrails.org", "public_html/am", "doc").upload
end
*Rails 3.0.0 [Release Candidate] (unreleased)*
* Add shallow routes back to the new router [Diego Carrion, Andrew White]
resources :posts do
shallow do
resources :comments
end
end
You can now use comment_path for /comments/1 instead of post_comment_path for /posts/1/comments/1.
* Add support for multi-subdomain session by setting cookie host in session cookie so you can share session between www.example.com, example.com and user.example.com. #4818 [Guillermo Álvarez]
* Removed textilize, textilize_without_paragraph and markdown helpers. [Santiago Pastorino]
......
require 'rubygems'
gem 'rdoc', '= 2.2'
require 'rdoc'
require 'rake'
require 'rake/testtask'
require 'rake/rdoctask'
......
require 'active_support/configurable'
require 'active_support/descendants_tracker'
require 'active_support/core_ext/module/anonymous'
module AbstractController
......@@ -10,6 +11,7 @@ class Base
attr_internal :action_name
include ActiveSupport::Configurable
extend ActiveSupport::DescendantsTracker
class << self
attr_reader :abstract
......@@ -21,17 +23,6 @@ def abstract!
@abstract = true
end
def inherited(klass)
::AbstractController::Base.descendants << klass.to_s
super
end
# A list of all descendants of AbstractController::Base. This is
# useful for initializers which need to add behavior to all controllers.
def descendants
@descendants ||= []
end
# A list of all internal methods for a controller. This finds the first
# abstract superclass of a controller, and gets a list of all public
# instance methods on that abstract class. Public instance methods of
......
......@@ -52,8 +52,7 @@ def build(action, app=nil, &block)
class Metal < AbstractController::Base
abstract!
# :api: public
attr_internal :params, :env
attr_internal :env
# Returns the last part of the controller's name, underscored, without the ending
# "Controller". For instance, MyApp::MyPostsController would return "my_posts" for
......@@ -85,6 +84,14 @@ def initialize(*)
super
end
def params
@_params ||= request.parameters
end
def params=(val)
@_params = val
end
# Basic implementations for content_type=, location=, and headers are
# provided to reduce the dependency on the RackDelegation module
# in Renderer and Redirector.
......
......@@ -14,10 +14,6 @@ def dispatch(action, request, response = ActionDispatch::Response.new)
super(action, request)
end
def params
@_params ||= @_request.parameters
end
def response_body=(body)
response.body = body if response
super
......
......@@ -11,7 +11,7 @@ module ActionController
# polymorphic_url([:admin, @article, @comment])
#
# results in:
#
#
# admin_article_comment_url(@article, @comment)
#
# == Usage within the framework
......@@ -166,6 +166,7 @@ def build_named_route_call(records, inflection, options = {})
route << RecordIdentifier.__send__("plural_class_name", record)
route = route.singularize if inflection == :singular
route << "_"
route << "index_" if RecordIdentifier.uncountable?(record) && inflection == :plural
end
action_prefix(options) + route + routing_type(options).to_s
......
require 'active_support/core_ext/module'
module ActionController
# The record identifier encapsulates a number of naming conventions for dealing with records, like Active Records or
# The record identifier encapsulates a number of naming conventions for dealing with records, like Active Records or
# Active Resources or pretty much any other model type that has an id. These patterns are then used to try elevate
# the view actions to a higher logical level. Example:
#
......@@ -28,7 +28,7 @@ module ActionController
# end
#
# As the example above shows, you can stop caring to a large extent what the actual id of the post is. You just know
# that one is being assigned and that the subsequent calls in redirect_to and the RJS expect that same naming
# that one is being assigned and that the subsequent calls in redirect_to and the RJS expect that same naming
# convention and allows you to write less code if you follow it.
module RecordIdentifier
extend self
......@@ -59,7 +59,7 @@ def dom_class(record_or_class, prefix = nil)
# If you need to address multiple instances of the same class in the same view, you can prefix the dom_id:
#
# dom_id(Post.find(45), :edit) # => "edit_post_45"
def dom_id(record, prefix = nil)
def dom_id(record, prefix = nil)
if record_id = record_key_for_dom_id(record)
"#{dom_class(record, prefix)}#{JOIN}#{record_id}"
else
......@@ -102,6 +102,14 @@ def singular_class_name(record_or_class)
model_name_from_record_or_class(record_or_class).singular
end
# Identifies whether the class name of a record or class is uncountable. Examples:
#
# uncountable?(Sheep) # => true
# uncountable?(Post) => false
def uncountable?(record_or_class)
plural_class_name(record_or_class) == singular_class_name(record_or_class)
end
private
def model_name_from_record_or_class(record_or_class)
(record_or_class.is_a?(Class) ? record_or_class : record_or_class.class).model_name
......
文件模式从 100755 更改为 100644
......@@ -8,7 +8,7 @@ module ActionDispatch
class Callbacks
include ActiveSupport::Callbacks
define_callbacks :call, :terminator => "result == false", :rescuable => true
define_callbacks :call, :rescuable => true
define_callbacks :prepare, :scope => :name
# Add a preparation callback. Preparation callbacks are run before every
......@@ -37,12 +37,12 @@ def self.after(*args, &block)
def initialize(app, prepare_each_request = false)
@app, @prepare_each_request = app, prepare_each_request
run_callbacks(:prepare)
_run_prepare_callbacks
end
def call(env)
run_callbacks(:call) do
run_callbacks(:prepare) if @prepare_each_request
_run_call_callbacks do
_run_prepare_callbacks if @prepare_each_request
@app.call(env)
end
end
......
......@@ -122,7 +122,7 @@ def status_code(exception)
end
def render(status, body)
[status, {'Content-Type' => 'text/html', 'Content-Length' => body.length.to_s}, [body]]
[status, {'Content-Type' => 'text/html', 'Content-Length' => body.bytesize.to_s}, [body]]
end
def public_path
......
......@@ -10,7 +10,7 @@ class Railtie < Rails::Railtie
# Prepare dispatcher callbacks and run 'prepare' callbacks
initializer "action_dispatch.prepare_dispatcher" do |app|
ActionDispatch::Callbacks.to_prepare { app.routes_reloader.reload_if_changed }
ActionDispatch::Callbacks.to_prepare { app.routes_reloader.execute_if_updated }
end
end
end
\ No newline at end of file
......@@ -896,8 +896,10 @@ def build_selects_from_types(order)
# Returns the separator for a given datetime component
def separator(type)
case type
when :month, :day
@options[:date_separator]
when :month
@options[:discard_month] ? "" : @options[:date_separator]
when :day
@options[:discard_day] ? "" : @options[:date_separator]
when :hour
(@options[:discard_year] && @options[:discard_day]) ? "" : @options[:datetime_separator]
when :minute
......
......@@ -303,7 +303,7 @@ def form_for(record_or_name_or_array, *args, &proc)
args.unshift object
end
options[:html][:remote] = true if options.delete(:remote)
(options[:html] ||= {})[:remote] = true if options.delete(:remote)
output = form_tag(options.delete(:url) || {}, options.delete(:html) || {})
output << fields_for(object_name, *(args << options), &proc)
......
......@@ -399,7 +399,7 @@ def option_groups_from_collection_for_select(collection, group_method, group_lab
options_for_select += "<optgroup label=\"#{html_escape(group_label_string)}\">"
options_for_select += options_from_collection_for_select(eval("group.#{group_method}"), option_key_method, option_value_method, selected_key)
options_for_select += '</optgroup>'
end
end.html_safe
end
# Returns a string of <tt><option></tt> tags, like <tt>options_for_select</tt>, but
......
......@@ -40,7 +40,10 @@ def safe_concat(string)
# for a total length not exceeding <tt>:length</tt>.
#
# Pass a <tt>:separator</tt> to truncate +text+ at a natural break.
# Pass a <tt>:safe</tt> value as "true" to not to escape the content.
#
# The result is not marked as HTML-safe, so will be subject to the default escaping when
# used in views, unless wrapped by <tt>raw()</tt>. Care should be taken if +text+ contains HTML tags
# or entities, because truncation may produce invalid HTML (such as unbalanced or incomplete tags).
#
# ==== Examples
#
......@@ -57,12 +60,6 @@ def safe_concat(string)
# # => "And they f... (continued)"
#
# truncate("<p>Once upon a time in a world far far away</p>")
# # => "&lt;p&gt;Once upon a time i..."
#
# truncate("<p>Once upon a time in a world far far away</p>", :safe => true)
# # => "<p>Once upon a time in a wo..."
#
# truncate("<p>Once upon a time in a world far far away</p>".html_safe)
# # => "<p>Once upon a time in a wo..."
#
# You can still use <tt>truncate</tt> with the old API that accepts the
......@@ -85,7 +82,6 @@ def truncate(text, *args)
options.reverse_merge!(:length => 30)
text = h(text) unless text.html_safe? || options[:safe]
text.truncate(options.delete(:length), options) if text
end
......@@ -117,13 +113,13 @@ def highlight(text, phrases, *args)
end
options.reverse_merge!(:highlighter => '<strong class="highlight">\1</strong>')
text = h(text) unless text.html_safe? || options[:safe]
text = sanitize(text) unless options[:sanitize] == false
if text.blank? || phrases.blank?
text
else
match = Array(phrases).map { |p| Regexp.escape(p) }.join('|')
text.gsub(/(#{match})(?!(?:[^<]*?)(?:["'])[^<>]*>)/i, options[:highlighter])
end
end.html_safe
end
# Extracts an excerpt from +text+ that matches the first instance of +phrase+.
......@@ -253,9 +249,9 @@ def word_wrap(text, *args)
# simple_format("Look ma! A class!", :class => 'description')
# # => "<p class='description'>Look ma! A class!</p>"
def simple_format(text, html_options={}, options={})
text = '' if text.nil?
text = ''.html_safe if text.nil?
start_tag = tag('p', html_options, true)
text = h(text) unless text.html_safe? || options[:safe]
text = sanitize(text) unless options[:sanitize] == false
text.gsub!(/\r\n?/, "\n") # \r\n and \r -> \n
text.gsub!(/\n\n+/, "</p>\n\n#{start_tag}") # 2+ newline -> paragraph
text.gsub!(/([^\n]\n)(?=[^\n])/, '\1<br />') # 1 newline -> br
......@@ -499,7 +495,11 @@ def auto_link_urls(text, html_options = {}, options = {})
link_text = block_given?? yield(href) : href
href = 'http://' + href unless scheme
content_tag(:a, link_text, link_attributes.merge('href' => href), !(options[:safe] || text.html_safe?)) + punctuation.reverse.join('')
unless options[:sanitize] == false
link_text = sanitize(link_text)
href = sanitize(href)
end
content_tag(:a, link_text, link_attributes.merge('href' => href), !!options[:sanitize]) + punctuation.reverse.join('')
end
end.html_safe
end
......@@ -514,7 +514,11 @@ def auto_link_email_addresses(text, html_options = {}, options = {})
text.html_safe
else
display_text = (block_given?) ? yield(text) : text
display_text = h(display_text) unless options[:safe]
unless options[:sanitize] == false
text = sanitize(text)
display_text = sanitize(display_text) unless text == display_text
end
mail_to text, display_text, html_options
end
end
......
......@@ -318,7 +318,7 @@ def partial_path(object = @object)
object.class.model_name.partial_path.dup.tap do |partial|
path = @view.controller_path
partial.insert(0, "#{File.dirname(path)}/") if path.include?(?/)
partial.insert(0, "#{File.dirname(path)}/") if partial.include?(?/) && path.include?(?/)
end
end
end
......
......@@ -85,6 +85,7 @@ def include_helper_modules!
def setup_with_controller
@controller = ActionView::TestCase::TestController.new
@request = @controller.request
@output_buffer = ActiveSupport::SafeBuffer.new
@rendered = ''
......
......@@ -381,6 +381,7 @@ def test_uncountable_resource
with_test_routes do
@series.save
assert_equal "http://example.com/series/#{@series.id}", polymorphic_url(@series)
assert_equal "http://example.com/series", polymorphic_url(Series.new)
end
end
......
......@@ -13,6 +13,19 @@ def name
end
end
class Sheep
extend ActiveModel::Naming
include ActiveModel::Conversion
attr_reader :id
def to_key; id ? [id] : nil end
def save; @id = 1 end
def new_record?; @id.nil? end
def name
@id.nil? ? 'new sheep' : "sheep ##{@id}"
end
end
class Comment::Nested < Comment; end
class Test::Unit::TestCase
......@@ -20,7 +33,7 @@ class Test::Unit::TestCase
def comments_url
'http://www.example.com/comments'
end
def comment_url(comment)
"http://www.example.com/comments/#{comment.id}"
end
......@@ -35,6 +48,7 @@ def setup
@record = @klass.new
@singular = 'comment'
@plural = 'comments'
@uncountable = Sheep
end
def test_dom_id_with_new_record
......@@ -58,7 +72,7 @@ def test_dom_id_with_prefix
def test_dom_class
assert_equal @singular, dom_class(@record)
end
def test_dom_class_with_prefix
assert_equal "custom_prefix_#{@singular}", dom_class(@record, :custom_prefix)
end
......@@ -79,6 +93,11 @@ def test_plural_class_name_for_class
assert_equal @plural, plural_class_name(@klass)
end
def test_uncountable
assert_equal true, uncountable?(@uncountable)
assert_equal false, uncountable?(@klass)
end
private
def method_missing(method, *args)
RecordIdentifier.send(method, *args)
......
......@@ -7,6 +7,10 @@ class GamesController < ActionController::Base
# :ported:
def hello_world
end
def nested_partial_with_form_builder
render :partial => ActionView::Helpers::FormBuilder.new(:post, nil, view_context, {}, Proc.new {})
end
end
end
......@@ -1230,6 +1234,13 @@ def test_partial_with_form_builder_subclass
assert_match(/<label/, @response.body)
assert_template('test/_labelling_form')
end
def test_nested_partial_with_form_builder
@controller = Fun::GamesController.new
get :nested_partial_with_form_builder
assert_match(/<label/, @response.body)
assert_template('fun/games/_form')
end
def test_partial_collection
get :partial_collection
......
......@@ -68,6 +68,8 @@ def self.matches?(request)
get 'admin/accounts' => "queenbee#accounts"
end
get 'admin/passwords' => "queenbee#passwords", :constraints => ::TestRoutingMapper::IpRestrictor
scope 'pt', :name_prefix => 'pt' do
resources :projects, :path_names => { :edit => 'editar', :new => 'novo' }, :path => 'projetos' do
post :preview, :on => :new
......@@ -142,6 +144,32 @@ def self.matches?(request)
resources :comments, :except => :destroy
end
resource :past, :only => :destroy
resource :present, :only => :update
resource :future, :only => :create
resources :relationships, :only => [:create, :destroy]
resources :friendships, :only => [:update]
shallow do
namespace :api do
resources :teams do
resources :players
resource :captain
end
end
end
resources :threads, :shallow => true do
resource :owner
resources :messages do
resources :comments do
member do
post :preview
end
end
end
end
resources :sheep
resources :clients do
......@@ -154,6 +182,33 @@ def self.matches?(request)
end
end
resources :customers do
get "recent" => "customers#recent", :as => :recent, :on => :collection
get "profile" => "customers#profile", :as => :profile, :on => :member
post "preview" => "customers#preview", :as => :preview, :on => :new
resource :avatar do
get "thumbnail(.:format)" => "avatars#thumbnail", :as => :thumbnail, :on => :member
end
resources :invoices do
get "outstanding" => "invoices#outstanding", :as => :outstanding, :on => :collection
get "overdue", :to => :overdue, :on => :collection
get "print" => "invoices#print", :as => :print, :on => :member
post "preview" => "invoices#preview", :as => :preview, :on => :new
end
resources :notes, :shallow => true do
get "preview" => "notes#preview", :as => :preview, :on => :new
get "print" => "notes#print", :as => :print, :on => :member
end
end
namespace :api do
resources :customers do
get "recent" => "customers#recent", :as => :recent, :on => :collection
get "profile" => "customers#profile", :as => :profile, :on => :member
post "preview" => "customers#preview", :as => :preview, :on => :new
end
end
match 'sprockets.js' => ::TestRoutingMapper::SprocketsApp
match 'people/:id/update', :to => 'people#update', :as => :update_person
......@@ -223,8 +278,11 @@ def self.matches?(request)
resource :dashboard, :constraints => { :ip => /192\.168\.1\.\d{1,3}/ }
scope :module => 'api' do
scope :module => :api do
resource :token
resources :errors, :shallow => true do
resources :notices
end
end
scope :path => 'api' do
......@@ -448,6 +506,12 @@ def test_admin
get '/admin/accounts', {}, {'REMOTE_ADDR' => '10.0.0.100'}
assert_equal 'pass', @response.headers['X-Cascade']
get '/admin/passwords', {}, {'REMOTE_ADDR' => '192.168.1.100'}
assert_equal 'queenbee#passwords', @response.body
get '/admin/passwords', {}, {'REMOTE_ADDR' => '10.0.0.100'}
assert_equal 'pass', @response.headers['X-Cascade']
end
end
......@@ -709,6 +773,38 @@ def test_resource_routes_with_only_and_except
end
end
def test_resource_routes_only_create_update_destroy
with_test_routes do
delete '/past'
assert_equal 'pasts#destroy', @response.body
assert_equal '/past', past_path
put '/present'
assert_equal 'presents#update', @response.body
assert_equal '/present', present_path
post '/future'
assert_equal 'futures#create', @response.body
assert_equal '/future', future_path
end
end
def test_resources_routes_only_create_update_destroy
with_test_routes do
post '/relationships'
assert_equal 'relationships#create', @response.body
assert_equal '/relationships', relationships_path
delete '/relationships/1'
assert_equal 'relationships#destroy', @response.body
assert_equal '/relationships/1', relationship_path(1)
put '/friendships/1'
assert_equal 'friendships#update', @response.body
assert_equal '/friendships/1', friendship_path(1)
end
end
def test_resource_with_slugs_in_ids
with_test_routes do
get '/posts/rails-rocks'
......@@ -823,7 +919,7 @@ def test_nested_namespace
assert_equal '/account/admin/subscription', account_admin_subscription_path
end
end
def test_namespace_nested_in_resources
with_test_routes do
get '/clients/1/google/account'
......@@ -1132,6 +1228,143 @@ def test_resources_merges_options_from_scope
end
end
def test_shallow_nested_resources
with_test_routes do
get '/api/teams'
assert_equal 'api/teams#index', @response.body
assert_equal '/api/teams', api_teams_path
get '/api/teams/new'
assert_equal 'api/teams#new', @response.body
assert_equal '/api/teams/new', new_api_team_path
get '/api/teams/1'
assert_equal 'api/teams#show', @response.body
assert_equal '/api/teams/1', api_team_path(:id => '1')
get '/api/teams/1/edit'
assert_equal 'api/teams#edit', @response.body
assert_equal '/api/teams/1/edit', edit_api_team_path(:id => '1')
get '/api/teams/1/players'
assert_equal 'api/players#index', @response.body
assert_equal '/api/teams/1/players', api_team_players_path(:team_id => '1')
get '/api/teams/1/players/new'
assert_equal 'api/players#new', @response.body
assert_equal '/api/teams/1/players/new', new_api_team_player_path(:team_id => '1')
get '/api/players/2'
assert_equal 'api/players#show', @response.body
assert_equal '/api/players/2', api_player_path(:id => '2')
get '/api/players/2/edit'
assert_equal 'api/players#edit', @response.body
assert_equal '/api/players/2/edit', edit_api_player_path(:id => '2')
get '/api/teams/1/captain'
assert_equal 'api/captains#show', @response.body
assert_equal '/api/teams/1/captain', api_team_captain_path(:team_id => '1')
get '/api/teams/1/captain/new'
assert_equal 'api/captains#new', @response.body
assert_equal '/api/teams/1/captain/new', new_api_team_captain_path(:team_id => '1')
get '/api/teams/1/captain/edit'
assert_equal 'api/captains#edit', @response.body
assert_equal '/api/teams/1/captain/edit', edit_api_team_captain_path(:team_id => '1')
get '/threads'
assert_equal 'threads#index', @response.body
assert_equal '/threads', threads_path
get '/threads/new'
assert_equal 'threads#new', @response.body
assert_equal '/threads/new', new_thread_path
get '/threads/1'
assert_equal 'threads#show', @response.body
assert_equal '/threads/1', thread_path(:id => '1')
get '/threads/1/edit'
assert_equal 'threads#edit', @response.body
assert_equal '/threads/1/edit', edit_thread_path(:id => '1')
get '/threads/1/owner'
assert_equal 'owners#show', @response.body
assert_equal '/threads/1/owner', thread_owner_path(:thread_id => '1')
get '/threads/1/messages'
assert_equal 'messages#index', @response.body
assert_equal '/threads/1/messages', thread_messages_path(:thread_id => '1')
get '/threads/1/messages/new'
assert_equal 'messages#new', @response.body
assert_equal '/threads/1/messages/new', new_thread_message_path(:thread_id => '1')
get '/messages/2'
assert_equal 'messages#show', @response.body
assert_equal '/messages/2', message_path(:id => '2')
get '/messages/2/edit'
assert_equal 'messages#edit', @response.body
assert_equal '/messages/2/edit', edit_message_path(:id => '2')
get '/messages/2/comments'
assert_equal 'comments#index', @response.body
assert_equal '/messages/2/comments', message_comments_path(:message_id => '2')
get '/messages/2/comments/new'
assert_equal 'comments#new', @response.body
assert_equal '/messages/2/comments/new', new_message_comment_path(:message_id => '2')
get '/comments/3'
assert_equal 'comments#show', @response.body
assert_equal '/comments/3', comment_path(:id => '3')
get '/comments/3/edit'
assert_equal 'comments#edit', @response.body
assert_equal '/comments/3/edit', edit_comment_path(:id => '3')
post '/comments/3/preview'
assert_equal 'comments#preview', @response.body
assert_equal '/comments/3/preview', preview_comment_path(:id => '3')
end
end
def test_custom_resource_routes_are_scoped
with_test_routes do
assert_equal '/customers/recent', recent_customers_path
assert_equal '/customers/1/profile', profile_customer_path(:id => '1')
assert_equal '/customers/new/preview', preview_new_customer_path
assert_equal '/customers/1/avatar/thumbnail.jpg', thumbnail_customer_avatar_path(:customer_id => '1', :format => :jpg)
assert_equal '/customers/1/invoices/outstanding', outstanding_customer_invoices_path(:customer_id => '1')
assert_equal '/customers/1/invoices/2/print', print_customer_invoice_path(:customer_id => '1', :id => '2')
assert_equal '/customers/1/invoices/new/preview', preview_new_customer_invoice_path(:customer_id => '1')
assert_equal '/customers/1/notes/new/preview', preview_new_customer_note_path(:customer_id => '1')
assert_equal '/notes/1/print', print_note_path(:id => '1')
assert_equal '/api/customers/recent', recent_api_customers_path
assert_equal '/api/customers/1/profile', profile_api_customer_path(:id => '1')
assert_equal '/api/customers/new/preview', preview_new_api_customer_path
get '/customers/1/invoices/overdue'
assert_equal 'invoices#overdue', @response.body
end
end
def test_shallow_nested_routes_ignore_module
with_test_routes do
get '/errors/1/notices'
assert_equal 'api/notices#index', @response.body
assert_equal '/errors/1/notices', error_notices_path(:error_id => '1')
get '/notices/1'
assert_equal 'api/notices#show', @response.body
assert_equal '/notices/1', notice_path(:id => '1')
end
end
private
def with_test_routes
yield
......
......@@ -882,6 +882,33 @@ def test_select_date_with_separator
assert_dom_equal expected, select_date(Time.mktime(2003, 8, 16), { :date_separator => " / ", :start_year => 2003, :end_year => 2005, :prefix => "date[first]"})
end
def test_select_date_with_separator_and_discard_day
expected = %(<select id="date_first_year" name="date[first][year]">\n)
expected << %(<option value="2003" selected="selected">2003</option>\n<option value="2004">2004</option>\n<option value="2005">2005</option>\n)
expected << "</select>\n"
expected << " / "
expected << %(<select id="date_first_month" name="date[first][month]">\n)
expected << %(<option value="1">January</option>\n<option value="2">February</option>\n<option value="3">March</option>\n<option value="4">April</option>\n<option value="5">May</option>\n<option value="6">June</option>\n<option value="7">July</option>\n<option value="8" selected="selected">August</option>\n<option value="9">September</option>\n<option value="10">October</option>\n<option value="11">November</option>\n<option value="12">December</option>\n)
expected << "</select>\n"
expected << %(<input type="hidden" id="date_first_day" name="date[first][day]" value="1" />\n)
assert_dom_equal expected, select_date(Time.mktime(2003, 8, 16), { :date_separator => " / ", :discard_day => true, :start_year => 2003, :end_year => 2005, :prefix => "date[first]"})
end
def test_select_date_with_separator_discard_month_and_day
expected = %(<select id="date_first_year" name="date[first][year]">\n)
expected << %(<option value="2003" selected="selected">2003</option>\n<option value="2004">2004</option>\n<option value="2005">2005</option>\n)
expected << "</select>\n"
expected << %(<input type="hidden" id="date_first_month" name="date[first][month]" value="8" />\n)
expected << %(<input type="hidden" id="date_first_day" name="date[first][day]" value="16" />\n)
assert_dom_equal expected, select_date(Time.mktime(2003, 8, 16), { :date_separator => " / ", :discard_month => true, :discard_day => true, :start_year => 2003, :end_year => 2005, :prefix => "date[first]"})
end
def test_select_datetime
expected = %(<select id="date_first_year" name="date[first][year]">\n)
expected << %(<option value="2003" selected="selected">2003</option>\n<option value="2004">2004</option>\n<option value="2005">2005</option>\n)
......
......@@ -644,6 +644,26 @@ def test_form_for_with_remote
assert_dom_equal expected, output_buffer
end
def test_form_for_with_remote_without_html
assert_deprecated do
form_for(:post, @post, :remote => true) do |f|
concat f.text_field(:title)
concat f.text_area(:body)
concat f.check_box(:secret)
end
end
expected =
"<form action='http://www.example.com' method='post' data-remote='true'>" +
"<input name='post[title]' size='30' type='text' id='post_title' value='Hello World' />" +
"<textarea name='post[body]' id='post_body' rows='20' cols='40'>Back to the hill and over it again!</textarea>" +
"<input name='post[secret]' type='hidden' value='0' />" +
"<input name='post[secret]' checked='checked' type='checkbox' id='post_secret' value='1' />" +
"</form>"
assert_dom_equal expected, output_buffer
end
def test_form_for_without_object
form_for(:post, :html => { :id => 'create-post' }) do |f|
concat f.text_field(:title)
......
......@@ -177,17 +177,16 @@ def test_ducktyped_options_for_select
end
def test_option_groups_from_collection_for_select
@continents = [
Continent.new("<Africa>", [Country.new("<sa>", "<South Africa>"), Country.new("so", "Somalia")] ),
Continent.new("Europe", [Country.new("dk", "Denmark"), Country.new("ie", "Ireland")] )
]
assert_dom_equal(
"<optgroup label=\"&lt;Africa&gt;\"><option value=\"&lt;sa&gt;\">&lt;South Africa&gt;</option>\n<option value=\"so\">Somalia</option></optgroup><optgroup label=\"Europe\"><option value=\"dk\" selected=\"selected\">Denmark</option>\n<option value=\"ie\">Ireland</option></optgroup>",
option_groups_from_collection_for_select(@continents, "countries", "continent_name", "country_id", "country_name", "dk")
option_groups_from_collection_for_select(dummy_continents, "countries", "continent_name", "country_id", "country_name", "dk")
)
end
def test_option_groups_from_collection_for_select_returns_html_safe_string
assert option_groups_from_collection_for_select(dummy_continents, "countries", "continent_name", "country_id", "country_name", "dk").html_safe?
end
def test_grouped_options_for_select_with_array
assert_dom_equal(
"<optgroup label=\"North America\"><option value=\"US\">United States</option>\n<option value=\"Canada\">Canada</option></optgroup><optgroup label=\"Europe\"><option value=\"GB\">Great Britain</option>\n<option value=\"Germany\">Germany</option></optgroup>",
......@@ -824,31 +823,21 @@ def test_option_html_attributes_with_special_characters
end
def test_grouped_collection_select
@continents = [
Continent.new("<Africa>", [Country.new("<sa>", "<South Africa>"), Country.new("so", "Somalia")] ),
Continent.new("Europe", [Country.new("dk", "Denmark"), Country.new("ie", "Ireland")] )
]
@post = Post.new
@post.origin = 'dk'
assert_dom_equal(
%Q{<select id="post_origin" name="post[origin]"><optgroup label="&lt;Africa&gt;"><option value="&lt;sa&gt;">&lt;South Africa&gt;</option>\n<option value="so">Somalia</option></optgroup><optgroup label="Europe"><option value="dk" selected="selected">Denmark</option>\n<option value="ie">Ireland</option></optgroup></select>},
grouped_collection_select("post", "origin", @continents, :countries, :continent_name, :country_id, :country_name)
grouped_collection_select("post", "origin", dummy_continents, :countries, :continent_name, :country_id, :country_name)
)
end
def test_grouped_collection_select_under_fields_for
@continents = [
Continent.new("<Africa>", [Country.new("<sa>", "<South Africa>"), Country.new("so", "Somalia")] ),
Continent.new("Europe", [Country.new("dk", "Denmark"), Country.new("ie", "Ireland")] )
]
@post = Post.new
@post.origin = 'dk'
output_buffer = fields_for :post, @post do |f|
concat f.grouped_collection_select("origin", @continents, :countries, :continent_name, :country_id, :country_name)
concat f.grouped_collection_select("origin", dummy_continents, :countries, :continent_name, :country_id, :country_name)
end
assert_dom_equal(
......@@ -864,4 +853,9 @@ def dummy_posts
Post.new("Babe went home", "Babe", "To a little house", "shh!"),
Post.new("Cabe went home", "Cabe", "To a little house", "shh!") ]
end
def dummy_continents
[ Continent.new("<Africa>", [Country.new("<sa>", "<South Africa>"), Country.new("so", "Somalia")] ),
Continent.new("Europe", [Country.new("dk", "Denmark"), Country.new("ie", "Ireland")] ) ]
end
end
......@@ -218,4 +218,12 @@ def render_from_helper
end
end
end
class RenderTemplateTest < ActionView::TestCase
test "render template" do
controller.controller_path = "test"
render(:template => "test/calling_partial_with_layout")
assert_template "partial_for_use_in_layout"
end
end
end
......@@ -19,6 +19,10 @@ def test_concat
assert_equal 'foobar', output_buffer
end
def test_simple_format_should_be_html_safe
assert simple_format("<b> test with html tags </b>").html_safe?
end
def test_simple_format
assert_equal "<p></p>", simple_format(nil)
......@@ -36,43 +40,25 @@ def test_simple_format
assert_equal %Q(<p class="test">para 1</p>\n\n<p class="test">para 2</p>), simple_format("para 1\n\npara 2", :class => 'test')
end
def test_simple_format_should_be_html_safe
assert simple_format("<b> test with html tags </b>").html_safe?
def test_simple_format_should_sanitize_input_when_sanitize_option_is_not_false
assert_equal "<p><b> test with unsafe string </b></p>", simple_format("<b> test with unsafe string </b><script>code!</script>")
end
def test_simple_format_should_escape_unsafe_input
assert_equal "<p>&lt;b&gt; test with unsafe string &lt;/b&gt;&lt;script&gt;code!&lt;/script&gt;</p>", simple_format("<b> test with unsafe string </b><script>code!</script>")
def test_simple_format_should_not_sanitize_input_when_sanitize_option_is_false
assert_equal "<p><b> test with unsafe string </b><script>code!</script></p>", simple_format("<b> test with unsafe string </b><script>code!</script>", {}, :sanitize => false)
end
def test_simple_format_should_not_escape_input_if_safe_option
assert_equal "<p><b> test with unsafe string </b><script>code!</script></p>", simple_format("<b> test with unsafe string </b><script>code!</script>", {}, :safe => true)
def test_truncate_should_not_be_html_safe
assert !truncate("Hello World!", :length => 12).html_safe?
end
def test_simple_format_should_not_escape_safe_input
assert_equal "<p><b> test with safe string </b></p>", simple_format("<b> test with safe string </b>".html_safe)
end
def test_truncate_should_be_html_safe
assert truncate("Hello World!", :length => 12).html_safe?
end
def test_truncate
assert_equal "Hello World!", truncate("Hello World!", :length => 12)
assert_equal "Hello Wor...", truncate("Hello World!!", :length => 12)
end
def test_truncate_should_escape_unsafe_input
assert_equal "Hello &lt...", truncate("Hello <script>code!</script>World!!", :length => 12)
end
def test_truncate_should_not_escape_input_if_safe_option
assert_equal "Hello <sc...", truncate("Hello <script>code!</script>World!", :length => 12, :safe => true)
assert_equal "Hello <sc...", truncate("Hello <script>code!</script>World!!", :length => 12, :safe => true)
end
def test_truncate_should_not_escape_safe_input
assert_equal "Hello <sc...", truncate("Hello <script>code!</script>World!".html_safe, :length => 12)
assert_equal "Hello <sc...", truncate("Hello <script>code!</script>World!!".html_safe, :length => 12)
def test_truncate_should_not_escape_input
assert_equal "Hello <sc...", truncate("Hello <script>code!</script>World!!", :length => 12)
end
def test_truncate_should_use_default_length_of_30
......@@ -138,24 +124,17 @@ def test_highlight
assert_equal ' ', highlight(' ', 'blank text is returned verbatim')
end
def test_highlight_should_escape_unsafe_input
def test_highlight_should_sanitize_input
assert_equal(
"This is a <strong class=\"highlight\">beautiful</strong> morning&lt;script&gt;code!&lt;/script&gt;",
"This is a <strong class=\"highlight\">beautiful</strong> morning",
highlight("This is a beautiful morning<script>code!</script>", "beautiful")
)
end
def test_highlight_should_not_escape_input_if_safe_option
assert_equal(
"This is a <strong class=\"highlight\">beautiful</strong> morning<script>code!</script>",
highlight("This is a beautiful morning<script>code!</script>", "beautiful", :safe => true)
)
end
def test_highlight_should_not_escape_safe_input
def test_highlight_should_not_sanitize_if_sanitize_option_if_false
assert_equal(
"This is a <strong class=\"highlight\">beautiful</strong> morning<script>code!</script>",
highlight("This is a beautiful morning<script>code!</script>".html_safe, "beautiful")
highlight("This is a beautiful morning<script>code!</script>", "beautiful", :sanitize => false)
)
end
......@@ -189,23 +168,23 @@ def test_highlight_with_options_hash
def test_highlight_with_html
assert_equal(
"&lt;p&gt;This is a <strong class=\"highlight\">beautiful</strong> morning, but also a <strong class=\"highlight\">beautiful</strong> day&lt;/p&gt;",
"<p>This is a <strong class=\"highlight\">beautiful</strong> morning, but also a <strong class=\"highlight\">beautiful</strong> day</p>",
highlight("<p>This is a beautiful morning, but also a beautiful day</p>", "beautiful")
)
assert_equal(
"&lt;p&gt;This is a &lt;em&gt;<strong class=\"highlight\">beautiful</strong>&lt;/em&gt; morning, but also a <strong class=\"highlight\">beautiful</strong> day&lt;/p&gt;",
"<p>This is a <em><strong class=\"highlight\">beautiful</strong></em> morning, but also a <strong class=\"highlight\">beautiful</strong> day</p>",
highlight("<p>This is a <em>beautiful</em> morning, but also a beautiful day</p>", "beautiful")
)
assert_equal(
"&lt;p&gt;This is a &lt;em class=&quot;error&quot;&gt;<strong class=\"highlight\">beautiful</strong>&lt;/em&gt; morning, but also a <strong class=\"highlight\">beautiful</strong> &lt;span class=&quot;last&quot;&gt;day&lt;/span&gt;&lt;/p&gt;",
"<p>This is a <em class=\"error\"><strong class=\"highlight\">beautiful</strong></em> morning, but also a <strong class=\"highlight\">beautiful</strong> <span class=\"last\">day</span></p>",
highlight("<p>This is a <em class=\"error\">beautiful</em> morning, but also a beautiful <span class=\"last\">day</span></p>", "beautiful")
)
assert_equal(
"&lt;p class=&quot;<strong class=\"highlight\">beautiful</strong>&quot;&gt;This is a <strong class=\"highlight\">beautiful</strong> morning, but also a <strong class=\"highlight\">beautiful</strong> day&lt;/p&gt;",
"<p class=\"beautiful\">This is a <strong class=\"highlight\">beautiful</strong> morning, but also a <strong class=\"highlight\">beautiful</strong> day</p>",
highlight("<p class=\"beautiful\">This is a beautiful morning, but also a beautiful day</p>", "beautiful")
)
assert_equal(
"&lt;p&gt;This is a <strong class=\"highlight\">beautiful</strong> &lt;a href=&quot;http://example.com/<strong class=\"highlight\">beautiful</strong>#top?what=<strong class=\"highlight\">beautiful</strong>%20morning&amp;when=now+then&quot;&gt;morning&lt;/a&gt;, but also a <strong class=\"highlight\">beautiful</strong> day&lt;/p&gt;",
"<p>This is a <strong class=\"highlight\">beautiful</strong> <a href=\"http://example.com/beautiful#top?what=beautiful%20morning&amp;when=now+then\">morning</a>, but also a <strong class=\"highlight\">beautiful</strong> day</p>",
highlight("<p>This is a beautiful <a href=\"http://example.com/beautiful\#top?what=beautiful%20morning&when=now+then\">morning</a>, but also a beautiful day</p>", "beautiful")
)
end
......@@ -217,6 +196,10 @@ def test_excerpt
assert_nil excerpt("This is a beautiful morning", "day")
end
def test_excerpt_should_not_be_html_safe
assert !excerpt('This is a beautiful! morning', 'beautiful', 5).html_safe?
end
def test_excerpt_in_borderline_cases
assert_equal("", excerpt("", "", 0))
assert_equal("a", excerpt("a", "a", 0))
......@@ -323,9 +306,13 @@ def test_auto_link_parsing
end
end
def generate_result(link_text, href = nil)
def generate_result(link_text, href = nil, escape = false)
href ||= link_text
%{<a href="#{CGI::escapeHTML href}">#{CGI::escapeHTML link_text}</a>}
if escape
%{<a href="#{CGI::escapeHTML href}">#{CGI::escapeHTML link_text}</a>}
else
%{<a href="#{href}">#{link_text}</a>}
end
end
def test_auto_link_should_be_html_safe
......@@ -430,19 +417,14 @@ def test_auto_link
assert_equal %(<p>#{link10_result} Link</p>), auto_link("<p>#{link10_raw} Link</p>")
end
def test_auto_link_should_sanitize_unsafe_input
link_raw = %{http://www.rubyonrails.com?id=1&num=2}
assert_equal %{<a href="http://www.rubyonrails.com?id=1&amp;num=2">http://www.rubyonrails.com?id=1&amp;num=2</a>}, auto_link(link_raw)
end
def test_auto_link_should_sanitize_unsafe_input
def test_auto_link_should_sanitize_input_when_sanitize_option_is_not_false
link_raw = %{http://www.rubyonrails.com?id=1&num=2}
assert_equal %{<a href="http://www.rubyonrails.com?id=1&num=2">http://www.rubyonrails.com?id=1&num=2</a>}, auto_link(link_raw, :safe => true)
assert_equal %{<a href="http://www.rubyonrails.com?id=1&num=2">http://www.rubyonrails.com?id=1&num=2</a>}, auto_link(link_raw)
end
def test_auto_link_should_not_sanitize_safe_input
def test_auto_link_should_not_sanitize_input_when_sanitize_option_is_false
link_raw = %{http://www.rubyonrails.com?id=1&num=2}
assert_equal %{<a href="http://www.rubyonrails.com?id=1&num=2">http://www.rubyonrails.com?id=1&num=2</a>}, auto_link(link_raw.html_safe)
assert_equal %{<a href="http://www.rubyonrails.com?id=1&num=2">http://www.rubyonrails.com?id=1&num=2</a>}, auto_link(link_raw, :sanitize => false)
end
def test_auto_link_other_protocols
......@@ -453,6 +435,7 @@ def test_auto_link_other_protocols
z39_scheme = 'z39.50r://host:696/db'
chrome_scheme = 'chrome://package/section/path'
view_source = 'view-source:http://en.wikipedia.org/wiki/URI_scheme'
assert_equal generate_result(file_scheme), auto_link(file_scheme)
assert_equal generate_result(z39_scheme), auto_link(z39_scheme)
assert_equal generate_result(chrome_scheme), auto_link(chrome_scheme)
assert_equal generate_result(view_source), auto_link(view_source)
......
dir = File.dirname(__FILE__)
gem 'rdoc', '= 2.2'
require 'rdoc'
require 'rake/testtask'
task :default => :test
......
......@@ -3,6 +3,7 @@
require 'active_support/core_ext/class/attribute'
require 'active_support/core_ext/hash/keys'
require 'active_model/errors'
require 'active_model/validations/callbacks'
module ActiveModel
......@@ -164,8 +165,7 @@ def errors
def valid?(context = nil)
current_context, self.validation_context = validation_context, context
errors.clear
_run_validate_callbacks
errors.empty?
run_validations!
ensure
self.validation_context = current_context
end
......@@ -194,6 +194,13 @@ def invalid?(context = nil)
# end
#
alias :read_attribute_for_validation :send
protected
def run_validations!
_run_validate_callbacks
errors.empty?
end
end
end
......
require 'active_support/callbacks'
module ActiveModel
module Validations
module Callbacks
# == Active Model Validation callbacks
#
# Provides an interface for any class to have <tt>before_validation</tt> and
# <tt>after_validation</tt> callbacks.
#
# First, extend ActiveModel::Callbacks from the class you are creating:
#
# class MyModel
# include ActiveModel::Validations::Callbacks
#
# before_validation :do_stuff_before_validation
# after_validation :do_tuff_after_validation
# end
#
# Like other before_* callbacks if <tt>before_validation</tt> returns false
# then <tt>valid?</tt> will not be called.
extend ActiveSupport::Concern
included do
include ActiveSupport::Callbacks
define_callbacks :validation, :terminator => "result == false", :scope => [:kind, :name]
end
module ClassMethods
def before_validation(*args, &block)
options = args.last
if options.is_a?(Hash) && options[:on]
options[:if] = Array.wrap(options[:if])
options[:if] << "self.validation_context == :#{options[:on]}"
end
set_callback(:validation, :before, *args, &block)
end
def after_validation(*args, &block)
options = args.extract_options!
options[:prepend] = true
options[:if] = Array.wrap(options[:if])
options[:if] << "!halted && value != false"
options[:if] << "self.validation_context == :#{options[:on]}" if options[:on]
set_callback(:validation, :after, *(args << options), &block)
end
end
protected
# Overwrite run validations to include callbacks.
def run_validations!
_run_validation_callbacks { super }
end
end
end
end
# encoding: utf-8
require 'cases/helper'
class Dog
include ActiveModel::Validations
include ActiveModel::Validations::Callbacks
attr_accessor :name, :history
def history
@history ||= []
end
end
class DogWithMethodCallbacks < Dog
before_validation :set_before_validation_marker
after_validation :set_after_validation_marker
def set_before_validation_marker; self.history << 'before_validation_marker'; end
def set_after_validation_marker; self.history << 'after_validation_marker' ; end
end
class DogValidtorsAreProc < Dog
before_validation { self.history << 'before_validation_marker' }
after_validation { self.history << 'after_validation_marker' }
end
class DogWithTwoValidators < Dog
before_validation { self.history << 'before_validation_marker1' }
before_validation { self.history << 'before_validation_marker2' }
end
class DogValidatorReturningFalse < Dog
before_validation { false }
before_validation { self.history << 'before_validation_marker2' }
end
class DogWithMissingName < Dog
before_validation { self.history << 'before_validation_marker' }
validates_presence_of :name
end
class CallbacksWithMethodNamesShouldBeCalled < ActiveModel::TestCase
def test_before_validation_and_after_validation_callbacks_should_be_called
d = DogWithMethodCallbacks.new
d.valid?
assert_equal ['before_validation_marker', 'after_validation_marker'], d.history
end
def test_before_validation_and_after_validation_callbacks_should_be_called_with_proc
d = DogValidtorsAreProc.new
d.valid?
assert_equal ['before_validation_marker', 'after_validation_marker'], d.history
end
def test_before_validation_and_after_validation_callbacks_should_be_called_in_declared_order
d = DogWithTwoValidators.new
d.valid?
assert_equal ['before_validation_marker1', 'before_validation_marker2'], d.history
end
def test_further_callbacks_should_not_be_called_if_before_validation_returns_false
d = DogValidatorReturningFalse.new
output = d.valid?
assert_equal [], d.history
assert_equal false, output
end
def test_validation_test_should_be_done
d = DogWithMissingName.new
output = d.valid?
assert_equal ['before_validation_marker'], d.history
assert_equal false, output
end
end
*Rails 3.0.0 [RC1] (unreleased)*
* PostgreSQL: ensure the database time zone matches Ruby's time zone. #4895 [Aaron Patterson]
*Rails 3.0.0 [beta 4] (June 8th, 2010)*
* Fixed that ActiveRecord::Base.compute_type would swallow NoMethodError #4751 [Andrew Bloomgarden, Andrew White]
......
......@@ -32,5 +32,7 @@ being initialized - you can initialize the schema with:
rake test_mysql TEST=test/cases/aaa_create_tables_test.rb
The incantation for running a particular test looks like this
ruby -w -I"lib:test:test/connections/native_postgresql" test/cases/datatype_test_postgresql.rb -n test_timestamp_with_zone_values_without_rails_time_zone_support
require 'rubygems'
gem 'rdoc', '= 2.2'
require 'rdoc'
require 'rake'
require 'rake/testtask'
require 'rake/rdoctask'
......@@ -222,5 +223,5 @@ end
desc "Publish the API documentation"
task :pdoc => [:rdoc] do
require 'rake/contrib/sshpublisher'
Rake::SshDirPublisher.new("wrath.rubyonrails.org", "public_html/ar", "doc").upload
Rake::SshDirPublisher.new("rails@api.rubyonrails.org", "public_html/ar", "doc").upload
end
文件模式从 100755 更改为 100644
......@@ -2066,7 +2066,7 @@ def association_join
unless klass.descends_from_active_record?
sti_column = aliased_table[klass.inheritance_column]
sti_condition = sti_column.eq(klass.sti_name)
klass.send(:subclasses).each {|subclass| sti_condition = sti_condition.or(sti_column.eq(subclass.sti_name)) }
klass.descendants.each {|subclass| sti_condition = sti_condition.or(sti_column.eq(subclass.sti_name)) }
@join << sti_condition
end
......
......@@ -390,7 +390,11 @@ def load_target
begin
if !loaded?
if @target.is_a?(Array) && @target.any?
@target = find_target + @target.find_all {|t| t.new_record? }
@target = find_target.map do |f|
i = @target.index(f)
t = @target.delete_at(i) if i
(t && t.changed?) ? t : f
end + @target
else
@target = find_target
end
......
......@@ -2,6 +2,7 @@
require 'set'
require 'active_support/benchmarkable'
require 'active_support/dependencies'
require 'active_support/descendants_tracker'
require 'active_support/time'
require 'active_support/core_ext/class/attribute'
require 'active_support/core_ext/class/attribute_accessors'
......@@ -276,28 +277,6 @@ class Base
# on to any new database connections made and which can be retrieved on both a class and instance level by calling +logger+.
cattr_accessor :logger, :instance_writer => false
def self.inherited(child) #:nodoc:
@@subclasses[self] ||= []
@@subclasses[self] << child
super
end
def self.reset_subclasses #:nodoc:
nonreloadables = []
subclasses.each do |klass|
unless ActiveSupport::Dependencies.autoloaded? klass
nonreloadables << klass
next
end
klass.instance_variables.each { |var| klass.send(:remove_instance_variable, var) }
klass.instance_methods(false).each { |m| klass.send :undef_method, m }
end
@@subclasses = {}
nonreloadables.each { |klass| (@@subclasses[klass.superclass] ||= []) << klass }
end
@@subclasses = {}
##
# :singleton-method:
# Contains the database configuration - as is typically stored in config/database.yml -
......@@ -812,7 +791,7 @@ def reset_column_information
end
def reset_column_information_and_inheritable_attributes_for_all_subclasses#:nodoc:
subclasses.each { |klass| klass.reset_inheritable_attributes; klass.reset_column_information }
descendants.each { |klass| klass.reset_inheritable_attributes; klass.reset_column_information }
end
def attribute_method?(attribute)
......@@ -977,7 +956,7 @@ def construct_finder_arel(options = {}, scope = nil)
def type_condition
sti_column = arel_table[inheritance_column]
condition = sti_column.eq(sti_name)
subclasses.each{|subclass| condition = condition.or(sti_column.eq(subclass.sti_name)) }
descendants.each { |subclass| condition = condition.or(sti_column.eq(subclass.sti_name)) }
condition
end
......@@ -1167,14 +1146,6 @@ def with_exclusive_scope(method_scoping = {}, &block)
with_scope(method_scoping, :overwrite, &block)
end
# Returns a list of all subclasses of this class, meaning all descendants.
def subclasses
@@subclasses[self] ||= []
@@subclasses[self] + @@subclasses[self].inject([]) {|list, subclass| list + subclass.subclasses }
end
public :subclasses
# Sets the default options for the model. The format of the
# <tt>options</tt> argument is the same as in find.
#
......@@ -1902,6 +1873,7 @@ def object_from_yaml(string)
extend ActiveModel::Naming
extend QueryCache::ClassMethods
extend ActiveSupport::Benchmarkable
extend ActiveSupport::DescendantsTracker
include ActiveModel::Conversion
include Validations
......
......@@ -236,8 +236,7 @@ module Callbacks
included do
extend ActiveModel::Callbacks
define_callbacks :validation, :terminator => "result == false", :scope => [:kind, :name]
include ActiveModel::Validations::Callbacks
define_model_callbacks :initialize, :find, :only => :after
define_model_callbacks :save, :create, :update, :destroy
......@@ -251,29 +250,6 @@ def method_added(meth)
send(meth.to_sym, meth.to_sym)
end
end
def before_validation(*args, &block)
options = args.last
if options.is_a?(Hash) && options[:on]
options[:if] = Array.wrap(options[:if])
options[:if] << "@_on_validate == :#{options[:on]}"
end
set_callback(:validation, :before, *args, &block)
end
def after_validation(*args, &block)
options = args.extract_options!
options[:prepend] = true
options[:if] = Array.wrap(options[:if])
options[:if] << "!halted && value != false"
options[:if] << "@_on_validate == :#{options[:on]}" if options[:on]
set_callback(:validation, :after, *(args << options), &block)
end
end
def valid?(*) #:nodoc:
@_on_validate = new_record? ? :create : :update
_run_validation_callbacks { super }
end
def destroy #:nodoc:
......@@ -288,6 +264,7 @@ def deprecated_callback_method(symbol) #:nodoc:
end
private
def create_or_update #:nodoc:
_run_save_callbacks { super }
end
......
......@@ -304,7 +304,7 @@ def rollback_transaction_records(rollback) #:nodoc
begin
record.rolledback!(rollback)
rescue Exception => e
record.logger.error(e) if record.respond_to?(:logger)
record.logger.error(e) if record.respond_to?(:logger) && record.logger
end
end
end
......@@ -319,7 +319,7 @@ def commit_transaction_records #:nodoc
begin
record.committed!
rescue Exception => e
record.logger.error(e) if record.respond_to?(:logger)
record.logger.error(e) if record.respond_to?(:logger) && record.logger
end
end
end
......
......@@ -927,7 +927,12 @@ def configure_connection
# If using Active Record's time zone support configure the connection to return
# TIMESTAMP WITH ZONE types in UTC.
execute("SET time zone 'UTC'") if ActiveRecord::Base.default_timezone == :utc
if ActiveRecord::Base.default_timezone == :utc
execute("SET time zone 'UTC'")
else
offset = Time.local(2000).utc_offset / 3600
execute("SET time zone '#{offset}'")
end
end
# Returns the current ID of a table's sequence.
......
......@@ -107,8 +107,9 @@ def self.method_added(method)
end
protected
def observed_subclasses
observed_classes.sum([]) { |klass| klass.send(:subclasses) }
observed_classes.sum([]) { |klass| klass.send(:descendants) }
end
def observe_callbacks?
......
......@@ -69,7 +69,6 @@ class Railtie < Rails::Railtie
unless app.config.cache_classes
ActiveSupport.on_load(:active_record) do
ActionDispatch::Callbacks.after do
ActiveRecord::Base.reset_subclasses
ActiveRecord::Base.clear_reloadable_connections!
end
end
......
......@@ -116,45 +116,7 @@ def custom_join_sql(*joins)
def build_arel
arel = table
joined_associations = []
association_joins = []
joins = @joins_values.map {|j| j.respond_to?(:strip) ? j.strip : j}.uniq
joins.each do |join|
association_joins << join if [Hash, Array, Symbol].include?(join.class) && !array_of_strings?(join)
end
stashed_association_joins = joins.select {|j| j.is_a?(ActiveRecord::Associations::ClassMethods::JoinDependency::JoinAssociation)}
non_association_joins = (joins - association_joins - stashed_association_joins).reject {|j| j.blank?}
custom_joins = custom_join_sql(*non_association_joins)
join_dependency = ActiveRecord::Associations::ClassMethods::JoinDependency.new(@klass, association_joins, custom_joins)
join_dependency.graft(*stashed_association_joins)
@implicit_readonly = true unless association_joins.empty? && stashed_association_joins.empty?
to_join = []
join_dependency.join_associations.each do |association|
if (association_relation = association.relation).is_a?(Array)
to_join << [association_relation.first, association.join_class, association.association_join.first]
to_join << [association_relation.last, association.join_class, association.association_join.last]
else
to_join << [association_relation, association.join_class, association.association_join]
end
end
to_join.each do |tj|
unless joined_associations.detect {|ja| ja[0] == tj[0] && ja[1] == tj[1] && ja[2] == tj[2] }
joined_associations << tj
arel = arel.join(tj[0], tj[1]).on(*tj[2])
end
end
arel = arel.join(custom_joins)
arel = build_joins(arel, @joins_values) if @joins_values.present?
@where_values.uniq.each do |where|
next if where.blank?
......@@ -168,9 +130,7 @@ def build_arel
end
end
@having_values.uniq.each do |h|
arel = h.is_a?(String) ? arel.having(h) : arel.having(*h)
end
arel = arel.having(*@having_values.uniq.select{|h| h.present?})
arel = arel.take(@limit_value) if @limit_value.present?
arel = arel.skip(@offset_value) if @offset_value.present?
......@@ -181,18 +141,16 @@ def build_arel
selects = @select_values.uniq
quoted_table_name = @klass.quoted_table_name
if selects.present?
selects.each do |s|
@implicit_readonly = false
arel = arel.project(s) if s.present?
end
else
arel = arel.project(quoted_table_name + '.*')
arel = arel.project(@klass.quoted_table_name + '.*')
end
arel = @from_value.present? ? arel.from(@from_value) : arel.from(quoted_table_name)
arel = @from_value.present? ? arel.from(@from_value) : arel.from(@klass.quoted_table_name)
case @lock_value
when TrueClass
......@@ -221,6 +179,48 @@ def build_where(*args)
private
def build_joins(relation, joins)
joined_associations = []
association_joins = []
joins = @joins_values.map {|j| j.respond_to?(:strip) ? j.strip : j}.uniq
joins.each do |join|
association_joins << join if [Hash, Array, Symbol].include?(join.class) && !array_of_strings?(join)
end
stashed_association_joins = joins.select {|j| j.is_a?(ActiveRecord::Associations::ClassMethods::JoinDependency::JoinAssociation)}
non_association_joins = (joins - association_joins - stashed_association_joins).reject {|j| j.blank?}
custom_joins = custom_join_sql(*non_association_joins)
join_dependency = ActiveRecord::Associations::ClassMethods::JoinDependency.new(@klass, association_joins, custom_joins)
join_dependency.graft(*stashed_association_joins)
@implicit_readonly = true unless association_joins.empty? && stashed_association_joins.empty?
to_join = []
join_dependency.join_associations.each do |association|
if (association_relation = association.relation).is_a?(Array)
to_join << [association_relation.first, association.join_class, association.association_join.first]
to_join << [association_relation.last, association.join_class, association.association_join.last]
else
to_join << [association_relation, association.join_class, association.association_join]
end
end
to_join.each do |tj|
unless joined_associations.detect {|ja| ja[0] == tj[0] && ja[1] == tj[1] && ja[2] == tj[2] }
joined_associations << tj
relation = relation.join(tj[0], tj[1]).on(*tj[2])
end
end
relation.join(custom_joins)
end
def apply_modules(modules)
values = Array.wrap(modules)
@extensions += values if values.present?
......
......@@ -322,6 +322,7 @@ def restore_transaction_record_state(force = false) #:nodoc
if @_start_transaction_state[:level] < 1
restore_state = remove_instance_variable(:@_start_transaction_state)
if restore_state
@attributes = @attributes.dup if @attributes.frozen?
@new_record = restore_state[:new_record]
@destroyed = restore_state[:destroyed]
if restore_state[:id]
......
......@@ -52,12 +52,12 @@ def save!(options={})
# Runs all the specified validations and returns true if no errors were added otherwise false.
def valid?(context = nil)
context ||= (new_record? ? :create : :update)
super(context)
output = super(context)
deprecated_callback_method(:validate)
deprecated_callback_method(:"validate_on_#{context}")
errors.empty?
errors.empty? && output
end
protected
......
class <%= migration_class_name %> < ActiveRecord::Migration
def self.up<% attributes.each do |attribute| %>
<%= migration_action %>_column :<%= table_name %>, :<%= attribute.name %><% if migration_action == 'add' %>, :<%= attribute.type %><% end -%>
<%- end %>
<%- if migration_action -%>
<%= migration_action %>_column :<%= table_name %>, :<%= attribute.name %><% if migration_action == 'add' %>, :<%= attribute.type %><% end %>
<%- end -%>
<%- end -%>
end
def self.down<% attributes.reverse.each do |attribute| %>
<%= migration_action == 'add' ? 'remove' : 'add' %>_column :<%= table_name %>, :<%= attribute.name %><% if migration_action == 'remove' %>, :<%= attribute.type %><% end -%>
<%- end %>
<%- if migration_action -%>
<%= migration_action == 'add' ? 'remove' : 'add' %>_column :<%= table_name %>, :<%= attribute.name %><% if migration_action == 'remove' %>, :<%= attribute.type %><% end %>
<%- end -%>
<%- end -%>
end
end
......@@ -65,15 +65,14 @@ def test_show_nonexistent_variable_returns_nil
end
def test_not_specifying_database_name_for_cross_database_selects
assert_nothing_raised do
ActiveRecord::Base.establish_connection({
:adapter => 'mysql',
:username => 'rails'
})
ActiveRecord::Base.connection.execute "SELECT activerecord_unittest.pirates.*, activerecord_unittest2.courses.* FROM activerecord_unittest.pirates, activerecord_unittest2.courses"
begin
assert_nothing_raised do
ActiveRecord::Base.establish_connection(ActiveRecord::Base.configurations['arunit'].except(:database))
ActiveRecord::Base.connection.execute "SELECT activerecord_unittest.pirates.*, activerecord_unittest2.courses.* FROM activerecord_unittest.pirates, activerecord_unittest2.courses"
end
ensure
ActiveRecord::Base.establish_connection 'arunit'
end
ActiveRecord::Base.establish_connection 'arunit'
end
end
......
......@@ -712,7 +712,6 @@ def destroy(*args)
end
assert_raise(RuntimeError) { assert !@pirate.save }
assert before.first.frozen? # the first child was indeed destroyed
assert_equal before, @pirate.reload.send(association_name)
end
......
......@@ -2076,10 +2076,6 @@ def test_descends_from_active_record
assert !SubStiPost.descends_from_active_record?
end
def test_base_subclasses_is_public_method
assert ActiveRecord::Base.public_methods.map(&:to_sym).include?(:subclasses)
end
def test_find_on_abstract_base_class_doesnt_use_type_condition
old_class = LooseDescendant
Object.send :remove_const, :LooseDescendant
......
文件模式从 100755 更改为 100644
......@@ -1032,7 +1032,7 @@ def test_add_table_with_decimals
elsif current_adapter?(:SQLiteAdapter)
# - SQLite3 stores a float, in violation of SQL
assert_kind_of BigDecimal, b.value_of_e
assert_equal BigDecimal("2.71828182845905"), b.value_of_e
assert_in_delta BigDecimal("2.71828182845905"), b.value_of_e, 0.00000000000001
else
# - SQL standard is an integer
assert_kind_of Fixnum, b.value_of_e
......
......@@ -466,6 +466,27 @@ def test_should_not_load_association_when_updating_existing_records
assert_equal 'Grace OMalley', @child_1.reload.name
end
def test_should_not_overwrite_unsaved_updates_when_loading_association
@pirate.reload
@pirate.send(association_setter, [{ :id => @child_1.id, :name => 'Grace OMalley' }])
assert_equal 'Grace OMalley', @pirate.send(@association_name).send(:load_target).find { |r| r.id == @child_1.id }.name
end
def test_should_preserve_order_when_not_overwriting_unsaved_updates
@pirate.reload
@pirate.send(association_setter, [{ :id => @child_1.id, :name => 'Grace OMalley' }])
assert_equal @child_1.id, @pirate.send(@association_name).send(:load_target).first.id
end
def test_should_refresh_saved_records_when_not_overwriting_unsaved_updates
@pirate.reload
record = @pirate.class.reflect_on_association(@association_name).klass.new(:name => 'Grace OMalley')
@pirate.send(@association_name) << record
record.save!
@pirate.send(@association_name).last.update_attributes!(:name => 'Polly')
assert_equal 'Polly', @pirate.send(@association_name).send(:load_target).last.name
end
def test_should_take_a_hash_with_composite_id_keys_and_assign_the_attributes_to_the_associated_models
@child_1.stubs(:id).returns('ABC1X')
@child_2.stubs(:id).returns('ABC2X')
......
......@@ -221,20 +221,28 @@ def @first.commits(i=0); @commits ||= 0; @commits += i if i; end
assert_equal 2, @first.rollbacks
end
def test_after_transaction_callbacks_should_not_raise_errors
def test_after_transaction_callbacks_should_prevent_callbacks_from_being_called
def @first.last_after_transaction_error=(e); @last_transaction_error = e; end
def @first.last_after_transaction_error; @last_transaction_error; end
@first.after_commit_block{|r| r.last_after_transaction_error = :commit; raise "fail!";}
@first.after_rollback_block{|r| r.last_after_transaction_error = :rollback; raise "fail!";}
@second.after_commit_block{|r| r.history << :after_commit}
@second.after_rollback_block{|r| r.history << :after_rollback}
@first.save!
Topic.transaction do
@first.save!
@second.save!
end
assert_equal :commit, @first.last_after_transaction_error
assert_equal [:after_commit], @second.history
@second.history.clear
Topic.transaction do
@first.save!
@second.save!
raise ActiveRecord::Rollback
end
assert_equal :rollback, @first.last_after_transaction_error
assert_equal [:after_rollback], @second.history
end
end
class Pirate < ActiveRecord::Base
belongs_to :parrot, :validate => true
belongs_to :non_validated_parrot, :class_name => 'Parrot'
has_and_belongs_to_many :parrots, :validate => true
has_and_belongs_to_many :parrots, :validate => true, :order => 'parrots.id ASC'
has_and_belongs_to_many :non_validated_parrots, :class_name => 'Parrot'
has_and_belongs_to_many :parrots_with_method_callbacks, :class_name => "Parrot",
:before_add => :log_before_add,
......@@ -21,7 +21,7 @@ class Pirate < ActiveRecord::Base
has_one :ship
has_one :update_only_ship, :class_name => 'Ship'
has_one :non_validated_ship, :class_name => 'Ship'
has_many :birds
has_many :birds, :order => 'birds.id ASC'
has_many :birds_with_method_callbacks, :class_name => "Bird",
:before_add => :log_before_add,
:after_add => :log_after_add,
......
require 'rubygems'
gem 'rdoc', '= 2.2'
require 'rdoc'
require 'rake'
require 'rake/testtask'
require 'rake/rdoctask'
......@@ -83,5 +84,5 @@ end
desc "Publish the API documentation"
task :pdoc => [:rdoc] do
require 'rake/contrib/sshpublisher'
Rake::SshDirPublisher.new("wrath.rubyonrails.org", "public_html/ar", "doc").upload
Rake::SshDirPublisher.new("rails@api.rubyonrails.org", "public_html/ar", "doc").upload
end
*Rails 3.0.0 [Release Candidate] (unreleased)*
* Added ActiveSupport::FileUpdateChecker to execute a block only if a set of files changed, used by Router and I18n locale files. [José Valim]
* Added ActiveSupport::DescendantsTracker to track descendants with support to constants reloading. [José Valim]
* ActiveSupport::OrderedHash#merge and #merge! accept a block. #4838 [Paul Mucur, fxn]
* Date#since, #ago, #beginning_of_day, #end_of_day, and #xmlschema honor now the user time zone if set. [Geoff Buesing]
......
gem 'rdoc', '= 2.2'
require 'rdoc'
require 'rake/testtask'
require 'rake/rdoctask'
require 'rake/gempackagetask'
......@@ -47,5 +49,5 @@ end
desc "Publish the API documentation"
task :pdoc => [:rdoc] do
require 'rake/contrib/sshpublisher'
Rake::SshDirPublisher.new("wrath.rubyonrails.org", "public_html/as", "doc").upload
Rake::SshDirPublisher.new("rails@api.rubyonrails.org", "public_html/as", "doc").upload
end
文件模式从 100755 更改为 100644
......@@ -39,6 +39,9 @@ def load_all!; load_all_hooks.each { |hook| hook.call } end
module ActiveSupport
extend ActiveSupport::Autoload
autoload :DescendantsTracker
autoload :FileUpdateChecker
# TODO: Narrow this list down
eager_autoload do
autoload :BacktraceCleaner
......
require 'active_support/descendants_tracker'
require 'active_support/core_ext/array/wrap'
require 'active_support/core_ext/class/inheritable_attributes'
require 'active_support/core_ext/class/subclasses'
require 'active_support/core_ext/kernel/reporting'
require 'active_support/core_ext/kernel/singleton_class'
......@@ -85,6 +85,10 @@ module ActiveSupport
module Callbacks
extend Concern
included do
extend ActiveSupport::DescendantsTracker
end
def run_callbacks(kind, *args, &block)
send("_run_#{kind}_callbacks", *args, &block)
end
......@@ -428,7 +432,7 @@ def __update_callbacks(name, filters = [], block = nil) #:nodoc:
options = filters.last.is_a?(Hash) ? filters.pop : {}
filters.unshift(block) if block
([self] + self.descendents).each do |target|
([self] + self.descendants).each do |target|
chain = target.send("_#{name}_callbacks")
yield chain, type, filters, options
target.__define_runner(name)
......@@ -502,7 +506,7 @@ def skip_callback(name, *filter_list, &block)
def reset_callbacks(symbol)
callbacks = send("_#{symbol}_callbacks")
self.descendents.each do |target|
self.descendants.each do |target|
chain = target.send("_#{symbol}_callbacks")
callbacks.each { |c| chain.delete(c) }
target.__define_runner(symbol)
......
......@@ -11,9 +11,9 @@ def subclasses
# Rubinius
if defined?(Class.__subclasses__)
def descendents
def descendants
subclasses = []
__subclasses__.each {|k| subclasses << k; subclasses.concat k.descendents }
__subclasses__.each {|k| subclasses << k; subclasses.concat k.descendants }
subclasses
end
else
......@@ -21,7 +21,7 @@ def descendents
begin
ObjectSpace.each_object(Class.new) {}
def descendents
def descendants
subclasses = []
ObjectSpace.each_object(class << self; self; end) do |k|
subclasses << k unless k == self
......@@ -30,7 +30,7 @@ def descendents
end
# JRuby
rescue StandardError
def descendents
def descendants
subclasses = []
ObjectSpace.each_object(Class) do |k|
subclasses << k if k < self
......@@ -48,7 +48,7 @@ def descendents
def self.subclasses_of(*superclasses) #:nodoc:
subclasses = []
superclasses.each do |klass|
subclasses.concat klass.descendents.select {|k| k.anonymous? || k.reachable?}
subclasses.concat klass.descendants.select {|k| k.anonymous? || k.reachable?}
end
subclasses
end
......
......@@ -12,6 +12,8 @@ class DateTime
#
# DateTime.new(2000).in_time_zone('Alaska') # => Fri, 31 Dec 1999 15:00:00 AKST -09:00
def in_time_zone(zone = ::Time.zone)
return self unless zone
ActiveSupport::TimeWithZone.new(utc? ? self : getutc, ::Time.__send__(:get_zone, zone))
end
end
文件模式从 100755 更改为 100644
......@@ -73,6 +73,8 @@ def get_zone(time_zone)
#
# Time.utc(2000).in_time_zone('Alaska') # => Fri, 31 Dec 1999 15:00:00 AKST -09:00
def in_time_zone(zone = ::Time.zone)
return self unless zone
ActiveSupport::TimeWithZone.new(utc? ? self : getutc, ::Time.__send__(:get_zone, zone))
end
end
require 'active_support/dependencies'
module ActiveSupport
# This module provides an internal implementation to track descendants
# which is faster than iterating through ObjectSpace.
module DescendantsTracker
@@descendants = Hash.new { |h, k| h[k] = [] }
def self.descendants
@@descendants
end
def self.clear
@@descendants.each do |klass, descendants|
if ActiveSupport::Dependencies.autoloaded?(klass)
@@descendants.delete(klass)
else
descendants.reject! { |v| ActiveSupport::Dependencies.autoloaded?(v) }
end
end
end
def inherited(base)
self.direct_descendants << base
super
end
def direct_descendants
@@descendants[self]
end
def descendants
@@descendants[self].inject([]) do |descendants, klass|
descendants << klass
descendants.concat klass.descendants
end
end
end
end
\ No newline at end of file
module ActiveSupport
# This class is responsible to track files and invoke the given block
# whenever one of these files are changed. For example, this class
# is used by Rails to reload routes whenever they are changed upon
# a new request.
#
# routes_reloader = ActiveSupport::FileUpdateChecker.new(paths) do
# paths.each { |p| load(p) }
# Rails::Application.routes.reload!
# end
#
# ActionDispatch::Callbacks.to_prepare do
# routes_reloader.execute_if_updated
# end
#
class FileUpdateChecker
attr_reader :paths, :last_update_at
def initialize(paths, calculate=false, &block)
@paths = paths
@block = block
@last_update_at = updated_at if calculate
end
def updated_at
paths.map { |path| File.stat(path).mtime }.max
end
def execute_if_updated
current_update_at = self.updated_at
if @last_update_at != current_update_at
@last_update_at = current_update_at
@block.call
end
end
end
end
\ No newline at end of file
......@@ -4,5 +4,6 @@
$stderr.puts "You don't have i18n installed in your application. Please add it to your Gemfile and run bundle install"
raise e
end
I18n.load_path << "#{File.dirname(__FILE__)}/locale/en.yml"
ActiveSupport.run_load_hooks(:i18n)
require "active_support"
require "rails"
require "active_support/file_update_checker"
module I18n
class Railtie < Rails::Railtie
config.i18n = ActiveSupport::OrderedOptions.new
config.i18n.railties_load_path = []
config.i18n.load_path = []
config.i18n.fallbacks = ActiveSupport::OrderedOptions.new
def self.reloader
@reloader ||= ActiveSupport::FileUpdateChecker.new([]){ I18n.reload! }
end
# Add I18n::Railtie.reloader to ActionDispatch callbacks. Since, at this
# point, no path was added to the reloader, I18n.reload! is not triggered
# on to_prepare callbacks. This will only happen on the config.after_initialize
# callback below.
initializer "i18n.callbacks" do
ActionDispatch::Callbacks.to_prepare do
I18n::Railtie.reloader.execute_if_updated
end
end
# Set the i18n configuration only after initialization since a lot of
# configuration is still usually done in application initializers.
config.after_initialize do |app|
fallbacks = app.config.i18n.delete(:fallbacks)
app.config.i18n.each do |setting, value|
case setting
when :railties_load_path
app.config.i18n.load_path.unshift(*value)
when :load_path
I18n.load_path += value
else
I18n.send("#{setting}=", value)
end
end
init_fallbacks(fallbacks) if fallbacks && validate_fallbacks(fallbacks)
reloader.paths.concat I18n.load_path
reloader.execute_if_updated
end
protected
def self.include_fallbacks_module
I18n.backend.class.send(:include, I18n::Backend::Fallbacks)
end
def self.init_fallbacks(fallbacks)
include_fallbacks_module
args = case fallbacks
when ActiveSupport::OrderedOptions
[*(fallbacks[:defaults] || []) << fallbacks[:map]].compact
when Hash, Array
Array.wrap(fallbacks)
else # TrueClass
[]
end
I18n.fallbacks = I18n::Locale::Fallbacks.new(*args)
end
def self.validate_fallbacks(fallbacks)
case fallbacks
when ActiveSupport::OrderedOptions
!fallbacks.empty?
when TrueClass, Array, Hash
true
else
raise "Unexpected fallback type #{fallbacks.inspect}"
end
end
end
end
\ No newline at end of file
require 'yajl-ruby' unless defined?(Yajl)
require 'yajl' unless defined?(Yajl)
module ActiveSupport
module JSON
......
......@@ -50,10 +50,6 @@ def initialize(string) #:nodoc:
end
end
def <=>(other)
@wrapped_string <=> other
end
# Forward all undefined methods to the wrapped string.
def method_missing(method, *args, &block)
if method.to_s =~ /!$/
......@@ -87,6 +83,16 @@ def self.consumes?(string)
include Comparable
# Returns <tt>-1</tt>, <tt>0</tt> or <tt>+1</tt> depending on whether the Chars object is to be sorted before,
# equal or after the object on the right side of the operation. It accepts any object that implements +to_s+.
# See <tt>String#<=></tt> for more details.
#
# Example:
# 'é'.mb_chars <=> 'ü'.mb_chars #=> -1
def <=>(other)
@wrapped_string <=> other.to_s
end
if RUBY_VERSION < "1.9"
# Returns +true+ if the Chars class can and should act as a proxy for the string _string_. Returns
# +false+ otherwise.
......@@ -94,16 +100,6 @@ def self.wants?(string)
$KCODE == 'UTF8' && consumes?(string)
end
# Returns <tt>-1</tt>, <tt>0</tt> or <tt>+1</tt> depending on whether the Chars object is to be sorted before,
# equal or after the object on the right side of the operation. It accepts any object that implements +to_s+.
# See <tt>String#<=></tt> for more details.
#
# Example:
# 'é'.mb_chars <=> 'ü'.mb_chars #=> -1
def <=>(other)
@wrapped_string <=> other.to_s
end
# Returns a new Chars object containing the _other_ object concatenated to the string.
#
# Example:
......@@ -375,6 +371,16 @@ def capitalize
(slice(0) || chars('')).upcase + (slice(1..-1) || chars('')).downcase
end
# Capitalizes the first letter of every word, when possible.
#
# Example:
# "ÉL QUE SE ENTERÓ".mb_chars.titleize # => "Él Que Se Enteró"
# "日本語".mb_chars.titleize # => "日本語"
def titleize
chars(downcase.to_s.gsub(/\b('?[\S])/u) { Unicode.apply_mapping $1, :uppercase_mapping })
end
alias_method :titlecase, :titleize
# Returns the KC normalization of the string by default. NFKC is considered the best normalization form for
# passing strings to databases and validations.
#
......
require "active_support"
require "rails"
require "active_support/i18n_railtie"
module ActiveSupport
class Railtie < Rails::Railtie
......@@ -26,75 +27,4 @@ class Railtie < Rails::Railtie
Time.zone_default = zone_default
end
end
end
module I18n
class Railtie < Rails::Railtie
config.i18n = ActiveSupport::OrderedOptions.new
config.i18n.railties_load_path = []
config.i18n.load_path = []
config.i18n.fallbacks = ActiveSupport::OrderedOptions.new
initializer "i18n.initialize" do
ActiveSupport.on_load(:i18n) do
I18n.reload!
ActionDispatch::Callbacks.to_prepare do
I18n.reload!
end
end
end
# Set the i18n configuration from config.i18n but special-case for
# the load_path which should be appended to what's already set instead of overwritten.
config.after_initialize do |app|
fallbacks = app.config.i18n.delete(:fallbacks)
app.config.i18n.each do |setting, value|
case setting
when :railties_load_path
app.config.i18n.load_path.unshift(*value)
when :load_path
I18n.load_path += value
else
I18n.send("#{setting}=", value)
end
end
init_fallbacks(fallbacks) if fallbacks && validate_fallbacks(fallbacks)
I18n.reload!
end
class << self
protected
def init_fallbacks(fallbacks)
include_fallbacks_module
args = case fallbacks
when ActiveSupport::OrderedOptions
[*(fallbacks[:defaults] || []) << fallbacks[:map]].compact
when Hash, Array
Array.wrap(fallbacks)
else # TrueClass
[]
end
I18n.fallbacks = I18n::Locale::Fallbacks.new(*args)
end
def include_fallbacks_module
I18n.backend.class.send(:include, I18n::Backend::Fallbacks)
end
def validate_fallbacks(fallbacks)
case fallbacks
when ActiveSupport::OrderedOptions
!fallbacks.empty?
when TrueClass, Array, Hash
true
else
raise "Unexpected fallback type #{fallbacks.inspect}"
end
end
end
end
end
\ No newline at end of file
......@@ -260,14 +260,8 @@ def profile
end
protected
if GC.respond_to?(:enable_stats)
def with_gc_stats
GC.enable_stats
yield
ensure
GC.disable_stats
end
elsif defined?(GC::Profiler)
# Ruby 1.9 + extented GC profiler patch
if defined?(GC::Profiler) and GC::Profiler.respond_to?(:data)
def with_gc_stats
GC.start
GC.disable
......@@ -277,6 +271,16 @@ def with_gc_stats
GC::Profiler.disable
GC.enable
end
# Ruby 1.8 + ruby-prof wrapper (enable/disable stats for Benchmarker)
elsif GC.respond_to?(:enable_stats)
def with_gc_stats
GC.enable_stats
yield
ensure
GC.disable_stats
end
else
def with_gc_stats
yield
......@@ -319,7 +323,7 @@ class CpuTime < Time
def initialize(*args)
# FIXME: yeah my CPU is 2.33 GHz
RubyProf.cpu_frequency = 2.33e9
RubyProf.cpu_frequency = 2.33e9 unless RubyProf.cpu_frequency > 0
super
end
......@@ -331,38 +335,8 @@ def measure
class Memory < Base
Mode = RubyProf::MEMORY if RubyProf.const_defined?(:MEMORY)
# ruby-prof wrapper
if RubyProf.respond_to?(:measure_memory)
def measure
RubyProf.measure_memory / 1024.0
end
# Ruby 1.8 + railsbench patch
elsif GC.respond_to?(:allocated_size)
def measure
GC.allocated_size / 1024.0
end
# Ruby 1.8 + lloyd patch
elsif GC.respond_to?(:heap_info)
def measure
GC.heap_info['heap_current_memory'] / 1024.0
end
# Ruby 1.9 with total_malloc_allocated_size patch
elsif GC.respond_to?(:malloc_total_allocated_size)
def measure
GC.total_malloc_allocated_size / 1024.0
end
# Ruby 1.9 unpatched
elsif GC.respond_to?(:malloc_allocated_size)
def measure
GC.malloc_allocated_size / 1024.0
end
# Ruby 1.9 + GC profiler patch
elsif defined?(GC::Profiler)
# Ruby 1.9 + extended GC profiler patch
if defined?(GC::Profiler) and GC::Profiler.respond_to?(:data)
def measure
GC.enable
GC.start
......@@ -370,6 +344,12 @@ def measure
GC.disable
kb
end
# Ruby 1.8 + ruby-prof wrapper
elsif RubyProf.respond_to?(:measure_memory)
def measure
RubyProf.measure_memory / 1024.0
end
end
def format(measurement)
......@@ -380,27 +360,21 @@ def format(measurement)
class Objects < Base
Mode = RubyProf::ALLOCATIONS if RubyProf.const_defined?(:ALLOCATIONS)
if RubyProf.respond_to?(:measure_allocations)
def measure
RubyProf.measure_allocations
end
# Ruby 1.8 + railsbench patch
elsif ObjectSpace.respond_to?(:allocated_objects)
def measure
ObjectSpace.allocated_objects
end
# Ruby 1.9 + GC profiler patch
elsif defined?(GC::Profiler)
# Ruby 1.9 + extented GC profiler patch
if defined?(GC::Profiler) and GC::Profiler.respond_to?(:data)
def measure
GC.enable
GC.start
last = GC::Profiler.data.last
count = last[:HEAP_LIVE_OBJECTS] + last[:HEAP_FREE_OBJECTS]
count = GC::Profiler.data.last[:HEAP_TOTAL_OBJECTS]
GC.disable
count
end
# Ruby 1.8 + ruby-prof wrapper
elsif RubyProf.respond_to?(:measure_allocations)
def measure
RubyProf.measure_allocations
end
end
def format(measurement)
......@@ -411,17 +385,20 @@ def format(measurement)
class GcRuns < Base
Mode = RubyProf::GC_RUNS if RubyProf.const_defined?(:GC_RUNS)
if RubyProf.respond_to?(:measure_gc_runs)
# Ruby 1.9 + extented GC profiler patch
if defined?(GC::Profiler) and GC::Profiler.respond_to?(:data)
def measure
RubyProf.measure_gc_runs
end
elsif GC.respond_to?(:collections)
def measure
GC.collections
GC.enable
GC.start
count = GC::Profiler.data.last[:GC_RUNS]
GC.disable
count
end
elsif GC.respond_to?(:heap_info)
# Ruby 1.8 + ruby-prof wrapper
elsif RubyProf.respond_to?(:measure_gc_runs)
def measure
GC.heap_info['num_gc_passes']
RubyProf.measure_gc_runs
end
end
......@@ -433,13 +410,20 @@ def format(measurement)
class GcTime < Base
Mode = RubyProf::GC_TIME if RubyProf.const_defined?(:GC_TIME)
if RubyProf.respond_to?(:measure_gc_time)
# Ruby 1.9 + extented GC profiler patch
if defined?(GC::Profiler) and GC::Profiler.respond_to?(:data)
def measure
RubyProf.measure_gc_time
GC.enable
GC.start
sec = GC::Profiler.data.inject(0) { |total, run| total += run[:GC_TIME] }
GC.disable
sec
end
elsif GC.respond_to?(:time)
# Ruby 1.8 + ruby-prof wrapper
elsif RubyProf.respond_to?(:measure_gc_time)
def measure
GC.time
RubyProf.measure_gc_time
end
end
......@@ -452,4 +436,4 @@ def format(measurement)
end
end
rescue LoadError
end
\ No newline at end of file
end
......@@ -737,6 +737,13 @@ def test_in_time_zone
end
end
def test_nil_time_zone
Time.use_zone nil do
assert !@t.in_time_zone.respond_to?(:period), 'no period method'
assert !@dt.in_time_zone.respond_to?(:period), 'no period method'
end
end
def test_in_time_zone_with_argument
Time.use_zone 'Eastern Time (US & Canada)' do # Time.zone will not affect #in_time_zone(zone)
assert_equal 'Fri, 31 Dec 1999 15:00:00 AKST -09:00', @t.in_time_zone('Alaska').inspect
......
require 'abstract_unit'
require 'test/unit'
require 'active_support'
require 'active_support/core_ext/hash/slice'
class DescendantsTrackerTest < Test::Unit::TestCase
class Parent
extend ActiveSupport::DescendantsTracker
end
class Child1 < Parent
end
class Child2 < Parent
end
class Grandchild1 < Child1
end
class Grandchild2 < Child1
end
ALL = [Parent, Child1, Child2, Grandchild1, Grandchild2]
def test_descendants
assert_equal [Child1, Grandchild1, Grandchild2, Child2], Parent.descendants
assert_equal [Grandchild1, Grandchild2], Child1.descendants
assert_equal [], Child2.descendants
end
def test_direct_descendants
assert_equal [Child1, Child2], Parent.direct_descendants
assert_equal [Grandchild1, Grandchild2], Child1.direct_descendants
assert_equal [], Child2.direct_descendants
end
def test_clear_with_autoloaded_parent_children_and_granchildren
mark_as_autoloaded *ALL do
ActiveSupport::DescendantsTracker.clear
assert ActiveSupport::DescendantsTracker.descendants.slice(*ALL).empty?
end
end
def test_clear_with_autoloaded_children_and_granchildren
mark_as_autoloaded Child1, Grandchild1, Grandchild2 do
ActiveSupport::DescendantsTracker.clear
assert_equal [Child2], Parent.descendants
assert_equal [], Child2.descendants
end
end
def test_clear_with_autoloaded_granchildren
mark_as_autoloaded Grandchild1, Grandchild2 do
ActiveSupport::DescendantsTracker.clear
assert_equal [Child1, Child2], Parent.descendants
assert_equal [], Child1.descendants
assert_equal [], Child2.descendants
end
end
protected
def mark_as_autoloaded(*klasses)
old_autoloaded = ActiveSupport::Dependencies.autoloaded_constants.dup
ActiveSupport::Dependencies.autoloaded_constants = klasses.map(&:name)
old_descendants = ActiveSupport::DescendantsTracker.descendants.dup
old_descendants.each { |k, v| old_descendants[k] = v.dup }
yield
ensure
ActiveSupport::Dependencies.autoloaded_constants = old_autoloaded
ActiveSupport::DescendantsTracker.descendants.replace(old_descendants)
end
end
\ No newline at end of file
require 'abstract_unit'
require 'test/unit'
require 'active_support'
require 'fileutils'
MTIME_FIXTURES_PATH = File.expand_path("../fixtures", __FILE__)
class FileUpdateCheckerTest < Test::Unit::TestCase
FILES = %w(1.txt 2.txt 3.txt)
def setup
FileUtils.touch(FILES)
end
def teardown
FileUtils.rm(FILES)
end
def test_should_not_execute_the_block_if_no_paths_are_given
i = 0
checker = ActiveSupport::FileUpdateChecker.new([]){ i += 1 }
checker.execute_if_updated
assert_equal 0, i
end
def test_should_invoke_the_block_on_first_call_if_it_does_not_calculate_last_updated_at_on_load
i = 0
checker = ActiveSupport::FileUpdateChecker.new(FILES){ i += 1 }
checker.execute_if_updated
assert_equal 1, i
end
def test_should_not_invoke_the_block_on_first_call_if_it_calculates_last_updated_at_on_load
i = 0
checker = ActiveSupport::FileUpdateChecker.new(FILES, true){ i += 1 }
checker.execute_if_updated
assert_equal 0, i
end
def test_should_not_invoke_the_block_if_no_file_has_changed
i = 0
checker = ActiveSupport::FileUpdateChecker.new(FILES){ i += 1 }
5.times { checker.execute_if_updated }
assert_equal 1, i
end
def test_should_invoke_the_block_if_a_file_has_changed
i = 0
checker = ActiveSupport::FileUpdateChecker.new(FILES){ i += 1 }
checker.execute_if_updated
sleep(1)
FileUtils.touch(FILES)
checker.execute_if_updated
assert_equal 2, i
end
end
......@@ -443,6 +443,11 @@ def test_capitalize_should_work_on_ascii_characters
assert_equal 'Abc', 'abc'.mb_chars.capitalize
end
def test_titleize_should_work_on_ascii_characters
assert_equal '', ''.mb_chars.titleize
assert_equal 'Abc Abc', 'abc abc'.mb_chars.titleize
end
def test_respond_to_knows_which_methods_the_proxy_responds_to
assert ''.mb_chars.respond_to?(:slice) # Defined on Chars
assert ''.mb_chars.respond_to?(:capitalize!) # Defined on Chars
......@@ -480,6 +485,15 @@ def test_capitalize_should_be_unicode_aware
end
end
def test_titleize_should_be_unicode_aware
assert_equal "Él Que Se Enteró", chars("ÉL QUE SE ENTERÓ").titleize
assert_equal "Абвг Абвг", chars("аБвг аБвг").titleize
end
def test_titleize_should_not_affect_characters_that_do_not_case_fold
assert_equal "日本語", chars("日本語").titleize
end
def test_limit_should_not_break_on_blank_strings
example = chars('')
assert_equal example, example.limit(0)
......
#!/usr/bin/env ruby
begin
require "rails/cli"
rescue LoadError
......
......@@ -11,8 +11,12 @@
end
end
require 'rdoc/generator/html'
module RDoc
module Page
module Generator
class HTML
class HORO
FONTS = "\"Bitstream Vera Sans\", Verdana, Arial, Helvetica, sans-serif"
......@@ -28,7 +32,7 @@ module Page
}
body, td, p {
font-family: %fonts%;
font-family: <%= values['fonts'] %>;
background: #FFF;
color: #000;
margin: 0px;
......@@ -206,7 +210,7 @@ module Page
}
CSS
XHTML_PREAMBLE = %{<?xml version="1.0" encoding="%charset%"?>
XHTML_PREAMBLE = %{<?xml version="1.0" encoding="<%= values['charset'] %>"?>
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
......@@ -221,9 +225,9 @@ module Page
HEADER = XHTML_PREAMBLE + <<ENDHEADER
<html>
<head>
<title>%title%</title>
<meta http-equiv="Content-Type" content="text/html; charset=%charset%" />
<link rel="stylesheet" href="%style_url%" type="text/css" media="screen" />
<title><%= values['title'] %></title>
<meta http-equiv="Content-Type" content="text/html; charset=<%= values['charset'] %>" />
<link rel="stylesheet" href="<%= values['style_url'] %>" type="text/css" media="screen" />
<script language="JavaScript" type="text/javascript">
// <![CDATA[
......@@ -273,20 +277,20 @@ module Page
<table border='0' cellpadding='0' cellspacing='0' width="100%" class='banner'>
<tr><td>
<table width="100%" border='0' cellpadding='0' cellspacing='0'><tr>
<td class="file-title" colspan="2"><span class="file-title-prefix">File</span><br />%short_name%</td>
<td class="file-title" colspan="2"><span class="file-title-prefix">File</span><br /><%= values['short_name'] %></td>
<td align="right">
<table border='0' cellspacing="0" cellpadding="2">
<tr>
<td>Path:</td>
<td>%full_path%
IF:cvsurl
&nbsp;(<a href="%cvsurl%">CVS</a>)
ENDIF:cvsurl
<td><%= values['full_path'] %>
<% if values['cvsurl'] %>
&nbsp;(<a href="<%= values['cvsurl'] %>">CVS</a>)
<% end %>
</td>
</tr>
<tr>
<td>Modified:</td>
<td>%dtm_modified%</td>
<td><%= values['dtm_modified'] %></td>
</tr>
</table>
</td></tr>
......@@ -299,34 +303,34 @@ module Page
CLASS_PAGE = <<HTML
<table width="100%" border='0' cellpadding='0' cellspacing='0' class='banner'><tr>
<td class="file-title"><span class="file-title-prefix">%classmod%</span><br />%full_name%</td>
<td class="file-title"><span class="file-title-prefix"><%= values['classmod'] %></span><br /><%= values['full_name'] %></td>
<td align="right">
<table cellspacing="0" cellpadding="2">
<tr valign="top">
<td>In:</td>
<td>
START:infiles
HREF:full_path_url:full_path:
IF:cvsurl
&nbsp;(<a href="%cvsurl%">CVS</a>)
ENDIF:cvsurl
END:infiles
<% values['infiles'].each do |infile| %>
<%= href infile['full_path_url'], infile['full_path'] %>:
<% if infile['cvsurl'] %>
&nbsp;(<a href="<%= infile['cvsurl'] %>">CVS</a>)
<% end %>
<% end %>
</td>
</tr>
IF:parent
<% if values['parent'] %>
<tr>
<td>Parent:</td>
<td>
IF:par_url
<a href="%par_url%">
ENDIF:par_url
%parent%
IF:par_url
<% if values['par_url'] %>
<a href="<%= values['par_url'] %>">
<% end %>
<%= values['parent'] %>
<% if values['par_url'] %>
</a>
ENDIF:par_url
<% end %>
</td>
</tr>
ENDIF:parent
<% end %>
</table>
</td>
</tr>
......@@ -337,149 +341,149 @@ module Page
METHOD_LIST = <<HTML
<div id="content">
IF:diagram
<% if values['diagram'] %>
<table cellpadding='0' cellspacing='0' border='0' width="100%"><tr><td align="center">
%diagram%
<%= values['diagram'] %>
</td></tr></table>
ENDIF:diagram
<% end %>
IF:description
<div class="description">%description%</div>
ENDIF:description
<% if values['description'] %>
<div class="description"><%= values['description'] %></div>
<% end %>
IF:requires
<% if values['requires'] %>
<div class="sectiontitle">Required Files</div>
<ul>
START:requires
<li>HREF:aref:name:</li>
END:requires
<% values['requires'].each do |require| %>
<li><%= href require['aref'], require['name'] %>:</li>
<% end %>
</ul>
ENDIF:requires
<% end %>
IF:toc
<% if values['toc'] %>
<div class="sectiontitle">Contents</div>
<ul>
START:toc
<li><a href="#%href%">%secname%</a></li>
END:toc
<% values['toc'].each do |toc| %>
<li><a href="#<%= toc['href'] %>"><%= toc['secname'] %></a></li>
<% end %>
</ul>
ENDIF:toc
<% end %>
IF:methods
<% if values['methods'] %>
<div class="sectiontitle">Methods</div>
<ul>
START:methods
<li>HREF:aref:name:</li>
END:methods
<% values['methods'].each do |method| %>
<li><%= href method['aref'], method['name'] %></li>
<% end %>
</ul>
ENDIF:methods
<% end %>
IF:includes
<% if values['includes'] %>
<div class="sectiontitle">Included Modules</div>
<ul>
START:includes
<li>HREF:aref:name:</li>
END:includes
<% values['includes'].each do |include| %>
<li><%= href include['aref'], include['name'] %>:</li>
<% end %>
</ul>
ENDIF:includes
<% end %>
START:sections
IF:sectitle
<div class="sectiontitle"><a name="%secsequence%">%sectitle%</a></div>
IF:seccomment
<% values['sections'].each do |section| %>
<% if section['sectitle'] %>
<div class="sectiontitle"><a name="<%= section['secsequence'] %>"><%= section['sectitle'] %></a></div>
<% if section['seccomment'] %>
<div class="description">
%seccomment%
<%= section['seccomment'] %>
</div>
ENDIF:seccomment
ENDIF:sectitle
<% end %>
<% end %>
IF:classlist
<% if section['classlist'] %>
<div class="sectiontitle">Classes and Modules</div>
%classlist%
ENDIF:classlist
<%= section['classlist'] %>
<% end %>
IF:constants
<% if section['constants'] %>
<div class="sectiontitle">Constants</div>
<table border='0' cellpadding='5'>
START:constants
<% section['constants'].each do |constant| %>
<tr valign='top'>
<td class="attr-name">%name%</td>
<td class="attr-name"><%= constant['name'] %></td>
<td>=</td>
<td class="attr-value">%value%</td>
<td class="attr-value"><%= constant['value'] %></td>
</tr>
IF:desc
<% if constant['desc'] %>
<tr valign='top'>
<td>&nbsp;</td>
<td colspan="2" class="attr-desc">%desc%</td>
<td colspan="2" class="attr-desc"><%= constant['desc'] %></td>
</tr>
ENDIF:desc
END:constants
<% end %>
<% end %>
</table>
ENDIF:constants
<% end %>
IF:attributes
<% if section['attributes'] %>
<div class="sectiontitle">Attributes</div>
<table border='0' cellpadding='5'>
START:attributes
<% section['attributes'].each do |attribute| %>
<tr valign='top'>
<td class='attr-rw'>
IF:rw
[%rw%]
ENDIF:rw
<% if attribute['rw'] %>
[<%= attribute['rw'] %>]
<% end %>
</td>
<td class='attr-name'>%name%</td>
<td class='attr-desc'>%a_desc%</td>
<td class='attr-name'><%= attribute['name'] %></td>
<td class='attr-desc'><%= attribute['a_desc'] %></td>
</tr>
END:attributes
<% end %>
</table>
ENDIF:attributes
<% end %>
IF:method_list
START:method_list
IF:methods
<div class="sectiontitle">%type% %category% methods</div>
START:methods
<% if section['method_list'] %>
<% section['method_list'].each do |method_list| %>
<% if method_list['methods'] %>
<div class="sectiontitle"><%= method_list['type'] %> <%= method_list['category'] %> methods</div>
<% method_list['methods'].each do |method| %>
<div class="method">
<div class="title">
IF:callseq
<a name="%aref%"></a><b>%callseq%</b>
ENDIF:callseq
IFNOT:callseq
<a name="%aref%"></a><b>%name%</b>%params%
ENDIF:callseq
IF:codeurl
[&nbsp;<a href="%codeurl%" target="SOURCE_CODE" onclick="javascript:openCode('%codeurl%'); return false;">source</a>&nbsp;]
ENDIF:codeurl
<% if method['callseq'] %>
<a name="<%= method['aref'] %>"></a><b><%= method['callseq'] %></b>
<% end %>
<% unless method['callseq'] %>
<a name="<%= method['aref'] %>"></a><b><%= method['name'] %></b><%= method['params'] %>
<% end %>
<% if method['codeurl'] %>
[&nbsp;<a href="<%= method['codeurl'] %>" target="SOURCE_CODE" onclick="javascript:openCode('<%= method['codeurl'] %>'); return false;">source</a>&nbsp;]
<% end %>
</div>
IF:m_desc
<% if method['m_desc'] %>
<div class="description">
%m_desc%
<%= method['m_desc'] %>
</div>
ENDIF:m_desc
IF:aka
<% end %>
<% if method['aka'] %>
<div class="aka">
This method is also aliased as
START:aka
<a href="%aref%">%name%</a>
END:aka
<% method['aka'].each do |aka| %>
<a href="<%= aka['aref'] %>"><%= aka['name'] %></a>
<% end %>
</div>
ENDIF:aka
IF:sourcecode
<% end %>
<% if method['sourcecode'] %>
<div class="sourcecode">
<p class="source-link">[ <a href="javascript:toggleSource('%aref%_source')" id="l_%aref%_source">show source</a> ]</p>
<div id="%aref%_source" class="dyn-source">
<p class="source-link">[ <a href="javascript:toggleSource('<%= method['aref'] %>_source')" id="l_<%= method['aref'] %>_source">show source</a> ]</p>
<div id="<%= method['aref'] %>_source" class="dyn-source">
<pre>
%sourcecode%
<%= method['sourcecode'] %>
</pre>
</div>
</div>
ENDIF:sourcecode
<% end %>
</div>
END:methods
ENDIF:methods
END:method_list
ENDIF:method_list
END:sections
<% end %>
<% end %>
<% end %>
<% end %>
<% end %>
</div>
HTML
......@@ -489,7 +493,7 @@ module Page
ENDFOOTER
BODY = HEADER + <<ENDBODY
!INCLUDE! <!-- banner header -->
<%= template_include %> <!-- banner header -->
<div id="bodyContent">
#{METHOD_LIST}
......@@ -502,8 +506,8 @@ module Page
SRC_PAGE = XHTML_PREAMBLE + <<HTML
<html>
<head><title>%title%</title>
<meta http-equiv="Content-Type" content="text/html; charset=%charset%" />
<head><title><%= values['title'] %></title>
<meta http-equiv="Content-Type" content="text/html; charset=<%= values['charset'] %>" />
<style type="text/css">
.ruby-comment { color: green; font-style: italic }
.ruby-constant { color: #4433aa; font-weight: bold; }
......@@ -521,7 +525,7 @@ module Page
</style>
</head>
<body bgcolor="white">
<pre>%code%</pre>
<pre><%= values['code'] %></pre>
</body>
</html>
HTML
......@@ -529,13 +533,13 @@ module Page
########################## Index ################################
FR_INDEX_BODY = <<HTML
!INCLUDE!
<%= template_include %>
HTML
FILE_INDEX = XHTML_PREAMBLE + <<HTML
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=%charset%" />
<meta http-equiv="Content-Type" content="text/html; charset=<%= values['charset'] %>" />
<title>Index</title>
<style type="text/css">
<!--
......@@ -571,11 +575,11 @@ module Page
<base target="docwin" />
</head>
<body>
<div class="banner">%list_title%</div>
<div class="banner"><%= values['list_title'] %></div>
<div class="entries">
START:entries
<a href="%href%">%name%</a><br />
END:entries
<% values['entries'].each do |entrie| %>
<a href="<%= entrie['href'] %>"><%= entrie['name'] %></a><br />
<% end %>
</div>
</body></html>
HTML
......@@ -586,8 +590,8 @@ module Page
INDEX = XHTML_FRAMESET_PREAMBLE + <<HTML
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>%title%</title>
<meta http-equiv="Content-Type" content="text/html; charset=%charset%" />
<title><%= values['title'] %></title>
<meta http-equiv="Content-Type" content="text/html; charset=<%= values['charset'] %>" />
</head>
<frameset cols="20%,*">
......@@ -596,7 +600,7 @@ module Page
<frame src="fr_class_index.html" name="Classes" />
<frame src="fr_method_index.html" name="Methods" />
</frameset>
<frame src="%initial_page%" name="docwin" />
<frame src="<%= values['initial_page'] %>" name="docwin" />
<noframes>
<body bgcolor="white">
Click <a href="html/index.html">here</a> for a non-frames
......@@ -610,4 +614,5 @@ module Page
end
end
end
end
gem 'rdoc', '= 2.2'
require 'rdoc'
require 'rake'
require 'rake/testtask'
require 'rake/rdoctask'
......
文件模式从 100755 更改为 100644
文件模式从 100755 更改为 100644
文件模式从 100755 更改为 100644
文件模式从 100755 更改为 100644
文件模式从 100755 更改为 100644
require 'active_support/core_ext/hash/reverse_merge'
require 'active_support/file_update_checker'
require 'fileutils'
require 'rails/plugin'
require 'rails/engine'
......@@ -46,7 +47,6 @@ class Application < Engine
autoload :Configuration, 'rails/application/configuration'
autoload :Finisher, 'rails/application/finisher'
autoload :Railties, 'rails/application/railties'
autoload :RoutesReloader, 'rails/application/routes_reloader'
class << self
private :new
......@@ -84,17 +84,30 @@ def method_missing(*args, &block)
delegate :middleware, :to => :config
def add_lib_to_load_paths!
# This method is called just after an application inherits from Rails::Application,
# allowing the developer to load classes in lib and use them during application
# configuration.
#
# class MyApplication < Rails::Application
# require "my_backend" # in lib/my_backend
# config.i18n.backend = MyBackend
# end
#
# Notice this method takes into consideration the default root path. So if you
# are changing config.root inside your application definition or having a custom
# Rails application, you will need to add lib to $LOAD_PATH on your own in case
# you need to load files in lib/ during the application configuration as well.
def add_lib_to_load_paths! #:nodoc:
path = config.root.join('lib').to_s
$LOAD_PATH.unshift(path) if File.exists?(path)
end
def require_environment!
def require_environment! #:nodoc:
environment = paths.config.environment.to_a.first
require environment if environment
end
def eager_load!
def eager_load! #:nodoc:
railties.all(&:eager_load!)
super
end
......@@ -108,11 +121,18 @@ def railties
end
def routes_reloader
@routes_reloader ||= RoutesReloader.new
@routes_reloader ||= ActiveSupport::FileUpdateChecker.new([]){ reload_routes! }
end
def reload_routes!
routes_reloader.reload!
routes = Rails::Application.routes
routes.disable_clear_and_finalize = true
routes.clear!
routes_reloader.paths.each { |path| load(path) }
ActiveSupport.on_load(:action_controller) { routes.finalize! }
ensure
routes.disable_clear_and_finalize = false
end
def initialize!
......
require "active_support/notifications"
require "active_support/descendants_tracker"
module Rails
class Application
......@@ -55,6 +56,7 @@ module Bootstrap
initializer :set_clear_dependencies_hook do
unless config.cache_classes
ActionDispatch::Callbacks.after do
ActiveSupport::DescendantsTracker.clear
ActiveSupport::Dependencies.clear
end
end
......
module Rails
class Application
class RoutesReloader
attr_reader :paths
def initialize
@paths, @last_change_at = [], nil
end
def changed_at
routes_changed_at = nil
paths.each do |path|
config_changed_at = File.stat(path).mtime
if routes_changed_at.nil? || config_changed_at > routes_changed_at
routes_changed_at = config_changed_at
end
end
routes_changed_at
end
def reload!
routes = Rails::Application.routes
routes.disable_clear_and_finalize = true
routes.clear!
paths.each { |path| load(path) }
ActiveSupport.on_load(:action_controller) { routes.finalize! }
nil
ensure
routes.disable_clear_and_finalize = false
end
def reload_if_changed
current_change_at = changed_at
if @last_change_at != current_change_at
@last_change_at = current_change_at
reload!
end
end
end
end
end
\ No newline at end of file
文件模式从 100755 更改为 100644
......@@ -83,7 +83,8 @@ def default_options
:environment => (ENV['RAILS_ENV'] || "development").dup,
:daemonize => false,
:debugger => false,
:pid => "tmp/pids/server.pid"
:pid => File.expand_path("tmp/pids/server.pid"),
:config => File.expand_path("config.ru")
})
end
end
......
......@@ -3,4 +3,4 @@
<%%= render 'form' %>
<%%= link_to 'Show', @<%= singular_name %> %> |
<%%= link_to 'Back', <%= plural_name %>_path %>
<%%= link_to 'Back', <%= index_helper %>_path %>
......@@ -2,4 +2,4 @@
<%%= render 'form' %>
<%%= link_to 'Back', <%= plural_name %>_path %>
<%%= link_to 'Back', <%= index_helper %>_path %>
......@@ -9,4 +9,4 @@
<% end -%>
<%%= link_to 'Edit', edit_<%= singular_name %>_path(@<%= singular_name %>) %> |
<%%= link_to 'Back', <%= plural_name %>_path %>
<%%= link_to 'Back', <%= index_helper %>_path %>
......@@ -46,6 +46,14 @@ def table_name
end
end
def uncountable?
singular_name == plural_name
end
def index_helper
uncountable? ? "#{plural_name}_index" : plural_name
end
# Tries to retrieve the application name or simple return application.
def application_name
if defined?(Rails) && Rails.application
......
......@@ -37,7 +37,7 @@ link:files/vendor/rails/actionpack/README.html.
3. Go to http://localhost:3000/ and you'll see:
"Welcome aboard: You're riding the Rails!"
4. Follow the guidelines to start developing your application. You can find
4. Follow the guidelines to start developing your application. You can find
the following resources handy:
* The Getting Started Guide: http://guides.rubyonrails.org/getting_started.html
......@@ -71,13 +71,13 @@ The result will be a message in your log file along the lines of:
More information on how to use the logger is at http://www.ruby-doc.org/core/
Also, Ruby documentation can be found at http://www.ruby-lang.org/. There are
Also, Ruby documentation can be found at http://www.ruby-lang.org/. There are
several books available online as well:
* Programming Ruby: http://www.ruby-doc.org/docs/ProgrammingRuby/ (Pickaxe)
* Learn to Program: http://pine.fm/LearnToProgram/ (a beginners guide)
These two books will bring you up to speed on the Ruby language and also on
These two books will bring you up to speed on the Ruby language and also on
programming in general.
......@@ -199,7 +199,7 @@ app/controllers
ApplicationController which itself descends from ActionController::Base.
app/models
Holds models that should be named like post.rb. Models descend from
Holds models that should be named like post.rb. Models descend from
ActiveRecord::Base by default.
app/views
......
文件模式从 100755 更改为 100644
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册