ambition 0.2.2 → 0.3.1

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.
data/Manifest CHANGED
@@ -4,6 +4,7 @@
4
4
  ./lib/ambition/proc_to_ruby.rb
5
5
  ./lib/ambition/processor.rb
6
6
  ./lib/ambition/query.rb
7
+ ./lib/ambition/ruby_processor.rb
7
8
  ./lib/ambition/select_processor.rb
8
9
  ./lib/ambition/simple_processor.rb
9
10
  ./lib/ambition/sort_processor.rb
@@ -42,5 +43,6 @@
42
43
  ./test/order_test.rb
43
44
  ./test/profiler.rb
44
45
  ./test/source_test.rb
46
+ ./test/ruby_test.rb
45
47
  ./test/types_test.rb
46
48
  ./test/where_test.rb
data/README CHANGED
@@ -59,21 +59,13 @@ See, +to_hash+:
59
59
  >> User.select { |m| m.name == 'jon' }.to_hash
60
60
  => {:conditions=>"users.name = 'jon'"}
61
61
 
62
- == Limitations
63
-
64
- You can use variables, but any more complex Ruby (right now) won't work
65
- inside your blocks. Just do it outside the block and assign it to a variable.
66
-
67
- Instead of:
68
- User.select { |m| m.date == 2.days.ago }
69
-
70
- Just do:
71
- date = 2.days.ago
72
- User.select { |m| m.date == date }
62
+ == Equality -- select { |u| u.field == 'bob' }
73
63
 
74
- Instance variables and globals work, too. Same with method calls.
64
+ User.select { |m| m.name == 'jon' }
65
+ "SELECT * FROM users WHERE users.name = 'jon'"
75
66
 
76
- == Equality -- select { |u| u.field == 'bob' }
67
+ User.select { |m| m.created_at > 2.days.ago }
68
+ "SELECT * FROM users WHERE users.created_at > '2007-09-26 20:37:47'"
77
69
 
78
70
  User.select { |m| m.name == 'jon' }
79
71
  "SELECT * FROM users WHERE users.name = 'jon'"
@@ -208,4 +200,8 @@ Found a bug? Sweet. Add it at the Lighthouse:
208
200
 
209
201
  Feature requests are welcome.
210
202
 
203
+ And hey, join our mailing list!
204
+
205
+ http://groups.google.com/group/ambition-rb
206
+
211
207
  * Chris Wanstrath [ chris@ozmm.org ]
data/Rakefile CHANGED
@@ -2,19 +2,18 @@ require 'rake'
2
2
  require 'rake/testtask'
3
3
  require 'rake/rdoctask'
4
4
 
5
- Version = '0.2.2'
5
+ Version = '0.3.1'
6
6
 
7
7
  module Rake::TaskManager
8
- def redefine_task(task_class, args, &block)
8
+ def delete_task(task_class, args, &block)
9
9
  task_name, deps = resolve_args(args)
10
10
  @tasks.delete(task_class.scope_name(@scope, task_name).to_s)
11
- define_task(task_class, args, &block)
12
11
  end
13
12
  end
14
13
  class Rake::Task
15
- def self.redefine_task(args, &block) Rake.application.redefine_task(self, args, &block) end
14
+ def self.delete_task(args, &block) Rake.application.delete_task(self, args, &block) end
16
15
  end
17
- def redefine_task(args, &block) Rake::Task.redefine_task(args, &block) end
16
+ def delete_task(args, &block) Rake::Task.delete_task(args, &block) end
18
17
 
19
18
  begin
20
19
  require 'rubygems'
@@ -30,6 +29,7 @@ begin
30
29
  p.author = 'Chris Wanstrath'
31
30
  p.email = "chris@ozmm.org"
32
31
  p.extra_deps << ['ParseTree', '=2.0.1']
32
+ p.extra_deps << ['ruby2ruby', '=1.1.7']
33
33
  p.extra_deps << ['activerecord', '>=1.15.0']
34
34
  p.test_globs = 'test/*_test.rb'
35
35
  end
@@ -37,7 +37,7 @@ begin
37
37
  rescue LoadError
38
38
  end
39
39
 
40
- redefine_task(:test) { }
40
+ delete_task :test
41
41
 
42
42
  Rake::TestTask.new('test') do |t|
43
43
  t.pattern = 'test/*_test.rb'
@@ -5,6 +5,7 @@ end
5
5
  require 'ambition/api'
6
6
  require 'ambition/source'
7
7
  require 'ambition/processor'
8
+ require 'ambition/ruby_processor'
8
9
  require 'ambition/select_processor'
9
10
  require 'ambition/sort_processor'
10
11
  require 'ambition/simple_processor'
@@ -1,6 +1,7 @@
1
1
  ##
2
2
  # Taken from ruby2ruby, Copyright (c) 2006 Ryan Davis under the MIT License
3
3
  require 'parse_tree'
4
+ require 'ruby2ruby'
4
5
 
5
6
  class ProcHolder
6
7
  end
@@ -14,23 +14,31 @@ module Ambition
14
14
 
15
15
  ##
16
16
  # Processing methods
17
- def process_error(exp)
18
- raise "Missing process method for sexp: #{exp.inspect}"
19
- end
20
-
21
17
  def process_proc(exp)
22
18
  receiver, body = process(exp.shift), exp.shift
23
- return process(body)
19
+ process(body)
24
20
  end
25
21
 
26
22
  def process_dasgn_curr(exp)
27
- @receiver = exp.shift
28
- return @receiver.to_s
23
+ @receiver = exp.first
24
+ @receiver.to_s
29
25
  end
26
+ alias_method :process_dasgn, :process_dasgn_curr
30
27
 
31
28
  def process_array(exp)
32
- arrayed = exp.map { |m| process(m) }
33
- return arrayed.join(', ')
29
+ # Branch on whether this is straight Ruby or a real array
30
+ if ruby = rubify(exp)
31
+ value ruby
32
+ else
33
+ arrayed = exp.map { |m| process(m) }
34
+ arrayed.join(', ')
35
+ end
36
+ end
37
+
38
+ def rubify(exp)
39
+ if exp.first.first == :call && exp.first[1].last != @receiver && Array(exp.first[1][1]).last != @receiver
40
+ RubyProcessor.process(exp.first)
41
+ end
34
42
  end
35
43
 
36
44
  ##
@@ -39,6 +47,10 @@ module Ambition
39
47
  process(@block.to_sexp).squeeze(' ')
40
48
  end
41
49
 
50
+ def value(variable)
51
+ sanitize eval(variable, @block)
52
+ end
53
+
42
54
  def sanitize(value)
43
55
  if value.is_a? Array
44
56
  return value.map { |v| sanitize(v) }.join(', ')
@@ -98,7 +110,14 @@ module Ambition
98
110
 
99
111
  def process(node)
100
112
  node ||= []
101
- respond_to?(method = "process_#{node.shift}") ? send(method, node) : ''
113
+
114
+ if respond_to?(method = "process_#{node.first}")
115
+ send(method, node[1..-1])
116
+ elsif node.blank?
117
+ ''
118
+ else
119
+ raise "Missing process method for sexp: #{node.inspect}"
120
+ end
102
121
  end
103
122
  end
104
123
  end
@@ -58,12 +58,13 @@ module Ambition
58
58
  def to_s
59
59
  hash = keyed_clauses
60
60
 
61
+ raise "Sorry, I can't construct SQL with complex joins (yet)" unless hash[:includes].blank?
62
+
61
63
  sql = []
62
- sql << "JOIN #{hash[:includes].join(', ')}" unless hash[:includes].blank?
63
64
  sql << "WHERE #{hash[:conditions].join(' AND ')}" unless hash[:conditions].blank?
64
65
  sql << "ORDER BY #{hash[:order].join(', ')}" unless hash[:order].blank?
65
66
  sql << "LIMIT #{hash[:limit]}" unless hash[:limit].blank?
66
- sql << "OFFSET #{hash[:limit]}" unless hash[:offset].blank?
67
+ sql << "OFFSET #{hash[:offset]}" unless hash[:offset].blank?
67
68
 
68
69
  @@select % [ @table_name, sql.join(' ') ]
69
70
  end
@@ -0,0 +1,22 @@
1
+ module Ambition
2
+ class RubyProcessor < RubyToRuby
3
+ def self.process(node)
4
+ @processor ||= new
5
+ @processor.process node
6
+ end
7
+
8
+ ##
9
+ # This is not DRY, and I don't care.
10
+ def process(node)
11
+ node ||= []
12
+
13
+ if respond_to?(method = "process_#{node.first}")
14
+ send(method, node[1..-1])
15
+ elsif node.blank?
16
+ ''
17
+ else
18
+ raise "Missing process method for sexp: #{node.inspect}"
19
+ end
20
+ end
21
+ end
22
+ end
@@ -103,10 +103,6 @@ module Ambition
103
103
  "(" + clauses.map { |c| process(c) }.join(" #{with} ") + ")"
104
104
  end
105
105
 
106
- def value(variable)
107
- sanitize eval(variable, @block)
108
- end
109
-
110
106
  def negate(method, target = nil)
111
107
  if Array(target).last == [:nil]
112
108
  return 'IS NOT'
@@ -30,6 +30,12 @@ Benchmark.bm(30) do |x|
30
30
  end
31
31
  end
32
32
 
33
+ x.report 'simple select w/ eval' do
34
+ Times.times do
35
+ User.select { |u| u.created_at == Time.now }.to_hash
36
+ end
37
+ end
38
+
33
39
  x.report 'dual select' do
34
40
  Times.times do
35
41
  User.select { |u| u.id == 20 && u.age > 20 }.to_hash
@@ -25,6 +25,19 @@ context "Joins" do
25
25
  }
26
26
  end
27
27
 
28
+ specify "belongs_to" do
29
+ sql = User.select { |m| m.account.id > 20 }
30
+ sql.to_hash.should == {
31
+ :conditions => "accounts.id > 20",
32
+ :include => [:account]
33
+ }
34
+ end
35
+
36
+ specify "complex joins have no to_s" do
37
+ sql = User.select { |m| m.account.id > 20 }
38
+ should.raise { sql.to_s }
39
+ end
40
+
28
41
  specify "non-existant associations" do
29
42
  sql = User.select { |m| m.liquor.brand == 'Jack' }
30
43
  should.raise { sql.to_hash }
@@ -0,0 +1,9 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ context "Inline Ruby" do
4
+ xspecify "should know what to return" do
5
+ name = 'David'
6
+ sql = User.select { |u| name.nil? || u.name == name }.to_s
7
+ sql.should == "SELECT * FROM users WHERE (users.name = 'David')"
8
+ end
9
+ end
@@ -52,9 +52,8 @@ context "Different types" do
52
52
  sql.should == "SELECT * FROM users WHERE users.name IS NOT NULL"
53
53
  end
54
54
 
55
- xspecify "Time" do
56
- # TODO: nothing but variables inside blocks for now
55
+ specify "Time" do
57
56
  sql = User.select { |m| m.name == Time.now }.to_sql
58
- sql.should == "SELECT * FROM users WHERE users.name = NULL"
57
+ sql.should == "SELECT * FROM users WHERE users.name = '#{Time.now.to_s(:db)}'"
59
58
  end
60
59
  end
@@ -74,7 +74,7 @@ context "Where (using select)" do
74
74
  sql.should == "SELECT * FROM users WHERE users.name = '#{@me}'"
75
75
  end
76
76
 
77
- xspecify "simple == with instance variable method call" do
77
+ specify "simple == with instance variable method call" do
78
78
  require 'ostruct'
79
79
  @person = OpenStruct.new(:name => 'chris')
80
80
 
@@ -136,11 +136,15 @@ context "Where (using select)" do
136
136
  specify "undefined equality symbol" do
137
137
  should.raise { User.select { |m| m.name =* /chris/ }.to_sql }
138
138
  end
139
+
140
+ specify "block variable / assigning variable conflict" do
141
+ m = User.select { |m| m.name == 'chris' }.to_sql
142
+ m.should == "SELECT * FROM users WHERE users.name = 'chris'"
143
+ end
139
144
 
140
- xspecify "simple == with inline ruby" do
141
- # TODO: implement this
145
+ specify "simple == with inline ruby" do
142
146
  sql = User.select { |m| m.created_at == 2.days.ago.to_s(:db) }.to_sql
143
- sql.should == "SELECT * FROM users WHERE users.created_at = #{2.days.ago.to_s(:db)}"
147
+ sql.should == "SELECT * FROM users WHERE users.created_at = '#{2.days.ago.to_s(:db)}'"
144
148
  end
145
149
 
146
150
  specify "inspect" do
metadata CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.0
3
3
  specification_version: 1
4
4
  name: ambition
5
5
  version: !ruby/object:Gem::Version
6
- version: 0.2.2
7
- date: 2007-09-11 00:00:00 -07:00
6
+ version: 0.3.1
7
+ date: 2007-11-06 00:00:00 -08:00
8
8
  summary: Ambition builds SQL from plain jane Ruby.
9
9
  require_paths:
10
10
  - lib
@@ -35,6 +35,7 @@ files:
35
35
  - ./lib/ambition/proc_to_ruby.rb
36
36
  - ./lib/ambition/processor.rb
37
37
  - ./lib/ambition/query.rb
38
+ - ./lib/ambition/ruby_processor.rb
38
39
  - ./lib/ambition/select_processor.rb
39
40
  - ./lib/ambition/simple_processor.rb
40
41
  - ./lib/ambition/sort_processor.rb
@@ -73,6 +74,7 @@ files:
73
74
  - ./test/order_test.rb
74
75
  - ./test/profiler.rb
75
76
  - ./test/source_test.rb
77
+ - ./test/ruby_test.rb
76
78
  - ./test/types_test.rb
77
79
  - ./test/where_test.rb
78
80
  test_files:
@@ -82,6 +84,7 @@ test_files:
82
84
  - test/join_test.rb
83
85
  - test/limit_test.rb
84
86
  - test/order_test.rb
87
+ - test/ruby_test.rb
85
88
  - test/source_test.rb
86
89
  - test/types_test.rb
87
90
  - test/where_test.rb
@@ -105,6 +108,15 @@ dependencies:
105
108
  - !ruby/object:Gem::Version
106
109
  version: 2.0.1
107
110
  version:
111
+ - !ruby/object:Gem::Dependency
112
+ name: ruby2ruby
113
+ version_requirement:
114
+ version_requirements: !ruby/object:Gem::Version::Requirement
115
+ requirements:
116
+ - - "="
117
+ - !ruby/object:Gem::Version
118
+ version: 1.1.7
119
+ version:
108
120
  - !ruby/object:Gem::Dependency
109
121
  name: activerecord
110
122
  version_requirement: