1
0
Fork 0
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:
Mikel Lindsaar 2010-03-11 22:07:48 +11:00
commit 965fe59bff
173 changed files with 3634 additions and 2185 deletions

18
Gemfile
View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -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

View file

@ -1,5 +1,6 @@
require "action_controller"
require "rails"
require "action_view/railtie"
module ActionController
class Railtie < Rails::Railtie

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View 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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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" %>

View file

@ -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

View file

@ -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&lt;=?"/>), @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

View file

@ -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

View file

@ -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")

View file

@ -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 = []

View file

@ -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>&lt;b&gt; test with unsafe string &lt;/b&gt;</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"))

View file

@ -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]

View file

@ -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

View file

@ -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

View file

@ -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/**/*"]

View file

@ -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

View file

@ -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.

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -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

View file

@ -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

View file

@ -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

View 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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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'

View file

@ -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
########################################################################

View file

@ -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

View file

@ -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]

View file

@ -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

View file

@ -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'

View file

@ -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'

View file

@ -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

View file

@ -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)

View file

@ -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'

View file

@ -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

View file

@ -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)

View file

@ -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'

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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'

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View 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

View file

@ -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

View file

@ -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'

View file

@ -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

View file

@ -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.
# ...

View 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

View 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

View 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

View file

@ -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

View file

@ -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?

View file

@ -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

View file

@ -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'

View file

@ -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|

View file

@ -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

View file

@ -7,12 +7,6 @@ class NuclearExplosion < StandardError
end
class MadRonon < StandardError
attr_accessor :message
def initialize(message)
@message = message
super()
end
end
class Stargate

View file

@ -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}"}

View file

@ -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

View file

@ -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
View 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

View file

@ -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

View file

@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

View file

@ -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

View file

@ -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>

View file

@ -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:

View file

@ -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