communard 0.0.5 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 803308ca6f5424ff74123dcbb892f6ef6b76ecd0
4
- data.tar.gz: 310a953d2846d2f7f0b7f0188ae69c84635260d9
2
+ SHA256:
3
+ metadata.gz: 94f9d91890f50281fc8ce1d4678153cf2aff2c2068c00166774aeeafe80dfb16
4
+ data.tar.gz: cd21196d14631a2e3eda1435e16c4fd4afdabc1da2ab16d0d198290c1275e153
5
5
  SHA512:
6
- metadata.gz: bcd25b010ae79cc52aa3c50cea57d74072d924f68b3d84873d7399396052305d67beacf728d920e788ea7c0ca11bcd870cb6d036b5994938dc28e3eaa85f0f3d
7
- data.tar.gz: e5c9d2270735b60a121e5057215f7d359268472398e16f4101bd605c09bb509f64162d9f1cedfaba4fe216be5f9b6b37befe056383a9148925287b5e66ca7223
6
+ metadata.gz: 4968eb2fb22782695eb7335028f0d8fb76d58a3bb4fe437ec3e3da75fb8b1edc74cc66a8b2fceeabbad8c6c44aa7adf8c206566ba08fed93552ec8fe356521ae
7
+ data.tar.gz: 55000cbc291e4ca20050c1fff461b709f689aeea3a17f28d922ec8c69220d042dbd22ff628f5be8ce2889594ab9c0d8fa652ac82b9b60c6113d16d3e278e7101
data/README.md CHANGED
@@ -2,9 +2,6 @@
2
2
 
3
3
  Communard adds some conventions from [ActiveRecord][ar] to [Sequel][sq].
4
4
 
5
- This means you can use `config/database.yml` and `db/migrate` again, so you
6
- don't have to change deployment scripts that are made for ActiveRecord.
7
-
8
5
  Sequel doesn't provide the exact same functionality as ActiveRecord. Communard
9
6
  doesn't try to make Sequel quack like ActiveRecord, it just tries to help with
10
7
  some (not all) setup.
@@ -31,25 +28,15 @@ $ gem install communard
31
28
 
32
29
  ## Usage
33
30
 
34
- ### Connecting to the database
35
-
36
- To get a database connection:
37
-
38
- ``` ruby
39
- DB = Communard.connect
40
- ```
41
-
42
- The `DB` object will be familiar to you if you've ever read the Sequel documentation.
43
-
44
- Note: Communard doesn't remember your connection.
45
-
46
31
  ### Rake integration
47
32
 
48
33
  To add most Rake tasks, add this to your `Rakefile` or to `lib/tasks/communard.rake`:
49
34
 
50
35
  ``` ruby
51
36
  require "communard/rake"
52
- Communard::Rake.add_tasks
37
+ namespace :db do
38
+ Communard::Rake.add_tasks
39
+ end
53
40
  ```
54
41
 
55
42
  This will add the most used rake tasks, like `db:create`, `db:migrate`, and `db:setup`.
@@ -60,34 +47,68 @@ To see them all:
60
47
  $ rake -T db
61
48
  ```
62
49
 
50
+ `Communard::Rake.add_tasks` accepts the same configuration options as
51
+ `Sequel.connect`. It doesn't immediately make a connection, only when needed.
52
+
53
+ The default connection string is `ENV["DATABASE_URL"]`, so if you use that,
54
+ there is no need to configure anything.
55
+
56
+ Other configuration options, can be set via a block:
57
+
58
+ ``` ruby
59
+ namespace :db do
60
+ Communard::Rake.add_tasks do |config|
61
+
62
+ # Change where the application is located, defaults to Dir.pwd
63
+ config.root_path = Dir.pwd
64
+
65
+ # Automatically generate schema (default: false)
66
+ config.dump_after_migrating = false
67
+
68
+ # Dump types in native format (default) or Ruby (more portable)
69
+ config.same_db = true
70
+
71
+ # Add a logger
72
+ config.logger = Logger.new("log/migrations.log")
73
+
74
+ end
75
+ end
76
+ ```
77
+
78
+ Example with using `config/database.yml`:
79
+
80
+ ``` ruby
81
+ namespace :db do
82
+ environment = ENV["RAILS_ENV"] || "development"
83
+ all_config = YAML.load_file("config/database.yml")
84
+ Communard::Rake.add_tasks(config.fetch(environment))
85
+ end
86
+ ```
87
+
88
+ Note about test environment: Communard doesn't try to create a test database
89
+ like ActiveRecord does. The only rake task that attempts to do that is
90
+ `rake db:test:prepare`. It respawns rake with different environment variables
91
+ set. Your mileage may vary.
92
+
63
93
  ### Migrations
64
94
 
65
95
  To generate a migration:
66
96
 
67
97
  ```
68
- $ bundle exec communard --generate-migration create_posts
98
+ $ communard migration create_posts
69
99
  ```
70
100
 
71
101
  Communard doesn't support more arguments, like the Rails generator does. You'll
72
102
  have to edit the generated migration file yourself.
73
103
 
74
- ### Configuration
75
-
76
- There are a couple of configuration options available. They can be set by giving
77
- a block to `connect` or `add_tasks`. Under normal circumstances you don't need
78
- to set them.
79
-
80
- ``` ruby
81
- DB = Communard.connect { |config|
82
- config.root = Rails.root
83
- config.logger = Rails.logger
84
- config.environment = Rails.env.to_s
85
- }
86
- ```
104
+ Communard supports both timestamps and integer versions. It automatically
105
+ detects which type you have. If you have no migrations yet and want to use
106
+ timestamps, add `--timestamps`. Read more about how to choose in the
107
+ [Sequel docs][tm].
87
108
 
88
109
  ## Contributing
89
110
 
90
- 1. Fork it ( https://github.com/yourkarma/communard/fork )
111
+ 1. Fork it ( https://github.com/iain/communard/fork )
91
112
  2. Create your feature branch (`git checkout -b my-new-feature`)
92
113
  3. Commit your changes (`git commit -am 'Add some feature'`)
93
114
  4. Push to the branch (`git push origin my-new-feature`)
@@ -95,3 +116,4 @@ DB = Communard.connect { |config|
95
116
 
96
117
  [ar]: http://rubyonrails.org
97
118
  [sq]: http://sequel.jeremyevans.net
119
+ [tm]: http://sequel.jeremyevans.net/rdoc/files/doc/migration_rdoc.html#label-How+to+choose
data/bin/communard CHANGED
@@ -1,26 +1,54 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- require "communard"
4
- require "optparse"
3
+ command = ARGV.shift
5
4
 
6
- parser = OptionParser.new do |opts|
5
+ case command
7
6
 
8
- opts.on "-m", "--generate-migration NAME", "Generates a migration" do |name|
9
- Communard.context.generate_migration(name: name)
10
- exit
11
- end
7
+ when nil, "-h", "--help", "help"
8
+ puts "Usage: communard migration NAME"
9
+ exit
10
+
11
+ when "-v", "--version"
12
+ require "communard"
13
+ puts Communard::VERSION
14
+ exit
15
+
16
+ when "migration", "-m", "--generate-migration", "m"
17
+ migration_name = ARGV.shift
18
+
19
+ require "optparse"
20
+ require "pathname"
21
+ require "fileutils"
22
+
23
+ migrations_dir = Pathname(Dir.pwd).join("db/migrate")
24
+ FileUtils.mkdir_p(migrations_dir)
25
+
26
+ migration_files = Pathname.glob(migrations_dir.join("*.rb")).map { |f| f.basename.to_s }
12
27
 
13
- opts.on_tail "-v", "--version" do
14
- puts "Communard version #{Communard::VERSION}"
15
- exit
28
+ if (conflict = migration_files.find { |f| f.match?(/\A\d+_#{migration_name}.rb\z/) })
29
+ abort "Migration with same name already exists: #{conflict}"
16
30
  end
17
31
 
18
- opts.on_tail "-h", "--help" do
19
- puts parser
20
- exit
32
+ options = {}
33
+
34
+ OptionParser.new do |opts|
35
+ opts.on "--[no-]timestamps", "Use timestamps for versions" do |bool|
36
+ options[:use_timestamps] = bool
37
+ end
38
+ end.parse!
39
+
40
+ versions = migration_files.map { |file| file.to_s.split("_", 2).first.to_i }
41
+
42
+ if !options.has_key?(:use_timestamps)
43
+ options[:use_timestamps] = versions.any? { |v| v > 20000101 }
21
44
  end
22
45
 
23
- end
24
- parser.parse!
46
+ version = options[:use_timestamps] ? Time.now.strftime("%Y%m%d%H%M%S") : "%03d" % (versions.max.to_i + 1)
47
+
48
+ filename = migrations_dir.join("#{version}_#{migration_name}.rb")
25
49
 
26
- puts parser
50
+ File.open(filename, "w") { |f| f.puts "Sequel.migration do\n\n change do\n end\n\nend" }
51
+ puts "Migration generated: #{filename.relative_path_from(Pathname(Dir.pwd))}"
52
+ else
53
+ abort "Unknown command: #{command}"
54
+ end
data/communard.gemspec CHANGED
@@ -10,7 +10,7 @@ Gem::Specification.new do |spec|
10
10
  spec.email = ["iain@iain.nl"]
11
11
  spec.summary = %q{Adds some conventions from ActiveRecord to Sequel.}
12
12
  spec.description = %q{Adds some conventions from ActiveRecord to Sequel.}
13
- spec.homepage = "https://github.com/yourkarma/communard"
13
+ spec.homepage = "https://github.com/iain/communard"
14
14
  spec.license = "MIT"
15
15
 
16
16
  spec.files = `git ls-files -z`.split("\x0")
@@ -18,7 +18,7 @@ Gem::Specification.new do |spec|
18
18
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
19
  spec.require_paths = ["lib"]
20
20
 
21
- spec.add_dependency "sequel", "~> 4.13"
21
+ spec.add_dependency "sequel", "~> 5.2"
22
22
 
23
23
  spec.add_development_dependency "bundler", "~> 1.6"
24
24
  spec.add_development_dependency "rake"
@@ -0,0 +1,156 @@
1
+ require "forwardable"
2
+
3
+ module Communard
4
+ class Commands
5
+
6
+ extend Forwardable
7
+
8
+ attr_reader :configuration
9
+
10
+ def_delegators :configuration,
11
+ :connection,
12
+ :adapter,
13
+ :database_name,
14
+ :options,
15
+ :root_path
16
+
17
+ def initialize(configuration)
18
+ @configuration = configuration
19
+ Sequel.extension :migration, :core_extensions
20
+ end
21
+
22
+ def create_database
23
+ return if adapter == "sqlite"
24
+ run_without_database("CREATE DATABASE %{database_name}")
25
+ rescue Sequel::DatabaseError => error
26
+ if error.message.to_s =~ /database (.*) already exists/
27
+ configuration.default_logger.warn "Database #{$1} already exists."
28
+ else
29
+ raise
30
+ end
31
+ end
32
+
33
+ def drop_database
34
+ if adapter == "sqlite"
35
+ file = database_name
36
+ File.rm(file) if File.exist?(file)
37
+ else
38
+ run_without_database("DROP DATABASE IF EXISTS %{database_name}")
39
+ end
40
+ end
41
+
42
+ def migrate(target: nil)
43
+ target = Integer(target) if target
44
+ migrator(target: target, current: nil).run
45
+ dump_schema if target.nil? && configuration.dump_after_migrating
46
+ end
47
+
48
+ def seed
49
+ load seeds_file if seeds_file.exist?
50
+ end
51
+
52
+ def rollback(step: 1)
53
+ target = applied_migrations[-step - 1]
54
+ if target
55
+ migrate(target: target.split(/_/, 2).first)
56
+ else
57
+ fail ArgumentError, "Cannot roll back to #{step}"
58
+ end
59
+ end
60
+
61
+ def load_schema
62
+ migration = instance_eval(schema_file.read, schema_file.expand_path.to_s, 1)
63
+ conn = configuration.silent_connection
64
+ migration.apply(conn, :up)
65
+ end
66
+
67
+ def dump_schema
68
+ conn = configuration.silent_connection
69
+ conn.extension :schema_dumper
70
+ schema = conn.dump_schema_migration(same_db: configuration.same_db)
71
+ schema_file.open("w") { |f| f.puts schema.gsub(/^\s+$/m, "").gsub(/:(\w+)=>/, '\1: ') }
72
+ end
73
+
74
+ def status
75
+ results = Hash.new { |h, k| h[k] = Status.new(k, false, false) }
76
+ available = Pathname.glob(migrations_dir.join("*.rb")).map(&:basename).map(&:to_s)
77
+ available.each { |migration| results[migration].available = true }
78
+ applied_migrations(available).each { |migration| results[migration].applied = true }
79
+
80
+ $stdout.puts
81
+ $stdout.puts "database: #{connection.opts.fetch(:database)}"
82
+ $stdout.puts
83
+ $stdout.puts " Status Migration ID Migration Name"
84
+ $stdout.puts "--------------------------------------------------"
85
+ results.values.sort.each do |result|
86
+ $stdout.puts " %-7s %-15s %s" % [ result.status, result.id, result.name ]
87
+ end
88
+ $stdout.puts
89
+ end
90
+
91
+ def run_without_database(query)
92
+ opts = options.dup
93
+ database_name = opts.delete("database")
94
+ if adapter == "postgres"
95
+ opts["database"] = "postgres"
96
+ opts["schema_search_path"] = "public"
97
+ end
98
+ conn = Sequel.connect(opts)
99
+ conn.run(query % { database_name: database_name })
100
+ end
101
+
102
+ private
103
+
104
+ def applied_migrations(available)
105
+ m = migrator(allow_missing_migration_files: true)
106
+ if m.is_a?(Sequel::IntegerMigrator)
107
+ available.select { |f| f.split("_", 2).first.to_i <= m.current }
108
+ else
109
+ instance.applied_migrations
110
+ end
111
+ end
112
+
113
+ def migrator(opts = {})
114
+ migrator = Sequel::Migrator.migrator_class(migrations_dir)
115
+ migrator.new(connection, migrations_dir, opts)
116
+ end
117
+
118
+ def schema_file
119
+ root_path.join("db/schema.rb")
120
+ end
121
+
122
+ def seeds_file
123
+ root_path.join("db/seeds.rb")
124
+ end
125
+
126
+ def migrations_dir
127
+ root_path.join("db/migrate")
128
+ end
129
+
130
+ Status = Struct.new(:file, :applied, :available) do
131
+
132
+ def <=>(other)
133
+ id <=> other.id
134
+ end
135
+
136
+ def status
137
+ return "????" unless available
138
+ applied ? " up " : "down"
139
+ end
140
+
141
+ def id
142
+ splitted.first
143
+ end
144
+
145
+ def name
146
+ splitted.last.capitalize.tr("_", " ").sub(/\.rb$/, "")
147
+ end
148
+
149
+ def splitted
150
+ file.split(/_/, 2)
151
+ end
152
+
153
+ end
154
+
155
+ end
156
+ end
@@ -1,52 +1,97 @@
1
+ require "pathname"
2
+ require "logger"
3
+ require "uri"
4
+
1
5
  module Communard
2
6
  class Configuration
3
7
 
4
- attr_accessor :environment, :root, :dump_same_db, :loggers, :sql_log_level, :log_warn_duration
8
+ attr_reader :options
9
+
10
+ def initialize(conn_string = ENV["DATABASE_URL"], opts = Sequel::OPTS)
11
+ @conn_string = conn_string
12
+ @opts = opts
13
+
14
+ case conn_string
15
+ when String
16
+ uri = URI.parse(conn_string)
17
+ @options = {
18
+ "adapter" => uri.scheme,
19
+ "user" => uri.user,
20
+ "password" => uri.password,
21
+ "port" => uri.port,
22
+ "host" => uri.hostname,
23
+ "database" => (m = %r{/(.*)}.match(uri.path)) && (m[1]),
24
+ }
25
+ when Hash
26
+ @options = conn_string.map { |k, v| [ k.to_s, v ] }.to_h
27
+ else
28
+ raise ArgumentError, "Sequel::Database.connect takes either a Hash or a String, given: #{conn_string.inspect}"
29
+ end
30
+
31
+ self.root_path = Dir.pwd
32
+ self.logger = nil
33
+ self.dump_after_migrating = true
34
+ self.same_db = true
5
35
 
6
- def initialize
7
- self.environment = ENV["RACK_ENV"] || ENV["RUBY_ENV"] || ENV["RACK_ENV"] || "development"
8
- self.root = Pathname(Dir.pwd)
9
- self.logger = stdout_logger
10
- self.log_level = :info
11
- self.dump_same_db = false
12
- self.sql_log_level = :debug
13
- self.log_warn_duration = 0.5
14
36
  yield self if block_given?
15
37
  end
16
38
 
17
- def dump_same_db!
18
- self.dump_same_db = true
19
- end
39
+ attr_accessor :logger
40
+
41
+ attr_accessor :same_db
42
+
43
+ attr_accessor :dump_after_migrating
20
44
 
21
- def logger=(logger)
22
- self.loggers = [logger]
45
+ attr_reader :root_path
46
+
47
+ def root_path=(path)
48
+ @root_path = Pathname(path)
23
49
  end
24
50
 
25
- def loggers
26
- Array(@loggers).compact
51
+ def connection
52
+ Sequel.connect(@conn_string, @opts).tap { |c|
53
+ c.loggers = [logger, default_logger].compact
54
+ c.sql_log_level = :debug
55
+ }
27
56
  end
28
57
 
29
- def log_level=(level)
30
- real_level = ::Logger.const_get(level.to_s.upcase)
31
- loggers.each do |logger|
32
- logger.level = real_level
33
- end
58
+ def silent_connection
59
+ Sequel.connect(@conn_string, @opts).tap { |c|
60
+ c.loggers = [logger].compact
61
+ }
34
62
  end
35
63
 
36
- def stdout_logger(out = $stdout)
64
+ def default_logger(out = $stdout)
37
65
  ::Logger.new(out).tap { |l|
38
66
  alternate = 0
39
67
  l.formatter = Proc.new { |sev, _, _, msg|
40
68
  alternate = ((alternate + 1) % 2)
41
- color = case sev
42
- when "INFO" then 35 + alternate
43
- when "DEBUG" then 90
44
- else 31
69
+ msg = if sev == "DEBUG"
70
+ " #{msg}"
71
+ else
72
+ "[#{sev}] #{msg}"
73
+ end
74
+ if out.tty?
75
+ color = case sev
76
+ when "INFO" then 35 + alternate
77
+ when "DEBUG" then 30
78
+ else 31
79
+ end
80
+ "\e[#{color}m#{msg}\e[0m\n"
81
+ else
82
+ "#{msg}\n"
45
83
  end
46
- "\e[#{color}m[#{sev}]\e[0m #{msg}\n"
47
84
  }
48
85
  }
49
86
  end
50
87
 
88
+ def adapter
89
+ options.fetch("adapter")
90
+ end
91
+
92
+ def database_name
93
+ options.fetch("database")
94
+ end
95
+
51
96
  end
52
97
  end
@@ -5,83 +5,87 @@ module Communard
5
5
 
6
6
  extend ::Rake::DSL if defined?(::Rake::DSL)
7
7
 
8
- def self.add_tasks(ns = :db, &block)
9
-
10
- namespace ns do
11
- task :_load_communard do
12
- @_communard_context = Communard.context(&block)
13
- end
8
+ def self.add_tasks(*args, &block)
9
+ task :_load_communard do
10
+ @_communard_commands = Communard.commands(*args, &block)
11
+ end
14
12
 
15
- desc "Creates the database, migrate the schema, and loads seed data"
16
- task :setup => [:create, :migrate, :seed, "db:test:prepare"]
13
+ desc "Creates the database, migrate the schema, and loads seed data"
14
+ task setup: ["db:create", "db:migrate", "db:seed", "db:test:prepare"]
17
15
 
18
- desc "Creates the database"
19
- task :create => :_load_communard do
20
- @_communard_context.create_database
21
- end
16
+ desc "Creates the database"
17
+ task create: :_load_communard do
18
+ @_communard_commands.create_database
19
+ end
22
20
 
23
- desc "Drops the database"
24
- task :drop => :_load_communard do
25
- @_communard_context.drop_database
26
- end
21
+ desc "Drops the database"
22
+ task drop: :_load_communard do
23
+ @_communard_commands.drop_database
24
+ end
27
25
 
28
- desc "Drops and creates the database"
29
- task :reset => [:drop, :setup]
26
+ desc "Drops and creates the database"
27
+ task reset: ["db:drop", "db:setup"]
30
28
 
31
- desc "Migrate the database"
32
- task :migrate => :_load_communard do
33
- target = ENV["VERSION"] || ENV["TARGET"]
34
- @_communard_context.migrate(target: target)
35
- end
29
+ desc "Migrate the database"
30
+ task migrate: :_load_communard do
31
+ target = ENV["TARGET"]
32
+ @_communard_commands.migrate(target: target)
33
+ end
36
34
 
37
- desc "Load the seed data from db/seeds.rb"
38
- task :seed => :_load_communard do
39
- @_communard_context.seed
40
- end
35
+ desc "Load the seed data from db/seeds.rb"
36
+ task seed: :_load_communard do
37
+ @_communard_commands.seed
38
+ end
41
39
 
42
- desc "Rolls the schema back to the previous version"
43
- task :rollback => :_load_communard do
44
- step = Integer(ENV["STEP"] || 1)
45
- @_communard_context.rollback(step: step)
46
- end
40
+ desc "Rolls the schema back to the previous version"
41
+ task rollback: :_load_communard do
42
+ step = Integer(ENV["STEP"] || 1)
43
+ @_communard_commands.rollback(step: step)
44
+ end
47
45
 
48
- namespace :test do
49
- desc "Cleans the test database"
50
- task :prepare => :_load_communard do
51
- context = @_communard_context
52
- context.drop_database(env: "test")
53
- context.create_database(env: "test")
54
- context.migrate(env: "test")
55
- end
46
+ namespace :test do
47
+ desc "Cleans the test database"
48
+ task prepare: :_load_communard do
49
+ env = {
50
+ "RACK_ENV" => "test",
51
+ "RAILS_ENV" => "test",
52
+ "RUBY_ENV" => "test",
53
+ "DATABASE_URL" => nil,
54
+ }
55
+ Process.spawn(env, $PROGRAM_NAME, "db:drop", "db:create", "db:schema:load")
56
+ _pid, status = Process.wait2
57
+ fail "Failed to re-create test database" if status.exitstatus != 0
56
58
  end
59
+ end
57
60
 
58
- namespace :migrate do
61
+ namespace :migrate do
59
62
 
60
- desc "Redo the last migration"
61
- task :redo => :_load_communard do
62
- context = @_communard_context
63
- context.rollback
64
- context.migrate
65
- end
63
+ desc "Redo the last migration"
64
+ task redo: :_load_communard do
65
+ commands = @_communard_commands
66
+ commands.rollback
67
+ commands.migrate
68
+ end
66
69
 
67
- desc "Display status of migrations"
68
- task :status, :_load_communard do
69
- @_communard_context.status
70
- end
70
+ desc "Display status of migrations"
71
+ task status: :_load_communard do
72
+ @_communard_commands.status
71
73
  end
72
74
 
73
- namespace :schema do
75
+ desc "Drop and recreate database with migrations"
76
+ task reset: ["db:drop", "db:create", "db:migrate"]
77
+ end
74
78
 
75
- desc "Load the schema from db/schema.rb"
76
- task :load => :_load_communard do
77
- @_communard_context.load_schema
78
- end
79
+ namespace :schema do
79
80
 
80
- desc "Dumps the schema to db/schema.rb"
81
- task :dump => :_load_communard do
82
- @_communard_context.dump_schema
83
- end
81
+ desc "Load the schema from db/schema.rb"
82
+ task load: :_load_communard do
83
+ @_communard_commands.load_schema
84
+ end
84
85
 
86
+ desc "Dumps the schema to db/schema.rb"
87
+ task dump: :_load_communard do
88
+ @_communard_commands.dump_schema
85
89
  end
86
90
 
87
91
  end
@@ -1,3 +1,5 @@
1
1
  module Communard
2
- VERSION = "0.0.5"
2
+
3
+ VERSION = "0.1.0"
4
+
3
5
  end
data/lib/communard.rb CHANGED
@@ -1,24 +1,17 @@
1
- require "sequel"
2
- require "logger"
3
- require "pathname"
1
+ require "sequel/core"
4
2
 
5
3
  require "communard/version"
6
- require "communard/maintenance"
7
4
  require "communard/configuration"
8
- require "communard/context"
5
+ require "communard/commands"
9
6
 
10
7
  module Communard
11
8
 
12
- def self.connect(&block)
13
- context(&block).connect
9
+ def self.commands(*args, &block)
10
+ Commands.new(configuration(*args, &block))
14
11
  end
15
12
 
16
- def self.context(&block)
17
- Context.new(configuration(&block))
18
- end
19
-
20
- def self.configuration(&block)
21
- Configuration.new(&block)
13
+ def self.configuration(*args, &block)
14
+ Configuration.new(*args, &block)
22
15
  end
23
16
 
24
17
  end
@@ -3,57 +3,34 @@ require "yaml"
3
3
  RSpec.describe "Integration", type: :aruba do
4
4
 
5
5
  example "SQLite" do
6
- run_tests(
7
- "adapter" => "sqlite",
8
- "database" => "db/test.sqlite3",
9
- "pool" => 5,
10
- "timeout" => 5000,
11
- )
6
+ run_tests("sqlite://db/test.sqlite3")
12
7
  end
13
8
 
14
9
  example "PostgreSQL" do
15
- run_tests(
16
- "adapter" => "postgres",
17
- "database" => "communard_test",
18
- "pool" => 5,
19
- "timeout" => 5000,
20
- )
10
+ run_tests("postgresql://localhost:5432/communard_test")
21
11
  end
22
12
 
23
13
  example "MySQL" do
24
- run_tests(
25
- "adapter" => "mysql2",
26
- "database" => "communard_test",
27
- "username" => "root",
28
- "pool" => 5,
29
- "timeout" => 5000,
30
- )
14
+ run_tests("mysql2://root@localhost:3306/communard_test")
31
15
  end
32
16
 
33
-
34
17
  def run_tests(database_config)
35
-
36
- write_file "config/database.yml", { "development" => database_config }.to_yaml
37
-
38
18
  write_file "Rakefile", <<-FILE.gsub(/^\s{6}/, "")
39
19
  $LOAD_PATH.unshift(File.expand_path("../../../lib", __FILE__))
40
- require "yaml"
41
20
  require "communard/rake"
42
- Communard::Rake.add_tasks
21
+ namespace :db do
22
+ Communard::Rake.add_tasks("#{database_config}")
23
+ end
43
24
  FILE
44
25
 
45
- run_simple "bundle exec communard --generate-migration create_posts"
26
+ run_simple "bundle exec communard migration create_posts"
46
27
 
47
- file = Dir[absolute_path("db/migrate/*_create_posts.rb")].first
28
+ glob = Dir[expand_path("db/migrate/*_create_posts.rb")]
29
+ file = glob.first
48
30
 
49
- expect(File.read(file)).to eq <<-FILE.gsub(/^\s{6}/, "").chomp
50
- Sequel.migration do
51
- change do
52
- end
53
- end
54
- FILE
31
+ expect(File.read(file)).to eq "Sequel.migration do\n\n change do\n end\n\nend\n"
55
32
 
56
- write_file file, <<-FILE.gsub(/^\s{6}/, "")
33
+ write_file "db/migrate/#{File.basename(file)}", <<-FILE.gsub(/^\s{6}/, "")
57
34
  Sequel.migration do
58
35
  change do
59
36
  create_table :posts do
@@ -64,31 +41,11 @@ RSpec.describe "Integration", type: :aruba do
64
41
  end
65
42
  FILE
66
43
 
67
- run_simple "rake db:drop"
68
-
69
- run_simple "rake db:create"
44
+ run_simple "bundle exec rake db:drop"
70
45
 
71
- run_simple "rake db:migrate"
46
+ run_simple "bundle exec rake db:create"
72
47
 
73
- write_file "app.rb", <<-FILE.gsub(/^\s{6}/, "")
74
- $LOAD_PATH.unshift(File.expand_path("../../../lib", __FILE__))
75
- require "yaml"
76
- require "communard"
77
-
78
- db = Communard.connect
79
- posts = db[:posts]
80
-
81
- 4.times do
82
- posts.insert(name: "hello world")
83
- end
84
-
85
- puts "Post count: '\#{posts.count}'"
86
- FILE
87
-
88
- run_simple "ruby app.rb"
89
-
90
- assert_partial_output("Post count: '4'", all_stdout)
48
+ run_simple "bundle exec rake db:migrate"
91
49
  end
92
50
 
93
-
94
51
  end
data/spec/spec_helper.rb CHANGED
@@ -1,22 +1,12 @@
1
- require 'aruba/api'
2
- require 'aruba/reporting'
1
+ require "aruba"
3
2
 
4
3
  RSpec.configure do |config|
5
4
  config.disable_monkey_patching!
6
5
  config.include Aruba::Api, type: :aruba
7
6
 
8
- config.before :each do
9
- next unless self.class.include?(Aruba::Api)
7
+ config.before :each, type: :aruba do
10
8
  restore_env
11
- clean_current_dir
12
-
13
- if ENV["DEBUG"] == "true"
14
- @announce_stdout = true
15
- @announce_stderr = true
16
- @announce_cmd = true
17
- @announce_dir = true
18
- @announce_env = true
19
- end
9
+ setup_aruba
20
10
  end
21
11
 
22
12
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: communard
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.5
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - iain
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-05-17 00:00:00.000000000 Z
11
+ date: 2017-11-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sequel
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '4.13'
19
+ version: '5.2'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '4.13'
26
+ version: '5.2'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: bundler
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -139,14 +139,13 @@ files:
139
139
  - bin/communard
140
140
  - communard.gemspec
141
141
  - lib/communard.rb
142
+ - lib/communard/commands.rb
142
143
  - lib/communard/configuration.rb
143
- - lib/communard/context.rb
144
- - lib/communard/maintenance.rb
145
144
  - lib/communard/rake.rb
146
145
  - lib/communard/version.rb
147
146
  - spec/integration_spec.rb
148
147
  - spec/spec_helper.rb
149
- homepage: https://github.com/yourkarma/communard
148
+ homepage: https://github.com/iain/communard
150
149
  licenses:
151
150
  - MIT
152
151
  metadata: {}
@@ -166,7 +165,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
166
165
  version: '0'
167
166
  requirements: []
168
167
  rubyforge_project:
169
- rubygems_version: 2.4.5
168
+ rubygems_version: 2.7.1
170
169
  signing_key:
171
170
  specification_version: 4
172
171
  summary: Adds some conventions from ActiveRecord to Sequel.
@@ -1,118 +0,0 @@
1
- module Communard
2
- class Context
3
-
4
- attr_reader :configuration
5
-
6
- def initialize(configuration)
7
- @configuration = configuration
8
- end
9
-
10
- def connect(opts = options)
11
- ::Sequel.connect(opts).tap do |connection|
12
- connection.loggers = loggers
13
- connection.sql_log_level = configuration.sql_log_level
14
- connection.log_warn_duration = configuration.log_warn_duration
15
- end
16
- end
17
-
18
- def generate_migration(name: nil)
19
- fail ArgumentError, "Name is required" if name.to_s == ""
20
- require "fileutils"
21
- underscore = name.
22
- gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
23
- gsub(/([a-z\d])([A-Z])/,'\1_\2').
24
- tr("-", "_").
25
- downcase
26
- filename = root.join("db/migrate/#{Time.now.strftime("%Y%m%d%H%M%S")}_#{underscore}.rb")
27
- FileUtils.mkdir_p(File.dirname(filename))
28
- File.open(filename, "w") { |f| f << "Sequel.migration do\n change do\n end\nend" }
29
- puts "#{filename} created"
30
- end
31
-
32
- def create_database(env: environment)
33
- unless adapter(env: env) == "sqlite"
34
- run_without_database("CREATE DATABASE %{database_name}", env: env)
35
- end
36
- rescue Sequel::DatabaseError => error
37
- if /database (.*) already exists/ === error.message
38
- loggers.each { |logger| logger.info "Database #{$1} already exists, which is fine." }
39
- else
40
- raise
41
- end
42
- end
43
-
44
- def drop_database(env: environment)
45
- fail ArgumentError, "Don't drop the production database, you monkey!" if env.to_s == "production"
46
- if adapter(env: env) == "sqlite"
47
- file = options(env: env).fetch("database")
48
- if File.exist?(file)
49
- File.rm(file)
50
- end
51
- else
52
- run_without_database("DROP DATABASE IF EXISTS %{database_name}", env: env)
53
- end
54
- end
55
-
56
- def migrate(target: nil, env: environment)
57
- maintenance(env: env).migrate(target: target, dump_same_db: configuration.dump_same_db)
58
- end
59
-
60
- def seed(env: environment)
61
- maintenance(env: env).seed
62
- end
63
-
64
- def rollback(step: 1, env: environment)
65
- maintenance(env: env).rollback(step: step, dump_same_db: configuration.dump_same_db)
66
- end
67
-
68
- def load_schema(env: environment)
69
- maintenance(env: env).load_schema
70
- end
71
-
72
- def dump_schema(env: environment)
73
- maintenance(env: env).dump_schema(dump_same_db: configuration.dump_same_db)
74
- end
75
-
76
- def status(env: environment)
77
- maintenance(env: env).status
78
- end
79
-
80
- def run_without_database(cmd, env: environment)
81
- opts = options(env: env).dup
82
- database_name = opts.delete("database")
83
- if opts.fetch("adapter") == "postgres"
84
- opts["database"] = "postgres"
85
- opts["schema_search_path"] = "public"
86
- end
87
- connection = connect(opts)
88
- connection.run(cmd % { database_name: database_name })
89
- end
90
-
91
- def options(env: environment)
92
- YAML.load_file(root.join("config/database.yml")).fetch(env.to_s)
93
- end
94
-
95
- private
96
-
97
- def maintenance(env: environment)
98
- Maintenance.new(connection: connect(options(env: env)), root: root)
99
- end
100
-
101
- def environment
102
- configuration.environment
103
- end
104
-
105
- def root
106
- configuration.root
107
- end
108
-
109
- def loggers
110
- configuration.loggers
111
- end
112
-
113
- def adapter(env: environment)
114
- options(env: env).fetch("adapter").to_s
115
- end
116
-
117
- end
118
- end
@@ -1,102 +0,0 @@
1
- module Communard
2
- class Maintenance
3
-
4
- attr_reader :connection, :root
5
-
6
- def initialize(connection: nil, root: nil)
7
- ::Sequel.extension :migration, :core_extensions
8
- @connection = connection
9
- @root = root
10
- end
11
-
12
- def migrate(target: nil, dump_same_db: false)
13
- target = Integer(target) if target
14
- ::Sequel::Migrator.run(connection, migrations, target: target, allow_missing_migration_files: true)
15
- dump_schema(dump_same_db: dump_same_db)
16
- end
17
-
18
- def seed
19
- load seeds_file if seeds_file.exist?
20
- end
21
-
22
- def rollback(step: 1, dump_same_db: false)
23
- target = applied_migrations[-step - 1]
24
- if target
25
- migrate(target: target.split(/_/, 2).first, dump_same_db: dump_same_db)
26
- else
27
- fail ArgumentError, "Cannot roll back that far"
28
- end
29
- end
30
-
31
- def load_schema
32
- migration = instance_eval(schema_file.read, schema_file.expand_path.to_s, 1)
33
- migration.apply(connection, :up)
34
- end
35
-
36
- def dump_schema(dump_same_db: false)
37
- connection.extension :schema_dumper
38
- schema = connection.dump_schema_migration(same_db: dump_same_db)
39
- schema_file.open("w") { |f| f << schema.gsub(/\s+$/m, "") }
40
- end
41
-
42
- def status
43
- results = Hash.new { |h,k| h[k] = Status.new(k, false, false) }
44
- available = Pathname.glob(migrations.join("*.rb")).map(&:basename).map(&:to_s).reverse
45
- available.each { |migration| results[migration].available = true }
46
- applied_migrations.each { |migration| results[migration].applied = true }
47
-
48
- puts
49
- puts "database: #{connection.opts.fetch(:database)}"
50
- puts
51
- puts " Status Migration ID Migration Name"
52
- puts "--------------------------------------------------"
53
- results.values.sort.each do |result|
54
- puts " #{result.status} #{result.id} #{result.name}"
55
- end
56
- puts
57
- end
58
-
59
- private
60
-
61
- def applied_migrations
62
- ::Sequel::Migrator.migrator_class(migrations).new(connection, migrations, allow_missing_migration_files: true).applied_migrations
63
- end
64
-
65
- def schema_file
66
- root.join("db/schema.rb")
67
- end
68
-
69
- def seeds_file
70
- root.join("db/seeds.rb")
71
- end
72
-
73
- def migrations
74
- root.join("db/migrate")
75
- end
76
-
77
- Status = Struct.new(:file, :applied, :available) do
78
-
79
- def <=>(other)
80
- id <=> other.id
81
- end
82
-
83
- def status
84
- available ? applied ? " up " : "down" : "????"
85
- end
86
-
87
- def id
88
- splitted.first
89
- end
90
-
91
- def name
92
- splitted.last.capitalize.gsub("_", " ").sub(/\.rb$/, "")
93
- end
94
-
95
- def splitted
96
- file.split(/_/, 2)
97
- end
98
-
99
- end
100
-
101
- end
102
- end