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