ambitious-activerecord 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,21 @@
1
+ lib/ambition/adapters/active_record/base.rb
2
+ lib/ambition/adapters/active_record/query.rb
3
+ lib/ambition/adapters/active_record/select.rb
4
+ lib/ambition/adapters/active_record/slice.rb
5
+ lib/ambition/adapters/active_record/sort.rb
6
+ lib/ambition/adapters/active_record/statements.rb
7
+ lib/ambition/adapters/active_record.rb
8
+ test/benchmark.rb
9
+ test/chaining_test.rb
10
+ test/count_test.rb
11
+ test/enumerable_test.rb
12
+ test/helper.rb
13
+ test/join_test.rb
14
+ test/profiler.rb
15
+ test/ruby_test.rb
16
+ test/select_test.rb
17
+ test/slice_test.rb
18
+ test/sort_test.rb
19
+ test/source_test.rb
20
+ test/types_test.rb
21
+ Manifest
@@ -0,0 +1,55 @@
1
+
2
+ # Gem::Specification for Ambitious-activerecord-0.1.0
3
+ # Originally generated by Echoe
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = %q{ambitious-activerecord}
7
+ s.version = "0.1.0"
8
+ s.date = %q{2008-01-29}
9
+ s.summary = %q{An ambitious adapter for ActiveRecord}
10
+ s.email = %q{chris@ozmm.org}
11
+ s.homepage = %q{http://ambition.rubyforge.org/}
12
+ s.rubyforge_project = %q{ambition}
13
+ s.description = %q{An ambitious adapter for ActiveRecord}
14
+ s.has_rdoc = true
15
+ s.authors = ["Chris Wanstrath"]
16
+ s.files = ["lib/ambition/adapters/active_record/base.rb", "lib/ambition/adapters/active_record/query.rb", "lib/ambition/adapters/active_record/select.rb", "lib/ambition/adapters/active_record/slice.rb", "lib/ambition/adapters/active_record/sort.rb", "lib/ambition/adapters/active_record/statements.rb", "lib/ambition/adapters/active_record.rb", "test/benchmark.rb", "test/chaining_test.rb", "test/count_test.rb", "test/enumerable_test.rb", "test/helper.rb", "test/join_test.rb", "test/profiler.rb", "test/ruby_test.rb", "test/select_test.rb", "test/slice_test.rb", "test/sort_test.rb", "test/source_test.rb", "test/types_test.rb", "Manifest", "ambitious-activerecord.gemspec"]
17
+ s.test_files = ["test/chaining_test.rb", "test/count_test.rb", "test/enumerable_test.rb", "test/join_test.rb", "test/ruby_test.rb", "test/select_test.rb", "test/slice_test.rb", "test/sort_test.rb", "test/source_test.rb", "test/types_test.rb"]
18
+ s.add_dependency(%q<activerecord>, [">= 1.15.0"])
19
+ s.add_dependency(%q<ambition>, [">= 0.5.0"])
20
+ end
21
+
22
+
23
+ # # Original Rakefile source (requires the Echoe gem):
24
+ #
25
+ # require 'rake'
26
+ #
27
+ # Version = '0.1.0'
28
+ #
29
+ # begin
30
+ # require 'rubygems'
31
+ # gem 'echoe', '>=2.7'
32
+ # ENV['RUBY_FLAGS'] = ""
33
+ # require 'echoe'
34
+ #
35
+ # Echoe.new('ambitious-activerecord') do |p|
36
+ # p.dependencies << 'activerecord >=1.15.0'
37
+ # p.summary = "An ambitious adapter for ActiveRecord"
38
+ # p.author = 'Chris Wanstrath'
39
+ # p.email = "chris@ozmm.org"
40
+ #
41
+ # p.project = 'ambition'
42
+ # p.url = "http://ambition.rubyforge.org/"
43
+ # p.test_pattern = 'test/*_test.rb'
44
+ # p.version = Version
45
+ # p.dependencies << 'ambition >=0.5.0'
46
+ # end
47
+ #
48
+ # rescue LoadError
49
+ # puts "Not doing any of the Echoe gemmy stuff, because you don't have the specified gem versions"
50
+ # end
51
+ #
52
+ # desc 'Install as a gem'
53
+ # task :install_gem do
54
+ # puts `rake manifest package && gem install pkg/ambitious-activerecord-#{Version}.gem`
55
+ # end
@@ -0,0 +1,11 @@
1
+ require 'ambition'
2
+ require 'active_record'
3
+ require 'ambition/adapters/active_record/query'
4
+ require 'ambition/adapters/active_record/base'
5
+ require 'ambition/adapters/active_record/select'
6
+ require 'ambition/adapters/active_record/sort'
7
+ require 'ambition/adapters/active_record/slice'
8
+ require 'ambition/adapters/active_record/statements'
9
+
10
+ ActiveRecord::Base.extend Ambition::API
11
+ ActiveRecord::Base.ambition_adapter = Ambition::Adapters::ActiveRecord
@@ -0,0 +1,57 @@
1
+ require 'active_record/connection_adapters/abstract/quoting'
2
+
3
+ module Ambition
4
+ module Adapters
5
+ module ActiveRecord
6
+ class Base
7
+ include ::ActiveRecord::ConnectionAdapters::Quoting
8
+
9
+ def sanitize(value)
10
+ if value.is_a? Array
11
+ return value.map { |v| sanitize(v) }.join(', ')
12
+ end
13
+
14
+ case value
15
+ when true, 'true'
16
+ '1'
17
+ when false, 'false'
18
+ '0'
19
+ when Regexp
20
+ "'#{value.source}'"
21
+ else
22
+ if active_connection?
23
+ ::ActiveRecord::Base.connection.quote(value)
24
+ else
25
+ quote(value)
26
+ end
27
+ end
28
+ rescue
29
+ "'#{value}'"
30
+ end
31
+
32
+ def quote_column_name(value)
33
+ if active_connection?
34
+ ::ActiveRecord::Base.connection.quote_column_name(value)
35
+ else
36
+ value.to_s
37
+ end
38
+ end
39
+
40
+ def active_connection?
41
+ ::ActiveRecord::Base.active_connection_name
42
+ end
43
+
44
+ def dbadapter_name
45
+ ::ActiveRecord::Base.connection.adapter_name
46
+ rescue ::ActiveRecord::ConnectionNotEstablished
47
+ 'Abstract'
48
+ end
49
+
50
+ def statement(*args)
51
+ @statement_instance ||= DatabaseStatements.const_get(dbadapter_name).new
52
+ @statement_instance.send(*args)
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,56 @@
1
+ module Ambition
2
+ module Adapters
3
+ module ActiveRecord
4
+ class Query
5
+ @@select = 'SELECT * FROM %s %s'
6
+
7
+ def kick
8
+ owner.find(:all, to_hash)
9
+ end
10
+
11
+ def size
12
+ owner.count(to_hash)
13
+ end
14
+
15
+ def to_hash
16
+ hash = {}
17
+
18
+ unless (where = clauses[:select]).blank?
19
+ hash[:conditions] = Array(where)
20
+ hash[:conditions] *= ' AND '
21
+ end
22
+
23
+ if order = clauses[:sort]
24
+ hash[:order] = order.join(', ')
25
+ end
26
+
27
+ if clauses[:slice].last =~ /LIMIT (\d+)/
28
+ hash[:limit] = $1.to_i
29
+ end
30
+
31
+ if clauses[:slice].last =~ /OFFSET (\d+)/
32
+ hash[:offset] = $1.to_i
33
+ end
34
+
35
+ hash[:include] = stash[:include] if stash[:include]
36
+
37
+ hash
38
+ end
39
+
40
+ def to_s
41
+ hash = to_hash
42
+
43
+ raise "Sorry, I can't construct SQL with complex joins (yet)" unless hash[:include].blank?
44
+
45
+ sql = []
46
+ sql << "WHERE #{hash[:conditions]}" unless hash[:conditions].blank?
47
+ sql << "ORDER BY #{hash[:order]}" unless hash[:order].blank?
48
+ sql << clauses[:slice].last unless hash[:slice].blank?
49
+
50
+ @@select % [ owner.table_name, sql.join(' ') ]
51
+ end
52
+ alias_method :to_sql, :to_s
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,94 @@
1
+ module Ambition
2
+ module Adapters
3
+ module ActiveRecord
4
+ class Select < Base
5
+ def call(method)
6
+ "#{owner.table_name}.#{quote_column_name method}"
7
+ end
8
+
9
+ def chained_call(*methods)
10
+ if reflection = owner.reflections[methods.first]
11
+ stash[:include] ||= []
12
+ stash[:include] << methods.first
13
+ "#{reflection.table_name}.#{quote_column_name methods.last}"
14
+ elsif respond_to? methods[1]
15
+ send(methods[1], methods.first)
16
+ else
17
+ raise "I don't understand: #{methods.inspect}"
18
+ end
19
+ end
20
+
21
+ def both(left, right)
22
+ "(#{left} AND #{right})"
23
+ end
24
+
25
+ def either(left, right)
26
+ "(#{left} OR #{right})"
27
+ end
28
+
29
+ def ==(left, right)
30
+ if right.nil?
31
+ "#{left} IS NULL"
32
+ else
33
+ "#{left} = #{sanitize right}"
34
+ end
35
+ end
36
+
37
+ # !=
38
+ def not_equal(left, right)
39
+ if right.nil?
40
+ "#{left} IS NOT NULL"
41
+ else
42
+ "#{left} <> #{sanitize right}"
43
+ end
44
+ end
45
+
46
+ def =~(left, right)
47
+ if right.is_a? Regexp
48
+ "#{left} #{statement(:regexp, right)} #{sanitize right}"
49
+ else
50
+ "#{left} LIKE #{sanitize right}"
51
+ end
52
+ end
53
+
54
+ # !~
55
+ def not_regexp(left, right)
56
+ if right.is_a? Regexp
57
+ "#{left} #{statement(:not_regexp, right)} #{sanitize right}"
58
+ else
59
+ "#{left} NOT LIKE #{sanitize right}"
60
+ end
61
+ end
62
+
63
+ def <(left, right)
64
+ "#{left} < #{sanitize right}"
65
+ end
66
+
67
+ def >(left, right)
68
+ "#{left} > #{sanitize right}"
69
+ end
70
+
71
+ def >=(left, right)
72
+ "#{left} >= #{sanitize right}"
73
+ end
74
+
75
+ def <=(left, right)
76
+ "#{left} <= #{sanitize right}"
77
+ end
78
+
79
+ def include?(left, right)
80
+ left = left.map { |element| sanitize element }.join(', ')
81
+ "#{right} IN (#{left})"
82
+ end
83
+
84
+ def downcase(column)
85
+ "LOWER(#{owner.table_name}.#{quote_column_name column})"
86
+ end
87
+
88
+ def upcase(column)
89
+ "UPPER(#{owner.table_name}.#{quote_column_name column})"
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,19 @@
1
+ module Ambition
2
+ module Adapters
3
+ module ActiveRecord
4
+ class Slice < Base
5
+ def slice(start, length=nil)
6
+ if start.is_a? Range
7
+ length = start.end
8
+ length -= 1 if start.exclude_end?
9
+ start = start.first - 1
10
+ length -= start
11
+ end
12
+ out = "LIMIT #{length} "
13
+ out << "OFFSET #{start}" if start.to_i.nonzero?
14
+ out
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,43 @@
1
+ module Ambition
2
+ module Adapters
3
+ module ActiveRecord
4
+ class Sort < Base
5
+ def sort_by(method)
6
+ "#{owner.table_name}.#{quote_column_name method}"
7
+ end
8
+
9
+ def reverse_sort_by(method)
10
+ "#{owner.table_name}.#{quote_column_name method} DESC"
11
+ end
12
+
13
+ def chained_sort_by(receiver, method)
14
+ if reflection = owner.reflections[receiver]
15
+ stash[:include] ||= []
16
+ stash[:include] << receiver
17
+ "#{reflection.table_name}.#{quote_column_name method}"
18
+ else
19
+ raise [ receiver, method ].inspect
20
+ end
21
+ end
22
+
23
+ def chained_reverse_sort_by(receiver, method)
24
+ if reflection = owner.reflections[receiver]
25
+ stash[:include] ||= []
26
+ stash[:include] << receiver
27
+ "#{reflection.table_name}.#{quote_column_name method} DESC"
28
+ else
29
+ raise [ receiver, method ].inspect
30
+ end
31
+ end
32
+
33
+ def to_proc(symbol)
34
+ "#{owner.table_name}.#{symbol}"
35
+ end
36
+
37
+ def rand
38
+ 'RAND()'
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,39 @@
1
+ module Ambition
2
+ module Adapters
3
+ module ActiveRecord
4
+ module DatabaseStatements
5
+ def self.const_missing(*args)
6
+ Abstract
7
+ end
8
+
9
+ class Abstract
10
+ def regexp(regexp)
11
+ 'REGEXP'
12
+ end
13
+
14
+ def not_regexp(regexp)
15
+ 'NOT REGEXP'
16
+ end
17
+ end
18
+
19
+ class PostgreSQL < Abstract
20
+ def regexp(regexp)
21
+ if regexp.options == 1
22
+ '~*'
23
+ else
24
+ '~'
25
+ end
26
+ end
27
+
28
+ def not_regexp(regexp)
29
+ if regexp.options == 1
30
+ '!~*'
31
+ else
32
+ '!~'
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,67 @@
1
+ $:.unshift File.dirname(__FILE__) + '/../../../lib'
2
+ %w( rubygems ambition ambition/adapters/active_record benchmark ).each { |f| require f }
3
+
4
+ class User < ActiveRecord::Base
5
+ def self.reflections
6
+ return @reflections if @reflections
7
+ @reflections = {}
8
+ @reflections[:ideas] = Reflection.new(:has_many, 'user_id', :ideas, 'ideas')
9
+ @reflections[:invites] = Reflection.new(:has_many, 'referrer_id', :invites, 'invites')
10
+ @reflections[:profile] = Reflection.new(:has_one, 'user_id', :profile, 'profiles')
11
+ @reflections[:account] = Reflection.new(:belongs_to, 'account_id', :account, 'accounts')
12
+ @reflections
13
+ end
14
+
15
+ def self.table_name
16
+ 'users'
17
+ end
18
+ end
19
+
20
+ class Reflection < Struct.new(:macro, :primary_key_name, :name, :table_name)
21
+ end
22
+
23
+ Times = 10000
24
+
25
+ Benchmark.bm(30) do |x|
26
+ x.report 'simple select' do
27
+ Times.times do
28
+ User.select { |u| u.id == 20 }.to_hash
29
+ end
30
+ end
31
+
32
+ x.report 'simple select w/ eval' do
33
+ Times.times do
34
+ User.select { |u| u.created_at == Time.now }.to_hash
35
+ end
36
+ end
37
+
38
+ x.report 'dual select' do
39
+ Times.times do
40
+ User.select { |u| u.id == 20 && u.age > 20 }.to_hash
41
+ end
42
+ end
43
+
44
+ x.report 'join select' do
45
+ Times.times do
46
+ User.select { |u| u.id == 20 && u.ideas.name =~ /stuff/ }.to_hash
47
+ end
48
+ end
49
+
50
+ x.report 'dual select w/ sort' do
51
+ Times.times do
52
+ User.select { |u| u.id == 20 && u.age > 20 }.sort_by { |u| u.id }.to_hash
53
+ end
54
+ end
55
+
56
+ x.report 'dual select w/ sort & first' do
57
+ Times.times do
58
+ User.select { |u| u.id == 20 && u.age > 20 }.sort_by { |u| u.id }.first(20).to_hash
59
+ end
60
+ end
61
+
62
+ x.report "it's complicated" do
63
+ Times.times do
64
+ User.select { |u| (u.id == 20 && u.age > 20) || u.profile.name == 'Jon' }.sort_by { |u| [u.id, -u.name] }.first(20).to_hash
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,36 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ context "ActiveRecord Adapter" do
4
+ context "Chaining" do
5
+ specify "should join selects with AND" do
6
+ sql = User.select { |m| m.name == 'jon' }
7
+ sql = sql.select { |m| m.age == 22 }
8
+ sql.to_s.should == "SELECT * FROM users WHERE users.name = 'jon' AND users.age = 22"
9
+ end
10
+
11
+ specify "should join sort_bys with a comma" do
12
+ sql = User.select { |m| m.name == 'jon' }
13
+ sql = sql.sort_by { |m| m.name }
14
+ sql = sql.sort_by { |m| m.age }
15
+ sql.to_s.should == "SELECT * FROM users WHERE users.name = 'jon' ORDER BY users.name, users.age"
16
+ end
17
+
18
+ specify "should join selects and sorts intelligently" do
19
+ sql = User.select { |m| m.name == 'jon' }
20
+ sql = sql.select { |m| m.age == 22 }
21
+ sql = sql.sort_by { |m| -m.name }
22
+ sql = sql.sort_by { |m| m.age }
23
+ sql.to_s.should == "SELECT * FROM users WHERE users.name = 'jon' AND users.age = 22 ORDER BY users.name DESC, users.age"
24
+ end
25
+
26
+ specify "should join lots of selects and sorts intelligently" do
27
+ sql = User.select { |m| m.name == 'jon' }
28
+ sql = sql.select { |m| m.age == 22 }
29
+ sql = sql.sort_by { |m| m.name }
30
+ sql = sql.select { |m| m.power == true }
31
+ sql = sql.sort_by { |m| m.email }
32
+ sql = sql.select { |m| m.admin == true && m.email == 'chris@ozmm.org' }
33
+ sql.to_s.should == "SELECT * FROM users WHERE users.name = 'jon' AND users.age = 22 AND users.power = 1 AND (users.admin = 1 AND users.email = 'chris@ozmm.org') ORDER BY users.name, users.email"
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,19 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ context "ActiveRecord Adapter" do
4
+ context "Count" do
5
+ setup do
6
+ hash = { :conditions => "users.name = 'jon'" }
7
+ User.expects(:count).with(hash)
8
+ @sql = User.select { |m| m.name == 'jon' }
9
+ end
10
+
11
+ specify "size" do
12
+ @sql.size
13
+ end
14
+
15
+ specify "length" do
16
+ @sql.length
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,88 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ context "ActiveRecord Adapter" do
4
+ context "Each" do
5
+ specify "simple ==" do
6
+ hash = { :conditions => "users.age = 21" }
7
+ User.expects(:find).with(:all, hash).returns([])
8
+ User.select { |m| m.age == 21 }.each do |user|
9
+ puts user.name
10
+ end
11
+ end
12
+
13
+ specify "limit and conditions" do
14
+ hash = { :limit => 5, :conditions => "users.age = 21" }
15
+ User.expects(:find).with(:all, hash).returns([])
16
+ User.select { |m| m.age == 21 }.first(5).each do |user|
17
+ puts user.name
18
+ end
19
+ end
20
+
21
+ specify "limit and conditions and order" do
22
+ hash = { :limit => 5, :conditions => "users.age = 21", :order => 'users.name' }
23
+ User.expects(:find).with(:all, hash).returns([])
24
+ User.select { |m| m.age == 21 }.sort_by { |m| m.name }.first(5).each do |user|
25
+ puts user.name
26
+ end
27
+ end
28
+
29
+ specify "limit and order" do
30
+ hash = { :limit => 5, :order => 'users.name' }
31
+ User.expects(:find).with(:all, hash).returns([])
32
+ User.sort_by { |m| m.name }.first(5).each do |user|
33
+ puts user.name
34
+ end
35
+ end
36
+ end
37
+
38
+ context "Enumerable Methods" do
39
+ specify "map" do
40
+ hash = { :conditions => "users.age = 21" }
41
+ User.expects(:find).with(:all, hash).returns([])
42
+ User.select { |m| m.age == 21 }.map { |u| u.name }
43
+ end
44
+
45
+ specify "each_with_index" do
46
+ hash = { :conditions => "users.age = 21" }
47
+ User.expects(:find).with(:all, hash).returns([])
48
+ User.select { |m| m.age == 21 }.each_with_index do |user, i|
49
+ puts "#{i}: #{user.name}"
50
+ end
51
+ end
52
+
53
+ specify "any?" do
54
+ User.expects(:count).with(:conditions => "users.age > 21").returns(1)
55
+ User.any? { |u| u.age > 21 }.should == true
56
+ end
57
+
58
+ specify "all?" do
59
+ User.expects(:count).at_least_once.returns(10, 20)
60
+ User.all? { |u| u.age > 21 }.should == false
61
+
62
+ User.expects(:count).at_least_once.returns(10, 10)
63
+ User.all? { |u| u.age > 21 }.should == true
64
+ end
65
+
66
+ specify "empty?" do
67
+ User.expects(:count).with(:conditions => "users.age > 21").returns(1)
68
+ User.select { |u| u.age > 21 }.empty?.should.equal false
69
+
70
+ User.expects(:count).with(:conditions => "users.age > 21").returns(0)
71
+ User.select { |u| u.age > 21 }.empty?.should.equal true
72
+ end
73
+
74
+ specify "entries" do
75
+ User.expects(:find).with(:all, {})
76
+ User.entries
77
+
78
+ hash = { :conditions => "users.age = 21" }
79
+ User.expects(:find).with(:all, hash).returns([])
80
+ User.select { |m| m.age == 21 }.entries
81
+ end
82
+
83
+ specify "to_a" do
84
+ User.expects(:find).with(:all, {})
85
+ User.to_a
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,43 @@
1
+ %w( rubygems test/spec mocha redgreen English ).each { |f| require f }
2
+
3
+ $LOAD_PATH.unshift *[ File.dirname(__FILE__) + '/../lib', File.dirname(__FILE__) + '/../../../lib' ]
4
+ require 'ambition/adapters/active_record'
5
+
6
+ class User < ActiveRecord::Base
7
+ def self.reflections
8
+ return @reflections if @reflections
9
+ @reflections = {}
10
+ @reflections[:ideas] = Reflection.new(:has_many, 'user_id', :ideas, 'ideas')
11
+ @reflections[:invites] = Reflection.new(:has_many, 'referrer_id', :invites, 'invites')
12
+ @reflections[:profile] = Reflection.new(:has_one, 'user_id', :profile, 'profiles')
13
+ @reflections[:account] = Reflection.new(:belongs_to, 'account_id', :account, 'accounts')
14
+ @reflections
15
+ end
16
+
17
+ def self.table_name
18
+ 'users'
19
+ end
20
+ end
21
+
22
+ class Reflection < Struct.new(:macro, :primary_key_name, :name, :table_name)
23
+ end
24
+
25
+ module ActiveRecord
26
+ module ConnectionAdapters
27
+ class MysqlAdapter
28
+ def connect(*args)
29
+ true
30
+ end
31
+ end
32
+
33
+ class PostgreSQLAdapter
34
+ def connect(*args)
35
+ true
36
+ end
37
+ class PGError; end
38
+ end
39
+
40
+ class FakeAdapter < AbstractAdapter
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,62 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ context "ActiveRecord Adapter" do
4
+ context "Joins" do
5
+ specify "simple == on an association" do
6
+ sql = User.select { |m| m.account.email == 'chris@ozmm.org' }
7
+ sql.to_hash.should == {
8
+ :conditions => "accounts.email = 'chris@ozmm.org'",
9
+ :include => [:account]
10
+ }
11
+ end
12
+
13
+ specify "simple mixed == on an association" do
14
+ sql = User.select { |m| m.name == 'chris' && m.account.email == 'chris@ozmm.org' }
15
+ sql.to_hash.should == {
16
+ :conditions => "(users.name = 'chris' AND accounts.email = 'chris@ozmm.org')",
17
+ :include => [:account]
18
+ }
19
+ end
20
+
21
+ specify "multiple associations" do
22
+ sql = User.select { |m| m.ideas.title == 'New Freezer' || m.invites.email == 'pj@hyett.com' }
23
+ sql.to_hash.should == {
24
+ :conditions => "(ideas.title = 'New Freezer' OR invites.email = 'pj@hyett.com')",
25
+ :include => [:ideas, :invites]
26
+ }
27
+ end
28
+
29
+ specify "belongs_to" do
30
+ sql = User.select { |m| m.account.id > 20 }
31
+ sql.to_hash.should == {
32
+ :conditions => "accounts.id > 20",
33
+ :include => [:account]
34
+ }
35
+ end
36
+
37
+ specify "complex joins have no to_s" do
38
+ sql = User.select { |m| m.account.id > 20 }
39
+ should.raise { sql.to_s }
40
+ end
41
+
42
+ specify "non-existant associations" do
43
+ should.raise { User.select { |m| m.liquor.brand == 'Jack' } }
44
+ end
45
+
46
+ specify "in order" do
47
+ sql = User.sort_by { |m| m.ideas.title }
48
+ sql.to_hash.should == {
49
+ :order => "ideas.title",
50
+ :include => [:ideas]
51
+ }
52
+ end
53
+
54
+ specify "in a more complex order" do
55
+ sql = User.sort_by { |m| [ m.ideas.title, -m.invites.email ] }
56
+ sql.to_hash.should == {
57
+ :order => "ideas.title, invites.email DESC",
58
+ :include => [:ideas, :invites]
59
+ }
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,36 @@
1
+ $:.unshift File.dirname(__FILE__) + '/../../../lib'
2
+ require 'rubygems'
3
+ require 'ambition'
4
+ require 'ambition/adapters/active_record'
5
+ require 'ruby-prof'
6
+
7
+ class User < ActiveRecord::Base
8
+ def self.reflections
9
+ return @reflections if @reflections
10
+ @reflections = {}
11
+ @reflections[:ideas] = Reflection.new(:has_many, 'user_id', :ideas, 'ideas')
12
+ @reflections[:invites] = Reflection.new(:has_many, 'referrer_id', :invites, 'invites')
13
+ @reflections[:profile] = Reflection.new(:has_one, 'user_id', :profile, 'profiles')
14
+ @reflections[:account] = Reflection.new(:belongs_to, 'account_id', :account, 'accounts')
15
+ @reflections
16
+ end
17
+
18
+ def self.table_name
19
+ 'users'
20
+ end
21
+ end
22
+
23
+ class Reflection < Struct.new(:macro, :primary_key_name, :name, :table_name)
24
+ end
25
+
26
+ result = RubyProf.profile do
27
+ 1000.times do
28
+ User.select { |u| (u.id == 20 && u.age > 20) || u.profile.name == 'Jon' }.sort_by { |u| [u.id, -u.name] }.first(20).to_hash
29
+ end
30
+ end
31
+
32
+ printer = RubyProf::FlatPrinter.new(result)
33
+ #printer = RubyProf::GraphPrinter.new(result)
34
+ printer.print(STDOUT, 0)
35
+
36
+ puts User.select { |u| (u.id == 20 && u.age > 20) || u.profile.name == 'Jon' }.sort_by { |u| [u.id, -u.name] }.first(20).to_hash.inspect
@@ -0,0 +1,11 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ context "ActiveRecord Adapter" do
4
+ context "Inline Ruby" do
5
+ xspecify "should know what to return" do
6
+ name = 'David'
7
+ sql = User.select { |u| name.nil? || u.name == name }.to_s
8
+ sql.should == "SELECT * FROM users WHERE (users.name = 'David')"
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,259 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ context "ActiveRecord Adapter" do
4
+ context "Select" do
5
+ specify "simple ==" do
6
+ sql = User.select { |m| m.name == 'jon' }.to_s
7
+ sql.should == "SELECT * FROM users WHERE users.name = 'jon'"
8
+ end
9
+
10
+ specify "simple !=" do
11
+ sql = User.select { |m| m.name != 'jon' }.to_s
12
+ sql.should == "SELECT * FROM users WHERE users.name <> 'jon'"
13
+ end
14
+
15
+ specify "simple == && ==" do
16
+ sql = User.select { |m| m.name == 'jon' && m.age == 21 }.to_s
17
+ sql.should == "SELECT * FROM users WHERE (users.name = 'jon' AND users.age = 21)"
18
+ end
19
+
20
+ specify "simple == || ==" do
21
+ sql = User.select { |m| m.name == 'jon' || m.age == 21 }.to_s
22
+ sql.should == "SELECT * FROM users WHERE (users.name = 'jon' OR users.age = 21)"
23
+ end
24
+
25
+ specify "mixed && and ||" do
26
+ sql = User.select { |m| m.name == 'jon' || m.age == 21 && m.password == 'pass' }.to_s
27
+ sql.should == "SELECT * FROM users WHERE (users.name = 'jon' OR (users.age = 21 AND users.password = 'pass'))"
28
+ end
29
+
30
+ specify "grouped && and ||" do
31
+ sql = User.select { |m| (m.name == 'jon' || m.name == 'rick') && m.age == 21 }.to_s
32
+ sql.should == "SELECT * FROM users WHERE ((users.name = 'jon' OR users.name = 'rick') AND users.age = 21)"
33
+ end
34
+
35
+ specify "simple >/<" do
36
+ sql = User.select { |m| m.age > 21 }.to_s
37
+ sql.should == "SELECT * FROM users WHERE users.age > 21"
38
+
39
+ sql = User.select { |m| m.age >= 21 }.to_s
40
+ sql.should == "SELECT * FROM users WHERE users.age >= 21"
41
+
42
+ sql = User.select { |m| m.age < 21 }.to_s
43
+ sql.should == "SELECT * FROM users WHERE users.age < 21"
44
+ end
45
+
46
+ specify "array.include? item" do
47
+ sql = User.select { |m| [1, 2, 3, 4].include? m.id }.to_s
48
+ sql.should == "SELECT * FROM users WHERE users.id IN (1, 2, 3, 4)"
49
+ end
50
+
51
+ specify "variable'd array.include? item" do
52
+ array = [1, 2, 3, 4]
53
+ sql = User.select { |m| array.include? m.id }.to_s
54
+ sql.should == "SELECT * FROM users WHERE users.id IN (1, 2, 3, 4)"
55
+ end
56
+
57
+ specify "simple == with variables" do
58
+ me = 'chris'
59
+ sql = User.select { |m| m.name == me }.to_s
60
+ sql.should == "SELECT * FROM users WHERE users.name = '#{me}'"
61
+ end
62
+
63
+ specify "simple == with method arguments" do
64
+ def test_it(name)
65
+ sql = User.select { |m| m.name == name }.to_s
66
+ sql.should == "SELECT * FROM users WHERE users.name = '#{name}'"
67
+ end
68
+
69
+ test_it('chris')
70
+ end
71
+
72
+ specify "simple == with instance variables" do
73
+ @me = 'chris'
74
+ sql = User.select { |m| m.name == @me }.to_s
75
+ sql.should == "SELECT * FROM users WHERE users.name = '#{@me}'"
76
+ end
77
+
78
+ specify "simple == with instance variable method call" do
79
+ require 'ostruct'
80
+ @person = OpenStruct.new(:name => 'chris')
81
+
82
+ sql = User.select { |m| m.name == @person.name }.to_s
83
+ sql.should == "SELECT * FROM users WHERE users.name = '#{@person.name}'"
84
+ end
85
+
86
+ specify "simple == with global variables" do
87
+ $my_name = 'boston'
88
+ sql = User.select { |m| m.name == $my_name }.to_s
89
+ sql.should == "SELECT * FROM users WHERE users.name = '#{$my_name}'"
90
+ end
91
+
92
+ specify "simple == with method call" do
93
+ def band
94
+ 'megadeth'
95
+ end
96
+
97
+ sql = User.select { |m| m.name == band }.to_s
98
+ sql.should == "SELECT * FROM users WHERE users.name = '#{band}'"
99
+ end
100
+
101
+ specify "simple =~ with string" do
102
+ sql = User.select { |m| m.name =~ 'chris' }.to_s
103
+ sql.should == "SELECT * FROM users WHERE users.name LIKE 'chris'"
104
+
105
+ sql = User.select { |m| m.name =~ 'chri%' }.to_s
106
+ sql.should == "SELECT * FROM users WHERE users.name LIKE 'chri%'"
107
+ end
108
+
109
+ specify "simple !~ with string" do
110
+ sql = User.select { |m| m.name !~ 'chris' }.to_s
111
+ sql.should == "SELECT * FROM users WHERE users.name NOT LIKE 'chris'"
112
+
113
+ sql = User.select { |m| !(m.name =~ 'chris') }.to_s
114
+ sql.should == "SELECT * FROM users WHERE users.name NOT LIKE 'chris'"
115
+ end
116
+
117
+ specify "simple =~ with regexp" do
118
+ sql = User.select { |m| m.name =~ /chris/ }.to_s
119
+ sql.should == "SELECT * FROM users WHERE users.name REGEXP 'chris'"
120
+ end
121
+
122
+ specify "simple =~ with regexp flags" do
123
+ sql = User.select { |m| m.name =~ /chris/i }.to_s
124
+ sql.should == "SELECT * FROM users WHERE users.name REGEXP 'chris'"
125
+ end
126
+
127
+ specify "simple LOWER()" do
128
+ sql = User.select { |m| m.name.downcase =~ 'chris%' }.to_s
129
+ sql.should == "SELECT * FROM users WHERE LOWER(users.name) LIKE 'chris%'"
130
+ end
131
+
132
+ specify "simple UPPER()" do
133
+ sql = User.select { |m| m.name.upcase =~ 'chris%' }.to_s
134
+ sql.should == "SELECT * FROM users WHERE UPPER(users.name) LIKE 'chris%'"
135
+ end
136
+
137
+ specify "undefined equality symbol" do
138
+ should.raise { User.select { |m| m.name =* /chris/ }.to_s }
139
+ end
140
+
141
+ specify "block variable / assigning variable conflict" do
142
+ m = User.select { |m| m.name == 'chris' }.to_s
143
+ m.should == "SELECT * FROM users WHERE users.name = 'chris'"
144
+ end
145
+
146
+ specify "simple == with inline ruby" do
147
+ sql = User.select { |m| m.created_at == 2.days.ago.to_s(:db) }.to_s
148
+ sql.should == "SELECT * FROM users WHERE users.created_at = '#{2.days.ago.to_s(:db)}'"
149
+ end
150
+
151
+ specify "deep chains" do
152
+ should.raise do
153
+ User.select { |m| m.created_at.something.else.perhaps }.to_s
154
+ end
155
+ end
156
+
157
+ specify "inspect" do
158
+ User.select { |u| u.name }.inspect.should.match %r(call #to_s or #to_hash)
159
+ end
160
+ end
161
+
162
+ context "Detect" do
163
+ specify "simple ==" do
164
+ User.expects(:select).returns(mock(:first => true))
165
+ User.detect { |m| m.name == 'chris' }
166
+ end
167
+
168
+ specify "nothing found" do
169
+ User.expects(:select).returns(mock(:first => nil))
170
+ User.detect { |m| m.name == 'chris' }.should.be.nil
171
+ end
172
+ end
173
+
174
+ xcontext "[]" do
175
+ specify "finds a single row" do
176
+ User.expects(:find).with(1)
177
+ User[1]
178
+ end
179
+ end
180
+
181
+ context "PostgreSQL specific" do
182
+ setup do
183
+ ActiveRecord::Base.connection = ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.new 'fake_connection', 'fake_logger'
184
+ end
185
+
186
+ teardown do
187
+ ActiveRecord::Base.remove_connection
188
+ end
189
+
190
+ specify "quoting of column name" do
191
+ me = 'chris'
192
+ sql = User.select { |m| m.name == me }.to_s
193
+ sql.should == %(SELECT * FROM users WHERE users."name" = '#{me}')
194
+ end
195
+
196
+ specify "simple =~ with regexp" do
197
+ sql = User.select { |m| m.name =~ /chris/ }.to_s
198
+ sql.should == %(SELECT * FROM users WHERE users."name" ~ 'chris')
199
+ end
200
+
201
+ specify "insensitive =~" do
202
+ sql = User.select { |m| m.name =~ /chris/i }.to_s
203
+ sql.should == %(SELECT * FROM users WHERE users."name" ~* 'chris')
204
+ end
205
+
206
+ specify "negated =~" do
207
+ sql = User.select { |m| m.name !~ /chris/ }.to_s
208
+ sql.should == %(SELECT * FROM users WHERE users."name" !~ 'chris')
209
+ end
210
+
211
+ specify "negated insensitive =~" do
212
+ sql = User.select { |m| m.name !~ /chris/i }.to_s
213
+ sql.should == %(SELECT * FROM users WHERE users."name" !~* 'chris')
214
+ end
215
+ end
216
+
217
+ context "MySQL specific" do
218
+ setup do
219
+ ActiveRecord::Base.connection = ActiveRecord::ConnectionAdapters::MysqlAdapter.new('connection', 'logger', 'options', 'config')
220
+ end
221
+
222
+ teardown do
223
+ ActiveRecord::Base.connection = ActiveRecord::ConnectionAdapters::FakeAdapter.new('connection', 'logger')
224
+ end
225
+
226
+ specify "quoting of column name" do
227
+ me = 'chris'
228
+ sql = User.select { |m| m.name == me }.to_s
229
+ sql.should == "SELECT * FROM users WHERE users.`name` = '#{me}'"
230
+ end
231
+
232
+ specify "simple =~ with regexp" do
233
+ sql = User.select { |m| m.name =~ /chris/ }.to_s
234
+ sql.should == "SELECT * FROM users WHERE users.`name` REGEXP 'chris'"
235
+ end
236
+
237
+ specify "negated =~" do
238
+ sql = User.select { |m| m.name !~ 'chris' }.to_s
239
+ sql.should == "SELECT * FROM users WHERE users.`name` NOT LIKE 'chris'"
240
+ end
241
+
242
+ specify "negated =~ with regexp" do
243
+ sql = User.select { |m| m.name !~ /chris/ }.to_s
244
+ sql.should == "SELECT * FROM users WHERE users.`name` NOT REGEXP 'chris'"
245
+ end
246
+ end
247
+
248
+ context "Adapter without overrides" do
249
+ setup do
250
+ ActiveRecord::Base.connection = ActiveRecord::ConnectionAdapters::FakeAdapter.new('connection', 'logger')
251
+ end
252
+
253
+ specify "quoting of column name" do
254
+ me = 'chris'
255
+ sql = User.select { |m| m.name == me }.to_s
256
+ sql.should == "SELECT * FROM users WHERE users.name = '#{me}'"
257
+ end
258
+ end
259
+ end
@@ -0,0 +1,43 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ context "ActiveRecord Adapter" do
4
+ context "Slice" do
5
+ setup do
6
+ @sql = User.select { |m| m.name == 'jon' }
7
+ end
8
+
9
+ specify "first" do
10
+ conditions = { :conditions => "users.name = 'jon'", :limit => 1 }
11
+ User.expects(:find).with(:all, conditions)
12
+ @sql.first
13
+ end
14
+
15
+ specify "first with argument" do
16
+ conditions = { :conditions => "users.name = 'jon'", :limit => 5 }
17
+ User.expects(:find).with(:all, conditions)
18
+ @sql.first(5).entries
19
+ end
20
+
21
+ specify "[] with two elements" do
22
+ conditions = { :conditions => "users.name = 'jon'", :limit => 20, :offset => 10 }
23
+ User.expects(:find).with(:all, conditions)
24
+ @sql[10, 20].entries
25
+
26
+ conditions = { :conditions => "users.name = 'jon'", :limit => 20, :offset => 20 }
27
+ User.expects(:find).with(:all, conditions)
28
+ @sql[20, 20].entries
29
+ end
30
+
31
+ specify "slice is an alias of []" do
32
+ conditions = { :conditions => "users.name = 'jon'", :limit => 20, :offset => 10 }
33
+ User.expects(:find).with(:all, conditions)
34
+ @sql.slice(10, 20).entries
35
+ end
36
+
37
+ specify "[] with range" do
38
+ conditions = { :conditions => "users.name = 'jon'", :limit => 10, :offset => 10 }
39
+ User.expects(:find).with(:all, conditions)
40
+ @sql[11..20].entries
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,54 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ context "ActiveRecord Adapter" do
4
+ context "Sort" do
5
+ setup do
6
+ @sql = User.select { |m| m.name == 'jon' }
7
+ end
8
+
9
+ specify "simple order" do
10
+ string = @sql.sort_by { |m| m.name }.to_s
11
+ string.should == "SELECT * FROM users WHERE users.name = 'jon' ORDER BY users.name"
12
+ end
13
+
14
+ specify "simple combined order" do
15
+ string = @sql.sort_by { |m| [ m.name, m.age ] }.to_s
16
+ string.should == "SELECT * FROM users WHERE users.name = 'jon' ORDER BY users.name, users.age"
17
+ end
18
+
19
+ specify "simple combined order with single reverse" do
20
+ string = @sql.sort_by { |m| [ m.name, -m.age ] }.to_s
21
+ string.should == "SELECT * FROM users WHERE users.name = 'jon' ORDER BY users.name, users.age DESC"
22
+ end
23
+
24
+ specify "simple combined order with two reverses" do
25
+ string = @sql.sort_by { |m| [ -m.name, -m.age ] }.to_s
26
+ string.should == "SELECT * FROM users WHERE users.name = 'jon' ORDER BY users.name DESC, users.age DESC"
27
+ end
28
+
29
+ specify "reverse order with -" do
30
+ string = @sql.sort_by { |m| -m.age }.to_s
31
+ string.should == "SELECT * FROM users WHERE users.name = 'jon' ORDER BY users.age DESC"
32
+ end
33
+
34
+ xspecify "reverse order with #reverse" do
35
+ # TODO: not implemented
36
+ string = @sql.sort_by { |m| m.age }.reverse.to_s
37
+ string.should == "SELECT * FROM users WHERE users.name = 'jon' ORDER BY users.age DESC"
38
+ end
39
+
40
+ specify "random order" do
41
+ string = @sql.sort_by { rand }.to_s
42
+ string.should == "SELECT * FROM users WHERE users.name = 'jon' ORDER BY RAND()"
43
+ end
44
+
45
+ specify "non-existent method to sort by" do
46
+ should.raise(NoMethodError) { @sql.sort_by { foo }.to_s }
47
+ end
48
+
49
+ specify "Symbol#to_proc" do
50
+ string = User.sort_by(&:name).to_s
51
+ string.should == "SELECT * FROM users ORDER BY users.name"
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,43 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+ require 'ostruct'
3
+
4
+ context "Setting the ambition_source" do
5
+ setup do
6
+ # @users = [
7
+ # OpenStruct.new(:name => 'Chris', :age => 22),
8
+ # OpenStruct.new(:name => 'PJ', :age => 24),
9
+ # OpenStruct.new(:name => 'Kevin', :age => 23),
10
+ # OpenStruct.new(:name => '_why', :age => 65)
11
+ # ]
12
+ # User.ambition_source = @users
13
+ end
14
+
15
+ teardown do
16
+ # User.ambition_source = nil
17
+ end
18
+
19
+ xspecify "should run all selects / detects against that collection" do
20
+ User.detect { |u| u.name == 'Chris' }.should == @users.first
21
+ end
22
+
23
+ xspecify "should run all sorts against that collection" do
24
+ User.sort_by { |u| -u.age }.entries.should == @users.sort_by { |u| -u.age }
25
+ end
26
+
27
+ xspecify "should chain successfully" do
28
+ User.select { |u| u.age > 22 }.sort_by { |u| -u.age }.entries.should == [ @users[3], @users[1], @users[2] ]
29
+ end
30
+
31
+ xspecify "should be able to revert to normal" do
32
+ block = proc { User.select { |m| m.name == 'PJ' }.first }
33
+
34
+ User.expects(:find).never
35
+ block.call.should == @users[1]
36
+
37
+ conditions = { :conditions => "users.name = 'PJ'", :limit => 1 }
38
+ User.expects(:find).with(:first, conditions)
39
+
40
+ User.ambition_source = nil
41
+ block.call
42
+ end
43
+ end
@@ -0,0 +1,59 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ ##
4
+ # Once dynamically, once hardcoded
5
+ context "Different types" do
6
+ types_hash = {
7
+ 'string' => "'string'",
8
+ :symbol => "'--- :symbol\n'",
9
+ 1 => '1',
10
+ 1.2 => '1.2',
11
+ true => '1',
12
+ false => '0',
13
+ Time.now => "'#{Time.now.to_s(:db)}'",
14
+ DateTime.now => "'#{DateTime.now.to_s(:db)}'",
15
+ Date.today => "'#{Date.today.to_s(:db)}'"
16
+ }
17
+
18
+ types_hash.each do |type, translation|
19
+ specify "simple using #{type}" do
20
+ sql = User.select { |m| m.name == type }.to_s
21
+ sql.should == "SELECT * FROM users WHERE users.name = #{translation}"
22
+ end
23
+ end
24
+
25
+ specify "float" do
26
+ sql = User.select { |m| m.name == 1.2 }.to_s
27
+ sql.should == "SELECT * FROM users WHERE users.name = 1.2"
28
+ end
29
+
30
+ specify "integer" do
31
+ sql = User.select { |m| m.name == 1 }.to_s
32
+ sql.should == "SELECT * FROM users WHERE users.name = 1"
33
+ end
34
+
35
+ specify "true" do
36
+ sql = User.select { |m| m.name == true }.to_s
37
+ sql.should == "SELECT * FROM users WHERE users.name = 1"
38
+ end
39
+
40
+ specify "false" do
41
+ sql = User.select { |m| m.name == false }.to_s
42
+ sql.should == "SELECT * FROM users WHERE users.name = 0"
43
+ end
44
+
45
+ specify "nil" do
46
+ sql = User.select { |m| m.name == nil }.to_s
47
+ sql.should == "SELECT * FROM users WHERE users.name IS NULL"
48
+ end
49
+
50
+ specify "not nil" do
51
+ sql = User.select { |m| m.name != nil }.to_s
52
+ sql.should == "SELECT * FROM users WHERE users.name IS NOT NULL"
53
+ end
54
+
55
+ specify "Time" do
56
+ sql = User.select { |m| m.name == Time.now }.to_s
57
+ sql.should == "SELECT * FROM users WHERE users.name = '#{Time.now.to_s(:db)}'"
58
+ end
59
+ end
metadata ADDED
@@ -0,0 +1,93 @@
1
+ --- !ruby/object:Gem::Specification
2
+ rubygems_version: 0.9.4
3
+ specification_version: 1
4
+ name: ambitious-activerecord
5
+ version: !ruby/object:Gem::Version
6
+ version: 0.1.0
7
+ date: 2008-01-29 00:00:00 -08:00
8
+ summary: An ambitious adapter for ActiveRecord
9
+ require_paths:
10
+ - lib
11
+ email: chris@ozmm.org
12
+ homepage: http://ambition.rubyforge.org/
13
+ rubyforge_project: ambition
14
+ description: An ambitious adapter for ActiveRecord
15
+ autorequire:
16
+ default_executable:
17
+ bindir: bin
18
+ has_rdoc: true
19
+ required_ruby_version: !ruby/object:Gem::Version::Requirement
20
+ requirements:
21
+ - - ">"
22
+ - !ruby/object:Gem::Version
23
+ version: 0.0.0
24
+ version:
25
+ platform: ruby
26
+ signing_key:
27
+ cert_chain:
28
+ post_install_message:
29
+ authors:
30
+ - Chris Wanstrath
31
+ files:
32
+ - lib/ambition/adapters/active_record/base.rb
33
+ - lib/ambition/adapters/active_record/query.rb
34
+ - lib/ambition/adapters/active_record/select.rb
35
+ - lib/ambition/adapters/active_record/slice.rb
36
+ - lib/ambition/adapters/active_record/sort.rb
37
+ - lib/ambition/adapters/active_record/statements.rb
38
+ - lib/ambition/adapters/active_record.rb
39
+ - test/benchmark.rb
40
+ - test/chaining_test.rb
41
+ - test/count_test.rb
42
+ - test/enumerable_test.rb
43
+ - test/helper.rb
44
+ - test/join_test.rb
45
+ - test/profiler.rb
46
+ - test/ruby_test.rb
47
+ - test/select_test.rb
48
+ - test/slice_test.rb
49
+ - test/sort_test.rb
50
+ - test/source_test.rb
51
+ - test/types_test.rb
52
+ - Manifest
53
+ - ambitious-activerecord.gemspec
54
+ test_files:
55
+ - test/chaining_test.rb
56
+ - test/count_test.rb
57
+ - test/enumerable_test.rb
58
+ - test/join_test.rb
59
+ - test/ruby_test.rb
60
+ - test/select_test.rb
61
+ - test/slice_test.rb
62
+ - test/sort_test.rb
63
+ - test/source_test.rb
64
+ - test/types_test.rb
65
+ rdoc_options: []
66
+
67
+ extra_rdoc_files: []
68
+
69
+ executables: []
70
+
71
+ extensions: []
72
+
73
+ requirements: []
74
+
75
+ dependencies:
76
+ - !ruby/object:Gem::Dependency
77
+ name: activerecord
78
+ version_requirement:
79
+ version_requirements: !ruby/object:Gem::Version::Requirement
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ version: 1.15.0
84
+ version:
85
+ - !ruby/object:Gem::Dependency
86
+ name: ambition
87
+ version_requirement:
88
+ version_requirements: !ruby/object:Gem::Version::Requirement
89
+ requirements:
90
+ - - ">="
91
+ - !ruby/object:Gem::Version
92
+ version: 0.5.0
93
+ version: