diff --git a/lib/gruf/autoloaders.rb b/lib/gruf/autoloaders.rb index 158c2ea..67689f6 100644 --- a/lib/gruf/autoloaders.rb +++ b/lib/gruf/autoloaders.rb @@ -24,12 +24,17 @@ class << self include Enumerable ## - # Initialize the autoloaders with a given controllers path + # Initialize the autoloaders with given controllers paths # # @param [String] controllers_path The path to Gruf Controllers + # @param [Array] controllers_paths The path to Gruf Controllers # - def load!(controllers_path:) - controllers(controllers_path: controllers_path) + def load!(controllers_path: nil, controllers_paths: []) + if controllers_path + ::Gruf.logger.warn('controllers_path is deprecated. Please use controllers_paths instead.') + controllers_paths = [controllers_path] + end + controllers(controllers_paths: controllers_paths) end ## @@ -52,9 +57,10 @@ def reload # @return [::Gruf::Controllers::Autoloader] # # rubocop:disable ThreadSafety/ClassInstanceVariable - def controllers(controllers_path: nil) + def controllers(controllers_paths: []) + controllers_paths = ::Gruf.controllers_paths if controllers_paths.empty? controllers_mutex do - @controllers ||= ::Gruf::Controllers::Autoloader.new(path: controllers_path || ::Gruf.controllers_path) + @controllers ||= ::Gruf::Controllers::Autoloader.new(paths: controllers_paths) end end # rubocop:enable ThreadSafety/ClassInstanceVariable diff --git a/lib/gruf/cli/executor.rb b/lib/gruf/cli/executor.rb index cec4155..643b080 100644 --- a/lib/gruf/cli/executor.rb +++ b/lib/gruf/cli/executor.rb @@ -119,7 +119,7 @@ def parse_options # def register_services! # wait to load controllers until last possible second to allow late configuration - ::Gruf.autoloaders.load!(controllers_path: Gruf.controllers_path) + ::Gruf.autoloaders.load!(controllers_paths: Gruf.controllers_paths) services = determine_services(@services) services = bind_health_check!(services) if health_check_enabled? diff --git a/lib/gruf/client.rb b/lib/gruf/client.rb index 0e031ee..9d07e5a 100644 --- a/lib/gruf/client.rb +++ b/lib/gruf/client.rb @@ -159,7 +159,7 @@ def rpc_desc(request_method) # def request_object(request_method, params = {}) desc = rpc_desc(request_method) - desc&.input ? desc.input.new(params) : nil + desc&.input&.new(params) end ## diff --git a/lib/gruf/configuration.rb b/lib/gruf/configuration.rb index 5d949ef..e23a627 100644 --- a/lib/gruf/configuration.rb +++ b/lib/gruf/configuration.rb @@ -44,6 +44,8 @@ module Configuration # @return [String] If use_ssl is true, the relative path from the root_path to the key file for the server # @!attribute controllers_path # @return [String] The relative path from root_path to locate Gruf Controllers in + # @!attribute controllers_paths + # @return [Array] The relative paths from root_path to locate Gruf Controllers in # @!attribute services # @return [Array] An array of services to serve with this Gruf server # @!attribute logger @@ -96,6 +98,7 @@ module Configuration ssl_crt_file: '', ssl_key_file: '', controllers_path: '', + controllers_paths: [], services: [], logger: nil, grpc_logger: nil, @@ -176,6 +179,7 @@ def reset self.ssl_key_file = "#{root_path}config/ssl/#{environment}.key" cp = ::ENV.fetch('GRUF_CONTROLLERS_PATH', 'app/rpc').to_s self.controllers_path = root_path.to_s.empty? ? cp : "#{root_path}/#{cp}" + self.controllers_paths = [controllers_path] self.backtrace_on_error = ::ENV.fetch('GRPC_BACKTRACE_ON_ERROR', 0).to_i.positive? self.rpc_server_options = { max_waiting_requests: ::ENV.fetch('GRPC_SERVER_MAX_WAITING_REQUESTS', diff --git a/lib/gruf/controllers/autoloader.rb b/lib/gruf/controllers/autoloader.rb index a7bfe73..757af26 100644 --- a/lib/gruf/controllers/autoloader.rb +++ b/lib/gruf/controllers/autoloader.rb @@ -20,24 +20,24 @@ module Gruf module Controllers ## - # Handles autoloading of Gruf controllers in the application path. This allows for code reloading on Gruf + # Handles autoloading of Gruf controllers in the application paths. This allows for code reloading on Gruf # controllers. # class Autoloader include ::Gruf::Loggable - # @!attribute [r] path - # @return [String] The path for this autoloader - attr_reader :path + # @!attribute [r] paths + # @return [Array] The paths for this autoloader + attr_reader :paths ## - # @param [String] path + # @param [Array] paths # @param [Boolean] reloading # @param [String] tag # - def initialize(path:, reloading: nil, tag: nil) + def initialize(paths:, reloading: nil, tag: nil) super() - @path = path + @paths = paths @loader = ::Zeitwerk::Loader.new @loader.tag = tag || 'gruf-controllers' @setup = false @@ -73,11 +73,14 @@ def with_fresh_controller(controller_name) def setup! return true if @setup - return false unless File.directory?(@path) + directories = @paths.select { |path| File.directory?(path) } + return false unless directories.any? @loader.enable_reloading if @reloading_enabled - @loader.ignore("#{@path}/**/*_pb.rb") - @loader.push_dir(@path) + directories.each do |path| + @loader.ignore("#{path}/**/*_pb.rb") + @loader.push_dir(path) + end @loader.setup # always eager load RPC files, so that the service binder can bind the Gruf::Controller instantiation # to the gRPC Service classes diff --git a/lib/gruf/hooks/registry.rb b/lib/gruf/hooks/registry.rb index 8af5f6a..1b11eb4 100644 --- a/lib/gruf/hooks/registry.rb +++ b/lib/gruf/hooks/registry.rb @@ -90,7 +90,7 @@ def insert_after(after_class, hook_class, options = {}) raise HookNotFoundError if pos.nil? @registry.insert( - (pos + 1), + pos + 1, klass: hook_class, options: options ) diff --git a/lib/gruf/integrations/rails/railtie.rb b/lib/gruf/integrations/rails/railtie.rb index 2a6483d..04f8122 100644 --- a/lib/gruf/integrations/rails/railtie.rb +++ b/lib/gruf/integrations/rails/railtie.rb @@ -26,10 +26,10 @@ class Railtie < ::Rails::Railtie config.before_configuration do # Remove autoloading of the controllers path from Rails' zeitwerk, so that we ensure Gruf's zeitwerk # properly manages them itself. This allows us to manage code reloading and logging in Gruf specifically - app.config.eager_load_paths -= [::Gruf.controllers_path] if app.config.respond_to?(:eager_load_paths) + app.config.eager_load_paths -= ::Gruf.controllers_paths if app.config.respond_to?(:eager_load_paths) if ::Rails.respond_to?(:autoloaders) # if we're on a late enough version of rails ::Rails.autoloaders.each do |autoloader| - autoloader.ignore(Gruf.controllers_path) + autoloader.ignore(Gruf.controllers_paths) end end end diff --git a/lib/gruf/interceptors/registry.rb b/lib/gruf/interceptors/registry.rb index 283bf57..0661c85 100644 --- a/lib/gruf/interceptors/registry.rb +++ b/lib/gruf/interceptors/registry.rb @@ -90,7 +90,7 @@ def insert_after(after_class, interceptor_class, options = {}) raise InterceptorNotFoundError if pos.nil? @registry.insert( - (pos + 1), + pos + 1, klass: interceptor_class, options: options ) diff --git a/lib/gruf/server.rb b/lib/gruf/server.rb index 492d48e..356b0a8 100644 --- a/lib/gruf/server.rb +++ b/lib/gruf/server.rb @@ -202,6 +202,13 @@ def controllers_path options.fetch(:controllers_path, Gruf.controllers_path) end + ## + # @param [Array] + # + def controllers_paths + options.fetch(:controllers_paths, Gruf.controllers_paths) + end + ## # Load the SSL/TLS credentials for this server # diff --git a/spec/gruf/autoloaders_spec.rb b/spec/gruf/autoloaders_spec.rb index e90209c..57ba953 100644 --- a/spec/gruf/autoloaders_spec.rb +++ b/spec/gruf/autoloaders_spec.rb @@ -22,12 +22,28 @@ let(:controllers_path) { 'spec/pb' } describe '#load!' do - subject { autoloaders.load!(controllers_path: controllers_path) } + subject { autoloaders.load!(controllers_paths: [controllers_path]) } it 'creates a controller autoloader for the passed path' do subject expect(autoloaders.controllers).to be_a(::Gruf::Controllers::Autoloader) - expect(autoloaders.controllers.path).to eq controllers_path + expect(autoloaders.controllers.paths).to eq [controllers_path] + end + + context 'when deprecated controllers_path is passed' do + subject { autoloaders.load!(controllers_path: controllers_path) } + + it 'creates a controller autoloader for the passed path' do + subject + expect(autoloaders.controllers).to be_a(::Gruf::Controllers::Autoloader) + expect(autoloaders.controllers.paths).to eq [controllers_path] + end + + it 'logs a deprecation warning' do + expect(::Gruf.logger) + .to receive(:warn).with('controllers_path is deprecated. Please use controllers_paths instead.') + subject + end end end @@ -41,7 +57,7 @@ subject { autoloaders.reload } before do - autoloaders.load!(controllers_path: controllers_path) + autoloaders.load!(controllers_paths: [controllers_path]) end it 'runs reload on all autoloaders' do diff --git a/spec/gruf/controllers/autoloader_spec.rb b/spec/gruf/controllers/autoloader_spec.rb index 775919e..463d65c 100644 --- a/spec/gruf/controllers/autoloader_spec.rb +++ b/spec/gruf/controllers/autoloader_spec.rb @@ -21,7 +21,7 @@ let(:path) { 'spec/pb' } let(:reloading) { nil } let(:tag) { 'gruf-controllers' } - let(:autoloader) { described_class.new(path: path, reloading: reloading) } + let(:autoloader) { described_class.new(paths: [path], reloading: reloading) } let(:zeitwerk) do instance_spy(::Zeitwerk::Loader, setup: true, 'tag=': tag, tag: tag, ignore: true, push_dir: true, eager_load: true) end