lib/hanami/app.rb in hanami-2.0.0.beta1.1 vs lib/hanami/app.rb in hanami-2.0.0.beta2
- old
+ new
@@ -1,8 +1,7 @@
# frozen_string_literal: true
-require "zeitwerk"
require_relative "configuration"
require_relative "constants"
require_relative "slice"
require_relative "slice_name"
@@ -29,33 +28,101 @@
subclass.extend(ClassMethods)
@_mutex.synchronize do
subclass.class_eval do
@configuration = Hanami::Configuration.new(app_name: slice_name, env: Hanami.env)
- @autoloader = Zeitwerk::Loader.new
- prepare_base_load_path
+ # Prepare the load path (based on the default root of `Dir.pwd`) as early as
+ # possible, so you can make a `require` inside the body of an `App` subclass,
+ # which may be useful for certain kinds of app configuration.
+ prepare_load_path
+
+ load_dotenv
end
end
end
# App class interface
module ClassMethods
- attr_reader :autoloader, :configuration
+ attr_reader :configuration
def app_name
slice_name
end
+ # Prepares the $LOAD_PATH based on the app's configured root, prepending the `lib/`
+ # directory if it exists. If the lib directory is already added, this will do
+ # nothing.
+ #
+ # In ordinary circumstances, you should never have to call this method: this method
+ # is called immediately upon subclassing {Hanami::App}, as a convenicence to put
+ # lib/ (under the default root of `Dir.pwd`) on the load path automatically. This is
+ # helpful if you need to require files inside the subclass body for performing
+ # certain app configuration steps.
+ #
+ # If you change your app's `config.root` and you need to require files from its
+ # `lib/` directory within your {App} subclass body, you should call
+ # {.prepare_load_path} explicitly after setting the new root.
+ #
+ # Otherwise, this method is called again as part of the app {.prepare} step, so if
+ # you've changed your app's root and do _not_ need to require files within your {App}
+ # subclass body, then you don't need to call this method.
+ #
+ # @example
+ # module MyApp
+ # class App < Hanami::App
+ # config.root = Pathname(__dir__).join("../src")
+ # prepare_load_path
+ #
+ # # You can make requires for your files here
+ # end
+ # end
+ #
+ # @return [self]
+ #
+ # @api public
+ # @since 2.0.0
+ def prepare_load_path
+ if (lib_path = root.join(LIB_DIR)).directory?
+ path = lib_path.realpath.to_s
+ $LOAD_PATH.prepend(path) unless $LOAD_PATH.include?(path)
+ end
+
+ self
+ end
+
private
- def prepare_base_load_path
- base_path = root.join(LIB_DIR)
- $LOAD_PATH.unshift(base_path) unless $LOAD_PATH.include?(base_path)
+ # Uses [dotenv](https://github.com/bkeepers/dotenv) (if available) to populate `ENV` from
+ # various `.env` files.
+ #
+ # For a given `HANAMI_ENV` environment, the `.env` files are looked up in the following order:
+ #
+ # - .env.{environment}.local
+ # - .env.local (unless the environment is `test`)
+ # - .env.{environment}
+ # - .env
+ #
+ # If dotenv is unavailable, the method exits and does nothing.
+ def load_dotenv
+ return unless Hanami.bundled?("dotenv")
+
+ hanami_env = Hanami.env
+ dotenv_files = [
+ ".env.#{hanami_env}.local",
+ (".env.local" unless hanami_env == :test),
+ ".env.#{hanami_env}",
+ ".env"
+ ].compact
+
+ require "dotenv"
+ Dotenv.load(*dotenv_files)
end
def prepare_all
+ prepare_load_path
+
# Make app-wide notifications available as early as possible
container.use(:notifications)
# Ensure all basic slice preparation is complete before we make adjustments below
# (which rely on the basic prepare steps having already run)
@@ -63,20 +130,13 @@
# Run specific prepare steps for the app slice. Note also that some
# standard steps have been skipped via the empty method overrides below.
prepare_app_component_dirs
prepare_app_providers
-
- # The autoloader must be setup after the container is configured, which is the
- # point at which any component dirs from other slices are added to the autoloader
- app = self
- container.after(:configure) do
- app.send(:prepare_app_autoloader)
- end
end
- # Skip standard slice prepare steps that do not apply to the app slice
+ # Skip standard slice prepare steps that do not apply to the app
def prepare_container_component_dirs; end
def prepare_container_imports; end
# rubocop:disable Metrics/AbcSize
@@ -120,10 +180,10 @@
require_relative "providers/rack"
register_provider(:rack, source: Hanami::Providers::Rack, namespace: true)
end
- def prepare_app_autoloader
+ def prepare_autoloader
# Component dirs are automatically pushed to the autoloader by dry-system's
# zeitwerk plugin. This method adds other dirs that are not otherwise configured
# as component dirs.
# Autoload classes from `lib/[app_namespace]/`