提交 d1eed079 编写于 作者: M Mikel Lindsaar

Merge branch 'master' of git://github.com/rails/rails

gem "rake", ">= 0.8.7"
path File.expand_path('..', __FILE__)
source :gemcutter
gem "rails", "3.0.pre"
gem "rake", ">= 0.8.7"
gem "mocha", ">= 0.9.8"
gem "ruby-debug", ">= 0.10.3" if RUBY_VERSION < '1.9'
gem "rails", "3.0.pre", :path => "railties"
%w(activesupport activemodel actionpack actionmailer activerecord activeresource).each do |lib|
gem lib, '3.0.pre', :path => lib
if RUBY_VERSION < '1.9'
gem "ruby-debug", ">= 0.10.3"
end
# AR
gem "arel", "0.2.pre", :git => "git://github.com/rails/arel.git"
gem "sqlite3-ruby", ">= 1.2.5"
only :test do
group :test do
gem "pg", ">= 0.8.0"
gem "mysql", ">= 2.8.1"
end
......@@ -21,8 +23,6 @@ gem "rack-test", "0.5.3"
gem "RedCloth", ">= 4.2.2"
if ENV['CI']
disable_system_gems
gem "nokogiri", ">= 1.4.0"
gem "memcache-client", ">= 1.7.6"
......@@ -34,5 +34,3 @@ if ENV['CI']
gem "test-unit", ">= 2.0.5"
end
end
disable_system_gems
......@@ -38,7 +38,6 @@ Rake::GemPackageTask.new(spec) do |pkg|
end
task :install => :gem do
system %(cd arel && gem build arel.gemspec && gem install arel-0.2.pre.gem --no-ri --no-rdoc --ignore-dependencies)
system %(cd rack && rake gem VERSION=1.0.2.pre && gem install rack-1.0.2.pre.gem --no-ri --no-rdoc --ignore-dependencies)
(PROJECTS - ["railties"]).each do |project|
puts "INSTALLING #{project}"
......
......@@ -268,13 +268,13 @@ class Base < AbstractController::Base
private_class_method :new #:nodoc:
extlib_inheritable_accessor :default_params
class_attribute :default_params
self.default_params = {
:mime_version => "1.0",
:charset => "utf-8",
:content_type => "text/plain",
:parts_order => [ "text/plain", "text/enriched", "text/html" ]
}
}.freeze
class << self
......@@ -284,9 +284,9 @@ def mailer_name
attr_writer :mailer_name
alias :controller_path :mailer_name
def default(value=nil)
self.default_params.merge!(value) if value
self.default_params
def default(value = nil)
self.default_params = default_params.merge(value).freeze if value
default_params
end
# Receives a raw email, parses it into an email object, decodes it,
......
......@@ -7,8 +7,7 @@ module DeliveryMethods
extend ActiveSupport::Concern
included do
extlib_inheritable_accessor :delivery_methods, :delivery_method,
:instance_writer => false
class_attribute :delivery_methods, :delivery_method
# Do not make this inheritable, because we always want it to propagate
cattr_accessor :raise_delivery_errors
......@@ -17,7 +16,7 @@ module DeliveryMethods
cattr_accessor :perform_deliveries
self.perform_deliveries = true
self.delivery_methods = {}
self.delivery_methods = {}.freeze
self.delivery_method = :smtp
add_delivery_method :smtp, Mail::SMTP,
......@@ -53,12 +52,9 @@ module ClassMethods
# :arguments => '-i -t'
#
def add_delivery_method(symbol, klass, default_options={})
unless respond_to?(:"#{symbol}_settings")
extlib_inheritable_accessor(:"#{symbol}_settings", :instance_writer => false)
end
class_attribute(:"#{symbol}_settings") unless respond_to?(:"#{symbol}_settings")
send(:"#{symbol}_settings=", default_options)
self.delivery_methods[symbol.to_sym] = klass
self.delivery_methods = delivery_methods.merge(symbol.to_sym => klass).freeze
end
def wrap_delivery_behavior(mail, method=nil) #:nodoc:
......@@ -87,4 +83,4 @@ def wrap_delivery_behavior!(*args) #:nodoc:
self.class.wrap_delivery_behavior(message, *args)
end
end
end
\ No newline at end of file
end
......@@ -47,7 +47,7 @@ def template_root
end
def template_root=(root)
ActiveSupport::Deprecation.warn "template_root= is deprecated, use view_paths.unshift instead", caller[0,2]
ActiveSupport::Deprecation.warn "template_root= is deprecated, use prepend_view_path instead", caller[0,2]
self.view_paths = ActionView::Base.process_view_paths(root)
end
......
begin
require File.expand_path('../../../vendor/gems/environment', __FILE__)
rescue LoadError
end
lib = File.expand_path('../../lib', __FILE__)
$:.unshift(lib) unless $:.include?('lib') || $:.include?(lib)
require File.expand_path('../../../load_paths', __FILE__)
require 'rubygems'
require 'test/unit'
require 'action_mailer'
require 'action_mailer/test_case'
# Show backtraces for deprecated behavior for quicker cleanup.
ActiveSupport::Deprecation.debug = true
......
......@@ -81,8 +81,8 @@ def custom_block(include_html=false)
def different_template(template_name='')
mail do |format|
format.text { render :template => template_name }
format.html { render :template => template_name }
format.text { render :template => "#{mailer_name}/#{template_name}" }
format.html { render :template => "#{mailer_name}/#{template_name}" }
end
end
......@@ -254,7 +254,7 @@ def different_layout(layout_name='')
end
test "subject gets default from I18n" do
BaseMailer.default[:subject] = nil
BaseMailer.default :subject => nil
email = BaseMailer.welcome(:subject => nil)
assert_equal "Welcome", email.subject
......@@ -331,22 +331,24 @@ def different_layout(layout_name='')
end
test "implicit multipart with several view paths uses the first one with template" do
old = BaseMailer.view_paths
begin
BaseMailer.view_paths.unshift(File.join(FIXTURE_LOAD_PATH, "another.path"))
BaseMailer.view_paths = [File.join(FIXTURE_LOAD_PATH, "another.path")] + old.dup
email = BaseMailer.welcome
assert_equal("Welcome from another path", email.body.encoded)
ensure
BaseMailer.view_paths.shift
BaseMailer.view_paths = old
end
end
test "implicit multipart with inexistent templates uses the next view path" do
old = BaseMailer.view_paths
begin
BaseMailer.view_paths.unshift(File.join(FIXTURE_LOAD_PATH, "unknown"))
BaseMailer.view_paths = [File.join(FIXTURE_LOAD_PATH, "unknown")] + old.dup
email = BaseMailer.welcome
assert_equal("Welcome", email.body.encoded)
ensure
BaseMailer.view_paths.shift
BaseMailer.view_paths = old
end
end
......@@ -503,16 +505,10 @@ def swap(klass, new_values)
end
def with_default(klass, new_values)
hash = klass.default
old_values = {}
new_values.each do |key, value|
old_values[key] = hash[key]
hash[key] = value
end
old = klass.default_params
klass.default(new_values)
yield
ensure
old_values.each do |key, value|
hash[key] = value
end
klass.default_params = old
end
end
......@@ -45,7 +45,9 @@ def setup
def teardown
ActionMailer::Base.delivery_method = @old_delivery_method
ActionMailer::Base.delivery_methods.delete(:custom)
new = ActionMailer::Base.delivery_methods.dup
new.delete(:custom)
ActionMailer::Base.delivery_methods = new
end
test "allow to add custom delivery method" do
......@@ -167,4 +169,4 @@ def teardown
assert_equal(0, DeliveryMailer.deliveries.length)
end
end
\ No newline at end of file
end
require 'active_support/dependencies'
require 'active_support/core_ext/class/attribute'
require 'active_support/core_ext/module/delegation'
module AbstractController
module Helpers
......@@ -12,10 +14,10 @@ def self.next_serial
end
included do
extlib_inheritable_accessor(:_helpers) { Module.new }
extlib_inheritable_accessor(:_helper_serial) do
AbstractController::Helpers.next_serial
end
class_attribute :_helpers, :_helper_serial
delegate :_helpers, :to => :'self.class'
self._helpers = Module.new
self._helper_serial = ::AbstractController::Helpers.next_serial
end
module ClassMethods
......
require 'active_support/core_ext/class/attribute'
require 'active_support/core_ext/module/delegation'
module AbstractController
# Layouts reverse the common pattern of including shared headers and footers in many templates to isolate changes in
# repeated setups. The inclusion pattern has pages that look like this:
......@@ -161,8 +164,9 @@ module Layouts
include Rendering
included do
extlib_inheritable_accessor(:_layout_conditions) { Hash.new }
extlib_inheritable_accessor(:_action_has_layout) { Hash.new }
class_attribute :_layout_conditions
delegate :_layout_conditions, :to => :'self.class'
self._layout_conditions = {}
_write_layout_method
end
......
require "abstract_controller/base"
require 'active_support/core_ext/class/attribute'
require 'active_support/core_ext/module/delegation'
require 'active_support/core_ext/array/wrap'
module AbstractController
class DoubleRenderError < Error
......@@ -13,8 +16,9 @@ module Rendering
extend ActiveSupport::Concern
included do
extlib_inheritable_accessor :_view_paths
self._view_paths ||= ActionView::PathSet.new
class_attribute :_view_paths
delegate :_view_paths, :to => :'self.class'
self._view_paths = ActionView::PathSet.new
end
# An instance of a view class. The default view class is ActionView::Base
......@@ -156,7 +160,6 @@ def _determine_template(options)
elsif options.key?(:file)
options[:_template_name] = options[:file]
end
name = (options[:_template_name] || options[:action] || action_name).to_s
options[:_prefix] ||= _prefix if (options.keys & [:partial, :file, :template]).empty?
......@@ -201,7 +204,7 @@ def clear_template_caches!
# the default view path. You may also provide a custom view path
# (see ActionView::ViewPathSet for more information)
def append_view_path(path)
self.view_paths << path
self.view_paths = view_paths.dup + Array.wrap(path)
end
# Prepend a path to the list of view paths for this controller.
......@@ -212,12 +215,12 @@ def append_view_path(path)
# (see ActionView::ViewPathSet for more information)
def prepend_view_path(path)
clear_template_caches!
self.view_paths.unshift(path)
self.view_paths = Array.wrap(path) + view_paths.dup
end
# A list of all of the default view paths for this controller.
def view_paths
self._view_paths
_view_paths
end
# Set the view paths.
......@@ -228,7 +231,8 @@ def view_paths
def view_paths=(paths)
clear_template_caches!
self._view_paths = paths.is_a?(ActionView::PathSet) ? paths : ActionView::Base.process_view_paths(paths)
_view_paths.freeze
end
end
end
end
\ No newline at end of file
end
require 'active_support/core_ext/class/inheritable_attributes'
require 'active_support/core_ext/class/attribute'
module ActionController
# ActionController::Metal provides a way to get a valid Rack application from a controller.
......@@ -90,7 +90,12 @@ def call(env)
end
end
extlib_inheritable_accessor(:middleware_stack) { ActionDispatch::MiddlewareStack.new }
class_attribute :middleware_stack
self.middleware_stack = ActionDispatch::MiddlewareStack.new
def self.inherited(base)
self.middleware_stack = base.middleware_stack.dup
end
def self.use(*args)
middleware_stack.use(*args)
......
......@@ -15,9 +15,6 @@ class ::ActionController::ActionControllerError < StandardError #:nodoc:
cattr_accessor :session_options
self.session_options = {}
cattr_accessor :allow_concurrency
self.allow_concurrency = false
cattr_accessor :relative_url_root
self.relative_url_root = ENV['RAILS_RELATIVE_URL_ROOT']
......@@ -44,9 +41,6 @@ class << self
self.page_cache_directory = defined?(Rails.public_path) ? Rails.public_path : ""
cattr_accessor :consider_all_requests_local
self.consider_all_requests_local = true
# Prepends all the URL-generating helpers from AssetHelper. This makes it possible to easily move javascripts, stylesheets,
# and images to a dedicated asset server away from the main web server. Example:
# ActionController::Base.asset_host = "http://assets.example.com"
......@@ -74,6 +68,25 @@ def process_action(*)
module ClassMethods
def consider_all_requests_local
ActiveSupport::Deprecation.warn "ActionController::Base.consider_all_requests_local is deprecated, " <<
"use Rails.application.config.consider_all_requests_local instead"
Rails.application.config.consider_all_requests_local
end
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="
end
def allow_concurrency
ActiveSupport::Deprecation.warn "ActionController::Base.allow_concurrency is deprecated, " <<
"use Rails.application.config.allow_concurrency instead"
Rails.application.config.allow_concurrency
end
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="
end
def rescue_action(env)
......@@ -86,6 +99,9 @@ def cache_store=(store_option)
end
end
delegate :consider_all_requests_local, :consider_all_requests_local=,
:allow_concurrency, :allow_concurrency=, :to => :"self.class"
def render_to_body(options)
if options.is_a?(Hash) && options.key?(:template)
options[:template].sub!(/^\//, '')
......
require 'active_support/core_ext/class/attribute'
module ActionController
# The Rails framework provides a large number of helpers for working with +assets+, +dates+, +forms+,
# +numbers+ and model objects, to name a few. These helpers are available to all templates
......@@ -50,7 +52,7 @@ module Helpers
include AbstractController::Helpers
included do
extlib_inheritable_accessor(:helpers_path)
class_attribute :helpers_path
self.helpers_path = []
end
......
require 'active_support/core_ext/class/attribute'
module ActionController
# ActionController::HideActions adds the ability to prevent public methods on a controller
# to be called as actions.
......@@ -5,7 +7,8 @@ module HideActions
extend ActiveSupport::Concern
included do
extlib_inheritable_accessor(:hidden_actions) { Set.new }
class_attribute :hidden_actions
self.hidden_actions = Set.new
end
private
......@@ -14,7 +17,7 @@ module HideActions
# action name is in the list of hidden actions.
def action_method?(action_name)
self.class.visible_action?(action_name) do
!hidden_actions.include?(action_name) && super
!self.class.hidden_actions.include?(action_name) && super
end
end
......@@ -24,7 +27,7 @@ module ClassMethods
# ==== Parameters
# *args<#to_s>:: A list of actions
def hide_action(*args)
hidden_actions.merge(args.map! {|a| a.to_s })
self.hidden_actions = hidden_actions.dup.merge(args.map(&:to_s))
end
def inherited(klass)
......
require 'abstract_controller/collector'
require 'active_support/core_ext/class/attribute'
module ActionController #:nodoc:
module MimeResponds #:nodoc:
extend ActiveSupport::Concern
included do
extlib_inheritable_accessor :responder, :mimes_for_respond_to, :instance_writer => false
class_attribute :responder, :mimes_for_respond_to
self.responder = ActionController::Responder
clear_respond_to
end
......@@ -38,18 +39,20 @@ def respond_to(*mimes)
only_actions = Array(options.delete(:only))
except_actions = Array(options.delete(:except))
new = mimes_for_respond_to.dup
mimes.each do |mime|
mime = mime.to_sym
mimes_for_respond_to[mime] = {}
mimes_for_respond_to[mime][:only] = only_actions unless only_actions.empty?
mimes_for_respond_to[mime][:except] = except_actions unless except_actions.empty?
new[mime] = {}
new[mime][:only] = only_actions unless only_actions.empty?
new[mime][:except] = except_actions unless except_actions.empty?
end
self.mimes_for_respond_to = new.freeze
end
# Clear all mimes in respond_to.
#
def clear_respond_to
self.mimes_for_respond_to = ActiveSupport::OrderedHash.new
self.mimes_for_respond_to = ActiveSupport::OrderedHash.new.freeze
end
end
......@@ -218,12 +221,12 @@ def respond_to(*mimes, &block)
#
def respond_with(*resources, &block)
raise "In order to use respond_with, first you need to declare the formats your " <<
"controller responds to in the class level" if mimes_for_respond_to.empty?
"controller responds to in the class level" if self.class.mimes_for_respond_to.empty?
if response = retrieve_response_from_mimes(&block)
options = resources.extract_options!
options.merge!(:default_response => response)
(options.delete(:responder) || responder).call(self, resources, options)
(options.delete(:responder) || self.class.responder).call(self, resources, options)
end
end
......@@ -235,8 +238,8 @@ def respond_with(*resources, &block)
def collect_mimes_from_class_level #:nodoc:
action = action_name.to_sym
mimes_for_respond_to.keys.select do |mime|
config = mimes_for_respond_to[mime]
self.class.mimes_for_respond_to.keys.select do |mime|
config = self.class.mimes_for_respond_to[mime]
if config[:except]
!config[:except].include?(action)
......
require 'active_support/core_ext/class/attribute'
module ActionController
def self.add_renderer(key, &block)
Renderers.add(key, &block)
......@@ -7,8 +9,8 @@ module Renderers
extend ActiveSupport::Concern
included do
extlib_inheritable_accessor :_renderers
self._renderers = {}
class_attribute :_renderers
self._renderers = {}.freeze
end
module ClassMethods
......@@ -30,9 +32,11 @@ def _handle_render_options(options)
end
def use_renderers(*args)
new = _renderers.dup
args.each do |key|
_renderers[key] = RENDERERS[key]
new[key] = RENDERERS[key]
end
self._renderers = new.freeze
_write_render_options
end
alias use_renderer use_renderers
......
require 'active_support/core_ext/class/attribute'
module ActionController #:nodoc:
class InvalidAuthenticityToken < ActionControllerError #:nodoc:
end
......@@ -13,7 +15,7 @@ module RequestForgeryProtection
cattr_accessor :request_forgery_protection_token
# Controls whether request forgergy protection is turned on or not. Turned off by default only in test mode.
extlib_inheritable_accessor :allow_forgery_protection
class_attribute :allow_forgery_protection
self.allow_forgery_protection = true
helper_method :form_authenticity_token
......@@ -107,7 +109,7 @@ def form_authenticity_param
end
def protect_against_forgery?
allow_forgery_protection
self.class.allow_forgery_protection
end
end
end
require 'active_support/core_ext/class/attribute'
module ActionController
# In <b>routes.rb</b> one defines URL-to-controller mappings, but the reverse
# is also possible: an URL can be generated from one of your routing definitions.
......@@ -85,9 +87,8 @@ module UrlFor
included do
ActionController::Routing::Routes.install_helpers(self)
extlib_inheritable_accessor :default_url_options,
:instance_writer => false, :instance_reader => false
self.default_url_options ||= {}
class_attribute :default_url_options
self.default_url_options = {}
end
# Overwrite to implement a number of default options that all url_for-based methods will use. The default options should come in
......
......@@ -35,7 +35,6 @@ module ActionView
autoload :Context
autoload :Template
autoload :Helpers
autoload :SafeBuffer
autoload_under "render" do
autoload :Partials
......@@ -56,7 +55,7 @@ module ActionView
autoload :TestCase, 'action_view/test_case'
end
require 'action_view/erb/util'
require 'active_support/core_ext/string/output_safety'
require 'action_view/base'
I18n.load_path << "#{File.dirname(__FILE__)}/action_view/locale/en.yml"
require 'active_support/core_ext/module/attr_internal'
require 'active_support/core_ext/module/delegation'
require 'active_support/core_ext/class/attribute'
module ActionView #:nodoc:
class ActionViewError < StandardError #:nodoc:
......@@ -244,7 +245,7 @@ def self.process_view_paths(value)
ActionView::PathSet.new(Array(value))
end
extlib_inheritable_accessor :helpers
class_attribute :helpers
attr_reader :helpers
def self.for_controller(controller)
......@@ -284,7 +285,7 @@ def initialize(view_paths = [], assigns_for_first_render = {}, controller = nil,
@helpers = self.class.helpers || Module.new
@_controller = controller
@_content_for = Hash.new {|h,k| h[k] = ActionView::SafeBuffer.new }
@_content_for = Hash.new {|h,k| h[k] = ActiveSupport::SafeBuffer.new }
@_virtual_path = nil
self.view_paths = view_paths
end
......
require 'erb'
class ERB
module Util
HTML_ESCAPE = { '&' => '&amp;', '>' => '&gt;', '<' => '&lt;', '"' => '&quot;' }
JSON_ESCAPE = { '&' => '\u0026', '>' => '\u003E', '<' => '\u003C' }
# A utility method for escaping HTML tag characters.
# This method is also aliased as <tt>h</tt>.
#
# In your ERb templates, use this method to escape any unsafe content. For example:
# <%=h @person.name %>
#
# ==== Example:
# puts html_escape("is a > 0 & a < 10?")
# # => is a &gt; 0 &amp; a &lt; 10?
def html_escape(s)
s = s.to_s
if s.html_safe?
s
else
s.gsub(/[&"><]/) { |special| HTML_ESCAPE[special] }.html_safe!
end
end
undef :h
alias h html_escape
module_function :html_escape
module_function :h
# A utility method for escaping HTML entities in JSON strings.
# This method is also aliased as <tt>j</tt>.
#
# In your ERb templates, use this method to escape any HTML entities:
# <%=j @person.to_json %>
#
# ==== Example:
# puts json_escape("is a > 0 & a < 10?")
# # => is a \u003E 0 \u0026 a \u003C 10?
def json_escape(s)
s.to_s.gsub(/[&"><]/) { |special| JSON_ESCAPE[special] }
end
alias j json_escape
module_function :j
module_function :json_escape
end
end
......@@ -6,7 +6,7 @@
module ActionView
class Base
@@field_error_proc = Proc.new{ |html_tag, instance| "<div class=\"fieldWithErrors\">#{html_tag}</div>".html_safe! }
@@field_error_proc = Proc.new{ |html_tag, instance| "<div class=\"fieldWithErrors\">#{html_tag}</div>".html_safe }
cattr_accessor :field_error_proc
end
......@@ -86,12 +86,11 @@ def form(record_name, options = {})
submit_value = options[:submit_value] || options[:action].gsub(/[^\w]/, '').capitalize
contents = form_tag({:action => action}, :method =>(options[:method] || 'post'), :enctype => options[:multipart] ? 'multipart/form-data': nil)
contents << hidden_field(record_name, :id) unless record.new_record?
contents << all_input_tags(record, record_name, options)
contents.safe_concat hidden_field(record_name, :id) unless record.new_record?
contents.safe_concat all_input_tags(record, record_name, options)
yield contents if block_given?
contents << submit_tag(submit_value)
contents << '</form>'
contents.html_safe!
contents.safe_concat submit_tag(submit_value)
contents.safe_concat('</form>')
end
# Returns a string containing the error message attached to the +method+ on the +object+ if one exists.
......
......@@ -293,7 +293,7 @@ def javascript_include_tag(*sources)
else
sources = expand_javascript_sources(sources, recursive)
ensure_javascript_sources!(sources) if cache
sources.collect { |source| javascript_src_tag(source, options) }.join("\n").html_safe!
sources.collect { |source| javascript_src_tag(source, options) }.join("\n").html_safe
end
end
......@@ -444,7 +444,7 @@ def stylesheet_link_tag(*sources)
else
sources = expand_stylesheet_sources(sources, recursive)
ensure_stylesheet_sources!(sources) if cache
sources.collect { |source| stylesheet_tag(source, options) }.join("\n").html_safe!
sources.collect { |source| stylesheet_tag(source, options) }.join("\n").html_safe
end
end
......@@ -588,7 +588,7 @@ def video_tag(sources, options = {})
if sources.is_a?(Array)
content_tag("video", options) do
sources.map { |source| tag("source", :src => source) }.join.html_safe!
sources.map { |source| tag("source", :src => source) }.join.html_safe
end
else
options[:src] = path_to_video(sources)
......
......@@ -143,7 +143,7 @@ def content_for?(name)
# Defaults to a new empty string.
def with_output_buffer(buf = nil) #:nodoc:
unless buf
buf = ActionView::SafeBuffer.new
buf = ActiveSupport::SafeBuffer.new
buf.force_encoding(output_buffer.encoding) if buf.respond_to?(:force_encoding)
end
self.output_buffer, old_buffer = buf, output_buffer
......
......@@ -616,7 +616,7 @@ def select_datetime
build_selects_from_types(order)
else
"#{select_date}#{@options[:datetime_separator]}#{select_time}".html_safe!
"#{select_date}#{@options[:datetime_separator]}#{select_time}".html_safe
end
end
......@@ -835,7 +835,7 @@ def build_select(type, select_options_as_html)
select_html << prompt_option_tag(type, @options[:prompt]) + "\n" if @options[:prompt]
select_html << select_options_as_html.to_s
(content_tag(:select, select_html, select_options) + "\n").html_safe!
(content_tag(:select, select_html, select_options) + "\n").html_safe
end
# Builds a prompt option tag with supplied options or from default options
......@@ -865,7 +865,7 @@ def build_hidden(type, value)
:id => input_id_from_type(type),
:name => input_name_from_type(type),
:value => value
}) + "\n").html_safe!
}) + "\n").html_safe
end
# Returns the name attribute for the input tag
......@@ -896,7 +896,7 @@ def build_selects_from_types(order)
separator = separator(type) unless type == order.first # don't add on last field
select.insert(0, separator.to_s + send("select_#{type}").to_s)
end
select.html_safe!
select.html_safe
end
# Returns the separator for a given datetime component
......@@ -916,15 +916,15 @@ def separator(type)
class InstanceTag #:nodoc:
def to_date_select_tag(options = {}, html_options = {})
datetime_selector(options, html_options).select_date.html_safe!
datetime_selector(options, html_options).select_date.html_safe
end
def to_time_select_tag(options = {}, html_options = {})
datetime_selector(options, html_options).select_time.html_safe!
datetime_selector(options, html_options).select_time.html_safe
end
def to_datetime_select_tag(options = {}, html_options = {})
datetime_selector(options, html_options).select_datetime.html_safe!
datetime_selector(options, html_options).select_datetime.html_safe
end
private
......
......@@ -27,10 +27,10 @@ module DebugHelper
def debug(object)
begin
Marshal::dump(object)
"<pre class='debug_dump'>#{h(object.to_yaml).gsub(" ", "&nbsp; ")}</pre>".html_safe!
"<pre class='debug_dump'>#{h(object.to_yaml).gsub(" ", "&nbsp; ")}</pre>".html_safe
rescue Exception => e # errors from Marshal or YAML
# Object couldn't be dumped, perhaps because of singleton methods -- this is the fallback
"<code class='debug_dump'>#{h(object.inspect)}</code>".html_safe!
"<code class='debug_dump'>#{h(object.inspect)}</code>".html_safe
end
end
end
......
......@@ -311,7 +311,7 @@ def form_for(record_or_name_or_array, *args, &proc)
concat(form_tag(options.delete(:url) || {}, options.delete(:html) || {}))
fields_for(object_name, *(args << options), &proc)
concat('</form>'.html_safe!)
safe_concat('</form>')
end
def apply_form_for_options!(object_or_array, options) #:nodoc:
......@@ -879,7 +879,7 @@ def to_check_box_tag(options = {}, checked_value = "1", unchecked_value = "0")
end
hidden = tag("input", "name" => options["name"], "type" => "hidden", "value" => options['disabled'] && checked ? checked_value : unchecked_value)
checkbox = tag("input", options)
(hidden + checkbox).html_safe!
(hidden + checkbox).html_safe
end
def to_boolean_select_tag(options = {})
......
......@@ -296,7 +296,7 @@ def options_for_select(container, selected = nil)
options << %(<option value="#{html_escape(value.to_s)}"#{selected_attribute}#{disabled_attribute}>#{html_escape(text.to_s)}</option>)
end
options_for_select.join("\n").html_safe!
options_for_select.join("\n").html_safe
end
# Returns a string of option tags that have been compiled by iterating over the +collection+ and assigning the
......
......@@ -446,7 +446,7 @@ def field_set_tag(legend = nil, options = nil, &block)
concat(tag(:fieldset, options, true))
concat(content_tag(:legend, legend)) unless legend.blank?
concat(content)
concat("</fieldset>".html_safe!)
safe_concat("</fieldset>")
end
private
......@@ -474,14 +474,14 @@ def extra_tags_for_form(html_options)
def form_tag_html(html_options)
extra_tags = extra_tags_for_form(html_options)
(tag(:form, html_options, true) + extra_tags).html_safe!
(tag(:form, html_options, true) + extra_tags).html_safe
end
def form_tag_in_block(html_options, &block)
content = capture(&block)
concat(form_tag_html(html_options))
concat(content)
concat("</form>".html_safe!)
safe_concat("</form>")
end
def token_tag
......
......@@ -92,7 +92,7 @@ def number_to_currency(number, options = {})
:precision => precision,
:delimiter => delimiter,
:separator => separator)
).gsub(/%u/, unit).html_safe!
).gsub(/%u/, unit).html_safe
rescue
number
end
......
......@@ -610,7 +610,7 @@ def method_missing(method, *arguments)
# page.hide 'spinner'
# end
def update_page(&block)
JavaScriptGenerator.new(@template, &block).to_s.html_safe!
JavaScriptGenerator.new(@template, &block).to_s.html_safe
end
# Works like update_page but wraps the generated JavaScript in a <script>
......
......@@ -2,7 +2,7 @@ module ActionView #:nodoc:
module Helpers #:nodoc:
module RawOutputHelper
def raw(stringish)
stringish.to_s.html_safe!
stringish.to_s.html_safe
end
end
end
......
......@@ -50,11 +50,7 @@ module SanitizeHelper
# confuse browsers.
#
def sanitize(html, options = {})
returning self.class.white_list_sanitizer.sanitize(html, options) do |sanitized|
if sanitized
sanitized.html_safe!
end
end
self.class.white_list_sanitizer.sanitize(html, options).try(:html_safe)
end
# Sanitizes a block of CSS code. Used by +sanitize+ when it comes across a style attribute.
......@@ -77,11 +73,7 @@ def sanitize_css(style)
# strip_tags("<div id='top-bar'>Welcome to my website!</div>")
# # => Welcome to my website!
def strip_tags(html)
returning self.class.full_sanitizer.sanitize(html) do |sanitized|
if sanitized
sanitized.html_safe!
end
end
self.class.full_sanitizer.sanitize(html).try(:html_safe)
end
# Strips all link tags from +text+ leaving just the link text.
......
require 'action_view/erb/util'
require 'set'
module ActionView
......@@ -41,7 +40,7 @@ module TagHelper
# tag("img", { :src => "open &amp; shut.png" }, false, false)
# # => <img src="open &amp; shut.png" />
def tag(name, options = nil, open = false, escape = true)
"<#{name}#{tag_options(options, escape) if options}#{open ? ">" : " />"}".html_safe!
"<#{name}#{tag_options(options, escape) if options}#{open ? ">" : " />"}".html_safe
end
# Returns an HTML block tag of type +name+ surrounding the +content+. Add
......@@ -94,7 +93,7 @@ def content_tag(name, content_or_options_with_block = nil, options = nil, escape
# cdata_section(File.read("hello_world.txt"))
# # => <![CDATA[<hello from a text file]]>
def cdata_section(content)
"<![CDATA[#{content}]]>".html_safe!
"<![CDATA[#{content}]]>".html_safe
end
# Returns an escaped version of +html+ without affecting existing escaped entities.
......@@ -128,7 +127,7 @@ def block_called_from_erb?(block)
def content_tag_string(name, content, options, escape = true)
tag_options = tag_options(options, escape) if options
"<#{name}#{tag_options}>#{content}</#{name}>".html_safe!
"<#{name}#{tag_options}>#{content}</#{name}>".html_safe
end
def tag_options(options, escape = true)
......@@ -143,7 +142,7 @@ def tag_options(options, escape = true)
attrs << %(#{key}="#{final_value}")
end
end
" #{attrs.sort * ' '}".html_safe! unless attrs.empty?
" #{attrs.sort * ' '}".html_safe unless attrs.empty?
end
end
end
......
......@@ -24,14 +24,14 @@ module TextHelper
# end
# # will either display "Logged in!" or a login link
# %>
def concat(string, unused_binding = nil)
if unused_binding
ActiveSupport::Deprecation.warn("The binding argument of #concat is no longer needed. Please remove it from your views and helpers.", caller)
end
def concat(string)
output_buffer << string
end
def safe_concat(string)
output_buffer.safe_concat(string)
end
# Truncates a given +text+ after a given <tt>:length</tt> if +text+ is longer than <tt>:length</tt>
# (defaults to 30). The last characters will be replaced with the <tt>:omission</tt> (defaults to "...")
# for a total length not exceeding <tt>:length</tt>.
......
......@@ -12,7 +12,7 @@ module TranslationHelper
# prepend the key with a period, nothing is converted.
def translate(key, options = {})
options[:raise] = true
I18n.translate(scope_key_by_partial(key), options).html_safe!
I18n.translate(scope_key_by_partial(key), options).html_safe
rescue I18n::MissingTranslationData => e
keys = I18n.send(:normalize_translation_keys, e.locale, e.key, e.options[:scope])
content_tag('span', keys.join(', '), :class => 'translation_missing')
......
......@@ -98,7 +98,7 @@ def url_for(options = {})
polymorphic_path(options)
end
escape ? escape_once(url).html_safe! : url
escape ? escape_once(url).html_safe : url
end
# Creates a link tag of the given +name+ using a URL created by the set
......@@ -208,7 +208,7 @@ def link_to(*args, &block)
if block_given?
options = args.first || {}
html_options = args.second
concat(link_to(capture(&block), options, html_options).html_safe!)
safe_concat(link_to(capture(&block), options, html_options))
else
name = args[0]
options = args[1] || {}
......@@ -226,7 +226,7 @@ def link_to(*args, &block)
end
href_attr = "href=\"#{url}\"" unless href
"<a #{href_attr}#{tag_options}>#{ERB::Util.h(name || url)}</a>".html_safe!
"<a #{href_attr}#{tag_options}>#{ERB::Util.h(name || url)}</a>".html_safe
end
end
......@@ -312,7 +312,7 @@ def button_to(name, options = {}, html_options = {})
html_options.merge!("type" => "submit", "value" => name)
("<form method=\"#{form_method}\" action=\"#{escape_once url}\" #{"data-remote=\"true\"" if remote} class=\"button-to\"><div>" +
method_tag + tag("input", html_options) + request_token_tag + "</div></form>").html_safe!
method_tag + tag("input", html_options) + request_token_tag + "</div></form>").html_safe
end
......
......@@ -240,7 +240,7 @@ def render_collection
end
result = @template ? collection_with_template : collection_without_template
result.join(spacer).html_safe!
result.join(spacer).html_safe
end
def collection_with_template(template = @template)
......
module ActionView #:nodoc:
class SafeBuffer < String
def <<(value)
if value.html_safe?
super(value)
else
super(ERB::Util.h(value))
end
end
def concat(value)
self << value
end
def html_safe?
true
end
def html_safe!
self
end
def to_s
self
end
end
end
\ No newline at end of file
require "active_support/core_ext/class/inheritable_attributes"
require "action_dispatch/http/mime_type"
require 'active_support/core_ext/class/attribute'
# Legacy TemplateHandler stub
module ActionView
......@@ -23,7 +23,7 @@ def compile(template)
end
class Template::Handler
extlib_inheritable_accessor :default_format
class_attribute :default_format
self.default_format = Mime::HTML
def self.call(template)
......
......@@ -6,7 +6,7 @@ module ActionView
module Template::Handlers
class Erubis < ::Erubis::Eruby
def add_preamble(src)
src << "@output_buffer = ActionView::SafeBuffer.new;"
src << "@output_buffer = ActiveSupport::SafeBuffer.new;"
end
def add_text(src, text)
......@@ -15,7 +15,11 @@ def add_text(src, text)
end
def add_expr_literal(src, code)
src << '@output_buffer << ((' << code << ').to_s);'
if code =~ /\s*raw\s+(.*)/
src << "@output_buffer.safe_concat((" << $1 << ").to_s);"
else
src << '@output_buffer << ((' << code << ').to_s);'
end
end
def add_expr_escaped(src, code)
......
require "pathname"
require "active_support/core_ext/class"
require "active_support/core_ext/array/wrap"
require "action_view/template"
module ActionView
......@@ -11,7 +12,7 @@ class Resolver
def self.register_detail(name, options = {})
registered_details[name] = lambda do |val|
val ||= yield
val = Array.wrap(val || yield)
val |= [nil] unless options[:allow_nil] == false
val
end
......
......@@ -53,7 +53,7 @@ def initialize
setup :setup_with_controller
def setup_with_controller
@controller = TestController.new
@output_buffer = ActionView::SafeBuffer.new
@output_buffer = ActiveSupport::SafeBuffer.new
@rendered = ''
self.class.send(:include_helper_modules!)
......
begin
require File.expand_path('../../../vendor/gems/environment', __FILE__)
rescue LoadError
end
lib = File.expand_path('../../lib', __FILE__)
$:.unshift(lib) unless $:.include?('lib') || $:.include?(lib)
require File.expand_path('../../../load_paths', __FILE__)
$:.unshift(File.dirname(__FILE__) + '/lib')
$:.unshift(File.dirname(__FILE__) + '/fixtures/helpers')
......@@ -20,9 +14,6 @@
require 'action_dispatch'
require 'fixture_template'
require 'active_support/dependencies'
activemodel_path = File.expand_path('../../../activemodel/lib', __FILE__)
$:.unshift(activemodel_path) if File.directory?(activemodel_path) && !$:.include?(activemodel_path)
require 'active_model'
begin
......
......@@ -611,7 +611,7 @@ def test_fragment_for_with_disabled_caching
@store.write('views/expensive', 'fragment content')
fragment_computed = false
buffer = 'generated till now -> '
buffer = 'generated till now -> '.html_safe
@controller.fragment_for(buffer, 'expensive') { fragment_computed = true }
assert fragment_computed
......@@ -622,7 +622,7 @@ def test_fragment_for
@store.write('views/expensive', 'fragment content')
fragment_computed = false
buffer = 'generated till now -> '
buffer = 'generated till now -> '.html_safe
@controller.fragment_for(buffer, 'expensive') { fragment_computed = true }
assert !fragment_computed
......
......@@ -2,18 +2,19 @@
module RenderTemplate
class WithoutLayoutController < ActionController::Base
self.view_paths = [ActionView::FixtureResolver.new(
"test/basic.html.erb" => "Hello from basic.html.erb",
"shared.html.erb" => "Elastica",
"locals.html.erb" => "The secret is <%= secret %>",
"xml_template.xml.builder" => "xml.html do\n xml.p 'Hello'\nend"
"xml_template.xml.builder" => "xml.html do\n xml.p 'Hello'\nend",
"with_raw.html.erb" => "Hello <%=raw '<strong>this is raw</strong>' %>"
)]
def index
render :template => "test/basic"
end
def index_without_key
render "test/basic"
end
......@@ -25,59 +26,70 @@ def in_top_directory
def in_top_directory_with_slash
render :template => '/shared'
end
def in_top_directory_with_slash_without_key
render '/shared'
end
def with_locals
render :template => "locals", :locals => { :secret => 'area51' }
end
def builder_template
render :template => "xml_template"
end
def with_raw
render :template => "with_raw"
end
end
class TestWithoutLayout < Rack::TestCase
testing RenderTemplate::WithoutLayoutController
test "rendering a normal template with full path without layout" do
get :index
assert_response "Hello from basic.html.erb"
end
test "rendering a normal template with full path without layout without key" do
get :index_without_key
assert_response "Hello from basic.html.erb"
end
test "rendering a template not in a subdirectory" do
get :in_top_directory
assert_response "Elastica"
end
test "rendering a template not in a subdirectory with a leading slash" do
get :in_top_directory_with_slash
assert_response "Elastica"
end
test "rendering a template not in a subdirectory with a leading slash without key" do
get :in_top_directory_with_slash_without_key
assert_response "Elastica"
end
test "rendering a template with local variables" do
get :with_locals
assert_response "The secret is area51"
end
test "rendering a builder template" do
get :builder_template, "format" => "xml"
assert_response "<html>\n <p>Hello</p>\n</html>\n"
end
test "rendering a template with <%=raw stuff %>" do
get :with_raw
assert_body "Hello <strong>this is raw</strong>"
assert_status 200
end
end
class WithLayoutController < ::ApplicationController
self.view_paths = [ActionView::FixtureResolver.new(
"test/basic.html.erb" => "Hello from basic.html.erb",
......@@ -85,28 +97,28 @@ class WithLayoutController < ::ApplicationController
"layouts/application.html.erb" => "<%= yield %>, I'm here!",
"layouts/greetings.html.erb" => "<%= yield %>, I wish thee well."
)]
def index
render :template => "test/basic"
end
def with_layout
render :template => "test/basic", :layout => true
end
def with_layout_false
render :template => "test/basic", :layout => false
end
def with_layout_nil
render :template => "test/basic", :layout => nil
end
def with_custom_layout
render :template => "test/basic", :layout => "greetings"
end
end
class TestWithLayout < Rack::TestCase
describe "Rendering with :template using implicit or explicit layout"
......
......@@ -13,7 +13,7 @@ class OutputEscapingTest < ActiveSupport::TestCase
test "escapeHTML shouldn't touch explicitly safe strings" do
# TODO this seems easier to compose and reason about, but
# this should be verified
assert_equal "<", ERB::Util.h("<".html_safe!)
assert_equal "<", ERB::Util.h("<".html_safe)
end
end
......@@ -142,9 +142,9 @@ class C < ActionController::Base; end
assert_paths A, "a/path"
assert_paths A, *B.view_paths
assert_paths C, *original_load_paths
C.view_paths = []
assert_nothing_raised { C.view_paths << 'c/path' }
assert_nothing_raised { C.append_view_path 'c/path' }
assert_paths C, "c/path"
end
end
......@@ -22,7 +22,7 @@ def test_html_escape_is_html_safe
end
def test_html_escape_passes_html_escpe_unmodified
escaped = h("<p>".html_safe!)
escaped = h("<p>".html_safe)
assert_equal "<p>", escaped
assert escaped.html_safe?
end
......
......@@ -1170,7 +1170,7 @@ class LabelledFormBuilder < ActionView::Helpers::FormBuilder
(field_helpers - %w(hidden_field)).each do |selector|
src = <<-END_SRC
def #{selector}(field, *args, &proc)
("<label for='\#{field}'>\#{field.to_s.humanize}:</label> " + super + "<br/>").html_safe!
("<label for='\#{field}'>\#{field.to_s.humanize}:</label> " + super + "<br/>").html_safe
end
END_SRC
class_eval src, __FILE__, __LINE__
......
......@@ -335,19 +335,19 @@ def test_field_set_tag_in_erb
expected = %(<fieldset><legend>Your details</legend>Hello world!</fieldset>)
assert_dom_equal expected, output_buffer
self.output_buffer = ''
self.output_buffer = ''.html_safe
field_set_tag { concat "Hello world!" }
expected = %(<fieldset>Hello world!</fieldset>)
assert_dom_equal expected, output_buffer
self.output_buffer = ''
self.output_buffer = ''.html_safe
field_set_tag('') { concat "Hello world!" }
expected = %(<fieldset>Hello world!</fieldset>)
assert_dom_equal expected, output_buffer
self.output_buffer = ''
self.output_buffer = ''.html_safe
field_set_tag('', :class => 'format') { concat "Hello world!" }
expected = %(<fieldset class="format">Hello world!</fieldset>)
......
......@@ -160,7 +160,7 @@ def from_test_case; 'Word!'; end
class AssertionsTest < ActionView::TestCase
def render_from_helper
form_tag('/foo') do
concat render(:text => '<ul><li>foo</li></ul>').html_safe!
safe_concat render(:text => '<ul><li>foo</li></ul>')
end
end
helper_method :render_from_helper
......
begin
require File.expand_path('../../../../vendor/gems/environment', __FILE__)
rescue LoadError
end
lib = File.expand_path('../../../lib', __FILE__)
$:.unshift(lib) unless $:.include?('lib') || $:.include?(lib)
require File.expand_path('../../../../load_paths', __FILE__)
require 'config'
require 'active_model'
......
......@@ -9,7 +9,7 @@
s.add_dependency('activesupport', '= 3.0.pre')
s.add_dependency('activemodel', '= 3.0.pre')
s.add_dependency('arel', '= 0.2.pre')
s.add_dependency('arel', '~> 0.2.0')
s.require_path = 'lib'
s.autorequire = 'active_record'
......
require 'active_support/core_ext/class/attribute'
module ActiveRecord
# Observer classes respond to lifecycle callbacks to implement trigger-like
# behavior outside the original class. This is a great way to reduce the
......@@ -85,7 +87,8 @@ module ActiveRecord
# singletons and that call instantiates and registers them.
#
class Observer < ActiveModel::Observer
extlib_inheritable_accessor(:observed_methods){ [] }
class_attribute :observed_methods
self.observed_methods = []
def initialize
super
......@@ -93,7 +96,7 @@ def initialize
end
def self.method_added(method)
observed_methods << method if ActiveRecord::Callbacks::CALLBACKS.include?(method.to_sym)
self.observed_methods += [method] if ActiveRecord::Callbacks::CALLBACKS.include?(method.to_sym)
end
protected
......@@ -106,7 +109,7 @@ def add_observer!(klass)
# Check if a notifier callback was already added to the given class. If
# it was not, add it.
self.observed_methods.each do |method|
self.class.observed_methods.each do |method|
callback = :"_notify_observers_for_#{method}"
if (klass.instance_methods & [callback, callback.to_s]).empty?
klass.class_eval "def #{callback}; notify_observers(:#{method}); end"
......
begin
require File.expand_path('../../../../vendor/gems/environment', __FILE__)
rescue LoadError
end
lib = File.expand_path('../../../lib', __FILE__)
$:.unshift(lib) unless $:.include?('lib') || $:.include?(lib)
require File.expand_path('../../../../load_paths', __FILE__)
require 'config'
require 'rubygems'
require 'test/unit'
require 'stringio'
......
begin
require File.expand_path('../../../vendor/gems/environment', __FILE__)
rescue LoadError
end
lib = File.expand_path('../../lib', __FILE__)
$:.unshift(lib) unless $:.include?('lib') || $:.include?(lib)
require File.expand_path('../../../load_paths', __FILE__)
require 'rubygems'
require 'test/unit'
......
*Rails 3.0 (pending)*
* 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]
* YAML serialization for OrderedHash. #3608 [Gregor Schmidt]
......
......@@ -67,5 +67,6 @@ module ActiveSupport
autoload :XmlMini
end
autoload :SafeBuffer, "active_support/core_ext/string/output_safety"
autoload :TestCase
end
require 'active_support/core_ext/object/metaclass'
require 'active_support/core_ext/module/delegation'
class Class
# Declare a class-level attribute whose value is inheritable and
# overwritable by subclasses:
#
# class Base
# class_attribute :setting
# end
#
# class Subclass < Base
# end
#
# Base.setting = true
# Subclass.setting # => true
# Subclass.setting = false
# Subclass.setting # => false
# Base.setting # => true
#
# This matches normal Ruby method inheritance: think of writing an attribute
# on a subclass as overriding the reader method.
#
# For convenience, a query method is defined as well:
#
# Subclass.setting? # => false
def class_attribute(*attrs)
attrs.each do |attr|
metaclass.send(:define_method, attr) { }
metaclass.send(:define_method, "#{attr}?") { !!send(attr) }
metaclass.send(:define_method, "#{attr}=") do |value|
metaclass.send(:define_method, attr) { value }
end
end
end
end
require "erb"
class ERB
module Util
HTML_ESCAPE = { '&' => '&amp;', '>' => '&gt;', '<' => '&lt;', '"' => '&quot;' }
JSON_ESCAPE = { '&' => '\u0026', '>' => '\u003E', '<' => '\u003C' }
# A utility method for escaping HTML tag characters.
# This method is also aliased as <tt>h</tt>.
#
# In your ERb templates, use this method to escape any unsafe content. For example:
# <%=h @person.name %>
#
# ==== Example:
# puts html_escape("is a > 0 & a < 10?")
# # => is a &gt; 0 &amp; a &lt; 10?
def html_escape(s)
s = s.to_s
if s.html_safe?
s
else
s.gsub(/[&"><]/) { |special| HTML_ESCAPE[special] }.html_safe
end
end
undef :h
alias h html_escape
module_function :html_escape
module_function :h
# A utility method for escaping HTML entities in JSON strings.
# This method is also aliased as <tt>j</tt>.
#
# In your ERb templates, use this method to escape any HTML entities:
# <%=j @person.to_json %>
#
# ==== Example:
# puts json_escape("is a > 0 & a < 10?")
# # => is a \u003E 0 \u0026 a \u003C 10?
def json_escape(s)
s.to_s.gsub(/[&"><]/) { |special| JSON_ESCAPE[special] }
end
alias j json_escape
module_function :j
module_function :json_escape
end
end
class Object
def html_safe?
false
......@@ -10,32 +60,46 @@ def html_safe?
end
end
class String
attr_accessor :_rails_html_safe
alias html_safe? _rails_html_safe
module ActiveSupport #:nodoc:
class SafeBuffer < String
alias safe_concat concat
def html_safe!
@_rails_html_safe = true
self
end
def concat(value)
if value.html_safe?
super(value)
else
super(ERB::Util.h(value))
end
end
def html_safe
dup.html_safe!
end
def +(other)
dup.concat(other)
end
def <<(value)
self.concat(value)
end
def html_safe?
true
end
def html_safe
self
end
alias original_plus +
def +(other)
result = original_plus(other)
result._rails_html_safe = html_safe? && other.html_safe?
result
def to_s
self
end
end
end
alias original_concat <<
alias safe_concat <<
def <<(other)
@_rails_html_safe = false unless other.html_safe?
result = original_concat(other)
class String
def html_safe!
raise "You can't call html_safe! on a String"
end
alias concat <<
def html_safe
ActiveSupport::SafeBuffer.new(self)
end
end
\ No newline at end of file
require 'active_support/core_ext/class/inheritable_attributes'
require 'active_support/core_ext/class/attribute'
require 'active_support/core_ext/proc'
require 'active_support/core_ext/string/inflections'
require 'active_support/core_ext/array/extract_options'
......@@ -9,7 +9,7 @@ module Rescuable
extend Concern
included do
class_inheritable_accessor :rescue_handlers
class_attribute :rescue_handlers
self.rescue_handlers = []
end
......@@ -67,7 +67,7 @@ def rescue_from(*klasses, &block)
end
# put the new handler at the end because the list is read in reverse
rescue_handlers << [key, options[:with]]
self.rescue_handlers += [[key, options[:with]]]
end
end
end
......@@ -83,7 +83,7 @@ def rescue_with_handler(exception)
def handler_for_rescue(exception)
# We go from right to left because pairs are pushed onto rescue_handlers
# as rescue_from declarations are found.
_, rescuer = rescue_handlers.reverse.detect do |klass_name, handler|
_, rescuer = self.class.rescue_handlers.reverse.detect do |klass_name, handler|
# The purpose of allowing strings in rescue_from is to support the
# declaration of handler associations for exception classes whose
# definition is yet unknown.
......
ORIG_ARGV = ARGV.dup
begin
require File.expand_path('../../../vendor/gems/environment', __FILE__)
rescue LoadError
end
lib = File.expand_path("#{File.dirname(__FILE__)}/../lib")
$:.unshift(lib) unless $:.include?('lib') || $:.include?(lib)
require File.expand_path('../../../load_paths', __FILE__)
require 'test/unit'
require 'mocha'
......
require 'abstract_unit'
require 'active_support/core_ext/class/attribute'
class ClassAttributeTest < ActiveSupport::TestCase
class Base
class_attribute :setting
end
class Subclass < Base
end
def setup
@klass = Class.new { class_attribute :setting }
@sub = Class.new(@klass)
end
test 'defaults to nil' do
assert_nil @klass.setting
assert_nil @sub.setting
end
test 'inheritable' do
@klass.setting = 1
assert_equal 1, @sub.setting
end
test 'overridable' do
@sub.setting = 1
assert_nil @klass.setting
@klass.setting = 2
assert_equal 1, @sub.setting
assert_equal 1, Class.new(@sub).setting
end
test 'query method' do
assert_equal false, @klass.setting?
@klass.setting = 1
assert_equal true, @klass.setting?
end
test 'no instance delegates' do
assert_raise(NoMethodError) { @klass.new.setting }
assert_raise(NoMethodError) { @klass.new.setting? }
end
end
......@@ -342,12 +342,12 @@ def setup
end
test "A string can be marked safe" do
@string.html_safe!
assert @string.html_safe?
string = @string.html_safe
assert string.html_safe?
end
test "Marking a string safe returns the string" do
assert_equal @string, @string.html_safe!
assert_equal @string, @string.html_safe
end
test "A fixnum is safe by default" do
......@@ -361,7 +361,7 @@ def to_str
end
end
@string.html_safe!
@string.html_safe
@string << klass.new
assert_equal "helloother", @string
......@@ -369,44 +369,44 @@ def to_str
end
test "Adding a safe string to another safe string returns a safe string" do
@other_string = "other".html_safe!
@string.html_safe!
@combination = @other_string + @string
@other_string = "other".html_safe
string = @string.html_safe
@combination = @other_string + string
assert_equal "otherhello", @combination
assert @combination.html_safe?
end
test "Adding an unsafe string to a safe string returns an unsafe string" do
@other_string = "other".html_safe!
@combination = @other_string + @string
@other_combination = @string + @other_string
test "Adding an unsafe string to a safe string escapes it and returns a safe string" do
@other_string = "other".html_safe
@combination = @other_string + "<foo>"
@other_combination = @string + "<foo>"
assert_equal "otherhello", @combination
assert_equal "helloother", @other_combination
assert_equal "other&lt;foo&gt;", @combination
assert_equal "hello<foo>", @other_combination
assert !@combination.html_safe?
assert @combination.html_safe?
assert !@other_combination.html_safe?
end
test "Concatting safe onto unsafe yields unsafe" do
@other_string = "other"
@string.html_safe!
@string.html_safe
@other_string.concat(@string)
assert !@other_string.html_safe?
end
test "Concatting unsafe onto safe yields unsafe" do
@other_string = "other".html_safe!
@other_string.concat(@string)
assert !@other_string.html_safe?
test "Concatting unsafe onto safe yields escaped safe" do
@other_string = "other".html_safe
string = @other_string.concat("<foo>")
assert_equal "other&lt;foo&gt;", string
assert string.html_safe?
end
test "Concatting safe onto safe yields safe" do
@other_string = "other".html_safe!
@string.html_safe!
@other_string = "other".html_safe
@string.html_safe
@other_string.concat(@string)
assert @other_string.html_safe?
......@@ -414,31 +414,32 @@ def to_str
test "Concatting safe onto unsafe with << yields unsafe" do
@other_string = "other"
@string.html_safe!
@string.html_safe
@other_string << @string
assert !@other_string.html_safe?
end
test "Concatting unsafe onto safe with << yields unsafe" do
@other_string = "other".html_safe!
@other_string << @string
assert !@other_string.html_safe?
test "Concatting unsafe onto safe with << yields escaped safe" do
@other_string = "other".html_safe
string = @other_string << "<foo>"
assert_equal "other&lt;foo&gt;", string
assert string.html_safe?
end
test "Concatting safe onto safe with << yields safe" do
@other_string = "other".html_safe!
@string.html_safe!
@other_string = "other".html_safe
@string.html_safe
@other_string << @string
assert @other_string.html_safe?
end
test "Concatting a fixnum to safe always yields safe" do
@string.html_safe!
@string.concat(13)
assert @string.html_safe?
string = @string.html_safe
string = string.concat(13)
assert_equal "hello".concat(13), string
assert string.html_safe?
end
end
......
......@@ -301,10 +301,10 @@ def test_rjust_should_count_characters_instead_of_bytes
assert_equal " #{UNICODE_STRING}", @chars.rjust(5)
assert_equal " #{UNICODE_STRING}", @chars.rjust(7)
assert_equal "---#{UNICODE_STRING}", @chars.rjust(7, '-')
assert_equal "ααα#{UNICODE_STRING}", @chars.rjust(7, 'α')
assert_equal "αα#{UNICODE_STRING}", @chars.rjust(7, 'α')
assert_equal "aba#{UNICODE_STRING}", @chars.rjust(7, 'ab')
assert_equal "αηα#{UNICODE_STRING}", @chars.rjust(7, 'αη')
assert_equal "αηαη#{UNICODE_STRING}", @chars.rjust(8, 'αη')
assert_equal "αη#{UNICODE_STRING}", @chars.rjust(8, 'αη')
end
def test_ljust_should_raise_argument_errors_on_bad_arguments
......@@ -319,10 +319,10 @@ def test_ljust_should_count_characters_instead_of_bytes
assert_equal "#{UNICODE_STRING} ", @chars.ljust(5)
assert_equal "#{UNICODE_STRING} ", @chars.ljust(7)
assert_equal "#{UNICODE_STRING}---", @chars.ljust(7, '-')
assert_equal "#{UNICODE_STRING}ααα", @chars.ljust(7, 'α')
assert_equal "#{UNICODE_STRING}αα", @chars.ljust(7, 'α')
assert_equal "#{UNICODE_STRING}aba", @chars.ljust(7, 'ab')
assert_equal "#{UNICODE_STRING}αηα", @chars.ljust(7, 'αη')
assert_equal "#{UNICODE_STRING}αηαη", @chars.ljust(8, 'αη')
assert_equal "#{UNICODE_STRING}αη", @chars.ljust(8, 'αη')
end
def test_center_should_raise_argument_errors_on_bad_arguments
......@@ -339,13 +339,13 @@ def test_center_should_count_charactes_instead_of_bytes
assert_equal " #{UNICODE_STRING} ", @chars.center(7)
assert_equal "--#{UNICODE_STRING}--", @chars.center(8, '-')
assert_equal "--#{UNICODE_STRING}---", @chars.center(9, '-')
assert_equal α#{UNICODE_STRING}αα", @chars.center(8, 'α')
assert_equal α#{UNICODE_STRING}ααα", @chars.center(9, 'α')
assert_equal "a#{UNICODE_STRING}ab", @chars.center(7, 'ab')
assert_equal "ab#{UNICODE_STRING}ab", @chars.center(8, 'ab')
assert_equal "abab#{UNICODE_STRING}abab", @chars.center(12, 'ab')
assert_equal #{UNICODE_STRING}αη", @chars.center(7, 'αη')
assert_equal "αη#{UNICODE_STRING}αη", @chars.center(8, 'αη')
assert_equal #{UNICODE_STRING}α", @chars.center(8, 'α')
assert_equal #{UNICODE_STRING}αα", @chars.center(9, 'α')
assert_equal "a#{UNICODE_STRING}", @chars.center(7, 'ab')
assert_equal UNICODE_STRING, @chars.center(8, 'ab')
assert_equal "ab#{UNICODE_STRING}ab", @chars.center(12, 'ab')
assert_equal #{UNICODE_STRING}", @chars.center(7, 'αη')
assert_equal UNICODE_STRING, @chars.center(8, 'αη')
end
def test_lstrip_strips_whitespace_from_the_left_of_the_string
......
require 'abstract_unit'
class SafeBufferTest < ActionView::TestCase
class SafeBufferTest < ActiveSupport::TestCase
def setup
@buffer = ActionView::SafeBuffer.new
@buffer = ActiveSupport::SafeBuffer.new
end
test "Should look like a string" do
......@@ -16,7 +16,7 @@ def setup
end
test "Should NOT escape a safe value passed to it" do
@buffer << "<script>".html_safe!
@buffer << "<script>".html_safe
assert_equal "<script>", @buffer
end
......@@ -36,6 +36,6 @@ def setup
test "Should return a safe buffer when calling to_s" do
new_buffer = @buffer.to_s
assert_equal ActionView::SafeBuffer, new_buffer.class
assert_equal ActiveSupport::SafeBuffer, new_buffer.class
end
end
......@@ -7,26 +7,25 @@ def root_dir
end
def rake(*tasks)
tasks.each { |task| return false unless system("#{root_dir}/bin/rake", task) }
tasks.each { |task| return false unless system("bundle exec rake", task) }
true
end
puts "[CruiseControl] Rails build"
build_results = {}
# Requires gem home and path to be writeable and/or overridden to be ~/.gem,
# Will enable when RubyGems supports this properly (in a coming release)
# build_results[:geminstaller] = system 'geminstaller --exceptions'
# 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"
# for now, use the no-passwd sudoers approach (documented in ci_setup_notes.txt)
# A security hole, but there is nothing valuable on rails CI box anyway.
build_results[:geminstaller] = system "sudo geminstaller --config=#{root_dir}/ci/geminstaller.yml --exceptions"
# Install required version of bundler.
build_results[:geminstaller] = system "sudo gem install bundler -v 0.9.0.pre3 --prerelease --no-ri --no-rdoc"
cd root_dir do
puts
puts "[CruiseControl] Bundling RubyGems"
puts
build_results[:bundle] = system 'rm -rf vendor && env CI=1 gem bundle --update && chmod 755 bin vendor vendor/gems'
build_results[:bundle] = system 'env CI=1 sudo bundle install'
end
cd "#{root_dir}/activesupport" do
......@@ -107,7 +106,7 @@ def rake(*tasks)
puts "[CruiseControl] SQLite3: #{`sqlite3 -version`}"
`gem env`.each_line {|line| print "[CruiseControl] #{line}"}
puts "[CruiseControl] Bundled gems:"
`gem bundle --list`.each_line {|line| print "[CruiseControl] #{line}"}
# `gem bundle --list`.each_line {|line| print "[CruiseControl] #{line}"}
puts "[CruiseControl] Local gems:"
`gem list`.each_line {|line| print "[CruiseControl] #{line}"}
......
---
gems:
- name: geminstaller
version: >= 0.4.3
- name: rubygems-update
version: >= 1.3.5
- name: bundler
version: >= 0.7.1
begin
require File.expand_path('../vendor/environment', __FILE__)
rescue LoadError
begin
require 'rubygems'
require 'bundler'
Bundler.setup
rescue LoadError
%w(
actionmailer
actionpack
activemodel
activerecord
activeresource
activesupport
railties
).each do |framework|
$:.unshift File.expand_path("../#{framework}/lib", __FILE__)
end
end
end
\ No newline at end of file
......@@ -14,6 +14,7 @@
s.add_dependency('activeresource', '= 3.0.pre')
s.add_dependency('actionmailer', '= 3.0.pre')
s.add_dependency('railties', '= 3.0.pre')
s.add_dependency('bundler', '>= 0.9.0.pre')
s.rdoc_options << '--exclude' << '.'
s.has_rdoc = false
......
begin
require File.expand_path('../../vendor/gems/environment', __FILE__)
rescue LoadError
end
require File.expand_path('../../load_paths', __FILE__)
require 'rake'
require 'rake/testtask'
......
class Rails::InfoController < ActionController::Base
def properties
if consider_all_requests_local || local_request?
if consider_all_requests_local? || local_request?
render :inline => Rails::Info.to_html
else
render :text => '<p>For security purposes, this information is only available to local requests.</p>', :status => :forbidden
end
end
protected
def consider_all_requests_local?
Rails.application.config.consider_all_requests_local
end
end
......@@ -90,6 +90,18 @@ def create_boot_file
template "config/boot.rb"
end
def gem_for_database
# %w( mysql oracle postgresql sqlite3 frontbase ibm_db )
case options[:database]
when "mysql" then "mysql"
when "oracle" then "ruby-oci8"
when "postgresql" then "pg"
when "sqlite3" then "sqlite3-ruby"
when "frontbase" then "ruby-frontbase"
when "ibm_db" then "ibm_db"
end
end
def create_activerecord_files
return if options[:skip_activerecord]
template "config/databases/#{options[:database]}.yml", "config/database.yml"
......
# Edit this Gemfile to bundle your application's dependencies.
source :gemcutter
<% if !dev_or_edge? %>
gem "rails", "<%= Rails::VERSION::STRING %>"
<% end -%>
......@@ -11,6 +13,14 @@ gem "rails", "<%= Rails::VERSION::STRING %>"
<%= "# " unless options.edge? %>gem "rails", :git => "git://github.com/rails/rails.git"
<%- end -%>
<% unless options[:skip_activerecord] -%>
<% if options[:database] == 'sqlite3' -%>
# ActiveRecord requires a database adapter. By default,
# Rails has selected sqlite3.
<% end -%>
gem "<%= gem_for_database %>"
<% end -%>
## Bundle the gems you use:
# gem "bj"
# gem "hpricot", "0.6"
......
# Use Bundler (preferred)
environment = File.expand_path('../../vendor/gems/environment', __FILE__)
if File.exist?("#{environment}.rb")
require environment
# Use 2.x style vendor/rails and RubyGems
else
vendor_rails = File.expand_path('../../vendor/rails', __FILE__)
if File.exist?(vendor_rails)
Dir["#{vendor_rails}/*/lib"].each { |path| $:.unshift(path) }
end
begin
require File.expand_path('../../vendor/environment', __FILE__)
rescue LoadError
require 'rubygems'
require 'bundler'
Bundler.setup
# To use 2.x style vendor/rails and RubyGems
#
# vendor_rails = File.expand_path('../../vendor/rails', __FILE__)
# if File.exist?(vendor_rails)
# Dir["#{vendor_rails}/*/lib"].each { |path| $:.unshift(path) }
# end
#
# require 'rubygems'
end
<% unless options[:skip_activerecord] -%>
......
......@@ -5,7 +5,7 @@ class Application
class Configuration < ::Rails::Engine::Configuration
include ::Rails::Configuration::Deprecated
attr_accessor :cache_classes, :cache_store, :colorize_logging,
attr_accessor :allow_concurrency, :cache_classes, :cache_store, :colorize_logging,
:consider_all_requests_local, :dependency_loading,
:filter_parameters, :log_level, :logger, :metals,
:plugins, :preload_frameworks, :reload_engines, :reload_plugins,
......@@ -13,11 +13,13 @@ class Configuration < ::Rails::Engine::Configuration
def initialize(*)
super
@allow_concurrency = false
@colorize_logging = true
@filter_parameters = []
@dependency_loading = true
@serve_static_assets = true
@time_zone = "UTC"
@consider_all_requests_local = true
end
def paths
......@@ -50,7 +52,7 @@ def threadsafe!
self.preload_frameworks = true
self.cache_classes = true
self.dependency_loading = false
self.action_controller.allow_concurrency = true if respond_to?(:action_controller)
self.allow_concurrency = true
self
end
......
......@@ -8,10 +8,10 @@ module Shared
def middleware
@@default_middleware_stack ||= ActionDispatch::MiddlewareStack.new.tap do |middleware|
middleware.use('::ActionDispatch::Static', lambda { Rails.public_path }, :if => lambda { Rails.application.config.serve_static_assets })
middleware.use('::Rack::Lock', :if => lambda { !ActionController::Base.allow_concurrency })
middleware.use('::Rack::Lock', :if => lambda { !Rails.application.config.allow_concurrency })
middleware.use('::Rack::Runtime')
middleware.use('::Rails::Rack::Logger')
middleware.use('::ActionDispatch::ShowExceptions', lambda { ActionController::Base.consider_all_requests_local })
middleware.use('::ActionDispatch::ShowExceptions', lambda { Rails.application.config.consider_all_requests_local })
middleware.use('::ActionDispatch::Callbacks', lambda { !Rails.application.config.cache_classes })
middleware.use('::ActionDispatch::Cookies')
middleware.use(lambda { ActionController::Base.session_store }, lambda { ActionController::Base.session_options })
......@@ -88,11 +88,12 @@ def options
end
class Generators #:nodoc:
attr_accessor :aliases, :options, :colorize_logging
attr_accessor :aliases, :options, :fallbacks, :colorize_logging
def initialize
@aliases = Hash.new { |h,k| h[k] = {} }
@options = Hash.new { |h,k| h[k] = {} }
@fallbacks = {}
@colorize_logging = true
end
......
......@@ -67,6 +67,7 @@ def self.configure!(config = Rails.application.config.generators) #:nodoc:
no_color! unless config.colorize_logging
aliases.deep_merge! config.aliases
options.deep_merge! config.options
fallbacks.merge! config.fallbacks
end
def self.aliases #:nodoc:
......
require 'active_support/core_ext/class/inheritable_attributes'
require 'active_support/core_ext/class/attribute'
require 'active_support/core_ext/module/delegation'
require 'active_support/core_ext/hash/reverse_merge'
require 'rails/generators'
require 'fileutils'
......@@ -28,8 +29,8 @@ module Generators
class TestCase < ActiveSupport::TestCase
include FileUtils
extlib_inheritable_accessor :destination_root, :current_path, :generator_class,
:default_arguments, :instance_writer => false
class_attribute :destination_root, :current_path, :generator_class, :default_arguments
delegate :destination_root, :current_path, :generator_class, :default_arguments, :to => :'self.class'
# Generators frequently change the current path using +FileUtils.cd+.
# So we need to store the path at file load and revert back to it after each test.
......
ORIG_ARGV = ARGV.dup
root = File.expand_path('../../..', __FILE__)
begin
require "#{root}/vendor/gems/environment"
rescue LoadError
%w(activesupport activemodel activerecord actionpack actionmailer activeresource railties).each do |lib|
$:.unshift "#{root}/#{lib}/lib"
end
end
$:.unshift "#{root}/railties/builtin/rails_info"
require File.expand_path("../../../load_paths", __FILE__)
$:.unshift File.expand_path("../../builtin/rails_info", __FILE__)
require 'stringio'
require 'test/unit'
......
......@@ -93,7 +93,7 @@ def teardown
RUBY
require "#{app_path}/config/application"
assert AppTemplate::Application.config.action_controller.allow_concurrency
assert AppTemplate::Application.config.allow_concurrency
end
test "the application can be marked as threadsafe when there are no frameworks" do
......
......@@ -30,6 +30,7 @@ def with_bare_config
assert_equal(true, c.generators.colorize_logging)
assert_equal({}, c.generators.aliases)
assert_equal({}, c.generators.options)
assert_equal({}, c.generators.fallbacks)
end
end
......@@ -51,11 +52,20 @@ def with_bare_config
end
end
test "generators aliases and options on initialization" do
test "generators set rails fallbacks" do
with_config do |c|
c.generators.fallbacks[:shoulda] = :test_unit
expected = { :shoulda => :test_unit }
assert_equal expected, c.generators.fallbacks
end
end
test "generators aliases, options and fallbacks on initialization" do
add_to_config <<-RUBY
config.generators.rails :aliases => { :test_framework => "-w" }
config.generators.orm :datamapper
config.generators.test_framework :rspec
config.generators.fallbacks[:shoulda] = :test_unit
RUBY
# Initialize the application
......@@ -65,6 +75,7 @@ def with_bare_config
assert_equal :rspec, Rails::Generators.options[:rails][:test_framework]
assert_equal "-w", Rails::Generators.aliases[:rails][:test_framework]
assert_equal :test_unit, Rails::Generators.fallbacks[:shoulda]
end
test "generators no color on initialization" do
......
......@@ -39,7 +39,7 @@ def setup
end
test "removes lock if allow concurrency is set" do
add_to_config "config.action_controller.allow_concurrency = true"
add_to_config "config.allow_concurrency = true"
boot!
assert !middleware.include?("Rack::Lock")
end
......
......@@ -183,23 +183,7 @@ def use_frameworks(arr)
end
def boot_rails
root = File.expand_path('../../../..', __FILE__)
begin
require "#{root}/vendor/gems/environment"
rescue LoadError
%w(
actionmailer/lib
actionpack/lib
activemodel/lib
activerecord/lib
activeresource/lib
activesupport/lib
railties/lib
railties
).reverse_each do |path|
$:.unshift "#{root}/#{path}"
end
end
require File.expand_path('../../../../load_paths', __FILE__)
end
end
end
......@@ -220,14 +204,18 @@ class Test::Unit::TestCase
end
FileUtils.mkdir(tmp_path)
environment = File.expand_path('../../../../vendor/gems/environment', __FILE__)
environment = File.expand_path('../../../../load_paths', __FILE__)
if File.exist?("#{environment}.rb")
require_environment = "-r #{environment}"
end
`#{Gem.ruby} #{require_environment} #{RAILS_FRAMEWORK_ROOT}/railties/bin/rails #{tmp_path('app_template')}`
File.open("#{tmp_path}/app_template/config/boot.rb", 'w') do |f|
f.puts "require '#{environment}'" if require_environment
if require_environment
f.puts "Dir.chdir('#{File.dirname(environment)}') do"
f.puts " require '#{environment}'"
f.puts "end"
end
f.puts "require 'rails/all'"
end
end
......@@ -17,23 +17,23 @@ def setup
ActionController::Routing::Routes.draw do |map|
match ':controller/:action'
end
@controller.stubs(:consider_all_requests_local => false, :local_request? => true)
@controller.stubs(:consider_all_requests_local? => false, :local_request? => true)
end
test "info controller does not allow remote requests" do
@controller.stubs(:consider_all_requests_local => false, :local_request? => false)
@controller.stubs(:consider_all_requests_local? => false, :local_request? => false)
get :properties
assert_response :forbidden
end
test "info controller renders an error message when request was forbidden" do
@controller.stubs(:consider_all_requests_local => false, :local_request? => false)
@controller.stubs(:consider_all_requests_local? => false, :local_request? => false)
get :properties
assert_select 'p'
end
test "info controller allows requests when all requests are considered local" do
@controller.stubs(:consider_all_requests_local => true, :local_request? => false)
@controller.stubs(:consider_all_requests_local? => true, :local_request? => false)
get :properties
assert_response :success
end
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册