lib/hanami/slice_registrar.rb in hanami-2.0.0.beta1.1 vs lib/hanami/slice_registrar.rb in hanami-2.0.0.beta2
- old
+ new
@@ -4,19 +4,23 @@
require_relative "slice"
module Hanami
# @api private
class SliceRegistrar
+ SLICE_DELIMITER = CONTAINER_KEY_DELIMITER
+
attr_reader :parent, :slices
private :parent, :slices
def initialize(parent)
@parent = parent
@slices = {}
end
def register(name, slice_class = nil, &block)
+ return unless filter_slice_names([name]).any?
+
if slices.key?(name.to_sym)
raise SliceLoadError, "Slice '#{name}' is already registered"
end
# TODO: raise error unless name meets format (i.e. single level depth only)
@@ -47,27 +51,42 @@
slice_dirs = Dir[File.join(root, SLICES_DIR, "*")]
.select { |path| File.directory?(path) }
.map { |path| File.basename(path) }
- (slice_dirs + slice_configs).uniq.sort.each do |slice_name|
+ slice_names = (slice_dirs + slice_configs).uniq.sort
+ .then { filter_slice_names(_1) }
+
+ slice_names.each do |slice_name|
load_slice(slice_name)
end
self
end
def each(&block)
slices.each_value(&block)
end
+ def keys
+ slices.keys
+ end
+
def to_a
slices.values
end
private
+ def root
+ parent.root
+ end
+
+ def inflector
+ parent.inflector
+ end
+
# Runs when a slice file has been found at `config/slices/[slice_name].rb`, or a slice
# directory at `slices/[slice_name]`. Attempts to require the slice class, if defined,
# or generates a new slice class for the given slice name.
def load_slice(slice_name)
slice_const_name = inflector.camelize(slice_name)
@@ -104,16 +123,57 @@
def configure_slice(slice_name, slice)
slice.instance_variable_set(:@parent, parent)
# Slices require a root, so provide a sensible default based on the slice's parent
slice.config.root ||= root.join(SLICES_DIR, slice_name.to_s)
+
+ slice.config.slices = child_slice_names(slice_name, parent.config.slices)
end
- def root
- parent.root
+ # Returns a filtered array of slice names based on the parent's `config.slices`
+ #
+ # This works with both singular slice names (e.g. `"admin"`) as well as dot-delimited nested
+ # slice names (e.g. `"admin.shop"`).
+ #
+ # It will consider only the base names of the slices (since in this case, a parent slice must be
+ # loaded in order for its children to be loaded).
+ #
+ # @example
+ # parent.config.slices # => ["admin.shop"]
+ # filter_slice_names(["admin", "main"]) # => ["admin"]
+ #
+ # parent.config.slices # => ["admin"]
+ # filter_slice_names(["admin", "main"]) # => ["admin"]
+ def filter_slice_names(slice_names)
+ slice_names = slice_names.map(&:to_s)
+
+ if parent.config.slices
+ slice_names & parent.config.slices.map { base_slice_name(_1) }
+ else
+ slice_names
+ end
end
- def inflector
- parent.inflector
+ # Returns the base slice name from an (optionally) dot-delimited nested slice name.
+ #
+ # @example
+ # base_slice_name("admin") # => "admin"
+ # base_slice_name("admin.users") # => "admin"
+ def base_slice_name(name)
+ name.to_s.split(SLICE_DELIMITER).first
+ end
+
+ # Returns an array of slice names specific to the given child slice.
+ #
+ # @example
+ # child_local_slice_names("admin", ["main", "admin.users"]) # => ["users"]
+ def child_slice_names(parent_slice_name, slice_names)
+ slice_names
+ &.select { |name|
+ name.include?(SLICE_DELIMITER) && name.split(SLICE_DELIMITER)[0] == parent_slice_name.to_s
+ }
+ &.map { |name|
+ name.split(SLICE_DELIMITER)[1..].join(SLICE_DELIMITER) # which version of Ruby supports this?
+ }
end
end
end