diff options
author | Pratik Naik <pratiknaik@gmail.com> | 2008-11-02 03:52:15 +0530 |
---|---|---|
committer | Pratik Naik <pratiknaik@gmail.com> | 2008-11-02 03:52:15 +0530 |
commit | 1147453fce0890ea229c3af5f43c909ebe53061e (patch) | |
tree | 221d816ef0c908044fd6029950ccad064866ab8f /railties | |
parent | a3aa0c17ef8594a0084511f4852be7b5dc66e5e2 (diff) | |
parent | 5a02f0bccf55191c2cfbcc69bd8165df6d7a2012 (diff) | |
download | rails-1147453fce0890ea229c3af5f43c909ebe53061e.tar.gz rails-1147453fce0890ea229c3af5f43c909ebe53061e.tar.bz2 rails-1147453fce0890ea229c3af5f43c909ebe53061e.zip |
Merge commit 'mainstream/master'
Conflicts:
railties/doc/guides/html/layouts_and_rendering.html
railties/doc/guides/source/active_record_basics.txt
railties/doc/guides/source/layouts_and_rendering.txt
Diffstat (limited to 'railties')
-rw-r--r-- | railties/CHANGELOG | 7 | ||||
-rw-r--r-- | railties/Rakefile | 2 | ||||
-rw-r--r-- | railties/doc/guides/source/active_record_basics.txt | 2 | ||||
-rw-r--r-- | railties/html/javascripts/prototype.js | 337 | ||||
-rw-r--r-- | railties/lib/initializer.rb | 1 | ||||
-rw-r--r-- | railties/lib/rails/gem_dependency.rb | 37 | ||||
-rw-r--r-- | railties/lib/rails_generator/generators/components/plugin/plugin_generator.rb | 20 | ||||
-rw-r--r-- | railties/lib/rails_generator/generators/components/plugin/templates/Rakefile | 1 | ||||
-rw-r--r-- | railties/lib/rails_generator/generators/components/plugin/templates/test_helper.rb | 3 | ||||
-rw-r--r-- | railties/lib/rails_generator/generators/components/plugin/templates/unit_test.rb | 4 | ||||
-rw-r--r-- | railties/lib/tasks/gems.rake | 3 | ||||
-rw-r--r-- | railties/test/gem_dependency_test.rb | 5 |
12 files changed, 272 insertions, 150 deletions
diff --git a/railties/CHANGELOG b/railties/CHANGELOG index 390da3b890..058afddbde 100644 --- a/railties/CHANGELOG +++ b/railties/CHANGELOG @@ -1,3 +1,10 @@ +*2.2.1 [RC2 or 2.2 final]* + +* Fixed plugin generator so that generated unit tests would subclass ActiveSupport::TestCase, also introduced a helper script to reduce the needed require statements #1137 [Mathias Meyer] + +* Update Prototype to 1.6.0.3 [sam] + + *2.2.0 [RC1] (October 24th, 2008)* * Fixed that sqlite would report "db/development.sqlite3 already exists" whether true or not on db:create #614 [Antonio Cangiano] diff --git a/railties/Rakefile b/railties/Rakefile index adb6db0b64..872ea83ec2 100644 --- a/railties/Rakefile +++ b/railties/Rakefile @@ -192,7 +192,7 @@ task :copy_configs do app_name = "rails" socket = nil require 'erb' - File.open("#{PKG_DESTINATION}/config/database.yml", 'w') {|f| f.write ERB.new(IO.read("configs/databases/mysql.yml"), nil, '-').result(binding)} + File.open("#{PKG_DESTINATION}/config/database.yml", 'w') {|f| f.write ERB.new(IO.read("configs/databases/sqlite3.yml"), nil, '-').result(binding)} cp "configs/routes.rb", "#{PKG_DESTINATION}/config/routes.rb" diff --git a/railties/doc/guides/source/active_record_basics.txt b/railties/doc/guides/source/active_record_basics.txt index 11a7bdb302..15fc544f25 100644 --- a/railties/doc/guides/source/active_record_basics.txt +++ b/railties/doc/guides/source/active_record_basics.txt @@ -178,4 +178,4 @@ Rails has a reputation of being a zero-config framework which means that it aim * (6) before_create * (-) create * (7) after_create - * (8) after_save
\ No newline at end of file + * (8) after_save diff --git a/railties/html/javascripts/prototype.js b/railties/html/javascripts/prototype.js index 2c70b8a7e8..dfe8ab4e13 100644 --- a/railties/html/javascripts/prototype.js +++ b/railties/html/javascripts/prototype.js @@ -1,4 +1,4 @@ -/* Prototype JavaScript framework, version 1.6.0.2 +/* Prototype JavaScript framework, version 1.6.0.3 * (c) 2005-2008 Sam Stephenson * * Prototype is freely distributable under the terms of an MIT-style license. @@ -7,23 +7,26 @@ *--------------------------------------------------------------------------*/ var Prototype = { - Version: '1.6.0.2', + Version: '1.6.0.3', Browser: { - IE: !!(window.attachEvent && !window.opera), - Opera: !!window.opera, + IE: !!(window.attachEvent && + navigator.userAgent.indexOf('Opera') === -1), + Opera: navigator.userAgent.indexOf('Opera') > -1, WebKit: navigator.userAgent.indexOf('AppleWebKit/') > -1, - Gecko: navigator.userAgent.indexOf('Gecko') > -1 && navigator.userAgent.indexOf('KHTML') == -1, + Gecko: navigator.userAgent.indexOf('Gecko') > -1 && + navigator.userAgent.indexOf('KHTML') === -1, MobileSafari: !!navigator.userAgent.match(/Apple.*Mobile.*Safari/) }, BrowserFeatures: { XPath: !!document.evaluate, + SelectorsAPI: !!document.querySelector, ElementExtensions: !!window.HTMLElement, SpecificElementExtensions: - document.createElement('div').__proto__ && - document.createElement('div').__proto__ !== - document.createElement('form').__proto__ + document.createElement('div')['__proto__'] && + document.createElement('div')['__proto__'] !== + document.createElement('form')['__proto__'] }, ScriptFragment: '<script[^>]*>([\\S\\s]*?)<\/script>', @@ -83,12 +86,13 @@ Class.Methods = { var property = properties[i], value = source[property]; if (ancestor && Object.isFunction(value) && value.argumentNames().first() == "$super") { - var method = value, value = Object.extend((function(m) { + var method = value; + value = (function(m) { return function() { return ancestor[m].apply(this, arguments) }; - })(property).wrap(method), { - valueOf: function() { return method }, - toString: function() { return method.toString() } - }); + })(property).wrap(method); + + value.valueOf = method.valueOf.bind(method); + value.toString = method.toString.bind(method); } this.prototype[property] = value; } @@ -167,7 +171,7 @@ Object.extend(Object, { }, isElement: function(object) { - return object && object.nodeType == 1; + return !!(object && object.nodeType == 1); }, isArray: function(object) { @@ -198,7 +202,8 @@ Object.extend(Object, { Object.extend(Function.prototype, { argumentNames: function() { - var names = this.toString().match(/^[\s\(]*function[^(]*\((.*?)\)/)[1].split(",").invoke("strip"); + var names = this.toString().match(/^[\s\(]*function[^(]*\(([^\)]*)\)/)[1] + .replace(/\s+/g, '').split(','); return names.length == 1 && !names[0] ? [] : names; }, @@ -232,6 +237,11 @@ Object.extend(Function.prototype, { }, timeout); }, + defer: function() { + var args = [0.01].concat($A(arguments)); + return this.delay.apply(this, args); + }, + wrap: function(wrapper) { var __method = this; return function() { @@ -248,8 +258,6 @@ Object.extend(Function.prototype, { } }); -Function.prototype.defer = Function.prototype.delay.curry(0.01); - Date.prototype.toJSON = function() { return '"' + this.getUTCFullYear() + '-' + (this.getUTCMonth() + 1).toPaddedString(2) + '-' + @@ -530,7 +538,7 @@ if (Prototype.Browser.WebKit || Prototype.Browser.IE) Object.extend(String.proto return this.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>'); }, unescapeHTML: function() { - return this.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>'); + return this.stripTags().replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>'); } }); @@ -547,7 +555,7 @@ Object.extend(String.prototype.escapeHTML, { text: document.createTextNode('') }); -with (String.prototype.escapeHTML) div.appendChild(text); +String.prototype.escapeHTML.div.appendChild(String.prototype.escapeHTML.text); var Template = Class.create({ initialize: function(template, pattern) { @@ -589,10 +597,9 @@ var $break = { }; var Enumerable = { each: function(iterator, context) { var index = 0; - iterator = iterator.bind(context); try { this._each(function(value) { - iterator(value, index++); + iterator.call(context, value, index++); }); } catch (e) { if (e != $break) throw e; @@ -601,47 +608,46 @@ var Enumerable = { }, eachSlice: function(number, iterator, context) { - iterator = iterator ? iterator.bind(context) : Prototype.K; var index = -number, slices = [], array = this.toArray(); + if (number < 1) return array; while ((index += number) < array.length) slices.push(array.slice(index, index+number)); return slices.collect(iterator, context); }, all: function(iterator, context) { - iterator = iterator ? iterator.bind(context) : Prototype.K; + iterator = iterator || Prototype.K; var result = true; this.each(function(value, index) { - result = result && !!iterator(value, index); + result = result && !!iterator.call(context, value, index); if (!result) throw $break; }); return result; }, any: function(iterator, context) { - iterator = iterator ? iterator.bind(context) : Prototype.K; + iterator = iterator || Prototype.K; var result = false; this.each(function(value, index) { - if (result = !!iterator(value, index)) + if (result = !!iterator.call(context, value, index)) throw $break; }); return result; }, collect: function(iterator, context) { - iterator = iterator ? iterator.bind(context) : Prototype.K; + iterator = iterator || Prototype.K; var results = []; this.each(function(value, index) { - results.push(iterator(value, index)); + results.push(iterator.call(context, value, index)); }); return results; }, detect: function(iterator, context) { - iterator = iterator.bind(context); var result; this.each(function(value, index) { - if (iterator(value, index)) { + if (iterator.call(context, value, index)) { result = value; throw $break; } @@ -650,17 +656,16 @@ var Enumerable = { }, findAll: function(iterator, context) { - iterator = iterator.bind(context); var results = []; this.each(function(value, index) { - if (iterator(value, index)) + if (iterator.call(context, value, index)) results.push(value); }); return results; }, grep: function(filter, iterator, context) { - iterator = iterator ? iterator.bind(context) : Prototype.K; + iterator = iterator || Prototype.K; var results = []; if (Object.isString(filter)) @@ -668,7 +673,7 @@ var Enumerable = { this.each(function(value, index) { if (filter.match(value)) - results.push(iterator(value, index)); + results.push(iterator.call(context, value, index)); }); return results; }, @@ -696,9 +701,8 @@ var Enumerable = { }, inject: function(memo, iterator, context) { - iterator = iterator.bind(context); this.each(function(value, index) { - memo = iterator(memo, value, index); + memo = iterator.call(context, memo, value, index); }); return memo; }, @@ -711,10 +715,10 @@ var Enumerable = { }, max: function(iterator, context) { - iterator = iterator ? iterator.bind(context) : Prototype.K; + iterator = iterator || Prototype.K; var result; this.each(function(value, index) { - value = iterator(value, index); + value = iterator.call(context, value, index); if (result == null || value >= result) result = value; }); @@ -722,10 +726,10 @@ var Enumerable = { }, min: function(iterator, context) { - iterator = iterator ? iterator.bind(context) : Prototype.K; + iterator = iterator || Prototype.K; var result; this.each(function(value, index) { - value = iterator(value, index); + value = iterator.call(context, value, index); if (result == null || value < result) result = value; }); @@ -733,10 +737,10 @@ var Enumerable = { }, partition: function(iterator, context) { - iterator = iterator ? iterator.bind(context) : Prototype.K; + iterator = iterator || Prototype.K; var trues = [], falses = []; this.each(function(value, index) { - (iterator(value, index) ? + (iterator.call(context, value, index) ? trues : falses).push(value); }); return [trues, falses]; @@ -751,19 +755,20 @@ var Enumerable = { }, reject: function(iterator, context) { - iterator = iterator.bind(context); var results = []; this.each(function(value, index) { - if (!iterator(value, index)) + if (!iterator.call(context, value, index)) results.push(value); }); return results; }, sortBy: function(iterator, context) { - iterator = iterator.bind(context); return this.map(function(value, index) { - return {value: value, criteria: iterator(value, index)}; + return { + value: value, + criteria: iterator.call(context, value, index) + }; }).sort(function(left, right) { var a = left.criteria, b = right.criteria; return a < b ? -1 : a > b ? 1 : 0; @@ -815,8 +820,12 @@ function $A(iterable) { if (Prototype.Browser.WebKit) { $A = function(iterable) { if (!iterable) return []; - if (!(Object.isFunction(iterable) && iterable == '[object NodeList]') && - iterable.toArray) return iterable.toArray(); + // In Safari, only use the `toArray` method if it's not a NodeList. + // A NodeList is a function, has an function `item` property, and a numeric + // `length` property. Adapted from Google Doctype. + if (!(typeof iterable === 'function' && typeof iterable.length === + 'number' && typeof iterable.item === 'function') && iterable.toArray) + return iterable.toArray(); var length = iterable.length || 0, results = new Array(length); while (length--) results[length] = iterable[length]; return results; @@ -963,8 +972,8 @@ Object.extend(Number.prototype, { return this + 1; }, - times: function(iterator) { - $R(0, this, true).each(iterator); + times: function(iterator, context) { + $R(0, this, true).each(iterator, context); return this; }, @@ -1011,7 +1020,9 @@ var Hash = Class.create(Enumerable, (function() { }, get: function(key) { - return this._object[key]; + // simulating poorly supported hasOwnProperty + if (this._object[key] !== Object.prototype[key]) + return this._object[key]; }, unset: function(key) { @@ -1051,14 +1062,14 @@ var Hash = Class.create(Enumerable, (function() { }, toQueryString: function() { - return this.map(function(pair) { + return this.inject([], function(results, pair) { var key = encodeURIComponent(pair.key), values = pair.value; if (values && typeof values == 'object') { if (Object.isArray(values)) - return values.map(toQueryPair.curry(key)).join('&'); - } - return toQueryPair(key, values); + return results.concat(values.map(toQueryPair.curry(key))); + } else results.push(toQueryPair(key, values)); + return results; }).join('&'); }, @@ -1558,6 +1569,7 @@ if (!Node.ELEMENT_NODE) { return Element.writeAttribute(cache[tagName].cloneNode(false), attributes); }; Object.extend(this.Element, element || { }); + if (element) this.Element.prototype = element.prototype; }).call(window); Element.cache = { }; @@ -1574,12 +1586,14 @@ Element.Methods = { }, hide: function(element) { - $(element).style.display = 'none'; + element = $(element); + element.style.display = 'none'; return element; }, show: function(element) { - $(element).style.display = ''; + element = $(element); + element.style.display = ''; return element; }, @@ -1733,7 +1747,7 @@ Element.Methods = { element = $(element); if (arguments.length == 1) return element.firstDescendant(); return Object.isNumber(expression) ? element.descendants()[expression] : - element.select(expression)[index || 0]; + Element.select(element, expression)[index || 0]; }, previous: function(element, expression, index) { @@ -1863,24 +1877,16 @@ Element.Methods = { descendantOf: function(element, ancestor) { element = $(element), ancestor = $(ancestor); - var originalAncestor = ancestor; if (element.compareDocumentPosition) return (element.compareDocumentPosition(ancestor) & 8) === 8; - if (element.sourceIndex && !Prototype.Browser.Opera) { - var e = element.sourceIndex, a = ancestor.sourceIndex, - nextAncestor = ancestor.nextSibling; - if (!nextAncestor) { - do { ancestor = ancestor.parentNode; } - while (!(nextAncestor = ancestor.nextSibling) && ancestor.parentNode); - } - if (nextAncestor && nextAncestor.sourceIndex) - return (e > a && e < nextAncestor.sourceIndex); - } + if (ancestor.contains) + return ancestor.contains(element) && ancestor !== element; while (element = element.parentNode) - if (element == originalAncestor) return true; + if (element == ancestor) return true; + return false; }, @@ -1895,7 +1901,7 @@ Element.Methods = { element = $(element); style = style == 'float' ? 'cssFloat' : style.camelize(); var value = element.style[style]; - if (!value) { + if (!value || value == 'auto') { var css = document.defaultView.getComputedStyle(element, null); value = css ? css[style] : null; } @@ -1934,7 +1940,7 @@ Element.Methods = { getDimensions: function(element) { element = $(element); - var display = $(element).getStyle('display'); + var display = element.getStyle('display'); if (display != 'none' && display != null) // Safari bug return {width: element.offsetWidth, height: element.offsetHeight}; @@ -1963,7 +1969,7 @@ Element.Methods = { element.style.position = 'relative'; // Opera returns the offset relative to the positioning context, when an // element is position relative but top and left have not been defined - if (window.opera) { + if (Prototype.Browser.Opera) { element.style.top = 0; element.style.left = 0; } @@ -2018,7 +2024,7 @@ Element.Methods = { valueL += element.offsetLeft || 0; element = element.offsetParent; if (element) { - if (element.tagName == 'BODY') break; + if (element.tagName.toUpperCase() == 'BODY') break; var p = Element.getStyle(element, 'position'); if (p !== 'static') break; } @@ -2028,7 +2034,7 @@ Element.Methods = { absolutize: function(element) { element = $(element); - if (element.getStyle('position') == 'absolute') return; + if (element.getStyle('position') == 'absolute') return element; // Position.prepare(); // To be done manually by Scripty when it needs it. var offsets = element.positionedOffset(); @@ -2052,7 +2058,7 @@ Element.Methods = { relativize: function(element) { element = $(element); - if (element.getStyle('position') == 'relative') return; + if (element.getStyle('position') == 'relative') return element; // Position.prepare(); // To be done manually by Scripty when it needs it. element.style.position = 'relative'; @@ -2103,7 +2109,7 @@ Element.Methods = { element = forElement; do { - if (!Prototype.Browser.Opera || element.tagName == 'BODY') { + if (!Prototype.Browser.Opera || (element.tagName && (element.tagName.toUpperCase() == 'BODY'))) { valueT -= element.scrollTop || 0; valueL -= element.scrollLeft || 0; } @@ -2218,6 +2224,9 @@ else if (Prototype.Browser.IE) { Element.Methods.getOffsetParent = Element.Methods.getOffsetParent.wrap( function(proceed, element) { element = $(element); + // IE throws an error if element is not in document + try { element.offsetParent } + catch(e) { return $(document.body) } var position = element.getStyle('position'); if (position !== 'static') return proceed(element); element.setStyle({ position: 'relative' }); @@ -2231,6 +2240,8 @@ else if (Prototype.Browser.IE) { Element.Methods[method] = Element.Methods[method].wrap( function(proceed, element) { element = $(element); + try { element.offsetParent } + catch(e) { return Element._returnOffset(0,0) } var position = element.getStyle('position'); if (position !== 'static') return proceed(element); // Trigger hasLayout on the offset parent so that IE6 reports @@ -2246,6 +2257,14 @@ else if (Prototype.Browser.IE) { ); }); + Element.Methods.cumulativeOffset = Element.Methods.cumulativeOffset.wrap( + function(proceed, element) { + try { element.offsetParent } + catch(e) { return Element._returnOffset(0,0) } + return proceed(element); + } + ); + Element.Methods.getStyle = function(element, style) { element = $(element); style = (style == 'float' || style == 'cssFloat') ? 'styleFloat' : style.camelize(); @@ -2337,7 +2356,7 @@ else if (Prototype.Browser.IE) { Element._attributeTranslations.has = {}; $w('colSpan rowSpan vAlign dateTime accessKey tabIndex ' + - 'encType maxLength readOnly longDesc').each(function(attr) { + 'encType maxLength readOnly longDesc frameBorder').each(function(attr) { Element._attributeTranslations.write.names[attr.toLowerCase()] = attr; Element._attributeTranslations.has[attr.toLowerCase()] = attr; }); @@ -2390,7 +2409,7 @@ else if (Prototype.Browser.WebKit) { (value < 0.00001) ? 0 : value; if (value == 1) - if(element.tagName == 'IMG' && element.width) { + if(element.tagName.toUpperCase() == 'IMG' && element.width) { element.width++; element.width--; } else try { var n = document.createTextNode(' '); @@ -2521,7 +2540,7 @@ Element.Methods.Simulated = { hasAttribute: function(element, attribute) { attribute = Element._attributeTranslations.has[attribute] || attribute; var node = $(element).getAttributeNode(attribute); - return node && node.specified; + return !!(node && node.specified); } }; @@ -2530,9 +2549,9 @@ Element.Methods.ByTag = { }; Object.extend(Element, Element.Methods); if (!Prototype.BrowserFeatures.ElementExtensions && - document.createElement('div').__proto__) { + document.createElement('div')['__proto__']) { window.HTMLElement = { }; - window.HTMLElement.prototype = document.createElement('div').__proto__; + window.HTMLElement.prototype = document.createElement('div')['__proto__']; Prototype.BrowserFeatures.ElementExtensions = true; } @@ -2547,7 +2566,7 @@ Element.extend = (function() { element.nodeType != 1 || element == window) return element; var methods = Object.clone(Methods), - tagName = element.tagName, property, value; + tagName = element.tagName.toUpperCase(), property, value; // extend methods for specific tags if (ByTag[tagName]) Object.extend(methods, ByTag[tagName]); @@ -2643,7 +2662,7 @@ Element.addMethods = function(methods) { if (window[klass]) return window[klass]; window[klass] = { }; - window[klass].prototype = document.createElement(tagName).__proto__; + window[klass].prototype = document.createElement(tagName)['__proto__']; return window[klass]; } @@ -2669,12 +2688,18 @@ Element.addMethods = function(methods) { document.viewport = { getDimensions: function() { - var dimensions = { }; - var B = Prototype.Browser; + var dimensions = { }, B = Prototype.Browser; $w('width height').each(function(d) { var D = d.capitalize(); - dimensions[d] = (B.WebKit && !document.evaluate) ? self['inner' + D] : - (B.Opera) ? document.body['client' + D] : document.documentElement['client' + D]; + if (B.WebKit && !document.evaluate) { + // Safari <3.0 needs self.innerWidth/Height + dimensions[d] = self['inner' + D]; + } else if (B.Opera && parseFloat(window.opera.version()) < 9.5) { + // Opera <9.5 needs document.body.clientWidth/Height + dimensions[d] = document.body['client' + D] + } else { + dimensions[d] = document.documentElement['client' + D]; + } }); return dimensions; }, @@ -2693,14 +2718,24 @@ document.viewport = { window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop); } }; -/* Portions of the Selector class are derived from Jack Slocum’s DomQuery, +/* Portions of the Selector class are derived from Jack Slocum's DomQuery, * part of YUI-Ext version 0.40, distributed under the terms of an MIT-style * license. Please see http://www.yui-ext.com/ for more information. */ var Selector = Class.create({ initialize: function(expression) { this.expression = expression.strip(); - this.compileMatcher(); + + if (this.shouldUseSelectorsAPI()) { + this.mode = 'selectorsAPI'; + } else if (this.shouldUseXPath()) { + this.mode = 'xpath'; + this.compileXPathMatcher(); + } else { + this.mode = "normal"; + this.compileMatcher(); + } + }, shouldUseXPath: function() { @@ -2715,16 +2750,29 @@ var Selector = Class.create({ // XPath can't do namespaced attributes, nor can it read // the "checked" property from DOM nodes - if ((/(\[[\w-]*?:|:checked)/).test(this.expression)) + if ((/(\[[\w-]*?:|:checked)/).test(e)) return false; return true; }, - compileMatcher: function() { - if (this.shouldUseXPath()) - return this.compileXPathMatcher(); + shouldUseSelectorsAPI: function() { + if (!Prototype.BrowserFeatures.SelectorsAPI) return false; + + if (!Selector._div) Selector._div = new Element('div'); + + // Make sure the browser treats the selector as valid. Test on an + // isolated element to minimize cost of this check. + try { + Selector._div.querySelector(this.expression); + } catch(e) { + return false; + } + + return true; + }, + compileMatcher: function() { var e = this.expression, ps = Selector.patterns, h = Selector.handlers, c = Selector.criteria, le, p, m; @@ -2742,7 +2790,7 @@ var Selector = Class.create({ p = ps[i]; if (m = e.match(p)) { this.matcher.push(Object.isFunction(c[i]) ? c[i](m) : - new Template(c[i]).evaluate(m)); + new Template(c[i]).evaluate(m)); e = e.replace(m[0], ''); break; } @@ -2781,8 +2829,27 @@ var Selector = Class.create({ findElements: function(root) { root = root || document; - if (this.xpath) return document._getElementsByXPath(this.xpath, root); - return this.matcher(root); + var e = this.expression, results; + + switch (this.mode) { + case 'selectorsAPI': + // querySelectorAll queries document-wide, then filters to descendants + // of the context element. That's not what we want. + // Add an explicit context to the selector if necessary. + if (root !== document) { + var oldId = root.id, id = $(root).identify(); + e = "#" + id + " " + e; + } + + results = $A(root.querySelectorAll(e)).map(Element.extend); + root.id = oldId; + + return results; + case 'xpath': + return document._getElementsByXPath(this.xpath, root); + default: + return this.matcher(root); + } }, match: function(element) { @@ -2873,10 +2940,10 @@ Object.extend(Selector, { 'first-child': '[not(preceding-sibling::*)]', 'last-child': '[not(following-sibling::*)]', 'only-child': '[not(preceding-sibling::* or following-sibling::*)]', - 'empty': "[count(*) = 0 and (count(text()) = 0 or translate(text(), ' \t\r\n', '') = '')]", + 'empty': "[count(*) = 0 and (count(text()) = 0)]", 'checked': "[@checked]", - 'disabled': "[@disabled]", - 'enabled': "[not(@disabled)]", + 'disabled': "[(@disabled) and (@type!='hidden')]", + 'enabled': "[not(@disabled) and (@type!='hidden')]", 'not': function(m) { var e = m[6], p = Selector.patterns, x = Selector.xpath, le, v; @@ -2968,7 +3035,7 @@ Object.extend(Selector, { className: /^\.([\w\-\*]+)(\b|$)/, pseudo: /^:((first|last|nth|nth-last|only)(-child|-of-type)|empty|checked|(en|dis)abled|not)(\((.*?)\))?(\b|$|(?=\s|[:+~>]))/, - attrPresence: /^\[([\w]+)\]/, + attrPresence: /^\[((?:[\w]+:)?[\w]+)\]/, attr: /\[((?:[\w-]*:)?[\w-]+)\s*(?:([!^$*~|]?=)\s*((['"])([^\4]*?)\4|([^'"][^\]]*?)))?\]/ }, @@ -3081,7 +3148,7 @@ Object.extend(Selector, { nextElementSibling: function(node) { while (node = node.nextSibling) - if (node.nodeType == 1) return node; + if (node.nodeType == 1) return node; return null; }, @@ -3270,7 +3337,7 @@ Object.extend(Selector, { 'empty': function(nodes, value, root) { for (var i = 0, results = [], node; node = nodes[i]; i++) { // IE treats comments as element nodes - if (node.tagName == '!' || (node.firstChild && !node.innerHTML.match(/^\s*$/))) continue; + if (node.tagName == '!' || node.firstChild) continue; results.push(node); } return results; @@ -3288,7 +3355,8 @@ Object.extend(Selector, { 'enabled': function(nodes, value, root) { for (var i = 0, results = [], node; node = nodes[i]; i++) - if (!node.disabled) results.push(node); + if (!node.disabled && (!node.type || node.type !== 'hidden')) + results.push(node); return results; }, @@ -3308,11 +3376,14 @@ Object.extend(Selector, { operators: { '=': function(nv, v) { return nv == v; }, '!=': function(nv, v) { return nv != v; }, - '^=': function(nv, v) { return nv.startsWith(v); }, + '^=': function(nv, v) { return nv == v || nv && nv.startsWith(v); }, + '$=': function(nv, v) { return nv == v || nv && nv.endsWith(v); }, + '*=': function(nv, v) { return nv == v || nv && nv.include(v); }, '$=': function(nv, v) { return nv.endsWith(v); }, '*=': function(nv, v) { return nv.include(v); }, '~=': function(nv, v) { return (' ' + nv + ' ').include(' ' + v + ' '); }, - '|=': function(nv, v) { return ('-' + nv.toUpperCase() + '-').include('-' + v.toUpperCase() + '-'); } + '|=': function(nv, v) { return ('-' + (nv || "").toUpperCase() + + '-').include('-' + (v || "").toUpperCase() + '-'); } }, split: function(expression) { @@ -3386,7 +3457,7 @@ var Form = { var data = elements.inject({ }, function(result, element) { if (!element.disabled && element.name) { key = element.name; value = $(element).getValue(); - if (value != null && (element.type != 'submit' || (!submitted && + if (value != null && element.type != 'file' && (element.type != 'submit' || (!submitted && submit !== false && (!submit || key == submit) && (submitted = true)))) { if (key in result) { // a key is already present; construct an array of values @@ -3547,7 +3618,6 @@ Form.Element.Methods = { disable: function(element) { element = $(element); - element.blur(); element.disabled = true; return element; }, @@ -3587,22 +3657,22 @@ Form.Element.Serializers = { else element.value = value; }, - select: function(element, index) { - if (Object.isUndefined(index)) + select: function(element, value) { + if (Object.isUndefined(value)) return this[element.type == 'select-one' ? 'selectOne' : 'selectMany'](element); else { - var opt, value, single = !Object.isArray(index); + var opt, currentValue, single = !Object.isArray(value); for (var i = 0, length = element.length; i < length; i++) { opt = element.options[i]; - value = this.optionValue(opt); + currentValue = this.optionValue(opt); if (single) { - if (value == index) { + if (currentValue == value) { opt.selected = true; return; } } - else opt.selected = index.include(value); + else opt.selected = value.include(currentValue); } } }, @@ -3773,8 +3843,23 @@ Event.Methods = (function() { isRightClick: function(event) { return isButton(event, 2) }, element: function(event) { - var node = Event.extend(event).target; - return Element.extend(node.nodeType == Node.TEXT_NODE ? node.parentNode : node); + event = Event.extend(event); + + var node = event.target, + type = event.type, + currentTarget = event.currentTarget; + + if (currentTarget && currentTarget.tagName) { + // Firefox screws up the "click" event when moving between radio buttons + // via arrow keys. It also screws up the "load" and "error" events on images, + // reporting the document as the target instead of the original image. + if (type === 'load' || type === 'error' || + (type === 'click' && currentTarget.tagName.toLowerCase() === 'input' + && currentTarget.type === 'radio')) + node = currentTarget; + } + if (node.nodeType == Node.TEXT_NODE) node = node.parentNode; + return Element.extend(node); }, findElement: function(event, expression) { @@ -3785,11 +3870,15 @@ Event.Methods = (function() { }, pointer: function(event) { + var docElement = document.documentElement, + body = document.body || { scrollLeft: 0, scrollTop: 0 }; return { x: event.pageX || (event.clientX + - (document.documentElement.scrollLeft || document.body.scrollLeft)), + (docElement.scrollLeft || body.scrollLeft) - + (docElement.clientLeft || 0)), y: event.pageY || (event.clientY + - (document.documentElement.scrollTop || document.body.scrollTop)) + (docElement.scrollTop || body.scrollTop) - + (docElement.clientTop || 0)) }; }, @@ -3834,7 +3923,7 @@ Event.extend = (function() { }; } else { - Event.prototype = Event.prototype || document.createEvent("HTMLEvents").__proto__; + Event.prototype = Event.prototype || document.createEvent("HTMLEvents")['__proto__']; Object.extend(Event.prototype, methods); return Prototype.K; } @@ -3899,10 +3988,20 @@ Object.extend(Event, (function() { cache[id][eventName] = null; } + + // Internet Explorer needs to remove event handlers on page unload + // in order to avoid memory leaks. if (window.attachEvent) { window.attachEvent("onunload", destroyCache); } + // Safari has a dummy event handler on page unload so that it won't + // use its bfcache. Safari <= 3.1 has an issue with restoring the "document" + // object when page is returned to via the back button using its bfcache. + if (Prototype.Browser.WebKit) { + window.addEventListener('unload', Prototype.emptyFunction, false); + } + return { observe: function(element, eventName, handler) { element = $(element); diff --git a/railties/lib/initializer.rb b/railties/lib/initializer.rb index 6500b2d309..e3a0e3bad1 100644 --- a/railties/lib/initializer.rb +++ b/railties/lib/initializer.rb @@ -267,6 +267,7 @@ module Rails end def add_gem_load_paths + Rails::GemDependency.add_frozen_gem_path unless @configuration.gems.empty? require "rubygems" @configuration.gems.each { |gem| gem.add_load_paths } diff --git a/railties/lib/rails/gem_dependency.rb b/railties/lib/rails/gem_dependency.rb index 46d5fd3a47..cd280ac023 100644 --- a/railties/lib/rails/gem_dependency.rb +++ b/railties/lib/rails/gem_dependency.rb @@ -18,11 +18,14 @@ module Rails def self.add_frozen_gem_path @@paths_loaded ||= begin - Gem.source_index = Rails::VendorGemSourceIndex.new(Gem.source_index) + source_index = Rails::VendorGemSourceIndex.new(Gem.source_index) + Gem.clear_paths + Gem.source_index = source_index # loaded before us - we can't change them, so mark them Gem.loaded_specs.each do |name, spec| @@framework_gems[name] = spec end + true end end @@ -170,19 +173,27 @@ module Rails exact_dep = Gem::Dependency.new(name, "= #{specification.version}") matches = real_gems.search(exact_dep) installed_spec = matches.first - if installed_spec - # we have a real copy - # get a fresh spec - matches should only have one element - # note that there is no reliable method to check that the loaded - # spec is the same as the copy from real_gems - Gem.activate changes - # some of the fields - real_spec = Gem::Specification.load(matches.first.loaded_from) - write_spec(directory, real_spec) - puts "Reloaded specification for #{name} from installed gems." + if File.exist?(File.dirname(spec_filename(directory))) + if installed_spec + # we have a real copy + # get a fresh spec - matches should only have one element + # note that there is no reliable method to check that the loaded + # spec is the same as the copy from real_gems - Gem.activate changes + # some of the fields + real_spec = Gem::Specification.load(matches.first.loaded_from) + write_spec(directory, real_spec) + puts "Reloaded specification for #{name} from installed gems." + else + # the gem isn't installed locally - write out our current specs + write_spec(directory, specification) + puts "Gem #{name} not loaded locally - writing out current spec." + end else - # the gem isn't installed locally - write out our current specs - write_spec(directory, specification) - puts "Gem #{name} not loaded locally - writing out current spec." + if framework_gem? + puts "Gem directory for #{name} not found - check if it's loading before rails." + else + puts "Something bad is going on - gem directory not found for #{name}." + end end end diff --git a/railties/lib/rails_generator/generators/components/plugin/plugin_generator.rb b/railties/lib/rails_generator/generators/components/plugin/plugin_generator.rb index 615c575e6e..6826998252 100644 --- a/railties/lib/rails_generator/generators/components/plugin/plugin_generator.rb +++ b/railties/lib/rails_generator/generators/components/plugin/plugin_generator.rb @@ -16,16 +16,16 @@ class PluginGenerator < Rails::Generator::NamedBase m.directory "#{plugin_path}/tasks" m.directory "#{plugin_path}/test" - m.template 'README', "#{plugin_path}/README" - m.template 'MIT-LICENSE', "#{plugin_path}/MIT-LICENSE" - m.template 'Rakefile', "#{plugin_path}/Rakefile" - m.template 'init.rb', "#{plugin_path}/init.rb" - m.template 'install.rb', "#{plugin_path}/install.rb" - m.template 'uninstall.rb', "#{plugin_path}/uninstall.rb" - m.template 'plugin.rb', "#{plugin_path}/lib/#{file_name}.rb" - m.template 'tasks.rake', "#{plugin_path}/tasks/#{file_name}_tasks.rake" - m.template 'unit_test.rb', "#{plugin_path}/test/#{file_name}_test.rb" - + m.template 'README', "#{plugin_path}/README" + m.template 'MIT-LICENSE', "#{plugin_path}/MIT-LICENSE" + m.template 'Rakefile', "#{plugin_path}/Rakefile" + m.template 'init.rb', "#{plugin_path}/init.rb" + m.template 'install.rb', "#{plugin_path}/install.rb" + m.template 'uninstall.rb', "#{plugin_path}/uninstall.rb" + m.template 'plugin.rb', "#{plugin_path}/lib/#{file_name}.rb" + m.template 'tasks.rake', "#{plugin_path}/tasks/#{file_name}_tasks.rake" + m.template 'unit_test.rb', "#{plugin_path}/test/#{file_name}_test.rb" + m.template 'test_helper.rb', "#{plugin_path}/test/test_helper.rb" if @with_generator m.directory "#{plugin_path}/generators" m.directory "#{plugin_path}/generators/#{file_name}" diff --git a/railties/lib/rails_generator/generators/components/plugin/templates/Rakefile b/railties/lib/rails_generator/generators/components/plugin/templates/Rakefile index 1824fb10fe..85e8ff1834 100644 --- a/railties/lib/rails_generator/generators/components/plugin/templates/Rakefile +++ b/railties/lib/rails_generator/generators/components/plugin/templates/Rakefile @@ -8,6 +8,7 @@ task :default => :test desc 'Test the <%= file_name %> plugin.' Rake::TestTask.new(:test) do |t| t.libs << 'lib' + t.libs << 'test' t.pattern = 'test/**/*_test.rb' t.verbose = true end diff --git a/railties/lib/rails_generator/generators/components/plugin/templates/test_helper.rb b/railties/lib/rails_generator/generators/components/plugin/templates/test_helper.rb new file mode 100644 index 0000000000..cf148b8b47 --- /dev/null +++ b/railties/lib/rails_generator/generators/components/plugin/templates/test_helper.rb @@ -0,0 +1,3 @@ +require 'rubygems' +require 'active_support' +require 'active_support/test_case'
\ No newline at end of file diff --git a/railties/lib/rails_generator/generators/components/plugin/templates/unit_test.rb b/railties/lib/rails_generator/generators/components/plugin/templates/unit_test.rb index 6ede6ef1d2..3e0bc29d3a 100644 --- a/railties/lib/rails_generator/generators/components/plugin/templates/unit_test.rb +++ b/railties/lib/rails_generator/generators/components/plugin/templates/unit_test.rb @@ -1,6 +1,6 @@ -require 'test/unit' +require 'test_helper' -class <%= class_name %>Test < Test::Unit::TestCase +class <%= class_name %>Test < ActiveSupport::TestCase # Replace this with your real tests. test "the truth" do assert true diff --git a/railties/lib/tasks/gems.rake b/railties/lib/tasks/gems.rake index e2cb4b9577..754e3ba5c9 100644 --- a/railties/lib/tasks/gems.rake +++ b/railties/lib/tasks/gems.rake @@ -6,10 +6,11 @@ task :gems => 'gems:base' do puts puts "I = Installed" puts "F = Frozen" + puts "R = Framework (loaded before rails starts)" end def print_gem_status(gem, indent=1) - code = gem.loaded? ? (gem.frozen? ? "F" : "I") : " " + code = gem.loaded? ? (gem.frozen? ? (gem.framework_gem? ? "R" : "F") : "I") : " " puts " "*(indent-1)+" - [#{code}] #{gem.name} #{gem.requirement.to_s}" gem.dependencies.each { |g| print_gem_status(g, indent+1)} if gem.loaded? end diff --git a/railties/test/gem_dependency_test.rb b/railties/test/gem_dependency_test.rb index 5f026b2616..4f9e824c9f 100644 --- a/railties/test/gem_dependency_test.rb +++ b/railties/test/gem_dependency_test.rb @@ -1,12 +1,11 @@ -require 'lib/rails/vendor_gem_source_index' -Rails::VendorGemSourceIndex.silence_spec_warnings = true - require 'plugin_test_helper' class Rails::GemDependency public :install_command, :unpack_command end +Rails::VendorGemSourceIndex.silence_spec_warnings = true + uses_mocha "Plugin Tests" do class GemDependencyTest < Test::Unit::TestCase def setup |