lib/alchemy/modules.rb
# frozen_string_literal: true
module Alchemy
module Modules
mattr_accessor :alchemy_modules
@@alchemy_modules = YAML.load_file(File.expand_path("../../config/alchemy/modules.yml", __dir__))
class << self
def included(base)
base.send :helper_method, :alchemy_modules, :module_definition_for
end
# Register a Alchemy module.
#
# A module is a Hash that must have at least a name and a navigation key
# that has a controller and action name.
#
# == Example:
#
# name: 'module',
# navigation: {
# controller: 'admin/controller_name',
# action: 'index'
# }
#
def register_module(module_definition)
definition_hash = module_definition.deep_stringify_keys
### Validate controller(s) existence
if definition_hash["navigation"].is_a?(Hash)
defined_controllers = [definition_hash["navigation"]["controller"]]
if definition_hash["navigation"]["sub_navigation"].is_a?(Array)
defined_controllers.concat(definition_hash["navigation"]["sub_navigation"].map { |x| x["controller"] })
end
validate_controllers_existence(defined_controllers, definition_hash)
end
@@alchemy_modules |= [definition_hash]
end
private
def validate_controllers_existence(controllers, definition_hash)
controllers.each do |controller_val|
next if controller_val.blank?
controller_name = "#{controller_val.camelize}Controller"
begin
controller_name.constantize
rescue NameError
raise "Error in AlchemyCMS module definition: '#{definition_hash["name"]}'. Could not find the matching controller class #{controller_name.sub(/^::/, "")} for the specified controller: '#{controller_val}'"
end
end
end
end
# Get the module definition for given module name
#
# You can also pass a hash of an module definition.
# It then tries to find the module defintion from controller name and action name
#
def module_definition_for(name_or_params)
case name_or_params
when String
alchemy_modules.detect { |m| m["name"] == name_or_params }
when Hash
name_or_params.stringify_keys!
alchemy_modules.detect do |alchemy_module|
module_navi = alchemy_module.fetch("navigation", {})
definition_from_mainnavi(module_navi, name_or_params) ||
definition_from_subnavi(module_navi, name_or_params) ||
definition_from_nested(module_navi, name_or_params)
end
else
raise ArgumentError, "Could not find module definition for #{name_or_params}"
end
end
private
def definition_from_mainnavi(module_navi, params)
controller_matches?(module_navi, params) && action_matches?(module_navi, params)
end
def definition_from_subnavi(module_navi, params)
subnavi = module_navi["sub_navigation"]
return if subnavi.nil?
subnavi.any? do |navi|
controller_matches?(navi, params) && action_matches?(navi, params)
end
end
def definition_from_nested(module_navi, params)
nested = module_navi["nested"]
return if nested.nil?
nested.any? do |navi|
controller_matches?(navi, params) && action_matches?(navi, params)
end
end
def controller_matches?(navi, params)
remove_slash(navi["controller"]) == remove_slash(params["controller"])
end
def action_matches?(navi, params)
navi["action"] == params["action"]
end
def remove_slash(str)
str.gsub(/^\//, "")
end
end
end