mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
Merge branch 'master' of github.com:lifo/docrails
This commit is contained in:
commit
965fe59bff
173 changed files with 3634 additions and 2185 deletions
18
Gemfile
18
Gemfile
|
@ -1,7 +1,7 @@
|
|||
path File.expand_path('..', __FILE__)
|
||||
source :gemcutter
|
||||
path File.dirname(__FILE__)
|
||||
source 'http://gemcutter.org'
|
||||
|
||||
gem "rails", "3.0.0.beta"
|
||||
gem "rails", "3.0.0.beta1"
|
||||
|
||||
gem "rake", ">= 0.8.7"
|
||||
gem "mocha", ">= 0.9.8"
|
||||
|
@ -11,7 +11,7 @@ if RUBY_VERSION < '1.9'
|
|||
end
|
||||
|
||||
# AR
|
||||
gem "sqlite3-ruby", ">= 1.2.5"
|
||||
gem "sqlite3-ruby", ">= 1.2.5", :require => 'sqlite3'
|
||||
|
||||
group :test do
|
||||
gem "pg", ">= 0.8.0"
|
||||
|
@ -19,18 +19,12 @@ group :test do
|
|||
end
|
||||
|
||||
# AP
|
||||
gem "rack-test", "0.5.3"
|
||||
gem "rack-test", "0.5.3", :require => 'rack/test'
|
||||
gem "RedCloth", ">= 4.2.2"
|
||||
|
||||
if ENV['CI']
|
||||
gem "nokogiri", ">= 1.4.0"
|
||||
gem "memcache-client", ">= 1.7.6"
|
||||
|
||||
# fcgi gem doesn't compile on 1.9
|
||||
# avoid minitest strangeness on 1.9
|
||||
if RUBY_VERSION < '1.9.0'
|
||||
gem "fcgi", ">= 0.8.7"
|
||||
else
|
||||
gem "test-unit", ">= 2.0.5"
|
||||
end
|
||||
gem "fcgi", ">= 0.8.7" if RUBY_VERSION < '1.9.0'
|
||||
end
|
||||
|
|
22
Rakefile
22
Rakefile
|
@ -13,7 +13,7 @@ end
|
|||
desc 'Run all tests by default'
|
||||
task :default => %w(test test:isolated)
|
||||
|
||||
%w(test test:isolated rdoc pgem package release gem gemspec).each do |task_name|
|
||||
%w(test test:isolated rdoc pgem package gem gemspec).each do |task_name|
|
||||
desc "Run #{task_name} task for all projects"
|
||||
task task_name do
|
||||
errors = []
|
||||
|
@ -37,6 +37,22 @@ Rake::GemPackageTask.new(spec) do |pkg|
|
|||
pkg.gem_spec = spec
|
||||
end
|
||||
|
||||
desc "Release all gems to gemcutter. Package rails, package & push components, then push rails"
|
||||
task :release => :release_projects do
|
||||
require 'rake/gemcutter'
|
||||
Rake::Gemcutter::Tasks.new(spec).define
|
||||
Rake::Task['gem:push'].invoke
|
||||
end
|
||||
|
||||
desc "Release all components to gemcutter."
|
||||
task :release_projects => :package do
|
||||
errors = []
|
||||
PROJECTS.each do |project|
|
||||
system(%(cd #{project} && #{env} #{$0} release)) || errors << project
|
||||
end
|
||||
fail("Errors in #{errors.join(', ')}") unless errors.empty?
|
||||
end
|
||||
|
||||
task :install => :gem do
|
||||
(PROJECTS - ["railties"]).each do |project|
|
||||
puts "INSTALLING #{project}"
|
||||
|
@ -88,6 +104,10 @@ Rake::RDocTask.new do |rdoc|
|
|||
rdoc.rdoc_files.include('activesupport/CHANGELOG')
|
||||
rdoc.rdoc_files.include('activesupport/lib/active_support/**/*.rb')
|
||||
rdoc.rdoc_files.exclude('activesupport/lib/active_support/vendor/*')
|
||||
|
||||
rdoc.rdoc_files.include('activemodel/README')
|
||||
rdoc.rdoc_files.include('activemodel/CHANGELOG')
|
||||
rdoc.rdoc_files.include('activemodel/lib/active_model/**/*.rb')
|
||||
end
|
||||
|
||||
# Enhance rdoc task to copy referenced images also
|
||||
|
|
|
@ -101,7 +101,7 @@ Example:
|
|||
This Mailman can be the target for Postfix or other MTAs. In Rails, you would use the runner in the
|
||||
trivial case like this:
|
||||
|
||||
./script/runner 'Mailman.receive(STDIN.read)'
|
||||
rails runner 'Mailman.receive(STDIN.read)'
|
||||
|
||||
However, invoking Rails in the runner for each mail to be received is very resource intensive. A single
|
||||
instance of Rails should be run within a daemon if it is going to be utilized to process more than just
|
||||
|
|
|
@ -54,11 +54,11 @@ Rake::GemPackageTask.new(spec) do |p|
|
|||
p.gem_spec = spec
|
||||
end
|
||||
|
||||
desc "Publish the API documentation"
|
||||
task :pgem => [:package] do
|
||||
require 'rake/contrib/sshpublisher'
|
||||
Rake::SshFilePublisher.new("gems.rubyonrails.org", "/u/sites/gems/gems", "pkg", "#{PKG_FILE_NAME}.gem").upload
|
||||
`ssh gems.rubyonrails.org '/u/sites/gems/gemupdate.sh'`
|
||||
desc "Release to gemcutter"
|
||||
task :release => :package do
|
||||
require 'rake/gemcutter'
|
||||
Rake::Gemcutter::Tasks.new(spec).define
|
||||
Rake::Task['gem:push'].invoke
|
||||
end
|
||||
|
||||
desc "Publish the API documentation"
|
||||
|
@ -66,15 +66,3 @@ task :pdoc => [:rdoc] do
|
|||
require 'rake/contrib/sshpublisher'
|
||||
Rake::SshDirPublisher.new("wrath.rubyonrails.org", "public_html/am", "doc").upload
|
||||
end
|
||||
|
||||
desc "Publish the release files to RubyForge."
|
||||
task :release => [ :package ] do
|
||||
require 'rubyforge'
|
||||
require 'rake/contrib/rubyforgepublisher'
|
||||
|
||||
packages = %w( gem tgz zip ).collect{ |ext| "pkg/#{PKG_NAME}-#{PKG_VERSION}.#{ext}" }
|
||||
|
||||
rubyforge = RubyForge.new
|
||||
rubyforge.login
|
||||
rubyforge.add_release(PKG_NAME, PKG_NAME, "REL #{PKG_VERSION}", *packages)
|
||||
end
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
Gem::Specification.new do |s|
|
||||
s.platform = Gem::Platform::RUBY
|
||||
s.name = 'actionmailer'
|
||||
s.version = '3.0.0.beta'
|
||||
s.version = '3.0.0.beta1'
|
||||
s.summary = 'Email composition, delivery, and recieval framework (part of Rails).'
|
||||
s.description = 'Email composition, delivery, and recieval framework (part of Rails).'
|
||||
s.required_ruby_version = '>= 1.8.7'
|
||||
|
||||
s.author = 'David Heinemeier Hansson'
|
||||
s.email = 'david@loudthinking.com'
|
||||
|
@ -16,7 +17,7 @@ Gem::Specification.new do |s|
|
|||
|
||||
s.has_rdoc = true
|
||||
|
||||
s.add_dependency('actionpack', '= 3.0.0.beta')
|
||||
s.add_dependency('actionpack', '= 3.0.0.beta1')
|
||||
s.add_dependency('mail', '~> 2.1.2')
|
||||
s.add_dependency('text-format', '~> 1.0.0')
|
||||
end
|
||||
|
|
|
@ -9,7 +9,7 @@ module ActionMailer #:nodoc:
|
|||
#
|
||||
# To use Action Mailer, you need to create a mailer model.
|
||||
#
|
||||
# $ script/generate mailer Notifier
|
||||
# $ rails generate mailer Notifier
|
||||
#
|
||||
# The generated model inherits from ActionMailer::Base. Emails are defined by creating methods
|
||||
# within the model which are then used to set variables to be used in the mail template, to
|
||||
|
|
|
@ -5,6 +5,10 @@ module ActionMailer
|
|||
class Railtie < Rails::Railtie
|
||||
railtie_name :action_mailer
|
||||
|
||||
initializer "action_mailer.url_for", :before => :load_environment_config do |app|
|
||||
ActionMailer::Base.send(:include, ActionController::UrlFor) if defined?(ActionController)
|
||||
end
|
||||
|
||||
require "action_mailer/railties/subscriber"
|
||||
subscriber ActionMailer::Railties::Subscriber.new
|
||||
|
||||
|
@ -17,9 +21,5 @@ module ActionMailer
|
|||
ActionMailer::Base.send "#{k}=", v
|
||||
end
|
||||
end
|
||||
|
||||
initializer "action_mailer.url_for" do |app|
|
||||
ActionMailer::Base.send(:include, ActionController::UrlFor) if defined?(ActionController)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -2,7 +2,7 @@ module ActionMailer
|
|||
module VERSION #:nodoc:
|
||||
MAJOR = 3
|
||||
MINOR = 0
|
||||
TINY = "0.beta"
|
||||
TINY = "0.beta1"
|
||||
|
||||
STRING = [MAJOR, MINOR, TINY].join('.')
|
||||
end
|
||||
|
|
|
@ -461,7 +461,8 @@ class BaseTest < ActiveSupport::TestCase
|
|||
assert_instance_of Mail::Message, mail
|
||||
end
|
||||
|
||||
test "calling deliver on the action should increment the deliveries collection" do
|
||||
test "calling deliver on the action should increment the deliveries collection if using the test mailer" do
|
||||
BaseMailer.delivery_method = :test
|
||||
BaseMailer.deliveries.clear
|
||||
BaseMailer.welcome.deliver
|
||||
assert_equal(1, BaseMailer.deliveries.length)
|
||||
|
|
|
@ -70,6 +70,13 @@ Rake::GemPackageTask.new(spec) do |p|
|
|||
p.gem_spec = spec
|
||||
end
|
||||
|
||||
desc "Release to gemcutter"
|
||||
task :release => :package do
|
||||
require 'rake/gemcutter'
|
||||
Rake::Gemcutter::Tasks.new(spec).define
|
||||
Rake::Task['gem:push'].invoke
|
||||
end
|
||||
|
||||
task :lines do
|
||||
lines, codelines, total_lines, total_codelines = 0, 0, 0, 0
|
||||
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
Gem::Specification.new do |s|
|
||||
s.platform = Gem::Platform::RUBY
|
||||
s.name = 'actionpack'
|
||||
s.version = '3.0.0.beta'
|
||||
s.version = '3.0.0.beta1'
|
||||
s.summary = 'Web-flow and rendering framework putting the VC in MVC (part of Rails).'
|
||||
s.description = 'Web-flow and rendering framework putting the VC in MVC (part of Rails).'
|
||||
s.required_ruby_version = '>= 1.8.7'
|
||||
|
||||
s.author = 'David Heinemeier Hansson'
|
||||
s.email = 'david@loudthinking.com'
|
||||
|
@ -16,10 +17,10 @@ Gem::Specification.new do |s|
|
|||
|
||||
s.has_rdoc = true
|
||||
|
||||
s.add_dependency('activesupport', '= 3.0.0.beta')
|
||||
s.add_dependency('activemodel', '= 3.0.0.beta')
|
||||
s.add_dependency('activesupport', '= 3.0.0.beta1')
|
||||
s.add_dependency('activemodel', '= 3.0.0.beta1')
|
||||
s.add_dependency('rack', '~> 1.1.0')
|
||||
s.add_dependency('rack-test', '~> 0.5.0')
|
||||
s.add_dependency('rack-mount', '~> 0.4.0')
|
||||
s.add_dependency('rack-mount', '~> 0.4.7')
|
||||
s.add_dependency('erubis', '~> 2.6.5')
|
||||
end
|
||||
|
|
|
@ -76,6 +76,7 @@ module ActionController
|
|||
def consider_all_requests_local=(value)
|
||||
ActiveSupport::Deprecation.warn "ActionController::Base.consider_all_requests_local= is no longer effective. " <<
|
||||
"Please configure it on your application with config.consider_all_requests_local="
|
||||
Rails.application.config.consider_all_requests_local = value
|
||||
end
|
||||
|
||||
def allow_concurrency
|
||||
|
@ -87,6 +88,7 @@ module ActionController
|
|||
def allow_concurrency=(value)
|
||||
ActiveSupport::Deprecation.warn "ActionController::Base.allow_concurrency= is no longer effective. " <<
|
||||
"Please configure it on your application with config.allow_concurrency="
|
||||
Rails.application.config.allow_concurrency = value
|
||||
end
|
||||
|
||||
def rescue_action(env)
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
require 'active_support/core_ext/class/attribute'
|
||||
require 'active_support/core_ext/module/attribute_accessors'
|
||||
|
||||
module ActionController
|
||||
# In <b>routes.rb</b> one defines URL-to-controller mappings, but the reverse
|
||||
|
@ -87,7 +88,14 @@ module ActionController
|
|||
|
||||
included do
|
||||
ActionController::Routing::Routes.install_helpers(self)
|
||||
class_attribute :default_url_options
|
||||
|
||||
# Including in a class uses an inheritable hash. Modules get a plain hash.
|
||||
if respond_to?(:class_attribute)
|
||||
class_attribute :default_url_options
|
||||
else
|
||||
mattr_accessor :default_url_options
|
||||
end
|
||||
|
||||
self.default_url_options = {}
|
||||
end
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
require "action_controller"
|
||||
require "rails"
|
||||
require "action_view/railtie"
|
||||
|
||||
module ActionController
|
||||
class Railtie < Rails::Railtie
|
||||
|
|
|
@ -15,9 +15,8 @@ module ActionController
|
|||
payload = event.payload
|
||||
additions = ActionController::Base.log_process_action(payload)
|
||||
|
||||
message = "Completed in %.0fms" % event.duration
|
||||
message = "Completed #{payload[:status]} #{Rack::Utils::HTTP_STATUS_CODES[payload[:status]]} in %.0fms" % event.duration
|
||||
message << " (#{additions.join(" | ")})" unless additions.blank?
|
||||
message << " with #{payload[:status]}"
|
||||
|
||||
info(message)
|
||||
end
|
||||
|
|
|
@ -5,20 +5,6 @@ require 'action_dispatch/http/request'
|
|||
module ActionDispatch
|
||||
# This middleware rescues any exception returned by the application and renders
|
||||
# nice exception pages if it's being rescued locally.
|
||||
#
|
||||
# Every time an exception is caught, a notification is published, becoming a good API
|
||||
# to deal with exceptions. So, if you want send an e-mail through ActionMailer
|
||||
# everytime this notification is published, you just need to do the following:
|
||||
#
|
||||
# ActiveSupport::Notifications.subscribe "action_dispatch.show_exception" do |name, start, end, instrumentation_id, payload|
|
||||
# ExceptionNotifier.deliver_exception(start, payload)
|
||||
# end
|
||||
#
|
||||
# The payload is a hash which has two pairs:
|
||||
#
|
||||
# * :env - Contains the rack env for the given request;
|
||||
# * :exception - The exception raised;
|
||||
#
|
||||
class ShowExceptions
|
||||
LOCALHOST = ['127.0.0.1', '::1'].freeze
|
||||
|
||||
|
|
|
@ -44,7 +44,8 @@ module ActionDispatch
|
|||
controller = "#{params[:controller].camelize}Controller"
|
||||
ActiveSupport::Inflector.constantize(controller)
|
||||
end
|
||||
rescue NameError
|
||||
rescue NameError => e
|
||||
raise unless e.message.include?(controller)
|
||||
nil
|
||||
end
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ module ActionPack #:nodoc:
|
|||
module VERSION #:nodoc:
|
||||
MAJOR = 3
|
||||
MINOR = 0
|
||||
TINY = "0.beta"
|
||||
TINY = "0.beta1"
|
||||
|
||||
STRING = [MAJOR, MINOR, TINY].join('.')
|
||||
end
|
||||
|
|
|
@ -7,6 +7,7 @@ module ActionView #:nodoc:
|
|||
autoload :AtomFeedHelper, 'action_view/helpers/atom_feed_helper'
|
||||
autoload :CacheHelper, 'action_view/helpers/cache_helper'
|
||||
autoload :CaptureHelper, 'action_view/helpers/capture_helper'
|
||||
autoload :CsrfHelper, 'action_view/helpers/csrf_helper'
|
||||
autoload :DateHelper, 'action_view/helpers/date_helper'
|
||||
autoload :DebugHelper, 'action_view/helpers/debug_helper'
|
||||
autoload :FormHelper, 'action_view/helpers/form_helper'
|
||||
|
@ -40,6 +41,7 @@ module ActionView #:nodoc:
|
|||
include AtomFeedHelper
|
||||
include CacheHelper
|
||||
include CaptureHelper
|
||||
include CsrfHelper
|
||||
include DateHelper
|
||||
include DebugHelper
|
||||
include FormHelper
|
||||
|
|
12
actionpack/lib/action_view/helpers/csrf_helper.rb
Normal file
12
actionpack/lib/action_view/helpers/csrf_helper.rb
Normal file
|
@ -0,0 +1,12 @@
|
|||
module ActionView
|
||||
module Helpers
|
||||
module CsrfHelper
|
||||
# Returns a meta tag with the request forgery protection token for forms to use. Put this in your head.
|
||||
def csrf_meta_tag
|
||||
if protect_against_forgery?
|
||||
%(<meta name="csrf-param" content="#{Rack::Utils.escape_html(request_forgery_protection_token)}"/>\n<meta name="csrf-token" content="#{Rack::Utils.escape_html(form_authenticity_token)}"/>).html_safe
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -309,7 +309,7 @@ module ActionView
|
|||
|
||||
options[:html][:remote] = true if options.delete(:remote)
|
||||
|
||||
concat(form_tag(options.delete(:url) || {}, options.delete(:html) || {}))
|
||||
safe_concat(form_tag(options.delete(:url) || {}, options.delete(:html) || {}))
|
||||
fields_for(object_name, *(args << options), &proc)
|
||||
safe_concat('</form>')
|
||||
end
|
||||
|
@ -1172,7 +1172,9 @@ module ActionView
|
|||
|
||||
def fields_for_with_nested_attributes(association_name, args, block)
|
||||
name = "#{object_name}[#{association_name}_attributes]"
|
||||
association = args.first.to_model if args.first.respond_to?(:to_model)
|
||||
options = args.extract_options!
|
||||
association = args.shift
|
||||
association = association.to_model if association.respond_to?(:to_model)
|
||||
|
||||
if association.respond_to?(:new_record?)
|
||||
association = [association] if @object.send(association_name).is_a?(Array)
|
||||
|
@ -1181,20 +1183,22 @@ module ActionView
|
|||
end
|
||||
|
||||
if association.is_a?(Array)
|
||||
explicit_child_index = args.last[:child_index] if args.last.is_a?(Hash)
|
||||
explicit_child_index = options[:child_index]
|
||||
association.map do |child|
|
||||
fields_for_nested_model("#{name}[#{explicit_child_index || nested_child_index(name)}]", child, args, block)
|
||||
fields_for_nested_model("#{name}[#{explicit_child_index || nested_child_index(name)}]", child, options, block)
|
||||
end.join
|
||||
elsif association
|
||||
fields_for_nested_model(name, association, args, block)
|
||||
fields_for_nested_model(name, association, options, block)
|
||||
end
|
||||
end
|
||||
|
||||
def fields_for_nested_model(name, object, args, block)
|
||||
def fields_for_nested_model(name, object, options, block)
|
||||
object = object.to_model if object.respond_to?(:to_model)
|
||||
|
||||
if object.new_record?
|
||||
@template.fields_for(name, object, *args, &block)
|
||||
@template.fields_for(name, object, options, &block)
|
||||
else
|
||||
@template.fields_for(name, object, *args) do |builder|
|
||||
@template.fields_for(name, object, options) do |builder|
|
||||
block.call(builder)
|
||||
@template.concat builder.hidden_field(:id) unless builder.emitted_hidden_id?
|
||||
end
|
||||
|
|
|
@ -441,8 +441,8 @@ module ActionView
|
|||
# # => <fieldset class="format"><p><input id="name" name="name" type="text" /></p></fieldset>
|
||||
def field_set_tag(legend = nil, options = nil, &block)
|
||||
content = capture(&block)
|
||||
concat(tag(:fieldset, options, true))
|
||||
concat(content_tag(:legend, legend)) unless legend.blank?
|
||||
safe_concat(tag(:fieldset, options, true))
|
||||
safe_concat(content_tag(:legend, legend)) unless legend.blank?
|
||||
concat(content)
|
||||
safe_concat("</fieldset>")
|
||||
end
|
||||
|
@ -477,7 +477,7 @@ module ActionView
|
|||
|
||||
def form_tag_in_block(html_options, &block)
|
||||
content = capture(&block)
|
||||
concat(form_tag_html(html_options))
|
||||
safe_concat(form_tag_html(html_options))
|
||||
concat(content)
|
||||
safe_concat("</form>")
|
||||
end
|
||||
|
|
|
@ -86,7 +86,7 @@ module ActionView
|
|||
tag = content_tag(:script, javascript_cdata_section(content), html_options.merge(:type => Mime::JS))
|
||||
|
||||
if block_called_from_erb?(block)
|
||||
concat(tag)
|
||||
safe_concat(tag)
|
||||
else
|
||||
tag
|
||||
end
|
||||
|
|
|
@ -72,7 +72,7 @@ module ActionView
|
|||
content_tag = content_tag_string(name, capture(&block), options, escape)
|
||||
|
||||
if block_called_from_erb?(block)
|
||||
concat(content_tag)
|
||||
safe_concat(content_tag)
|
||||
else
|
||||
content_tag
|
||||
end
|
||||
|
|
|
@ -187,7 +187,7 @@ module ActionView
|
|||
# pluralize(0, 'person')
|
||||
# # => 0 people
|
||||
def pluralize(count, singular, plural = nil)
|
||||
"#{count || 0} " + ((count == 1 || count == '1') ? singular : (plural || singular.pluralize))
|
||||
"#{count || 0} " + ((count == 1 || count =~ /^1(\.0+)?$/) ? singular : (plural || singular.pluralize))
|
||||
end
|
||||
|
||||
# Wraps the +text+ into lines no longer than +line_width+ width. This method
|
||||
|
@ -327,12 +327,12 @@ module ActionView
|
|||
# # => "<p class='description'>Look ma! A class!</p>"
|
||||
def simple_format(text, html_options={})
|
||||
start_tag = tag('p', html_options, true)
|
||||
text = text.to_s.dup
|
||||
text = h(text)
|
||||
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
|
||||
text.insert 0, start_tag
|
||||
text << "</p>"
|
||||
text.safe_concat("</p>")
|
||||
end
|
||||
|
||||
# Turns all URLs and e-mail addresses into clickable links. The <tt>:link</tt> option
|
||||
|
@ -415,7 +415,7 @@ module ActionView
|
|||
# {:first => 'Emily', :middle => 'Shannon', :maiden => 'Pike', :last => 'Hicks'},
|
||||
# {:first => 'June', :middle => 'Dae', :last => 'Jones'}]
|
||||
# <% @items.each do |item| %>
|
||||
# <tr class="<%= cycle("even", "odd", :name => "row_class") -%>">
|
||||
# <tr class="<%= cycle("odd", "even", :name => "row_class") -%>">
|
||||
# <td>
|
||||
# <% item.values.each do |value| %>
|
||||
# <%# Create a named cycle "colors" %>
|
||||
|
|
|
@ -19,7 +19,7 @@ module ActionView
|
|||
options[:locals] ||= {}
|
||||
|
||||
if block_given?
|
||||
return concat(_render_partial(options.merge(:partial => layout), &block))
|
||||
return safe_concat(_render_partial(options.merge(:partial => layout), &block))
|
||||
elsif options.key?(:partial)
|
||||
return _render_partial(options)
|
||||
end
|
||||
|
|
|
@ -15,13 +15,17 @@ module RequestForgeryProtectionActions
|
|||
render :text => 'pwn'
|
||||
end
|
||||
|
||||
def meta
|
||||
render :inline => "<%= csrf_meta_tag %>"
|
||||
end
|
||||
|
||||
def rescue_action(e) raise e end
|
||||
end
|
||||
|
||||
# sample controllers
|
||||
class RequestForgeryProtectionController < ActionController::Base
|
||||
include RequestForgeryProtectionActions
|
||||
protect_from_forgery :only => :index
|
||||
protect_from_forgery :only => %w(index meta)
|
||||
end
|
||||
|
||||
class FreeCookieController < RequestForgeryProtectionController
|
||||
|
@ -211,6 +215,12 @@ class RequestForgeryProtectionControllerTest < ActionController::TestCase
|
|||
ActiveSupport::SecureRandom.stubs(:base64).returns(@token)
|
||||
ActionController::Base.request_forgery_protection_token = :authenticity_token
|
||||
end
|
||||
|
||||
test 'should emit a csrf-token meta tag' do
|
||||
ActiveSupport::SecureRandom.stubs(:base64).returns(@token + '<=?')
|
||||
get :meta
|
||||
assert_equal %(<meta name="csrf-param" content="authenticity_token"/>\n<meta name="csrf-token" content="cf50faa3fe97702ca1ae<=?"/>), @response.body
|
||||
end
|
||||
end
|
||||
|
||||
class FreeCookieControllerTest < ActionController::TestCase
|
||||
|
@ -238,6 +248,11 @@ class FreeCookieControllerTest < ActionController::TestCase
|
|||
assert_nothing_raised { send(method, :index)}
|
||||
end
|
||||
end
|
||||
|
||||
test 'should not emit a csrf-token meta tag' do
|
||||
get :meta
|
||||
assert @response.body.blank?
|
||||
end
|
||||
end
|
||||
|
||||
class CustomAuthenticityParamControllerTest < ActionController::TestCase
|
||||
|
|
|
@ -73,7 +73,7 @@ class ACSubscriberTest < ActionController::TestCase
|
|||
wait
|
||||
assert_equal 2, logs.size
|
||||
assert_match /Completed/, logs.last
|
||||
assert_match /with 200/, logs.last
|
||||
assert_match /200 OK/, logs.last
|
||||
end
|
||||
|
||||
def test_process_action_without_parameters
|
||||
|
|
|
@ -118,6 +118,8 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
|
|||
match 'description', :to => "account#description", :as => "description"
|
||||
resource :subscription, :credit, :credit_card
|
||||
|
||||
root :to => "account#index"
|
||||
|
||||
namespace :admin do
|
||||
resource :subscription
|
||||
end
|
||||
|
@ -659,6 +661,14 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
|
|||
end
|
||||
end
|
||||
|
||||
def test_namespaced_roots
|
||||
with_test_routes do
|
||||
assert_equal '/account', account_root_path
|
||||
get '/account'
|
||||
assert_equal 'account#index', @response.body
|
||||
end
|
||||
end
|
||||
|
||||
def test_optional_scoped_root
|
||||
with_test_routes do
|
||||
assert_equal '/en', root_path("en")
|
||||
|
|
|
@ -918,6 +918,28 @@ class FormHelperTest < ActionView::TestCase
|
|||
assert_dom_equal expected, output_buffer
|
||||
end
|
||||
|
||||
def test_nested_fields_for_with_existing_records_on_a_supplied_nested_attributes_collection_different_from_record_one
|
||||
comments = Array.new(2) { |id| Comment.new(id + 1) }
|
||||
@post.comments = []
|
||||
|
||||
form_for(:post, @post) do |f|
|
||||
concat f.text_field(:title)
|
||||
f.fields_for(:comments, comments) do |cf|
|
||||
concat cf.text_field(:name)
|
||||
end
|
||||
end
|
||||
|
||||
expected = '<form action="http://www.example.com" method="post">' +
|
||||
'<input name="post[title]" size="30" type="text" id="post_title" value="Hello World" />' +
|
||||
'<input id="post_comments_attributes_0_name" name="post[comments_attributes][0][name]" size="30" type="text" value="comment #1" />' +
|
||||
'<input id="post_comments_attributes_0_id" name="post[comments_attributes][0][id]" type="hidden" value="1" />' +
|
||||
'<input id="post_comments_attributes_1_name" name="post[comments_attributes][1][name]" size="30" type="text" value="comment #2" />' +
|
||||
'<input id="post_comments_attributes_1_id" name="post[comments_attributes][1][id]" type="hidden" value="2" />' +
|
||||
'</form>'
|
||||
|
||||
assert_dom_equal expected, output_buffer
|
||||
end
|
||||
|
||||
def test_nested_fields_for_on_a_nested_attributes_collection_association_yields_only_builder
|
||||
@post.comments = [Comment.new(321), Comment.new]
|
||||
yielded_comments = []
|
||||
|
|
|
@ -40,6 +40,18 @@ class TextHelperTest < ActionView::TestCase
|
|||
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?
|
||||
end
|
||||
|
||||
def test_simple_format_should_escape_unsafe_input
|
||||
assert_equal "<p><b> test with unsafe string </b></p>", simple_format("<b> test with unsafe string </b>")
|
||||
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
|
||||
assert_equal "Hello World!", truncate("Hello World!", :length => 12)
|
||||
assert_equal "Hello Wor...", truncate("Hello World!!", :length => 12)
|
||||
|
@ -228,6 +240,8 @@ class TextHelperTest < ActionView::TestCase
|
|||
assert_equal("2 counts", pluralize('2', "count"))
|
||||
assert_equal("1,066 counts", pluralize('1,066', "count"))
|
||||
assert_equal("1.25 counts", pluralize('1.25', "count"))
|
||||
assert_equal("1.0 count", pluralize('1.0', "count"))
|
||||
assert_equal("1.00 count", pluralize('1.00', "count"))
|
||||
assert_equal("2 counters", pluralize(2, "count", "counters"))
|
||||
assert_equal("0 counters", pluralize(nil, "count", "counters"))
|
||||
assert_equal("2 people", pluralize(2, "person"))
|
||||
|
|
|
@ -1,5 +1,16 @@
|
|||
*Edge*
|
||||
|
||||
* ActiveModel::Observer#add_observer!
|
||||
|
||||
It has a custom hook to define after_find that should really be in a
|
||||
ActiveRecord::Observer subclass:
|
||||
|
||||
def add_observer!(klass)
|
||||
klass.add_observer(self)
|
||||
klass.class_eval 'def after_find() end' unless
|
||||
klass.respond_to?(:after_find)
|
||||
end
|
||||
|
||||
* Change the ActiveModel::Base.include_root_in_json default to true for Rails 3 [DHH]
|
||||
|
||||
* Add validates_format_of :without => /regexp/ option. #430 [Elliot Winkler, Peer Allan]
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
Changes from extracting bits to ActiveModel
|
||||
|
||||
* ActiveModel::Observer#add_observer!
|
||||
|
||||
It has a custom hook to define after_find that should really be in a
|
||||
ActiveRecord::Observer subclass:
|
||||
|
||||
def add_observer!(klass)
|
||||
klass.add_observer(self)
|
||||
klass.class_eval 'def after_find() end' unless
|
||||
klass.respond_to?(:after_find)
|
||||
end
|
|
@ -32,13 +32,13 @@ require 'rake/rdoctask'
|
|||
|
||||
# Generate the RDoc documentation
|
||||
Rake::RDocTask.new do |rdoc|
|
||||
rdoc.rdoc_dir = "#{dir}/doc"
|
||||
rdoc.rdoc_dir = "doc"
|
||||
rdoc.title = "Active Model"
|
||||
rdoc.options << '--line-numbers' << '--inline-source' << '-A cattr_accessor=object'
|
||||
rdoc.options << '--charset' << 'utf-8'
|
||||
rdoc.template = ENV['template'] ? "#{ENV['template']}.rb" : '../doc/template/horo'
|
||||
rdoc.rdoc_files.include("#{dir}/README", "#{dir}/CHANGES")
|
||||
rdoc.rdoc_files.include("#{dir}/lib/**/*.rb")
|
||||
rdoc.rdoc_files.include("README", "CHANGELOG")
|
||||
rdoc.rdoc_files.include("lib/**/*.rb")
|
||||
end
|
||||
|
||||
|
||||
|
@ -50,3 +50,10 @@ spec = eval(File.read("#{dir}/activemodel.gemspec"))
|
|||
Rake::GemPackageTask.new(spec) do |p|
|
||||
p.gem_spec = spec
|
||||
end
|
||||
|
||||
desc "Release to gemcutter"
|
||||
task :release => :package do
|
||||
require 'rake/gemcutter'
|
||||
Rake::Gemcutter::Tasks.new(spec).define
|
||||
Rake::Task['gem:push'].invoke
|
||||
end
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
Gem::Specification.new do |s|
|
||||
s.platform = Gem::Platform::RUBY
|
||||
s.name = 'activemodel'
|
||||
s.version = '3.0.0.beta'
|
||||
s.version = '3.0.0.beta1'
|
||||
s.summary = "A toolkit for building other modeling frameworks like ActiveRecord"
|
||||
s.description = %q{Extracts common modeling concerns from ActiveRecord to share between similar frameworks like ActiveResource.}
|
||||
s.required_ruby_version = '>= 1.8.7'
|
||||
|
||||
s.author = "David Heinemeier Hansson"
|
||||
s.email = "david@loudthinking.com"
|
||||
|
@ -12,7 +13,7 @@ Gem::Specification.new do |s|
|
|||
|
||||
s.has_rdoc = true
|
||||
|
||||
s.add_dependency('activesupport', '= 3.0.0.beta')
|
||||
s.add_dependency('activesupport', '= 3.0.0.beta1')
|
||||
|
||||
s.require_path = 'lib'
|
||||
s.files = Dir["CHANGELOG", "MIT-LICENSE", "README", "lib/**/*"]
|
||||
|
|
|
@ -2,7 +2,7 @@ module ActiveModel
|
|||
module VERSION #:nodoc:
|
||||
MAJOR = 3
|
||||
MINOR = 0
|
||||
TINY = "0.beta"
|
||||
TINY = "0.beta1"
|
||||
|
||||
STRING = [MAJOR, MINOR, TINY].join('.')
|
||||
end
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
*Edge*
|
||||
|
||||
* Silenced "SHOW FIELDS" and "SET SQL_AUTO_IS_NULL=0" statements from the MySQL driver to improve log signal to noise ration in development [DHH]
|
||||
|
||||
|
||||
*Rails 3.0 [Beta] (February 4th, 2010)*
|
||||
|
||||
* PostgreSQLAdapter: set time_zone to UTC when Base.default_timezone == :utc so that Postgres doesn't incorrectly offset-adjust values inserted into TIMESTAMP WITH TIME ZONE columns. #3777 [Jack Christensen]
|
||||
|
||||
* Allow relations to be used as scope.
|
||||
|
|
|
@ -226,11 +226,11 @@ end
|
|||
|
||||
# Publishing ------------------------------------------------------
|
||||
|
||||
desc "Publish the beta gem"
|
||||
task :pgem => [:package] do
|
||||
require 'rake/contrib/sshpublisher'
|
||||
Rake::SshFilePublisher.new("gems.rubyonrails.org", "/u/sites/gems/gems", "pkg", "#{PKG_FILE_NAME}.gem").upload
|
||||
`ssh gems.rubyonrails.org '/u/sites/gems/gemupdate.sh'`
|
||||
desc "Release to gemcutter"
|
||||
task :release => :package do
|
||||
require 'rake/gemcutter'
|
||||
Rake::Gemcutter::Tasks.new(spec).define
|
||||
Rake::Task['gem:push'].invoke
|
||||
end
|
||||
|
||||
desc "Publish the API documentation"
|
||||
|
@ -238,15 +238,3 @@ task :pdoc => [:rdoc] do
|
|||
require 'rake/contrib/sshpublisher'
|
||||
Rake::SshDirPublisher.new("wrath.rubyonrails.org", "public_html/ar", "doc").upload
|
||||
end
|
||||
|
||||
desc "Publish the release files to RubyForge."
|
||||
task :release => [ :package ] do
|
||||
require 'rubyforge'
|
||||
require 'rake/contrib/rubyforgepublisher'
|
||||
|
||||
packages = %w( gem tgz zip ).collect{ |ext| "pkg/#{PKG_NAME}-#{PKG_VERSION}.#{ext}" }
|
||||
|
||||
rubyforge = RubyForge.new
|
||||
rubyforge.login
|
||||
rubyforge.add_release(PKG_NAME, PKG_NAME, "REL #{PKG_VERSION}", *packages)
|
||||
end
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
Gem::Specification.new do |s|
|
||||
s.platform = Gem::Platform::RUBY
|
||||
s.name = 'activerecord'
|
||||
s.version = '3.0.0.beta'
|
||||
s.version = '3.0.0.beta1'
|
||||
s.summary = 'Object-relational mapper framework (part of Rails).'
|
||||
s.description = 'Object-relational mapper framework (part of Rails).'
|
||||
s.required_ruby_version = '>= 1.8.7'
|
||||
|
||||
s.author = 'David Heinemeier Hansson'
|
||||
s.email = 'david@loudthinking.com'
|
||||
|
@ -17,7 +18,7 @@ Gem::Specification.new do |s|
|
|||
s.extra_rdoc_files = %w( README )
|
||||
s.rdoc_options.concat ['--main', 'README']
|
||||
|
||||
s.add_dependency('activesupport', '= 3.0.0.beta')
|
||||
s.add_dependency('activemodel', '= 3.0.0.beta')
|
||||
s.add_dependency('arel', '~> 0.2.0')
|
||||
s.add_dependency('activesupport', '= 3.0.0.beta1')
|
||||
s.add_dependency('activemodel', '= 3.0.0.beta1')
|
||||
s.add_dependency('arel', '~> 0.2.1')
|
||||
end
|
||||
|
|
|
@ -55,10 +55,10 @@ module ActiveRecord
|
|||
autoload :Calculations
|
||||
autoload :PredicateBuilder
|
||||
autoload :SpawnMethods
|
||||
autoload :Batches
|
||||
end
|
||||
|
||||
autoload :Base
|
||||
autoload :Batches
|
||||
autoload :Callbacks
|
||||
autoload :DynamicFinderMatch
|
||||
autoload :DynamicScopeMatch
|
||||
|
|
|
@ -119,11 +119,11 @@ module ActiveRecord #:nodoc:
|
|||
class ReadOnlyRecord < ActiveRecordError
|
||||
end
|
||||
|
||||
# ActiveRecord::Transactions::ClassMethods.transaction uses this exception
|
||||
# <tt>ActiveRecord::Transactions::ClassMethods.transaction</tt> uses this exception
|
||||
# to distinguish a deliberate rollback from other exceptional situations.
|
||||
# Normally, raising an exception will cause the +transaction+ method to rollback
|
||||
# the database transaction *and* pass on the exception. But if you raise an
|
||||
# ActiveRecord::Rollback exception, then the database transaction will be rolled back,
|
||||
# <tt>ActiveRecord::Rollback</tt> exception, then the database transaction will be rolled back,
|
||||
# without passing on the exception.
|
||||
#
|
||||
# For example, you could do this in your controller to rollback a transaction:
|
||||
|
@ -557,6 +557,7 @@ module ActiveRecord #:nodoc:
|
|||
alias :colorize_logging= :colorize_logging
|
||||
|
||||
delegate :find, :first, :last, :all, :destroy, :destroy_all, :exists?, :delete, :delete_all, :update, :update_all, :to => :scoped
|
||||
delegate :find_each, :find_in_batches, :to => :scoped
|
||||
delegate :select, :group, :order, :limit, :joins, :where, :preload, :eager_load, :includes, :from, :lock, :readonly, :having, :to => :scoped
|
||||
delegate :count, :average, :minimum, :maximum, :sum, :calculate, :to => :scoped
|
||||
|
||||
|
@ -2394,7 +2395,7 @@ module ActiveRecord #:nodoc:
|
|||
# #save_with_autosave_associations to be wrapped inside a transaction.
|
||||
include AutosaveAssociation, NestedAttributes
|
||||
|
||||
include Aggregations, Transactions, Reflection, Batches, Serialization
|
||||
include Aggregations, Transactions, Reflection, Serialization
|
||||
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,79 +0,0 @@
|
|||
module ActiveRecord
|
||||
module Batches # :nodoc:
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
# When processing large numbers of records, it's often a good idea to do
|
||||
# so in batches to prevent memory ballooning.
|
||||
module ClassMethods
|
||||
# Yields each record that was found by the find +options+. The find is
|
||||
# performed by find_in_batches with a batch size of 1000 (or as
|
||||
# specified by the <tt>:batch_size</tt> option).
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# Person.find_each(:conditions => "age > 21") do |person|
|
||||
# person.party_all_night!
|
||||
# end
|
||||
#
|
||||
# Note: This method is only intended to use for batch processing of
|
||||
# large amounts of records that wouldn't fit in memory all at once. If
|
||||
# you just need to loop over less than 1000 records, it's probably
|
||||
# better just to use the regular find methods.
|
||||
def find_each(options = {})
|
||||
find_in_batches(options) do |records|
|
||||
records.each { |record| yield record }
|
||||
end
|
||||
|
||||
self
|
||||
end
|
||||
|
||||
# Yields each batch of records that was found by the find +options+ as
|
||||
# an array. The size of each batch is set by the <tt>:batch_size</tt>
|
||||
# option; the default is 1000.
|
||||
#
|
||||
# You can control the starting point for the batch processing by
|
||||
# supplying the <tt>:start</tt> option. This is especially useful if you
|
||||
# want multiple workers dealing with the same processing queue. You can
|
||||
# make worker 1 handle all the records between id 0 and 10,000 and
|
||||
# worker 2 handle from 10,000 and beyond (by setting the <tt>:start</tt>
|
||||
# option on that worker).
|
||||
#
|
||||
# It's not possible to set the order. That is automatically set to
|
||||
# ascending on the primary key ("id ASC") to make the batch ordering
|
||||
# work. This also mean that this method only works with integer-based
|
||||
# primary keys. You can't set the limit either, that's used to control
|
||||
# the the batch sizes.
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# Person.find_in_batches(:conditions => "age > 21") do |group|
|
||||
# sleep(50) # Make sure it doesn't get too crowded in there!
|
||||
# group.each { |person| person.party_all_night! }
|
||||
# end
|
||||
def find_in_batches(options = {})
|
||||
raise "You can't specify an order, it's forced to be #{batch_order}" if options[:order]
|
||||
raise "You can't specify a limit, it's forced to be the batch_size" if options[:limit]
|
||||
|
||||
start = options.delete(:start).to_i
|
||||
batch_size = options.delete(:batch_size) || 1000
|
||||
|
||||
with_scope(:find => options.merge(:order => batch_order, :limit => batch_size)) do
|
||||
records = find(:all, :conditions => [ "#{table_name}.#{primary_key} >= ?", start ])
|
||||
|
||||
while records.any?
|
||||
yield records
|
||||
|
||||
break if records.size < batch_size
|
||||
records = find(:all, :conditions => [ "#{table_name}.#{primary_key} > ?", records.last.id ])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
def batch_order
|
||||
"#{table_name}.#{primary_key} ASC"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -321,7 +321,11 @@ module ActiveRecord
|
|||
|
||||
# Executes a SQL query and returns a MySQL::Result object. Note that you have to free the Result object after you're done using it.
|
||||
def execute(sql, name = nil) #:nodoc:
|
||||
log(sql, name) { @connection.query(sql) }
|
||||
if name == :skip_logging
|
||||
@connection.query(sql)
|
||||
else
|
||||
log(sql, name) { @connection.query(sql) }
|
||||
end
|
||||
rescue ActiveRecord::StatementInvalid => exception
|
||||
if exception.message.split(":").first =~ /Packets out of order/
|
||||
raise ActiveRecord::StatementInvalid, "'Packets out of order' error was received from the database. Please update your mysql bindings (gem install mysql) and read http://dev.mysql.com/doc/mysql/en/password-hashing.html for more information. If you're on Windows, use the Instant Rails installer to get the updated mysql bindings."
|
||||
|
@ -456,7 +460,7 @@ module ActiveRecord
|
|||
def columns(table_name, name = nil)#:nodoc:
|
||||
sql = "SHOW FIELDS FROM #{quote_table_name(table_name)}"
|
||||
columns = []
|
||||
result = execute(sql, name)
|
||||
result = execute(sql, :skip_logging)
|
||||
result.each { |field| columns << MysqlColumn.new(field[0], field[4], field[1], field[2] == "YES") }
|
||||
result.free
|
||||
columns
|
||||
|
@ -616,11 +620,11 @@ module ActiveRecord
|
|||
|
||||
def configure_connection
|
||||
encoding = @config[:encoding]
|
||||
execute("SET NAMES '#{encoding}'") if encoding
|
||||
execute("SET NAMES '#{encoding}'", :skip_logging) if encoding
|
||||
|
||||
# By default, MySQL 'where id is null' selects the last inserted id.
|
||||
# Turn this off. http://dev.rubyonrails.org/ticket/6778
|
||||
execute("SET SQL_AUTO_IS_NULL=0")
|
||||
execute("SET SQL_AUTO_IS_NULL=0", :skip_logging)
|
||||
end
|
||||
|
||||
def select(sql, name = nil)
|
||||
|
|
|
@ -107,7 +107,7 @@ module ActiveRecord
|
|||
# The Rails package has several tools to help create and apply migrations.
|
||||
#
|
||||
# To generate a new migration, you can use
|
||||
# script/generate migration MyNewMigration
|
||||
# rails generate migration MyNewMigration
|
||||
#
|
||||
# where MyNewMigration is the name of your migration. The generator will
|
||||
# create an empty migration file <tt>timestamp_my_new_migration.rb</tt> in the <tt>db/migrate/</tt>
|
||||
|
@ -117,7 +117,7 @@ module ActiveRecord
|
|||
# MyNewMigration.
|
||||
#
|
||||
# There is a special syntactic shortcut to generate migrations that add fields to a table.
|
||||
# script/generate migration add_fieldname_to_tablename fieldname:string
|
||||
# rails generate migration add_fieldname_to_tablename fieldname:string
|
||||
#
|
||||
# This will generate the file <tt>timestamp_add_fieldname_to_tablename</tt>, which will look like this:
|
||||
# class AddFieldnameToTablename < ActiveRecord::Migration
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
require "active_record"
|
||||
require "rails"
|
||||
require "active_model/railtie"
|
||||
|
||||
# For now, action_controller must always be present with
|
||||
# rails, so let's make sure that it gets required before
|
||||
# here. This is needed for correctly setting up the middleware.
|
||||
# In the future, this might become an optional require.
|
||||
require "active_record"
|
||||
require "action_controller/railtie"
|
||||
require "rails"
|
||||
|
||||
module ActiveRecord
|
||||
class Railtie < Rails::Railtie
|
||||
|
|
|
@ -5,7 +5,7 @@ module ActiveRecord
|
|||
MULTI_VALUE_METHODS = [:select, :group, :order, :joins, :where, :having]
|
||||
SINGLE_VALUE_METHODS = [:limit, :offset, :lock, :readonly, :create_with, :from]
|
||||
|
||||
include FinderMethods, Calculations, SpawnMethods, QueryMethods
|
||||
include FinderMethods, Calculations, SpawnMethods, QueryMethods, Batches
|
||||
|
||||
delegate :length, :collect, :map, :each, :all?, :include?, :to => :to_a
|
||||
delegate :insert, :to => :arel
|
||||
|
|
78
activerecord/lib/active_record/relation/batches.rb
Normal file
78
activerecord/lib/active_record/relation/batches.rb
Normal file
|
@ -0,0 +1,78 @@
|
|||
module ActiveRecord
|
||||
module Batches # :nodoc:
|
||||
# Yields each record that was found by the find +options+. The find is
|
||||
# performed by find_in_batches with a batch size of 1000 (or as
|
||||
# specified by the <tt>:batch_size</tt> option).
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# Person.where("age > 21").find_each do |person|
|
||||
# person.party_all_night!
|
||||
# end
|
||||
#
|
||||
# Note: This method is only intended to use for batch processing of
|
||||
# large amounts of records that wouldn't fit in memory all at once. If
|
||||
# you just need to loop over less than 1000 records, it's probably
|
||||
# better just to use the regular find methods.
|
||||
def find_each(options = {})
|
||||
find_in_batches(options) do |records|
|
||||
records.each { |record| yield record }
|
||||
end
|
||||
|
||||
self
|
||||
end
|
||||
|
||||
# Yields each batch of records that was found by the find +options+ as
|
||||
# an array. The size of each batch is set by the <tt>:batch_size</tt>
|
||||
# option; the default is 1000.
|
||||
#
|
||||
# You can control the starting point for the batch processing by
|
||||
# supplying the <tt>:start</tt> option. This is especially useful if you
|
||||
# want multiple workers dealing with the same processing queue. You can
|
||||
# make worker 1 handle all the records between id 0 and 10,000 and
|
||||
# worker 2 handle from 10,000 and beyond (by setting the <tt>:start</tt>
|
||||
# option on that worker).
|
||||
#
|
||||
# It's not possible to set the order. That is automatically set to
|
||||
# ascending on the primary key ("id ASC") to make the batch ordering
|
||||
# work. This also mean that this method only works with integer-based
|
||||
# primary keys. You can't set the limit either, that's used to control
|
||||
# the the batch sizes.
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# Person.where("age > 21").find_in_batches do |group|
|
||||
# sleep(50) # Make sure it doesn't get too crowded in there!
|
||||
# group.each { |person| person.party_all_night! }
|
||||
# end
|
||||
def find_in_batches(options = {})
|
||||
relation = self
|
||||
|
||||
if (finder_options = options.except(:start, :batch_size)).present?
|
||||
raise "You can't specify an order, it's forced to be #{batch_order}" if options[:order].present?
|
||||
raise "You can't specify a limit, it's forced to be the batch_size" if options[:limit].present?
|
||||
|
||||
relation = apply_finder_options(finder_options)
|
||||
end
|
||||
|
||||
start = options.delete(:start).to_i
|
||||
batch_size = options.delete(:batch_size) || 1000
|
||||
|
||||
relation = relation.except(:order).order(batch_order).limit(batch_size)
|
||||
records = relation.where(primary_key.gteq(start)).all
|
||||
|
||||
while records.any?
|
||||
yield records
|
||||
|
||||
break if records.size < batch_size
|
||||
records = relation.where(primary_key.gt(records.last.id)).all
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def batch_order
|
||||
"#{@klass.table_name}.#{@klass.primary_key} ASC"
|
||||
end
|
||||
end
|
||||
end
|
|
@ -2,7 +2,7 @@ module ActiveRecord
|
|||
module VERSION #:nodoc:
|
||||
MAJOR = 3
|
||||
MINOR = 0
|
||||
TINY = "0.beta"
|
||||
TINY = "0.beta1"
|
||||
|
||||
STRING = [MAJOR, MINOR, TINY].join('.')
|
||||
end
|
||||
|
|
|
@ -157,9 +157,9 @@ class ValidationsTest < ActiveRecord::TestCase
|
|||
end
|
||||
|
||||
def test_validates_acceptance_of_as_database_column
|
||||
Topic.validates_acceptance_of(:author_name)
|
||||
topic = Topic.create("author_name" => "Dan Brown")
|
||||
assert_equal "Dan Brown", topic["author_name"]
|
||||
Topic.validates_acceptance_of(:approved)
|
||||
topic = Topic.create("approved" => true)
|
||||
assert topic["approved"]
|
||||
end
|
||||
|
||||
def test_validate_is_deprecated_on_create
|
||||
|
|
|
@ -89,11 +89,11 @@ end
|
|||
|
||||
# Publishing ------------------------------------------------------
|
||||
|
||||
desc "Publish the beta gem"
|
||||
task :pgem => [:package] do
|
||||
require 'rake/contrib/sshpublisher'
|
||||
Rake::SshFilePublisher.new("gems.rubyonrails.org", "/u/sites/gems/gems", "pkg", "#{PKG_FILE_NAME}.gem").upload
|
||||
`ssh gems.rubyonrails.org '/u/sites/gems/gemupdate.sh'`
|
||||
desc "Release to gemcutter"
|
||||
task :release => :package do
|
||||
require 'rake/gemcutter'
|
||||
Rake::Gemcutter::Tasks.new(spec).define
|
||||
Rake::Task['gem:push'].invoke
|
||||
end
|
||||
|
||||
desc "Publish the API documentation"
|
||||
|
@ -101,14 +101,3 @@ task :pdoc => [:rdoc] do
|
|||
require 'rake/contrib/sshpublisher'
|
||||
Rake::SshDirPublisher.new("wrath.rubyonrails.org", "public_html/ar", "doc").upload
|
||||
end
|
||||
|
||||
desc "Publish the release files to RubyForge."
|
||||
task :release => [ :package ] do
|
||||
`rubyforge login`
|
||||
|
||||
for ext in %w( gem tgz zip )
|
||||
release_command = "rubyforge add_release #{PKG_NAME} #{PKG_NAME} 'REL #{PKG_VERSION}' pkg/#{PKG_NAME}-#{PKG_VERSION}.#{ext}"
|
||||
puts release_command
|
||||
system(release_command)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
Gem::Specification.new do |s|
|
||||
s.platform = Gem::Platform::RUBY
|
||||
s.name = 'activeresource'
|
||||
s.version = '3.0.0.beta'
|
||||
s.version = '3.0.0.beta1'
|
||||
s.summary = 'REST-model framework (part of Rails).'
|
||||
s.description = 'REST-model framework (part of Rails).'
|
||||
s.required_ruby_version = '>= 1.8.7'
|
||||
|
||||
s.author = 'David Heinemeier Hansson'
|
||||
s.email = 'david@loudthinking.com'
|
||||
|
@ -17,6 +18,6 @@ Gem::Specification.new do |s|
|
|||
s.extra_rdoc_files = %w( README )
|
||||
s.rdoc_options.concat ['--main', 'README']
|
||||
|
||||
s.add_dependency('activesupport', '= 3.0.0.beta')
|
||||
s.add_dependency('activemodel', '= 3.0.0.beta')
|
||||
s.add_dependency('activesupport', '= 3.0.0.beta1')
|
||||
s.add_dependency('activemodel', '= 3.0.0.beta1')
|
||||
end
|
||||
|
|
|
@ -2,7 +2,7 @@ module ActiveResource
|
|||
module VERSION #:nodoc:
|
||||
MAJOR = 3
|
||||
MINOR = 0
|
||||
TINY = "0.beta"
|
||||
TINY = "0.beta1"
|
||||
|
||||
STRING = [MAJOR, MINOR, TINY].join('.')
|
||||
end
|
||||
|
|
|
@ -4,6 +4,7 @@ require 'rubygems'
|
|||
require 'test/unit'
|
||||
require 'active_resource'
|
||||
require 'active_support'
|
||||
require 'active_support/test_case'
|
||||
|
||||
$:.unshift "#{File.dirname(__FILE__)}/../test"
|
||||
require 'setter_trap'
|
||||
|
|
|
@ -5,6 +5,7 @@ require "fixtures/street_address"
|
|||
require "fixtures/beast"
|
||||
require "fixtures/proxy"
|
||||
require 'active_support/core_ext/hash/conversions'
|
||||
require 'mocha'
|
||||
|
||||
class BaseTest < Test::Unit::TestCase
|
||||
def setup
|
||||
|
@ -98,10 +99,15 @@ class BaseTest < Test::Unit::TestCase
|
|||
mock.get "/customers/1.xml", {}, @luis
|
||||
end
|
||||
|
||||
@original_person_site = Person.site
|
||||
Person.user = nil
|
||||
Person.password = nil
|
||||
end
|
||||
|
||||
def teardown
|
||||
Person.site = @original_person_site
|
||||
end
|
||||
|
||||
########################################################################
|
||||
# Tests relating to setting up the API-connection configuration
|
||||
########################################################################
|
||||
|
|
|
@ -2,6 +2,7 @@ require "abstract_unit"
|
|||
require "fixtures/person"
|
||||
require "rails/subscriber/test_helper"
|
||||
require "active_resource/railties/subscriber"
|
||||
require "active_support/core_ext/hash/conversions"
|
||||
|
||||
class SubscriberTest < ActiveSupport::TestCase
|
||||
include Rails::Subscriber::TestHelper
|
||||
|
@ -24,7 +25,7 @@ class SubscriberTest < ActiveSupport::TestCase
|
|||
matz = Person.find(1)
|
||||
wait
|
||||
assert_equal 2, @logger.logged(:info).size
|
||||
assert_equal "GET http://somewhere.else:80/people/1.xml", @logger.logged(:info)[0]
|
||||
assert_equal "GET http://37s.sunrise.i:3000/people/1.xml", @logger.logged(:info)[0]
|
||||
assert_match /\-\-\> 200 200 106/, @logger.logged(:info)[1]
|
||||
end
|
||||
end
|
|
@ -1,5 +1,10 @@
|
|||
*Rails 3.0 (pending)*
|
||||
|
||||
* JSON backend for YAJL. Preferred if available. #2666 [Brian Lopez]
|
||||
|
||||
|
||||
*Rails 3.0.0 [beta] (February 4, 2010)*
|
||||
|
||||
* Introduce class_attribute to declare inheritable class attributes. Writing an attribute on a subclass behaves just like overriding the superclass reader method. Unifies and replaces most usage of cattr_accessor, class_inheritable_attribute, superclass_delegating_attribute, and extlib_inheritable_attribute. [Jeremy Kemper, Yehuda Katz]
|
||||
|
||||
* Time#- with a DateTime argument behaves the same as with a Time argument, i.e. returns the difference between self and arg as a Float #3476 [Geoff Buesing]
|
||||
|
|
|
@ -49,11 +49,11 @@ Rake::GemPackageTask.new(spec) do |p|
|
|||
p.gem_spec = spec
|
||||
end
|
||||
|
||||
desc "Publish the beta gem"
|
||||
task :pgem => [:package] do
|
||||
require 'rake/contrib/sshpublisher'
|
||||
Rake::SshFilePublisher.new("gems.rubyonrails.org", "/u/sites/gems/gems", "pkg", "#{PKG_FILE_NAME}.gem").upload
|
||||
`ssh gems.rubyonrails.org '/u/sites/gems/gemupdate.sh'`
|
||||
desc "Release to gemcutter"
|
||||
task :release => :package do
|
||||
require 'rake/gemcutter'
|
||||
Rake::Gemcutter::Tasks.new(spec).define
|
||||
Rake::Task['gem:push'].invoke
|
||||
end
|
||||
|
||||
desc "Publish the API documentation"
|
||||
|
@ -61,15 +61,3 @@ task :pdoc => [:rdoc] do
|
|||
require 'rake/contrib/sshpublisher'
|
||||
Rake::SshDirPublisher.new("wrath.rubyonrails.org", "public_html/as", "doc").upload
|
||||
end
|
||||
|
||||
desc "Publish the release files to RubyForge."
|
||||
task :release => [ :package ] do
|
||||
require 'rubyforge'
|
||||
require 'rake/contrib/rubyforgepublisher'
|
||||
|
||||
packages = %w( gem tgz zip ).collect{ |ext| "pkg/#{PKG_NAME}-#{PKG_VERSION}.#{ext}" }
|
||||
|
||||
rubyforge = RubyForge.new
|
||||
rubyforge.login
|
||||
rubyforge.add_release(PKG_NAME, PKG_NAME, "REL #{PKG_VERSION}", *packages)
|
||||
end
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
Gem::Specification.new do |s|
|
||||
s.platform = Gem::Platform::RUBY
|
||||
s.name = 'activesupport'
|
||||
s.version = '3.0.0.beta'
|
||||
s.version = '3.0.0.beta1'
|
||||
s.summary = 'Support and utility classes used by the Rails framework.'
|
||||
s.description = 'Support and utility classes used by the Rails framework.'
|
||||
s.required_ruby_version = '>= 1.8.7'
|
||||
|
||||
s.author = 'David Heinemeier Hansson'
|
||||
s.email = 'david@loudthinking.com'
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
require 'active_support/core_ext/class/attribute_accessors'
|
||||
require 'active_support/core_ext/class/inheritable_attributes'
|
||||
require 'active_support/core_ext/class/delegating_attributes'
|
||||
require 'active_support/core_ext/class/subclasses'
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
require 'active_support/core_ext/module/anonymous'
|
||||
require 'active_support/core_ext/module/reachable'
|
||||
|
||||
class Class #:nodoc:
|
||||
# Returns an array with the names of the subclasses of +self+ as strings.
|
||||
#
|
||||
# Integer.subclasses # => ["Bignum", "Fixnum"]
|
||||
def subclasses
|
||||
Class.subclasses_of(self).map { |o| o.to_s }
|
||||
end
|
||||
|
||||
# Rubinius
|
||||
if defined?(Class.__subclasses__)
|
||||
def descendents
|
||||
subclasses = []
|
||||
__subclasses__.each {|k| subclasses << k; subclasses.concat k.descendents }
|
||||
subclasses
|
||||
end
|
||||
else
|
||||
# MRI
|
||||
begin
|
||||
ObjectSpace.each_object(Class.new) {}
|
||||
|
||||
def descendents
|
||||
subclasses = []
|
||||
ObjectSpace.each_object(class << self; self; end) do |k|
|
||||
subclasses << k unless k == self
|
||||
end
|
||||
subclasses
|
||||
end
|
||||
# JRuby
|
||||
rescue StandardError
|
||||
def descendents
|
||||
subclasses = []
|
||||
ObjectSpace.each_object(Class) do |k|
|
||||
subclasses << k if k < self
|
||||
end
|
||||
subclasses.uniq!
|
||||
subclasses
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Exclude this class unless it's a subclass of our supers and is defined.
|
||||
# We check defined? in case we find a removed class that has yet to be
|
||||
# garbage collected. This also fails for anonymous classes -- please
|
||||
# submit a patch if you have a workaround.
|
||||
def self.subclasses_of(*superclasses) #:nodoc:
|
||||
subclasses = []
|
||||
superclasses.each do |klass|
|
||||
subclasses.concat klass.descendents.select {|k| k.anonymous? || k.reachable?}
|
||||
end
|
||||
subclasses
|
||||
end
|
||||
end
|
|
@ -9,7 +9,7 @@ class File
|
|||
# If your temp directory is not on the same filesystem as the file you're
|
||||
# trying to write, you can provide a different temporary directory.
|
||||
#
|
||||
# File.atomic_write("/data/something.important", "/data/tmp") do |f|
|
||||
# File.atomic_write("/data/something.important", "/data/tmp") do |file|
|
||||
# file.write("hello")
|
||||
# end
|
||||
def self.atomic_write(file_name, temp_dir = Dir.tmpdir)
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
require 'active_support/core_ext/kernel/daemonizing'
|
||||
require 'active_support/core_ext/kernel/reporting'
|
||||
require 'active_support/core_ext/kernel/agnostics'
|
||||
require 'active_support/core_ext/kernel/requires'
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
module Kernel
|
||||
# Turns the current script into a daemon process that detaches from the console.
|
||||
# It can be shut down with a TERM signal.
|
||||
def daemonize
|
||||
Process.daemon
|
||||
end
|
||||
end
|
|
@ -1,6 +1,6 @@
|
|||
module Kernel
|
||||
unless respond_to?(:debugger)
|
||||
# Starts a debugging session if ruby-debug has been loaded (call script/server --debugger to do load it).
|
||||
# Starts a debugging session if ruby-debug has been loaded (call rails server --debugger to do load it).
|
||||
def debugger
|
||||
message = "\n***** Debugger requested, but was not available: Start server with --debugger to enable *****\n"
|
||||
defined?(Rails) ? Rails.logger.info(message) : $stderr.puts(message)
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
require 'active_support/core_ext/module/aliasing'
|
||||
require 'active_support/core_ext/module/introspection'
|
||||
|
||||
require 'active_support/core_ext/module/inclusion'
|
||||
require 'active_support/core_ext/module/anonymous'
|
||||
require 'active_support/core_ext/module/reachable'
|
||||
require 'active_support/core_ext/module/attribute_accessors'
|
||||
require 'active_support/core_ext/module/attr_internal'
|
||||
require 'active_support/core_ext/module/attr_accessor_with_default'
|
||||
require 'active_support/core_ext/module/delegation'
|
||||
require 'active_support/core_ext/module/loading'
|
||||
require 'active_support/core_ext/module/synchronization'
|
||||
require 'active_support/core_ext/module/deprecation'
|
|
@ -0,0 +1,24 @@
|
|||
require 'active_support/core_ext/object/blank'
|
||||
|
||||
class Module
|
||||
# A module may or may not have a name.
|
||||
#
|
||||
# module M; end
|
||||
# M.name # => "M"
|
||||
#
|
||||
# m = Module.new
|
||||
# m.name # => ""
|
||||
#
|
||||
# A module gets a name when it is first assigned to a constant. Either
|
||||
# via the +module+ or +class+ keyword or by an explicit assignment:
|
||||
#
|
||||
# m = Module.new # creates an anonymous module
|
||||
# M = m # => m gets a name here as a side-effect
|
||||
# m.name # => "M"
|
||||
#
|
||||
def anonymous?
|
||||
# Uses blank? because the name of an anonymous class is an empty
|
||||
# string in 1.8, and nil in 1.9.
|
||||
name.blank?
|
||||
end
|
||||
end
|
|
@ -1,30 +0,0 @@
|
|||
class Module
|
||||
# Returns the classes in the current ObjectSpace where this module has been
|
||||
# mixed in according to Module#included_modules.
|
||||
#
|
||||
# module M
|
||||
# end
|
||||
#
|
||||
# module N
|
||||
# include M
|
||||
# end
|
||||
#
|
||||
# class C
|
||||
# include M
|
||||
# end
|
||||
#
|
||||
# class D < C
|
||||
# end
|
||||
#
|
||||
# p M.included_in_classes # => [C, D]
|
||||
#
|
||||
def included_in_classes
|
||||
classes = []
|
||||
ObjectSpace.each_object(Class) { |k| classes << k if k.included_modules.include?(self) }
|
||||
|
||||
classes.reverse.inject([]) do |unique_classes, klass|
|
||||
unique_classes << klass unless unique_classes.collect { |k| k.to_s }.include?(klass.to_s)
|
||||
unique_classes
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,25 +0,0 @@
|
|||
require 'active_support/core_ext/string/inflections'
|
||||
|
||||
class Module
|
||||
# Returns String#underscore applied to the module name minus trailing classes.
|
||||
#
|
||||
# ActiveRecord.as_load_path # => "active_record"
|
||||
# ActiveRecord::Associations.as_load_path # => "active_record/associations"
|
||||
# ActiveRecord::Base.as_load_path # => "active_record" (Base is a class)
|
||||
#
|
||||
# The Kernel module gives an empty string by definition.
|
||||
#
|
||||
# Kernel.as_load_path # => ""
|
||||
# Math.as_load_path # => "math"
|
||||
def as_load_path
|
||||
if self == Object || self == Kernel
|
||||
''
|
||||
elsif is_a? Class
|
||||
parent == self ? '' : parent.as_load_path
|
||||
else
|
||||
name.split('::').collect do |word|
|
||||
word.underscore
|
||||
end * '/'
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,10 @@
|
|||
require 'active_support/core_ext/module/anonymous'
|
||||
require 'active_support/core_ext/string/inflections'
|
||||
|
||||
class Module
|
||||
def reachable? #:nodoc:
|
||||
!anonymous? && name.constantize.equal?(self)
|
||||
rescue NameError
|
||||
false
|
||||
end
|
||||
end
|
|
@ -7,3 +7,9 @@ require 'active_support/core_ext/object/conversions'
|
|||
require 'active_support/core_ext/object/instance_variables'
|
||||
require 'active_support/core_ext/object/metaclass'
|
||||
require 'active_support/core_ext/object/misc'
|
||||
require 'active_support/core_ext/object/extending'
|
||||
|
||||
require 'active_support/core_ext/object/returning'
|
||||
require 'active_support/core_ext/object/to_param'
|
||||
require 'active_support/core_ext/object/to_query'
|
||||
require 'active_support/core_ext/object/with_options'
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
require 'active_support/core_ext/class/subclasses'
|
||||
|
||||
class Object
|
||||
# Exclude this class unless it's a subclass of our supers and is defined.
|
||||
# We check defined? in case we find a removed class that has yet to be
|
||||
# garbage collected. This also fails for anonymous classes -- please
|
||||
# submit a patch if you have a workaround.
|
||||
def subclasses_of(*superclasses) #:nodoc:
|
||||
Class.subclasses_of(*superclasses)
|
||||
end
|
||||
end
|
|
@ -71,15 +71,12 @@ module ActiveSupport #:nodoc:
|
|||
super(ERB::Util.h(value))
|
||||
end
|
||||
end
|
||||
alias << concat
|
||||
|
||||
def +(other)
|
||||
dup.concat(other)
|
||||
end
|
||||
|
||||
def <<(value)
|
||||
self.concat(value)
|
||||
end
|
||||
|
||||
def html_safe?
|
||||
true
|
||||
end
|
||||
|
@ -102,4 +99,4 @@ class String
|
|||
def html_safe
|
||||
ActiveSupport::SafeBuffer.new(self)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
begin
|
||||
# See http://bogomips.org/fast_xs/ by Eric Wong.
|
||||
# See http://fast-xs.rubyforge.org/ by Eric Wong.
|
||||
# Also included with hpricot.
|
||||
require 'fast_xs'
|
||||
rescue LoadError
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
require 'set'
|
||||
require 'thread'
|
||||
require 'pathname'
|
||||
require 'active_support/core_ext/module/aliasing'
|
||||
require 'active_support/core_ext/module/attribute_accessors'
|
||||
require 'active_support/core_ext/module/introspection'
|
||||
require 'active_support/core_ext/module/anonymous'
|
||||
require 'active_support/core_ext/object/blank'
|
||||
require 'active_support/core_ext/load_error'
|
||||
require 'active_support/core_ext/name_error'
|
||||
|
@ -58,37 +60,105 @@ module ActiveSupport #:nodoc:
|
|||
mattr_accessor :log_activity
|
||||
self.log_activity = false
|
||||
|
||||
class WatchStack < Array
|
||||
def initialize
|
||||
@mutex = Mutex.new
|
||||
end
|
||||
|
||||
def self.locked(*methods)
|
||||
methods.each { |m| class_eval "def #{m}(*) lock { super } end" }
|
||||
end
|
||||
|
||||
def get(key)
|
||||
(val = assoc(key)) ? val[1] : []
|
||||
end
|
||||
|
||||
locked :concat, :each, :delete_if, :<<
|
||||
|
||||
def new_constants_for(frames)
|
||||
frames.map do |mod_name, prior_constants|
|
||||
mod = Inflector.constantize(mod_name)
|
||||
next unless mod.is_a?(Module)
|
||||
|
||||
new_constants = mod.local_constant_names - prior_constants
|
||||
get(mod_name).concat(new_constants)
|
||||
|
||||
new_constants.map do |suffix|
|
||||
([mod_name, suffix] - ["Object"]).join("::")
|
||||
end
|
||||
end.flatten
|
||||
end
|
||||
|
||||
# Add a set of modules to the watch stack, remembering the initial constants
|
||||
def add_modules(modules)
|
||||
list = modules.map do |desc|
|
||||
name = Dependencies.to_constant_name(desc)
|
||||
consts = Dependencies.qualified_const_defined?(name) ?
|
||||
Inflector.constantize(name).local_constant_names : []
|
||||
[name, consts]
|
||||
end
|
||||
concat(list)
|
||||
list
|
||||
end
|
||||
|
||||
def lock
|
||||
@mutex.synchronize { yield self }
|
||||
end
|
||||
end
|
||||
|
||||
# An internal stack used to record which constants are loaded by any block.
|
||||
mattr_accessor :constant_watch_stack
|
||||
self.constant_watch_stack = []
|
||||
|
||||
mattr_accessor :constant_watch_stack_mutex
|
||||
self.constant_watch_stack_mutex = Mutex.new
|
||||
self.constant_watch_stack = WatchStack.new
|
||||
|
||||
# Module includes this module
|
||||
module ModuleConstMissing #:nodoc:
|
||||
def self.included(base) #:nodoc:
|
||||
def self.append_features(base)
|
||||
base.class_eval do
|
||||
unless defined? const_missing_without_dependencies
|
||||
alias_method_chain :const_missing, :dependencies
|
||||
end
|
||||
# Emulate #exclude via an ivar
|
||||
return if @_const_missing
|
||||
@_const_missing = method(:const_missing)
|
||||
remove_method(:const_missing)
|
||||
end
|
||||
super
|
||||
end
|
||||
|
||||
def self.excluded(base) #:nodoc:
|
||||
def self.exclude_from(base)
|
||||
base.class_eval do
|
||||
if defined? const_missing_without_dependencies
|
||||
undef_method :const_missing
|
||||
alias_method :const_missing, :const_missing_without_dependencies
|
||||
undef_method :const_missing_without_dependencies
|
||||
end
|
||||
define_method :const_missing, @_const_missing
|
||||
@_const_missing = nil
|
||||
end
|
||||
end
|
||||
|
||||
# Use const_missing to autoload associations so we don't have to
|
||||
# require_association when using single-table inheritance.
|
||||
def const_missing_with_dependencies(class_id)
|
||||
ActiveSupport::Dependencies.load_missing_constant self, class_id
|
||||
def const_missing(const_name, nesting = nil)
|
||||
klass_name = name.presence || "Object"
|
||||
|
||||
if !nesting
|
||||
# We'll assume that the nesting of Foo::Bar is ["Foo::Bar", "Foo"]
|
||||
# even though it might not be, such as in the case of
|
||||
# class Foo::Bar; Baz; end
|
||||
nesting = []
|
||||
klass_name.to_s.scan(/::|$/) { nesting.unshift $` }
|
||||
end
|
||||
|
||||
# If there are multiple levels of nesting to search under, the top
|
||||
# level is the one we want to report as the lookup fail.
|
||||
error = nil
|
||||
|
||||
nesting.each do |namespace|
|
||||
begin
|
||||
return Dependencies.load_missing_constant namespace.constantize, const_name
|
||||
rescue NoMethodError then raise
|
||||
rescue NameError => e
|
||||
error ||= e
|
||||
end
|
||||
end
|
||||
|
||||
# Raise the first error for this set. If this const_missing came from an
|
||||
# earlier const_missing, this will result in the real error bubbling
|
||||
# all the way up
|
||||
raise error
|
||||
end
|
||||
|
||||
def unloadable(const_desc = self)
|
||||
|
@ -96,47 +166,10 @@ module ActiveSupport #:nodoc:
|
|||
end
|
||||
end
|
||||
|
||||
# Class includes this module
|
||||
module ClassConstMissing #:nodoc:
|
||||
def const_missing(const_name)
|
||||
if [Object, Kernel].include?(self) || parent == self
|
||||
super
|
||||
else
|
||||
begin
|
||||
begin
|
||||
Dependencies.load_missing_constant self, const_name
|
||||
rescue NameError
|
||||
parent.send :const_missing, const_name
|
||||
end
|
||||
rescue NameError => e
|
||||
# Make sure that the name we are missing is the one that caused the error
|
||||
parent_qualified_name = Dependencies.qualified_name_for parent, const_name
|
||||
raise unless e.missing_name? parent_qualified_name
|
||||
qualified_name = Dependencies.qualified_name_for self, const_name
|
||||
raise NameError.new("uninitialized constant #{qualified_name}").copy_blame!(e)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Object includes this module
|
||||
module Loadable #:nodoc:
|
||||
def self.included(base) #:nodoc:
|
||||
base.class_eval do
|
||||
unless defined? load_without_new_constant_marking
|
||||
alias_method_chain :load, :new_constant_marking
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def self.excluded(base) #:nodoc:
|
||||
base.class_eval do
|
||||
if defined? load_without_new_constant_marking
|
||||
undef_method :load
|
||||
alias_method :load, :load_without_new_constant_marking
|
||||
undef_method :load_without_new_constant_marking
|
||||
end
|
||||
end
|
||||
def self.exclude_from(base)
|
||||
base.class_eval { define_method(:load, Kernel.instance_method(:load)) }
|
||||
end
|
||||
|
||||
def require_or_load(file_name)
|
||||
|
@ -151,26 +184,23 @@ module ActiveSupport #:nodoc:
|
|||
Dependencies.associate_with(file_name)
|
||||
end
|
||||
|
||||
def load_with_new_constant_marking(file, *extras) #:nodoc:
|
||||
def load_dependency(file)
|
||||
if Dependencies.load?
|
||||
Dependencies.new_constants_in(Object) { load_without_new_constant_marking(file, *extras) }
|
||||
Dependencies.new_constants_in(Object) { yield }.presence
|
||||
else
|
||||
load_without_new_constant_marking(file, *extras)
|
||||
yield
|
||||
end
|
||||
rescue Exception => exception # errors from loading file
|
||||
exception.blame_file! file
|
||||
raise
|
||||
end
|
||||
|
||||
def require(file, *extras) #:nodoc:
|
||||
if Dependencies.load?
|
||||
Dependencies.new_constants_in(Object) { super }
|
||||
else
|
||||
super
|
||||
end
|
||||
rescue Exception => exception # errors from required file
|
||||
exception.blame_file! file
|
||||
raise
|
||||
def load(file, *)
|
||||
load_dependency(file) { super }
|
||||
end
|
||||
|
||||
def require(file, *)
|
||||
load_dependency(file) { super }
|
||||
end
|
||||
|
||||
# Mark the given constant as unloadable. Unloadable constants are removed each
|
||||
|
@ -213,16 +243,15 @@ module ActiveSupport #:nodoc:
|
|||
end
|
||||
|
||||
def hook!
|
||||
Object.instance_eval { include Loadable }
|
||||
Module.instance_eval { include ModuleConstMissing }
|
||||
Class.instance_eval { include ClassConstMissing }
|
||||
Exception.instance_eval { include Blamable }
|
||||
Object.class_eval { include Loadable }
|
||||
Module.class_eval { include ModuleConstMissing }
|
||||
Exception.class_eval { include Blamable }
|
||||
true
|
||||
end
|
||||
|
||||
def unhook!
|
||||
ModuleConstMissing.excluded(Module)
|
||||
Loadable.excluded(Object)
|
||||
ModuleConstMissing.exclude_from(Module)
|
||||
Loadable.exclude_from(Object)
|
||||
true
|
||||
end
|
||||
|
||||
|
@ -292,29 +321,22 @@ module ActiveSupport #:nodoc:
|
|||
|
||||
# Is the provided constant path defined?
|
||||
def qualified_const_defined?(path)
|
||||
raise NameError, "#{path.inspect} is not a valid constant name!" unless
|
||||
/^(::)?([A-Z]\w*)(::[A-Z]\w*)*$/ =~ path
|
||||
names = path.sub(/^::/, '').to_s.split('::')
|
||||
|
||||
names = path.to_s.split('::')
|
||||
names.shift if names.first.empty?
|
||||
|
||||
# We can't use defined? because it will invoke const_missing for the parent
|
||||
# of the name we are checking.
|
||||
names.inject(Object) do |mod, name|
|
||||
return false unless uninherited_const_defined?(mod, name)
|
||||
return false unless local_const_defined?(mod, name)
|
||||
mod.const_get name
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
if Module.method(:const_defined?).arity == 1
|
||||
# Does this module define this constant?
|
||||
# Wrapper to accomodate changing Module#const_defined? in Ruby 1.9
|
||||
def uninherited_const_defined?(mod, const)
|
||||
def local_const_defined?(mod, const)
|
||||
mod.const_defined?(const)
|
||||
end
|
||||
else
|
||||
def uninherited_const_defined?(mod, const) #:nodoc:
|
||||
def local_const_defined?(mod, const) #:nodoc:
|
||||
mod.const_defined?(const, false)
|
||||
end
|
||||
end
|
||||
|
@ -322,29 +344,20 @@ module ActiveSupport #:nodoc:
|
|||
# Given +path+, a filesystem path to a ruby file, return an array of constant
|
||||
# paths which would cause Dependencies to attempt to load this file.
|
||||
def loadable_constants_for_path(path, bases = load_paths)
|
||||
path = $1 if path =~ /\A(.*)\.rb\Z/
|
||||
expanded_path = File.expand_path(path)
|
||||
expanded_path = Pathname.new(path[/\A(.*?)(\.rb)?\Z/, 1]).expand_path
|
||||
|
||||
bases.collect do |root|
|
||||
expanded_root = File.expand_path(root)
|
||||
next unless %r{\A#{Regexp.escape(expanded_root)}(/|\\)} =~ expanded_path
|
||||
|
||||
nesting = expanded_path[(expanded_root.size)..-1]
|
||||
nesting = nesting[1..-1] if nesting && nesting[0] == ?/
|
||||
next if nesting.blank?
|
||||
nesting_camel = nesting.camelize
|
||||
begin
|
||||
qualified_const_defined?(nesting_camel)
|
||||
rescue NameError
|
||||
next
|
||||
end
|
||||
[ nesting_camel ]
|
||||
end.compact.flatten.compact.uniq
|
||||
bases.inject([]) do |paths, root|
|
||||
expanded_root = Pathname.new(root).expand_path
|
||||
nesting = expanded_path.relative_path_from(expanded_root).to_s
|
||||
next paths if nesting =~ /\.\./
|
||||
paths << nesting.camelize
|
||||
end.uniq
|
||||
end
|
||||
|
||||
# Search for a file in load_paths matching the provided suffix.
|
||||
def search_for_file(path_suffix)
|
||||
path_suffix = "#{path_suffix}.rb" unless path_suffix =~ /\.rb\Z/
|
||||
path_suffix = path_suffix.sub(/(\.rb)?$/, ".rb")
|
||||
|
||||
load_paths.each do |root|
|
||||
path = File.join(root, path_suffix)
|
||||
return path if File.file? path
|
||||
|
@ -393,7 +406,7 @@ module ActiveSupport #:nodoc:
|
|||
|
||||
result = nil
|
||||
newly_defined_paths = new_constants_in(*parent_paths) do
|
||||
result = load_without_new_constant_marking path
|
||||
result = Kernel.load path
|
||||
end
|
||||
|
||||
autoloaded_constants.concat newly_defined_paths unless load_once_path?(path)
|
||||
|
@ -405,7 +418,7 @@ module ActiveSupport #:nodoc:
|
|||
# Return the constant path for the provided parent and constant name.
|
||||
def qualified_name_for(mod, name)
|
||||
mod_name = to_constant_name mod
|
||||
(%w(Object Kernel).include? mod_name) ? name.to_s : "#{mod_name}::#{name}"
|
||||
mod_name == "Object" ? name.to_s : "#{mod_name}::#{name}"
|
||||
end
|
||||
|
||||
# Load the constant named +const_name+ which is missing from +from_mod+. If
|
||||
|
@ -413,38 +426,27 @@ module ActiveSupport #:nodoc:
|
|||
# using const_missing.
|
||||
def load_missing_constant(from_mod, const_name)
|
||||
log_call from_mod, const_name
|
||||
if from_mod == Kernel
|
||||
if ::Object.const_defined?(const_name)
|
||||
log "Returning Object::#{const_name} for Kernel::#{const_name}"
|
||||
return ::Object.const_get(const_name)
|
||||
else
|
||||
log "Substituting Object for Kernel"
|
||||
from_mod = Object
|
||||
end
|
||||
end
|
||||
|
||||
# If we have an anonymous module, all we can do is attempt to load from Object.
|
||||
from_mod = Object if from_mod.name.blank?
|
||||
|
||||
unless qualified_const_defined?(from_mod.name) && Inflector.constantize(from_mod.name).object_id == from_mod.object_id
|
||||
unless qualified_const_defined?(from_mod.name) && Inflector.constantize(from_mod.name).equal?(from_mod)
|
||||
raise ArgumentError, "A copy of #{from_mod} has been removed from the module tree but is still active!"
|
||||
end
|
||||
|
||||
raise ArgumentError, "#{from_mod} is not missing constant #{const_name}!" if uninherited_const_defined?(from_mod, const_name)
|
||||
raise ArgumentError, "#{from_mod} is not missing constant #{const_name}!" if local_const_defined?(from_mod, const_name)
|
||||
|
||||
qualified_name = qualified_name_for from_mod, const_name
|
||||
path_suffix = qualified_name.underscore
|
||||
name_error = NameError.new("uninitialized constant #{qualified_name}")
|
||||
|
||||
file_path = search_for_file(path_suffix)
|
||||
|
||||
if file_path && ! loaded.include?(File.expand_path(file_path)) # We found a matching file to load
|
||||
require_or_load file_path
|
||||
raise LoadError, "Expected #{file_path} to define #{qualified_name}" unless uninherited_const_defined?(from_mod, const_name)
|
||||
raise LoadError, "Expected #{file_path} to define #{qualified_name}" unless local_const_defined?(from_mod, const_name)
|
||||
return from_mod.const_get(const_name)
|
||||
elsif mod = autoload_module!(from_mod, const_name, qualified_name, path_suffix)
|
||||
return mod
|
||||
elsif (parent = from_mod.parent) && parent != from_mod &&
|
||||
! from_mod.parents.any? { |p| uninherited_const_defined?(p, const_name) }
|
||||
! from_mod.parents.any? { |p| local_const_defined?(p, const_name) }
|
||||
# If our parents do not have a constant named +const_name+ then we are free
|
||||
# to attempt to load upwards. If they do have such a constant, then this
|
||||
# const_missing must be due to from_mod::const_name, which should not
|
||||
|
@ -471,7 +473,7 @@ module ActiveSupport #:nodoc:
|
|||
# Determine if the given constant has been automatically loaded.
|
||||
def autoloaded?(desc)
|
||||
# No name => anonymous module.
|
||||
return false if desc.is_a?(Module) && desc.name.blank?
|
||||
return false if desc.is_a?(Module) && desc.anonymous?
|
||||
name = to_constant_name desc
|
||||
return false unless qualified_const_defined? name
|
||||
return autoloaded_constants.include?(name)
|
||||
|
@ -505,79 +507,26 @@ module ActiveSupport #:nodoc:
|
|||
# and will be removed immediately.
|
||||
def new_constants_in(*descs)
|
||||
log_call(*descs)
|
||||
|
||||
# Build the watch frames. Each frame is a tuple of
|
||||
# [module_name_as_string, constants_defined_elsewhere]
|
||||
watch_frames = descs.collect do |desc|
|
||||
if desc.is_a? Module
|
||||
mod_name = desc.name
|
||||
initial_constants = desc.local_constant_names
|
||||
elsif desc.is_a?(String) || desc.is_a?(Symbol)
|
||||
mod_name = desc.to_s
|
||||
|
||||
# Handle the case where the module has yet to be defined.
|
||||
initial_constants = if qualified_const_defined?(mod_name)
|
||||
Inflector.constantize(mod_name).local_constant_names
|
||||
else
|
||||
[]
|
||||
end
|
||||
else
|
||||
raise Argument, "#{desc.inspect} does not describe a module!"
|
||||
end
|
||||
|
||||
[mod_name, initial_constants]
|
||||
end
|
||||
|
||||
constant_watch_stack_mutex.synchronize do
|
||||
constant_watch_stack.concat watch_frames
|
||||
end
|
||||
watch_frames = constant_watch_stack.add_modules(descs)
|
||||
|
||||
aborting = true
|
||||
begin
|
||||
yield # Now yield to the code that is to define new constants.
|
||||
aborting = false
|
||||
ensure
|
||||
# Find the new constants.
|
||||
new_constants = watch_frames.collect do |mod_name, prior_constants|
|
||||
# Module still doesn't exist? Treat it as if it has no constants.
|
||||
next [] unless qualified_const_defined?(mod_name)
|
||||
|
||||
mod = Inflector.constantize(mod_name)
|
||||
next [] unless mod.is_a? Module
|
||||
new_constants = mod.local_constant_names - prior_constants
|
||||
|
||||
# Make sure no other frames takes credit for these constants.
|
||||
constant_watch_stack_mutex.synchronize do
|
||||
constant_watch_stack.each do |frame_name, constants|
|
||||
constants.concat new_constants if frame_name == mod_name
|
||||
end
|
||||
end
|
||||
|
||||
new_constants.collect do |suffix|
|
||||
mod_name == "Object" ? suffix : "#{mod_name}::#{suffix}"
|
||||
end
|
||||
end.flatten
|
||||
new_constants = constant_watch_stack.new_constants_for(watch_frames)
|
||||
|
||||
log "New constants: #{new_constants * ', '}"
|
||||
return new_constants unless aborting
|
||||
|
||||
if aborting
|
||||
log "Error during loading, removing partially loaded constants "
|
||||
new_constants.each { |name| remove_constant name }
|
||||
new_constants.clear
|
||||
end
|
||||
log "Error during loading, removing partially loaded constants "
|
||||
new_constants.each {|c| remove_constant(c) }.clear
|
||||
end
|
||||
|
||||
return new_constants
|
||||
return []
|
||||
ensure
|
||||
# Remove the stack frames that we added.
|
||||
if defined?(watch_frames) && ! watch_frames.blank?
|
||||
frame_ids = watch_frames.collect { |frame| frame.object_id }
|
||||
constant_watch_stack_mutex.synchronize do
|
||||
constant_watch_stack.delete_if do |watch_frame|
|
||||
frame_ids.include? watch_frame.object_id
|
||||
end
|
||||
end
|
||||
end
|
||||
watch_frames.each {|f| constant_watch_stack.delete(f) } if watch_frames.present?
|
||||
end
|
||||
|
||||
class LoadingModule #:nodoc:
|
||||
|
@ -595,11 +544,11 @@ module ActiveSupport #:nodoc:
|
|||
# A module, class, symbol, or string may be provided.
|
||||
def to_constant_name(desc) #:nodoc:
|
||||
name = case desc
|
||||
when String then desc.starts_with?('::') ? desc[2..-1] : desc
|
||||
when String then desc.sub(/^::/, '')
|
||||
when Symbol then desc.to_s
|
||||
when Module
|
||||
raise ArgumentError, "Anonymous modules have no name to be referenced by" if desc.name.blank?
|
||||
desc.name
|
||||
desc.name.presence ||
|
||||
raise(ArgumentError, "Anonymous modules have no name to be referenced by")
|
||||
else raise TypeError, "Not a valid constant descriptor: #{desc.inspect}"
|
||||
end
|
||||
end
|
||||
|
@ -607,16 +556,13 @@ module ActiveSupport #:nodoc:
|
|||
def remove_constant(const) #:nodoc:
|
||||
return false unless qualified_const_defined? const
|
||||
|
||||
const = $1 if /\A::(.*)\Z/ =~ const.to_s
|
||||
names = const.to_s.split('::')
|
||||
if names.size == 1 # It's under Object
|
||||
parent = Object
|
||||
else
|
||||
parent = Inflector.constantize(names[0..-2] * '::')
|
||||
end
|
||||
# Normalize ::Foo, Foo, Object::Foo, and ::Object::Foo to Object::Foo
|
||||
names = const.to_s.sub(/^::(Object)?/, 'Object::').split("::")
|
||||
to_remove = names.pop
|
||||
parent = Inflector.constantize(names * '::')
|
||||
|
||||
log "removing constant #{const}"
|
||||
parent.instance_eval { remove_const names.last }
|
||||
parent.instance_eval { remove_const to_remove }
|
||||
return true
|
||||
end
|
||||
|
||||
|
|
40
activesupport/lib/active_support/json/backends/yajl.rb
Normal file
40
activesupport/lib/active_support/json/backends/yajl.rb
Normal file
|
@ -0,0 +1,40 @@
|
|||
require 'yajl-ruby' unless defined?(Yajl)
|
||||
|
||||
module ActiveSupport
|
||||
module JSON
|
||||
module Backends
|
||||
module Yajl
|
||||
ParseError = ::Yajl::ParseError
|
||||
extend self
|
||||
|
||||
# Parses a JSON string or IO and convert it into an object
|
||||
def decode(json)
|
||||
data = ::Yajl::Parser.new.parse(json)
|
||||
if ActiveSupport.parse_json_times
|
||||
convert_dates_from(data)
|
||||
else
|
||||
data
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def convert_dates_from(data)
|
||||
case data
|
||||
when nil
|
||||
nil
|
||||
when DATE_REGEX
|
||||
DateTime.parse(data)
|
||||
when Array
|
||||
data.map! { |d| convert_dates_from(d) }
|
||||
when Hash
|
||||
data.each do |key, value|
|
||||
data[key] = convert_dates_from(value)
|
||||
end
|
||||
else
|
||||
data
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -6,12 +6,15 @@ module ActiveSupport
|
|||
mattr_accessor :parse_json_times
|
||||
|
||||
module JSON
|
||||
# Listed in order of preference.
|
||||
DECODERS = %w(Yajl JSONGem Yaml)
|
||||
|
||||
class << self
|
||||
attr_reader :parse_error
|
||||
delegate :decode, :to => :backend
|
||||
|
||||
def backend
|
||||
self.backend = "Yaml" unless defined?(@backend)
|
||||
set_default_backend unless defined?(@backend)
|
||||
@backend
|
||||
end
|
||||
|
||||
|
@ -31,6 +34,18 @@ module ActiveSupport
|
|||
ensure
|
||||
self.backend = old_backend
|
||||
end
|
||||
|
||||
def set_default_backend
|
||||
DECODERS.find do |name|
|
||||
begin
|
||||
self.backend = name
|
||||
true
|
||||
rescue LoadError
|
||||
# Try next decoder.
|
||||
false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -21,12 +21,6 @@ module ActiveSupport
|
|||
alias_method :method_name, :name if method_defined? :name
|
||||
alias_method :method_name, :__name__ if method_defined? :__name__
|
||||
else
|
||||
# TODO: Figure out how to get the Rails::BacktraceFilter into minitest/unit
|
||||
if defined?(Rails) && ENV['BACKTRACE'].nil?
|
||||
require 'rails/backtrace_cleaner'
|
||||
Test::Unit::Util::BacktraceFilter.module_eval { include Rails::BacktraceFilterForTestUnit }
|
||||
end
|
||||
|
||||
Assertion = Test::Unit::AssertionFailedError
|
||||
|
||||
require 'active_support/testing/default'
|
||||
|
|
|
@ -2,7 +2,7 @@ module ActiveSupport
|
|||
module VERSION #:nodoc:
|
||||
MAJOR = 3
|
||||
MINOR = 0
|
||||
TINY = "0.beta"
|
||||
TINY = "0.beta1"
|
||||
|
||||
STRING = [MAJOR, MINOR, TINY].join('.')
|
||||
end
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
# classes in NilClass::WHINERS the error message suggests which could be the
|
||||
# actual intended class:
|
||||
#
|
||||
# $ script/runner nil.destroy
|
||||
# $ rails runner nil.destroy
|
||||
# ...
|
||||
# You might have expected an instance of ActiveRecord::Base.
|
||||
# ...
|
||||
|
|
29
activesupport/test/core_ext/class_test.rb
Normal file
29
activesupport/test/core_ext/class_test.rb
Normal file
|
@ -0,0 +1,29 @@
|
|||
require 'abstract_unit'
|
||||
require 'active_support/core_ext/class'
|
||||
|
||||
class A
|
||||
end
|
||||
|
||||
module X
|
||||
class B
|
||||
end
|
||||
end
|
||||
|
||||
module Y
|
||||
module Z
|
||||
class C
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class ClassTest < Test::Unit::TestCase
|
||||
def test_retrieving_subclasses
|
||||
@parent = eval("class D; end; D")
|
||||
@sub = eval("class E < D; end; E")
|
||||
@subofsub = eval("class F < E; end; F")
|
||||
assert_equal 2, @parent.subclasses.size
|
||||
assert_equal [@subofsub.to_s], @sub.subclasses
|
||||
assert_equal [], @subofsub.subclasses
|
||||
assert_equal [@sub.to_s, @subofsub.to_s].sort, @parent.subclasses.sort
|
||||
end
|
||||
end
|
14
activesupport/test/core_ext/module/anonymous_test.rb
Normal file
14
activesupport/test/core_ext/module/anonymous_test.rb
Normal file
|
@ -0,0 +1,14 @@
|
|||
require 'abstract_unit'
|
||||
require 'active_support/core_ext/module/anonymous'
|
||||
|
||||
class AnonymousTest < ActiveSupport::TestCase
|
||||
test "an anonymous class or module are anonymous" do
|
||||
assert Module.new.anonymous?
|
||||
assert Class.new.anonymous?
|
||||
end
|
||||
|
||||
test "a named class or module are not anonymous" do
|
||||
assert !Kernel.anonymous?
|
||||
assert !Object.anonymous?
|
||||
end
|
||||
end
|
41
activesupport/test/core_ext/module/reachable_test.rb
Normal file
41
activesupport/test/core_ext/module/reachable_test.rb
Normal file
|
@ -0,0 +1,41 @@
|
|||
require 'abstract_unit'
|
||||
require 'active_support/core_ext/module/reachable'
|
||||
|
||||
class AnonymousTest < ActiveSupport::TestCase
|
||||
test "an anonymous class or module is not reachable" do
|
||||
assert !Module.new.reachable?
|
||||
assert !Class.new.reachable?
|
||||
end
|
||||
|
||||
test "ordinary named classes or modules are reachable" do
|
||||
assert Kernel.reachable?
|
||||
assert Object.reachable?
|
||||
end
|
||||
|
||||
test "a named class or module whose constant has gone is not reachable" do
|
||||
c = eval "class C; end; C"
|
||||
m = eval "module M; end; M"
|
||||
|
||||
self.class.send(:remove_const, :C)
|
||||
self.class.send(:remove_const, :M)
|
||||
|
||||
assert !c.reachable?
|
||||
assert !m.reachable?
|
||||
end
|
||||
|
||||
test "a named class or module whose constants store different objects are not reachable" do
|
||||
c = eval "class C; end; C"
|
||||
m = eval "module M; end; M"
|
||||
|
||||
self.class.send(:remove_const, :C)
|
||||
self.class.send(:remove_const, :M)
|
||||
|
||||
eval "class C; end"
|
||||
eval "module M; end"
|
||||
|
||||
assert C.reachable?
|
||||
assert M.reachable?
|
||||
assert !c.reachable?
|
||||
assert !m.reachable?
|
||||
end
|
||||
end
|
|
@ -72,13 +72,6 @@ class ModuleTest < Test::Unit::TestCase
|
|||
@david = Someone.new("David", Somewhere.new("Paulina", "Chicago"))
|
||||
end
|
||||
|
||||
def test_included_in_classes
|
||||
assert One.included_in_classes.include?(Ab)
|
||||
assert One.included_in_classes.include?(Xy::Bc)
|
||||
assert One.included_in_classes.include?(Yz::Zy::Cd)
|
||||
assert !One.included_in_classes.include?(De)
|
||||
end
|
||||
|
||||
def test_delegation_to_methods
|
||||
assert_equal "Paulina", @david.street
|
||||
assert_equal "Chicago", @david.city
|
||||
|
@ -170,11 +163,6 @@ class ModuleTest < Test::Unit::TestCase
|
|||
def test_local_constants
|
||||
assert_equal %w(Constant1 Constant3), Ab.local_constants.sort.map(&:to_s)
|
||||
end
|
||||
|
||||
def test_as_load_path
|
||||
assert_equal 'yz/zy', Yz::Zy.as_load_path
|
||||
assert_equal 'yz', Yz.as_load_path
|
||||
end
|
||||
end
|
||||
|
||||
module BarMethodAliaser
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
require 'abstract_unit'
|
||||
require 'active_support/time'
|
||||
require 'active_support/core_ext/object'
|
||||
require 'active_support/core_ext/class/subclasses'
|
||||
|
||||
class ClassA; end
|
||||
class ClassB < ClassA; end
|
||||
|
@ -39,6 +40,55 @@ class Foo
|
|||
include Bar
|
||||
end
|
||||
|
||||
class ClassExtTest < Test::Unit::TestCase
|
||||
def test_subclasses_of_should_find_nested_classes
|
||||
assert Class.subclasses_of(ClassK).include?(Nested::ClassL)
|
||||
end
|
||||
|
||||
def test_subclasses_of_should_not_return_removed_classes
|
||||
# First create the removed class
|
||||
old_class = Nested.class_eval { remove_const :ClassL }
|
||||
new_class = Class.new(ClassK)
|
||||
Nested.const_set :ClassL, new_class
|
||||
assert_equal "Nested::ClassL", new_class.name # Sanity check
|
||||
|
||||
subclasses = Class.subclasses_of(ClassK)
|
||||
assert subclasses.include?(new_class)
|
||||
assert ! subclasses.include?(old_class)
|
||||
ensure
|
||||
Nested.const_set :ClassL, old_class unless defined?(Nested::ClassL)
|
||||
end
|
||||
|
||||
def test_subclasses_of_should_not_trigger_const_missing
|
||||
const_missing = false
|
||||
Nested.on_const_missing { const_missing = true }
|
||||
|
||||
subclasses = Class.subclasses_of ClassK
|
||||
assert !const_missing
|
||||
assert_equal [ Nested::ClassL ], subclasses
|
||||
|
||||
removed = Nested.class_eval { remove_const :ClassL } # keep it in memory
|
||||
subclasses = Class.subclasses_of ClassK
|
||||
assert !const_missing
|
||||
assert subclasses.empty?
|
||||
ensure
|
||||
Nested.const_set :ClassL, removed unless defined?(Nested::ClassL)
|
||||
end
|
||||
|
||||
def test_subclasses_of_with_multiple_roots
|
||||
classes = Class.subclasses_of(ClassI, ClassK)
|
||||
assert_equal %w(ClassJ Nested::ClassL), classes.collect(&:to_s).sort
|
||||
end
|
||||
|
||||
def test_subclasses_of_doesnt_find_anonymous_classes
|
||||
assert_equal [], Class.subclasses_of(Foo)
|
||||
bar = Class.new(Foo)
|
||||
assert_nothing_raised do
|
||||
assert_equal [bar], Class.subclasses_of(Foo)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class ObjectTests < Test::Unit::TestCase
|
||||
class DuckTime
|
||||
def acts_like_time?
|
||||
|
|
|
@ -335,6 +335,11 @@ end
|
|||
class OutputSafetyTest < ActiveSupport::TestCase
|
||||
def setup
|
||||
@string = "hello"
|
||||
@object = Class.new(Object) do
|
||||
def to_s
|
||||
"other"
|
||||
end
|
||||
end.new
|
||||
end
|
||||
|
||||
test "A string is unsafe by default" do
|
||||
|
@ -355,17 +360,15 @@ class OutputSafetyTest < ActiveSupport::TestCase
|
|||
end
|
||||
|
||||
test "An object is unsafe by default" do
|
||||
klass = Class.new(Object) do
|
||||
def to_str
|
||||
"other"
|
||||
end
|
||||
end
|
||||
assert !@object.html_safe?
|
||||
end
|
||||
|
||||
@string.html_safe
|
||||
@string << klass.new
|
||||
test "Adding an object to a safe string returns a safe string" do
|
||||
string = @string.html_safe
|
||||
string << @object
|
||||
|
||||
assert_equal "helloother", @string
|
||||
assert !@string.html_safe?
|
||||
assert_equal "helloother", string
|
||||
assert string.html_safe?
|
||||
end
|
||||
|
||||
test "Adding a safe string to another safe string returns a safe string" do
|
||||
|
@ -391,9 +394,9 @@ class OutputSafetyTest < ActiveSupport::TestCase
|
|||
|
||||
test "Concatting safe onto unsafe yields unsafe" do
|
||||
@other_string = "other"
|
||||
@string.html_safe
|
||||
|
||||
@other_string.concat(@string)
|
||||
string = @string.html_safe
|
||||
@other_string.concat(string)
|
||||
assert !@other_string.html_safe?
|
||||
end
|
||||
|
||||
|
@ -406,17 +409,17 @@ class OutputSafetyTest < ActiveSupport::TestCase
|
|||
|
||||
test "Concatting safe onto safe yields safe" do
|
||||
@other_string = "other".html_safe
|
||||
@string.html_safe
|
||||
string = @string.html_safe
|
||||
|
||||
@other_string.concat(@string)
|
||||
@other_string.concat(string)
|
||||
assert @other_string.html_safe?
|
||||
end
|
||||
|
||||
test "Concatting safe onto unsafe with << yields unsafe" do
|
||||
@other_string = "other"
|
||||
@string.html_safe
|
||||
string = @string.html_safe
|
||||
|
||||
@other_string << @string
|
||||
@other_string << string
|
||||
assert !@other_string.html_safe?
|
||||
end
|
||||
|
||||
|
@ -429,9 +432,9 @@ class OutputSafetyTest < ActiveSupport::TestCase
|
|||
|
||||
test "Concatting safe onto safe with << yields safe" do
|
||||
@other_string = "other".html_safe
|
||||
@string.html_safe
|
||||
string = @string.html_safe
|
||||
|
||||
@other_string << @string
|
||||
@other_string << string
|
||||
assert @other_string.html_safe?
|
||||
end
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
require 'abstract_unit'
|
||||
require 'pp'
|
||||
require 'active_support/dependencies'
|
||||
require 'active_support/core_ext/module/loading'
|
||||
require 'active_support/core_ext/kernel/reporting'
|
||||
|
||||
module ModuleWithMissing
|
||||
|
@ -43,12 +42,17 @@ class DependenciesTest < Test::Unit::TestCase
|
|||
require_dependency 'dependencies/service_one'
|
||||
require_dependency 'dependencies/service_two'
|
||||
assert_equal 2, ActiveSupport::Dependencies.loaded.size
|
||||
ensure
|
||||
Object.send(:remove_const, :ServiceOne) if Object.const_defined?(:ServiceOne)
|
||||
Object.send(:remove_const, :ServiceTwo) if Object.const_defined?(:ServiceTwo)
|
||||
end
|
||||
|
||||
def test_tracking_identical_loaded_files
|
||||
require_dependency 'dependencies/service_one'
|
||||
require_dependency 'dependencies/service_one'
|
||||
assert_equal 1, ActiveSupport::Dependencies.loaded.size
|
||||
ensure
|
||||
Object.send(:remove_const, :ServiceOne) if Object.const_defined?(:ServiceOne)
|
||||
end
|
||||
|
||||
def test_missing_dependency_raises_missing_source_file
|
||||
|
@ -130,10 +134,6 @@ class DependenciesTest < Test::Unit::TestCase
|
|||
end
|
||||
end
|
||||
|
||||
def test_as_load_path
|
||||
assert_equal '', DependenciesTest.as_load_path
|
||||
end
|
||||
|
||||
def test_module_loading
|
||||
with_autoloading_fixtures do
|
||||
assert_kind_of Module, A
|
||||
|
@ -291,7 +291,7 @@ class DependenciesTest < Test::Unit::TestCase
|
|||
assert ActiveSupport::Dependencies.qualified_const_defined?("::Test::Unit::TestCase")
|
||||
end
|
||||
|
||||
def test_qualified_const_defined_should_not_call_method_missing
|
||||
def test_qualified_const_defined_should_not_call_const_missing
|
||||
ModuleWithMissing.missing_count = 0
|
||||
assert ! ActiveSupport::Dependencies.qualified_const_defined?("ModuleWithMissing::A")
|
||||
assert_equal 0, ModuleWithMissing.missing_count
|
||||
|
@ -299,6 +299,10 @@ class DependenciesTest < Test::Unit::TestCase
|
|||
assert_equal 0, ModuleWithMissing.missing_count
|
||||
end
|
||||
|
||||
def test_qualified_const_defined_explodes_with_invalid_const_name
|
||||
assert_raises(NameError) { ActiveSupport::Dependencies.qualified_const_defined?("invalid") }
|
||||
end
|
||||
|
||||
def test_autoloaded?
|
||||
with_autoloading_fixtures do
|
||||
assert ! ActiveSupport::Dependencies.autoloaded?("ModuleFolder")
|
||||
|
@ -333,7 +337,6 @@ class DependenciesTest < Test::Unit::TestCase
|
|||
assert_equal "A", ActiveSupport::Dependencies.qualified_name_for(:Object, :A)
|
||||
assert_equal "A", ActiveSupport::Dependencies.qualified_name_for("Object", :A)
|
||||
assert_equal "A", ActiveSupport::Dependencies.qualified_name_for("::Object", :A)
|
||||
assert_equal "A", ActiveSupport::Dependencies.qualified_name_for("::Kernel", :A)
|
||||
|
||||
assert_equal "ActiveSupport::Dependencies::A", ActiveSupport::Dependencies.qualified_name_for(:'ActiveSupport::Dependencies', :A)
|
||||
assert_equal "ActiveSupport::Dependencies::A", ActiveSupport::Dependencies.qualified_name_for(ActiveSupport::Dependencies, :A)
|
||||
|
@ -460,14 +463,6 @@ class DependenciesTest < Test::Unit::TestCase
|
|||
end
|
||||
end
|
||||
|
||||
def test_const_missing_on_kernel_should_fallback_to_object
|
||||
with_autoloading_fixtures do
|
||||
kls = Kernel::E
|
||||
assert_equal "E", kls.name
|
||||
assert_equal kls.object_id, Kernel::E.object_id
|
||||
end
|
||||
end
|
||||
|
||||
def test_preexisting_constants_are_not_marked_as_autoloaded
|
||||
with_autoloading_fixtures do
|
||||
require_dependency 'e'
|
||||
|
@ -711,7 +706,7 @@ class DependenciesTest < Test::Unit::TestCase
|
|||
def test_autoload_doesnt_shadow_name_error
|
||||
with_autoloading_fixtures do
|
||||
Object.send(:remove_const, :RaisesNameError) if defined?(::RaisesNameError)
|
||||
2.times do
|
||||
2.times do |i|
|
||||
begin
|
||||
::RaisesNameError::FooBarBaz.object_id
|
||||
flunk 'should have raised NameError when autoloaded file referenced FooBarBaz'
|
||||
|
|
|
@ -45,10 +45,11 @@ class TestJSONDecoding < ActiveSupport::TestCase
|
|||
}
|
||||
|
||||
# load the default JSON backend
|
||||
ActiveSupport::JSON.backend
|
||||
ActiveSupport::JSON.backend = 'Yaml'
|
||||
|
||||
backends = %w(Yaml)
|
||||
backends << "JSONGem" if defined?(::JSON)
|
||||
backends << "Yajl" if defined?(::Yajl)
|
||||
|
||||
backends.each do |backend|
|
||||
TESTS.each do |json, expected|
|
||||
|
|
|
@ -50,13 +50,18 @@ class TestJSONEncoding < Test::Unit::TestCase
|
|||
StandardDateTimeTests = [[ DateTime.civil(2005,2,1,15,15,10), %("2005-02-01T15:15:10+00:00") ]]
|
||||
StandardStringTests = [[ 'this is the <string>', %("this is the <string>")]]
|
||||
|
||||
def sorted_json(json)
|
||||
return json unless json =~ /^\{.*\}$/
|
||||
'{' + json[1..-2].split(',').sort.join(',') + '}'
|
||||
end
|
||||
|
||||
constants.grep(/Tests$/).each do |class_tests|
|
||||
define_method("test_#{class_tests[0..-6].underscore}") do
|
||||
begin
|
||||
ActiveSupport.escape_html_entities_in_json = class_tests !~ /^Standard/
|
||||
ActiveSupport.use_standard_json_time_format = class_tests =~ /^Standard/
|
||||
self.class.const_get(class_tests).each do |pair|
|
||||
assert_equal pair.last, ActiveSupport::JSON.encode(pair.first)
|
||||
assert_equal pair.last, sorted_json(ActiveSupport::JSON.encode(pair.first))
|
||||
end
|
||||
ensure
|
||||
ActiveSupport.escape_html_entities_in_json = false
|
||||
|
@ -71,8 +76,7 @@ class TestJSONEncoding < Test::Unit::TestCase
|
|||
assert_equal %({\"a\":[1,2]}), ActiveSupport::JSON.encode('a' => [1,2])
|
||||
assert_equal %({"1":2}), ActiveSupport::JSON.encode(1 => 2)
|
||||
|
||||
sorted_json = '{' + ActiveSupport::JSON.encode(:a => :b, :c => :d)[1..-2].split(',').sort.join(',') + '}'
|
||||
assert_equal %({\"a\":\"b\",\"c\":\"d\"}), sorted_json
|
||||
assert_equal %({\"a\":\"b\",\"c\":\"d\"}), sorted_json(ActiveSupport::JSON.encode(:a => :b, :c => :d))
|
||||
end
|
||||
|
||||
def test_utf8_string_encoded_properly_when_kcode_is_utf8
|
||||
|
|
|
@ -7,12 +7,6 @@ class NuclearExplosion < StandardError
|
|||
end
|
||||
|
||||
class MadRonon < StandardError
|
||||
attr_accessor :message
|
||||
|
||||
def initialize(message)
|
||||
@message = message
|
||||
super()
|
||||
end
|
||||
end
|
||||
|
||||
class Stargate
|
||||
|
|
|
@ -18,18 +18,16 @@ end
|
|||
puts "[CruiseControl] Rails build"
|
||||
build_results = {}
|
||||
|
||||
# Install rubygems-update, so 'gem update --system' in cruise_config.rb auto-installs it on next build.
|
||||
# This is how you can auto-update rubygems without logging in to CI system
|
||||
build_results[:geminstaller] = system "sudo gem install rubygems-update -v 1.3.5 --no-ri --no-rdoc"
|
||||
|
||||
# Install required version of bundler.
|
||||
build_results[:geminstaller] = system "sudo gem install bundler -v 0.9.1.pre1 --prerelease --no-ri --no-rdoc"
|
||||
bundler_install_cmd = "gem install bundler -v 0.9.3 --no-ri --no-rdoc"
|
||||
puts "Running command: #{bundler_install_cmd}"
|
||||
build_results[:install_bundler] = system bundler_install_cmd
|
||||
|
||||
cd root_dir do
|
||||
puts
|
||||
puts "[CruiseControl] Bundling RubyGems"
|
||||
puts
|
||||
build_results[:bundle] = system 'env CI=1 sudo bundle install'
|
||||
build_results[:bundle] = system 'rm -rf ~/.bundle; env CI=1 bundle install'
|
||||
end
|
||||
|
||||
cd "#{root_dir}/activesupport" do
|
||||
|
@ -60,6 +58,7 @@ cd "#{root_dir}/actionmailer" do
|
|||
puts "[CruiseControl] Building ActionMailer"
|
||||
puts
|
||||
build_results[:actionmailer] = rake 'test'
|
||||
build_results[:actionmailer_isolated] = rake 'test:isolated'
|
||||
end
|
||||
|
||||
cd "#{root_dir}/activemodel" do
|
||||
|
@ -67,6 +66,7 @@ cd "#{root_dir}/activemodel" do
|
|||
puts "[CruiseControl] Building ActiveModel"
|
||||
puts
|
||||
build_results[:activemodel] = rake 'test'
|
||||
build_results[:activemodel_isolated] = rake 'test:isolated'
|
||||
end
|
||||
|
||||
rm_f "#{root_dir}/activeresource/debug.log"
|
||||
|
@ -75,6 +75,7 @@ cd "#{root_dir}/activeresource" do
|
|||
puts "[CruiseControl] Building ActiveResource"
|
||||
puts
|
||||
build_results[:activeresource] = rake 'test'
|
||||
build_results[:activeresource_isolated] = rake 'test:isolated'
|
||||
end
|
||||
|
||||
rm_f "#{root_dir}/activerecord/debug.log"
|
||||
|
@ -82,21 +83,24 @@ cd "#{root_dir}/activerecord" do
|
|||
puts
|
||||
puts "[CruiseControl] Building ActiveRecord with MySQL"
|
||||
puts
|
||||
build_results[:activerecord_mysql] = rake 'mysql:rebuild_databases', 'test_mysql'
|
||||
build_results[:activerecord_mysql] = rake 'mysql:rebuild_databases', 'mysql:test'
|
||||
build_results[:activerecord_mysql_isolated] = rake 'mysql:rebuild_databases', 'mysql:isolated_test'
|
||||
end
|
||||
|
||||
cd "#{root_dir}/activerecord" do
|
||||
puts
|
||||
puts "[CruiseControl] Building ActiveRecord with PostgreSQL"
|
||||
puts
|
||||
build_results[:activerecord_postgresql8] = rake 'postgresql:rebuild_databases', 'test_postgresql'
|
||||
build_results[:activerecord_postgresql8] = rake 'postgresql:rebuild_databases', 'postgresql:test'
|
||||
build_results[:activerecord_postgresql8_isolated] = rake 'postgresql:rebuild_databases', 'postgresql:isolated_test'
|
||||
end
|
||||
|
||||
cd "#{root_dir}/activerecord" do
|
||||
puts
|
||||
puts "[CruiseControl] Building ActiveRecord with SQLite 3"
|
||||
puts
|
||||
build_results[:activerecord_sqlite3] = rake 'test_sqlite3'
|
||||
build_results[:activerecord_sqlite3] = rake 'sqlite3:test'
|
||||
build_results[:activerecord_sqlite3_isolated] = rake 'sqlite3:isolated_test'
|
||||
end
|
||||
|
||||
|
||||
|
@ -109,9 +113,8 @@ puts "[CruiseControl] #{`mysql --version`}"
|
|||
puts "[CruiseControl] #{`pg_config --version`}"
|
||||
puts "[CruiseControl] SQLite3: #{`sqlite3 -version`}"
|
||||
`gem env`.each_line {|line| print "[CruiseControl] #{line}"}
|
||||
# Commented until bundler supports --list again
|
||||
# puts "[CruiseControl] Bundled gems:"
|
||||
# `gem bundle --list`.each_line {|line| print "[CruiseControl] #{line}"}
|
||||
puts "[CruiseControl] Bundled gems:"
|
||||
`bundle show`.each_line {|line| print "[CruiseControl] #{line}"}
|
||||
puts "[CruiseControl] Local gems:"
|
||||
`gem list`.each_line {|line| print "[CruiseControl] #{line}"}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
begin
|
||||
require File.expand_path('../vendor/environment', __FILE__)
|
||||
require File.expand_path('../.bundle/environment', __FILE__)
|
||||
rescue LoadError
|
||||
begin
|
||||
require 'rubygems'
|
||||
|
@ -18,4 +18,4 @@ rescue LoadError
|
|||
$:.unshift File.expand_path("../#{framework}/lib", __FILE__)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,23 +1,24 @@
|
|||
Gem::Specification.new do |s|
|
||||
s.platform = Gem::Platform::RUBY
|
||||
s.name = 'rails'
|
||||
s.version = '3.0.0.beta'
|
||||
s.version = '3.0.0.beta1'
|
||||
s.summary = 'Full-stack web-application framework.'
|
||||
s.description = 'Full-stack web-application framework.'
|
||||
s.required_ruby_version = '>= 1.8.7'
|
||||
|
||||
s.author = 'David Heinemeier Hansson'
|
||||
s.email = 'david@loudthinking.com'
|
||||
s.homepage = 'http://www.rubyonrails.org'
|
||||
s.rubyforge_project = 'rails'
|
||||
|
||||
s.files = []
|
||||
s.require_path = []
|
||||
|
||||
s.rdoc_options << '--exclude' << '.'
|
||||
s.has_rdoc = false
|
||||
|
||||
s.add_dependency('activesupport', '= 3.0.0.beta')
|
||||
s.add_dependency('actionpack', '= 3.0.0.beta')
|
||||
s.add_dependency('activerecord', '= 3.0.0.beta')
|
||||
s.add_dependency('activeresource', '= 3.0.0.beta')
|
||||
s.add_dependency('actionmailer', '= 3.0.0.beta')
|
||||
s.add_dependency('railties', '= 3.0.0.beta')
|
||||
s.add_dependency('bundler', '>= 0.9.1.pre1')
|
||||
s.add_dependency('activesupport', '= 3.0.0.beta1')
|
||||
s.add_dependency('actionpack', '= 3.0.0.beta1')
|
||||
s.add_dependency('activerecord', '= 3.0.0.beta1')
|
||||
s.add_dependency('activeresource', '= 3.0.0.beta1')
|
||||
s.add_dependency('actionmailer', '= 3.0.0.beta1')
|
||||
s.add_dependency('railties', '= 3.0.0.beta1')
|
||||
s.add_dependency('bundler', '>= 0.9.3')
|
||||
end
|
||||
|
|
28
rails3b.gemspec
Normal file
28
rails3b.gemspec
Normal file
|
@ -0,0 +1,28 @@
|
|||
Gem::Specification.new do |s|
|
||||
s.platform = Gem::Platform::RUBY
|
||||
s.name = 'rails3b'
|
||||
s.version = '3.0.1'
|
||||
s.summary = 'Just the Rails 3 beta dependencies. Works around prerelease RubyGems bug.'
|
||||
s.description = 'My kingdom for working dependencies.'
|
||||
s.required_ruby_version = '>= 1.8.7'
|
||||
|
||||
s.author = 'Jeremy Kemper'
|
||||
s.email = 'jeremy@bitsweat.net'
|
||||
|
||||
s.files = []
|
||||
s.require_path = []
|
||||
|
||||
s.add_dependency('mail', '~> 2.1.2')
|
||||
s.add_dependency('text-format', '~> 1.0.0')
|
||||
s.add_dependency('rack', '~> 1.1.0')
|
||||
s.add_dependency('rack-test', '~> 0.5.0')
|
||||
s.add_dependency('rack-mount', '= 0.4.7')
|
||||
s.add_dependency('erubis', '~> 2.6.5')
|
||||
s.add_dependency('i18n', '~> 0.3.0')
|
||||
s.add_dependency('tzinfo', '~> 0.3.16')
|
||||
s.add_dependency('builder', '~> 2.1.2')
|
||||
s.add_dependency('memcache-client', '~> 1.7.5')
|
||||
s.add_dependency('bundler', '>= 0.9.2')
|
||||
s.add_dependency('rake', '>= 0.8.3')
|
||||
s.add_dependency('thor', '~> 0.13')
|
||||
end
|
|
@ -250,7 +250,7 @@ app/views/layouts
|
|||
|
||||
app/helpers
|
||||
Holds view helpers that should be named like weblogs_helper.rb. These are generated
|
||||
for you automatically when using rails generate for controllers. Helpers can be used to
|
||||
for you automatically when using <tt>rails generate</tt> for controllers. Helpers can be used to
|
||||
wrap functionality for your views into methods.
|
||||
|
||||
config
|
||||
|
@ -277,7 +277,7 @@ script
|
|||
Helper scripts for automation and generation.
|
||||
|
||||
test
|
||||
Unit and functional tests along with fixtures. When using the rails generate command, template
|
||||
Unit and functional tests along with fixtures. When using the <tt>rails generate</tt> scripts, template
|
||||
test files will be generated for you and placed in this directory.
|
||||
|
||||
vendor
|
||||
|
|
|
@ -90,11 +90,11 @@ end
|
|||
|
||||
# Publishing -------------------------------------------------------
|
||||
|
||||
desc "Publish the rails gem"
|
||||
task :pgem => [:gem] do
|
||||
require 'rake/contrib/sshpublisher'
|
||||
Rake::SshFilePublisher.new("gems.rubyonrails.org", "/u/sites/gems/gems", "pkg", "#{PKG_FILE_NAME}.gem").upload
|
||||
`ssh gems.rubyonrails.org '/u/sites/gems/gemupdate.sh'`
|
||||
desc "Release to gemcutter"
|
||||
task :release => :package do
|
||||
require 'rake/gemcutter'
|
||||
Rake::Gemcutter::Tasks.new(spec).define
|
||||
Rake::Task['gem:push'].invoke
|
||||
end
|
||||
|
||||
desc "Publish the guides"
|
||||
|
@ -105,15 +105,3 @@ task :pguides => :generate_guides do
|
|||
Rake::SshFilePublisher.new("web.rubyonrails.org", "/u/sites/guides.rubyonrails.org/public", "pkg", "guides.gz").upload
|
||||
`ssh web.rubyonrails.org 'cd /u/sites/guides.rubyonrails.org/public/ && tar -xvzf guides.gz && mv guides/output/* . && rm -rf guides*'`
|
||||
end
|
||||
|
||||
desc "Publish the release files to RubyForge."
|
||||
task :release => [ :package ] do
|
||||
require 'rake/contrib/rubyforgepublisher'
|
||||
require 'rubyforge'
|
||||
|
||||
packages = %w( gem ).collect{ |ext| "pkg/#{PKG_NAME}-#{PKG_VERSION}.#{ext}" }
|
||||
|
||||
rubyforge = RubyForge.new
|
||||
rubyforge.login
|
||||
rubyforge.add_release(PKG_NAME, PKG_NAME, "REL #{PKG_VERSION}", *packages)
|
||||
end
|
||||
|
|
BIN
railties/guides/images/edge_badge.png
Normal file
BIN
railties/guides/images/edge_badge.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 7.8 KiB |
|
@ -1,4 +1,5 @@
|
|||
require 'set'
|
||||
require 'fileutils'
|
||||
|
||||
module RailsGuides
|
||||
class Generator
|
||||
|
@ -49,16 +50,19 @@ module RailsGuides
|
|||
if guide =~ /\.textile\.erb$/
|
||||
# Generate the erb pages with textile formatting - e.g. index/authors
|
||||
result = view.render(:layout => 'layout', :file => guide)
|
||||
f.write textile(result)
|
||||
result = textile(result)
|
||||
else
|
||||
body = File.read(File.join(view_path, guide))
|
||||
body = set_header_section(body, @view)
|
||||
body = set_index(body, @view)
|
||||
|
||||
result = view.render(:layout => 'layout', :text => textile(body).html_safe)
|
||||
f.write result
|
||||
|
||||
warn_about_broken_links(result) if ENV.key?("WARN_BROKEN_LINKS")
|
||||
end
|
||||
|
||||
result = insert_edge_badge(result) if ENV.key?('INSERT_EDGE_BADGE')
|
||||
f.write result
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -168,5 +172,9 @@ module RailsGuides
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
def insert_edge_badge(html)
|
||||
html.sub(/<body[^>]*>/, '\&<img src="images/edge_badge.png" style="position:fixed; right:0px; top:0px; border:none; z-index:100"/>')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -25,8 +25,9 @@ TIP: To install the Rails 3 prerelease beta using rubygems you have to install a
|
|||
<shell>
|
||||
# Use sudo if your setup requires it
|
||||
gem install tzinfo builder i18n memcache-client rack \
|
||||
rake rack-test rack-mount erubis mail text-format \
|
||||
rake rack-test erubis mail text-format \
|
||||
thor bundler
|
||||
gem install rack-mount -v=0.4
|
||||
gem install rails --pre
|
||||
</shell>
|
||||
|
||||
|
@ -50,8 +51,8 @@ h4. script/* replaced by script/rails
|
|||
The new <tt>script/rails</tt> replaces all the scripts that used to be in the <tt>script</tt> directory. You do not run <tt>script/rails</tt> directly though, the +rails+ command detects it is being invoked in the root of a Rails application and runs the script for you. Intended usage is:
|
||||
|
||||
<shell>
|
||||
rails console # => ./script/console
|
||||
rails g scaffold post title:string # => ./script/generate scaffold post title:string
|
||||
rails console # instead of script/console
|
||||
rails g scaffold post title:string # instead of script/generate scaffold post title:string
|
||||
</shell>
|
||||
|
||||
Run <tt>rails --help</tt> for a list of all the options.
|
||||
|
@ -529,8 +530,8 @@ The security patch for REXML remains in Active Support because early patchlevels
|
|||
The following methods have been removed because they are no longer used in the framework:
|
||||
|
||||
* +Kernel#daemonize+
|
||||
* <tt>Object#remove_subclasses_of</tt>, <tt>Object#subclasses_of</tt>, <tt>Object#extend_with_included_modules_from</tt>, <tt>Object#extended_by</tt>
|
||||
* <tt>Class#subclasses</tt>, <tt>Class#reachable?</tt>, <tt>Class#remove_class</tt>
|
||||
* <tt>Object#remove_subclasses_of</tt> <tt>Object#extend_with_included_modules_from</tt>, <tt>Object#extended_by</tt>
|
||||
* <tt>Class#remove_class</tt>
|
||||
* <tt>Regexp#number_of_captures</tt>, <tt>Regexp.unoptionalize</tt>, <tt>Regexp.optionalize</tt>, <tt>Regexp#number_of_captures</tt>
|
||||
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ h4. Walkthrough to Generating a Mailer
|
|||
h5. Create the Mailer
|
||||
|
||||
<shell>
|
||||
./script/generate mailer UserMailer
|
||||
rails generate mailer UserMailer
|
||||
create app/mailers/user_mailer.rb
|
||||
invoke erb
|
||||
create app/views/user_mailer
|
||||
|
@ -111,7 +111,7 @@ Let's see how we would go about wiring it up using an observer.
|
|||
First off, we need to create a simple +User+ scaffold:
|
||||
|
||||
<shell>
|
||||
$ script/generate scaffold user name:string email:string login:string
|
||||
$ rails generate scaffold user name:string email:string login:string
|
||||
$ rake db:migrate
|
||||
</shell>
|
||||
|
||||
|
@ -333,7 +333,7 @@ Receiving and parsing emails with Action Mailer can be a rather complex endeavou
|
|||
|
||||
* Implement a +receive+ method in your mailer.
|
||||
|
||||
* Configure your email server to forward emails from the address(es) you would like your app to receive to +/path/to/app/script/runner 'UserMailer.receive(STDIN.read)'+.
|
||||
* Configure your email server to forward emails from the address(es) you would like your app to receive to +/path/to/app/script/rails runner 'UserMailer.receive(STDIN.read)'+.
|
||||
|
||||
Once a method called +receive+ is defined in any mailer, Action Mailer will parse the raw incoming email into an email object, decode it, instantiate a new mailer, and pass the email object to the mailer +receive+ instance method. Here's an example:
|
||||
|
||||
|
|
|
@ -33,13 +33,13 @@ gem install actionpack
|
|||
gem install rack
|
||||
</shell>
|
||||
|
||||
Now we'll create a simple "Hello World" application that uses the +titleize+ method provided by Action View.
|
||||
Now we'll create a simple "Hello World" application that uses the +titleize+ method provided by Active Support.
|
||||
|
||||
*hello_world.rb:*
|
||||
|
||||
<ruby>
|
||||
require 'rubygems'
|
||||
require 'action_view'
|
||||
require 'active_support/core_ext/string/inflections'
|
||||
require 'rack'
|
||||
|
||||
def hello_world(env)
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue