boothby 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/exe/boothby ADDED
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ lib_path = File.expand_path('../lib', __dir__)
5
+ $LOAD_PATH.unshift(lib_path) unless $LOAD_PATH.include?(lib_path)
6
+ require 'boothby/cli'
7
+
8
+ Signal.trap('INT') do
9
+ warn("\n#{caller.join("\n")}: interrupted")
10
+ exit(1)
11
+ end
12
+
13
+ begin
14
+ Boothby::CLI.start
15
+ rescue Boothby::CLI::Error => e
16
+ puts("ERROR: #{e.message}")
17
+ exit(1)
18
+ end
@@ -0,0 +1,6 @@
1
+
2
+ module Boothby
3
+ class base
4
+
5
+ end
6
+ end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'thor'
4
+
5
+ module Boothby
6
+ # Handle the application command line parsing
7
+ # and the dispatch to various command objects
8
+ #
9
+ # @api public
10
+ class CLI < Thor
11
+ # Error raised by this runner
12
+ Error = Class.new(StandardError)
13
+
14
+ desc 'version', 'boothby version'
15
+ def version
16
+ require_relative('version')
17
+ puts("v#{Boothby::VERSION}")
18
+ end
19
+ map %w[--version -v] => :version
20
+
21
+ desc 'seed', 'Command description...'
22
+ method_option :help,
23
+ aliases: '-h',
24
+ type: :boolean,
25
+ desc: 'Display usage information'
26
+ def seed(*)
27
+ if options[:help]
28
+ invoke(:help, ['seed'])
29
+ else
30
+ require_relative('commands/seed')
31
+ Boothby::Commands::Seed.new(options).execute
32
+ end
33
+ end
34
+
35
+ desc 'update', 'Command description...'
36
+ method_option :help,
37
+ aliases: '-h',
38
+ type: :boolean,
39
+ desc: 'Display usage information'
40
+ def update(*)
41
+ if options[:help]
42
+ invoke(:help, ['update'])
43
+ else
44
+ require_relative('commands/update')
45
+ Boothby::Commands::Update.new(options).execute
46
+ end
47
+ end
48
+
49
+ desc 'setup', 'Command description...'
50
+ method_option :help,
51
+ aliases: '-h',
52
+ type: :boolean,
53
+ desc: 'Display usage information'
54
+ def setup(*)
55
+ if options[:help]
56
+ invoke(:help, ['setup'])
57
+ else
58
+ require_relative('commands/setup')
59
+ Boothby::Commands::Setup.new(options).execute
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,121 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'forwardable'
4
+
5
+ module Boothby
6
+ class Command
7
+ extend Forwardable
8
+
9
+ def_delegators :command, :run
10
+
11
+ # Execute this command
12
+ #
13
+ # @api public
14
+ def execute(*)
15
+ raise(
16
+ NotImplementedError,
17
+ "#{self.class}##{__method__} must be implemented"
18
+ )
19
+ end
20
+
21
+ # The external commands runner
22
+ #
23
+ # @see http://www.rubydoc.info/gems/tty-command
24
+ #
25
+ # @api public
26
+ def command(**options)
27
+ require('tty-command')
28
+ TTY::Command.new(options)
29
+ end
30
+
31
+ # The cursor movement
32
+ #
33
+ # @see http://www.rubydoc.info/gems/tty-cursor
34
+ #
35
+ # @api public
36
+ def cursor
37
+ require('tty-cursor')
38
+ TTY::Cursor
39
+ end
40
+
41
+ # Open a file or text in the user's preferred editor
42
+ #
43
+ # @see http://www.rubydoc.info/gems/tty-editor
44
+ #
45
+ # @api public
46
+ def editor
47
+ require('tty-editor')
48
+ TTY::Editor
49
+ end
50
+
51
+ # File manipulation utility methods
52
+ #
53
+ # @see http://www.rubydoc.info/gems/tty-file
54
+ #
55
+ # @api public
56
+ def generator
57
+ require('tty-file')
58
+ TTY::File
59
+ end
60
+
61
+ # Terminal output paging
62
+ #
63
+ # @see http://www.rubydoc.info/gems/tty-pager
64
+ #
65
+ # @api public
66
+ def pager(**options)
67
+ require('tty-pager')
68
+ TTY::Pager.new(options)
69
+ end
70
+
71
+ # Terminal platform and OS properties
72
+ #
73
+ # @see http://www.rubydoc.info/gems/tty-pager
74
+ #
75
+ # @api public
76
+ def platform
77
+ require('tty-platform')
78
+ TTY::Platform.new
79
+ end
80
+
81
+ # The interactive prompt
82
+ #
83
+ # @see http://www.rubydoc.info/gems/tty-prompt
84
+ #
85
+ # @api public
86
+ def prompt(**options)
87
+ require('tty-prompt')
88
+ TTY::Prompt.new(options)
89
+ end
90
+
91
+ # Get terminal screen properties
92
+ #
93
+ # @see http://www.rubydoc.info/gems/tty-screen
94
+ #
95
+ # @api public
96
+ def screen
97
+ require('tty-screen')
98
+ TTY::Screen
99
+ end
100
+
101
+ # The unix which utility
102
+ #
103
+ # @see http://www.rubydoc.info/gems/tty-which
104
+ #
105
+ # @api public
106
+ def which(*args)
107
+ require('tty-which')
108
+ TTY::Which.which(*args)
109
+ end
110
+
111
+ # Check if executable exists
112
+ #
113
+ # @see http://www.rubydoc.info/gems/tty-which
114
+ #
115
+ # @api public
116
+ def exec_exist?(*args)
117
+ require('tty-which')
118
+ TTY::Which.exist?(*args)
119
+ end
120
+ end
121
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../command'
4
+ require_relative '../app'
5
+
6
+ module Boothby
7
+ module Commands
8
+ class Seed < Boothby::Command
9
+ def initialize(options)
10
+ @options = options
11
+ end
12
+
13
+ def execute(input: $stdin, output: $stdout)
14
+ Boothby::Seed.seed!
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../command'
4
+ require_relative '../app'
5
+
6
+ module Boothby
7
+ module Commands
8
+ class Setup < Boothby::Command
9
+ def initialize(options)
10
+ @options = options
11
+ end
12
+
13
+ def execute(input: $stdin, output: $stdout)
14
+ Boothby::App.setup
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../command'
4
+ require_relative '../app'
5
+
6
+ module Boothby
7
+ module Commands
8
+ class Update < Boothby::Command
9
+ def initialize(options)
10
+ @options = options
11
+ end
12
+
13
+ def execute(input: $stdin, output: $stdout)
14
+ Boothby::App.update
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Boothby
4
+ module Configuration
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ add_config :root
9
+ add_config :seeds_configuration
10
+ add_config :configuration_directory
11
+
12
+ # set default values
13
+ reset_config
14
+ end
15
+
16
+ module ClassMethods
17
+ def add_config(name)
18
+ class_eval(<<-METHODS, __FILE__, __LINE__ + 1)
19
+ @#{name} = nil
20
+ def self.#{name}(value=nil)
21
+ @#{name} = value if value
22
+ return @#{name} if self.object_id == #{object_id} || defined?(@#{name})
23
+ name = superclass.#{name}
24
+ return nil if name.nil? && !instance_variable_defined?(:@#{name})
25
+ @#{name} = name && !name.is_a?(Module) && !name.is_a?(Symbol) && !name.is_a?(Numeric) && !name.is_a?(TrueClass) && !name.is_a?(FalseClass) ? name.dup : name
26
+ end
27
+
28
+ def self.#{name}=(value)
29
+ @#{name} = value
30
+ end
31
+
32
+ def #{name}=(value)
33
+ @#{name} = value
34
+ end
35
+
36
+ def #{name}
37
+ value = @#{name} if instance_variable_defined?(:@#{name})
38
+ value = self.class.#{name} unless instance_variable_defined?(:@#{name})
39
+ if value.instance_of?(Proc)
40
+ value.arity >= 1 ? value.call(self) : value.call
41
+ else
42
+ value
43
+ end
44
+ end
45
+ METHODS
46
+ end
47
+
48
+ def configure
49
+ yield(self)
50
+ end
51
+
52
+ def reset_config
53
+ configure do |config|
54
+ config.root = -> { Rails.root }
55
+ config.seeds_configuration = 'db/seeds.yml'
56
+ config.configuration_directory = 'config'
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'singleton'
4
+ require_relative 'yaml_reader'
5
+
6
+ # Store configuration YAML files
7
+ module Boothby
8
+ class KeyRing
9
+ include Singleton
10
+
11
+ def initialize
12
+ config_files = Dir[Rails.root.join('config/*.y{a,}ml{.erb,}')]
13
+ @configs = config_files.to_h do |config|
14
+ config_name = File.basename(config).split('.').first.to_sym
15
+ [config_name, Boothby::YAMLReader.new(config)]
16
+ end
17
+ end
18
+
19
+ def self.method_missing(method_name, *arguments, **kwargs, &block)
20
+ if instance.respond_to?(method_name)
21
+ instance.public_send(method_name)
22
+ else
23
+ super
24
+ end
25
+ end
26
+
27
+ def self.respond_to_missing?(method_name, include_private = false)
28
+ instance.respond_to?(method_name) || super
29
+ end
30
+
31
+ def method_missing(method_name, *arguments, **kwargs, &block)
32
+ if @configs.key?(method_name.to_sym)
33
+ @configs[method_name.to_sym]
34
+ else
35
+ super
36
+ end
37
+ end
38
+
39
+ def respond_to_missing?(method_name, include_private = false)
40
+ @configs.key?(method_name.to_sym) || super
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,99 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'fileutils'
4
+ require 'tty-command'
5
+
6
+ module Boothby
7
+ class Toolbox
8
+ class << self
9
+ attr_writer :root
10
+ end
11
+
12
+ def self.setup_application
13
+ FileUtils.chdir(app_dir) do
14
+ copy_example_files
15
+ install_dependencies
16
+ rake_task('db:prepare', 'db:test:prepare', label: 'Preparing database')
17
+ rake_task('log:clear', 'tmp:clear', label: 'Cleaning old files')
18
+ rake_task('restart', label: 'Restarting application server')
19
+ end
20
+ end
21
+
22
+ def self.update_application
23
+ FileUtils.chdir(app_dir) do
24
+ copy_example_files
25
+ install_dependencies
26
+ rake_task('db:migrate', label: 'Updating database')
27
+ rake_task('log:clear', 'tmp:clear', label: 'Cleaning old files')
28
+ rake_task('restart', label: 'Restarting application server')
29
+ end
30
+ end
31
+
32
+ def self.upgrade_application
33
+ FileUtils.chdir(app_dir) do
34
+ copy_example_files
35
+ install_dependencies
36
+ rake_task('db:migrate', label: 'Updating database')
37
+ rake_task('log:clear', 'tmp:clear', label: 'Cleaning old files')
38
+ rake_task('restart', label: 'Restarting application server')
39
+ end
40
+ end
41
+
42
+ private_class_method def self.install_dependencies
43
+ puts("\n== Installing dependencies ==")
44
+ bundle_install
45
+ yarn_install
46
+ end
47
+
48
+ private_class_method def self.yarn_install
49
+ return unless File.exist?('package.json')
50
+
51
+ system('command', '-v', 'yarn') || system('npm', 'install', '-g', 'yarn')
52
+ run!(:yarn, :install)
53
+ end
54
+
55
+ private_class_method def self.bundle_install
56
+ return unless File.exist?('Gemfile')
57
+
58
+ system('bundle', 'check') || run!(:bundle, :install)
59
+ end
60
+
61
+ private_class_method def self.copy_example_files
62
+ example_files = Dir['**/*.example*'].filter_map do |example_file|
63
+ real_file = example_file.gsub('.example', '')
64
+ [example_file, real_file] unless File.exist?(real_file)
65
+ end
66
+
67
+ return unless example_files.any?
68
+
69
+ puts("\n== Copying example files ==")
70
+ example_files.each { |ef, rf| run(:cp, ef, rf) }
71
+ end
72
+
73
+ private_class_method def self.rake_task(*args, label:)
74
+ puts("\n== #{label} ==")
75
+ run(:bundle, :exec, :rails, *args)
76
+ end
77
+
78
+ private_class_method def self.run(*args, **kwargs)
79
+ kwargs[:only_output_on_error] = true
80
+ cmd.run!(*args, **kwargs)
81
+ end
82
+
83
+ private_class_method def self.run!(*args, **kwargs)
84
+ kwargs[:only_output_on_error] = false
85
+ cmd.run!(*args, **kwargs)
86
+ end
87
+
88
+ private_class_method def self.cmd
89
+ @cmd ||= TTY::Command.new(
90
+ uuid: false,
91
+ color: true
92
+ )
93
+ end
94
+
95
+ private_class_method def self.app_dir
96
+ (@root || File.expand_path('../..', __dir__))
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,173 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'tty-spinner'
4
+
5
+ module Boothby
6
+ class Plant
7
+ class << self
8
+ attr_writer :root, :config_file, :rails_env
9
+ end
10
+
11
+ def self.seed!
12
+ require_seed_modules!
13
+
14
+ seed(environment: :base)
15
+ seed(environment: rails_env)
16
+ end
17
+
18
+ private_class_method def self.seed(environment:)
19
+ label = environment == :base ? 'ALL ENVIRONMENTS' : environment.to_s.upcase
20
+ env_class = environment.to_s.classify
21
+ multi_spinner = TTY::Spinner::Multi.new(
22
+ "[:spinner] SEEDING MODELS FOR #{label}",
23
+ hide_cursor: true,
24
+ success_mark: pastel.green('✓'),
25
+ error_mark: pastel.red('×'),
26
+ interval: 5,
27
+ format: :arc,
28
+ style: {
29
+ top: ' ',
30
+ middle: ' ',
31
+ bottom: ' '
32
+ }
33
+ )
34
+
35
+ config(environment).each do |seed_class|
36
+ seed_from(seed_class)
37
+ end
38
+ multi_spinner.auto_spin
39
+ end
40
+
41
+ private_class_method def self.root(*args)
42
+ @root ||= File.expand_path('../..', __dir__)
43
+ File.join(@root, *args)
44
+ end
45
+
46
+ private_class_method def self.rails_env
47
+ (@rails_env || 'development').to_sym
48
+ end
49
+
50
+ private_class_method def self.seeds_available?(*path)
51
+ Dir[root(:db, :seeds, *path, '*.rb"')].count > 0
52
+ end
53
+
54
+ private_class_method def self.config_file
55
+ (@config_file || root('db/seeds.yml'))
56
+ end
57
+
58
+ private_class_method def self.require_modules(*path)
59
+ Dir[root(:db, :seeds, *path, '*.rb"')].sort.each { |s| require(s) }
60
+ end
61
+
62
+ private_class_method def self.config
63
+ @config ||= begin
64
+ content = File.read(config_file)
65
+ yml = YAML.safe_load(content, [Time, Date], aliases: true)
66
+ yml.with_indifferent_access
67
+ end
68
+ end
69
+
70
+ def self.seed_from(seed_class)
71
+ multi_spinner.register(
72
+ '[:spinner] :title',
73
+ hide_cursor: true,
74
+ success_mark: pastel.green('✓'),
75
+ error_mark: pastel.red('×'),
76
+ interval: 5,
77
+ format: :arc
78
+ ) do |spinner|
79
+ title = seed_method[4..-1].titleize
80
+ spinner.update(title: "Seeding #{title}")
81
+ seed_class.public_send(seed_method)
82
+ spinner.update(title: "Seeded #{title}")
83
+ spinner.success
84
+ end
85
+ end
86
+
87
+ def self.seed_methods(seed_class)
88
+ methods = seed_class.methods.map(&:to_s).select do |method|
89
+ method.starts_with?('seed_')
90
+ end
91
+ methods.sort_by { |method| seed_class.method(method).source_location.last }
92
+ end
93
+ end
94
+ end
95
+
96
+ # :nodoc:
97
+ module Seeds
98
+ # rubocop:disable Style/OpenStructUse
99
+ def self.departments
100
+ [
101
+ Department.master_department,
102
+ Department.executive_health,
103
+ Department.signature_care,
104
+ OpenStruct.new(name: 'General', key: 'general')
105
+ ]
106
+ end
107
+ # rubocop:enable Style/OpenStructUse
108
+
109
+ def self.sprout
110
+ return if Rails.env.test?
111
+
112
+ require_seed_modules!
113
+
114
+ seed_by_departments(environment: :base)
115
+ seed_by_departments(environment: Rails.env.to_sym)
116
+ end
117
+
118
+ def self.seed(environment:)
119
+ label = environment == :base ? 'ALL ENVIRONMENTS' : environment.to_s.upcase
120
+ env_class = environment.to_s.classify
121
+ multi_spinner = TTY::Spinner::Multi.new(
122
+ "[:spinner] SEEDING MODELS FOR #{label}",
123
+ hide_cursor: true,
124
+ success_mark: pastel.green('✓'),
125
+ error_mark: pastel.red('×'),
126
+ interval: 5,
127
+ format: :arc
128
+ )
129
+
130
+ departments.each do |department|
131
+ next unless seeds_available?(environment, department)
132
+
133
+ seed_class = "Seeds::#{env_class}::#{department.key.classify}".constantize
134
+
135
+ display(department.name.upcase, indent: 1)
136
+ seed_from(seed_class, department: department)
137
+ end
138
+ end
139
+
140
+ def self.require_seed_modules!
141
+ Dir[Rails.root.join('db/seeds/**/*.rb')].sort.each { |s| require(s) }
142
+ end
143
+
144
+ def self.seed_from(seed_class, department:)
145
+ seed_methods(seed_class).each do |seed_method|
146
+ title = seed_method[4..-1].titleize
147
+ display("Seeding #{title}...\n", indent: 2)
148
+ seed_class.public_send(seed_method, department)
149
+ display("Seeded: #{title}\n", indent: 2)
150
+ end
151
+ end
152
+
153
+ def self.seed_methods(seed_class)
154
+ methods = seed_class.methods.map(&:to_s).select do |method|
155
+ method.starts_with?('seed_')
156
+ end
157
+ methods.sort_by { |method| seed_class.method(method).source_location.last }
158
+ end
159
+
160
+ def self.display(text, indent: 0, header: false)
161
+ text = "\n====== #{text}" if header
162
+ text = "#{' ' * indent}- #{text}" if indent > 0
163
+
164
+ puts(text)
165
+ end
166
+
167
+ def self.seeds_available?(environment, department)
168
+ seed_path = "db/seeds/#{environment}/#{department.key}/*.rb"
169
+ Dir[Rails.root.join(seed_path)].count > 0
170
+ end
171
+ end
172
+
173
+ Seeds.sprout
@@ -0,0 +1 @@
1
+ #
@@ -0,0 +1 @@
1
+ #
@@ -0,0 +1 @@
1
+ #
@@ -0,0 +1 @@
1
+ #
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Boothby
4
+ VERSION = '0.1.1'
5
+ end