Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bew/56cb97ff83d0824e4eac712b2d8ec649 to your computer and use it in GitHub Desktop.
Save bew/56cb97ff83d0824e4eac712b2d8ec649 to your computer and use it in GitHub Desktop.
require "./pluggable_system_env.cr"
class InMemSystemEnv
include PluggableSystem::Env::Interface
@mem_env = Hash(String, String).new
def enabled?
PluggableSystem::Env.current_impl == self
end
# override system hooks
def __on_init
@mem_env.clear
end
def __on_deinit
@mem_env.clear
end
# impl the backend
# Annotation idea? To have (OPTIONAL?) checks to make sure the sig is valid, etc..
#@[SystemOverride(:set)]
def set(key : String, value : String) : Nil
puts "mem env: set #{key} → #{value}"
key.check_no_null_byte("key")
value.check_no_null_byte("value")
@mem_env[key] = value
end
#@[SystemOverride(:unset)]
def set(key : String, value : Nil) : Nil
puts "mem env: unset #{key}"
key.check_no_null_byte("key")
@mem_env.delete[key]
end
#@[SystemOverride(:get)]
def get(key : String) : String?
puts "mem env: get #{key}"
key.check_no_null_byte("key")
@mem_env[key]?
end
#@[SystemOverride(:has?)]
def has_key?(key : String) : Bool
puts "mem env: has? #{key}"
key.check_no_null_byte("key")
@mem_env.has_key?(key)
end
#@[SystemOverride(:each)]
def each(&block : String, String ->)
puts "mem env: each"
@mem_env.each &block
end
end
require "spec"
describe "bla" do
it "foo" do
mem_env = InMemSystemEnv.new
mem_env.enabled?.should be_false
initial_home = ENV["HOME"]?
initial_home.should_not be_nil
PluggableSystem::Env.use mem_env
mem_env.enabled?.should be_true
ENV["HOME"]?.should be_nil
ENV["HOME"] = "my super home!"
ENV["HOME"]?.should eq "my super home!"
PluggableSystem::Env.use_os
mem_env.enabled?.should be_false
ENV["HOME"]?.should eq initial_home
end
end
# System backend controller
module PluggableSystem::Env
#include BackendController
OS_BACKEND = Crystal::System::Env::PLUGGABLESYSTEM_OS_BACKEND
class_getter current_impl : Interface = OS_BACKEND
protected def self.set_current_impl(impl : Interface) : Nil
current_impl.__on_deinit
@@current_impl = impl
current_impl.__on_init
end
def self.use(impl : Interface)
self.set_current_impl(impl)
end
def self.use_os
self.set_current_impl(OS_BACKEND)
end
def self.halt
end
def self.resume
end
#--------------------------------------
module Interface
annotation DefineSystemFunc; end
macro freeze_interface!
# Well, it doesn't 'freeze' anything..
{% for def_node in @type.methods.select { |d| d.annotation(DefineSystemFunc) } %}
# use def_node here!
{% end %}
end
@[DefineSystemFunc(:set)]
abstract def set(key : String, value : String) : Nil
@[DefineSystemFunc(:unset)]
abstract def set(key : String, value : Nil) : Nil
@[DefineSystemFunc(:get)]
abstract def get(key : String) : String?
@[DefineSystemFunc(:has?)]
abstract def has_key?(key : String) : Bool
@[DefineSystemFunc(:each)]
abstract def each(&block : String, String ->)
freeze_interface!
# backend hooks
# Hook called when the backend is going to be activated
def __on_init
end
# Hook called when the backend is going to be halted (desactivated temporarily)
def __on_halt
end
# Hook called when the backend is going to be resumed (after being halted)
def __on_unhalt
end
# Hook called when the backend is going to be desactivated
def __on_deinit
end
# need macro on 'finished' that checks that all system funcs are implemented?
# (with types..)
end
end
class PluggableSystem::BackendWrapper(T)
include PluggableSystem::Env::Interface
def initialize(@mod_impl : T.class)
end
def set(key : String, value : String) : Nil
@mod_impl.set(key, value)
end
def set(key : String, value : Nil) : Nil
@mod_impl.set(key, value)
end
def get(key : String) : String?
puts "env wrapper: get #{key}"
@mod_impl.get(key)
end
def has_key?(key : String) : Bool
@mod_impl.has_key?(key)
end
def each(&block : String, String ->)
@mod_impl.each(&block)
end
# backend hooks
def __on_init
if (mod = @mod_impl).responds_to? :__on_init
mod.__on_init
end
end
def __on_halt
if (mod = @mod_impl).responds_to? :__on_halt
mod.__on_halt
end
end
def __on_unhalt
if (mod = @mod_impl).responds_to? :__on_unhalt
mod.__on_unhalt
end
end
def __on_deinit
if (mod = @mod_impl).responds_to? :__on_deinit
mod.__on_deinit
end
end
end
module Crystal::System::Env
PLUGGABLESYSTEM_OS_BACKEND = PluggableSystem::BackendWrapper.new(Crystal::System::Env)
# Override all the things! \o/
def self.set(key : String, value : String) : Nil
impl = PluggableSystem::Env.current_impl
if impl == PLUGGABLESYSTEM_OS_BACKEND
puts "system env: set #{key} → #{value}"
previous_def
else
impl.set(key, value)
end
end
def self.set(key : String, value : Nil) : Nil
impl = PluggableSystem::Env.current_impl
if impl == PLUGGABLESYSTEM_OS_BACKEND
puts "system env: unset #{key}"
previous_def
else
impl.set(key, value)
end
end
def self.get(key : String) : String?
impl = PluggableSystem::Env.current_impl
if impl == PLUGGABLESYSTEM_OS_BACKEND
puts "system env: get #{key}"
previous_def
else
impl.get(key)
end
end
def self.has_key?(key : String) : Bool
impl = PluggableSystem::Env.current_impl
if impl == PLUGGABLESYSTEM_OS_BACKEND
puts "system env: has? #{key}"
previous_def
else
impl.has_key?(key)
end
end
def self.each(&block : String, String ->)
impl = PluggableSystem::Env.current_impl
if impl == PLUGGABLESYSTEM_OS_BACKEND
puts "system env: each"
previous_def
else
# FIXME: ENV.to_h doesn't compile with this..
impl.each(&block)
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment