couch-migrate 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/Gemfile ADDED
@@ -0,0 +1,10 @@
1
+ source "http://rubygems.org"
2
+ gem 'couchrest'
3
+
4
+ group :development do
5
+ gem "rspec", "~> 2.3.0"
6
+ gem "yard", "~> 0.6.0"
7
+ gem "bundler", "~> 1.0.0"
8
+ gem "jeweler", "~> 1.6.4"
9
+ gem "rcov", ">= 0"
10
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,39 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ couchrest (1.1.2)
5
+ mime-types (~> 1.15)
6
+ multi_json (~> 1.0.0)
7
+ rest-client (~> 1.6.1)
8
+ diff-lcs (1.1.3)
9
+ git (1.2.5)
10
+ jeweler (1.6.4)
11
+ bundler (~> 1.0)
12
+ git (>= 1.2.5)
13
+ rake
14
+ mime-types (1.16)
15
+ multi_json (1.0.3)
16
+ rake (0.9.2)
17
+ rcov (0.9.10)
18
+ rest-client (1.6.7)
19
+ mime-types (>= 1.16)
20
+ rspec (2.3.0)
21
+ rspec-core (~> 2.3.0)
22
+ rspec-expectations (~> 2.3.0)
23
+ rspec-mocks (~> 2.3.0)
24
+ rspec-core (2.3.1)
25
+ rspec-expectations (2.3.0)
26
+ diff-lcs (~> 1.1.2)
27
+ rspec-mocks (2.3.0)
28
+ yard (0.6.8)
29
+
30
+ PLATFORMS
31
+ ruby
32
+
33
+ DEPENDENCIES
34
+ bundler (~> 1.0.0)
35
+ couchrest
36
+ jeweler (~> 1.6.4)
37
+ rcov
38
+ rspec (~> 2.3.0)
39
+ yard (~> 0.6.0)
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Greg Edwards
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,19 @@
1
+ = couch-migrate
2
+
3
+ Description goes here.
4
+
5
+ == Contributing to couch-migrate
6
+
7
+ * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
8
+ * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
9
+ * Fork the project
10
+ * Start a feature/bugfix branch
11
+ * Commit and push until you are happy with your contribution
12
+ * Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
13
+ * Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
14
+
15
+ == Copyright
16
+
17
+ Copyright (c) 2011 Greg Edwards. See LICENSE.txt for
18
+ further details.
19
+
data/Rakefile ADDED
@@ -0,0 +1,46 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+ begin
6
+ Bundler.setup(:default, :development)
7
+ rescue Bundler::BundlerError => e
8
+ $stderr.puts e.message
9
+ $stderr.puts "Run `bundle install` to install missing gems"
10
+ exit e.status_code
11
+ end
12
+ require 'rake'
13
+ import 'lib/tasks/couch_migrate.rake'
14
+
15
+ task 'environment' do
16
+ end
17
+
18
+ require 'jeweler'
19
+ Jeweler::Tasks.new do |gem|
20
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
21
+ gem.name = "couch-migrate"
22
+ gem.homepage = "https://github.com/gedwards/couch-migrate"
23
+ gem.license = "MIT"
24
+ gem.summary = %Q{A simple migration system for CouchDB}
25
+ gem.description = %Q{A simple migration system for CouchDB.}
26
+ gem.email = "greg@greglearns.com"
27
+ gem.authors = ["Greg Edwards"]
28
+ # dependencies defined in Gemfile
29
+ end
30
+ Jeweler::RubygemsDotOrgTasks.new
31
+
32
+ require 'rspec/core'
33
+ require 'rspec/core/rake_task'
34
+ RSpec::Core::RakeTask.new(:spec) do |spec|
35
+ spec.pattern = FileList['spec/**/*_spec.rb']
36
+ end
37
+
38
+ RSpec::Core::RakeTask.new(:rcov) do |spec|
39
+ spec.pattern = 'spec/**/*_spec.rb'
40
+ spec.rcov = true
41
+ end
42
+
43
+ task :default => :spec
44
+
45
+ require 'yard'
46
+ YARD::Rake::YardocTask.new
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 1.0.0
@@ -0,0 +1,84 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{couch-migrate}
8
+ s.version = "1.0.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Greg Edwards"]
12
+ s.date = %q{2011-09-20}
13
+ s.description = %q{A simple migration system for CouchDB.}
14
+ s.email = %q{greg@greglearns.com}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE.txt",
17
+ "README.rdoc"
18
+ ]
19
+ s.files = [
20
+ ".document",
21
+ ".rspec",
22
+ "Gemfile",
23
+ "Gemfile.lock",
24
+ "LICENSE.txt",
25
+ "README.rdoc",
26
+ "Rakefile",
27
+ "VERSION",
28
+ "couch-migrate.gemspec",
29
+ "db/migrate/1_test.rb",
30
+ "lib/couch-migrate.rb",
31
+ "lib/couch_migrate/base_executer.rb",
32
+ "lib/couch_migrate/base_migrater.rb",
33
+ "lib/couch_migrate/base_persisted_list.rb",
34
+ "lib/couch_migrate/couch_executer.rb",
35
+ "lib/couch_migrate/couch_migrater.rb",
36
+ "lib/couch_migrate/couch_persisted_list.rb",
37
+ "lib/couch_migrate/couchrest_model/extend.rb",
38
+ "lib/couch_migrate/file_migrater.rb",
39
+ "lib/couch_migrate/file_persisted_list.rb",
40
+ "lib/couch_migrate_railtie.rb",
41
+ "lib/tasks/couch_migrate.rake",
42
+ "spec/couch_migrate/base_executer_spec.rb",
43
+ "spec/couch_migrate/base_migrater_spec.rb",
44
+ "spec/couch_migrate/base_persisted_list_spec.rb",
45
+ "spec/couch_migrate/couch_migrater_spec.rb",
46
+ "spec/couch_migrate/couch_persisted_list_spec.rb",
47
+ "spec/couch_migrate/file_migrater_spec.rb",
48
+ "spec/couch_migrate/file_persisted_list_spec.rb",
49
+ "spec/spec_helper.rb"
50
+ ]
51
+ s.homepage = %q{https://github.com/gedwards/couch-migrate}
52
+ s.licenses = ["MIT"]
53
+ s.require_paths = ["lib"]
54
+ s.rubygems_version = %q{1.6.2}
55
+ s.summary = %q{A simple migration system for CouchDB}
56
+
57
+ if s.respond_to? :specification_version then
58
+ s.specification_version = 3
59
+
60
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
61
+ s.add_runtime_dependency(%q<couchrest>, [">= 0"])
62
+ s.add_development_dependency(%q<rspec>, ["~> 2.3.0"])
63
+ s.add_development_dependency(%q<yard>, ["~> 0.6.0"])
64
+ s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
65
+ s.add_development_dependency(%q<jeweler>, ["~> 1.6.4"])
66
+ s.add_development_dependency(%q<rcov>, [">= 0"])
67
+ else
68
+ s.add_dependency(%q<couchrest>, [">= 0"])
69
+ s.add_dependency(%q<rspec>, ["~> 2.3.0"])
70
+ s.add_dependency(%q<yard>, ["~> 0.6.0"])
71
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
72
+ s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
73
+ s.add_dependency(%q<rcov>, [">= 0"])
74
+ end
75
+ else
76
+ s.add_dependency(%q<couchrest>, [">= 0"])
77
+ s.add_dependency(%q<rspec>, ["~> 2.3.0"])
78
+ s.add_dependency(%q<yard>, ["~> 0.6.0"])
79
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
80
+ s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
81
+ s.add_dependency(%q<rcov>, [">= 0"])
82
+ end
83
+ end
84
+
@@ -0,0 +1,3 @@
1
+ puts "this is test 1"
2
+ up do puts "this is in the up of test 1"; end
3
+ down do puts "this is in the down of test 1" end
@@ -0,0 +1,2 @@
1
+ require_relative 'couch_migrate_railtie.rb' if defined?(Rails)
2
+ Dir["#{File.dirname(__FILE__)}/couch_migrate/**/*.rb"].each {|f| require f}
@@ -0,0 +1,35 @@
1
+ module CouchMigrate
2
+ class BaseExecuter
3
+ def initialize(enabled, str, filename = "")
4
+ raise "'enabled' argument must be an Array of symbols (such as [:up, :down] or []" unless enabled.is_a?(Array)
5
+ @migration_str = str
6
+ @enabled = enabled
7
+ @filename = filename
8
+ self
9
+ end
10
+
11
+ def go
12
+ Namespaced.module_eval(<<-EOS, __FILE__, __LINE__ + 1)
13
+ def self.up
14
+ yield if #{@enabled.include?(:up)}
15
+ end
16
+
17
+ def self.down
18
+ yield if #{@enabled.include?(:down)}
19
+ end
20
+
21
+ # convenience method for migration files to use
22
+ def self.use_couchrest_model
23
+ require 'couch_migrate/couchrest_model/extend.rb'
24
+ end
25
+
26
+ EOS
27
+
28
+ Namespaced.module_eval(@migration_str, @filename)
29
+ end
30
+
31
+ module Namespaced
32
+ end
33
+ end
34
+ end
35
+
@@ -0,0 +1,96 @@
1
+ module CouchMigrate
2
+ class BaseMigrater
3
+ attr_reader :failed_migration
4
+
5
+ def initialize(persisted_list = nil, executer = nil, migration_directory = "db/migrations")
6
+ @raw_migrations = []
7
+ @completed_migrations = persisted_list || BasePersistedList.new
8
+ @executer = executer || BaseExecuter
9
+ directory(migration_directory)
10
+ self
11
+ end
12
+
13
+ def migrate(*args)
14
+ migration_reserved_args= [:quiet]
15
+ executer_args = args - migration_reserved_args
16
+
17
+ @failed_migration, completed = nil, []
18
+ direction, action, migrations = if args.include?(:down)
19
+ [:down, :remove, [completed_migrations.last]]
20
+ else
21
+ [:up, :add, pending_migrations]
22
+ end
23
+
24
+ migrations.compact.each do |migration|
25
+ begin
26
+ puts '-'*40, "Migration #{direction} (#{migration})" unless args.include?(:quiet)
27
+ str = File.read(@directory + migration)
28
+ @executer.new(executer_args, str, migration).go
29
+ completed << migration
30
+ puts '-'*40 unless args.include?(:quiet)
31
+ rescue Exception => e
32
+ @failed_migration = migration
33
+ puts '-'*5,"FAILURE in migration #{direction} (#{migration}) with message:", e.message, '-'*5, e.backtrace[0...10], '-'*40 unless args.include?(:quiet)
34
+ return {success: completed, failed: [@failed_migration]}
35
+ end
36
+ end
37
+
38
+ return completed.empty? ? {} : {success: completed}
39
+ ensure
40
+ @completed_migrations.send(action, completed)
41
+ end
42
+
43
+ def directory(path=nil)
44
+ return @directory if path.nil?
45
+ @directory = Pathname.new(path)
46
+ refresh_raw_migrations
47
+ self
48
+ end
49
+
50
+ def reset
51
+ @completed_migrations.reset
52
+ self
53
+ end
54
+
55
+ def reload
56
+ refresh_raw_migrations
57
+ self
58
+ end
59
+
60
+ def refresh_raw_migrations(arr=nil)
61
+ raise "argument must be an array" unless arr.nil? || arr.is_a?(Array)
62
+ arr ||= Pathname.new(@directory).children(with_directory = false) rescue []
63
+ @raw_migrations = filter_and_sort(arr)
64
+ self
65
+ end
66
+
67
+ def raw_migrations(arr=nil)
68
+ return @raw_migrations if arr.nil?
69
+ refresh_raw_migrations(arr)
70
+ self
71
+ end
72
+
73
+ def completed_migrations(arr=nil)
74
+ return @completed_migrations.get if arr.nil?
75
+ @completed_migrations.set(arr)
76
+ self
77
+ end
78
+
79
+ def pending_migrations
80
+ raw_migrations - completed_migrations
81
+ end
82
+
83
+ private
84
+
85
+ def filter_and_sort(arr= [])
86
+ # discard invalid formats, then sort numerically by first number, then alphabetically for remainder
87
+ format = /(\d+)_(.*)\.rb/
88
+ arr.map do |e|
89
+ name = Pathname.new(e).basename.to_s
90
+ match = format.match(name)
91
+ [name, match[1], match[2]] rescue nil
92
+ end.compact.sort_by{|e| [e[1].to_i, e[2]] }.map{|e| e[0] }
93
+ end
94
+
95
+ end
96
+ end
@@ -0,0 +1,52 @@
1
+ module CouchMigrate
2
+ class BasePersistedList
3
+
4
+ def initialize
5
+ @list = []
6
+ end
7
+
8
+ def get
9
+ read
10
+ @list
11
+ end
12
+
13
+ def set(arr)
14
+ raise "argument must be an array" unless arr.is_a?(Array)
15
+ @list = arr.dup
16
+ write
17
+ self
18
+ end
19
+
20
+ def add(arr)
21
+ raise "argument must be an array" unless arr.is_a?(Array)
22
+ @list.concat(arr).uniq!
23
+ write
24
+ self
25
+ end
26
+
27
+ def remove(arr)
28
+ raise "argument must be an array" unless arr.is_a?(Array)
29
+ @list -= arr
30
+ write
31
+ self
32
+ end
33
+
34
+ def reset
35
+ @list = []
36
+ cleanup
37
+ self
38
+ end
39
+
40
+ protected
41
+
42
+ def read
43
+ end
44
+
45
+ def write
46
+ end
47
+
48
+ def cleanup
49
+ end
50
+ end
51
+ end
52
+
@@ -0,0 +1,10 @@
1
+ module CouchMigrate
2
+ class CouchExecuter < BaseExecuter
3
+ def initialize(enabled, str, filename = nil)
4
+ super
5
+ self
6
+ end
7
+
8
+ end
9
+ end
10
+
@@ -0,0 +1,15 @@
1
+ require_relative 'base_migrater'
2
+
3
+ module CouchMigrate
4
+ class CouchMigrater < BaseMigrater
5
+ def initialize(database, migration_directory="db/migrate")
6
+ persisted_list = CouchMigrate::CouchPersistedList.new(database)
7
+ executer = CouchMigrate::CouchExecuter
8
+ super(persisted_list, executer, migration_directory)
9
+ self
10
+ end
11
+
12
+ end
13
+ end
14
+
15
+
@@ -0,0 +1,36 @@
1
+ require 'couchrest'
2
+
3
+ module CouchMigrate
4
+ class CouchPersistedList < BasePersistedList
5
+ DocName = 'migrations'
6
+ MigrationField = 'completed'
7
+
8
+ def initialize(database)
9
+ @db = CouchRest.database!(database) # find or create
10
+ raise "db cannot be created using url #{database}" if @db.nil?
11
+ super()
12
+ self
13
+ end
14
+
15
+ private
16
+
17
+ def read
18
+ @list = @db.get(DocName)[MigrationField] rescue []
19
+ end
20
+
21
+ def write
22
+ doc = @db.get(DocName) rescue {'_id' => DocName}
23
+ doc[MigrationField] = @list
24
+ @db.save_doc(doc)
25
+ end
26
+
27
+ def cleanup
28
+ @list = []
29
+ write
30
+ self
31
+ end
32
+
33
+ end
34
+
35
+ end
36
+
@@ -0,0 +1,16 @@
1
+ # use "use_couchrest_model" in the DSL or
2
+ # include this module in a migration to use CouchRest::Model
3
+ if defined?(CouchRest::CouchRest::Model)
4
+ module CouchRest
5
+ module Model
6
+ class Base
7
+ before_save :rewrite_type_for_migration_classes
8
+
9
+ def rewrite_type_for_migration_classes
10
+ class_name = self.class.to_s.sub(/CouchMigrate::BaseExecuter::Namespaced::/, '')
11
+ self['type'] = class_name
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,14 @@
1
+ require_relative 'base_migrater'
2
+
3
+ module CouchMigrate
4
+ class FileMigrater < BaseMigrater
5
+ def initialize(migration_directory="db/migrate")
6
+ persisted_list = CouchMigrate::FilePersistedList.new(migration_directory)
7
+ executer = CouchMigrate::CouchExecuter
8
+ super(persisted_list, executer, migration_directory)
9
+ self
10
+ end
11
+
12
+ end
13
+ end
14
+
@@ -0,0 +1,35 @@
1
+ require 'pathname'
2
+ require 'yaml'
3
+
4
+ module CouchMigrate
5
+ class FilePersistedList < BasePersistedList
6
+ def initialize(directory="db/migrate")
7
+ super()
8
+ path = Pathname.new(directory)
9
+ path.mkpath
10
+ @path = path+"meta.yml"
11
+ read
12
+ self
13
+ end
14
+
15
+ protected
16
+
17
+ def read
18
+ @data = YAML.load(File.read(@path)) rescue {}
19
+ @data[:complete] ||= []
20
+ @list = @data[:complete]
21
+ end
22
+
23
+ def write
24
+ @data[:complete] = @list
25
+ File.open(@path,"w"){|f| f<< YAML.dump(@data) }
26
+ end
27
+
28
+ def cleanup
29
+ @path.delete rescue nil
30
+ end
31
+
32
+ end
33
+
34
+ end
35
+
@@ -0,0 +1,8 @@
1
+ module CouchMigrate
2
+ class CouchMigrateRailtie < ::Rails::Railtie
3
+ rake_tasks do
4
+ load 'tasks/couch_migrate.rake'
5
+ end
6
+ end
7
+ end
8
+
@@ -0,0 +1,40 @@
1
+ require_relative '../couch-migrate'
2
+
3
+ def migrater
4
+ $db_path = 'http://127.0.0.1:5984/couch-migrate_development'
5
+ migrater = CouchMigrate::CouchMigrater.new($db_path)
6
+ end
7
+
8
+ namespace :couch_migrate do
9
+
10
+ desc 'migrate all pending migrations'
11
+
12
+ namespace :test do
13
+
14
+ task :migrate => ['migrate:up']
15
+
16
+ namespace :migrate do
17
+ desc 'couchdb migration up'
18
+ task 'up' => [:environment, :url] do
19
+ migrater.migrate(:up)
20
+ end
21
+
22
+ desc 'couchdb migration down'
23
+ task 'down' => [:environment, :url] do
24
+ migrater.migrate(:down)
25
+ end
26
+
27
+ desc 'couchdb migration down, then up'
28
+ task 'redo' => [:environment, :url] do
29
+ migrater.migrate(:down)
30
+ migrater.migrate(:up)
31
+ end
32
+
33
+ desc 'print couchdb URL'
34
+ task 'url' => :environment do
35
+ $stderr.puts("CouchDB URL: #{$db_path}")
36
+ end
37
+
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,93 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+ require 'couch-migrate'
3
+
4
+ describe "CouchMigrate::BaseExecuter" do
5
+ subject{ CouchMigrate::BaseExecuter }
6
+ let(:msg) { "this line was executed by the script" }
7
+ let(:execution_verification) { "raise '#{msg}'" }
8
+
9
+ describe "#go" do
10
+ let(:enabled) { [] }
11
+ it "executes a string (typically loaded from a script file)" do
12
+ lambda{ subject.new(enabled, execution_verification).go }.should raise_error(RuntimeError,msg)
13
+ end
14
+
15
+ it "enables classes to be defined" do
16
+ script =<<-EOS
17
+ class Foo
18
+ def test; #{execution_verification} end
19
+ end
20
+ up do
21
+ Foo.new.test
22
+ end
23
+ EOS
24
+ lambda{ subject.new([:up], script).go }.should raise_error(RuntimeError,msg)
25
+ end
26
+
27
+ it "enables classes to be defined, and they are namespaced" do
28
+ script =<<-EOS
29
+ class NamespacedFoo
30
+ def test; end
31
+ end
32
+ up do
33
+ NamespacedFoo.new.test
34
+ # puts Module.constants.grep(/NamespacedFoo/).inspect
35
+ # puts Namespaced.constants.grep(/NamespacedFoo/).inspect
36
+ # puts BaseExecuter::Namespaced.constants.grep(/NamespacedFoo/).inspect
37
+ # puts BaseExecuter.constants.grep(/NamespacedFoo/).inspect
38
+ # puts
39
+ end
40
+ EOS
41
+
42
+ subject.new([:up], script).go
43
+
44
+ # puts Module.constants.grep(/Foo/).inspect
45
+ # puts BaseExecuter::Namespaced.constants.grep(/Foo/).inspect
46
+ # puts BaseExecuter.constants.grep(/Foo/).inspect
47
+
48
+ Module.constants.include?(:NamespacedFoo).should == false
49
+ CouchMigrate::BaseExecuter.constants.include?(:NamespacedFoo).should == false
50
+ CouchMigrate::BaseExecuter::Namespaced.constants.include?(:NamespacedFoo).should == true
51
+ end
52
+ end
53
+
54
+ describe "#up" do
55
+ context "when enabled" do
56
+ let(:enabled) { [:up] }
57
+
58
+ it "executes its block of code" do
59
+ lambda{ subject.new(enabled,"up do raise '#{msg}' end").go }.should raise_error(RuntimeError,msg)
60
+ end
61
+ end
62
+
63
+ context "when disabled" do
64
+ let(:enabled) { [] }
65
+
66
+ it "does not executes its block of code" do
67
+ lambda{ subject.new(enabled,"up do raise '#{msg}' end").go }.should_not raise_error(RuntimeError,msg)
68
+ end
69
+ end
70
+
71
+ end
72
+
73
+ describe "#down" do
74
+ context "when enabled" do
75
+ let(:enabled) { [:down] }
76
+
77
+ it "executes its block of code" do
78
+ lambda{ subject.new(enabled,"down do raise '#{msg}' end").go }.should raise_error(RuntimeError,msg)
79
+ end
80
+ end
81
+
82
+ context "when disabled" do
83
+ let(:enabled) { [] }
84
+
85
+ it "does not executes its block of code" do
86
+ lambda{ subject.new(enabled,"down do raise '#{msg}' end").go }.should_not raise_error(RuntimeError,msg)
87
+ end
88
+ end
89
+
90
+ end
91
+
92
+ end
93
+
@@ -0,0 +1,91 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+ require 'couch-migrate'
3
+
4
+ describe "BaseMigrater", "#migrate" do
5
+ subject { CouchMigrate::BaseMigrater.new }
6
+
7
+ let(:file_name_1){ "1_migration_a.rb" }
8
+ let(:file_name_2){ "2_migration_b.rb" }
9
+ let(:file_name_3){ "3_migration_b.rb" }
10
+
11
+ it "can set migrations from a list" do
12
+ subject.raw_migrations.should == []
13
+
14
+ subject.raw_migrations([file_name_1, file_name_2]).raw_migrations.should == [file_name_1,file_name_2]
15
+ end
16
+
17
+ context "interacting with the file system" do
18
+ let(:path){ Pathname.new("spec/tmp") }
19
+ let(:file_1){ path + file_name_1 }
20
+ let(:file_2){ path + file_name_2 }
21
+ let(:file_3){ path + file_name_3 }
22
+
23
+ before(:all) do
24
+ path.mkpath
25
+ File.open(file_3,"w"){|f| f << "up do end" }
26
+ File.open(file_2,"w"){|f| f << "up do raise '2 simulated failure' end" }
27
+ File.open(file_1,"w"){|f| f << "up do end" }
28
+ end
29
+
30
+ after(:all) do
31
+ file_1.delete
32
+ file_2.delete
33
+ file_3.delete
34
+ path.rmdir rescue nil
35
+ end
36
+
37
+ it "reads the db/migrations directory to generate a list of potential migrations to run" do
38
+ subject.directory(path).raw_migrations.should == [file_name_1, file_name_2, file_name_3]
39
+ subject.directory(path).pending_migrations.should == [file_name_1, file_name_2, file_name_3]
40
+ end
41
+
42
+ it "stops when a migration file exits with an error, not processing any subsequent files afterwards" do
43
+ subject.directory(path).pending_migrations.should == [file_name_1, file_name_2, file_name_3]
44
+ subject.migrate(:quiet, :up).should == {success: [file_name_1], failed: [file_name_2]}
45
+ subject.failed_migration.should == file_name_2
46
+ subject.pending_migrations.should == [file_name_2, file_name_3]
47
+ end
48
+
49
+ end
50
+
51
+ it "does not execute migrations that have already been run" do
52
+ subject.raw_migrations([file_name_1, file_name_2]).completed_migrations([file_name_1]).pending_migrations.should == [file_name_2]
53
+ end
54
+
55
+ end
56
+
57
+ describe "BaseMigrater", "sorting and filtering" do
58
+ subject { CouchMigrate::BaseMigrater.new }
59
+
60
+ it "sorts on migration numbers" do
61
+ subject.raw_migrations(['2_name.rb','1_name.rb', '3_name.rb'])
62
+ subject.pending_migrations.should == ['1_name.rb','2_name.rb', '3_name.rb']
63
+ end
64
+
65
+ it "sorts on title if migration numbers are the same" do
66
+ subject.raw_migrations(['2_a_name.rb','2_b_name.rb'])
67
+ subject.raw_migrations.should == ['2_a_name.rb','2_b_name.rb']
68
+ end
69
+
70
+ it "sorts on title if migration numbers are the same (version 2)" do
71
+ subject.raw_migrations(['2_b_name.rb','2_a_name.rb'])
72
+ subject.raw_migrations.should == ['2_a_name.rb','2_b_name.rb']
73
+ end
74
+
75
+ it "sorts migration numbers numerically, not alphabetically" do
76
+ subject.raw_migrations(['10_name.rb','2_name.rb'])
77
+ subject.raw_migrations.should == ['2_name.rb', '10_name.rb']
78
+ end
79
+
80
+ it "sorts migration numbers numerically, not alphabetically (version 2)" do
81
+ subject.raw_migrations(['2_name.rb','10_name.rb'])
82
+ subject.raw_migrations.should == ['2_name.rb', '10_name.rb']
83
+ end
84
+
85
+ it "ignores files that do not have follow the migrationOrder_migration_title format" do
86
+ subject.raw_migrations(['2_name.rb','a_bad_name.rb'])
87
+ subject.raw_migrations.should == ['2_name.rb']
88
+ end
89
+
90
+ end
91
+
@@ -0,0 +1,44 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+ require 'couch-migrate'
3
+
4
+ describe CouchMigrate::BasePersistedList do
5
+
6
+ it "starts off with an empty value/list" do
7
+ subject.get.should == []
8
+ end
9
+
10
+ it "can set values" do
11
+ arr = [1,2,3]
12
+ subject.set(arr).get.should == arr
13
+ end
14
+
15
+ it "can append values" do
16
+ arr = [1,2,3]
17
+ more = [4,5]
18
+ expected = [1,2,3,4,5]
19
+
20
+ subject.set(arr).add(more)
21
+ subject.get.should == expected
22
+ end
23
+
24
+ it "can remove values" do
25
+ arr = [1,2,3]
26
+ remove = [2,3]
27
+ expected = [1]
28
+
29
+ subject.set(arr).remove(remove)
30
+ subject.get.should == expected
31
+ end
32
+
33
+ it "can be reset" do
34
+ subject.set([1,2,3]).reset
35
+ subject.get.should == []
36
+ end
37
+
38
+ it "is chainable" do
39
+ subject.set([1]).add([2]).get.should == [1,2]
40
+ subject.set([1]).add([2]).reset.get.should == []
41
+ end
42
+
43
+ end
44
+
@@ -0,0 +1,84 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+ require 'couch-migrate'
3
+
4
+ describe "CouchMigrater", "#migrate" do
5
+
6
+
7
+ context "interacting with the file system" do
8
+ subject { CouchMigrate::CouchMigrater }
9
+ let(:db_path) { 'http://127.0.0.1:5984/couch-migrate_test' }
10
+ let(:path){ Pathname.new("spec/tmp") }
11
+
12
+ let(:file_name_1){ "1_migration_a.rb" }
13
+ let(:file_name_2){ "2_migration_b.rb" }
14
+ let(:file_name_3){ "3_migration_b.rb" }
15
+ let(:file_path_1){ path + file_name_1 }
16
+ let(:file_path_2){ path + file_name_2 }
17
+ let(:file_path_3){ path + file_name_3 }
18
+
19
+ before(:each) do
20
+ migrater.reset # clear pre-existing migration meta data
21
+ path.mkpath
22
+ file_path_1.delete rescue nil
23
+ file_path_2.delete rescue nil
24
+ file_path_3.delete rescue nil
25
+ end
26
+
27
+ after(:each) do
28
+ # migrater.reset # remove meta file
29
+ file_path_1.delete rescue nil
30
+ file_path_2.delete rescue nil
31
+ file_path_3.delete rescue nil
32
+ path.rmdir rescue nil
33
+ end
34
+
35
+ def migrater
36
+ # allows new migrations to be picked up
37
+ res = subject.new(db_path, path)
38
+ res
39
+ end
40
+
41
+ it "handles a sequence of migration added over time" do
42
+ params = [:up, :quiet]
43
+ down_params = [:down, :quiet]
44
+
45
+ # should succeed
46
+ File.open(file_path_1,"w"){|f| f << "up do end" }
47
+ migrater.migrate(*params).should == {success: [file_name_1]}
48
+
49
+ # should do nothing
50
+ migrater.migrate(*params).should == {}
51
+
52
+ # should fail
53
+ File.open(file_path_2,"w"){|f| f << "up do raise '2 simulated failure' end" }
54
+ migrater.migrate(*params).should == {success: [], failed: [file_name_2]}
55
+
56
+ # should pass now
57
+ File.open(file_path_2,"w"){|f| f << "up do end" }
58
+ migrater.migrate(*params).should == {success: [file_name_2]}
59
+
60
+ # should succeed
61
+ File.open(file_path_3,"w"){|f| f << "up do end" }
62
+ migrater.migrate(*params).should == {success: [file_name_3]}
63
+
64
+ # should do nothing
65
+ migrater.migrate(*params).should == {}
66
+
67
+ # resetting the migration causes all to be run next time
68
+ migrater.reset
69
+ migrater.migrate(*params).should == {success: [file_name_1, file_name_2, file_name_3]}
70
+
71
+ # Down * 3
72
+ migrater.migrate(*down_params).should == {success: [file_name_3]}
73
+ migrater.migrate(*down_params).should == {success: [file_name_2]}
74
+ migrater.migrate(*down_params).should == {success: [file_name_1]}
75
+
76
+ # Down does nothing
77
+ migrater.migrate(*down_params).should == {}
78
+ end
79
+
80
+ end
81
+
82
+ end
83
+
84
+
@@ -0,0 +1,40 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+ require 'couch-migrate'
3
+
4
+ describe CouchMigrate::CouchPersistedList do
5
+ let(:db_path) { 'http://127.0.0.1:5984/couch-migrate_test' }
6
+ subject { CouchMigrate::CouchPersistedList.new(db_path) }
7
+
8
+ before(:each) do
9
+ subject.reset
10
+ end
11
+
12
+ it "starts off with an empty value/list" do
13
+ subject.get.should == []
14
+ end
15
+
16
+ it "can set values" do
17
+ arr = [1,2,3]
18
+ subject.set(arr).get.should == arr
19
+ end
20
+
21
+ it "can append values" do
22
+ arr = [1,2,3]
23
+ more = [4,5]
24
+ expected = [1,2,3,4,5]
25
+
26
+ subject.set(arr).add(more)
27
+ subject.get.should == expected
28
+ end
29
+
30
+ it "can be reset" do
31
+ subject.set([1,2,3]).reset
32
+ subject.get.should == []
33
+ end
34
+
35
+ it "is chainable" do
36
+ subject.set([1]).add([2]).get.should == [1,2]
37
+ subject.set([1]).add([2]).reset.get.should == []
38
+ end
39
+
40
+ end
@@ -0,0 +1,87 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+ require 'couch-migrate'
3
+
4
+ describe "FileMigrater", "#migrate" do
5
+
6
+
7
+ context "interacting with the file system" do
8
+ subject { CouchMigrate::FileMigrater }
9
+ let(:path){ Pathname.new("spec/tmp") }
10
+
11
+ let(:file_name_1){ "1_migration_a.rb" }
12
+ let(:file_name_2){ "2_migration_b.rb" }
13
+ let(:file_name_3){ "3_migration_b.rb" }
14
+ let(:file_path_1){ path + file_name_1 }
15
+ let(:file_path_2){ path + file_name_2 }
16
+ let(:file_path_3){ path + file_name_3 }
17
+
18
+ before(:each) do
19
+ migrater.reset # clear pre-existing migration meta data
20
+ path.mkpath
21
+ file_path_1.delete rescue nil
22
+ file_path_2.delete rescue nil
23
+ file_path_3.delete rescue nil
24
+ end
25
+
26
+ after(:each) do
27
+ migrater.reset # remove meta file
28
+ file_path_1.delete rescue nil
29
+ file_path_2.delete rescue nil
30
+ file_path_3.delete rescue nil
31
+ path.rmdir rescue nil
32
+ end
33
+
34
+ def migrater
35
+ # allows new migrations to be picked up
36
+ subject.new(path)
37
+ end
38
+
39
+ it "handles a sequence of migration added over time" do
40
+ up_params = [:up, :quiet]
41
+ down_params = [:down, :quiet]
42
+
43
+ # should succeed
44
+ File.open(file_path_1,"w"){|f| f << "up do end" }
45
+ migrater.migrate(*up_params).should == {success: [file_name_1]}
46
+
47
+ # should do nothing
48
+ migrater.migrate(*up_params).should == {}
49
+
50
+ # should fail
51
+ File.open(file_path_2,"w"){|f| f << "up do raise '2 simulated failure' end" }
52
+ migrater.migrate(*up_params).should == {success: [], failed: [file_name_2]}
53
+
54
+ # should pass now
55
+ File.open(file_path_2,"w"){|f| f << "up do end" }
56
+ migrater.migrate(*up_params).should == {success: [file_name_2]}
57
+
58
+ # Down
59
+ migrater.migrate(*down_params).should == {success: [file_name_2]}
60
+
61
+ # up
62
+ migrater.migrate(*up_params).should == {success: [file_name_2]}
63
+
64
+ # should succeed
65
+ File.open(file_path_3,"w"){|f| f << "up do end" }
66
+ migrater.migrate(*up_params).should == {success: [file_name_3]}
67
+
68
+ # should do nothing
69
+ migrater.migrate(*up_params).should == {}
70
+
71
+ # resetting the migration causes all to be run next time
72
+ migrater.reset
73
+ migrater.migrate(*up_params).should == {success: [file_name_1, file_name_2, file_name_3]}
74
+
75
+ # Down * 3
76
+ migrater.migrate(*down_params).should == {success: [file_name_3]}
77
+ migrater.migrate(*down_params).should == {success: [file_name_2]}
78
+ migrater.migrate(*down_params).should == {success: [file_name_1]}
79
+
80
+ # Down does nothing
81
+ migrater.migrate(*down_params).should == {}
82
+ end
83
+
84
+ end
85
+
86
+ end
87
+
@@ -0,0 +1,42 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+ require 'couch-migrate'
3
+ require 'pathname'
4
+
5
+ describe CouchMigrate::FilePersistedList do
6
+ let(:path){ Pathname.new("spec/tmp") }
7
+ subject { CouchMigrate::FilePersistedList.new(path) }
8
+
9
+ after(:all) do
10
+ Pathname.new(path).delete
11
+ end
12
+
13
+ it "starts off with an empty value/list" do
14
+ subject.get.should == []
15
+ end
16
+
17
+ it "can set values" do
18
+ arr = [1,2,3]
19
+ subject.set(arr).get.should == arr
20
+ end
21
+
22
+ it "can append values" do
23
+ arr = [1,2,3]
24
+ more = [4,5]
25
+ expected = [1,2,3,4,5]
26
+
27
+ subject.set(arr).add(more)
28
+ subject.get.should == expected
29
+ end
30
+
31
+ it "can be reset" do
32
+ subject.set([1,2,3]).reset
33
+ subject.get.should == []
34
+ end
35
+
36
+ it "is chainable" do
37
+ subject.set([1]).add([2]).get.should == [1,2]
38
+ subject.set([1]).add([2]).reset.get.should == []
39
+ end
40
+
41
+ end
42
+
@@ -0,0 +1,11 @@
1
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
3
+ require 'rspec'
4
+
5
+ # Requires supporting files with custom matchers and macros, etc,
6
+ # in ./support/ and its subdirectories.
7
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
8
+
9
+ RSpec.configure do |config|
10
+
11
+ end
metadata ADDED
@@ -0,0 +1,148 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: couch-migrate
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Greg Edwards
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-09-20 00:00:00.000000000 -06:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: couchrest
17
+ requirement: &2157870300 !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ! '>='
21
+ - !ruby/object:Gem::Version
22
+ version: '0'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: *2157870300
26
+ - !ruby/object:Gem::Dependency
27
+ name: rspec
28
+ requirement: &2157869180 !ruby/object:Gem::Requirement
29
+ none: false
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: 2.3.0
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: *2157869180
37
+ - !ruby/object:Gem::Dependency
38
+ name: yard
39
+ requirement: &2157868040 !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - ~>
43
+ - !ruby/object:Gem::Version
44
+ version: 0.6.0
45
+ type: :development
46
+ prerelease: false
47
+ version_requirements: *2157868040
48
+ - !ruby/object:Gem::Dependency
49
+ name: bundler
50
+ requirement: &2157866720 !ruby/object:Gem::Requirement
51
+ none: false
52
+ requirements:
53
+ - - ~>
54
+ - !ruby/object:Gem::Version
55
+ version: 1.0.0
56
+ type: :development
57
+ prerelease: false
58
+ version_requirements: *2157866720
59
+ - !ruby/object:Gem::Dependency
60
+ name: jeweler
61
+ requirement: &2157865660 !ruby/object:Gem::Requirement
62
+ none: false
63
+ requirements:
64
+ - - ~>
65
+ - !ruby/object:Gem::Version
66
+ version: 1.6.4
67
+ type: :development
68
+ prerelease: false
69
+ version_requirements: *2157865660
70
+ - !ruby/object:Gem::Dependency
71
+ name: rcov
72
+ requirement: &2157864760 !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ type: :development
79
+ prerelease: false
80
+ version_requirements: *2157864760
81
+ description: A simple migration system for CouchDB.
82
+ email: greg@greglearns.com
83
+ executables: []
84
+ extensions: []
85
+ extra_rdoc_files:
86
+ - LICENSE.txt
87
+ - README.rdoc
88
+ files:
89
+ - .document
90
+ - .rspec
91
+ - Gemfile
92
+ - Gemfile.lock
93
+ - LICENSE.txt
94
+ - README.rdoc
95
+ - Rakefile
96
+ - VERSION
97
+ - couch-migrate.gemspec
98
+ - db/migrate/1_test.rb
99
+ - lib/couch-migrate.rb
100
+ - lib/couch_migrate/base_executer.rb
101
+ - lib/couch_migrate/base_migrater.rb
102
+ - lib/couch_migrate/base_persisted_list.rb
103
+ - lib/couch_migrate/couch_executer.rb
104
+ - lib/couch_migrate/couch_migrater.rb
105
+ - lib/couch_migrate/couch_persisted_list.rb
106
+ - lib/couch_migrate/couchrest_model/extend.rb
107
+ - lib/couch_migrate/file_migrater.rb
108
+ - lib/couch_migrate/file_persisted_list.rb
109
+ - lib/couch_migrate_railtie.rb
110
+ - lib/tasks/couch_migrate.rake
111
+ - spec/couch_migrate/base_executer_spec.rb
112
+ - spec/couch_migrate/base_migrater_spec.rb
113
+ - spec/couch_migrate/base_persisted_list_spec.rb
114
+ - spec/couch_migrate/couch_migrater_spec.rb
115
+ - spec/couch_migrate/couch_persisted_list_spec.rb
116
+ - spec/couch_migrate/file_migrater_spec.rb
117
+ - spec/couch_migrate/file_persisted_list_spec.rb
118
+ - spec/spec_helper.rb
119
+ has_rdoc: true
120
+ homepage: https://github.com/gedwards/couch-migrate
121
+ licenses:
122
+ - MIT
123
+ post_install_message:
124
+ rdoc_options: []
125
+ require_paths:
126
+ - lib
127
+ required_ruby_version: !ruby/object:Gem::Requirement
128
+ none: false
129
+ requirements:
130
+ - - ! '>='
131
+ - !ruby/object:Gem::Version
132
+ version: '0'
133
+ segments:
134
+ - 0
135
+ hash: 952696308215902437
136
+ required_rubygems_version: !ruby/object:Gem::Requirement
137
+ none: false
138
+ requirements:
139
+ - - ! '>='
140
+ - !ruby/object:Gem::Version
141
+ version: '0'
142
+ requirements: []
143
+ rubyforge_project:
144
+ rubygems_version: 1.6.2
145
+ signing_key:
146
+ specification_version: 3
147
+ summary: A simple migration system for CouchDB
148
+ test_files: []