gitmodel 0.0.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/.document +5 -0
 - data/.gitignore +7 -0
 - data/.rspec +1 -0
 - data/.rvmrc +1 -0
 - data/Gemfile +5 -0
 - data/Gemfile.lock +54 -0
 - data/LICENSE +20 -0
 - data/README.md +143 -0
 - data/Rakefile +3 -0
 - data/autotest/discover.rb +1 -0
 - data/gitmodel.gemspec +36 -0
 - data/lib/gitmodel/errors.rb +25 -0
 - data/lib/gitmodel/persistable.rb +269 -0
 - data/lib/gitmodel/transaction.rb +62 -0
 - data/lib/gitmodel.rb +76 -0
 - data/spec/gitmodel/persistable_spec.rb +436 -0
 - data/spec/gitmodel/transaction_spec.rb +59 -0
 - data/spec/gitmodel_spec.rb +39 -0
 - data/spec/spec_helper.rb +12 -0
 - data/spec/support/setup.rb +10 -0
 - metadata +206 -0
 
    
        data/lib/gitmodel.rb
    ADDED
    
    | 
         @@ -0,0 +1,76 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'rubygems'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'bundler/setup'
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            require 'active_model'
         
     | 
| 
      
 5 
     | 
    
         
            +
            require 'active_support/all' # TODO we don't really want all here, clean this up
         
     | 
| 
      
 6 
     | 
    
         
            +
            require 'grit'
         
     | 
| 
      
 7 
     | 
    
         
            +
            require 'json'
         
     | 
| 
      
 8 
     | 
    
         
            +
            require 'lockfile'
         
     | 
| 
      
 9 
     | 
    
         
            +
            require 'pp'
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
            $:.unshift(File.dirname(__FILE__))
         
     | 
| 
      
 12 
     | 
    
         
            +
            require 'gitmodel/errors'
         
     | 
| 
      
 13 
     | 
    
         
            +
            require 'gitmodel/persistable'
         
     | 
| 
      
 14 
     | 
    
         
            +
            require 'gitmodel/transaction'
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
            module GitModel
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
              # db_root must be an existing git repo. (It can be created with create_db!)
         
     | 
| 
      
 19 
     | 
    
         
            +
              # Bare repositories aren't supported yet, it must be a normal git repo with a
         
     | 
| 
      
 20 
     | 
    
         
            +
              # working directory and a '.git' subdirectory.
         
     | 
| 
      
 21 
     | 
    
         
            +
              mattr_accessor :db_root
         
     | 
| 
      
 22 
     | 
    
         
            +
              self.db_root = './gitmodel-data'
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
              mattr_accessor :default_branch
         
     | 
| 
      
 25 
     | 
    
         
            +
              self.default_branch = 'master'
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
              mattr_accessor :logger
         
     | 
| 
      
 28 
     | 
    
         
            +
              self.logger = ::Logger.new(STDERR)
         
     | 
| 
      
 29 
     | 
    
         
            +
              self.logger.level = ::Logger::WARN
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
              mattr_accessor :git_user_name
         
     | 
| 
      
 32 
     | 
    
         
            +
              mattr_accessor :git_user_email
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
              def self.repo
         
     | 
| 
      
 35 
     | 
    
         
            +
                @@repo = Grit::Repo.new(GitModel.db_root)
         
     | 
| 
      
 36 
     | 
    
         
            +
              end
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
              # Create the database defined in db_root. Raises an exception if it exists.
         
     | 
| 
      
 39 
     | 
    
         
            +
              def self.create_db!
         
     | 
| 
      
 40 
     | 
    
         
            +
                raise "Database #{db_root} already exists!" if File.exist? db_root
         
     | 
| 
      
 41 
     | 
    
         
            +
                if db_root =~ /.+\.git/
         
     | 
| 
      
 42 
     | 
    
         
            +
                  #logger.info "Creating database (bare): #{db_root}"
         
     | 
| 
      
 43 
     | 
    
         
            +
                  #Grit::Repo.init_bare db_root
         
     | 
| 
      
 44 
     | 
    
         
            +
                  logger.error "Bare repositories aren't supported yet"
         
     | 
| 
      
 45 
     | 
    
         
            +
                else
         
     | 
| 
      
 46 
     | 
    
         
            +
                  logger.info "Creating database: #{db_root}"
         
     | 
| 
      
 47 
     | 
    
         
            +
                  Grit::Repo.init db_root
         
     | 
| 
      
 48 
     | 
    
         
            +
                end
         
     | 
| 
      
 49 
     | 
    
         
            +
              end
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
              # Delete and re-create the database defined in db_root. Dangerous!
         
     | 
| 
      
 52 
     | 
    
         
            +
              def self.recreate_db!
         
     | 
| 
      
 53 
     | 
    
         
            +
                logger.info "Deleting database #{db_root}!!"
         
     | 
| 
      
 54 
     | 
    
         
            +
                FileUtils.rm_rf db_root
         
     | 
| 
      
 55 
     | 
    
         
            +
                create_db!
         
     | 
| 
      
 56 
     | 
    
         
            +
              end
         
     | 
| 
      
 57 
     | 
    
         
            +
             
     | 
| 
      
 58 
     | 
    
         
            +
              def self.last_commit(branch = nil)
         
     | 
| 
      
 59 
     | 
    
         
            +
                branch ||= default_branch
         
     | 
| 
      
 60 
     | 
    
         
            +
                # PERFORMANCE Cache this somewhere and update it on commit?
         
     | 
| 
      
 61 
     | 
    
         
            +
                # (Need separate instance per branch)
         
     | 
| 
      
 62 
     | 
    
         
            +
             
     | 
| 
      
 63 
     | 
    
         
            +
                return nil unless repo.commits(branch).any?
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
      
 65 
     | 
    
         
            +
                # We should be able to use just repo.commits(branch).first here but
         
     | 
| 
      
 66 
     | 
    
         
            +
                # this is a workaround for this bug: 
         
     | 
| 
      
 67 
     | 
    
         
            +
                # http://github.com/mojombo/grit/issues/issue/38
         
     | 
| 
      
 68 
     | 
    
         
            +
                GitModel.repo.commits("#{branch}^..#{branch}").first || GitModel.repo.commits(branch).first
         
     | 
| 
      
 69 
     | 
    
         
            +
              end
         
     | 
| 
      
 70 
     | 
    
         
            +
             
     | 
| 
      
 71 
     | 
    
         
            +
              def self.current_tree(branch = nil)
         
     | 
| 
      
 72 
     | 
    
         
            +
                c = last_commit(branch)
         
     | 
| 
      
 73 
     | 
    
         
            +
                c ? c.tree : nil
         
     | 
| 
      
 74 
     | 
    
         
            +
              end
         
     | 
| 
      
 75 
     | 
    
         
            +
             
     | 
| 
      
 76 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,436 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'spec_helper'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            class TestEntity
         
     | 
| 
      
 4 
     | 
    
         
            +
              include GitModel::Persistable
         
     | 
| 
      
 5 
     | 
    
         
            +
            end
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            class LintTest < ActiveModel::TestCase
         
     | 
| 
      
 8 
     | 
    
         
            +
              include ActiveModel::Lint::Tests
         
     | 
| 
      
 9 
     | 
    
         
            +
             
         
     | 
| 
      
 10 
     | 
    
         
            +
              def setup
         
     | 
| 
      
 11 
     | 
    
         
            +
                @model = TestEntity.new
         
     | 
| 
      
 12 
     | 
    
         
            +
              end
         
     | 
| 
      
 13 
     | 
    
         
            +
            end
         
     | 
| 
      
 14 
     | 
    
         
            +
              
         
     | 
| 
      
 15 
     | 
    
         
            +
            describe GitModel::Persistable do
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
              it 'passes ActiveModel lint tests' do
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                o = LintTest.new("ActiveModel lint test")
         
     | 
| 
      
 20 
     | 
    
         
            +
                o.setup
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                # TODO get this list of methods dynamically
         
     | 
| 
      
 23 
     | 
    
         
            +
                o.test_to_key
         
     | 
| 
      
 24 
     | 
    
         
            +
                o.test_to_param
         
     | 
| 
      
 25 
     | 
    
         
            +
                o.test_valid?
         
     | 
| 
      
 26 
     | 
    
         
            +
                o.test_persisted?
         
     | 
| 
      
 27 
     | 
    
         
            +
                o.test_model_naming
         
     | 
| 
      
 28 
     | 
    
         
            +
                o.test_errors_aref
         
     | 
| 
      
 29 
     | 
    
         
            +
                o.test_errors_full_messages
         
     | 
| 
      
 30 
     | 
    
         
            +
              end
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
              describe '#save' do
         
     | 
| 
      
 33 
     | 
    
         
            +
                
         
     | 
| 
      
 34 
     | 
    
         
            +
                it 'raises an exception if the id is not set' do
         
     | 
| 
      
 35 
     | 
    
         
            +
                  o = TestEntity.new
         
     | 
| 
      
 36 
     | 
    
         
            +
                  lambda {o.save}.should raise_error(GitModel::NullId)
         
     | 
| 
      
 37 
     | 
    
         
            +
                end
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
                it 'stores an instance in a Git repository in a subdir of db_root named with the id' do
         
     | 
| 
      
 40 
     | 
    
         
            +
                  id = 'foo'
         
     | 
| 
      
 41 
     | 
    
         
            +
                  TestEntity.create!(:id => id)
         
     | 
| 
      
 42 
     | 
    
         
            +
                  
         
     | 
| 
      
 43 
     | 
    
         
            +
                  repo = Grit::Repo.new(GitModel.db_root)
         
     | 
| 
      
 44 
     | 
    
         
            +
                  (repo.commits.first.tree / File.join(TestEntity.db_subdir, id, 'attributes.json')).data.should_not be_nil
         
     | 
| 
      
 45 
     | 
    
         
            +
                end
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
                it 'stores attributes in a JSON file' do
         
     | 
| 
      
 48 
     | 
    
         
            +
                  id = 'foo'
         
     | 
| 
      
 49 
     | 
    
         
            +
                  attrs = {:one => 1, :two => 2}
         
     | 
| 
      
 50 
     | 
    
         
            +
                  TestEntity.create!(:id => id, :attributes => attrs)
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
                  repo = Grit::Repo.new(GitModel.db_root)
         
     | 
| 
      
 53 
     | 
    
         
            +
                  attrs = (repo.commits.first.tree / File.join(TestEntity.db_subdir, id, 'attributes.json')).data
         
     | 
| 
      
 54 
     | 
    
         
            +
                  r = JSON.parse(attrs)
         
     | 
| 
      
 55 
     | 
    
         
            +
                  r.size.should == 2
         
     | 
| 
      
 56 
     | 
    
         
            +
                  r['one'].should == 1
         
     | 
| 
      
 57 
     | 
    
         
            +
                  r['two'].should == 2
         
     | 
| 
      
 58 
     | 
    
         
            +
                end
         
     | 
| 
      
 59 
     | 
    
         
            +
             
     | 
| 
      
 60 
     | 
    
         
            +
                it 'stores blobs in files' do
         
     | 
| 
      
 61 
     | 
    
         
            +
                  id = 'foo'
         
     | 
| 
      
 62 
     | 
    
         
            +
                  blobs = {'blob1.txt' => 'This is blob 1'}
         
     | 
| 
      
 63 
     | 
    
         
            +
                  TestEntity.create!(:id => id, :blobs => blobs)
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
      
 65 
     | 
    
         
            +
                  repo = Grit::Repo.new(GitModel.db_root)
         
     | 
| 
      
 66 
     | 
    
         
            +
                  (repo.commits.first.tree / File.join(TestEntity.db_subdir, id, 'blob1.txt')).data.should == 'This is blob 1'
         
     | 
| 
      
 67 
     | 
    
         
            +
                end
         
     | 
| 
      
 68 
     | 
    
         
            +
             
     | 
| 
      
 69 
     | 
    
         
            +
                it 'can store attributes and blobs' do
         
     | 
| 
      
 70 
     | 
    
         
            +
                  id = 'foo'
         
     | 
| 
      
 71 
     | 
    
         
            +
                  attrs = {:one => 1, :two => 2}
         
     | 
| 
      
 72 
     | 
    
         
            +
                  blobs = {'blob1.txt' => 'This is blob 1'}
         
     | 
| 
      
 73 
     | 
    
         
            +
                  TestEntity.create!(:id => id, :attributes => attrs, :blobs => blobs)
         
     | 
| 
      
 74 
     | 
    
         
            +
             
     | 
| 
      
 75 
     | 
    
         
            +
                  r = TestEntity.find('foo')
         
     | 
| 
      
 76 
     | 
    
         
            +
                  r.attributes['one'].should == 1
         
     | 
| 
      
 77 
     | 
    
         
            +
                  r.attributes['two'].should == 2
         
     | 
| 
      
 78 
     | 
    
         
            +
                  r.blobs['blob1.txt'].should == 'This is blob 1'
         
     | 
| 
      
 79 
     | 
    
         
            +
                end
         
     | 
| 
      
 80 
     | 
    
         
            +
             
     | 
| 
      
 81 
     | 
    
         
            +
                it 'returns false if the validations failed'
         
     | 
| 
      
 82 
     | 
    
         
            +
             
     | 
| 
      
 83 
     | 
    
         
            +
                it 'returns the SHA of the commit if the save was successful'
         
     | 
| 
      
 84 
     | 
    
         
            +
             
     | 
| 
      
 85 
     | 
    
         
            +
                it 'deletes blobs that have been removed'
         
     | 
| 
      
 86 
     | 
    
         
            +
              end
         
     | 
| 
      
 87 
     | 
    
         
            +
             
     | 
| 
      
 88 
     | 
    
         
            +
              describe '#save!' do
         
     | 
| 
      
 89 
     | 
    
         
            +
                
         
     | 
| 
      
 90 
     | 
    
         
            +
                it "calls save and returns the non-false and non-nil result"
         
     | 
| 
      
 91 
     | 
    
         
            +
             
     | 
| 
      
 92 
     | 
    
         
            +
                it "calls save and raises an exception if the result is nil"
         
     | 
| 
      
 93 
     | 
    
         
            +
                
         
     | 
| 
      
 94 
     | 
    
         
            +
                it "calls save and raises an exception if the result is false"
         
     | 
| 
      
 95 
     | 
    
         
            +
             
     | 
| 
      
 96 
     | 
    
         
            +
              end
         
     | 
| 
      
 97 
     | 
    
         
            +
             
     | 
| 
      
 98 
     | 
    
         
            +
              describe '#new' do
         
     | 
| 
      
 99 
     | 
    
         
            +
                it 'creates a new unsaved instance' do
         
     | 
| 
      
 100 
     | 
    
         
            +
                  TestEntity.new.new_record?.should be_true
         
     | 
| 
      
 101 
     | 
    
         
            +
                end
         
     | 
| 
      
 102 
     | 
    
         
            +
             
     | 
| 
      
 103 
     | 
    
         
            +
                it 'takes an optional hash to set id, attributes and blobs' do
         
     | 
| 
      
 104 
     | 
    
         
            +
                  o = TestEntity.new(:id => 'foo', :attributes => {:one => 1}, :blobs => {'blob1.txt' => 'This is blob 1'})
         
     | 
| 
      
 105 
     | 
    
         
            +
                  o.id.should == 'foo'
         
     | 
| 
      
 106 
     | 
    
         
            +
                  o.attributes['one'].should == 1
         
     | 
| 
      
 107 
     | 
    
         
            +
                  o.blobs['blob1.txt'].should == 'This is blob 1'
         
     | 
| 
      
 108 
     | 
    
         
            +
                end
         
     | 
| 
      
 109 
     | 
    
         
            +
              end
         
     | 
| 
      
 110 
     | 
    
         
            +
             
     | 
| 
      
 111 
     | 
    
         
            +
              describe '.create' do
         
     | 
| 
      
 112 
     | 
    
         
            +
                
         
     | 
| 
      
 113 
     | 
    
         
            +
                it 'creates a new instance with the given parameters and calls #save on it' do
         
     | 
| 
      
 114 
     | 
    
         
            +
                  id = 'foo'
         
     | 
| 
      
 115 
     | 
    
         
            +
                  attrs = {:one => 1, :two => 2}
         
     | 
| 
      
 116 
     | 
    
         
            +
                  blobs = {'blob1.txt' => 'This is blob 1'}
         
     | 
| 
      
 117 
     | 
    
         
            +
             
     | 
| 
      
 118 
     | 
    
         
            +
                  new_mock = mock("new_mock")
         
     | 
| 
      
 119 
     | 
    
         
            +
                  TestEntity.should_receive(:new).with(:id => id, :attributes => attrs, :blobs => blobs).and_return(new_mock)
         
     | 
| 
      
 120 
     | 
    
         
            +
                  new_mock.should_receive(:save)
         
     | 
| 
      
 121 
     | 
    
         
            +
             
     | 
| 
      
 122 
     | 
    
         
            +
                  TestEntity.create(:id => id, :attributes => attrs, :blobs => blobs) 
         
     | 
| 
      
 123 
     | 
    
         
            +
                end
         
     | 
| 
      
 124 
     | 
    
         
            +
             
     | 
| 
      
 125 
     | 
    
         
            +
                it 'returns an instance of the record created' do
         
     | 
| 
      
 126 
     | 
    
         
            +
                  o = TestEntity.create(:id => 'lemur')
         
     | 
| 
      
 127 
     | 
    
         
            +
                  o.should be_a(TestEntity)
         
     | 
| 
      
 128 
     | 
    
         
            +
                  o.id.should == 'lemur'
         
     | 
| 
      
 129 
     | 
    
         
            +
                end
         
     | 
| 
      
 130 
     | 
    
         
            +
             
     | 
| 
      
 131 
     | 
    
         
            +
                describe 'with a single array as a parameter' do
         
     | 
| 
      
 132 
     | 
    
         
            +
             
     | 
| 
      
 133 
     | 
    
         
            +
                  it 'creates a new instance with each element of the array as parameters and calls #save on it' do
         
     | 
| 
      
 134 
     | 
    
         
            +
                    args = [
         
     | 
| 
      
 135 
     | 
    
         
            +
                      {:id => 'foo', :attributes => {:one => 1}, :blobs => {'blob1.txt' => 'This is blob 1'}},
         
     | 
| 
      
 136 
     | 
    
         
            +
                      {:id => 'bar', :attributes => {:two => 2}, :blobs => {'blob2.txt' => 'This is blob 2'}}
         
     | 
| 
      
 137 
     | 
    
         
            +
                    ]
         
     | 
| 
      
 138 
     | 
    
         
            +
             
     | 
| 
      
 139 
     | 
    
         
            +
                    new_mock1 = mock("new_mock1")
         
     | 
| 
      
 140 
     | 
    
         
            +
                    new_mock2 = mock("new_mock2")
         
     | 
| 
      
 141 
     | 
    
         
            +
                    TestEntity.should_receive(:new).with(args[0]).once.and_return(new_mock1)
         
     | 
| 
      
 142 
     | 
    
         
            +
                    TestEntity.should_receive(:new).with(args[1]).once.and_return(new_mock2)
         
     | 
| 
      
 143 
     | 
    
         
            +
                    new_mock1.should_receive(:save)
         
     | 
| 
      
 144 
     | 
    
         
            +
                    new_mock2.should_receive(:save)
         
     | 
| 
      
 145 
     | 
    
         
            +
             
     | 
| 
      
 146 
     | 
    
         
            +
                    TestEntity.create(args) 
         
     | 
| 
      
 147 
     | 
    
         
            +
                  end
         
     | 
| 
      
 148 
     | 
    
         
            +
             
     | 
| 
      
 149 
     | 
    
         
            +
                end
         
     | 
| 
      
 150 
     | 
    
         
            +
             
     | 
| 
      
 151 
     | 
    
         
            +
              end
         
     | 
| 
      
 152 
     | 
    
         
            +
             
     | 
| 
      
 153 
     | 
    
         
            +
              describe '.create!' do
         
     | 
| 
      
 154 
     | 
    
         
            +
             
     | 
| 
      
 155 
     | 
    
         
            +
                it 'creates a new instance with the given parameters and calls #save! on it' do
         
     | 
| 
      
 156 
     | 
    
         
            +
                  id = 'foo'
         
     | 
| 
      
 157 
     | 
    
         
            +
                  attrs = {:one => 1, :two => 2}
         
     | 
| 
      
 158 
     | 
    
         
            +
                  blobs = {'blob1.txt' => 'This is blob 1'}
         
     | 
| 
      
 159 
     | 
    
         
            +
             
     | 
| 
      
 160 
     | 
    
         
            +
                  new_mock = mock("new_mock")
         
     | 
| 
      
 161 
     | 
    
         
            +
                  TestEntity.should_receive(:new).with(:id => id, :attributes => attrs, :blobs => blobs).and_return(new_mock)
         
     | 
| 
      
 162 
     | 
    
         
            +
                  new_mock.should_receive(:save!)
         
     | 
| 
      
 163 
     | 
    
         
            +
             
     | 
| 
      
 164 
     | 
    
         
            +
                  TestEntity.create!(:id => id, :attributes => attrs, :blobs => blobs) 
         
     | 
| 
      
 165 
     | 
    
         
            +
                end
         
     | 
| 
      
 166 
     | 
    
         
            +
             
     | 
| 
      
 167 
     | 
    
         
            +
                it 'returns an instance of the record created' do
         
     | 
| 
      
 168 
     | 
    
         
            +
                  o = TestEntity.create!(:id => 'lemur')
         
     | 
| 
      
 169 
     | 
    
         
            +
                  o.should be_a(TestEntity)
         
     | 
| 
      
 170 
     | 
    
         
            +
                  o.id.should == 'lemur'
         
     | 
| 
      
 171 
     | 
    
         
            +
                end
         
     | 
| 
      
 172 
     | 
    
         
            +
             
     | 
| 
      
 173 
     | 
    
         
            +
                describe 'with a single array as a parameter' do
         
     | 
| 
      
 174 
     | 
    
         
            +
                  it 'creates a new instance with each element of the array as parameters and calls #save! on it' do
         
     | 
| 
      
 175 
     | 
    
         
            +
                    args = [
         
     | 
| 
      
 176 
     | 
    
         
            +
                      {:id => 'foo', :attributes => {:one => 1}, :blobs => {'blob1.txt' => 'This is blob 1'}},
         
     | 
| 
      
 177 
     | 
    
         
            +
                      {:id => 'bar', :attributes => {:two => 2}, :blobs => {'blob2.txt' => 'This is blob 2'}}
         
     | 
| 
      
 178 
     | 
    
         
            +
                    ]
         
     | 
| 
      
 179 
     | 
    
         
            +
             
     | 
| 
      
 180 
     | 
    
         
            +
                    new_mock1 = mock("new_mock1")
         
     | 
| 
      
 181 
     | 
    
         
            +
                    new_mock2 = mock("new_mock2")
         
     | 
| 
      
 182 
     | 
    
         
            +
                    TestEntity.should_receive(:new).with(args[0]).once.and_return(new_mock1)
         
     | 
| 
      
 183 
     | 
    
         
            +
                    TestEntity.should_receive(:new).with(args[1]).once.and_return(new_mock2)
         
     | 
| 
      
 184 
     | 
    
         
            +
                    new_mock1.should_receive(:save!)
         
     | 
| 
      
 185 
     | 
    
         
            +
                    new_mock2.should_receive(:save!)
         
     | 
| 
      
 186 
     | 
    
         
            +
             
     | 
| 
      
 187 
     | 
    
         
            +
                    TestEntity.create!(args) 
         
     | 
| 
      
 188 
     | 
    
         
            +
                  end
         
     | 
| 
      
 189 
     | 
    
         
            +
                end
         
     | 
| 
      
 190 
     | 
    
         
            +
             
     | 
| 
      
 191 
     | 
    
         
            +
              end
         
     | 
| 
      
 192 
     | 
    
         
            +
             
     | 
| 
      
 193 
     | 
    
         
            +
              describe '.delete' do
         
     | 
| 
      
 194 
     | 
    
         
            +
             
     | 
| 
      
 195 
     | 
    
         
            +
                it 'deletes the object with the given id from the database' do
         
     | 
| 
      
 196 
     | 
    
         
            +
                  TestEntity.create!(:id => 'monkey')
         
     | 
| 
      
 197 
     | 
    
         
            +
                  TestEntity.delete('monkey')
         
     | 
| 
      
 198 
     | 
    
         
            +
             
     | 
| 
      
 199 
     | 
    
         
            +
                  TestEntity.exists?('monkey').should be_false
         
     | 
| 
      
 200 
     | 
    
         
            +
                end
         
     | 
| 
      
 201 
     | 
    
         
            +
             
     | 
| 
      
 202 
     | 
    
         
            +
                it 'also deletes blobs associated with the given object' do
         
     | 
| 
      
 203 
     | 
    
         
            +
                  id = 'Lemuridae'
         
     | 
| 
      
 204 
     | 
    
         
            +
                  TestEntity.create!(:id => id, :blobs => {:crowned => "Eulemur coronatus", :brown => "Eulemur fulvus"})
         
     | 
| 
      
 205 
     | 
    
         
            +
                  (GitModel.current_tree / File.join(TestEntity.db_subdir, id, 'crowned')).data.should_not be_nil
         
     | 
| 
      
 206 
     | 
    
         
            +
                  (GitModel.current_tree / File.join(TestEntity.db_subdir, id, 'brown')).data.should_not be_nil
         
     | 
| 
      
 207 
     | 
    
         
            +
                  TestEntity.delete(id)
         
     | 
| 
      
 208 
     | 
    
         
            +
             
     | 
| 
      
 209 
     | 
    
         
            +
                  (GitModel.current_tree / File.join(TestEntity.db_subdir, id, 'attributes.json')).should be_nil
         
     | 
| 
      
 210 
     | 
    
         
            +
                  (GitModel.current_tree / File.join(TestEntity.db_subdir, id, 'attributes.json')).should be_nil
         
     | 
| 
      
 211 
     | 
    
         
            +
             
     | 
| 
      
 212 
     | 
    
         
            +
                  (GitModel.current_tree / File.join(TestEntity.db_subdir, id, 'crowned')).should be_nil
         
     | 
| 
      
 213 
     | 
    
         
            +
                  (GitModel.current_tree / File.join(TestEntity.db_subdir, id, 'brown')).should be_nil
         
     | 
| 
      
 214 
     | 
    
         
            +
                end
         
     | 
| 
      
 215 
     | 
    
         
            +
             
     | 
| 
      
 216 
     | 
    
         
            +
             
     | 
| 
      
 217 
     | 
    
         
            +
              end
         
     | 
| 
      
 218 
     | 
    
         
            +
             
     | 
| 
      
 219 
     | 
    
         
            +
              describe '.delete_all' do
         
     | 
| 
      
 220 
     | 
    
         
            +
             
     | 
| 
      
 221 
     | 
    
         
            +
                it 'deletes all objects of the same type from the database' do
         
     | 
| 
      
 222 
     | 
    
         
            +
                  TestEntity.create!(:id => 'monkey')
         
     | 
| 
      
 223 
     | 
    
         
            +
                  TestEntity.create!(:id => 'ape')
         
     | 
| 
      
 224 
     | 
    
         
            +
             
     | 
| 
      
 225 
     | 
    
         
            +
                  TestEntity.delete_all
         
     | 
| 
      
 226 
     | 
    
         
            +
                  TestEntity.find_all.should be_empty
         
     | 
| 
      
 227 
     | 
    
         
            +
                end
         
     | 
| 
      
 228 
     | 
    
         
            +
             
     | 
| 
      
 229 
     | 
    
         
            +
              end
         
     | 
| 
      
 230 
     | 
    
         
            +
             
     | 
| 
      
 231 
     | 
    
         
            +
              describe '#delete' do
         
     | 
| 
      
 232 
     | 
    
         
            +
             
     | 
| 
      
 233 
     | 
    
         
            +
                it 'deletes the object from the database' do
         
     | 
| 
      
 234 
     | 
    
         
            +
                  o = TestEntity.create!(:id => 'monkey')
         
     | 
| 
      
 235 
     | 
    
         
            +
                  o.delete
         
     | 
| 
      
 236 
     | 
    
         
            +
             
     | 
| 
      
 237 
     | 
    
         
            +
                  TestEntity.exists?('monkey').should be_false
         
     | 
| 
      
 238 
     | 
    
         
            +
                end
         
     | 
| 
      
 239 
     | 
    
         
            +
             
     | 
| 
      
 240 
     | 
    
         
            +
                it 'freezes the object' do
         
     | 
| 
      
 241 
     | 
    
         
            +
                  o = TestEntity.create!(:id => 'monkey')
         
     | 
| 
      
 242 
     | 
    
         
            +
                  o.delete
         
     | 
| 
      
 243 
     | 
    
         
            +
             
     | 
| 
      
 244 
     | 
    
         
            +
                  o.frozen?.should be_true
         
     | 
| 
      
 245 
     | 
    
         
            +
                end
         
     | 
| 
      
 246 
     | 
    
         
            +
             
     | 
| 
      
 247 
     | 
    
         
            +
              end
         
     | 
| 
      
 248 
     | 
    
         
            +
             
     | 
| 
      
 249 
     | 
    
         
            +
              describe '#find' do
         
     | 
| 
      
 250 
     | 
    
         
            +
             
     | 
| 
      
 251 
     | 
    
         
            +
                #it 'can load an object from an empty subdir of db_root' do
         
     | 
| 
      
 252 
     | 
    
         
            +
                #  id = "foo"
         
     | 
| 
      
 253 
     | 
    
         
            +
                #  dir = File.join(GitModel.db_root, TestEntity.db_subdir, id)
         
     | 
| 
      
 254 
     | 
    
         
            +
                #  FileUtils.mkdir_p dir
         
     | 
| 
      
 255 
     | 
    
         
            +
             
     | 
| 
      
 256 
     | 
    
         
            +
                #  o = TestEntity.find(id)
         
     | 
| 
      
 257 
     | 
    
         
            +
                #  o.id.should == id
         
     | 
| 
      
 258 
     | 
    
         
            +
                #  o.attributes.should be_empty
         
     | 
| 
      
 259 
     | 
    
         
            +
                #  o.blobs.should be_empty
         
     | 
| 
      
 260 
     | 
    
         
            +
                #end
         
     | 
| 
      
 261 
     | 
    
         
            +
                
         
     | 
| 
      
 262 
     | 
    
         
            +
                describe 'with no commits in the repo' do
         
     | 
| 
      
 263 
     | 
    
         
            +
             
     | 
| 
      
 264 
     | 
    
         
            +
                  it 'raises GitModel::RecordNotFound if a record with the given id doesn\'t exist' do
         
     | 
| 
      
 265 
     | 
    
         
            +
                    lambda{TestEntity.find('missing')}.should raise_error(GitModel::RecordNotFound)
         
     | 
| 
      
 266 
     | 
    
         
            +
                  end
         
     | 
| 
      
 267 
     | 
    
         
            +
             
     | 
| 
      
 268 
     | 
    
         
            +
                end
         
     | 
| 
      
 269 
     | 
    
         
            +
                
         
     | 
| 
      
 270 
     | 
    
         
            +
                it 'raises GitModel::RecordNotFound if a record with the given id doesn\'t exist' do
         
     | 
| 
      
 271 
     | 
    
         
            +
                  TestEntity.create!(:id => 'something')
         
     | 
| 
      
 272 
     | 
    
         
            +
                  lambda{TestEntity.find('missing')}.should raise_error(GitModel::RecordNotFound)
         
     | 
| 
      
 273 
     | 
    
         
            +
                end
         
     | 
| 
      
 274 
     | 
    
         
            +
             
     | 
| 
      
 275 
     | 
    
         
            +
                it 'can load an object with attributes and no blobs' do
         
     | 
| 
      
 276 
     | 
    
         
            +
                  id = "foo"
         
     | 
| 
      
 277 
     | 
    
         
            +
                  attrs = {:one => 1, :two => 2}
         
     | 
| 
      
 278 
     | 
    
         
            +
                  TestEntity.create!(:id => id, :attributes => attrs)
         
     | 
| 
      
 279 
     | 
    
         
            +
             
     | 
| 
      
 280 
     | 
    
         
            +
                  o = TestEntity.find(id)
         
     | 
| 
      
 281 
     | 
    
         
            +
                  o.id.should == id
         
     | 
| 
      
 282 
     | 
    
         
            +
                  o.attributes.size.should == 2
         
     | 
| 
      
 283 
     | 
    
         
            +
                  o.attributes['one'].should == 1
         
     | 
| 
      
 284 
     | 
    
         
            +
                  o.attributes['two'].should == 2
         
     | 
| 
      
 285 
     | 
    
         
            +
                  o.blobs.should be_empty
         
     | 
| 
      
 286 
     | 
    
         
            +
                end
         
     | 
| 
      
 287 
     | 
    
         
            +
             
     | 
| 
      
 288 
     | 
    
         
            +
                it 'can load an object with blobs and no attributes' do
         
     | 
| 
      
 289 
     | 
    
         
            +
                  id = 'foo'
         
     | 
| 
      
 290 
     | 
    
         
            +
                  blobs = {'blob1.txt' => 'This is blob 1', 'blob2' => 'This is blob 2'}
         
     | 
| 
      
 291 
     | 
    
         
            +
                  TestEntity.create!(:id => id, :blobs => blobs)
         
     | 
| 
      
 292 
     | 
    
         
            +
             
     | 
| 
      
 293 
     | 
    
         
            +
                  o = TestEntity.find(id)
         
     | 
| 
      
 294 
     | 
    
         
            +
                  o.id.should == id
         
     | 
| 
      
 295 
     | 
    
         
            +
                  o.attributes.should be_empty
         
     | 
| 
      
 296 
     | 
    
         
            +
                  o.blobs.size.should == 2
         
     | 
| 
      
 297 
     | 
    
         
            +
                  o.blobs["blob1.txt"].should == 'This is blob 1'
         
     | 
| 
      
 298 
     | 
    
         
            +
                  o.blobs["blob2"].should == 'This is blob 2'
         
     | 
| 
      
 299 
     | 
    
         
            +
                end
         
     | 
| 
      
 300 
     | 
    
         
            +
             
     | 
| 
      
 301 
     | 
    
         
            +
                it 'can load an object with both attributes and blobs' do
         
     | 
| 
      
 302 
     | 
    
         
            +
                  id = 'foo'
         
     | 
| 
      
 303 
     | 
    
         
            +
                  attrs = {:one => 1, :two => 2}
         
     | 
| 
      
 304 
     | 
    
         
            +
                  blobs = {'blob1.txt' => 'This is blob 1', 'blob2' => 'This is blob 2'}
         
     | 
| 
      
 305 
     | 
    
         
            +
                  TestEntity.create!(:id => id, :attributes => attrs, :blobs => blobs)
         
     | 
| 
      
 306 
     | 
    
         
            +
             
     | 
| 
      
 307 
     | 
    
         
            +
                  o = TestEntity.find(id)
         
     | 
| 
      
 308 
     | 
    
         
            +
                  o.id.should == id
         
     | 
| 
      
 309 
     | 
    
         
            +
                  o.attributes.size.should == 2
         
     | 
| 
      
 310 
     | 
    
         
            +
                  o.attributes['one'].should == 1
         
     | 
| 
      
 311 
     | 
    
         
            +
                  o.attributes['two'].should == 2
         
     | 
| 
      
 312 
     | 
    
         
            +
                  o.blobs.size.should == 2
         
     | 
| 
      
 313 
     | 
    
         
            +
                  o.blobs["blob1.txt"].should == 'This is blob 1'
         
     | 
| 
      
 314 
     | 
    
         
            +
                  o.blobs["blob2"].should == 'This is blob 2'
         
     | 
| 
      
 315 
     | 
    
         
            +
                end
         
     | 
| 
      
 316 
     | 
    
         
            +
             
     | 
| 
      
 317 
     | 
    
         
            +
              end
         
     | 
| 
      
 318 
     | 
    
         
            +
             
     | 
| 
      
 319 
     | 
    
         
            +
              describe '#find_all' do
         
     | 
| 
      
 320 
     | 
    
         
            +
             
     | 
| 
      
 321 
     | 
    
         
            +
                it 'returns an array of all objects' do
         
     | 
| 
      
 322 
     | 
    
         
            +
                  TestEntity.create!(:id => 'one')
         
     | 
| 
      
 323 
     | 
    
         
            +
                  TestEntity.create!(:id => 'two')
         
     | 
| 
      
 324 
     | 
    
         
            +
                  TestEntity.create!(:id => 'three')
         
     | 
| 
      
 325 
     | 
    
         
            +
             
     | 
| 
      
 326 
     | 
    
         
            +
                  r = TestEntity.find_all
         
     | 
| 
      
 327 
     | 
    
         
            +
                  r.size.should == 3
         
     | 
| 
      
 328 
     | 
    
         
            +
                end
         
     | 
| 
      
 329 
     | 
    
         
            +
             
     | 
| 
      
 330 
     | 
    
         
            +
              end
         
     | 
| 
      
 331 
     | 
    
         
            +
             
     | 
| 
      
 332 
     | 
    
         
            +
              describe '#exists?' do
         
     | 
| 
      
 333 
     | 
    
         
            +
             
     | 
| 
      
 334 
     | 
    
         
            +
                it 'returns true if the record exists' do
         
     | 
| 
      
 335 
     | 
    
         
            +
                  TestEntity.create!(:id => 'one')
         
     | 
| 
      
 336 
     | 
    
         
            +
                  TestEntity.exists?('one').should be_true
         
     | 
| 
      
 337 
     | 
    
         
            +
                end
         
     | 
| 
      
 338 
     | 
    
         
            +
             
     | 
| 
      
 339 
     | 
    
         
            +
                it "returns false if the record doesn't exist" do
         
     | 
| 
      
 340 
     | 
    
         
            +
                  TestEntity.exists?('missing').should be_false
         
     | 
| 
      
 341 
     | 
    
         
            +
                end
         
     | 
| 
      
 342 
     | 
    
         
            +
             
     | 
| 
      
 343 
     | 
    
         
            +
              end
         
     | 
| 
      
 344 
     | 
    
         
            +
             
     | 
| 
      
 345 
     | 
    
         
            +
              describe '#attributes' do
         
     | 
| 
      
 346 
     | 
    
         
            +
                it 'accepts symbols or strings interchangeably as strings' do
         
     | 
| 
      
 347 
     | 
    
         
            +
                  o = TestEntity.new(:id => 'lol', :attributes => {"one" => 1, :two => 2})
         
     | 
| 
      
 348 
     | 
    
         
            +
                  o.save!
         
     | 
| 
      
 349 
     | 
    
         
            +
                  o.attributes["one"].should == 1
         
     | 
| 
      
 350 
     | 
    
         
            +
                  o.attributes[:one].should == 1
         
     | 
| 
      
 351 
     | 
    
         
            +
                  o.attributes["two"].should == 2
         
     | 
| 
      
 352 
     | 
    
         
            +
                  o.attributes[:two].should == 2
         
     | 
| 
      
 353 
     | 
    
         
            +
             
     | 
| 
      
 354 
     | 
    
         
            +
                  # Should also be true after reloading
         
     | 
| 
      
 355 
     | 
    
         
            +
                  o = TestEntity.find 'lol'
         
     | 
| 
      
 356 
     | 
    
         
            +
                  o.attributes["one"].should == 1
         
     | 
| 
      
 357 
     | 
    
         
            +
                  o.attributes[:one].should == 1
         
     | 
| 
      
 358 
     | 
    
         
            +
                  o.attributes["two"].should == 2
         
     | 
| 
      
 359 
     | 
    
         
            +
                  o.attributes[:two].should == 2
         
     | 
| 
      
 360 
     | 
    
         
            +
                end
         
     | 
| 
      
 361 
     | 
    
         
            +
              end
         
     | 
| 
      
 362 
     | 
    
         
            +
             
     | 
| 
      
 363 
     | 
    
         
            +
              describe '#blobs' do
         
     | 
| 
      
 364 
     | 
    
         
            +
                it 'accepts symbols or strings interchangeably as strings' do
         
     | 
| 
      
 365 
     | 
    
         
            +
                  o = TestEntity.new(:id => 'lol', :blobs => {"one" => 'this is blob 1', :two => 'this is blob 2'})
         
     | 
| 
      
 366 
     | 
    
         
            +
                  o.save!
         
     | 
| 
      
 367 
     | 
    
         
            +
                  o.blobs["one"].should == 'this is blob 1'
         
     | 
| 
      
 368 
     | 
    
         
            +
                  o.blobs[:one].should == 'this is blob 1'
         
     | 
| 
      
 369 
     | 
    
         
            +
                  o.blobs["two"].should == 'this is blob 2'
         
     | 
| 
      
 370 
     | 
    
         
            +
                  o.blobs[:two].should == 'this is blob 2'
         
     | 
| 
      
 371 
     | 
    
         
            +
             
     | 
| 
      
 372 
     | 
    
         
            +
                  # Should also be true after reloading
         
     | 
| 
      
 373 
     | 
    
         
            +
                  o = TestEntity.find 'lol'
         
     | 
| 
      
 374 
     | 
    
         
            +
                  o.blobs["one"].should == 'this is blob 1'
         
     | 
| 
      
 375 
     | 
    
         
            +
                  o.blobs[:one].should == 'this is blob 1'
         
     | 
| 
      
 376 
     | 
    
         
            +
                  o.blobs["two"].should == 'this is blob 2'
         
     | 
| 
      
 377 
     | 
    
         
            +
                  o.blobs[:two].should == 'this is blob 2'
         
     | 
| 
      
 378 
     | 
    
         
            +
                end
         
     | 
| 
      
 379 
     | 
    
         
            +
              end
         
     | 
| 
      
 380 
     | 
    
         
            +
             
     | 
| 
      
 381 
     | 
    
         
            +
              describe 'attribute description in the class definition' do
         
     | 
| 
      
 382 
     | 
    
         
            +
             
     | 
| 
      
 383 
     | 
    
         
            +
                it 'creates convenient accessor methods for accessing the attributes hash' do
         
     | 
| 
      
 384 
     | 
    
         
            +
                  o = TestEntity.new
         
     | 
| 
      
 385 
     | 
    
         
            +
                  class << o 
         
     | 
| 
      
 386 
     | 
    
         
            +
                    attribute :colour
         
     | 
| 
      
 387 
     | 
    
         
            +
                  end
         
     | 
| 
      
 388 
     | 
    
         
            +
             
     | 
| 
      
 389 
     | 
    
         
            +
                  o.colour.should == nil
         
     | 
| 
      
 390 
     | 
    
         
            +
                  o.colour = "red"
         
     | 
| 
      
 391 
     | 
    
         
            +
                  o.colour.should == "red"
         
     | 
| 
      
 392 
     | 
    
         
            +
                  o.attributes[:colour].should == "red"
         
     | 
| 
      
 393 
     | 
    
         
            +
                end
         
     | 
| 
      
 394 
     | 
    
         
            +
             
     | 
| 
      
 395 
     | 
    
         
            +
                it 'can set default values for attributes, with any ruby value for the default' do
         
     | 
| 
      
 396 
     | 
    
         
            +
                  o = TestEntity.new
         
     | 
| 
      
 397 
     | 
    
         
            +
             
     | 
| 
      
 398 
     | 
    
         
            +
                  # Change the singleton class for object o, this doesn't change the
         
     | 
| 
      
 399 
     | 
    
         
            +
                  # TestEntity class
         
     | 
| 
      
 400 
     | 
    
         
            +
                  class << o 
         
     | 
| 
      
 401 
     | 
    
         
            +
                    attribute :size, :default => "medium"
         
     | 
| 
      
 402 
     | 
    
         
            +
                    attribute :shape, :default => 2 
         
     | 
| 
      
 403 
     | 
    
         
            +
                    attribute :style, :default => nil 
         
     | 
| 
      
 404 
     | 
    
         
            +
                    attribute :teeth, :default => {"molars" => 4, "canines" => 2}
         
     | 
| 
      
 405 
     | 
    
         
            +
                  end
         
     | 
| 
      
 406 
     | 
    
         
            +
             
     | 
| 
      
 407 
     | 
    
         
            +
                  o.size.should == "medium"
         
     | 
| 
      
 408 
     | 
    
         
            +
                  o.shape.should == 2
         
     | 
| 
      
 409 
     | 
    
         
            +
                  o.style.should == nil
         
     | 
| 
      
 410 
     | 
    
         
            +
                  o.teeth.should == {"molars" => 4, "canines" => 2}
         
     | 
| 
      
 411 
     | 
    
         
            +
             
     | 
| 
      
 412 
     | 
    
         
            +
                  o.size = "large"
         
     | 
| 
      
 413 
     | 
    
         
            +
                  o.size.should == "large"
         
     | 
| 
      
 414 
     | 
    
         
            +
                end
         
     | 
| 
      
 415 
     | 
    
         
            +
             
     | 
| 
      
 416 
     | 
    
         
            +
              end
         
     | 
| 
      
 417 
     | 
    
         
            +
             
     | 
| 
      
 418 
     | 
    
         
            +
              describe 'blob description in the class definition' do
         
     | 
| 
      
 419 
     | 
    
         
            +
             
     | 
| 
      
 420 
     | 
    
         
            +
                it 'creates convenient accessor methods for accessing the blobs hash' do
         
     | 
| 
      
 421 
     | 
    
         
            +
                  o = TestEntity.new
         
     | 
| 
      
 422 
     | 
    
         
            +
                  class << o 
         
     | 
| 
      
 423 
     | 
    
         
            +
                    blob :avatar
         
     | 
| 
      
 424 
     | 
    
         
            +
                  end
         
     | 
| 
      
 425 
     | 
    
         
            +
             
     | 
| 
      
 426 
     | 
    
         
            +
                  o.avatar.should == nil
         
     | 
| 
      
 427 
     | 
    
         
            +
             
     | 
| 
      
 428 
     | 
    
         
            +
                  o.avatar = "image_data_here"
         
     | 
| 
      
 429 
     | 
    
         
            +
                  o.avatar.should == "image_data_here"
         
     | 
| 
      
 430 
     | 
    
         
            +
                  o.blobs[:avatar].should == "image_data_here"
         
     | 
| 
      
 431 
     | 
    
         
            +
                end
         
     | 
| 
      
 432 
     | 
    
         
            +
             
     | 
| 
      
 433 
     | 
    
         
            +
              end
         
     | 
| 
      
 434 
     | 
    
         
            +
             
     | 
| 
      
 435 
     | 
    
         
            +
            end
         
     | 
| 
      
 436 
     | 
    
         
            +
             
     | 
| 
         @@ -0,0 +1,59 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'spec_helper'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            describe GitModel::Transaction do
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
              describe '#execute' do
         
     | 
| 
      
 6 
     | 
    
         
            +
                it "yields to a given block" do
         
     | 
| 
      
 7 
     | 
    
         
            +
                  m = mock("mock")
         
     | 
| 
      
 8 
     | 
    
         
            +
                  m.should_receive(:a_method)
         
     | 
| 
      
 9 
     | 
    
         
            +
                  GitModel::Transaction.new.execute do
         
     | 
| 
      
 10 
     | 
    
         
            +
                    m.a_method
         
     | 
| 
      
 11 
     | 
    
         
            +
                  end
         
     | 
| 
      
 12 
     | 
    
         
            +
                end
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                describe "when called the first time" do
         
     | 
| 
      
 15 
     | 
    
         
            +
                  it "creates a new Git index" do
         
     | 
| 
      
 16 
     | 
    
         
            +
                    index = mock("index")
         
     | 
| 
      
 17 
     | 
    
         
            +
                    index.stub!(:read_tree)
         
     | 
| 
      
 18 
     | 
    
         
            +
                    index.stub!(:commit)
         
     | 
| 
      
 19 
     | 
    
         
            +
                    Grit::Index.should_receive(:new).and_return(index)
         
     | 
| 
      
 20 
     | 
    
         
            +
                    GitModel::Transaction.new.execute {}
         
     | 
| 
      
 21 
     | 
    
         
            +
                  end
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                  it "commits after yielding" do
         
     | 
| 
      
 24 
     | 
    
         
            +
                    index = mock("index")
         
     | 
| 
      
 25 
     | 
    
         
            +
                    index.stub!(:read_tree)
         
     | 
| 
      
 26 
     | 
    
         
            +
                    index.should_receive(:commit)
         
     | 
| 
      
 27 
     | 
    
         
            +
                    Grit::Index.should_receive(:new).and_return(index)
         
     | 
| 
      
 28 
     | 
    
         
            +
                    GitModel::Transaction.new.execute {}
         
     | 
| 
      
 29 
     | 
    
         
            +
                  end
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
                  it "can create the first commit in the repo" do
         
     | 
| 
      
 32 
     | 
    
         
            +
                    GitModel::Transaction.new.execute do |t|
         
     | 
| 
      
 33 
     | 
    
         
            +
                      t.index.add "foo", "foo"
         
     | 
| 
      
 34 
     | 
    
         
            +
                    end
         
     | 
| 
      
 35 
     | 
    
         
            +
                  end
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
                  # TODO it "locks the branch while committing"
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
                  # TODO it "merges commits from concurrent transactions"
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
                end
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
                describe "when called recursively" do
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
                  it "re-uses the existing git index and doesn't commit" do
         
     | 
| 
      
 46 
     | 
    
         
            +
                    index = mock("index")
         
     | 
| 
      
 47 
     | 
    
         
            +
                    index.stub!(:read_tree)
         
     | 
| 
      
 48 
     | 
    
         
            +
                    index.should_receive(:commit).once
         
     | 
| 
      
 49 
     | 
    
         
            +
                    Grit::Index.should_receive(:new).and_return(index)
         
     | 
| 
      
 50 
     | 
    
         
            +
                    GitModel::Transaction.new.execute do |t|
         
     | 
| 
      
 51 
     | 
    
         
            +
                      t.execute {}
         
     | 
| 
      
 52 
     | 
    
         
            +
                    end
         
     | 
| 
      
 53 
     | 
    
         
            +
                  end
         
     | 
| 
      
 54 
     | 
    
         
            +
             
     | 
| 
      
 55 
     | 
    
         
            +
                end
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
              end
         
     | 
| 
      
 58 
     | 
    
         
            +
             
     | 
| 
      
 59 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,39 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            describe GitModel do
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
              describe "#last_commit" do
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
                it "returns nil if there are no commits" do
         
     | 
| 
      
 8 
     | 
    
         
            +
                  GitModel.last_commit.should == nil
         
     | 
| 
      
 9 
     | 
    
         
            +
                end
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                it "returns the most recent commit on a branch" do
         
     | 
| 
      
 12 
     | 
    
         
            +
                  index = Grit::Index.new(GitModel.repo)
         
     | 
| 
      
 13 
     | 
    
         
            +
                  head = GitModel.repo.commits.first
         
     | 
| 
      
 14 
     | 
    
         
            +
                  index.read_tree head.to_s
         
     | 
| 
      
 15 
     | 
    
         
            +
                  index.add "foo", "foo"
         
     | 
| 
      
 16 
     | 
    
         
            +
                  sha = index.commit nil, nil, nil, nil, 'master'
         
     | 
| 
      
 17 
     | 
    
         
            +
                        
         
     | 
| 
      
 18 
     | 
    
         
            +
                  GitModel.last_commit.to_s.should == sha
         
     | 
| 
      
 19 
     | 
    
         
            +
                end
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
              end
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
              describe "#current_tree" do
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                it "returns nil if there are no commits" do
         
     | 
| 
      
 26 
     | 
    
         
            +
                  GitModel.current_tree.should == nil
         
     | 
| 
      
 27 
     | 
    
         
            +
                end
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                it "returns the tree for the most recent commit on a branch" do
         
     | 
| 
      
 30 
     | 
    
         
            +
                  last_commit = mock('last_commit')
         
     | 
| 
      
 31 
     | 
    
         
            +
                  last_commit.should_receive(:tree).and_return("yay, a tree!")
         
     | 
| 
      
 32 
     | 
    
         
            +
                  GitModel.should_receive(:last_commit).with('master').and_return(last_commit)
         
     | 
| 
      
 33 
     | 
    
         
            +
                  GitModel.current_tree('master')
         
     | 
| 
      
 34 
     | 
    
         
            +
                end
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
              end
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
            end
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
    
        data/spec/spec_helper.rb
    ADDED
    
    | 
         @@ -0,0 +1,12 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'rspec'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            $LOAD_PATH.unshift(File.dirname(__FILE__))
         
     | 
| 
      
 4 
     | 
    
         
            +
            $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
         
     | 
| 
      
 5 
     | 
    
         
            +
            require 'gitmodel'
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            Dir[File.join(File.dirname(__FILE__), "support/**/*.rb")].each {|f| require f}
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
            Rspec.configure do |c|
         
     | 
| 
      
 10 
     | 
    
         
            +
              c.mock_with :rspec
         
     | 
| 
      
 11 
     | 
    
         
            +
            end
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     |