Skip to content

Instantly share code, notes, and snippets.

@piclez
Forked from dajulia3/listings_controller.rb
Created March 30, 2023 01:36
Show Gist options
  • Save piclez/4f06923ca120830bc6e45273919768c1 to your computer and use it in GitHub Desktop.
Save piclez/4f06923ca120830bc6e45273919768c1 to your computer and use it in GitHub Desktop.
Service locator with Rails Initializer for rails service loader that loads the services from a config file.
class ListingsController < ApplicationController
def index
movie_listing_service = ServiceLocator.get_service_instance(:MovieListing)
@available_movies = movie_listing_service.available_movies
render nothing: true #this is just an example don't get hung up on it :)
end
end
#An example rails controller spec using this. Note that in your spec helper you could just have a before(:each) to reset the locator.
require "spec_helper"
describe ListingsController do
describe "GET #index" do
it "lists all the movies." do
gold_finger = mock("Goldfinger: an Awesome bond movie")
ferris_buellers_day_off = mock("Ferris Bueller's Day off")
fake_movie_listing_provider_service = mock("Fake Movie Listing Provider Service", available_movies: [gold_finger, ferris_buellers_day_off])
locator = ServiceLocator.instance
locator.register(:MovieListingProvider, fake_movie_listing_provider_service)
ServiceLocator.load_locator(locator)
get :index
assigns(:available_movies).should == [gold_finger, ferris_buellers_day_off]
end
end
end
class ServiceLocator
include Singleton
def self.reset_instance
self.instance_variable_set("@singleton__instance__", self.send(:new))
end
def initialize
@services = {}
end
#Do this in your setup file
def register(service_name, instance)
@services[service_name] = instance
end
def get_service_instance(service_name)
service_instance = @services[service_name]
raise NoSuchServiceInstanceException if service_instance.nil?
service_instance
end
class NoSuchServiceInstanceException < Exception; end
end
require "active_support/inflector"
#Require any gems that contain services that you'd like to use here
#eg: require "spacebook_api_services"
require "metflix"
require_relative File.join(Rails.root,"app/services/metflix_movie_listing_service") #Normally this would probably live in a gem!
services = YAML.load_file(File.join(File.expand_path( "..", File.dirname(__FILE__)), "services.yml"))
services.each do |service_name, service_info|
service_instance = service_info["class"].constantize.new(*service_args)
ServiceLocator.register(service_name.to_sym, service_instance)
endrequire "active_support/inflector"
require_relative File.join(Rails.root,"app/services/metflix_movie_listing_service") #Normally this would probably live in a gem!
services = YAML.load_file(File.join(File.expand_path( "..", File.dirname(__FILE__)), "services.yml"))
services.each do |service_name, service_info|
service_instance = service_info["class"].constantize.new(*service_args)
ServiceLocator.register(service_name.to_sym, service_instance)
end
require "spec_helper" #Could easily live in its own gem and be run/developed outside of rails but I was lazy ;)
describe ServiceLocator do
describe ".instance" do
it "returns the only locator instance for the Service Locator Singleton" do
ServiceLocator.instance.should == ServiceLocator.instance
end
end
describe ".reset_instance" do
it "sets the locator singleton's only instance to a new locator" do
original_instance = ServiceLocator.instance
ServiceLocator.reset_instance
ServiceLocator.instance.should_not == original_instance
end
end
describe ".get_service_instance" do
it "should return a properly constructed instance for the service named by the given symbol" do
locator = ServiceLocator.instance #Service locator instance from singleton ;)
charlie_horse_service = mock("A properly constructed charlie horse service instance")
locator.register(:CharlieHorseService, charlie_horse_service)
ServiceLocator.instance.get_service_instance(:CharlieHorseService).should == charlie_horse_service
end
it "should throw a NoSuchServiceInstance exception if there is no such instance registered with the locator" do
expect { ServiceLocator.instance.get_service_instance(:CrazyDataService) }.to raise_exception ServiceLocator::NoSuchServiceInstanceException
end
end
end
MovieListing:
class: MetFlixMovieListingService
args:
- abc_123 #api_key
- false #sandbox_mode
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment