lib/lizarb.rb in lizarb-1.0.3 vs lib/lizarb.rb in lizarb-1.0.4
- old
+ new
@@ -1,78 +1,302 @@
# frozen_string_literal: true
require "colorize"
require "json"
require "pathname"
-require "zeitwerk"
+require "fileutils"
require "lerb"
require_relative "lizarb/version"
+$APP ||= "app"
+
module Lizarb
class Error < StandardError; end
+ class ModeNotFound < Error; end
#
SPEC = Gem::Specification.find_by_name("lizarb")
GEM_DIR = SPEC.gem_dir
CUR_DIR = Dir.pwd
IS_APP_DIR = File.file? "#{CUR_DIR}/app.rb"
IS_LIZ_DIR = File.file? "#{CUR_DIR}/lib/lizarb.rb"
+ IS_GEM_DIR = File.file? "#{CUR_DIR}/lizarb.gemspec"
APP_DIR = IS_APP_DIR ? CUR_DIR : GEM_DIR
+ $APP = "app_global" if not IS_APP_DIR
+
#
module_function
def log s
puts s.bold
end
+ def self.logv s
+ log s if $VERBOSE
+ end
+
+ # Returns Lizarb::VERSION as a Gem::Version
+ def version
+ @version ||= Gem::Version.new VERSION
+ end
+
+ # Returns RUBY_VERSION as a Gem::Version
+ def ruby_version
+ @ruby_version ||= Gem::Version.new RUBY_VERSION
+ end
+
+ def ruby_supports_raise_cause?
+ RUBY_ENGINE != "jruby"
+ end
+
+ def self.load_all
+ Zeitwerk::Loader.eager_load_all
+ end
+
# called from exe/lizarb
- def call
+ def setup
+ lookup_and_load_core_ext
+ lookup_and_set_gemfile
+ end
+
+ # called from exe/lizarb
+ def app &block
require "app"
+ if block_given?
+ App.class_exec(&block)
+ else
+ lookup_and_require_app
+ end
+ end
- setup_core_ext
- setup_gemfile
+ # called from exe/lizarb
+ def call
+ lookup_and_set_mode
+ lookup_and_require_dependencies
+ lookup_and_load_settings
+ require_liza_and_bundle_systems
+ end
- require "#{APP_DIR}/app"
+ # called from exe/lizarb
+ def exit verbose: $VERBOSE
+ exit_messages if verbose
+ super 0
+ end
- versions = {ruby: RUBY_VERSION, bundler: Bundler::VERSION, zeitwerk: Zeitwerk::VERSION, lizarb: VERSION}
+ def exit_messages
+ versions = {
+ ruby: RUBY_VERSION,
+ bundler: Bundler::VERSION,
+ zeitwerk: Zeitwerk::VERSION,
+ lizarb: VERSION,
+ app: $APP,
+ mode: $MODE
+ }
bugs = SPEC.metadata["bug_tracker_uri"]
puts versions.to_s.green
puts "Report bugs at #{bugs}"
+ puts "Fork us on Github at #{bugs}/fork"
end
- # called from "#{APP_DIR}/app"
- def bundle
- require "bundler/setup"
- Bundler.require :default
+ # setup phase
- bundle_liza
+ def lookup_and_load_core_ext
+ files =
+ if IS_GEM_DIR
+ Dir["#{CUR_DIR}/lib/lizarb/ruby/*.rb"]
+ else
+ Dir["#{GEM_DIR}/lib/lizarb/ruby/*.rb"] + Dir["#{CUR_DIR}/lib/lizarb/ruby/*.rb"]
+ end
- check_mode!
+ files.each do |file_name|
+ log "#{self} loading #{file_name}" if $VERBOSE
+ load file_name
+ end
end
- # setup
+ def lookup_and_set_gemfile
+ gemfile = nil
- def setup_core_ext
- pattern =
- IS_LIZ_DIR ? "lib/lizarb/ruby/*.rb"
- : "#{GEM_DIR}/lib/lizarb/ruby/*.rb"
+ finder = \
+ proc do |file_name|
+ log "#{self}.#{__method__} #{file_name}" if $VERBOSE
+ if File.file? file_name
+ file_name
+ else
+ false
+ end
+ end
- Dir[pattern].each &method(:load)
+ gemfile ||= finder.call "#{CUR_DIR}/#{$APP}.gemfile.rb"
+ gemfile ||= finder.call "#{GEM_DIR}/#{$APP}.gemfile.rb" unless IS_GEM_DIR
+ gemfile ||= finder.call "#{CUR_DIR}/Gemfile"
+ gemfile ||= finder.call "#{GEM_DIR}/app_global.gemfile.rb"
+
+ log "#{self} setting BUNDLE_GEMFILE to #{gemfile}" if $VERBOSE
+ ENV["BUNDLE_GEMFILE"] = gemfile
end
- def setup_gemfile
- ENV["BUNDLE_GEMFILE"] =
- IS_APP_DIR ? "#{CUR_DIR}/Gemfile"
- : "#{GEM_DIR}/exe/Gemfile"
+ # app phase
+
+ def lookup_and_require_app
+ finder = \
+ proc do |lib_name, file_name|
+ log "#{self} checking if #{file_name} exists" if $VERBOSE
+ if File.file? "#{file_name}"
+ require lib_name
+ true
+ else
+ false
+ end
+ end
+
+ return if finder.call "#{CUR_DIR}/#{$APP}", "#{CUR_DIR}/#{$APP}.rb"
+ return if finder.call "#{GEM_DIR}/#{$APP}", "#{GEM_DIR}/#{$APP}.rb"
+
+ raise Error, "Could not find #{$APP}.rb in #{CUR_DIR} or #{GEM_DIR}"
end
- # threads
+ # call phase
+
+ def lookup_and_set_mode
+ raise ModeNotFound, "App #{$APP} has no modes" if App.modes.empty?
+
+ mode = ENV["MODE"]
+ mode ||= App.modes.first
+ mode = mode.to_sym
+
+ raise ModeNotFound, "MODE `#{mode}` is not included in #{App.modes}" unless App.modes.include? mode
+
+ log "#{self}.#{__method__} #{mode.inspect}" if $VERBOSE
+ $MODE = mode
+ end
+
+ def lookup_and_require_dependencies
+ require "bundler/setup"
+ Bundler.require :default, *App.systems.keys
+ end
+
+ def lookup_and_load_settings
+ files = ["#{$APP}.#{$MODE}.env", "#{$APP}.env"]
+ require "dotenv"
+ Dotenv.load(*files)
+ end
+
+ def require_liza_and_bundle_systems
+ require "zeitwerk"
+ require "liza"
+
+ # App.loaders[0] first loads Liza, then each System class
+ App.loaders << loader = Zeitwerk::Loader.new
+ loader.tag = Liza.to_s
+
+ # collapse Liza paths
+
+ # ORDER MATTERS: IGNORE, COLLAPSE, PUSH
+ loader.collapse "#{Liza.source_location_radical}/**/*"
+ loader.push_dir "#{Liza.source_location_radical}", namespace: Liza
+
+ # loader setup
+
+ loader.enable_reloading
+ loader.setup
+
+ # load each System class
+
+ App.systems.keys.each do |k|
+ key = "#{k}_system"
+
+ App.require_system key
+ klass = Object.const_get key.camelize
+
+ App.systems[k] = klass
+ end
+
+ # App.loaders[1] first loads each System, then the App
+ App.loaders << loader = Zeitwerk::Loader.new
+
+ # collapse each System paths
+
+ App.systems.each do |k, klass|
+ # ORDER MATTERS: IGNORE, COLLAPSE, PUSH
+ loader.collapse "#{klass.source_location_radical}/**/*"
+ loader.push_dir "#{klass.source_location_radical}", namespace: klass
+ end
+
+ # cherrypick App paths
+
+ app_dir = "#{APP_DIR}/#{$APP}"
+ logv "Lizarb app loader #{app_dir}".on_cyan
+ list = Dir["#{app_dir}/*"].to_set
+ logv "Lizarb app loader lists #{list.count} entries to review".on_cyan
+
+ if list.empty?
+ logv "no #{app_dir} found".red
+ else
+ logv "Lizarb app loader found #{app_dir}\t\tCollapsing #{app_dir}/*".on_cyan
+
+ to_collapse = []
+
+ App.systems.each do |k, klass|
+ box_dir = "#{app_dir}/#{k}"
+ box_file = "#{box_dir}_box.rb"
+
+ if !list.include? box_file
+ logv "Lizarb app loader missd #{box_file}".on_light_black
+ else
+ logv "Lizarb app loader found #{box_file}\t\tto_collapse!".on_cyan
+ to_collapse << box_file
+
+ if !list.include? box_dir
+ logv "Lizarb app loader missd #{box_dir}".on_light_black
+ else
+ logv "Lizarb app loader found #{box_dir}\t\tto_collapse!".on_cyan
+ to_collapse << box_dir
+ end
+ end
+ end
+
+ # ORDER MATTERS: IGNORE, COLLAPSE, PUSH
+ to_ignore = list - to_collapse
+ to_ignore.each do |file|
+ logv "Lizarb app loader missd #{file}\t\tSkipping this one".on_light_black
+ loader.ignore file
+ end
+
+ to_collapse.each do |path|
+ logv "Lizarb app loader collapsing #{path}".on_cyan
+ if path.end_with? ".rb"
+ loader.collapse path
+ else
+ loader.collapse "#{path}/**/*"
+ end
+ end
+ loader.collapse "#{app_dir}/*"
+
+ loader.push_dir app_dir, namespace: Object
+ end
+
+ # loader setup
+
+ loader.enable_reloading
+ loader.setup
+
+ # App connects to systems
+
+ App.systems.each do |k, klass|
+ App.connect_system k, klass
+ end
+
+ App.systems.freeze
+ end
+
+ # thread management
def thread_object_id
Thread.current.object_id
end