mince_migrator 0.0.1 → 1.0.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 (59) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +20 -58
  3. data/bin/mince_migrator +125 -0
  4. data/lib/mince_migrator/cli_helper.rb +72 -0
  5. data/lib/mince_migrator/config.rb +30 -0
  6. data/lib/mince_migrator/creator.rb +48 -0
  7. data/lib/mince_migrator/deleter.rb +42 -0
  8. data/lib/mince_migrator/list.rb +46 -0
  9. data/lib/mince_migrator/list_report.rb +67 -0
  10. data/lib/mince_migrator/migration.rb +66 -0
  11. data/lib/mince_migrator/migrations/file.rb +74 -0
  12. data/lib/mince_migrator/migrations/loader.rb +52 -0
  13. data/lib/mince_migrator/migrations/name.rb +48 -0
  14. data/lib/mince_migrator/migrations/runner.rb +39 -0
  15. data/lib/mince_migrator/migrations/runner_validator.rb +47 -0
  16. data/lib/mince_migrator/migrations/template.mustache +24 -0
  17. data/lib/mince_migrator/migrations/template.rb +16 -0
  18. data/lib/mince_migrator/migrations/versioned_file.rb +38 -0
  19. data/lib/mince_migrator/ran_migration.rb +27 -0
  20. data/lib/mince_migrator/reverter.rb +57 -0
  21. data/lib/mince_migrator/status_report.rb +41 -0
  22. data/lib/mince_migrator/version.rb +18 -1
  23. data/lib/mince_migrator.rb +5 -4
  24. data/spec/integration/create_a_migration_spec.rb +57 -0
  25. data/spec/integration/deleting_a_migration_spec.rb +40 -0
  26. data/spec/integration/list_all_migrations_spec.rb +57 -0
  27. data/spec/integration/reverting_a_migration_spec.rb +59 -0
  28. data/spec/integration/running_a_migration_spec.rb +66 -0
  29. data/spec/integration_helper.rb +17 -0
  30. data/spec/support/db/a_second_migration.rb +24 -0
  31. data/spec/support/db/a_second_migration_2.rb +24 -0
  32. data/spec/support/db/create_seeded_admin_users.rb +24 -0
  33. data/spec/support/db/first_migration.rb +24 -0
  34. data/spec/support/db/first_migration_2.rb +24 -0
  35. data/spec/support/db/first_migration_3.rb +24 -0
  36. data/spec/support/db/first_migration_4.rb +24 -0
  37. data/spec/support/db/name_of_migration.rb +24 -0
  38. data/spec/support/invalid_interface_migration.rb +7 -0
  39. data/spec/support/not_a_migration.rb +2 -0
  40. data/spec/support/test_migration.rb +30 -0
  41. data/spec/units/mince_migrator/cli_helper_spec.rb +147 -0
  42. data/spec/units/mince_migrator/creator_spec.rb +80 -0
  43. data/spec/units/mince_migrator/deleter_spec.rb +52 -0
  44. data/spec/units/mince_migrator/list_spec.rb +53 -0
  45. data/spec/units/mince_migrator/migration_spec.rb +119 -0
  46. data/spec/units/mince_migrator/migrations/file_spec.rb +85 -0
  47. data/spec/units/mince_migrator/migrations/loader_spec.rb +47 -0
  48. data/spec/units/mince_migrator/migrations/name_spec.rb +47 -0
  49. data/spec/units/mince_migrator/migrations/runner_spec.rb +70 -0
  50. data/spec/units/mince_migrator/migrations/runner_validator_spec.rb +46 -0
  51. data/spec/units/mince_migrator/migrations/template_spec.rb +42 -0
  52. data/spec/units/mince_migrator/migrations/versioned_file_spec.rb +48 -0
  53. data/spec/units/mince_migrator/ran_migration_spec.rb +60 -0
  54. data/spec/units/mince_migrator/reverter_spec.rb +78 -0
  55. metadata +298 -26
  56. data/.gitignore +0 -17
  57. data/Gemfile +0 -4
  58. data/Rakefile +0 -12
  59. data/mince_migrator.gemspec +0 -19
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 41b113ade7cbebb55bd8640f1f1a49739a1ba0c0
4
+ data.tar.gz: cb22a342cd4f20d89ecf0d0bd99a1b577566bde2
5
+ SHA512:
6
+ metadata.gz: a02d661a150eb49a28aea7e37ab96f9d69e979e9531bb0072aac2de525e1bb56eda2c31675f16e6285e95f7e46bfad678b13be914cfcb0579b1302feb7458a2f
7
+ data.tar.gz: 2d58ae4f149108c101ac01e939ddba2f5afc37e224d2fb6133054bdb4588cc559d3b1625563da847447e21fe3c46ca62b20882c87f9be2a835cad077d09bed2a
data/README.md CHANGED
@@ -1,89 +1,51 @@
1
1
  # Mince Migrator
2
2
 
3
- **This is not yet released, this read me is a roadmap for what to do, it is not necessarily what has been done yet.**
3
+ [![Travis CI](https://travis-ci.org/coffeencoke/mince_migrator.png)](https://travis-ci.org/#!/coffeencoke/mince_migrator)
4
4
 
5
- Mince Migrator is a library that provides a way to run database migrations for your application using the [Mince libraries](https://github.com/coffeencoke/mince).
5
+ Mince Migrator is a library that provides a way to run database
6
+ migrations for your ruby applications.
6
7
 
7
8
  ## Installation
8
9
 
9
- Add this line to your application's Gemfile:
10
-
11
- gem 'mince_migrator'
12
-
13
- And then execute:
14
-
15
- $ bundle install
16
-
17
- Or install it yourself as:
18
-
19
10
  $ gem install mince_migrator
20
11
 
21
12
  ## Usage
22
13
 
23
14
  ### Generate a migration
24
15
 
25
- $ bundle exec mince_migrator create "Load admin users"
16
+ $ mince_migrator create "Load admin users"
26
17
 
27
18
  ### Implement your migration
28
19
 
29
- The template provided to you for a migration looks like this:
30
-
31
- ```ruby
32
- module MinceMigrator
33
- module Migration
34
- module LoadAdminUsers
35
- def self.run
36
- # Actual migration goes here
37
- end
38
-
39
- def self.revert
40
- # In case you need to revert this one migration
41
- end
42
-
43
- # So you can change the order to run more easily
44
- def self.time_created
45
- "2013-02-23 19:03:27 UTC"
46
- end
47
-
48
- module Temporary
49
- # Migration dependent classes go here
50
- end
51
- end
52
- end
53
- end
54
- ```
55
-
56
- For an evolving explanation for the Temporary module, view [Migrating With Temporary Classes](https://github.com/coffeencoke/mince_migrator/wiki/migrating-with-temporary-classes).
20
+ The output of creating the migration will tell you where the migration was created.
21
+
22
+ Implement the `run` method with the behavior of your migration.
57
23
 
58
24
  ### Run your single migration
59
25
 
60
- $ bundle exec mince_migrator run "Load admin users"
26
+ $ mince_migrator run "Load admin users"
61
27
 
62
- *You can use any of the following as the name for the above command:*
63
-
64
- * `Load admin users` (in quotes)*
65
- * `LoadAdminUsers`
66
- * `load_admin_users`
67
-
68
28
  ### Revert your single migration
69
29
 
70
- $ bundle exec mince_migrator revert "Load admin users"
30
+ $ mince_migrator revert "Load admin users"
71
31
 
72
32
  ### Run all migrations that have not yet been ran
73
33
 
74
- $ bundle exec mince_migrator run_all
75
-
34
+ $ mince_migrator run_all
35
+
36
+ ### View all migrations
37
+
38
+ *My favorite!*
39
+
40
+ $ mince_migrator list
41
+
76
42
  ### Check the status of a migration
77
43
 
78
- $ bundle exec mince_migrator status "Load admin users"
44
+ $ mince_migrator show "Load admin users"
79
45
 
80
46
  ### View all available commands
81
47
 
82
- *Run any of the following*
83
-
84
- $ bundle exec mince_migrator
85
- $ bundle exec mince_migrator --help
86
- $ bundle exec mince_migrator help
48
+ $ mince_migrator --help
87
49
 
88
50
  ## Contributing
89
51
 
@@ -108,4 +70,4 @@ Copyright (c) 2013 Matt Simpson
108
70
 
109
71
  MIT License
110
72
 
111
- View the LICENSE.txt file included in the source
73
+ View the LICENSE.txt file included in the source
@@ -0,0 +1,125 @@
1
+ #!/usr/bin/env ruby
2
+ require 'gli'
3
+ require 'mince_migrator/version'
4
+ require 'mince_migrator/list'
5
+ require 'mince_migrator/cli_helper'
6
+
7
+ include GLI::App
8
+ include MinceMigrator::CliHelper
9
+
10
+ program_desc 'Manages database migrations for ruby applications'
11
+ version MinceMigrator.version
12
+
13
+ desc 'Creates a migration'
14
+ arg_name 'Name of migration'
15
+ command :create do |c|
16
+ c.action do |global_options,options,args|
17
+ name = args.join(" ")
18
+ create_migration(name)
19
+ end
20
+ end
21
+
22
+ desc 'Lists all migrations and their statuses'
23
+ command :list do |c|
24
+ c.action do |global_options,options,args|
25
+ list_migrations(MinceMigrator::List.new)
26
+ end
27
+ end
28
+
29
+ desc 'Reverts a migration'
30
+ arg_name 'Name of migration'
31
+ command :revert do |c|
32
+ c.action do |global_options,options,args|
33
+ name = args.join(" ")
34
+ revert_migration(name: name)
35
+ end
36
+ end
37
+
38
+ desc 'Deletes all migrations that have already ran'
39
+ command :delete_ran do |c|
40
+ c.action do |global_options,options,args|
41
+ list = MinceMigrator::List.new('ran')
42
+ if list.all.any?
43
+ list.all.each do |migration|
44
+ delete_migration(migration: migration)
45
+ end
46
+ else
47
+ puts "No migrations were found."
48
+ end
49
+ end
50
+ end
51
+
52
+ desc 'Deletes a migration'
53
+ arg_name 'Name of migration'
54
+ command :delete do |c|
55
+ c.action do |global_options,options,args|
56
+ name = args.join(" ")
57
+
58
+ delete_migration(name: name)
59
+ end
60
+ end
61
+
62
+ desc 'Runs a migration'
63
+ arg_name 'Name of migration'
64
+ command :run do |c|
65
+ c.action do |global_options,options,args|
66
+ name = args.join(" ")
67
+
68
+ run_migration(name: name)
69
+ end
70
+ end
71
+
72
+ desc 'Runs all migrations that have not yet been ran'
73
+ command :run_all do |c|
74
+ c.action do
75
+ list = MinceMigrator::List.new('not ran')
76
+ if list.all.any?
77
+ list.all.each do |migration|
78
+ run_migration(migration: migration)
79
+ end
80
+ else
81
+ puts "There were no migrations to run."
82
+ end
83
+ end
84
+ end
85
+
86
+ desc 'Shows the details of a migration'
87
+ arg_name 'Name of migration'
88
+ command :show do |c|
89
+ c.action do |global_options,options,args|
90
+ name = args.join(" ")
91
+
92
+ if args.any?
93
+ show_migration(name)
94
+ else
95
+ puts "You must provide a name"
96
+ end
97
+ end
98
+ end
99
+
100
+ pre do |global,command,options,args|
101
+ # Pre logic here
102
+ # Return true to proceed; false to abort and not call the
103
+ # chosen command
104
+ # Use skips_pre before a command to skip this block
105
+ # on that command only
106
+ if File.exists?(MinceMigrator::Config.config_file)
107
+ require MinceMigrator::Config.config_file
108
+ end
109
+
110
+ true
111
+ end
112
+
113
+ post do |global,command,options,args|
114
+ # Post logic here
115
+ # Use skips_post before a command to skip this
116
+ # block on that command only
117
+ end
118
+
119
+ on_error do |exception|
120
+ # Error logic here
121
+ # return false to skip default error handling
122
+ true
123
+ end
124
+
125
+ exit run(ARGV)
@@ -0,0 +1,72 @@
1
+ module MinceMigrator
2
+ require_relative 'deleter'
3
+ require_relative 'creator'
4
+ require_relative 'reverter'
5
+ require_relative 'list'
6
+ require_relative 'migrations/runner'
7
+ require_relative 'list_report'
8
+
9
+ module CliHelper
10
+ def delete_migration(options)
11
+ deleter = MinceMigrator::Deleter.new(options)
12
+ if deleter.can_delete_migration?
13
+ puts "Deleting #{deleter.name}..."
14
+ deleter.delete_migration
15
+ puts "Migration deleted successfully"
16
+ else
17
+ help_now!(deleter.reasons_for_failure)
18
+ end
19
+ end
20
+
21
+ def run_migration(options)
22
+ runner = MinceMigrator::Migrations::Runner.new(options)
23
+ if runner.can_run_migration?
24
+ puts "Running #{runner.name}..."
25
+ runner.run_migration
26
+ puts "Migration finished."
27
+ else
28
+ help_now!(runner.reasons_for_failure)
29
+ end
30
+ end
31
+
32
+ def create_migration(name)
33
+ creator = MinceMigrator::Creator.new(name)
34
+ if creator.can_create_migration?
35
+ puts "Creating #{creator.name}..."
36
+ creator.create_migration
37
+ puts "Migration created at #{creator.migration_file_relative_path}"
38
+ else
39
+ help_now!(creator.reasons_for_failure)
40
+ end
41
+ end
42
+
43
+ def list_migrations(list)
44
+ if list.all.any?
45
+ MinceMigrator::ListReport.new(list).run
46
+ else
47
+ puts "\nThere are no migrations in the '#{MinceMigrator::Config.migration_relative_dir}' directory.\n".red
48
+ puts "run the following for more info to create a migration:\n\n"
49
+ puts " mince_migrator create --help\n\n".green
50
+ end
51
+ end
52
+
53
+ def revert_migration(options)
54
+ reverter = MinceMigrator::Reverter.new(options)
55
+ if reverter.can_revert_migration?
56
+ puts "Reverting #{reverter.name}..."
57
+ reverter.revert_migration
58
+ puts "Migration reverted successfully"
59
+ else
60
+ help_now!(reverter.reasons_for_failure)
61
+ end
62
+ end
63
+
64
+ def show_migration(name)
65
+ if migration = MinceMigrator::Migration.find(name)
66
+ MinceMigrator::StatusReport.new(migration).run
67
+ else
68
+ puts "No migration was found with name: '#{name}'"
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,30 @@
1
+ module MinceMigrator
2
+ require 'singleton'
3
+
4
+ class Config
5
+ include Singleton
6
+
7
+ attr_reader :migration_relative_dir, :migration_dir
8
+
9
+ def initialize
10
+ self.migration_relative_dir = ::File.join("db", "migrations")
11
+ end
12
+
13
+ def migration_relative_dir=(val)
14
+ @migration_relative_dir = val
15
+ @migration_dir = ::File.join(Dir.pwd, migration_relative_dir)
16
+ end
17
+
18
+ def self.migration_relative_dir
19
+ instance.migration_relative_dir
20
+ end
21
+
22
+ def self.migration_dir
23
+ instance.migration_dir
24
+ end
25
+
26
+ def self.config_file
27
+ ::File.join(Dir.pwd, 'config', 'mince_migrator.rb')
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,48 @@
1
+ module MinceMigrator
2
+ require 'fileutils'
3
+ require_relative 'migrations/versioned_file'
4
+ require_relative 'migrations/name'
5
+ require_relative 'config'
6
+
7
+ class Creator
8
+ attr_reader :name, :migration_name
9
+
10
+ def initialize(name=nil)
11
+ @migration_name = Migrations::Name.new(name)
12
+ @name = migration_name.value
13
+ end
14
+
15
+ def can_create_migration?
16
+ migration_name.valid?
17
+ end
18
+
19
+ def reasons_for_failure
20
+ migration_name.reasons_for_failure
21
+ end
22
+
23
+ def create_migration
24
+ FileUtils.mkdir_p(Config.migration_dir)
25
+ file = ::File.open(migration_file.full_path, 'w+')
26
+ file.write migration_file.body
27
+ file.close
28
+ end
29
+
30
+ def migration_file
31
+ @migration_file ||= versioned_file.next_unused_version
32
+ end
33
+
34
+ def versioned_file
35
+ @versioned_file ||= Migrations::VersionedFile.new(name)
36
+ end
37
+
38
+ def migration_file_relative_path
39
+ migration_file.full_relative_path
40
+ end
41
+
42
+ def self.create(name)
43
+ new(name).tap do |creator|
44
+ creator.create_migration if creator.can_create_migration?
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,42 @@
1
+ module MinceMigrator
2
+ require_relative 'config'
3
+ require 'fileutils'
4
+ require_relative 'migrations/name'
5
+ require_relative 'ran_migration'
6
+
7
+ class Deleter
8
+ attr_reader :name, :filename, :migration_name, :migration
9
+
10
+ def initialize(options)
11
+ if options[:migration]
12
+ @migration = options[:migration]
13
+ @migration_name = Migrations::Name.new(migration.name)
14
+ elsif options[:name]
15
+ @migration_name = Migrations::Name.new(options[:name])
16
+ end
17
+ @name = migration_name.value
18
+ @filename = migration_name.filename
19
+ end
20
+
21
+ def delete_migration
22
+ ::FileUtils.rm(migration_path)
23
+ ran_migration.delete if ran_migration
24
+ end
25
+
26
+ def can_delete_migration?
27
+ ::File.exists?(migration_path)
28
+ end
29
+
30
+ def reasons_for_failure
31
+ "Migration does not exist with name '#{name}'" unless can_delete_migration?
32
+ end
33
+
34
+ def migration_path
35
+ ::File.join Config.migration_dir, filename
36
+ end
37
+
38
+ def ran_migration
39
+ @ran_migration ||= RanMigration.find_by_name(name)
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,46 @@
1
+ module MinceMigrator
2
+ require_relative 'config'
3
+ require_relative 'migration'
4
+
5
+ class List
6
+ attr_reader :status
7
+
8
+ def initialize(status=:any)
9
+ @status = status
10
+ end
11
+
12
+ def all
13
+ @all ||= all_for_status
14
+ end
15
+
16
+ def number_of_migrations
17
+ all.size
18
+ end
19
+
20
+ def filelist
21
+ @filelist ||= Dir.glob(filelist_pattern)
22
+ end
23
+
24
+ def filelist_pattern
25
+ File.join(Config.migration_dir, '*')
26
+ end
27
+
28
+ private
29
+
30
+ def all_for_status
31
+ filtered_by_status(all_for_any_status).sort_by(&:time_created)
32
+ end
33
+
34
+ def all_for_any_status
35
+ filelist.map{|a| Migration.load_from_file(a) }
36
+ end
37
+
38
+ def filtered_by_status(migrations)
39
+ migrations.select { |m| matches_status?(m) }
40
+ end
41
+
42
+ def matches_status?(migration)
43
+ status == :any || migration.status == status
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,67 @@
1
+ module MinceMigrator
2
+ require 'command_line_reporter'
3
+
4
+ class ListReport
5
+ include CommandLineReporter
6
+
7
+ attr_reader :sum_ran, :sum_not_ran
8
+
9
+ def initialize(list)
10
+ @list = list
11
+ @sum_ran = 0
12
+ @sum_not_ran = 0
13
+ end
14
+
15
+ def run
16
+ vertical_spacing 2
17
+ header title: 'List Of All Migrations', bold: true, rule: true, align: 'center', width: 70, timestamp: true
18
+
19
+ table border: false do
20
+ row header: true do
21
+ column 'Name', width: 40
22
+ column 'Status', width: 10
23
+ column 'Age', width: 5
24
+ column 'Date Created', width: 15
25
+ end
26
+ @list.all.each do |migration|
27
+ row do
28
+ column migration.name
29
+ status_column(migration)
30
+ column migration.age
31
+ column migration.time_created.strftime("%m/%d/%Y")
32
+ end
33
+ end
34
+ end
35
+
36
+ vertical_spacing 2
37
+
38
+ table border: false do
39
+ row do
40
+ column "Ran", width: 6
41
+ column sum_ran, color: 'green', width: 5
42
+ column "Not ran", width: 8
43
+ column sum_not_ran, color: 'red', width: 5
44
+ end
45
+ row bold: true do
46
+ column "Total", width: 6
47
+ column total_number_of_migrations, width: 5
48
+ end
49
+ end
50
+ end
51
+
52
+ def total_number_of_migrations
53
+ sum_ran + sum_not_ran
54
+ end
55
+
56
+ def status_column(migration)
57
+ if migration.ran?
58
+ @sum_ran += 1
59
+ color = 'green'
60
+ else
61
+ @sum_not_ran += 1
62
+ color = 'red'
63
+ end
64
+ column migration.status, color: color
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,66 @@
1
+ require 'debugger'
2
+
3
+ module MinceMigrator
4
+ require_relative 'migrations/file'
5
+ require_relative 'ran_migration'
6
+ require_relative 'migrations/name'
7
+
8
+ class Migration
9
+ attr_reader :time_created, :name, :status, :relative_path, :path
10
+
11
+ def initialize(options)
12
+ @klass = options[:klass]
13
+ @time_created = @klass.time_created
14
+ self.name = options[:name]
15
+ @relative_path = options[:relative_path]
16
+ @path = options[:path]
17
+ end
18
+
19
+ def age
20
+ @age ||= "#{(Time.now.utc.to_date - time_created.to_date).to_i}d"
21
+ end
22
+
23
+ def name=(val)
24
+ @name ||= Migrations::Name.new(val).value
25
+ end
26
+
27
+ def run
28
+ @klass.run
29
+ end
30
+
31
+ def revert
32
+ @klass.revert
33
+ end
34
+
35
+ def ran?
36
+ !!ran_migration
37
+ end
38
+
39
+ def status
40
+ ran? ? 'ran' : 'not ran'
41
+ end
42
+
43
+ def ran_migration
44
+ @ran_migration ||= RanMigration.find_by_name(name)
45
+ end
46
+
47
+ def self.find(name)
48
+ if file = Migrations::File.find(name)
49
+ new_from_file file
50
+ end
51
+ end
52
+
53
+ def self.load_from_file(path_to_file)
54
+ new_from_file Migrations::File.load_from_file(path_to_file)
55
+ end
56
+
57
+ def self.new_from_file(file)
58
+ new(
59
+ klass: file.klass,
60
+ name: file.name,
61
+ relative_path: file.full_relative_path,
62
+ path: file.full_path
63
+ )
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,74 @@
1
+ module MinceMigrator
2
+ module Migrations
3
+ require_relative 'template'
4
+ require_relative '../config'
5
+ require_relative 'versioned_file'
6
+ require_relative 'loader'
7
+
8
+ class File
9
+ attr_reader :name
10
+
11
+ def initialize(name)
12
+ @original_name = name
13
+ @version = 1
14
+ self.name = name
15
+ end
16
+
17
+ def full_relative_path
18
+ ::File.join(Config.migration_relative_dir, filename)
19
+ end
20
+
21
+ def name=(val)
22
+ @name = val.gsub(" ", "_").downcase
23
+ end
24
+
25
+ def filename
26
+ "#{name}.rb"
27
+ end
28
+
29
+ def full_path
30
+ ::File.join Config.migration_dir, filename
31
+ end
32
+
33
+ def klass_name
34
+ name.split("_").map(&:capitalize).join
35
+ end
36
+
37
+ def klass
38
+ loader.klass
39
+ end
40
+
41
+ def body
42
+ @body ||= Template.new(klass_name).render
43
+ end
44
+
45
+ def persisted?
46
+ ::File.exists?(full_path)
47
+ end
48
+
49
+ def load
50
+ loader.call
51
+ end
52
+
53
+ def self.load_from_file(path_to_file)
54
+ name = convert_path_to_name(path_to_file)
55
+ find(name)
56
+ end
57
+
58
+ def self.find(name)
59
+ file = new(name)
60
+ file.tap(&:load) if file.persisted?
61
+ end
62
+
63
+ def self.convert_path_to_name(path)
64
+ path.split("/")[-1].gsub('.rb', '')
65
+ end
66
+
67
+ private
68
+
69
+ def loader
70
+ @loader ||= Loader.new(full_path: full_path, klass_name: klass_name)
71
+ end
72
+ end
73
+ end
74
+ end