Last active
January 25, 2016 10:15
-
-
Save Yangff/070c5fc1a9b50047839e to your computer and use it in GitHub Desktop.
strong type system for ruby
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
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