diff --git a/lib/kangaru/router.rb b/lib/kangaru/router.rb index a656961..9a3b4bf 100644 --- a/lib/kangaru/router.rb +++ b/lib/kangaru/router.rb @@ -2,11 +2,38 @@ module Kangaru class Router using Patches::Constantise + class UndefinedControllerError < StandardError; end + + class UndefinedActionError < StandardError; end + attr_reader :command, :namespace def initialize(command, namespace: Object) @command = command @namespace = namespace + + validate_controller_defined! + validate_action_defined! + end + + private + + def controller_class + @controller_class ||= command.controller.constantise(root: namespace) + end + + def validate_controller_defined! + return if namespace.const_defined?(command.controller) + + raise UndefinedControllerError, + "#{command.controller} is not defined in #{namespace}" + end + + def validate_action_defined! + return if controller_class.instance_methods.include?(command.action) + + raise UndefinedActionError, + "#{command.action} is not defined by #{command.controller}" end end end diff --git a/sig/kangaru/router.rbs b/sig/kangaru/router.rbs index 8673f50..be0820d 100644 --- a/sig/kangaru/router.rbs +++ b/sig/kangaru/router.rbs @@ -1,8 +1,24 @@ module Kangaru class Router + class UndefinedControllerError < StandardError + end + + class UndefinedActionError < StandardError + end + attr_reader command: Command attr_reader namespace: Module def initialize: (Command, ?namespace: Module) -> void + + private + + @controller_class: untyped + + def controller_class: -> untyped + + def validate_controller_defined!: -> void + + def validate_action_defined!: -> void end end diff --git a/spec/kangaru/router_spec.rb b/spec/kangaru/router_spec.rb index 9be8e0b..8736e6a 100644 --- a/spec/kangaru/router_spec.rb +++ b/spec/kangaru/router_spec.rb @@ -9,11 +9,50 @@ let(:namespace) { SomeNamespace } - before { stub_const "SomeNamespace", Module.new } + let(:controller_class) do + Class.new(described_class) { def some_action = nil } + end + + before do + stub_const "SomeNamespace", Module.new + stub_const "SomeNamespace::SomeController", controller_class + end describe "#initialize" do - it "sets the attributes" do - expect(router).to have_attributes(command:, namespace:) + context "when command controller is not defined" do + let(:controller) { "AnotherController" } + + it "raises an error" do + expect { router }.to raise_error( + described_class::UndefinedControllerError, + "#{controller} is not defined in #{namespace}" + ) + end + end + + context "when command controller is defined" do + let(:controller) { "SomeController" } + + context "and command action is not defined" do + let(:controller_class) { Class.new(described_class) } + + it "raises an error" do + expect { router }.to raise_error( + described_class::UndefinedActionError, + "#{action} is not defined by #{controller}" + ) + end + end + + context "and command action is defined" do + it "does not raise an error" do + expect { router }.not_to raise_error + end + + it "sets the attributes" do + expect(router).to have_attributes(command:, namespace:) + end + end end end end