Sync with latest Instiki trunk. Changes:

1) Upgrade Rails to 1.2.3
2) Revert RedCloth to previous version (who %#$@ cares?)
3) Preserve the Rails Security fix  to vendor/rails/actionpack/lib/action_controller/caching.rb from Revision 80.
This commit is contained in:
Jacques Distler 2007-03-18 11:56:12 -05:00
parent ff3e03a45a
commit 7adac51d6d
68 changed files with 466 additions and 257 deletions

View file

@ -166,7 +166,7 @@
class RedCloth < String class RedCloth < String
VERSION = '3.0.4' VERSION = '3.0.3'
DEFAULT_RULES = [:textile, :markdown] DEFAULT_RULES = [:textile, :markdown]
# #
@ -193,18 +193,6 @@ class RedCloth < String
# #
attr_accessor :hard_breaks attr_accessor :hard_breaks
# Accessor for toggling lite mode.
#
# In lite mode, block-level rules are ignored. This means
# that tables, paragraphs, lists, and such aren't available.
# Only the inline markup for bold, italics, entities and so on.
#
# r = RedCloth.new( "And then? She *fell*!", [:lite_mode] )
# r.to_html
# #=> "And then? She <strong>fell</strong>!"
#
attr_accessor :lite_mode
# #
# Accessor for toggling span caps. # Accessor for toggling span caps.
# #
@ -231,7 +219,7 @@ class RedCloth < String
# inline_textile_image:: Textile inline images # inline_textile_image:: Textile inline images
# inline_textile_link:: Textile inline links # inline_textile_link:: Textile inline links
# inline_textile_span:: Textile inline spans # inline_textile_span:: Textile inline spans
# glyphs_textile:: Textile entities (such as em-dashes and smart quotes) # inline_textile_glyphs:: Textile entities (such as em-dashes and smart quotes)
# #
# == Markdown # == Markdown
# #
@ -272,7 +260,7 @@ class RedCloth < String
@shelf = [] @shelf = []
textile_rules = [:refs_textile, :block_textile_table, :block_textile_lists, textile_rules = [:refs_textile, :block_textile_table, :block_textile_lists,
:block_textile_prefix, :inline_textile_image, :inline_textile_link, :block_textile_prefix, :inline_textile_image, :inline_textile_link,
:inline_textile_code, :inline_textile_span, :glyphs_textile] :inline_textile_code, :inline_textile_glyphs, :inline_textile_span]
markdown_rules = [:refs_markdown, :block_markdown_setext, :block_markdown_atx, :block_markdown_rule, markdown_rules = [:refs_markdown, :block_markdown_setext, :block_markdown_atx, :block_markdown_rule,
:block_markdown_bq, :block_markdown_lists, :block_markdown_bq, :block_markdown_lists,
:inline_markdown_reflink, :inline_markdown_link] :inline_markdown_reflink, :inline_markdown_link]
@ -290,16 +278,14 @@ class RedCloth < String
# standard clean up # standard clean up
incoming_entities text incoming_entities text
clean_white_space text clean_white_space text
no_textile text
# start processor # start processor
@pre_list = [] @pre_list = []
rip_offtags text rip_offtags text
no_textile text hard_break text
hard_break text refs text
unless @lite_mode blocks text
refs text
blocks text
end
inline text inline text
smooth_offtags text smooth_offtags text
@ -347,8 +333,6 @@ class RedCloth < String
C = "(?:#{C_CLAS}?#{C_STYL}?#{C_LNGE}?|#{C_STYL}?#{C_LNGE}?#{C_CLAS}?|#{C_LNGE}?#{C_STYL}?#{C_CLAS}?)" C = "(?:#{C_CLAS}?#{C_STYL}?#{C_LNGE}?|#{C_STYL}?#{C_LNGE}?#{C_CLAS}?|#{C_LNGE}?#{C_STYL}?#{C_CLAS}?)"
# PUNCT = Regexp::quote( '!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~' ) # PUNCT = Regexp::quote( '!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~' )
PUNCT = Regexp::quote( '!"#$%&\'*+,-./:;=?@\\^_`|~' ) PUNCT = Regexp::quote( '!"#$%&\'*+,-./:;=?@\\^_`|~' )
PUNCT_NOQ = Regexp::quote( '!"#$&\',./:;=?@\\`|' )
PUNCT_Q = Regexp::quote( '*-_+^~%' )
HYPERLINK = '(\S+?)([^\w\s/;=\?]*?)(?=\s|<|$)' HYPERLINK = '(\S+?)([^\w\s/;=\?]*?)(?=\s|<|$)'
# Text markup tags, don't conflict with block tags # Text markup tags, don't conflict with block tags
@ -358,6 +342,41 @@ class RedCloth < String
'br', 'map', 'q', 'sub', 'sup', 'span', 'bdo' 'br', 'map', 'q', 'sub', 'sup', 'span', 'bdo'
] ]
# Elements to handle
GLYPHS = [
# [ /([^\s\[{(>])?\'([dmst]\b|ll\b|ve\b|\s|:|$)/, '\1&#8217;\2' ], # single closing
[ /([^\s\[{(>])\'/, '\1&#8217;' ], # single closing
[ /\'(?=\s|s\b|[#{PUNCT}])/, '&#8217;' ], # single closing
[ /\'/, '&#8216;' ], # single opening
# [ /([^\s\[{(])?"(\s|:|$)/, '\1&#8221;\2' ], # double closing
[ /([^\s\[{(>])"/, '\1&#8221;' ], # double closing
[ /"(?=\s|[#{PUNCT}])/, '&#8221;' ], # double closing
[ /"/, '&#8220;' ], # double opening
[ /\b( )?\.{3}/, '\1&#8230;' ], # ellipsis
[ /\b([A-Z][A-Z0-9]{2,})\b(?:[(]([^)]*)[)])/, '<acronym title="\2">\1</acronym>' ], # 3+ uppercase acronym
[ /(^|[^"][>\s])([A-Z][A-Z0-9 ]{2,})([^<a-z0-9]|$)/, '\1<span class="caps">\2</span>\3', :no_span_caps ], # 3+ uppercase caps
[ /(\.\s)?\s?--\s?/, '\1&#8212;' ], # em dash
[ /\s->\s/, ' &rarr; ' ], # right arrow
[ /\s-\s/, ' &#8211; ' ], # en dash
[ /(\d+) ?x ?(\d+)/, '\1&#215;\2' ], # dimension sign
[ /\b ?[(\[]TM[\])]/i, '&#8482;' ], # trademark
[ /\b ?[(\[]R[\])]/i, '&#174;' ], # registered
[ /\b ?[(\[]C[\])]/i, '&#169;' ] # copyright
]
H_ALGN_VALS = {
'<' => 'left',
'=' => 'center',
'>' => 'right',
'<>' => 'justify'
}
V_ALGN_VALS = {
'^' => 'top',
'-' => 'middle',
'~' => 'bottom'
}
QTAGS = [ QTAGS = [
['**', 'b'], ['**', 'b'],
['*', 'strong'], ['*', 'strong'],
@ -379,56 +398,19 @@ class RedCloth < String
(#{rcq}) (#{rcq})
(#{C}) (#{C})
(?::(\S+?))? (?::(\S+?))?
(\S.*?\S|\S) (.+?)
#{rcq} #{rcq}
(?=\W)/x (?=\W)/x
else else
/(#{rcq}) /(#{rcq})
(#{C}) (#{C})
(?::(\S+))? (?::(\S+?))?
(\S.*?\S|\S) (.+?)
#{rcq}/xm #{rcq}/xm
end end
[rc, ht, re, rtype] [rc, ht, re, rtype]
end end
# Elements to handle
GLYPHS = [
# [ /([^\s\[{(>])?\'([dmst]\b|ll\b|ve\b|\s|:|$)/, '\1&#8217;\2' ], # single closing
[ /([^\s\[{(>#{PUNCT_Q}][#{PUNCT_Q}]*)\'/, '\1&#8217;' ], # single closing
[ /\'(?=[#{PUNCT_Q}]*(s\b|[\s#{PUNCT_NOQ}]))/, '&#8217;' ], # single closing
[ /\'/, '&#8216;' ], # single opening
[ /</, '&lt;' ], # less-than
[ />/, '&gt;' ], # greater-than
# [ /([^\s\[{(])?"(\s|:|$)/, '\1&#8221;\2' ], # double closing
[ /([^\s\[{(>#{PUNCT_Q}][#{PUNCT_Q}]*)"/, '\1&#8221;' ], # double closing
[ /"(?=[#{PUNCT_Q}]*[\s#{PUNCT_NOQ}])/, '&#8221;' ], # double closing
[ /"/, '&#8220;' ], # double opening
[ /\b( )?\.{3}/, '\1&#8230;' ], # ellipsis
[ /\b([A-Z][A-Z0-9]{2,})\b(?:[(]([^)]*)[)])/, '<acronym title="\2">\1</acronym>' ], # 3+ uppercase acronym
[ /(^|[^"][>\s])([A-Z][A-Z0-9 ]+[A-Z0-9])([^<A-Za-z0-9]|$)/, '\1<span class="caps">\2</span>\3', :no_span_caps ], # 3+ uppercase caps
[ /(\.\s)?\s?--\s?/, '\1&#8212;' ], # em dash
[ /\s->\s/, ' &rarr; ' ], # right arrow
[ /\s-\s/, ' &#8211; ' ], # en dash
[ /(\d+) ?x ?(\d+)/, '\1&#215;\2' ], # dimension sign
[ /\b ?[(\[]TM[\])]/i, '&#8482;' ], # trademark
[ /\b ?[(\[]R[\])]/i, '&#174;' ], # registered
[ /\b ?[(\[]C[\])]/i, '&#169;' ] # copyright
]
H_ALGN_VALS = {
'<' => 'left',
'=' => 'center',
'>' => 'right',
'<>' => 'justify'
}
V_ALGN_VALS = {
'^' => 'top',
'-' => 'middle',
'~' => 'bottom'
}
# #
# Flexible HTML escaping # Flexible HTML escaping
# #
@ -548,7 +530,7 @@ class RedCloth < String
depth.pop depth.pop
end end
end end
if depth.last and depth.last.length == tl.length if depth.last.length == tl.length
lines[line_id - 1] << '</li>' lines[line_id - 1] << '</li>'
end end
end end
@ -595,7 +577,7 @@ class RedCloth < String
end end
def hard_break( text ) def hard_break( text )
text.gsub!( /(.)\n(?!\Z| *([#*=]+(\s|$)|[{|]))/, "\\1<br />" ) if hard_breaks text.gsub!( /(.)\n(?! *[#*\s|]|$)/, "\\1<br />" ) if hard_breaks
end end
BLOCKS_GROUP_RE = /\n{2,}(?! )/m BLOCKS_GROUP_RE = /\n{2,}(?! )/m
@ -723,9 +705,9 @@ class RedCloth < String
end end
end end
MARKDOWN_RULE_RE = /^(#{ MARKDOWN_RULE_RE = /^#{
['*', '-', '_'].collect { |ch| '( ?' + Regexp::quote( ch ) + ' ?){3,}' }.join( '|' ) ['*', '-', '_'].collect { |ch| '( ?' + Regexp::quote( ch ) + ' ?){3,}' }.join( '|' )
})$/ }$/
def block_markdown_rule( text ) def block_markdown_rule( text )
text.gsub!( MARKDOWN_RULE_RE ) do |blk| text.gsub!( MARKDOWN_RULE_RE ) do |blk|
@ -737,6 +719,9 @@ class RedCloth < String
def block_markdown_lists( text ) def block_markdown_lists( text )
end end
def inline_markdown_link( text )
end
def inline_textile_span( text ) def inline_textile_span( text )
QTAGS.each do |qtag_rc, ht, qtag_re, rtype| QTAGS.each do |qtag_rc, ht, qtag_re, rtype|
text.gsub!( qtag_re ) do |m| text.gsub!( qtag_re ) do |m|
@ -918,12 +903,12 @@ class RedCloth < String
def shelve( val ) def shelve( val )
@shelf << val @shelf << val
" :redsh##{ @shelf.length }:" " <#{ @shelf.length }>"
end end
def retrieve( text ) def retrieve( text )
@shelf.each_with_index do |r, i| @shelf.each_with_index do |r, i|
text.gsub!( " :redsh##{ i + 1 }:", r ) text.gsub!( " <#{ i + 1 }>", r )
end end
end end
@ -980,7 +965,7 @@ class RedCloth < String
HASTAG_MATCH = /(<\/?\w[^\n]*?>)/m HASTAG_MATCH = /(<\/?\w[^\n]*?>)/m
ALLTAG_MATCH = /(<\/?\w[^\n]*?>)|.*?(?=<\/?\w[^\n]*?>|$)/m ALLTAG_MATCH = /(<\/?\w[^\n]*?>)|.*?(?=<\/?\w[^\n]*?>|$)/m
def glyphs_textile( text, level = 0 ) def inline_textile_glyphs( text, level = 0 )
if text !~ HASTAG_MATCH if text !~ HASTAG_MATCH
pgl text pgl text
footnote_ref text footnote_ref text
@ -996,11 +981,11 @@ class RedCloth < String
codepre = 0 if codepre < 0 codepre = 0 if codepre < 0
end end
elsif codepre.zero? elsif codepre.zero?
glyphs_textile( line, level + 1 ) inline_textile_glyphs( line, level + 1 )
else else
htmlesc( line, :NoQuotes ) htmlesc( line, :NoQuotes )
end end
# p [level, codepre, line] ## p [level, codepre, orig_line, line]
line line
end end
@ -1048,10 +1033,8 @@ class RedCloth < String
end end
def inline( text ) def inline( text )
[/^inline_/, /^glyphs_/].each do |meth_re| @rules.each do |rule_name|
@rules.each do |rule_name| method( rule_name ).call( text ) if rule_name.to_s.match /^inline_/
method( rule_name ).call( text ) if rule_name.to_s.match( meth_re )
end
end end
end end
@ -1114,7 +1097,7 @@ class RedCloth < String
q2 = ( q != '' ? q : '\s' ) q2 = ( q != '' ? q : '\s' )
if raw[3] =~ /#{prop}\s*=\s*#{q}([^#{q2}]+)#{q}/i if raw[3] =~ /#{prop}\s*=\s*#{q}([^#{q2}]+)#{q}/i
attrv = $1 attrv = $1
next if prop == 'src' and attrv =~ %r{^(?!http)\w+:} next if prop == 'src' and attrv !~ /^http/
pcs << "#{prop}=\"#{$1.gsub('"', '\\"')}\"" pcs << "#{prop}=\"#{$1.gsub('"', '\\"')}\""
break break
end end

View file

@ -1,4 +1,9 @@
*1.13.2* (February 5th, 2007) *1.3.3* (March 12th, 2007)
* Depend on Action Pack 1.13.3
*1.3.2* (February 5th, 2007)
* Deprecate server_settings renaming it to smtp_settings, add sendmail_settings to allow you to override the arguments to and location of the sendmail executable. [Koz] * Deprecate server_settings renaming it to smtp_settings, add sendmail_settings to allow you to override the arguments to and location of the sendmail executable. [Koz]

View file

@ -54,7 +54,7 @@ spec = Gem::Specification.new do |s|
s.rubyforge_project = "actionmailer" s.rubyforge_project = "actionmailer"
s.homepage = "http://www.rubyonrails.org" s.homepage = "http://www.rubyonrails.org"
s.add_dependency('actionpack', '= 1.13.2' + PKG_BUILD) s.add_dependency('actionpack', '= 1.13.3' + PKG_BUILD)
s.has_rdoc = true s.has_rdoc = true
s.requirements << 'none' s.requirements << 'none'
@ -85,11 +85,11 @@ end
desc "Publish the release files to RubyForge." desc "Publish the release files to RubyForge."
task :release => [ :package ] do task :release => [ :package ] do
`rubyforge login` require 'rubyforge'
for ext in %w( gem tgz zip ) packages = %w( gem tgz zip ).collect{ |ext| "pkg/#{PKG_NAME}-#{PKG_VERSION}.#{ext}" }
release_command = "rubyforge add_release #{PKG_NAME} #{PKG_NAME} 'REL #{PKG_VERSION}' pkg/#{PKG_NAME}-#{PKG_VERSION}.#{ext}"
puts release_command rubyforge = RubyForge.new
system(release_command) rubyforge.login
end rubyforge.add_release(PKG_NAME, PKG_NAME, "REL #{PKG_VERSION}", *packages)
end end

View file

@ -2,7 +2,7 @@ module ActionMailer
module VERSION #:nodoc: module VERSION #:nodoc:
MAJOR = 1 MAJOR = 1
MINOR = 3 MINOR = 3
TINY = 2 TINY = 3
STRING = [MAJOR, MINOR, TINY].join('.') STRING = [MAJOR, MINOR, TINY].join('.')
end end

View file

@ -1,3 +1,12 @@
*1.13.3* (March 12th, 2007)
* Apply [5709] to stable.
* session_enabled? works with session :off. #6680 [Catfish]
* Performance: patch cgi/session to require digest/md5 once rather than per #create_new_id. [Stefan Kaes]
*1.13.2* (February 5th, 2007) *1.13.2* (February 5th, 2007)
* Add much-needed html-scanner tests. Fixed CDATA parsing bug. [Rick] * Add much-needed html-scanner tests. Fixed CDATA parsing bug. [Rick]
@ -10,8 +19,6 @@
* Add singleton resources from trunk [Rick Olson] * Add singleton resources from trunk [Rick Olson]
* TestSession supports indifferent access so session['foo'] == session[:foo] in your tests. #7372 [julik, jean.helou]
* select :multiple => true suffixes the attribute name with [] unless already suffixed. #6977 [nik.kakelin, ben, julik] * select :multiple => true suffixes the attribute name with [] unless already suffixed. #6977 [nik.kakelin, ben, julik]
* Improve routes documentation. #7095 [zackchandler] * Improve routes documentation. #7095 [zackchandler]

View file

@ -75,7 +75,7 @@ spec = Gem::Specification.new do |s|
s.has_rdoc = true s.has_rdoc = true
s.requirements << 'none' s.requirements << 'none'
s.add_dependency('activesupport', '= 1.4.1' + PKG_BUILD) s.add_dependency('activesupport', '= 1.4.2' + PKG_BUILD)
s.require_path = 'lib' s.require_path = 'lib'
s.autorequire = 'action_controller' s.autorequire = 'action_controller'
@ -144,11 +144,11 @@ end
desc "Publish the release files to RubyForge." desc "Publish the release files to RubyForge."
task :release => [ :package ] do task :release => [ :package ] do
`rubyforge login` require 'rubyforge'
for ext in %w( gem tgz zip ) packages = %w( gem tgz zip ).collect{ |ext| "pkg/#{PKG_NAME}-#{PKG_VERSION}.#{ext}" }
release_command = "rubyforge add_release #{PKG_NAME} #{PKG_NAME} 'REL #{PKG_VERSION}' pkg/#{PKG_NAME}-#{PKG_VERSION}.#{ext}"
puts release_command rubyforge = RubyForge.new
system(release_command) rubyforge.login
end rubyforge.add_release(PKG_NAME, PKG_NAME, "REL #{PKG_VERSION}", *packages)
end end

View file

@ -539,7 +539,7 @@ module ActionController #:nodoc:
end end
def session_enabled? def session_enabled?
request.session_options[:disabled] != false request.session_options && request.session_options[:disabled] != false
end end
protected protected

View file

@ -1,6 +1,7 @@
require 'action_controller/cgi_ext/cgi_ext' require 'action_controller/cgi_ext/cgi_ext'
require 'action_controller/cgi_ext/cookie_performance_fix' require 'action_controller/cgi_ext/cookie_performance_fix'
require 'action_controller/cgi_ext/raw_post_data_fix' require 'action_controller/cgi_ext/raw_post_data_fix'
require 'action_controller/cgi_ext/session_performance_fix'
module ActionController #:nodoc: module ActionController #:nodoc:
class Base class Base

View file

@ -344,10 +344,10 @@ module ActionController
# the query string. (Never use keys from the recalled request when building the # the query string. (Never use keys from the recalled request when building the
# query string.) # query string.)
method_decl = "def generate(#{args})\npath, hash = generate_raw(options, hash, expire_on)\nappend_query_string(path, hash, extra_keys(hash, expire_on))\nend" method_decl = "def generate(#{args})\npath, hash = generate_raw(options, hash, expire_on)\nappend_query_string(path, hash, extra_keys(options))\nend"
instance_eval method_decl, "generated code (#{__FILE__}:#{__LINE__})" instance_eval method_decl, "generated code (#{__FILE__}:#{__LINE__})"
method_decl = "def generate_extras(#{args})\npath, hash = generate_raw(options, hash, expire_on)\n[path, extra_keys(hash, expire_on)]\nend" method_decl = "def generate_extras(#{args})\npath, hash = generate_raw(options, hash, expire_on)\n[path, extra_keys(options)]\nend"
instance_eval method_decl, "generated code (#{__FILE__}:#{__LINE__})" instance_eval method_decl, "generated code (#{__FILE__}:#{__LINE__})"
raw_method raw_method
end end
@ -1238,7 +1238,7 @@ module ActionController
# drop the leading '/' on the controller name # drop the leading '/' on the controller name
options[:controller] = options[:controller][1..-1] if options[:controller] && options[:controller][0] == ?/ options[:controller] = options[:controller][1..-1] if options[:controller] && options[:controller][0] == ?/
merged = recall.merge(options) merged = recall.merge(options)
if named_route if named_route
path = named_route.generate(options, merged, expire_on) path = named_route.generate(options, merged, expire_on)
if path.nil? if path.nil?

View file

@ -288,11 +288,11 @@ module ActionController #:nodoc:
end end
def [](key) def [](key)
data[key.to_s] data[key]
end end
def []=(key, value) def []=(key, value)
data[key.to_s] = value data[key] = value
end end
def update def update

View file

@ -2,7 +2,7 @@ module ActionPack #:nodoc:
module VERSION #:nodoc: module VERSION #:nodoc:
MAJOR = 1 MAJOR = 1
MINOR = 13 MINOR = 13
TINY = 2 TINY = 3
STRING = [MAJOR, MINOR, TINY].join('.') STRING = [MAJOR, MINOR, TINY].join('.')
end end

View file

@ -1717,6 +1717,17 @@ class RouteSetTest < Test::Unit::TestCase
) )
end end
def test_query_params_will_be_shown_when_recalled
set.draw do |map|
map.connect 'show_post/:parameter', :controller => 'post', :action => 'show'
map.connect ':controller/:action/:id'
end
assert_equal '/post/edit?parameter=1', set.generate(
{:action => 'edit', :parameter => 1},
{:controller => 'post', :action => 'show', :parameter => 1}
)
end
end end
class RoutingTest < Test::Unit::TestCase class RoutingTest < Test::Unit::TestCase

View file

@ -142,4 +142,15 @@ class SessionManagementTest < Test::Unit::TestCase
get :tell get :tell
assert_equal "does not have cached associations", @response.body assert_equal "does not have cached associations", @response.body
end end
def test_session_is_enabled
@controller = TestController.new
get :show
assert_nothing_raised do
assert_equal false, @controller.session_enabled?
end
get :tell
assert @controller.session_enabled?
end
end end

View file

@ -8,12 +8,6 @@ class TestTest < Test::Unit::TestCase
render :text => 'ignore me' render :text => 'ignore me'
end end
def set_session
session['string'] = 'A wonder'
session[:symbol] = 'it works'
render :text => 'Success'
end
def render_raw_post def render_raw_post
raise Test::Unit::AssertionFailedError, "#raw_post is blank" if request.raw_post.blank? raise Test::Unit::AssertionFailedError, "#raw_post is blank" if request.raw_post.blank?
render :text => request.raw_post render :text => request.raw_post
@ -117,14 +111,6 @@ HTML
assert_equal '>value<', flash['test'] assert_equal '>value<', flash['test']
end end
def test_process_with_session
process :set_session
assert_equal 'A wonder', session['string'], "A value stored in the session should be available by string key"
assert_equal 'A wonder', session[:string], "Test session hash should allow indifferent access"
assert_equal 'it works', session['symbol'], "Test session hash should allow indifferent access"
assert_equal 'it works', session[:symbol], "Test session hash should allow indifferent access"
end
def test_process_with_request_uri_with_no_params def test_process_with_request_uri_with_no_params
process :test_uri process :test_uri
assert_equal "/test_test/test/test_uri", @response.body assert_equal "/test_test/test/test_uri", @response.body

View file

@ -1,3 +1,8 @@
*1.2.3* (March 12th, 2007)
* Depend on Action Pack 1.13.3
*1.2.2* (Feburary 4th, 2007) *1.2.2* (Feburary 4th, 2007)
* Depend on Action Pack 1.13.2 * Depend on Action Pack 1.13.2

View file

@ -71,8 +71,8 @@ spec = Gem::Specification.new do |s|
s.rubyforge_project = "aws" s.rubyforge_project = "aws"
s.homepage = "http://www.rubyonrails.org" s.homepage = "http://www.rubyonrails.org"
s.add_dependency('actionpack', '= 1.13.2' + PKG_BUILD) s.add_dependency('actionpack', '= 1.13.3' + PKG_BUILD)
s.add_dependency('activerecord', '= 1.15.2' + PKG_BUILD) s.add_dependency('activerecord', '= 1.15.3' + PKG_BUILD)
s.has_rdoc = true s.has_rdoc = true
s.requirements << 'none' s.requirements << 'none'
@ -161,11 +161,11 @@ end
desc "Publish the release files to RubyForge." desc "Publish the release files to RubyForge."
task :release => [ :package ] do task :release => [ :package ] do
`rubyforge login` require 'rubyforge'
for ext in %w( gem tgz zip ) packages = %w( gem tgz zip ).collect{ |ext| "pkg/#{PKG_NAME}-#{PKG_VERSION}.#{ext}" }
release_command = "rubyforge add_release #{PKG_NAME} #{PKG_NAME} 'REL #{PKG_VERSION}' pkg/#{PKG_NAME}-#{PKG_VERSION}.#{ext}"
puts release_command rubyforge = RubyForge.new
system(release_command) rubyforge.login
end rubyforge.add_release(PKG_NAME, PKG_NAME, "REL #{PKG_VERSION}", *packages)
end end

View file

@ -2,7 +2,7 @@ module ActionWebService
module VERSION #:nodoc: module VERSION #:nodoc:
MAJOR = 1 MAJOR = 1
MINOR = 2 MINOR = 2
TINY = 2 TINY = 3
STRING = [MAJOR, MINOR, TINY].join('.') STRING = [MAJOR, MINOR, TINY].join('.')
end end

View file

@ -1,3 +1,14 @@
*1.15.3* (March 12th, 2007)
* Allow a polymorphic :source for has_many :through associations. Closes #7143 [protocool]
* Consistently quote primary key column names. #7763 [toolmantim]
* Fixtures: fix YAML ordered map support. #2665 [Manuel Holtgrewe, nfbuckley]
* Fix has_many :through << with custom foreign keys. #6466, #7153 [naffis, Rich Collins]
*1.15.2* (February 5th, 2007) *1.15.2* (February 5th, 2007)
* Pass a range in :conditions to use the SQL BETWEEN operator. #6974 [dcmanges] * Pass a range in :conditions to use the SQL BETWEEN operator. #6974 [dcmanges]

View file

@ -151,7 +151,7 @@ spec = Gem::Specification.new do |s|
s.files = s.files + Dir.glob( "#{dir}/**/*" ).delete_if { |item| item.include?( "\.svn" ) } s.files = s.files + Dir.glob( "#{dir}/**/*" ).delete_if { |item| item.include?( "\.svn" ) }
end end
s.add_dependency('activesupport', '= 1.4.1' + PKG_BUILD) s.add_dependency('activesupport', '= 1.4.2' + PKG_BUILD)
s.files.delete "test/fixtures/fixture_database.sqlite" s.files.delete "test/fixtures/fixture_database.sqlite"
s.files.delete "test/fixtures/fixture_database_2.sqlite" s.files.delete "test/fixtures/fixture_database_2.sqlite"
@ -216,11 +216,11 @@ end
desc "Publish the release files to RubyForge." desc "Publish the release files to RubyForge."
task :release => [ :package ] do task :release => [ :package ] do
`rubyforge login` require 'rubyforge'
for ext in %w( gem tgz zip ) packages = %w( gem tgz zip ).collect{ |ext| "pkg/#{PKG_NAME}-#{PKG_VERSION}.#{ext}" }
release_command = "rubyforge add_release #{PKG_NAME} #{PKG_NAME} 'REL #{PKG_VERSION}' pkg/#{PKG_NAME}-#{PKG_VERSION}.#{ext}"
puts release_command rubyforge = RubyForge.new
system(release_command) rubyforge.login
end rubyforge.add_release(PKG_NAME, PKG_NAME, "REL #{PKG_VERSION}", *packages)
end end

View file

@ -20,7 +20,13 @@ module ActiveRecord
super("Cannot have a has_many :through association '#{owner_class_name}##{reflection.name}' on the polymorphic object '#{source_reflection.class_name}##{source_reflection.name}'.") super("Cannot have a has_many :through association '#{owner_class_name}##{reflection.name}' on the polymorphic object '#{source_reflection.class_name}##{source_reflection.name}'.")
end end
end end
class HasManyThroughAssociationPointlessSourceTypeError < ActiveRecordError #:nodoc:
def initialize(owner_class_name, reflection, source_reflection)
super("Cannot have a has_many :through association '#{owner_class_name}##{reflection.name}' with a :source_type option if the '#{reflection.through_reflection.class_name}##{source_reflection.name}' is not polymorphic. Try removing :source_type on your association.")
end
end
class HasManyThroughSourceAssociationNotFoundError < ActiveRecordError #:nodoc: class HasManyThroughSourceAssociationNotFoundError < ActiveRecordError #:nodoc:
def initialize(reflection) def initialize(reflection)
through_reflection = reflection.through_reflection through_reflection = reflection.through_reflection
@ -529,6 +535,8 @@ module ActiveRecord
# * <tt>:source</tt>: Specifies the source association name used by <tt>has_many :through</tt> queries. Only use it if the name cannot be # * <tt>:source</tt>: Specifies the source association name used by <tt>has_many :through</tt> queries. Only use it if the name cannot be
# inferred from the association. <tt>has_many :subscribers, :through => :subscriptions</tt> will look for either +:subscribers+ or # inferred from the association. <tt>has_many :subscribers, :through => :subscriptions</tt> will look for either +:subscribers+ or
# +:subscriber+ on +Subscription+, unless a +:source+ is given. # +:subscriber+ on +Subscription+, unless a +:source+ is given.
# * <tt>:source_type</tt>: Specifies type of the source association used by <tt>has_many :through</tt> queries where the source association
# is a polymorphic belongs_to.
# * <tt>:uniq</tt> - if set to true, duplicates will be omitted from the collection. Useful in conjunction with :through. # * <tt>:uniq</tt> - if set to true, duplicates will be omitted from the collection. Useful in conjunction with :through.
# #
# Option examples: # Option examples:
@ -1087,7 +1095,7 @@ module ActiveRecord
:class_name, :table_name, :foreign_key, :class_name, :table_name, :foreign_key,
:exclusively_dependent, :dependent, :exclusively_dependent, :dependent,
:select, :conditions, :include, :order, :group, :limit, :offset, :select, :conditions, :include, :order, :group, :limit, :offset,
:as, :through, :source, :as, :through, :source, :source_type,
:uniq, :uniq,
:finder_sql, :counter_sql, :finder_sql, :counter_sql,
:before_add, :after_add, :before_remove, :after_remove, :before_add, :after_add, :before_remove, :after_remove,
@ -1491,57 +1499,65 @@ module ActiveRecord
case case
when reflection.macro == :has_many && reflection.options[:through] when reflection.macro == :has_many && reflection.options[:through]
through_conditions = through_reflection.options[:conditions] ? "AND #{interpolate_sql(sanitize_sql(through_reflection.options[:conditions]))}" : '' through_conditions = through_reflection.options[:conditions] ? "AND #{interpolate_sql(sanitize_sql(through_reflection.options[:conditions]))}" : ''
if through_reflection.options[:as] # has_many :through against a polymorphic join
polymorphic_foreign_key = through_reflection.options[:as].to_s + '_id'
polymorphic_foreign_type = through_reflection.options[:as].to_s + '_type'
" LEFT OUTER JOIN %s ON (%s.%s = %s.%s AND %s.%s = %s) " % [ jt_foreign_key = jt_as_extra = jt_source_extra = jt_sti_extra = nil
table_alias_for(through_reflection.klass.table_name, aliased_join_table_name), first_key = second_key = as_extra = nil
aliased_join_table_name, polymorphic_foreign_key,
parent.aliased_table_name, parent.primary_key, if through_reflection.options[:as] # has_many :through against a polymorphic join
aliased_join_table_name, polymorphic_foreign_type, klass.quote_value(parent.active_record.base_class.name)] + jt_foreign_key = through_reflection.options[:as].to_s + '_id'
" LEFT OUTER JOIN %s ON %s.%s = %s.%s " % [table_name_and_alias, jt_as_extra = " AND %s.%s = %s" % [
aliased_table_name, primary_key, aliased_join_table_name, options[:foreign_key] || reflection.klass.to_s.classify.foreign_key aliased_join_table_name, reflection.active_record.connection.quote_column_name(through_reflection.options[:as].to_s + '_type'),
klass.quote_value(parent.active_record.base_class.name)
] ]
else else
if source_reflection.macro == :has_many && source_reflection.options[:as] jt_foreign_key = through_reflection.primary_key_name
" LEFT OUTER JOIN %s ON %s.%s = %s.%s " % [ end
table_alias_for(through_reflection.klass.table_name, aliased_join_table_name), aliased_join_table_name,
through_reflection.primary_key_name, case source_reflection.macro
parent.aliased_table_name, parent.primary_key] + when :has_many
" LEFT OUTER JOIN %s ON %s.%s = %s.%s AND %s.%s = %s " % [ if source_reflection.options[:as]
table_name_and_alias, first_key = "#{source_reflection.options[:as]}_id"
aliased_table_name, "#{source_reflection.options[:as]}_id", second_key = options[:foreign_key] || primary_key
aliased_join_table_name, options[:foreign_key] || primary_key, as_extra = " AND %s.%s = %s" % [
aliased_table_name, "#{source_reflection.options[:as]}_type", aliased_table_name, reflection.active_record.connection.quote_column_name("#{source_reflection.options[:as]}_type"),
klass.quote_value(source_reflection.active_record.base_class.name) klass.quote_value(source_reflection.active_record.base_class.name)
] ]
else else
case source_reflection.macro first_key = through_reflection.klass.base_class.to_s.classify.foreign_key
when :belongs_to second_key = options[:foreign_key] || primary_key
first_key = primary_key end
second_key = source_reflection.options[:foreign_key] || klass.to_s.classify.foreign_key
extra = nil unless through_reflection.klass.descends_from_active_record?
when :has_many jt_sti_extra = " AND %s.%s = %s" % [
first_key = through_reflection.klass.base_class.to_s.classify.foreign_key aliased_join_table_name,
second_key = options[:foreign_key] || primary_key reflection.active_record.connection.quote_column_name(through_reflection.active_record.inheritance_column),
extra = through_reflection.klass.descends_from_active_record? ? nil : through_reflection.klass.quote_value(through_reflection.klass.name.demodulize)]
" AND %s.%s = %s" % [ end
aliased_join_table_name, when :belongs_to
reflection.active_record.connection.quote_column_name(through_reflection.active_record.inheritance_column), first_key = primary_key
through_reflection.klass.quote_value(through_reflection.klass.name.demodulize)] if reflection.options[:source_type]
end second_key = source_reflection.association_foreign_key
" LEFT OUTER JOIN %s ON (%s.%s = %s.%s%s) " % [ jt_source_extra = " AND %s.%s = %s" % [
table_alias_for(through_reflection.klass.table_name, aliased_join_table_name), aliased_join_table_name, reflection.active_record.connection.quote_column_name(reflection.source_reflection.options[:foreign_type]),
aliased_join_table_name, through_reflection.primary_key_name, klass.quote_value(reflection.options[:source_type])
parent.aliased_table_name, parent.primary_key, extra] +
" LEFT OUTER JOIN %s ON (%s.%s = %s.%s) " % [
table_name_and_alias,
aliased_table_name, first_key,
aliased_join_table_name, second_key
] ]
else
second_key = source_reflection.options[:foreign_key] || klass.to_s.classify.foreign_key
end end
end end
" LEFT OUTER JOIN %s ON (%s.%s = %s.%s%s%s%s) " % [
table_alias_for(through_reflection.klass.table_name, aliased_join_table_name),
parent.aliased_table_name, reflection.active_record.connection.quote_column_name(parent.primary_key),
aliased_join_table_name, reflection.active_record.connection.quote_column_name(jt_foreign_key),
jt_as_extra, jt_source_extra, jt_sti_extra
] +
" LEFT OUTER JOIN %s ON (%s.%s = %s.%s%s) " % [
table_name_and_alias,
aliased_table_name, reflection.active_record.connection.quote_column_name(first_key),
aliased_join_table_name, reflection.active_record.connection.quote_column_name(second_key),
as_extra
]
when reflection.macro == :has_many && reflection.options[:as] when reflection.macro == :has_many && reflection.options[:as]
" LEFT OUTER JOIN %s ON %s.%s = %s.%s AND %s.%s = %s" % [ " LEFT OUTER JOIN %s ON %s.%s = %s.%s AND %s.%s = %s" % [
@ -1588,6 +1604,7 @@ module ActiveRecord
end end
protected protected
def pluralize(table_name) def pluralize(table_name)
ActiveRecord::Base.pluralize_table_names ? table_name.to_s.pluralize : table_name ActiveRecord::Base.pluralize_table_names ? table_name.to_s.pluralize : table_name
end end

View file

@ -138,7 +138,11 @@ module ActiveRecord
# Construct attributes for :through pointing to owner and associate. # Construct attributes for :through pointing to owner and associate.
def construct_join_attributes(associate) def construct_join_attributes(associate)
construct_owner_attributes(@reflection.through_reflection).merge(@reflection.source_reflection.association_foreign_key => associate.id) returning construct_owner_attributes(@reflection.through_reflection).merge(@reflection.source_reflection.primary_key_name => associate.id) do |join_attributes|
if @reflection.options[:source_type]
join_attributes.merge!(@reflection.source_reflection.options[:foreign_type] => associate.class.base_class.name.to_s)
end
end
end end
# Associate attributes pointing to owner, quoted. # Associate attributes pointing to owner, quoted.
@ -176,6 +180,12 @@ module ActiveRecord
if @reflection.through_reflection.options[:as] || @reflection.source_reflection.macro == :belongs_to if @reflection.through_reflection.options[:as] || @reflection.source_reflection.macro == :belongs_to
reflection_primary_key = @reflection.klass.primary_key reflection_primary_key = @reflection.klass.primary_key
source_primary_key = @reflection.source_reflection.primary_key_name source_primary_key = @reflection.source_reflection.primary_key_name
if @reflection.options[:source_type]
polymorphic_join = "AND %s.%s = %s" % [
@reflection.through_reflection.table_name, "#{@reflection.source_reflection.options[:foreign_type]}",
@owner.class.quote_value(@reflection.options[:source_type])
]
end
else else
reflection_primary_key = @reflection.source_reflection.primary_key_name reflection_primary_key = @reflection.source_reflection.primary_key_name
source_primary_key = @reflection.klass.primary_key source_primary_key = @reflection.klass.primary_key

View file

@ -479,7 +479,7 @@ module ActiveRecord #:nodoc:
# Deletes the record with the given +id+ without instantiating an object first. If an array of ids is provided, all of them # Deletes the record with the given +id+ without instantiating an object first. If an array of ids is provided, all of them
# are deleted. # are deleted.
def delete(id) def delete(id)
delete_all([ "#{primary_key} IN (?)", id ]) delete_all([ "#{connection.quote_column_name(primary_key)} IN (?)", id ])
end end
# Destroys the record with the given +id+ by instantiating the object and calling #destroy (all the callbacks are the triggered). # Destroys the record with the given +id+ by instantiating the object and calling #destroy (all the callbacks are the triggered).
@ -526,12 +526,12 @@ module ActiveRecord #:nodoc:
# for looping over a collection where each element require a number of aggregate values. Like the DiscussionBoard # for looping over a collection where each element require a number of aggregate values. Like the DiscussionBoard
# that needs to list both the number of posts and comments. # that needs to list both the number of posts and comments.
def increment_counter(counter_name, id) def increment_counter(counter_name, id)
update_all "#{counter_name} = #{counter_name} + 1", "#{primary_key} = #{quote_value(id)}" update_all "#{connection.quote_column_name(counter_name)} = #{connection.quote_column_name(counter_name)} + 1", "#{connection.quote_column_name(primary_key)} = #{quote_value(id)}"
end end
# Works like increment_counter, but decrements instead. # Works like increment_counter, but decrements instead.
def decrement_counter(counter_name, id) def decrement_counter(counter_name, id)
update_all "#{counter_name} = #{counter_name} - 1", "#{primary_key} = #{quote_value(id)}" update_all "#{connection.quote_column_name(counter_name)} = #{connection.quote_column_name(counter_name)} - 1", "#{connection.quote_column_name(primary_key)} = #{quote_value(id)}"
end end
@ -1020,7 +1020,7 @@ module ActiveRecord #:nodoc:
def find_one(id, options) def find_one(id, options)
conditions = " AND (#{sanitize_sql(options[:conditions])})" if options[:conditions] conditions = " AND (#{sanitize_sql(options[:conditions])})" if options[:conditions]
options.update :conditions => "#{table_name}.#{primary_key} = #{quote_value(id,columns_hash[primary_key])}#{conditions}" options.update :conditions => "#{table_name}.#{connection.quote_column_name(primary_key)} = #{quote_value(id,columns_hash[primary_key])}#{conditions}"
# Use find_every(options).first since the primary key condition # Use find_every(options).first since the primary key condition
# already ensures we have a single record. Using find_initial adds # already ensures we have a single record. Using find_initial adds
@ -1035,7 +1035,7 @@ module ActiveRecord #:nodoc:
def find_some(ids, options) def find_some(ids, options)
conditions = " AND (#{sanitize_sql(options[:conditions])})" if options[:conditions] conditions = " AND (#{sanitize_sql(options[:conditions])})" if options[:conditions]
ids_list = ids.map { |id| quote_value(id,columns_hash[primary_key]) }.join(',') ids_list = ids.map { |id| quote_value(id,columns_hash[primary_key]) }.join(',')
options.update :conditions => "#{table_name}.#{primary_key} IN (#{ids_list})#{conditions}" options.update :conditions => "#{table_name}.#{connection.quote_column_name(primary_key)} IN (#{ids_list})#{conditions}"
result = find_every(options) result = find_every(options)
@ -1052,10 +1052,9 @@ module ActiveRecord #:nodoc:
def instantiate(record) def instantiate(record)
object = object =
if subclass_name = record[inheritance_column] if subclass_name = record[inheritance_column]
# No type given.
if subclass_name.empty? if subclass_name.empty?
# No type given.
allocate allocate
else else
# Ignore type if no column is present since it was probably # Ignore type if no column is present since it was probably
# pulled in from a sloppy join. # pulled in from a sloppy join.
@ -1558,7 +1557,7 @@ module ActiveRecord #:nodoc:
unless new_record? unless new_record?
connection.delete <<-end_sql, "#{self.class.name} Destroy" connection.delete <<-end_sql, "#{self.class.name} Destroy"
DELETE FROM #{self.class.table_name} DELETE FROM #{self.class.table_name}
WHERE #{self.class.primary_key} = #{quoted_id} WHERE #{connection.quote_column_name(self.class.primary_key)} = #{quoted_id}
end_sql end_sql
end end
@ -1797,7 +1796,7 @@ module ActiveRecord #:nodoc:
connection.update( connection.update(
"UPDATE #{self.class.table_name} " + "UPDATE #{self.class.table_name} " +
"SET #{quoted_comma_pair_list(connection, attributes_with_quotes(false))} " + "SET #{quoted_comma_pair_list(connection, attributes_with_quotes(false))} " +
"WHERE #{self.class.primary_key} = #{quote_value(id)}", "WHERE #{connection.quote_column_name(self.class.primary_key)} = #{quote_value(id)}",
"#{self.class.name} Update" "#{self.class.name} Update"
) )
end end

View file

@ -301,18 +301,30 @@ class Fixtures < YAML::Omap
yaml_string << IO.read(subfixture_path) yaml_string << IO.read(subfixture_path)
end end
yaml_string << IO.read(yaml_file_path) yaml_string << IO.read(yaml_file_path)
begin begin
yaml = YAML::load(erb_render(yaml_string)) yaml = YAML::load(erb_render(yaml_string))
rescue Exception=>boom rescue Exception=>boom
raise Fixture::FormatError, "a YAML error occurred parsing #{yaml_file_path}. Please note that YAML must be consistently indented using spaces. Tabs are not allowed. Please have a look at http://www.yaml.org/faq.html\nThe exact error was:\n #{boom.class}: #{boom}" raise Fixture::FormatError, "a YAML error occurred parsing #{yaml_file_path}. Please note that YAML must be consistently indented using spaces. Tabs are not allowed. Please have a look at http://www.yaml.org/faq.html\nThe exact error was:\n #{boom.class}: #{boom}"
end end
if yaml if yaml
yaml = yaml.value if yaml.respond_to?(:type_id) and yaml.respond_to?(:value) # If the file is an ordered map, extract its children.
yaml.each do |name, data| yaml_value =
unless data if yaml.respond_to?(:type_id) && yaml.respond_to?(:value)
raise Fixture::FormatError, "Bad data for #{@class_name} fixture named #{name} (nil)" yaml.value
else
[yaml]
end
yaml_value.each do |fixture|
fixture.each do |name, data|
unless data
raise Fixture::FormatError, "Bad data for #{@class_name} fixture named #{name} (nil)"
end
self[name] = Fixture.new(data, @class_name)
end end
self[name] = Fixture.new(data, @class_name)
end end
end end
elsif File.file?(csv_file_path) elsif File.file?(csv_file_path)

View file

@ -186,8 +186,12 @@ module ActiveRecord
if source_reflection.nil? if source_reflection.nil?
raise HasManyThroughSourceAssociationNotFoundError.new(self) raise HasManyThroughSourceAssociationNotFoundError.new(self)
end end
if options[:source_type] && source_reflection.options[:polymorphic].nil?
raise HasManyThroughAssociationPointlessSourceTypeError.new(active_record.name, self, source_reflection)
end
if source_reflection.options[:polymorphic] if source_reflection.options[:polymorphic] && options[:source_type].nil?
raise HasManyThroughAssociationPolymorphicError.new(active_record.name, self, source_reflection) raise HasManyThroughAssociationPolymorphicError.new(active_record.name, self, source_reflection)
end end
@ -205,7 +209,7 @@ module ActiveRecord
if options[:class_name] if options[:class_name]
options[:class_name] options[:class_name]
elsif through_reflection # get the class_name of the belongs_to association of the through reflection elsif through_reflection # get the class_name of the belongs_to association of the through reflection
source_reflection.class_name options[:source_type] || source_reflection.class_name
else else
class_name = name.to_s.camelize class_name = name.to_s.camelize
class_name = class_name.singularize if [ :has_many, :has_and_belongs_to_many ].include?(macro) class_name = class_name.singularize if [ :has_many, :has_and_belongs_to_many ].include?(macro)

View file

@ -563,9 +563,9 @@ class Mysql
def scramble41(password, message) def scramble41(password, message)
return 0x00.chr if password.nil? or password.empty? return 0x00.chr if password.nil? or password.empty?
buf = [0x14] buf = [0x14]
s1 = Digest::SHA1.new(password).digest s1 = Digest::SHA1.digest(password)
s2 = Digest::SHA1.new(s1).digest s2 = Digest::SHA1.digest(s1)
x = Digest::SHA1.new(message + s2).digest x = Digest::SHA1.digest(message + s2)
(0..s1.length - 1).each {|i| buf.push(s1[i] ^ x[i])} (0..s1.length - 1).each {|i| buf.push(s1[i] ^ x[i])}
buf.pack("C*") buf.pack("C*")
end end
@ -1174,7 +1174,11 @@ class << Mysql
def finalizer(net) def finalizer(net)
proc { proc {
net.clear net.clear
net.write Mysql::COM_QUIT.chr begin
net.write(Mysql::COM_QUIT.chr)
net.close
rescue # Ignore IOError if socket is already closed.
end
} }
end end

View file

@ -2,7 +2,7 @@ module ActiveRecord
module VERSION #:nodoc: module VERSION #:nodoc:
MAJOR = 1 MAJOR = 1
MINOR = 15 MINOR = 15
TINY = 2 TINY = 3
STRING = [MAJOR, MINOR, TINY].join('.') STRING = [MAJOR, MINOR, TINY].join('.')
end end

View file

@ -6,10 +6,12 @@ require 'fixtures/comment'
require 'fixtures/author' require 'fixtures/author'
require 'fixtures/category' require 'fixtures/category'
require 'fixtures/categorization' require 'fixtures/categorization'
require 'fixtures/vertex'
require 'fixtures/edge'
class AssociationsJoinModelTest < Test::Unit::TestCase class AssociationsJoinModelTest < Test::Unit::TestCase
self.use_transactional_fixtures = false self.use_transactional_fixtures = false
fixtures :posts, :authors, :categories, :categorizations, :comments, :tags, :taggings, :author_favorites fixtures :posts, :authors, :categories, :categorizations, :comments, :tags, :taggings, :author_favorites, :vertices
def test_has_many def test_has_many
assert authors(:david).categories.include?(categories(:general)) assert authors(:david).categories.include?(categories(:general))
@ -298,6 +300,18 @@ class AssociationsJoinModelTest < Test::Unit::TestCase
assert_equal [posts(:welcome), posts(:thinking)], tags(:general).taggings.find(:all, :include => :taggable) assert_equal [posts(:welcome), posts(:thinking)], tags(:general).taggings.find(:all, :include => :taggable)
end end
end end
def test_has_many_polymorphic_with_source_type
assert_equal [posts(:welcome), posts(:thinking)], tags(:general).tagged_posts
end
def test_eager_has_many_polymorphic_with_source_type
tag_with_include = Tag.find(tags(:general).id, :include => :tagged_posts)
desired = [posts(:welcome), posts(:thinking)]
assert_no_queries do
assert_equal desired, tag_with_include.tagged_posts
end
end
def test_has_many_through_has_many_find_all def test_has_many_through_has_many_find_all
assert_equal comments(:greetings), authors(:david).comments.find(:all, :order => 'comments.id').first assert_equal comments(:greetings), authors(:david).comments.find(:all, :order => 'comments.id').first
@ -414,6 +428,9 @@ class AssociationsJoinModelTest < Test::Unit::TestCase
message = "Expected a Tagging in taggings collection, got #{wrong.class}.") message = "Expected a Tagging in taggings collection, got #{wrong.class}.")
assert_equal(count + 4, post_thinking.tags.size) assert_equal(count + 4, post_thinking.tags.size)
assert_equal(count + 4, post_thinking.tags(true).size) assert_equal(count + 4, post_thinking.tags(true).size)
# Raises if the wrong reflection name is used to set the Edge belongs_to
assert_nothing_raised { vertices(:vertex_1).sinks << vertices(:vertex_5) }
end end
def test_adding_junk_to_has_many_through_should_raise_type_mismatch def test_adding_junk_to_has_many_through_should_raise_type_mismatch

View file

@ -1,4 +1,4 @@
--- !omap --- !!omap
<% 100.times do |i| %> <% 100.times do |i| %>
- fixture_no_<%= i %>: - fixture_no_<%= i %>:
id: <%= i %> id: <%= i %>

View file

@ -29,3 +29,4 @@ DROP TABLE fk_test_has_fk;
DROP TABLE keyboards; DROP TABLE keyboards;
DROP TABLE legacy_things; DROP TABLE legacy_things;
DROP TABLE numeric_data; DROP TABLE numeric_data;
DROP TABLE mixed_case_monkeys;

View file

@ -224,3 +224,8 @@ CREATE TABLE numeric_data (
my_house_population DECIMAL(2), my_house_population DECIMAL(2),
decimal_number_with_default DECIMAL(3,2) DEFAULT 2.78 decimal_number_with_default DECIMAL(3,2) DEFAULT 2.78
); );
CREATE TABLE mixed_case_monkeys (
monkeyID INT NOT NULL PRIMARY KEY,
fleaCount INT
);

View file

@ -30,6 +30,7 @@ DROP TABLE keyboards;
DROP TABLE defaults; DROP TABLE defaults;
DROP TABLE legacy_things; DROP TABLE legacy_things;
DROP TABLE numeric_data; DROP TABLE numeric_data;
DROP TABLE mixed_case_monkeys;
DROP DOMAIN D_BOOLEAN; DROP DOMAIN D_BOOLEAN;
@ -59,3 +60,4 @@ DROP GENERATOR keyboards_seq;
DROP GENERATOR defaults_seq; DROP GENERATOR defaults_seq;
DROP GENERATOR legacy_things_seq; DROP GENERATOR legacy_things_seq;
DROP GENERATOR numeric_data_seq; DROP GENERATOR numeric_data_seq;
DROP GENERATOR mixed_case_monkeys_seq;

View file

@ -295,3 +295,10 @@ CREATE TABLE numeric_data (
); );
CREATE GENERATOR numeric_data_seq; CREATE GENERATOR numeric_data_seq;
SET GENERATOR numeric_data_seq TO 10000; SET GENERATOR numeric_data_seq TO 10000;
CREATE TABLE mixed_case_monkeys (
"monkeyID" BIGINT NOT NULL,
"fleaCount" INTEGER
);
CREATE GENERATOR mixed_case_monkeys_seq;
SET GENERATOR mixed_case_monkeys_seq TO 10000;

View file

@ -29,3 +29,4 @@ DROP TABLE fk_test_has_pk CASCADE;
DROP TABLE keyboards CASCADE; DROP TABLE keyboards CASCADE;
DROP TABLE legacy_things CASCADE; DROP TABLE legacy_things CASCADE;
DROP TABLE numeric_data CASCADE; DROP TABLE numeric_data CASCADE;
DROP TABLE mixed_case_monkeys CASCADE;

View file

@ -260,3 +260,9 @@ CREATE TABLE "numeric_data" (
primary key ("id") primary key ("id")
); );
SET UNIQUE FOR numeric_data(id); SET UNIQUE FOR numeric_data(id);
CREATE TABLE mixed_case_monkeys (
"monkeyID" integer DEFAULT unique,
"fleaCount" integer
);
SET UNIQUE FOR mixed_case_monkeys("monkeyID");

View file

@ -29,3 +29,4 @@ DROP TABLE fk_test_has_pk;
DROP TABLE keyboards; DROP TABLE keyboards;
DROP TABLE legacy_things; DROP TABLE legacy_things;
DROP TABLE numeric_data; DROP TABLE numeric_data;
DROP TABLE mixed_case_monkeys;

View file

@ -226,3 +226,9 @@ CREATE TABLE `numeric_data` (
`my_house_population` decimal(2), `my_house_population` decimal(2),
`decimal_number_with_default` decimal(3,2) DEFAULT 2.78 `decimal_number_with_default` decimal(3,2) DEFAULT 2.78
) TYPE=InnoDB; ) TYPE=InnoDB;
CREATE TABLE mixed_case_monkeys (
`monkeyID` int(11) NOT NULL auto_increment,
`fleaCount` int(11),
PRIMARY KEY (`monkeyID`)
) TYPE=InnoDB;

View file

@ -292,3 +292,11 @@ CREATE TABLE numeric_data (
go go
CREATE PRIMARY KEY numeric_data (id) CREATE PRIMARY KEY numeric_data (id)
go go
CREATE TABLE mixed_case_monkeys (
monkeyID INTEGER NOT NULL DEFAULT _rowid,
fleaCount INTEGER
);
go
CREATE PRIMARY KEY mixed_case_monkeys (monkeyID)
go

View file

@ -30,6 +30,7 @@ drop table fk_test_has_fk;
drop table keyboards; drop table keyboards;
drop table legacy_things; drop table legacy_things;
drop table numeric_data; drop table numeric_data;
drop table mixed_case_monkeys;
drop sequence accounts_seq; drop sequence accounts_seq;
drop sequence funny_jokes_seq; drop sequence funny_jokes_seq;
@ -61,3 +62,4 @@ drop sequence fk_test_has_fk_seq;
drop sequence keyboards_seq; drop sequence keyboards_seq;
drop sequence legacy_things_seq; drop sequence legacy_things_seq;
drop sequence numeric_data_seq; drop sequence numeric_data_seq;
drop sequence mixed_case_monkeys_seq;

View file

@ -317,3 +317,9 @@ CREATE TABLE numeric_data (
decimal_number_with_default decimal(3,2) DEFAULT 2.78 decimal_number_with_default decimal(3,2) DEFAULT 2.78
); );
create sequence numeric_data_seq minvalue 10000; create sequence numeric_data_seq minvalue 10000;
CREATE TABLE mixed_case_monkeys (
"monkeyID" INTEGER NOT NULL PRIMARY KEY,
"fleaCount" INTEGER
);
create sequence mixed_case_monkeys_seq minvalue 10000;

View file

@ -34,3 +34,4 @@ DROP TABLE keyboards;
DROP TABLE legacy_things; DROP TABLE legacy_things;
DROP TABLE numeric_data; DROP TABLE numeric_data;
DROP TABLE column_data; DROP TABLE column_data;
DROP TABLE mixed_case_monkeys;

View file

@ -256,3 +256,8 @@ CREATE TABLE numeric_data (
my_house_population decimal(2), my_house_population decimal(2),
decimal_number_with_default decimal(3,2) default 2.78 decimal_number_with_default decimal(3,2) default 2.78
); );
CREATE TABLE mixed_case_monkeys (
"monkeyID" INTEGER PRIMARY KEY,
"fleaCount" INTEGER
);

View file

@ -29,3 +29,4 @@ DROP TABLE fk_test_has_pk;
DROP TABLE keyboards; DROP TABLE keyboards;
DROP TABLE legacy_things; DROP TABLE legacy_things;
DROP TABLE numeric_data; DROP TABLE numeric_data;
DROP TABLE mixed_case_monkeys;

View file

@ -208,3 +208,8 @@ CREATE TABLE 'numeric_data' (
'my_house_population' DECIMAL(2), 'my_house_population' DECIMAL(2),
'decimal_number_with_default' DECIMAL(3,2) DEFAULT 2.78 'decimal_number_with_default' DECIMAL(3,2) DEFAULT 2.78
); );
CREATE TABLE mixed_case_monkeys (
'monkeyID' INTEGER NOT NULL PRIMARY KEY,
'fleaCount' INTEGER
);

View file

@ -31,3 +31,4 @@ DROP TABLE keyboards;
DROP TABLE legacy_things; DROP TABLE legacy_things;
DROP TABLE numeric_data; DROP TABLE numeric_data;
DROP TABLE [order]; DROP TABLE [order];
DROP TABLE mixed_case_monkeys;

View file

@ -236,3 +236,8 @@ CREATE TABLE [order] (
texture varchar(255), texture varchar(255),
flavor varchar(255) flavor varchar(255)
); );
CREATE TABLE mixed_case_monkeys (
[monkeyID] int NOT NULL IDENTITY(1, 1),
[fleaCount] int default NULL
);

View file

@ -29,5 +29,6 @@ DROP TABLE fk_test_has_pk
DROP TABLE keyboards DROP TABLE keyboards
DROP TABLE legacy_things DROP TABLE legacy_things
DROP TABLE numeric_data DROP TABLE numeric_data
DROP TABLE mixed_case_monkeys
DROP TABLE schema_info DROP TABLE schema_info
go go

View file

@ -210,4 +210,9 @@ CREATE TABLE numeric_data (
decimal_number_with_default numeric(3,2) DEFAULT 2.78 decimal_number_with_default numeric(3,2) DEFAULT 2.78
) )
CREATE TABLE mixed_case_monkeys (
[monkeyID] numeric(9,0) IDENTITY PRIMARY KEY,
[fleaCount] numeric(9,0)
);
go go

View file

@ -2,4 +2,6 @@ class Tag < ActiveRecord::Base
has_many :taggings has_many :taggings
has_many :taggables, :through => :taggings has_many :taggables, :through => :taggings
has_one :tagging has_one :tagging
has_many :tagged_posts, :through => :taggings, :source => :taggable, :source_type => 'Post'
end end

View file

@ -1,7 +1,7 @@
# This class models a vertex in a directed graph. # This class models a vertex in a directed graph.
class Vertex < ActiveRecord::Base class Vertex < ActiveRecord::Base
has_many :sink_edges, :class_name => 'Edge', :foreign_key => 'source_id' has_many :sink_edges, :class_name => 'Edge', :foreign_key => 'source_id'
has_many :sinks, :through => :sink_edges, :source => :sink has_many :sinks, :through => :sink_edges
has_and_belongs_to_many :sources, has_and_belongs_to_many :sources,
:class_name => 'Vertex', :join_table => 'edges', :class_name => 'Vertex', :join_table => 'edges',

View file

@ -4,9 +4,10 @@ require 'fixtures/reply'
require 'fixtures/subscriber' require 'fixtures/subscriber'
require 'fixtures/movie' require 'fixtures/movie'
require 'fixtures/keyboard' require 'fixtures/keyboard'
require 'fixtures/mixed_case_monkey'
class PrimaryKeysTest < Test::Unit::TestCase class PrimaryKeysTest < Test::Unit::TestCase
fixtures :topics, :subscribers, :movies fixtures :topics, :subscribers, :movies, :mixed_case_monkeys
def test_integer_key def test_integer_key
topic = Topic.find(1) topic = Topic.find(1)
@ -78,4 +79,26 @@ class PrimaryKeysTest < Test::Unit::TestCase
Topic.reset_primary_key Topic.reset_primary_key
assert_equal "id", Topic.primary_key assert_equal "id", Topic.primary_key
end end
def test_delete_should_quote_pkey
assert_nothing_raised { MixedCaseMonkey.delete(1) }
end
def test_increment_counter_should_quote_pkey_and_quote_counter_columns
assert_nothing_raised { MixedCaseMonkey.increment_counter(:fleaCount, 1) }
end
def test_decrement_counter_should_quote_pkey_and_quote_counter_columns
assert_nothing_raised { MixedCaseMonkey.decrement_counter(:fleaCount, 1) }
end
def test_find_with_one_id_should_quote_pkey
assert_nothing_raised { MixedCaseMonkey.find(1) }
end
def test_find_with_multiple_ids_should_quote_pkey
assert_nothing_raised { MixedCaseMonkey.find([1,2]) }
end
def test_instance_update_should_quote_pkey
assert_nothing_raised { MixedCaseMonkey.find(1).save }
end
def test_instance_destry_should_quote_pkey
assert_nothing_raised { MixedCaseMonkey.find(1).destroy }
end
end end

View file

@ -1,8 +1,16 @@
*1.4.2* (March 12th, 2007)
* Ruby 1.8.6 and 1.9 define private Time#to_date and #to_datetime; make them
public for compatibility. [Jeremy Kemper]
* Deprecation: warn on stderr if RAILS_DEFAULT_LOGGER isn't set yet. [Jeremy Kemper]
*1.4.1* (February 5th, 2007) *1.4.1* (February 5th, 2007)
* Optimize Class Inheritable Attributes so that unnecessary hashes are not created. [Bruce Perens] * Optimize Class Inheritable Attributes so that unnecessary hashes are not created. Closes #7472 [Bruce Perens]
* Added :instance_writer option to #mattr_writer/accessor, #cattr_writer/accessor, and #class_inheritable_writer to skip the creation of the instance writer. [Rick] * Added :instance_writer option to #mattr_writer/accessor, #cattr_writer/accessor, and #class_inheritable_writer to skip the creation of the instance writer. [Rick]
* Full test coverage for Inflector. #7228 [Dan Kubb] * Full test coverage for Inflector. #7228 [Dan Kubb]

View file

@ -72,11 +72,11 @@ end
desc "Publish the release files to RubyForge." desc "Publish the release files to RubyForge."
task :release => [ :package ] do task :release => [ :package ] do
`rubyforge login` require 'rubyforge'
for ext in %w( gem tgz zip ) packages = %w( gem tgz zip ).collect{ |ext| "pkg/#{PKG_NAME}-#{PKG_VERSION}.#{ext}" }
release_command = "rubyforge add_release #{PKG_NAME} #{PKG_NAME} 'REL #{PKG_VERSION}' pkg/#{PKG_NAME}-#{PKG_VERSION}.#{ext}"
puts release_command rubyforge = RubyForge.new
system(release_command) rubyforge.login
end rubyforge.add_release(PKG_NAME, PKG_NAME, "REL #{PKG_VERSION}", *packages)
end end

View file

@ -1,3 +1,13 @@
require 'date'
require 'time'
# Ruby 1.8-cvs and 1.9 define private Time#to_date
class Time
%w(to_date to_datetime).each do |method|
public method if private_instance_methods.include?(method)
end
end
require File.dirname(__FILE__) + '/time/calculations' require File.dirname(__FILE__) + '/time/calculations'
require File.dirname(__FILE__) + '/time/conversions' require File.dirname(__FILE__) + '/time/conversions'

View file

@ -1,6 +1,3 @@
require 'date'
require 'time'
module ActiveSupport #:nodoc: module ActiveSupport #:nodoc:
module CoreExtensions #:nodoc: module CoreExtensions #:nodoc:
module Time #:nodoc: module Time #:nodoc:

View file

@ -13,8 +13,9 @@ module ActiveSupport
$stderr.puts callstack.join("\n ") if debug $stderr.puts callstack.join("\n ") if debug
}, },
'development' => Proc.new { |message, callstack| 'development' => Proc.new { |message, callstack|
RAILS_DEFAULT_LOGGER.warn message logger = defined?(::RAILS_DEFAULT_LOGGER) ? ::RAILS_DEFAULT_LOGGER : Logger.new($stderr)
RAILS_DEFAULT_LOGGER.debug callstack.join("\n ") if debug logger.warn message
logger.debug callstack.join("\n ") if debug
} }
} }

View file

@ -2,7 +2,7 @@ module ActiveSupport
module VERSION #:nodoc: module VERSION #:nodoc:
MAJOR = 1 MAJOR = 1
MINOR = 4 MINOR = 4
TINY = 1 TINY = 2
STRING = [MAJOR, MINOR, TINY].join('.') STRING = [MAJOR, MINOR, TINY].join('.')
end end

View file

@ -1,3 +1,12 @@
*1.2.3* (March 12th, 2007)
* Ruby 1.8.6 compatibility
* Windows: include MinGW in RUBY_PLATFORM check. #2982 [okkez000@gmail.com, Kaspar Schiess]
* Stop swallowing errors during rake test [Koz]
*1.2.2* (February 5th, 2007) *1.2.2* (February 5th, 2007)
* Fix gem deprecation warnings, which also means depending on RubyGems 0.9.0+ [Chad Fowler] * Fix gem deprecation warnings, which also means depending on RubyGems 0.9.0+ [Chad Fowler]

View file

@ -287,12 +287,12 @@ spec = Gem::Specification.new do |s|
on top of either MySQL, PostgreSQL, SQLite, DB2, SQL Server, or Oracle with eRuby- or Builder-based templates. on top of either MySQL, PostgreSQL, SQLite, DB2, SQL Server, or Oracle with eRuby- or Builder-based templates.
EOF EOF
s.add_dependency('rake', '>= 0.7.1') s.add_dependency('rake', '>= 0.7.2')
s.add_dependency('activesupport', '= 1.4.1' + PKG_BUILD) s.add_dependency('activesupport', '= 1.4.2' + PKG_BUILD)
s.add_dependency('activerecord', '= 1.15.2' + PKG_BUILD) s.add_dependency('activerecord', '= 1.15.3' + PKG_BUILD)
s.add_dependency('actionpack', '= 1.13.2' + PKG_BUILD) s.add_dependency('actionpack', '= 1.13.3' + PKG_BUILD)
s.add_dependency('actionmailer', '= 1.3.2' + PKG_BUILD) s.add_dependency('actionmailer', '= 1.3.3' + PKG_BUILD)
s.add_dependency('actionwebservice', '= 1.2.2' + PKG_BUILD) s.add_dependency('actionwebservice', '= 1.2.3' + PKG_BUILD)
s.rdoc_options << '--exclude' << '.' s.rdoc_options << '--exclude' << '.'
s.has_rdoc = false s.has_rdoc = false
@ -323,9 +323,12 @@ task :pgem => [:gem] do
end end
desc "Publish the release files to RubyForge." desc "Publish the release files to RubyForge."
task :release => [ :gem ] do task :release => [ :package ] do
`rubyforge login` require 'rubyforge'
release_command = "rubyforge add_release #{PKG_NAME} #{PKG_NAME} 'REL #{PKG_VERSION}' pkg/#{PKG_NAME}-#{PKG_VERSION}.gem"
puts release_command packages = %w( gem ).collect{ |ext| "pkg/#{PKG_NAME}-#{PKG_VERSION}.#{ext}" }
system(release_command)
end rubyforge = RubyForge.new
rubyforge.login
rubyforge.add_release(PKG_NAME, PKG_NAME, "REL #{PKG_VERSION}", *packages)
end

View file

@ -3,7 +3,7 @@
unless defined?(RAILS_ROOT) unless defined?(RAILS_ROOT)
root_path = File.join(File.dirname(__FILE__), '..') root_path = File.join(File.dirname(__FILE__), '..')
unless RUBY_PLATFORM =~ /mswin32/ unless RUBY_PLATFORM =~ /(:?mswin|mingw)/
require 'pathname' require 'pathname'
root_path = Pathname.new(root_path).cleanpath(true).to_s root_path = Pathname.new(root_path).cleanpath(true).to_s
end end
@ -42,4 +42,4 @@ unless defined?(Rails::Initializer)
end end
Rails::Initializer.run(:set_load_path) Rails::Initializer.run(:set_load_path)
end end

View file

@ -1,4 +1,4 @@
irb = RUBY_PLATFORM =~ /mswin32/ ? 'irb.bat' : 'irb' irb = RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'irb.bat' : 'irb'
require 'optparse' require 'optparse'
options = { :sandbox => false, :irb => irb } options = { :sandbox => false, :irb => irb }

View file

@ -240,11 +240,12 @@ class Plugin
def install_using_http(options = {}) def install_using_http(options = {})
root = rails_env.root root = rails_env.root
mkdir_p "#{root}/vendor/plugins" mkdir_p "#{root}/vendor/plugins"
Dir.chdir "#{root}/vendor/plugins" Dir.chdir "#{root}/vendor/plugins" do
puts "fetching from '#{uri}'" if $verbose puts "fetching from '#{uri}'" if $verbose
fetcher = RecursiveHTTPFetcher.new(uri) fetcher = RecursiveHTTPFetcher.new(uri)
fetcher.quiet = true if options[:quiet] fetcher.quiet = true if options[:quiet]
fetcher.fetch fetcher.fetch
end
end end
def svn_command(cmd, options = {}) def svn_command(cmd, options = {})

View file

@ -1,6 +1,6 @@
require 'optparse' require 'optparse'
if RUBY_PLATFORM =~ /mswin32/ then abort("Inspector is only for Unix") end if RUBY_PLATFORM =~ /(:?mswin|mingw)/ then abort("Inspector is only for Unix") end
OPTIONS = { OPTIONS = {
:pid_path => File.expand_path(RAILS_ROOT + '/tmp/pids'), :pid_path => File.expand_path(RAILS_ROOT + '/tmp/pids'),
@ -65,4 +65,4 @@ ARGV.options do |opts|
opts.parse! opts.parse!
end end
Inspector.inspect(OPTIONS[:pid_path], OPTIONS[:pattern]) Inspector.inspect(OPTIONS[:pid_path], OPTIONS[:pattern])

View file

@ -2,7 +2,7 @@ require 'optparse'
require 'net/http' require 'net/http'
require 'uri' require 'uri'
if RUBY_PLATFORM =~ /mswin32/ then abort("Reaper is only for Unix") end if RUBY_PLATFORM =~ /(:?mswin|mingw)/ then abort("Reaper is only for Unix") end
class Killer class Killer
class << self class << self

View file

@ -92,7 +92,7 @@ server = case ARGV.first
else else
if defined?(Mongrel) if defined?(Mongrel)
"mongrel" "mongrel"
elsif RUBY_PLATFORM !~ /mswin/ && !silence_stderr { `spawn-fcgi -version` }.blank? && defined?(FCGI) elsif RUBY_PLATFORM !~ /(:?mswin|mingw)/ && !silence_stderr { `spawn-fcgi -version` }.blank? && defined?(FCGI)
"fcgi" "fcgi"
end end
end end
@ -206,4 +206,4 @@ if OPTIONS[:repeat]
end end
else else
spawner_class.spawn_all spawner_class.spawn_all
end end

View file

@ -19,7 +19,7 @@ server = case ARGV.first
else else
if defined?(Mongrel) if defined?(Mongrel)
"mongrel" "mongrel"
elsif RUBY_PLATFORM !~ /mswin/ && !silence_stderr { `lighttpd -version` }.blank? && defined?(FCGI) elsif RUBY_PLATFORM !~ /(:?mswin|mingw)/ && !silence_stderr { `lighttpd -version` }.blank? && defined?(FCGI)
"lighttpd" "lighttpd"
else else
"webrick" "webrick"

View file

@ -2,7 +2,7 @@ module Rails
module VERSION #:nodoc: module VERSION #:nodoc:
MAJOR = 1 MAJOR = 1
MINOR = 2 MINOR = 2
TINY = 2 TINY = 3
STRING = [MAJOR, MINOR, TINY].join('.') STRING = [MAJOR, MINOR, TINY].join('.')
end end

View file

@ -109,7 +109,7 @@ class AppGenerator < Rails::Generator::Base
end end
def mysql_socket_location def mysql_socket_location
RUBY_PLATFORM =~ /mswin32/ ? MYSQL_SOCKET_LOCATIONS.find { |f| File.exists?(f) } : nil MYSQL_SOCKET_LOCATIONS.find { |f| File.exists?(f) } unless RUBY_PLATFORM =~ /(:?mswin|mingw)/
end end

View file

@ -30,7 +30,7 @@ end
module Kernel module Kernel
def silence_stderr def silence_stderr
old_stderr = STDERR.dup old_stderr = STDERR.dup
STDERR.reopen(RUBY_PLATFORM =~ /mswin/ ? 'NUL:' : '/dev/null') STDERR.reopen(RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'NUL:' : '/dev/null')
STDERR.sync = true STDERR.sync = true
yield yield
ensure ensure
@ -40,14 +40,17 @@ end
desc 'Test all units and functionals' desc 'Test all units and functionals'
task :test do task :test do
Rake::Task["test:units"].invoke rescue got_error = true exceptions = ["test:units", "test:functionals", "test:integration"].collect do |task|
Rake::Task["test:functionals"].invoke rescue got_error = true begin
Rake::Task[task].invoke
nil
rescue => e
e
end
end.compact
if File.exist?("test/integration") exceptions.each {|e| puts e;puts e.backtrace }
Rake::Task["test:integration"].invoke rescue got_error = true raise "Test failures" unless exceptions.empty?
end
raise "Test failures" if got_error
end end
namespace :test do namespace :test do