module Obfusk::ADT::ClassMethods
Public Instance Methods
_new(ctor, data = {}, &b)
click to toggle source
# File lib/obfusk/adt.rb, line 41 def _new(ctor, data = {}, &b) c = constructors[ctor] c[:method].call *data.values_at(*c[:keys]), &b end
constructors()
click to toggle source
the constructors
# File lib/obfusk/adt.rb, line 106 def constructors @constructors ||= {} end
import_constructors(scope, const = true)
click to toggle source
import the constructors into another namespace
# File lib/obfusk/adt.rb, line 111 def import_constructors(scope, const = true) constructors.each_pair do |k,v| m = method k scope.define_singleton_method(k) { |*a,&b| m[*a,&b] } scope.const_set k, v[:ctor] if const end end
inherited(subclass)
click to toggle source
duplicate constructors for subclasses
# File lib/obfusk/adt.rb, line 47 def inherited(subclass) return if ::Obfusk::ADT_Meta__[:inheriting].last ctors = constructors subclass.class_eval do ctors.each_pair do |k,v| constructor v[:name], *v[:keys], &v[:block] end end end
match(x, opts)
click to toggle source
pattern matching
# File lib/obfusk/adt.rb, line 120 def match(x, opts) raise ArgumentError, 'not an ADT' unless x.is_a?(::Obfusk::ADT) raise ArgumentError, "types do not match (#{x.class.superclass} for #{self})" \ unless x.class.superclass == self x.match opts end
new(*a, &b)
click to toggle source
record constructor; call with name of constructor and hash of keys to values
Calls superclass method
# File lib/obfusk/adt.rb, line 37 def new(*a, &b) ancestors.include?(::Obfusk::ADT::Constructor) ? super : _new(*a, &b) end
Private Instance Methods
constructor(name, *keys, &b)
click to toggle source
create a constructor @param [Symbol] name the name of the constructor @param [<Symbol>] keys the keys of the constructor
# File lib/obfusk/adt.rb, line 60 def constructor(name, *keys, &b) keys_ = keys.map(&:to_sym) name_ = name.to_sym ctor = ::Obfusk::ADT_Meta__[:mutex].synchronize do begin ::Obfusk::ADT_Meta__[:inheriting] << true Class.new self ensure ::Obfusk::ADT_Meta__[:inheriting].pop end end ctor.class_eval do include ::Obfusk::ADT::Constructor keys_.each { |k| define_method(k) { __adt_data__[k] } } define_method(:initialize) do |guard, ctor, *values, &f| raise ArgumentError, 'for internal use only!' \ unless guard == :for_internal_use_only if !b && (k = keys_.length) != (v = values.length) raise ArgumentError, "wrong number of arguments (#{v} for #{k})" end data = Hash[keys_.zip values].freeze @ctor = ctor ; @ctor_name = name_ ; @ctor_keys = keys_ @data = b ? b[self, data, values, f].freeze : data end end class_eval do const_set name_, ctor f = -> v, b { ctor.new :for_internal_use_only, ctor, *v, &b } if !b && keys.empty? singleton = f[[],nil] define_singleton_method(name_) { singleton } define_method(name_) { singleton } else define_singleton_method(name_) { |*values,&b| f[values,b] } define_method(name_) { |*values,&b| f[values,b] } end constructors[name_] = { ctor: ctor, method: method(name_), name: name_, keys: keys_, block: b } end name_ end