Last active
August 29, 2015 14:15
-
-
Save sheldonh/175895d559a4d0b8ab04 to your computer and use it in GitHub Desktop.
Ruby factory prototype
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module Starjuice | |
module Factory | |
module Constructor | |
class Adaptor | |
def initialize(adaptor = nil) | |
@adaptor = adaptor || ->(properties) { [properties] } | |
end | |
def call(provider_class, properties = nil) | |
if properties.nil? | |
provider_class.new | |
else | |
provider_class.new(*adapt(properties)) | |
end | |
end | |
def adapt(properties) | |
@adaptor.call(properties) | |
end | |
end | |
class PropertyBased < Adaptor | |
end | |
class Positional < Adaptor | |
def initialize(*keywords) | |
@keywords = keywords | |
end | |
def adapt(properties) | |
@keywords.inject([]) { |m, k| m << properties[k] } | |
end | |
end | |
end | |
class ProviderRegistration | |
attr_reader :interface, :provider_id, :provider_class, :provider_constructor | |
def initialize(interface, provider_id, provider_class, provider_constructor) | |
@interface, @provider_id, @provider_class, @provider_constructor = interface, provider_id, provider_class, provider_constructor | |
end | |
end | |
class ProviderRegistry | |
def initialize | |
@registrations = [] | |
end | |
def register(provider_registration) | |
if existing = find(provider_registration.interface, provider_registration.provider_id) | |
$stderr.puts "WARNING: #{provider_registration.provider_class} replacing #{existing.provider_class} as #{provider_registration.provider_id} #{provider_registration.interface} provider" | |
end | |
@registrations.unshift provider_registration | |
end | |
def find(interface, provider_id) | |
@registrations.detect { |registration| registration.interface.eql?(interface) and registration.provider_id.eql?(provider_id) } | |
end | |
end | |
module InterfaceFactory | |
class Base | |
attr_reader :interface | |
def initialize(interface, options) | |
@interface = interface | |
@interface_constructor = options[:constructor] || ->(interface, provider) { interface.new(provider) } | |
@registry = ProviderRegistry.new | |
end | |
def register_provider(provider_id, provider_class, options = {}) | |
provider_constructor = options[:constructor] || Constructor::PropertyBased.new | |
registration = ProviderRegistration.new(@interface, provider_id, provider_class, provider_constructor) | |
@registry.register(registration) | |
end | |
def create(provider_id, properties = nil) | |
registration = @registry.find(@interface, provider_id) | |
provider = registration.provider_constructor.call(registration.provider_class, properties) | |
@interface_constructor.call(@interface, provider) | |
end | |
end | |
def creates_interface(interface, options = {}) | |
@interface_factory = Base.new(interface, options) | |
end | |
def create(provider_id, properties = nil) | |
@interface_factory.create(provider_id, properties) | |
end | |
def register_provider(provider_id, provider_class, options = {}) | |
@interface_factory.register_provider(provider_id, provider_class, options) | |
end | |
end | |
end | |
end | |
class Cow | |
def initialize(provider) | |
@provider = provider | |
end | |
def describe | |
@provider.describe | |
end | |
end | |
class CowFactory | |
extend Starjuice::Factory::InterfaceFactory | |
creates_interface Cow | |
end | |
class Friesland | |
def initialize(colors) | |
@background_color = colors[:background] | |
@foreground_color = colors[:foreground] | |
end | |
def describe | |
"A large, #{@foreground_color}-and-#{@background_color}, milk-producing cow" | |
end | |
end | |
CowFactory.register_provider :friesland, Friesland | |
class Jersey | |
def initialize(color = "brown") | |
@color = color | |
end | |
def describe | |
"A small, #{@color}, butter-producing cow" | |
end | |
end | |
CowFactory.register_provider :jersey, Jersey, constructor: Starjuice::Factory::Constructor::Positional.new(:color) | |
class Angus | |
def initialize(color) | |
@color = color | |
end | |
def describe | |
"A large, #{@color}, beef-producing cow with no horns" | |
end | |
end | |
CowFactory.register_provider :angus, Angus, constructor: ->(c, props) { c.new(props[:color]) } | |
CowFactory.register_provider :martian, Angus, constructor: Starjuice::Factory::Constructor::Positional.new(:color) | |
class Invisible | |
def describe | |
"An invisible cow (presumably)" | |
end | |
end | |
CowFactory.register_provider :invisible, Invisible | |
cows = { | |
"Abbie" => CowFactory.create(:friesland, foreground: "black", background: "white"), | |
"Bessy" => CowFactory.create(:jersey, color: "pink"), | |
"Curly" => CowFactory.create(:jersey), | |
"Daisy" => CowFactory.create(:angus, color: "brown"), | |
"Sneak" => CowFactory.create(:invisible), | |
"Xqtuk" => CowFactory.create(:martian, color: "green"), | |
} | |
cows.each { |name, cow| puts "#{name}: #{cow.describe}" } | |
puts "And now, a little warning..." | |
CowFactory.register_provider :martian, Friesland | |
cow = CowFactory.create(:martian, foreground: "spectral", background: "weird") | |
puts "Xqtuk has become: #{cow.describe}" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment