cheat 1.2.1 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README +5 -0
- data/bin/cheat +8 -2
- data/lib/ambition/LICENSE +18 -0
- data/lib/ambition/README +143 -0
- data/lib/ambition/Rakefile +29 -0
- data/lib/ambition/init.rb +1 -0
- data/lib/ambition/lib/ambition.rb +21 -0
- data/lib/ambition/lib/ambition/count.rb +8 -0
- data/lib/ambition/lib/ambition/enumerable.rb +9 -0
- data/lib/ambition/lib/ambition/limit.rb +34 -0
- data/lib/ambition/lib/ambition/order.rb +52 -0
- data/lib/ambition/lib/ambition/processor.rb +54 -0
- data/lib/ambition/lib/ambition/query.rb +85 -0
- data/lib/ambition/lib/ambition/where.rb +164 -0
- data/lib/ambition/lib/proc_to_ruby.rb +36 -0
- data/lib/ambition/test/chaining_test.rb +34 -0
- data/lib/ambition/test/count_test.rb +17 -0
- data/lib/ambition/test/enumerable_test.rb +51 -0
- data/lib/ambition/test/helper.rb +30 -0
- data/lib/ambition/test/join_test.rb +32 -0
- data/lib/ambition/test/limit_test.rb +37 -0
- data/lib/ambition/test/order_test.rb +48 -0
- data/lib/ambition/test/types_test.rb +56 -0
- data/lib/ambition/test/where_test.rb +131 -0
- data/lib/cheat.rb +81 -11
- data/lib/{diffr.rb → cheat/diffr.rb} +0 -1
- data/lib/{responder.rb → cheat/responder.rb} +3 -3
- data/lib/cheat/rv_harness.rb +41 -0
- data/lib/{site.rb → cheat/site.rb} +114 -93
- data/lib/cheat/version.rb +3 -0
- data/lib/{wrap.rb → cheat/wrap.rb} +0 -0
- metadata +77 -42
- data/lib/cheat/commands.rb +0 -41
- data/lib/new_cheat.rb +0 -163
- data/test/test_cheat.rb +0 -50
@@ -0,0 +1,164 @@
|
|
1
|
+
module Ambition
|
2
|
+
module Where
|
3
|
+
def select(*args, &block)
|
4
|
+
##
|
5
|
+
# XXX: AR::Base hack / workaround
|
6
|
+
if args.empty?
|
7
|
+
query_context.add WhereProcessor.new(self, block)
|
8
|
+
else
|
9
|
+
super
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def detect(&block)
|
14
|
+
select(&block).first
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class WhereProcessor < Processor
|
19
|
+
attr_reader :includes
|
20
|
+
|
21
|
+
def initialize(owner, block)
|
22
|
+
super()
|
23
|
+
@receiver = nil
|
24
|
+
@owner = owner
|
25
|
+
@table_name = owner.table_name
|
26
|
+
@block = block
|
27
|
+
@key = :conditions
|
28
|
+
@includes = []
|
29
|
+
end
|
30
|
+
|
31
|
+
##
|
32
|
+
# Sexp Processing Methods
|
33
|
+
def process_and(exp)
|
34
|
+
joined_expressions 'AND', exp
|
35
|
+
end
|
36
|
+
|
37
|
+
def process_or(exp)
|
38
|
+
joined_expressions 'OR', exp
|
39
|
+
end
|
40
|
+
|
41
|
+
def process_not(exp)
|
42
|
+
_, receiver, method, other = *exp.first
|
43
|
+
exp.clear
|
44
|
+
return translation(receiver, negate(method), other)
|
45
|
+
end
|
46
|
+
|
47
|
+
def process_call(exp)
|
48
|
+
receiver, method, other = *exp
|
49
|
+
exp.clear
|
50
|
+
|
51
|
+
return translation(receiver, method, other)
|
52
|
+
end
|
53
|
+
|
54
|
+
def process_lit(exp)
|
55
|
+
exp.shift.to_s
|
56
|
+
end
|
57
|
+
|
58
|
+
def process_str(exp)
|
59
|
+
sanitize exp.shift
|
60
|
+
end
|
61
|
+
|
62
|
+
def process_nil(exp)
|
63
|
+
'NULL'
|
64
|
+
end
|
65
|
+
|
66
|
+
def process_false(exp)
|
67
|
+
sanitize 'false'
|
68
|
+
end
|
69
|
+
|
70
|
+
def process_true(exp)
|
71
|
+
sanitize 'true'
|
72
|
+
end
|
73
|
+
|
74
|
+
def process_match3(exp)
|
75
|
+
regexp, target = exp.shift.last.inspect.gsub('/',''), process(exp.shift)
|
76
|
+
"#{target} REGEXP '#{regexp}'"
|
77
|
+
end
|
78
|
+
|
79
|
+
def process_dvar(exp)
|
80
|
+
target = exp.shift
|
81
|
+
if target == @receiver
|
82
|
+
return @table_name
|
83
|
+
else
|
84
|
+
return value(target.to_s[0..-1])
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def process_ivar(exp)
|
89
|
+
value(exp.shift.to_s[0..-1])
|
90
|
+
end
|
91
|
+
|
92
|
+
def process_lvar(exp)
|
93
|
+
value(exp.shift.to_s)
|
94
|
+
end
|
95
|
+
|
96
|
+
def process_vcall(exp)
|
97
|
+
value(exp.shift.to_s)
|
98
|
+
end
|
99
|
+
|
100
|
+
def process_gvar(exp)
|
101
|
+
value(exp.shift.to_s)
|
102
|
+
end
|
103
|
+
|
104
|
+
def process_attrasgn(exp)
|
105
|
+
exp.clear
|
106
|
+
raise "Assignment not supported. Maybe you meant ==?"
|
107
|
+
end
|
108
|
+
|
109
|
+
##
|
110
|
+
# Processor helper methods
|
111
|
+
def joined_expressions(with, exp)
|
112
|
+
clauses = []
|
113
|
+
while clause = exp.shift
|
114
|
+
clauses << clause
|
115
|
+
end
|
116
|
+
return "(" + clauses.map { |c| process(c) }.join(" #{with} ") + ")"
|
117
|
+
end
|
118
|
+
|
119
|
+
def value(variable)
|
120
|
+
sanitize eval(variable, @block)
|
121
|
+
end
|
122
|
+
|
123
|
+
def negate(method)
|
124
|
+
case method
|
125
|
+
when :==
|
126
|
+
'<>'
|
127
|
+
when :=~
|
128
|
+
'!~'
|
129
|
+
else
|
130
|
+
raise "Not implemented: #{method}"
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
def translation(receiver, method, other)
|
135
|
+
case method.to_s
|
136
|
+
when '=='
|
137
|
+
"#{process(receiver)} = #{process(other)}"
|
138
|
+
when '<>', '>', '<'
|
139
|
+
"#{process(receiver)} #{method} #{process(other)}"
|
140
|
+
when 'include?'
|
141
|
+
"#{process(other)} IN (#{process(receiver)})"
|
142
|
+
when '=~'
|
143
|
+
"#{process(receiver)} LIKE #{process(other)}"
|
144
|
+
when '!~'
|
145
|
+
"#{process(receiver)} NOT LIKE #{process(other)}"
|
146
|
+
else
|
147
|
+
build_condition(receiver, method, other)
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
def build_condition(receiver, method, other)
|
152
|
+
if receiver.first == :call && receiver[1].last == @receiver
|
153
|
+
if reflection = @owner.reflections[receiver.last]
|
154
|
+
@includes << reflection.name unless @includes.include? reflection.name
|
155
|
+
"#{reflection.table_name}.#{method}"
|
156
|
+
else
|
157
|
+
raise "No reflection `#{receiver.last}' found on #{@owner}"
|
158
|
+
end
|
159
|
+
else
|
160
|
+
"#{process(receiver)}.`#{method}` #{process(other)}"
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
##
|
2
|
+
# Taken from ruby2ruby, Copyright (c) 2006 Ryan Davis under the MIT License
|
3
|
+
require 'parse_tree'
|
4
|
+
require 'unique'
|
5
|
+
require 'sexp_processor'
|
6
|
+
|
7
|
+
class Method
|
8
|
+
def with_class_and_method_name
|
9
|
+
if self.inspect =~ /<Method: (.*)\#(.*)>/ then
|
10
|
+
klass = eval $1
|
11
|
+
method = $2.intern
|
12
|
+
raise "Couldn't determine class from #{self.inspect}" if klass.nil?
|
13
|
+
return yield(klass, method)
|
14
|
+
else
|
15
|
+
raise "Can't parse signature: #{self.inspect}"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def to_sexp
|
20
|
+
with_class_and_method_name do |klass, method|
|
21
|
+
ParseTree.new(false).parse_tree_for_method(klass, method)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
class Proc
|
27
|
+
def to_method
|
28
|
+
Unique.send(:define_method, :proc_to_method, self)
|
29
|
+
Unique.new.method(:proc_to_method)
|
30
|
+
end
|
31
|
+
|
32
|
+
def to_sexp
|
33
|
+
body = self.to_method.to_sexp[2][1..-1]
|
34
|
+
[:proc, *body]
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/helper'
|
2
|
+
|
3
|
+
context "Chaining" do
|
4
|
+
specify "should join selects with AND" do
|
5
|
+
sql = User.select { |m| m.name == 'jon' }
|
6
|
+
sql = sql.select { |m| m.age == 22 }
|
7
|
+
sql.to_sql.should == "SELECT * FROM users WHERE users.`name` = 'jon' AND users.`age` = 22"
|
8
|
+
end
|
9
|
+
|
10
|
+
specify "should join sort_bys with a comma" do
|
11
|
+
sql = User.select { |m| m.name == 'jon' }
|
12
|
+
sql = sql.sort_by { |m| m.name }
|
13
|
+
sql = sql.sort_by { |m| m.age }
|
14
|
+
sql.to_sql.should == "SELECT * FROM users WHERE users.`name` = 'jon' ORDER BY users.name, users.age"
|
15
|
+
end
|
16
|
+
|
17
|
+
specify "should join selects and sorts intelligently" do
|
18
|
+
sql = User.select { |m| m.name == 'jon' }
|
19
|
+
sql = sql.select { |m| m.age == 22 }
|
20
|
+
sql = sql.sort_by { |m| -m.name }
|
21
|
+
sql = sql.sort_by { |m| m.age }
|
22
|
+
sql.to_sql.should == "SELECT * FROM users WHERE users.`name` = 'jon' AND users.`age` = 22 ORDER BY users.name DESC, users.age"
|
23
|
+
end
|
24
|
+
|
25
|
+
specify "should join lots of selects and sorts intelligently" do
|
26
|
+
sql = User.select { |m| m.name == 'jon' }
|
27
|
+
sql = sql.select { |m| m.age == 22 }
|
28
|
+
sql = sql.sort_by { |m| m.name }
|
29
|
+
sql = sql.select { |m| m.power == true }
|
30
|
+
sql = sql.sort_by { |m| m.email }
|
31
|
+
sql = sql.select { |m| m.admin == true && m.email == 'chris@ozmm.org' }
|
32
|
+
sql.to_sql.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"
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/helper'
|
2
|
+
|
3
|
+
context "Count" do
|
4
|
+
setup do
|
5
|
+
hash = { :conditions => "users.`name` = 'jon'" }
|
6
|
+
User.expects(:count).with(hash)
|
7
|
+
@sql = User.select { |m| m.name == 'jon' }
|
8
|
+
end
|
9
|
+
|
10
|
+
specify "size" do
|
11
|
+
@sql.size
|
12
|
+
end
|
13
|
+
|
14
|
+
specify "length" do
|
15
|
+
@sql.length
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/helper'
|
2
|
+
|
3
|
+
context "Each" do
|
4
|
+
specify "simple ==" do
|
5
|
+
hash = { :conditions => "users.`age` = 21" }
|
6
|
+
User.expects(:find).with(:all, hash).returns([])
|
7
|
+
User.select { |m| m.age == 21 }.each do |user|
|
8
|
+
puts user.name
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
specify "limit and conditions" do
|
13
|
+
hash = { :limit => '5', :conditions => "users.`age` = 21" }
|
14
|
+
User.expects(:find).with(:all, hash).returns([])
|
15
|
+
User.select { |m| m.age == 21 }.first(5).each do |user|
|
16
|
+
puts user.name
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
specify "limit and conditions and order" do
|
21
|
+
hash = { :limit => '5', :conditions => "users.`age` = 21", :order => 'users.name' }
|
22
|
+
User.expects(:find).with(:all, hash).returns([])
|
23
|
+
User.select { |m| m.age == 21 }.sort_by { |m| m.name }.first(5).each do |user|
|
24
|
+
puts user.name
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
specify "limit and order" do
|
29
|
+
hash = { :limit => '5', :order => 'users.name' }
|
30
|
+
User.expects(:find).with(:all, hash).returns([])
|
31
|
+
User.sort_by { |m| m.name }.first(5).each do |user|
|
32
|
+
puts user.name
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
context "Enumerable Methods" do
|
38
|
+
specify "map" do
|
39
|
+
hash = { :conditions => "users.`age` = 21" }
|
40
|
+
User.expects(:find).with(:all, hash).returns([])
|
41
|
+
User.select { |m| m.age == 21 }.map { |u| u.name }
|
42
|
+
end
|
43
|
+
|
44
|
+
specify "each_with_index" do
|
45
|
+
hash = { :conditions => "users.`age` = 21" }
|
46
|
+
User.expects(:find).with(:all, hash).returns([])
|
47
|
+
User.select { |m| m.age == 21 }.each_with_index do |user, i|
|
48
|
+
puts "#{i}: #{user.name}"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'test/spec'
|
3
|
+
require 'mocha'
|
4
|
+
require 'redgreen'
|
5
|
+
require 'active_support'
|
6
|
+
require 'active_record'
|
7
|
+
|
8
|
+
$:.unshift File.dirname(__FILE__) + '/../lib'
|
9
|
+
require 'ambition'
|
10
|
+
|
11
|
+
class User
|
12
|
+
extend Ambition
|
13
|
+
|
14
|
+
def self.reflections
|
15
|
+
return @reflections if @reflections
|
16
|
+
@reflections = {}
|
17
|
+
@reflections[:ideas] = Reflection.new(:has_many, 'user_id', :ideas, 'ideas')
|
18
|
+
@reflections[:invites] = Reflection.new(:has_many, 'referrer_id', :invites, 'invites')
|
19
|
+
@reflections[:profile] = Reflection.new(:has_one, 'user_id', :profile, 'profiles')
|
20
|
+
@reflections[:account] = Reflection.new(:belongs_to, 'account_id', :account, 'accounts')
|
21
|
+
@reflections
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.table_name
|
25
|
+
'users'
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
class Reflection < Struct.new(:macro, :primary_key_name, :name, :table_name)
|
30
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/helper'
|
2
|
+
|
3
|
+
context "Joins" do
|
4
|
+
specify "simple == on an association" do
|
5
|
+
sql = User.select { |m| m.account.email == 'chris@ozmm.org' }
|
6
|
+
sql.to_hash.should == {
|
7
|
+
:conditions => "accounts.email = 'chris@ozmm.org'",
|
8
|
+
:includes => [:account]
|
9
|
+
}
|
10
|
+
end
|
11
|
+
|
12
|
+
specify "simple mixed == on an association" do
|
13
|
+
sql = User.select { |m| m.name == 'chris' && m.account.email == 'chris@ozmm.org' }
|
14
|
+
sql.to_hash.should == {
|
15
|
+
:conditions => "(users.`name` = 'chris' AND accounts.email = 'chris@ozmm.org')",
|
16
|
+
:includes => [:account]
|
17
|
+
}
|
18
|
+
end
|
19
|
+
|
20
|
+
specify "multiple associations" do
|
21
|
+
sql = User.select { |m| m.ideas.title == 'New Freezer' || m.invites.email == 'pj@hyett.com' }
|
22
|
+
sql.to_hash.should == {
|
23
|
+
:conditions => "(ideas.title = 'New Freezer' OR invites.email = 'pj@hyett.com')",
|
24
|
+
:includes => [:ideas, :invites]
|
25
|
+
}
|
26
|
+
end
|
27
|
+
|
28
|
+
specify "non-existant associations" do
|
29
|
+
sql = User.select { |m| m.liquor.brand == 'Jack' }
|
30
|
+
should.raise { sql.to_hash }
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/helper'
|
2
|
+
|
3
|
+
context "Limit" do
|
4
|
+
setup do
|
5
|
+
@sql = User.select { |m| m.name == 'jon' }
|
6
|
+
end
|
7
|
+
|
8
|
+
specify "first" do
|
9
|
+
conditions = { :conditions => "users.`name` = 'jon'", :limit => '1' }
|
10
|
+
User.expects(:find).with(:first, conditions)
|
11
|
+
@sql.first
|
12
|
+
end
|
13
|
+
|
14
|
+
specify "first with argument" do
|
15
|
+
conditions = { :conditions => "users.`name` = 'jon'", :limit => '5' }
|
16
|
+
User.expects(:find).with(:all, conditions)
|
17
|
+
@sql.first(5)
|
18
|
+
end
|
19
|
+
|
20
|
+
specify "[] with one element" do
|
21
|
+
conditions = { :conditions => "users.`name` = 'jon'", :limit => '10, 1' }
|
22
|
+
User.expects(:find).with(:all, conditions)
|
23
|
+
@sql[10]
|
24
|
+
end
|
25
|
+
|
26
|
+
specify "[] with two elements" do
|
27
|
+
conditions = { :conditions => "users.`name` = 'jon'", :limit => '10, 20' }
|
28
|
+
User.expects(:find).with(:all, conditions)
|
29
|
+
@sql[10, 20]
|
30
|
+
end
|
31
|
+
|
32
|
+
specify "[] with range" do
|
33
|
+
conditions = { :conditions => "users.`name` = 'jon'", :limit => '10, 10' }
|
34
|
+
User.expects(:find).with(:all, conditions)
|
35
|
+
@sql[10..20]
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/helper'
|
2
|
+
|
3
|
+
context "Order" do
|
4
|
+
setup do
|
5
|
+
@sql = User.select { |m| m.name == 'jon' }
|
6
|
+
end
|
7
|
+
|
8
|
+
specify "simple order" do
|
9
|
+
string = @sql.sort_by { |m| m.name }.to_sql
|
10
|
+
string.should == "SELECT * FROM users WHERE users.`name` = 'jon' ORDER BY users.name"
|
11
|
+
end
|
12
|
+
|
13
|
+
specify "simple combined order" do
|
14
|
+
string = @sql.sort_by { |m| [ m.name, m.age ] }.to_sql
|
15
|
+
string.should == "SELECT * FROM users WHERE users.`name` = 'jon' ORDER BY users.name, users.age"
|
16
|
+
end
|
17
|
+
|
18
|
+
specify "simple combined order with single reverse" do
|
19
|
+
string = @sql.sort_by { |m| [ m.name, -m.age ] }.to_sql
|
20
|
+
string.should == "SELECT * FROM users WHERE users.`name` = 'jon' ORDER BY users.name, users.age DESC"
|
21
|
+
end
|
22
|
+
|
23
|
+
specify "simple combined order with two reverses" do
|
24
|
+
string = @sql.sort_by { |m| [ -m.name, -m.age ] }.to_sql
|
25
|
+
string.should == "SELECT * FROM users WHERE users.`name` = 'jon' ORDER BY users.name DESC, users.age DESC"
|
26
|
+
end
|
27
|
+
|
28
|
+
specify "reverse order with -" do
|
29
|
+
string = @sql.sort_by { |m| -m.age }.to_sql
|
30
|
+
string.should == "SELECT * FROM users WHERE users.`name` = 'jon' ORDER BY users.age DESC"
|
31
|
+
end
|
32
|
+
|
33
|
+
xspecify "reverse order with #reverse" do
|
34
|
+
# TODO: not implemented
|
35
|
+
string = @sql.sort_by { |m| m.age }.reverse.to_sql
|
36
|
+
string.should == "SELECT * FROM users WHERE users.`name` = 'jon' ORDER BY users.age DESC"
|
37
|
+
end
|
38
|
+
|
39
|
+
specify "random order" do
|
40
|
+
string = @sql.sort_by { rand }.to_sql
|
41
|
+
string.should == "SELECT * FROM users WHERE users.`name` = 'jon' ORDER BY RAND()"
|
42
|
+
end
|
43
|
+
|
44
|
+
specify "Symbol#to_proc" do
|
45
|
+
string = User.sort_by(&:name).to_sql
|
46
|
+
string.should == "SELECT * FROM users ORDER BY users.name"
|
47
|
+
end
|
48
|
+
end
|