jun 0.0.1 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. checksums.yaml +5 -5
  2. data/.rubocop.yml +13 -0
  3. data/Gemfile +3 -1
  4. data/LICENSE.txt +1 -1
  5. data/README.md +18 -20
  6. data/Rakefile +13 -3
  7. data/bin/console +3 -9
  8. data/exe/jun +7 -0
  9. data/jun.gemspec +28 -18
  10. data/lib/jun/action_controller/base.rb +16 -0
  11. data/lib/jun/action_controller/callbacks.rb +46 -0
  12. data/lib/jun/action_controller/metal.rb +22 -0
  13. data/lib/jun/action_controller/redirecting.rb +17 -0
  14. data/lib/jun/action_controller/rendering.rb +84 -0
  15. data/lib/jun/action_dispatch/routing/mapper.rb +54 -0
  16. data/lib/jun/action_dispatch/routing/route_set.rb +112 -0
  17. data/lib/jun/action_dispatch/routing/welcome.html.erb +41 -0
  18. data/lib/jun/action_view/base.rb +26 -0
  19. data/lib/jun/action_view/helpers/url_helper.rb +13 -0
  20. data/lib/jun/action_view/helpers.rb +11 -0
  21. data/lib/jun/active_record/base.rb +52 -0
  22. data/lib/jun/active_record/migration.rb +76 -0
  23. data/lib/jun/active_record/migrator.rb +80 -0
  24. data/lib/jun/active_record/persistence.rb +60 -0
  25. data/lib/jun/active_record/relation.rb +42 -0
  26. data/lib/jun/active_support/core_ext/array/access.rb +27 -0
  27. data/lib/jun/active_support/core_ext/array/conversion.rb +10 -0
  28. data/lib/jun/active_support/core_ext/hash/transformation.rb +19 -0
  29. data/lib/jun/active_support/core_ext/string/access.rb +18 -0
  30. data/lib/jun/active_support/core_ext/string/inflector.rb +119 -0
  31. data/lib/jun/active_support/core_ext.rb +5 -0
  32. data/lib/jun/active_support/dependencies.rb +31 -0
  33. data/lib/jun/application.rb +45 -0
  34. data/lib/jun/cli/commands/base.rb +17 -0
  35. data/lib/jun/cli/commands/db/create.rb +35 -0
  36. data/lib/jun/cli/commands/db/drop.rb +18 -0
  37. data/lib/jun/cli/commands/db/migrate.rb +15 -0
  38. data/lib/jun/cli/commands/db/rollback.rb +15 -0
  39. data/lib/jun/cli/commands/db/schema/dump.rb +24 -0
  40. data/lib/jun/cli/commands/db/schema/load.rb +43 -0
  41. data/lib/jun/cli/commands/db/seed.rb +19 -0
  42. data/lib/jun/cli/commands/generate/migration.rb +27 -0
  43. data/lib/jun/cli/commands/new.rb +62 -0
  44. data/lib/jun/cli/commands/server.rb +17 -0
  45. data/lib/jun/cli/commands/version.rb +13 -0
  46. data/lib/jun/cli/generator_templates/migration.rb.erb +11 -0
  47. data/lib/jun/cli/generator_templates/new_app/Gemfile.erb +9 -0
  48. data/lib/jun/cli/generator_templates/new_app/README.md.erb +3 -0
  49. data/lib/jun/cli/generator_templates/new_app/app/controllers/application_controller.rb.erb +4 -0
  50. data/lib/jun/cli/generator_templates/new_app/app/helpers/application_helper.rb.erb +4 -0
  51. data/lib/jun/cli/generator_templates/new_app/app/models/application_record.rb.erb +4 -0
  52. data/lib/jun/cli/generator_templates/new_app/app/views/layouts/application.html.erb.erb +11 -0
  53. data/lib/jun/cli/generator_templates/new_app/bin/console.erb +8 -0
  54. data/lib/jun/cli/generator_templates/new_app/config/application.rb.erb +12 -0
  55. data/lib/jun/cli/generator_templates/new_app/config/environment.rb.erb +7 -0
  56. data/lib/jun/cli/generator_templates/new_app/config/routes.rb.erb +4 -0
  57. data/lib/jun/cli/generator_templates/new_app/config.ru.erb +6 -0
  58. data/lib/jun/cli/generator_templates/new_app/db/seeds.rb.erb +9 -0
  59. data/lib/jun/cli.rb +33 -0
  60. data/lib/jun/connection_adapters/sqlite_adapter.rb +19 -0
  61. data/lib/jun/version.rb +3 -1
  62. data/lib/jun.rb +50 -2
  63. metadata +129 -24
  64. data/.gitignore +0 -10
  65. data/.rspec +0 -2
  66. data/.travis.yml +0 -4
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../connection_adapters/sqlite_adapter"
4
+ require_relative "./persistence"
5
+
6
+ module ActiveRecord
7
+ class Base
8
+ include ActiveRecord::Persistence
9
+
10
+ def initialize(attributes = {})
11
+ @attributes = attributes
12
+ @new_record = true
13
+ end
14
+
15
+ def method_missing(name, *args)
16
+ if self.class.connection.columns(self.class.table_name).include?(name)
17
+ @attributes[name]
18
+ else
19
+ super
20
+ end
21
+ end
22
+
23
+ def self.find(id)
24
+ find_by_sql("SELECT * FROM #{table_name} WHERE id = #{id.to_i} LIMIT 1").first
25
+ end
26
+
27
+ def self.all
28
+ ActiveRecord::Relation.new(self)
29
+ end
30
+
31
+ def self.where(*args)
32
+ all.where(*args)
33
+ end
34
+
35
+ def self.find_by_sql(sql)
36
+ connection.execute(sql).map do |attributes|
37
+ object = new(attributes)
38
+ object.instance_variable_set("@new_record", false)
39
+
40
+ object
41
+ end
42
+ end
43
+
44
+ def self.table_name
45
+ name.downcase.pluralize
46
+ end
47
+
48
+ def self.connection
49
+ @@connection ||= SqliteAdapter.new
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ class Migration
5
+ def up
6
+ raise NoMethodError, "Subclass must implement method."
7
+ end
8
+
9
+ def down
10
+ raise NoMethodError, "Subclass must implement method."
11
+ end
12
+
13
+ def add_column(table_name, column_name, column_type, options = {})
14
+ sql = ["ALTER TABLE #{table_name} ADD COLUMN #{column_name}"]
15
+
16
+ sql << column_type.to_s.upcase
17
+ sql << "NOT NULL" if options[:null] == false
18
+ sql << "DEFAULT #{options[:default]}" if options[:default]
19
+ sql << "UNIQUE" if options[:unique] == true
20
+
21
+ execute(sql.join(" "))
22
+ end
23
+
24
+ def remove_column(table_name, column_name)
25
+ execute("ALTER TABLE #{table_name} DROP COLUMN #{column_name};")
26
+ end
27
+
28
+ def create_table(table_name, options = {})
29
+ sql = "CREATE TABLE IF NOT EXISTS #{table_name}"
30
+ column_options = []
31
+
32
+ if options[:id] || !options.key?(:id)
33
+ column_options << {
34
+ name: :id,
35
+ type: :integer,
36
+ primary_key: true,
37
+ null: false
38
+ }
39
+ end
40
+
41
+ column_options += options.fetch(:columns, [])
42
+
43
+ columns_sql = column_options.map do |column|
44
+ next(column) if column.is_a?(String)
45
+
46
+ column_sql = []
47
+
48
+ column_sql << column[:name]
49
+ column_sql << column[:type]&.to_s&.upcase
50
+ column_sql << "PRIMARY KEY" if column[:primary_key] == true
51
+ column_sql << "NOT NULL" if column[:null] == false
52
+ column_sql << "DEFAULT #{column[:default]}" if column[:default]
53
+ column_sql << "UNIQUE" if column[:unique] == true
54
+
55
+ column_sql.compact.join(" ")
56
+ end
57
+
58
+ sql += " (#{columns_sql.join(", ")})"
59
+ sql += ";"
60
+
61
+ execute(sql)
62
+ end
63
+
64
+ def drop_table(table_name)
65
+ execute("DROP TABLE IF EXISTS #{table_name};")
66
+ end
67
+
68
+ def rename_table(old_table_name, new_table_name)
69
+ execute("ALTER TABLE #{old_table_name} RENAME TO #{new_table_name};")
70
+ end
71
+
72
+ def execute(*args)
73
+ ActiveRecord::Base.connection.execute(*args)
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ class Migrator
5
+ ALLOWED_DIRECTIONS = %w[up down].freeze
6
+
7
+ def initialize(direction:)
8
+ unless ALLOWED_DIRECTIONS.include?(direction.to_s)
9
+ raise ArgumentError, "direction must be one of: #{ALLOWED_DIRECTIONS.inspect}"
10
+ end
11
+
12
+ @direction = direction.to_s
13
+ end
14
+
15
+ def call
16
+ process_migrations!
17
+ end
18
+
19
+ private
20
+
21
+ def process_migrations!
22
+ files_to_process = up_migration? ? pending_migration_files : processed_migration_files.last(1)
23
+
24
+ files_to_process.each do |filepath|
25
+ require filepath
26
+
27
+ filename = filepath.split("/").last.sub(".rb", "")
28
+ migration_version = filename.split("_").first
29
+ migration_class_name = filename.split("_", 2).last.camelize
30
+ migration_class = Object.const_get(migration_class_name)
31
+
32
+ migration_class.new.public_send(@direction)
33
+ up_migration? ? add_to_schema_migrations(migration_version) :
34
+ remove_from_schema_migrations(migration_version)
35
+
36
+ migration_verb = up_migration? ? "processed" : "rolled back"
37
+ puts "Migration #{migration_verb} (#{filename})."
38
+ end
39
+
40
+ dump_schema! if files_to_process.any?
41
+ end
42
+
43
+ def up_migration?
44
+ @direction == "up"
45
+ end
46
+
47
+ def pending_migration_files
48
+ @pending_migration_files ||= migration_files - processed_migration_files
49
+ end
50
+
51
+ def processed_migration_files
52
+ @processed_migration_files ||= migration_files.select do |filepath|
53
+ file_version = filepath.split("/").last.split("_").first
54
+ processed_versions.include?(file_version)
55
+ end
56
+ end
57
+
58
+ def migration_files
59
+ @migration_files ||= Dir.glob(Jun.root.join("db/migrate/*.rb")).sort
60
+ end
61
+
62
+ def processed_versions
63
+ ActiveRecord::Base.connection.execute("SELECT * FROM schema_migrations;").map do |attributes|
64
+ attributes[:version]
65
+ end
66
+ end
67
+
68
+ def add_to_schema_migrations(version)
69
+ ActiveRecord::Base.connection.execute("INSERT INTO schema_migrations (version) VALUES (#{version});")
70
+ end
71
+
72
+ def remove_from_schema_migrations(version)
73
+ ActiveRecord::Base.connection.execute("DELETE FROM schema_migrations WHERE version = #{version};")
74
+ end
75
+
76
+ def dump_schema!
77
+ Jun::CLI.process_command(["db:schema:dump"])
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ module Persistence
5
+ def self.included(klass)
6
+ klass.extend(ClassMethods)
7
+ end
8
+
9
+ module ClassMethods
10
+ def create(attributes = {})
11
+ object = new(attributes)
12
+ object.save
13
+
14
+ object
15
+ end
16
+
17
+ def primary_key=(value)
18
+ @primary_key = value.to_sym
19
+ end
20
+
21
+ def primary_key
22
+ defined?(@primary_key) ? @primary_key : :id
23
+ end
24
+ end
25
+
26
+ def save
27
+ if new_record?
28
+ result = self.class.connection.execute(
29
+ <<~SQL
30
+ INSERT INTO #{self.class.table_name}
31
+ (#{@attributes.keys.join(",")})
32
+ VALUES (#{@attributes.values.map { |v| "'#{v}'" }.join(",")})
33
+ RETURNING *;
34
+ SQL
35
+ )
36
+
37
+ @attributes[self.class.primary_key] = result.first[self.class.primary_key]
38
+ @new_record = false
39
+ else
40
+ self.class.connection.execute(
41
+ <<~SQL
42
+ UPDATE #{self.class.table_name}
43
+ SET #{@attributes.map { |k, v| "#{k} = #{v.nil? ? 'NULL' : "'#{v}'"}" }.join(",")}
44
+ WHERE id = #{id};
45
+ SQL
46
+ )
47
+ end
48
+
49
+ true
50
+ end
51
+
52
+ def new_record?
53
+ @new_record
54
+ end
55
+
56
+ def persisted?
57
+ !new_record?
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ class Relation
5
+ def initialize(klass)
6
+ @klass = klass
7
+ @where_clauses = []
8
+ end
9
+
10
+ def where!(condition)
11
+ clause = condition.is_a?(String) ? condition : condition.map { |k, v| "#{k} = #{v}" }.join(" AND ")
12
+ @where_clauses << clause
13
+
14
+ self
15
+ end
16
+
17
+ def where(condition)
18
+ clone.where!(condition)
19
+ end
20
+
21
+ def to_sql
22
+ sql = "SELECT * FROM #{@klass.table_name}"
23
+ sql += " WHERE #{@where_clauses.join(" AND ")}" if @where_clauses.any?
24
+
25
+ sql
26
+ end
27
+
28
+ def records
29
+ @records ||= @klass.find_by_sql(to_sql)
30
+ end
31
+
32
+ alias to_a records
33
+
34
+ def first
35
+ records.first
36
+ end
37
+
38
+ def each(&block)
39
+ records.each(&block)
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Array
4
+ def second
5
+ self[1]
6
+ end
7
+
8
+ def third
9
+ self[2]
10
+ end
11
+
12
+ def fourth
13
+ self[3]
14
+ end
15
+
16
+ def fifth
17
+ self[4]
18
+ end
19
+
20
+ def third_to_last
21
+ self[-3]
22
+ end
23
+
24
+ def second_to_last
25
+ self[-2]
26
+ end
27
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Array
4
+ def to_sentence(delimiter: ", ", last_delimiter: "and")
5
+ return "" if none?
6
+ return self.first if one?
7
+
8
+ "#{self[0...-1].join(delimiter)} #{last_delimiter} #{self[-1]}"
9
+ end
10
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Hash
4
+ def stringify_keys
5
+ transform_keys(&:to_s)
6
+ end
7
+
8
+ def stringify_keys!
9
+ transform_keys!(&:to_s)
10
+ end
11
+
12
+ def symbolize_keys
13
+ transform_keys { |key| key.to_sym rescue key }
14
+ end
15
+
16
+ def symbolize_keys!
17
+ transform_keys! { |key| key.to_sym rescue key }
18
+ end
19
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ class String
4
+ def at(position)
5
+ self[position]
6
+ end
7
+
8
+ def from(position)
9
+ self[position, length]
10
+ end
11
+
12
+ def to(position)
13
+ position += size if position.negative?
14
+ position = -1 if position.negative?
15
+
16
+ self[0, position + 1]
17
+ end
18
+ end
@@ -0,0 +1,119 @@
1
+ module Inflector
2
+ def self.included(base)
3
+ base.extend ClassMethods
4
+ end
5
+
6
+ PLURAL = {
7
+ '(quiz)$' => '\1zes',
8
+ '^(ox)$' => '\1en',
9
+ '([m|l])ouse$' => '\1ice',
10
+ '(matr|vert|ind)ix|ex$' => '\1ices',
11
+ '(x|ch|ss|sh)$' => '\1es',
12
+ '([^aeiouy]|qu)y$' => '\1ies',
13
+ '(hive)$' => '\1s',
14
+ '(?:([^f])fe|([lr])f)$' => '\1\2ves',
15
+ '(shea|lea|loa|thie)f$' => '\1ves',
16
+ 'sis$' => 'ses',
17
+ '([ti])um$' => '\1a',
18
+ '(tomat|potat|ech|her|vet)o$' => '\1oes',
19
+ '(bu)s$' => '\1ses',
20
+ '(alias)$' => '\1es',
21
+ '(octop)us$' => '\1i',
22
+ '(ax|test)is$' => '\1es',
23
+ '(us)$' => '\1es',
24
+ '([^s]+)$' => '\1s'
25
+ }
26
+
27
+ SINGULAR = {
28
+ '(quiz)zes$' => '\1',
29
+ '(matr)ices$' => '\1ix',
30
+ '(vert|ind)ices$' => '\1ex',
31
+ '^(ox)en$' => '\1',
32
+ '(alias)es$' => '\1',
33
+ '(octop|vir)i$' => '\1us',
34
+ '(cris|ax|test)es$' => '\1is',
35
+ '(shoe)s$' => '\1',
36
+ '(o)es$' => '\1',
37
+ '(bus)es$' => '\1',
38
+ '([m|l])ice$' => '\1ouse',
39
+ '(x|ch|ss|sh)es$' => '\1',
40
+ '(m)ovies$' => '\1ovie',
41
+ '(s)eries$' => '\1eries',
42
+ '([^aeiouy]|qu)ies$' => '\1y',
43
+ '([lr])ves$' => '\1f',
44
+ '(tive)s$' => '\1',
45
+ '(hive)s$' => '\1',
46
+ '(li|wi|kni)ves$' => '\1fe',
47
+ '(shea|loa|lea|thie)ves$'=> '\1f',
48
+ '(^analy)ses$' => '\1sis',
49
+ '((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$' => '\1\2sis',
50
+ '([ti])a$' => '\1um',
51
+ '(n)ews$' => '\1ews',
52
+ '(h|bl)ouses$' => '\1ouse',
53
+ '(corpse)s$' => '\1',
54
+ '(us)es$' => '\1',
55
+ 's$' => ''
56
+ }
57
+
58
+ UNCHANGEABLE = [
59
+ 'sheep',
60
+ 'fish',
61
+ 'deer',
62
+ 'moose',
63
+ 'series',
64
+ 'species',
65
+ 'money',
66
+ 'rice',
67
+ 'information',
68
+ 'equipment'
69
+ ]
70
+
71
+ def pluralize
72
+ return self if UNCHANGEABLE.include? self
73
+
74
+ pattern, replacement = ""
75
+ PLURAL.each do |k, v|
76
+ if self.match(k)
77
+ pattern = Regexp.new(k)
78
+ replacement = v
79
+ break
80
+ end
81
+ end
82
+ self.sub(pattern, replacement)
83
+ end
84
+
85
+ def singularize
86
+ return self if UNCHANGEABLE.include? self
87
+
88
+ pattern, replacement = ""
89
+ SINGULAR.each do |k, v|
90
+ if self.match(k)
91
+ pattern = Regexp.new(k)
92
+ replacement = v
93
+ break
94
+ end
95
+ end
96
+ self.sub(pattern, replacement)
97
+ end
98
+
99
+ def underscore
100
+ gsub(/::/, '/').
101
+ gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
102
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').
103
+ tr("-", "_").
104
+ downcase
105
+ end
106
+
107
+ def camelize
108
+ sub(/^[a-z\d]*/) { |match| match.capitalize }.
109
+ gsub(/(?:_|(\/))([a-z\d]*)/) { "#{$1}#{$2.capitalize}" }.
110
+ gsub("/", "::")
111
+ end
112
+
113
+ module ClassMethods
114
+ end
115
+ end
116
+
117
+ class String
118
+ include Inflector
119
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ Dir[File.expand_path("core_ext/**/*.rb", __dir__)].sort.each do |filepath|
4
+ require_relative filepath
5
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Jun
4
+ module ActiveSupport
5
+ module Dependencies
6
+ extend self
7
+
8
+ attr_accessor :autoload_paths
9
+ self.autoload_paths = []
10
+
11
+ def find_file(filename)
12
+ autoload_paths.each do |path|
13
+ filepath = File.join(path, "#{filename}.rb")
14
+ return filepath if File.file?(filepath)
15
+ end
16
+
17
+ nil
18
+ end
19
+ end
20
+ end
21
+ end
22
+
23
+ class Object
24
+ def self.const_missing(constant_name)
25
+ file = Jun::ActiveSupport::Dependencies.find_file(constant_name.to_s.underscore)
26
+ super if file.nil?
27
+
28
+ require file.sub(/\.rb\z/, "")
29
+ Object.const_get(constant_name)
30
+ end
31
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Jun
4
+ class Application
5
+ def self.inherited(subclass)
6
+ super
7
+ Jun.app_class = subclass
8
+ end
9
+
10
+ def call(env)
11
+ routes.call(env)
12
+ end
13
+
14
+ def routes
15
+ @routes ||= Jun::ActionDispatch::Routing::RouteSet.new
16
+ end
17
+
18
+ def initialize!
19
+ return false if initialized? || Jun.application.nil?
20
+
21
+ # Add app/* directories to autoload paths.
22
+ Jun::ActiveSupport::Dependencies.autoload_paths += Jun.root.join("app").children
23
+
24
+ # Set up routes and make its helpers available to controllers & views.
25
+ require Jun.root.join("config/routes.rb")
26
+ url_helpers = Jun.application.routes.url_helpers
27
+ Jun::ActionController::Base.include(url_helpers)
28
+ Jun::ActionView::Base.include(url_helpers)
29
+
30
+ # Include all helpers in app/helpers directory.
31
+ Dir.glob(Jun.root.join("app/helpers/**/*.rb")).each do |filepath|
32
+ helper_class_name = File.basename(filepath, ".rb").camelize
33
+ helper_class = Object.const_get(helper_class_name)
34
+
35
+ Jun::ActionView::Base.include(helper_class)
36
+ end
37
+
38
+ @initialized = true
39
+ end
40
+
41
+ def initialized?
42
+ !!@initialized
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Jun
4
+ module CLI
5
+ module Commands
6
+ class Base
7
+ def self.command_name
8
+ name.sub("Jun::CLI::Commands::", "").underscore.gsub("/", ":")
9
+ end
10
+
11
+ def process(*args)
12
+ raise NoMethodError, "Subclass must implement method."
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Jun
4
+ module CLI
5
+ module Commands
6
+ module DB
7
+ class Create < Base
8
+ def process(*args)
9
+ db_filepath = Jun.root.join("db/app.db")
10
+
11
+ if File.exist?(db_filepath)
12
+ puts "Database already exists."
13
+ else
14
+ File.open(db_filepath, "w") {}
15
+ create_schema_migrations_table
16
+ puts "Created database in #{db_filepath}."
17
+ end
18
+ end
19
+
20
+ private
21
+
22
+ def create_schema_migrations_table
23
+ ActiveRecord::Base.connection.execute(
24
+ <<~SQL
25
+ CREATE TABLE IF NOT EXISTS schema_migrations (
26
+ version text NOT NULL PRIMARY KEY
27
+ );"
28
+ SQL
29
+ )
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Jun
4
+ module CLI
5
+ module Commands
6
+ module DB
7
+ class Drop < Base
8
+ def process(*args)
9
+ db_filepath = Jun.root.join("db/app.db")
10
+
11
+ File.delete(db_filepath) if File.exist?(db_filepath)
12
+ puts "Dropped database."
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Jun
4
+ module CLI
5
+ module Commands
6
+ module DB
7
+ class Migrate < Base
8
+ def process(*args)
9
+ ActiveRecord::Migrator.new(direction: :up).call
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end