Skip to content

Instantly share code, notes, and snippets.

@kenpusney
Forked from Yangff/strong.rb
Created January 25, 2016 10:15
Show Gist options
  • Save kenpusney/355fd3911e50184efa05 to your computer and use it in GitHub Desktop.
Save kenpusney/355fd3911e50184efa05 to your computer and use it in GitHub Desktop.
strong type system for ruby
class Symbol
def [](*args)
a = [self, args, '[]']
a.instance_eval('@_type_flag = \'[]\'')
a
end
def <<(*ary)
a = [self, ary.flatten, '<']
a.instance_eval('@_type_flag = \'<\'')
a
end
end
class Array
def < (*ary)
raise NoMethodError, "undefined method `<' for Array:Class", caller(1) if @_type_flag.nil?
a = [self, ary.flatten, '<']
a.instance_eval('@_type_flag = \'<\'')
a
end
alias old_ll <<
def << (*args)
return old_ll *args if @_type_flag.nil?
return self < args
end
end
def Def(name, &proc)
name = name[] if (!name.is_a?(Array))
raise TypeError, "wrong type of argument." if name[2] != '[]'
name[0] = name[0].to_sym
params = proc.parameters
needArgs = (params.index {|x| x[0] == :opt || x[0] == :rest } || params.size - 1) + 1
hasRest = !(params.index {|x| x[0] == :rest}).nil?
hasBlock = !(params.index {|x| x[0] == :block}).nil?
if (name.is_a?(Array) and name.size == 3)
time = Time.now
method_name = "_#{name[0]}__bind_#{time.to_i}_#{time.usec}"
define_method(method_name, &proc)
define_method(name[0]) do |*args, &newproc|
raise ArgumentError, "wrong number of arguments (#{args.size} for #{needArgs})", caller(1) if (args.size < needArgs || (!hasRest and args.size > needArgs.size))
for n in 0...[name[1].size,args.size].min
needType = name[1][n].is_a?(Array) ? name[1][n] : [name[1][n]]
needType = needType.map {|x|
if x.is_a?(Class)
x
else
if (self.class.respond_to?(:_template_list))
raise TypeError, "", caller(0) if (self.class._template_list[x].nil?)
self.class._template_list[x]
else
raise TypeError, "", caller(0)
end
end
}.flatten
raise TypeError, "wrong type of argument #{params[n][1]} (#{args[n].class.name} for #{needType})", caller(3) unless (needType.any? {|x| args[n].kind_of?(x)})
end
if (hasBlock) then method(method_name).call(*args, &newproc) else method(method_name).call(*args) end
end
end
end
class Object
def is_klass?
return false
end
end
Def :Class[[Symbol, String, Array]] do |name = {}, &_proc|
parents = []
_template = []
if (name.is_a?(Array))
raise TypeError, 'wrong type of argument' if name.size != 3
if (name[2] == '<')
parents = name[1]
name = name[0]
end
if (name[2] == '[]')
_template = name[1]
name = name[0]
end
end
name = name.to_sym
parents.uniq!
o = if self.respond_to?(:const_set) then self else Object end
parents.map! {|x| if x.is_a?(Symbol) then o.const_get(x) else x end }
mkClass = proc do |template_matchs = []|
_template_list = {}
_template.each_index{|x| _template_list[_template[x]] = template_matchs[x]}
myklass = Class.new do
@_parents_flat = []
@_template_list = _template_list
def self._parents_flat
return @_parents_flat
end
def self._template_list
return @_template_list
end
parents = parents.map { |p|
[p, p.klass_parents_flat] if (p.is_klass?)
}.flatten.uniq
parents.each { |p|
unless (@_parents_flat.include? p)
@_parents_flat << p
raise TypeError, "Class is required", caller(3) if (!p.is_klass?)
@_template_list.merge! p.klass_templte_list
instance_eval &p.klass_init_proc
end
}
instance_eval &_proc
def is_a?(type)
org = super(type)
return true if org
self.class._parents_flat.any? {|x| x == type}
end
end
myklass.define_singleton_method(:is_klass?) {true}
myklass.define_singleton_method(:klass_init_proc) { _proc }
myklass.define_singleton_method(:klass_templte_list) { @_template_list }
myklass.define_singleton_method(:klass_parents_flat) { @_parents_flat }
myklass
end
if (_template.size == 0)
klass = mkClass.call()
o.const_set(name, klass)
else
o.const_set(name, Class.new do
def initialize(mkClass, needTemplate = 0)
@needTemplate = needTemplate
@mkClass = mkClass
@doneClass = {}
end
def [](*args)
_template = args
raise ArgumentError if (_template.size != @needTemplate)
@doneClass[_template] = @mkClass.call(_template) if @doneClass[_template].nil?
@doneClass[_template]
end
end.new(mkClass, _template.size))
end
end
module WoW
Class :Aaa do
Def :hello do
puts 'xy'
end
end
Class :BBB << :Aaa do
Def :fuck do
puts 'xy'
end
end
Class :MyClass[:T] < [:Aaa, :BBB] do
alias_method :aloha, :hello
Def :hello[[String,Integer], :T] {|a,b, *z,&c|
print a,b,*z
aloha()
c.call()
}
end
end
klass = WoW::MyClass[[String,Integer]].new
klass.hello(1,"a","3","4","5") {puts 'x'}
klass.fuck()
print klass.is_a?(Float).to_s + "\n"
print klass.is_a?(WoW::MyClass[String]).to_s + "\n"
print klass.is_a?(WoW::MyClass[Integer]).to_s + "\n"
print klass.is_a?(WoW::BBB).to_s + "\n"
print klass.is_a?(Object).to_s + "\n"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment