Skip to content

Instantly share code, notes, and snippets.

@ktimothy
Last active March 19, 2019 20:11
Show Gist options
  • Save ktimothy/d2ffb3b1c529cd8e0e16f9d6302f4c85 to your computer and use it in GitHub Desktop.
Save ktimothy/d2ffb3b1c529cd8e0e16f9d6302f4c85 to your computer and use it in GitHub Desktop.
Almost dynamic refinement in ruby.

This allows to restrict some method calls and allow to only specific classes.

module Restrictor
# used to save chains of const_missing method calls
# will allow to use constant instead of string even before constant was defined
# e. g. Okay::Allowed instead of 'Okay::Allowed'
class MissingChainer
def self.create
Class.new(self)
end
def self.const_missing(constant)
add_to_chain(constant)
self
end
def self.add_to_chain(c)
@chain ||= []
@chain << c.to_s
end
def self.erase_chain!
result = @chain.join('::') rescue nil
@chain = []
result
end
def self.chain
@chain.join('::') rescue nil
end
def self.to_s
chain
end
end
def restrict_method(name, *allow_tos)
alias_method("__#{name}", name)
define_method(name) { :restricted }
klass = self
allow_tos.each do |allow_to|
refined_module = Restrictor[allow_to.to_s]
refined_module.instance_exec do
refine klass do
define_method(name) do
send("__#{name}")
end
end
end
end
end
def const_missing(constant)
MissingChainer.create.const_missing(constant)
end
def self.[](model_or_name)
Restrictor.dict[model_or_name.to_s] ||= Module.new {}
end
private
def self.dict
@@dictionary ||= {}
end
end
class Model
extend Restrictor
def ololo
:allowed
end
restrict_method :ololo, Checker, Allowed, Okay::Allowed, One::Two::Three::Allowed
end
class Allowed
using Restrictor[self]
def try_it
Model.new.ololo
end
end
module Okay
class Allowed
using Restrictor[self]
def try_it
Model.new.ololo
end
end
end
module One
module Two
module Three
class Allowed
using Restrictor[self]
def try_it
Model.new.ololo
end
end
end
end
end
class Checker < One::Two::Three::Allowed
using Restrictor[self]
def try_it
Model.new.ololo
end
end
puts Model.new.ololo
puts Allowed.new.try_it
puts Okay::Allowed.new.try_it
puts One::Two::Three::Allowed.new.try_it
puts Checker.new.try_it
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment