diff --git a/lib/alchemy/modules.rb b/lib/alchemy/modules.rb index 544b43c49d..898f9ce4d0 100644 --- a/lib/alchemy/modules.rb +++ b/lib/alchemy/modules.rb @@ -6,25 +6,56 @@ module Modules @@alchemy_modules = YAML.load_file(File.expand_path('../../config/alchemy/modules.yml', __dir__)) - def self.included(base) - base.send :helper_method, :alchemy_modules, :module_definition_for - end + 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 self.register_module(module_definition) - @@alchemy_modules << module_definition.deep_stringify_keys + # 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) + end + + @@alchemy_modules << definition_hash + end + + private + + def validate_controllers_existence(controllers) + 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 diff --git a/spec/libraries/modules_spec.rb b/spec/libraries/modules_spec.rb index 7f7aea359b..8c539cbefe 100644 --- a/spec/libraries/modules_spec.rb +++ b/spec/libraries/modules_spec.rb @@ -57,16 +57,52 @@ class ModulesTestController < ApplicationController { 'name' => 'module', 'navigation' => { - 'controller' => 'admin/controller_name', + 'controller' => 'register_module_dummy', 'action' => 'index' } } end + let(:bad_alchemy_module_a) do + { + 'name' => 'bad_module_a', + 'navigation' => { + 'controller' => 'bad_module', + 'action' => 'index' + } + } + end + + let(:bad_alchemy_module_b) do + { + 'name' => 'bad_module_b', + 'navigation' => { + 'controller' => 'register_module_dummy', + 'action' => 'index', + 'sub_navigation' => [{ + 'controller' => 'bad_module', + 'action' => 'index' + }] + } + } + end + it "registers a module definition into global list of modules" do + class ::RegisterModuleDummyController + ### mock the existence of the controller + end + Modules.register_module(alchemy_module) expect(Modules.alchemy_modules).to include(alchemy_module) end + + it "fails to register a module when a matching navigation controller cannot be found" do + expect { Modules.register_module(bad_alchemy_module_a) }.to raise_error(NameError) + end + + it "fails to register a module when a matching sub_navigation controller cannot be found" do + expect { Modules.register_module(bad_alchemy_module_b) }.to raise_error(NameError) + end end end end