Skip to content

Commit

Permalink
Moving boot.rb around and adding named scope libs to test 1.2.6 rails…
Browse files Browse the repository at this point in the history
…. Also added ignore for local should to use 4.1 which can use active support in 1.2.6 when tested.
  • Loading branch information
metaskills committed Sep 26, 2008
1 parent 09629a4 commit 7b35b66
Show file tree
Hide file tree
Showing 5 changed files with 172 additions and 4 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
.DS_Store
test/debug.log
autotest
test/lib/shoulda*
autotest
3 changes: 1 addition & 2 deletions test/helper.rb
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
require File.join(File.dirname(__FILE__),'lib/boot') unless defined?(ActiveRecord)
require 'test/unit'
require 'rubygems'
require 'shoulda'
require 'quietbacktrace'
require 'mocha'
require File.join(File.dirname(__FILE__),'lib/boot') unless defined?(ActiveRecord)
require 'factory_girl'
require 'lib/test_case'
require 'grouped_scope'
Expand Down
13 changes: 12 additions & 1 deletion test/lib/boot.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
require 'rubygems'

plugin_root = File.expand_path(File.join(File.dirname(__FILE__),'..'))
framework_root = ["#{plugin_root}/rails", "#{plugin_root}/../../rails"].detect { |p| File.directory? p }
Expand All @@ -21,6 +22,16 @@
end
end

require 'activerecord'
require 'active_record'
require 'active_support'

def enable_named_scope
return if defined? ActiveRecord::NamedScope
require 'named_scope'
require 'named_scope_patch'
ActiveRecord::Base.class_eval do
include GroupedScope::NamedScope
end
end

enable_named_scope
132 changes: 132 additions & 0 deletions test/lib/named_scope.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
## stolen from: http://dev.rubyonrails.org/browser/trunk/activerecord/lib/active_record/named_scope.rb?rev=9084

module GroupedScope
# This is a feature backported from Rails 2.1 because of its usefullness not only with will_paginate,
# but in other aspects when managing complex conditions that you want to be reusable.
module NamedScope
# All subclasses of ActiveRecord::Base have two named_scopes:
# * <tt>all</tt>, which is similar to a <tt>find(:all)</tt> query, and
# * <tt>scoped</tt>, which allows for the creation of anonymous scopes, on the fly:
#
# Shirt.scoped(:conditions => {:color => 'red'}).scoped(:include => :washing_instructions)
#
# These anonymous scopes tend to be useful when procedurally generating complex queries, where passing
# intermediate values (scopes) around as first-class objects is convenient.
def self.included(base)
base.class_eval do
extend ClassMethods
named_scope :all
named_scope :scoped, lambda { |scope| scope }
end
end

module ClassMethods
def scopes #:nodoc:
read_inheritable_attribute(:scopes) || write_inheritable_attribute(:scopes, {})
end

# Adds a class method for retrieving and querying objects. A scope represents a narrowing of a database query,
# such as <tt>:conditions => {:color => :red}, :select => 'shirts.*', :include => :washing_instructions</tt>.
#
# class Shirt < ActiveRecord::Base
# named_scope :red, :conditions => {:color => 'red'}
# named_scope :dry_clean_only, :joins => :washing_instructions, :conditions => ['washing_instructions.dry_clean_only = ?', true]
# end
#
# The above calls to <tt>named_scope</tt> define class methods <tt>Shirt.red</tt> and <tt>Shirt.dry_clean_only</tt>. <tt>Shirt.red</tt>,
# in effect, represents the query <tt>Shirt.find(:all, :conditions => {:color => 'red'})</tt>.
#
# Unlike Shirt.find(...), however, the object returned by <tt>Shirt.red</tt> is not an Array; it resembles the association object
# constructed by a <tt>has_many</tt> declaration. For instance, you can invoke <tt>Shirt.red.find(:first)</tt>, <tt>Shirt.red.count</tt>,
# <tt>Shirt.red.find(:all, :conditions => {:size => 'small'})</tt>. Also, just
# as with the association objects, name scopes acts like an Array, implementing Enumerable; <tt>Shirt.red.each(&block)</tt>,
# <tt>Shirt.red.first</tt>, and <tt>Shirt.red.inject(memo, &block)</tt> all behave as if Shirt.red really were an Array.
#
# These named scopes are composable. For instance, <tt>Shirt.red.dry_clean_only</tt> will produce all shirts that are both red and dry clean only.
# Nested finds and calculations also work with these compositions: <tt>Shirt.red.dry_clean_only.count</tt> returns the number of garments
# for which these criteria obtain. Similarly with <tt>Shirt.red.dry_clean_only.average(:thread_count)</tt>.
#
# All scopes are available as class methods on the ActiveRecord descendent upon which the scopes were defined. But they are also available to
# <tt>has_many</tt> associations. If,
#
# class Person < ActiveRecord::Base
# has_many :shirts
# end
#
# then <tt>elton.shirts.red.dry_clean_only</tt> will return all of Elton's red, dry clean
# only shirts.
#
# Named scopes can also be procedural.
#
# class Shirt < ActiveRecord::Base
# named_scope :colored, lambda { |color|
# { :conditions => { :color => color } }
# }
# end
#
# In this example, <tt>Shirt.colored('puce')</tt> finds all puce shirts.
#
# Named scopes can also have extensions, just as with <tt>has_many</tt> declarations:
#
# class Shirt < ActiveRecord::Base
# named_scope :red, :conditions => {:color => 'red'} do
# def dom_id
# 'red_shirts'
# end
# end
# end
#
def named_scope(name, options = {}, &block)
scopes[name] = lambda do |parent_scope, *args|
Scope.new(parent_scope, case options
when Hash
options
when Proc
options.call(*args)
end, &block)
end
(class << self; self end).instance_eval do
define_method name do |*args|
scopes[name].call(self, *args)
end
end
end
end

class Scope #:nodoc:
attr_reader :proxy_scope, :proxy_options
[].methods.each { |m| delegate m, :to => :proxy_found unless m =~ /(^__|^nil\?|^send|class|extend|find|count|sum|average|maximum|minimum|paginate)/ }
delegate :scopes, :with_scope, :to => :proxy_scope

def initialize(proxy_scope, options, &block)
[options[:extend]].flatten.each { |extension| extend extension } if options[:extend]
extend Module.new(&block) if block_given?
@proxy_scope, @proxy_options = proxy_scope, options.except(:extend)
end

def reload
load_found; self
end

protected
def proxy_found
@found || load_found
end

private
def method_missing(method, *args, &block)
if scopes.include?(method)
scopes[method].call(self, *args)
else
with_scope :find => proxy_options do
proxy_scope.send(method, *args, &block)
end
end
end

def load_found
@found = find(:all)
end
end
end
end
25 changes: 25 additions & 0 deletions test/lib/named_scope_patch.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
## based on http://dev.rubyonrails.org/changeset/9084

ActiveRecord::Associations::AssociationProxy.class_eval do
protected
def with_scope(*args, &block)
@reflection.klass.send :with_scope, *args, &block
end
end


# Rails 1.2.6
ActiveRecord::Associations::HasAndBelongsToManyAssociation.class_eval do
protected
def method_missing(method, *args, &block)
if @target.respond_to?(method) || (!@reflection.klass.respond_to?(method) && Class.respond_to?(method))
super
elsif @reflection.klass.scopes.include?(method)
@reflection.klass.scopes[method].call(self, *args)
else
@reflection.klass.with_scope(:find => { :conditions => @finder_sql, :joins => @join_sql, :readonly => false }) do
@reflection.klass.send(method, *args, &block)
end
end
end
end if ActiveRecord::Base.respond_to? :find_first

0 comments on commit 7b35b66

Please sign in to comment.