ambition 0.3.1 → 0.5.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.
- data/Manifest +41 -48
 - data/README +6 -203
 - data/ambition.gemspec +111 -0
 - data/app_generators/ambition_adapter/USAGE +1 -0
 - data/app_generators/ambition_adapter/ambition_adapter_generator.rb +66 -0
 - data/app_generators/ambition_adapter/templates/LICENSE +18 -0
 - data/app_generators/ambition_adapter/templates/README +6 -0
 - data/app_generators/ambition_adapter/templates/Rakefile +31 -0
 - data/app_generators/ambition_adapter/templates/lib/base.rb.erb +12 -0
 - data/app_generators/ambition_adapter/templates/lib/init.rb.erb +22 -0
 - data/app_generators/ambition_adapter/templates/lib/query.rb.erb +52 -0
 - data/app_generators/ambition_adapter/templates/lib/select.rb.erb +100 -0
 - data/app_generators/ambition_adapter/templates/lib/slice.rb.erb +19 -0
 - data/app_generators/ambition_adapter/templates/lib/sort.rb.erb +43 -0
 - data/app_generators/ambition_adapter/templates/test/helper.rb.erb +9 -0
 - data/app_generators/ambition_adapter/templates/test/select_test.rb.erb +157 -0
 - data/app_generators/ambition_adapter/templates/test/slice_test.rb.erb +36 -0
 - data/app_generators/ambition_adapter/templates/test/sort_test.rb.erb +53 -0
 - data/bin/ambition_adapter +13 -0
 - data/lib/ambition.rb +8 -13
 - data/lib/ambition/api.rb +42 -35
 - data/lib/ambition/context.rb +62 -0
 - data/lib/ambition/{proc_to_ruby.rb → core_ext.rb} +13 -0
 - data/lib/ambition/enumerable.rb +6 -0
 - data/lib/ambition/processors/base.rb +126 -0
 - data/lib/ambition/processors/ruby.rb +24 -0
 - data/lib/ambition/processors/select.rb +105 -0
 - data/lib/ambition/processors/slice.rb +15 -0
 - data/lib/ambition/processors/sort.rb +51 -0
 - data/test/adapters/exemplar/association_test.rb +34 -0
 - data/test/adapters/exemplar/count_test.rb +0 -0
 - data/test/adapters/exemplar/detect_test.rb +9 -0
 - data/test/adapters/exemplar/enumerable_test.rb +0 -0
 - data/test/adapters/exemplar/helper.rb +3 -0
 - data/test/adapters/exemplar/index_operator.rb +6 -0
 - data/test/adapters/exemplar/reject_test.rb +0 -0
 - data/test/adapters/exemplar/select_test.rb +151 -0
 - data/test/adapters/exemplar/slice_test.rb +0 -0
 - data/test/adapters/exemplar/sort_test.rb +0 -0
 - data/test/debug +9 -0
 - data/test/helper.rb +2 -52
 - metadata +56 -71
 - data/Rakefile +0 -64
 - data/init.rb +0 -1
 - data/lib/ambition/database_statements.rb +0 -31
 - data/lib/ambition/processor.rb +0 -123
 - data/lib/ambition/query.rb +0 -91
 - data/lib/ambition/ruby_processor.rb +0 -22
 - data/lib/ambition/select_processor.rb +0 -149
 - data/lib/ambition/simple_processor.rb +0 -10
 - data/lib/ambition/sort_processor.rb +0 -47
 - data/lib/ambition/source.rb +0 -53
 - data/test/benchmark.rb +0 -68
 - data/test/chaining_test.rb +0 -34
 - data/test/console +0 -9
 - data/test/count_test.rb +0 -17
 - data/test/databases/boot.rb +0 -3
 - data/test/databases/database.yml +0 -17
 - data/test/databases/fixtures/admin.rb +0 -3
 - data/test/databases/fixtures/companies.yml +0 -24
 - data/test/databases/fixtures/company.rb +0 -23
 - data/test/databases/fixtures/developer.rb +0 -11
 - data/test/databases/fixtures/developers_projects.yml +0 -13
 - data/test/databases/fixtures/project.rb +0 -4
 - data/test/databases/fixtures/projects.yml +0 -7
 - data/test/databases/fixtures/replies.yml +0 -20
 - data/test/databases/fixtures/reply.rb +0 -5
 - data/test/databases/fixtures/topic.rb +0 -19
 - data/test/databases/fixtures/topics.yml +0 -32
 - data/test/databases/fixtures/user.rb +0 -2
 - data/test/databases/fixtures/users.yml +0 -35
 - data/test/databases/lib/activerecord_test_connector.rb +0 -65
 - data/test/databases/lib/load_fixtures.rb +0 -13
 - data/test/databases/lib/schema.rb +0 -41
 - data/test/enumerable_test.rb +0 -95
 - data/test/join_test.rb +0 -61
 - data/test/limit_test.rb +0 -41
 - data/test/order_test.rb +0 -52
 - data/test/profiler.rb +0 -34
 - data/test/ruby_test.rb +0 -9
 - data/test/source_test.rb +0 -43
 - data/test/types_test.rb +0 -59
 - data/test/where_test.rb +0 -245
 
| 
         @@ -0,0 +1,36 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require File.dirname(__FILE__) + '/helper'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            context "<%= adapter_module %> Adapter :: Slice" do
         
     | 
| 
      
 4 
     | 
    
         
            +
              setup do
         
     | 
| 
      
 5 
     | 
    
         
            +
                @klass = User
         
     | 
| 
      
 6 
     | 
    
         
            +
                @block = @klass.select { |m| m.name == 'jon' }
         
     | 
| 
      
 7 
     | 
    
         
            +
              end
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
              xspecify "first" do
         
     | 
| 
      
 10 
     | 
    
         
            +
                @klass.expects(:find).with(:limit => 1, :name => 'jon')
         
     | 
| 
      
 11 
     | 
    
         
            +
                @block.first
         
     | 
| 
      
 12 
     | 
    
         
            +
              end
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
              xspecify "first with argument" do
         
     | 
| 
      
 15 
     | 
    
         
            +
                @klass.expects(:find).with(:limit => 5, :name => 'jon')
         
     | 
| 
      
 16 
     | 
    
         
            +
                @block.first(5).entries
         
     | 
| 
      
 17 
     | 
    
         
            +
              end
         
     | 
| 
      
 18 
     | 
    
         
            +
              
         
     | 
| 
      
 19 
     | 
    
         
            +
              xspecify "[] with two elements" do
         
     | 
| 
      
 20 
     | 
    
         
            +
                @klass.expects(:find).with(:limit => 20, :offset => 10, :name => 'jon')
         
     | 
| 
      
 21 
     | 
    
         
            +
                @block[10, 20].entries
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                @klass.expects(:find).with(:limit => 20, :offset => 20, :name => 'jon')
         
     | 
| 
      
 24 
     | 
    
         
            +
                @block[20, 20].entries
         
     | 
| 
      
 25 
     | 
    
         
            +
              end
         
     | 
| 
      
 26 
     | 
    
         
            +
              
         
     | 
| 
      
 27 
     | 
    
         
            +
              xspecify "slice is an alias of []" do
         
     | 
| 
      
 28 
     | 
    
         
            +
                @klass.expects(:find).with(:limit => 20, :offset => 10, :name => 'jon')
         
     | 
| 
      
 29 
     | 
    
         
            +
                @block.slice(10, 20).entries
         
     | 
| 
      
 30 
     | 
    
         
            +
              end
         
     | 
| 
      
 31 
     | 
    
         
            +
              
         
     | 
| 
      
 32 
     | 
    
         
            +
              xspecify "[] with range" do
         
     | 
| 
      
 33 
     | 
    
         
            +
                @klass.expects(:find).with(:limit => 10, :offset => 10, :name => 'jon')
         
     | 
| 
      
 34 
     | 
    
         
            +
                @block[11..20].entries
         
     | 
| 
      
 35 
     | 
    
         
            +
              end
         
     | 
| 
      
 36 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,53 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require File.dirname(__FILE__) + '/helper'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            context "<%= adapter_module %> Adapter :: Sort" do
         
     | 
| 
      
 4 
     | 
    
         
            +
              setup do
         
     | 
| 
      
 5 
     | 
    
         
            +
                @klass = User
         
     | 
| 
      
 6 
     | 
    
         
            +
                @block = @klass.select { |m| m.name == 'jon' }
         
     | 
| 
      
 7 
     | 
    
         
            +
              end
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
              xspecify "order" do
         
     | 
| 
      
 10 
     | 
    
         
            +
                string = @block.sort_by { |m| m.name }.to_s
         
     | 
| 
      
 11 
     | 
    
         
            +
                string.should == "foo"
         
     | 
| 
      
 12 
     | 
    
         
            +
              end
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
              xspecify "combined order" do
         
     | 
| 
      
 15 
     | 
    
         
            +
                string = @block.sort_by { |m| [ m.name,  m.age ] }.to_s
         
     | 
| 
      
 16 
     | 
    
         
            +
                string.should == "foo"
         
     | 
| 
      
 17 
     | 
    
         
            +
              end
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
              xspecify "combined order with single reverse" do
         
     | 
| 
      
 20 
     | 
    
         
            +
                string = @block.sort_by { |m| [ m.name,  -m.age ] }.to_s
         
     | 
| 
      
 21 
     | 
    
         
            +
                string.should == "foo"
         
     | 
| 
      
 22 
     | 
    
         
            +
              end
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
              xspecify "combined order with two reverses" do
         
     | 
| 
      
 25 
     | 
    
         
            +
                string = @block.sort_by { |m| [ -m.name,  -m.age ] }.to_s
         
     | 
| 
      
 26 
     | 
    
         
            +
                string.should == "foo"
         
     | 
| 
      
 27 
     | 
    
         
            +
              end
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
              xspecify "reverse order with -" do
         
     | 
| 
      
 30 
     | 
    
         
            +
                string = @block.sort_by { |m| -m.age }.to_s
         
     | 
| 
      
 31 
     | 
    
         
            +
                string.should == "foo"
         
     | 
| 
      
 32 
     | 
    
         
            +
              end
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
              xspecify "reverse order with #reverse" do
         
     | 
| 
      
 35 
     | 
    
         
            +
                # TODO: not implemented
         
     | 
| 
      
 36 
     | 
    
         
            +
                string = @block.sort_by { |m| m.age }.reverse.to_s
         
     | 
| 
      
 37 
     | 
    
         
            +
                string.should == "foo"
         
     | 
| 
      
 38 
     | 
    
         
            +
              end
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
              xspecify "random order" do
         
     | 
| 
      
 41 
     | 
    
         
            +
                string = @block.sort_by { rand }.to_s
         
     | 
| 
      
 42 
     | 
    
         
            +
                string.should == "foo"
         
     | 
| 
      
 43 
     | 
    
         
            +
              end
         
     | 
| 
      
 44 
     | 
    
         
            +
              
         
     | 
| 
      
 45 
     | 
    
         
            +
              xspecify "non-existent method to sort by" do
         
     | 
| 
      
 46 
     | 
    
         
            +
                should.raise(NoMethodError) { @block.sort_by { foo }.to_s }
         
     | 
| 
      
 47 
     | 
    
         
            +
              end
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
              xspecify "Symbol#to_proc" do
         
     | 
| 
      
 50 
     | 
    
         
            +
                string = @klass.sort_by(&:name).to_s
         
     | 
| 
      
 51 
     | 
    
         
            +
                string.should == "foo"
         
     | 
| 
      
 52 
     | 
    
         
            +
              end
         
     | 
| 
      
 53 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,13 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            #!/usr/bin/env ruby
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'rubygems'
         
     | 
| 
      
 3 
     | 
    
         
            +
            require 'rubigen'
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            if %w(-v --version).include? ARGV.first
         
     | 
| 
      
 6 
     | 
    
         
            +
              version = File.read('./Rakefile').scan(/Version = '(.+)'/).first.first
         
     | 
| 
      
 7 
     | 
    
         
            +
              puts "#{File.basename($0)} #{version}"
         
     | 
| 
      
 8 
     | 
    
         
            +
              exit(0)
         
     | 
| 
      
 9 
     | 
    
         
            +
            end
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
            require 'rubigen/scripts/generate'
         
     | 
| 
      
 12 
     | 
    
         
            +
            RubiGen::Base.use_application_sources! :ambition_adapter
         
     | 
| 
      
 13 
     | 
    
         
            +
            RubiGen::Scripts::Generate.new.run(ARGV, :generator => 'ambition_adapter')
         
     | 
    
        data/lib/ambition.rb
    CHANGED
    
    | 
         @@ -1,15 +1,10 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
             
     | 
| 
       2 
     | 
    
         
            -
              require 'rubygems'
         
     | 
| 
       3 
     | 
    
         
            -
              require 'active_record' 
         
     | 
| 
       4 
     | 
    
         
            -
            end
         
     | 
| 
      
 1 
     | 
    
         
            +
            require 'ambition/enumerable'
         
     | 
| 
       5 
2 
     | 
    
         
             
            require 'ambition/api'
         
     | 
| 
       6 
     | 
    
         
            -
            require 'ambition/ 
     | 
| 
       7 
     | 
    
         
            -
            require 'ambition/ 
     | 
| 
       8 
     | 
    
         
            -
            require 'ambition/ruby_processor'
         
     | 
| 
       9 
     | 
    
         
            -
            require 'ambition/select_processor'
         
     | 
| 
       10 
     | 
    
         
            -
            require 'ambition/sort_processor'
         
     | 
| 
       11 
     | 
    
         
            -
            require 'ambition/simple_processor'
         
     | 
| 
       12 
     | 
    
         
            -
            require 'ambition/query'
         
     | 
| 
       13 
     | 
    
         
            -
            require 'ambition/database_statements'
         
     | 
| 
      
 3 
     | 
    
         
            +
            require 'ambition/context'
         
     | 
| 
      
 4 
     | 
    
         
            +
            require 'ambition/core_ext'
         
     | 
| 
       14 
5 
     | 
    
         | 
| 
       15 
     | 
    
         
            -
             
     | 
| 
      
 6 
     | 
    
         
            +
            require 'ambition/processors/base'
         
     | 
| 
      
 7 
     | 
    
         
            +
            require 'ambition/processors/select'
         
     | 
| 
      
 8 
     | 
    
         
            +
            require 'ambition/processors/sort'
         
     | 
| 
      
 9 
     | 
    
         
            +
            require 'ambition/processors/slice'
         
     | 
| 
      
 10 
     | 
    
         
            +
            require 'ambition/processors/ruby'
         
     | 
    
        data/lib/ambition/api.rb
    CHANGED
    
    | 
         @@ -2,57 +2,43 @@ module Ambition 
     | 
|
| 
       2 
2 
     | 
    
         
             
              module API
         
     | 
| 
       3 
3 
     | 
    
         
             
                include Enumerable
         
     | 
| 
       4 
4 
     | 
    
         | 
| 
       5 
     | 
    
         
            -
                 
     | 
| 
       6 
     | 
    
         
            -
                 
     | 
| 
       7 
     | 
    
         
            -
             
     | 
| 
      
 5 
     | 
    
         
            +
                ##
         
     | 
| 
      
 6 
     | 
    
         
            +
                # Entry methods
         
     | 
| 
      
 7 
     | 
    
         
            +
                def select(&block)
         
     | 
| 
      
 8 
     | 
    
         
            +
                  context = ambition_context 
         
     | 
| 
      
 9 
     | 
    
         
            +
                  context << Processors::Select.new(context, block)
         
     | 
| 
       8 
10 
     | 
    
         
             
                end
         
     | 
| 
       9 
11 
     | 
    
         | 
| 
       10 
     | 
    
         
            -
                def  
     | 
| 
       11 
     | 
    
         
            -
                   
     | 
| 
      
 12 
     | 
    
         
            +
                def sort_by(&block)
         
     | 
| 
      
 13 
     | 
    
         
            +
                  context = ambition_context 
         
     | 
| 
      
 14 
     | 
    
         
            +
                  context << Processors::Sort.new(context, block)
         
     | 
| 
       12 
15 
     | 
    
         
             
                end
         
     | 
| 
       13 
     | 
    
         
            -
                alias_method :to_a, :entries
         
     | 
| 
       14 
16 
     | 
    
         | 
| 
       15 
     | 
    
         
            -
                def  
     | 
| 
       16 
     | 
    
         
            -
                   
     | 
| 
      
 17 
     | 
    
         
            +
                def entries
         
     | 
| 
      
 18 
     | 
    
         
            +
                  ambition_context.kick
         
     | 
| 
       17 
19 
     | 
    
         
             
                end
         
     | 
| 
      
 20 
     | 
    
         
            +
                alias_method :to_a, :entries
         
     | 
| 
       18 
21 
     | 
    
         | 
| 
       19 
     | 
    
         
            -
                def  
     | 
| 
       20 
     | 
    
         
            -
                   
     | 
| 
       21 
     | 
    
         
            -
             
     | 
| 
       22 
     | 
    
         
            -
                  if limit == 1
         
     | 
| 
       23 
     | 
    
         
            -
                    find(:first, query_context.to_hash)
         
     | 
| 
       24 
     | 
    
         
            -
                  else
         
     | 
| 
       25 
     | 
    
         
            -
                    query_context
         
     | 
| 
       26 
     | 
    
         
            -
                  end
         
     | 
| 
      
 22 
     | 
    
         
            +
                def size
         
     | 
| 
      
 23 
     | 
    
         
            +
                  ambition_context.size
         
     | 
| 
       27 
24 
     | 
    
         
             
                end
         
     | 
| 
       28 
25 
     | 
    
         | 
| 
       29 
     | 
    
         
            -
                def slice( 
     | 
| 
       30 
     | 
    
         
            -
                   
     | 
| 
       31 
     | 
    
         
            -
             
     | 
| 
       32 
     | 
    
         
            -
                    limit -= 1 if offset.exclude_end?
         
     | 
| 
       33 
     | 
    
         
            -
                    offset = offset.first
         
     | 
| 
       34 
     | 
    
         
            -
                    limit -= offset
         
     | 
| 
       35 
     | 
    
         
            -
                  elsif limit.nil?
         
     | 
| 
       36 
     | 
    
         
            -
                    return find(offset)
         
     | 
| 
       37 
     | 
    
         
            -
                  end
         
     | 
| 
       38 
     | 
    
         
            -
             
     | 
| 
       39 
     | 
    
         
            -
                  query_context.add SimpleProcessor.new(:offset => offset)
         
     | 
| 
       40 
     | 
    
         
            -
                  query_context.add SimpleProcessor.new(:limit  => limit)
         
     | 
| 
      
 26 
     | 
    
         
            +
                def slice(start, length = nil)
         
     | 
| 
      
 27 
     | 
    
         
            +
                  context = ambition_context 
         
     | 
| 
      
 28 
     | 
    
         
            +
                  context << Processors::Slice.new(context, start, length)
         
     | 
| 
       41 
29 
     | 
    
         
             
                end
         
     | 
| 
       42 
30 
     | 
    
         
             
                alias_method :[], :slice
         
     | 
| 
       43 
31 
     | 
    
         | 
| 
       44 
     | 
    
         
            -
                 
     | 
| 
       45 
     | 
    
         
            -
             
     | 
| 
       46 
     | 
    
         
            -
                end
         
     | 
| 
       47 
     | 
    
         
            -
             
     | 
| 
      
 32 
     | 
    
         
            +
                ##
         
     | 
| 
      
 33 
     | 
    
         
            +
                # Convenience methods
         
     | 
| 
       48 
34 
     | 
    
         
             
                def detect(&block)
         
     | 
| 
       49 
35 
     | 
    
         
             
                  select(&block).first
         
     | 
| 
       50 
36 
     | 
    
         
             
                end
         
     | 
| 
       51 
37 
     | 
    
         | 
| 
       52 
     | 
    
         
            -
                def  
     | 
| 
       53 
     | 
    
         
            -
                  count 
     | 
| 
      
 38 
     | 
    
         
            +
                def first(count = 1)
         
     | 
| 
      
 39 
     | 
    
         
            +
                  sliced = slice(0, count)
         
     | 
| 
      
 40 
     | 
    
         
            +
                  count == 1 ? sliced.kick : sliced
         
     | 
| 
       54 
41 
     | 
    
         
             
                end
         
     | 
| 
       55 
     | 
    
         
            -
                alias_method :length, :size
         
     | 
| 
       56 
42 
     | 
    
         | 
| 
       57 
43 
     | 
    
         
             
                def each(&block)
         
     | 
| 
       58 
44 
     | 
    
         
             
                  entries.each(&block)
         
     | 
| 
         @@ -69,5 +55,26 @@ module Ambition 
     | 
|
| 
       69 
55 
     | 
    
         
             
                def empty?
         
     | 
| 
       70 
56 
     | 
    
         
             
                  size.zero?
         
     | 
| 
       71 
57 
     | 
    
         
             
                end
         
     | 
| 
      
 58 
     | 
    
         
            +
             
     | 
| 
      
 59 
     | 
    
         
            +
                ##
         
     | 
| 
      
 60 
     | 
    
         
            +
                # Plumbing
         
     | 
| 
      
 61 
     | 
    
         
            +
                def ambition_context
         
     | 
| 
      
 62 
     | 
    
         
            +
                  Context.new(self)
         
     | 
| 
      
 63 
     | 
    
         
            +
                end
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
      
 65 
     | 
    
         
            +
                def ambition_adapter
         
     | 
| 
      
 66 
     | 
    
         
            +
                  name   = respond_to?(:name) ? name : self.class.name
         
     | 
| 
      
 67 
     | 
    
         
            +
                  parent = respond_to?(:superclass) ? superclass : self.class.superclass
         
     | 
| 
      
 68 
     | 
    
         
            +
                  @@ambition_adapter[name] || @@ambition_adapter[parent.name]
         
     | 
| 
      
 69 
     | 
    
         
            +
                end
         
     | 
| 
      
 70 
     | 
    
         
            +
             
     | 
| 
      
 71 
     | 
    
         
            +
                def ambition_adapter=(klass)
         
     | 
| 
      
 72 
     | 
    
         
            +
                  @@ambition_adapter ||= {}
         
     | 
| 
      
 73 
     | 
    
         
            +
                  @@ambition_adapter[name] = klass
         
     | 
| 
      
 74 
     | 
    
         
            +
                end
         
     | 
| 
      
 75 
     | 
    
         
            +
             
     | 
| 
      
 76 
     | 
    
         
            +
                def ambition_owner
         
     | 
| 
      
 77 
     | 
    
         
            +
                  @owner || self
         
     | 
| 
      
 78 
     | 
    
         
            +
                end
         
     | 
| 
       72 
79 
     | 
    
         
             
              end
         
     | 
| 
       73 
80 
     | 
    
         
             
            end
         
     | 
| 
         @@ -0,0 +1,62 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Ambition
         
     | 
| 
      
 2 
     | 
    
         
            +
              class Context
         
     | 
| 
      
 3 
     | 
    
         
            +
                include API
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
                ##
         
     | 
| 
      
 6 
     | 
    
         
            +
                # These are the methods your Query and Translator classes will 
         
     | 
| 
      
 7 
     | 
    
         
            +
                # want to access.
         
     | 
| 
      
 8 
     | 
    
         
            +
                #
         
     | 
| 
      
 9 
     | 
    
         
            +
                #   +owner+   The class everything was called on.  Like `User' 
         
     | 
| 
      
 10 
     | 
    
         
            +
                #
         
     | 
| 
      
 11 
     | 
    
         
            +
                #   +clauses+ A hash of arrays, one key per processor.
         
     | 
| 
      
 12 
     | 
    
         
            +
                #             So, if someone called User.select, your
         
     | 
| 
      
 13 
     | 
    
         
            +
                #             +clauses+ hash would have a :select key with
         
     | 
| 
      
 14 
     | 
    
         
            +
                #             an array of translated strings via your Select
         
     | 
| 
      
 15 
     | 
    
         
            +
                #             class.
         
     | 
| 
      
 16 
     | 
    
         
            +
                #
         
     | 
| 
      
 17 
     | 
    
         
            +
                #   +stash+   A place for you to stick stuff.  Available to
         
     | 
| 
      
 18 
     | 
    
         
            +
                #             all Translators and your Query class.
         
     | 
| 
      
 19 
     | 
    
         
            +
                attr_reader :clauses, :owner, :stash
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                def initialize(owner)
         
     | 
| 
      
 22 
     | 
    
         
            +
                  @owner   = owner
         
     | 
| 
      
 23 
     | 
    
         
            +
                  @clauses = {}
         
     | 
| 
      
 24 
     | 
    
         
            +
                  @stash   = {}
         
     | 
| 
      
 25 
     | 
    
         
            +
                end
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                def ambition_context
         
     | 
| 
      
 28 
     | 
    
         
            +
                  self
         
     | 
| 
      
 29 
     | 
    
         
            +
                end
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
                def <<(clause)
         
     | 
| 
      
 32 
     | 
    
         
            +
                  @clauses[clause.key] ||= []
         
     | 
| 
      
 33 
     | 
    
         
            +
                  @clauses[clause.key] << clause.to_s
         
     | 
| 
      
 34 
     | 
    
         
            +
                  self
         
     | 
| 
      
 35 
     | 
    
         
            +
                end
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
                def adapter_query
         
     | 
| 
      
 38 
     | 
    
         
            +
                  Processors::Base.translator(self, :Query)
         
     | 
| 
      
 39 
     | 
    
         
            +
                end
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
                def to_hash
         
     | 
| 
      
 42 
     | 
    
         
            +
                  adapter_query.to_hash
         
     | 
| 
      
 43 
     | 
    
         
            +
                end
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
                def to_s
         
     | 
| 
      
 46 
     | 
    
         
            +
                  adapter_query.to_s
         
     | 
| 
      
 47 
     | 
    
         
            +
                end
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
                def kick
         
     | 
| 
      
 50 
     | 
    
         
            +
                  adapter_query.kick
         
     | 
| 
      
 51 
     | 
    
         
            +
                end
         
     | 
| 
      
 52 
     | 
    
         
            +
             
     | 
| 
      
 53 
     | 
    
         
            +
                def size
         
     | 
| 
      
 54 
     | 
    
         
            +
                  adapter_query.size
         
     | 
| 
      
 55 
     | 
    
         
            +
                end
         
     | 
| 
      
 56 
     | 
    
         
            +
                alias_method :length, :size
         
     | 
| 
      
 57 
     | 
    
         
            +
             
     | 
| 
      
 58 
     | 
    
         
            +
                def inspect
         
     | 
| 
      
 59 
     | 
    
         
            +
                  "(Query object: call #to_s or #to_hash to inspect, call an Enumerable (such as #each or #first) to request data)"
         
     | 
| 
      
 60 
     | 
    
         
            +
                end
         
     | 
| 
      
 61 
     | 
    
         
            +
              end
         
     | 
| 
      
 62 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -3,6 +3,19 @@ 
     | 
|
| 
       3 
3 
     | 
    
         
             
            require 'parse_tree'
         
     | 
| 
       4 
4 
     | 
    
         
             
            require 'ruby2ruby'
         
     | 
| 
       5 
5 
     | 
    
         | 
| 
      
 6 
     | 
    
         
            +
            class Object
         
     | 
| 
      
 7 
     | 
    
         
            +
              def to_sexp
         
     | 
| 
      
 8 
     | 
    
         
            +
                instance_eval <<-end_eval
         
     | 
| 
      
 9 
     | 
    
         
            +
                  return proc { #{inspect} }.to_sexp.last
         
     | 
| 
      
 10 
     | 
    
         
            +
                end_eval
         
     | 
| 
      
 11 
     | 
    
         
            +
              end
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
              def metaclass; (class << self; self end) end
         
     | 
| 
      
 14 
     | 
    
         
            +
              def meta_eval(&blk) metaclass.instance_eval(&blk) end
         
     | 
| 
      
 15 
     | 
    
         
            +
              def meta_def(name, &blk) meta_eval { define_method name, &blk } end
         
     | 
| 
      
 16 
     | 
    
         
            +
              def class_def(name, &blk) class_eval { define_method name, &blk } end
         
     | 
| 
      
 17 
     | 
    
         
            +
            end
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
       6 
19 
     | 
    
         
             
            class ProcHolder
         
     | 
| 
       7 
20 
     | 
    
         
             
            end
         
     | 
| 
       8 
21 
     | 
    
         | 
| 
         @@ -0,0 +1,126 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Ambition
         
     | 
| 
      
 2 
     | 
    
         
            +
              module Processors
         
     | 
| 
      
 3 
     | 
    
         
            +
                class Base
         
     | 
| 
      
 4 
     | 
    
         
            +
                  ##
         
     | 
| 
      
 5 
     | 
    
         
            +
                  # Processing methods
         
     | 
| 
      
 6 
     | 
    
         
            +
                  def process_proc(exp)
         
     | 
| 
      
 7 
     | 
    
         
            +
                    # puts "=> #{exp.inspect}"
         
     | 
| 
      
 8 
     | 
    
         
            +
                    receiver, body = process(exp.shift), exp.shift
         
     | 
| 
      
 9 
     | 
    
         
            +
                    process(body)
         
     | 
| 
      
 10 
     | 
    
         
            +
                  end
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                  def process_dasgn_curr(exp)
         
     | 
| 
      
 13 
     | 
    
         
            +
                    @receiver = exp.first
         
     | 
| 
      
 14 
     | 
    
         
            +
                    @receiver.to_s
         
     | 
| 
      
 15 
     | 
    
         
            +
                  end
         
     | 
| 
      
 16 
     | 
    
         
            +
                  alias_method :process_dasgn, :process_dasgn_curr
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                  def process_array(exp)
         
     | 
| 
      
 19 
     | 
    
         
            +
                    # Branch on whether this is straight Ruby or a real array
         
     | 
| 
      
 20 
     | 
    
         
            +
                    if ruby = rubify(exp)
         
     | 
| 
      
 21 
     | 
    
         
            +
                      ruby
         
     | 
| 
      
 22 
     | 
    
         
            +
                    else
         
     | 
| 
      
 23 
     | 
    
         
            +
                      exp.map { |m| process(m) }
         
     | 
| 
      
 24 
     | 
    
         
            +
                    end
         
     | 
| 
      
 25 
     | 
    
         
            +
                  end
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                  def process_str(exp)
         
     | 
| 
      
 28 
     | 
    
         
            +
                    exp.first
         
     | 
| 
      
 29 
     | 
    
         
            +
                  end
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
                  def process_lit(exp)
         
     | 
| 
      
 32 
     | 
    
         
            +
                    exp.first
         
     | 
| 
      
 33 
     | 
    
         
            +
                  end
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
                  def process_nil(exp)
         
     | 
| 
      
 36 
     | 
    
         
            +
                    nil
         
     | 
| 
      
 37 
     | 
    
         
            +
                  end
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
                  def process_true(exp)
         
     | 
| 
      
 40 
     | 
    
         
            +
                    true
         
     | 
| 
      
 41 
     | 
    
         
            +
                  end
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
                  def process_false(exp)
         
     | 
| 
      
 44 
     | 
    
         
            +
                    false
         
     | 
| 
      
 45 
     | 
    
         
            +
                  end
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
                  def process_dvar(exp)
         
     | 
| 
      
 48 
     | 
    
         
            +
                    target = exp.shift
         
     | 
| 
      
 49 
     | 
    
         
            +
                    value(target.to_s[0..-1])
         
     | 
| 
      
 50 
     | 
    
         
            +
                  end
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
                  def process_ivar(exp)
         
     | 
| 
      
 53 
     | 
    
         
            +
                    value(exp.shift.to_s[0..-1])
         
     | 
| 
      
 54 
     | 
    
         
            +
                  end
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
                  def process_lvar(exp)
         
     | 
| 
      
 57 
     | 
    
         
            +
                    value(exp.shift.to_s)
         
     | 
| 
      
 58 
     | 
    
         
            +
                  end
         
     | 
| 
      
 59 
     | 
    
         
            +
             
     | 
| 
      
 60 
     | 
    
         
            +
                  def process_vcall(exp)
         
     | 
| 
      
 61 
     | 
    
         
            +
                    value(exp.shift.to_s)
         
     | 
| 
      
 62 
     | 
    
         
            +
                  end
         
     | 
| 
      
 63 
     | 
    
         
            +
             
     | 
| 
      
 64 
     | 
    
         
            +
                  def process_gvar(exp)
         
     | 
| 
      
 65 
     | 
    
         
            +
                    value(exp.shift.to_s)
         
     | 
| 
      
 66 
     | 
    
         
            +
                  end
         
     | 
| 
      
 67 
     | 
    
         
            +
                  
         
     | 
| 
      
 68 
     | 
    
         
            +
                  def process(node)
         
     | 
| 
      
 69 
     | 
    
         
            +
                    node ||= []
         
     | 
| 
      
 70 
     | 
    
         
            +
             
     | 
| 
      
 71 
     | 
    
         
            +
                    if node.is_a? Symbol
         
     | 
| 
      
 72 
     | 
    
         
            +
                      node
         
     | 
| 
      
 73 
     | 
    
         
            +
                    elsif respond_to?(method = "process_#{node.first}") 
         
     | 
| 
      
 74 
     | 
    
         
            +
                      send(method, node[1..-1]) 
         
     | 
| 
      
 75 
     | 
    
         
            +
                    elsif node.blank?
         
     | 
| 
      
 76 
     | 
    
         
            +
                      ''
         
     | 
| 
      
 77 
     | 
    
         
            +
                    else
         
     | 
| 
      
 78 
     | 
    
         
            +
                      raise "Missing process method for sexp: #{node.inspect}"
         
     | 
| 
      
 79 
     | 
    
         
            +
                    end
         
     | 
| 
      
 80 
     | 
    
         
            +
                  end
         
     | 
| 
      
 81 
     | 
    
         
            +
             
     | 
| 
      
 82 
     | 
    
         
            +
                  ##
         
     | 
| 
      
 83 
     | 
    
         
            +
                  # Helper methods
         
     | 
| 
      
 84 
     | 
    
         
            +
                  def to_s
         
     | 
| 
      
 85 
     | 
    
         
            +
                    process @block.to_sexp
         
     | 
| 
      
 86 
     | 
    
         
            +
                  end
         
     | 
| 
      
 87 
     | 
    
         
            +
             
     | 
| 
      
 88 
     | 
    
         
            +
                  def key
         
     | 
| 
      
 89 
     | 
    
         
            +
                    self.class.name.split('::').last.downcase.intern
         
     | 
| 
      
 90 
     | 
    
         
            +
                  end
         
     | 
| 
      
 91 
     | 
    
         
            +
             
     | 
| 
      
 92 
     | 
    
         
            +
                  def value(variable)
         
     | 
| 
      
 93 
     | 
    
         
            +
                    eval variable, @block
         
     | 
| 
      
 94 
     | 
    
         
            +
                  end
         
     | 
| 
      
 95 
     | 
    
         
            +
             
     | 
| 
      
 96 
     | 
    
         
            +
                  def translator
         
     | 
| 
      
 97 
     | 
    
         
            +
                    @translator ||= self.class.translator(@context)
         
     | 
| 
      
 98 
     | 
    
         
            +
                  end
         
     | 
| 
      
 99 
     | 
    
         
            +
             
     | 
| 
      
 100 
     | 
    
         
            +
                  def self.translator(context, name = nil)
         
     | 
| 
      
 101 
     | 
    
         
            +
                    name   ||= self.name.split('::').last
         
     | 
| 
      
 102 
     | 
    
         
            +
                    klass    = context.owner.ambition_adapter.const_get(name)
         
     | 
| 
      
 103 
     | 
    
         
            +
                    instance = klass.new
         
     | 
| 
      
 104 
     | 
    
         
            +
             
     | 
| 
      
 105 
     | 
    
         
            +
                    unless instance.respond_to? :context
         
     | 
| 
      
 106 
     | 
    
         
            +
                      klass.class_eval do
         
     | 
| 
      
 107 
     | 
    
         
            +
                        attr_accessor :context
         
     | 
| 
      
 108 
     | 
    
         
            +
                        def owner;    @context.owner   end
         
     | 
| 
      
 109 
     | 
    
         
            +
                        def clauses;  @context.clauses end
         
     | 
| 
      
 110 
     | 
    
         
            +
                        def stash;    @context.stash   end
         
     | 
| 
      
 111 
     | 
    
         
            +
                      end
         
     | 
| 
      
 112 
     | 
    
         
            +
                    end
         
     | 
| 
      
 113 
     | 
    
         
            +
             
     | 
| 
      
 114 
     | 
    
         
            +
                    instance.context = context
         
     | 
| 
      
 115 
     | 
    
         
            +
                    instance
         
     | 
| 
      
 116 
     | 
    
         
            +
                  end
         
     | 
| 
      
 117 
     | 
    
         
            +
             
     | 
| 
      
 118 
     | 
    
         
            +
                  def rubify(exp)
         
     | 
| 
      
 119 
     | 
    
         
            +
                    # TODO: encapsulate this check in Ruby.should_process?(exp)
         
     | 
| 
      
 120 
     | 
    
         
            +
                    if exp.first.first == :call && exp.first[1].last != @receiver && Array(exp.first[1][1]).last != @receiver
         
     | 
| 
      
 121 
     | 
    
         
            +
                      value Ruby.process(exp.first)
         
     | 
| 
      
 122 
     | 
    
         
            +
                    end
         
     | 
| 
      
 123 
     | 
    
         
            +
                  end
         
     | 
| 
      
 124 
     | 
    
         
            +
                end
         
     | 
| 
      
 125 
     | 
    
         
            +
              end
         
     | 
| 
      
 126 
     | 
    
         
            +
            end
         
     |