Skip to content

Instantly share code, notes, and snippets.

@rosylilly
Created February 3, 2009 20:57
Show Gist options
  • Save rosylilly/57747 to your computer and use it in GitHub Desktop.
Save rosylilly/57747 to your computer and use it in GitHub Desktop.
Prototype class for ruby
class Object
def method_missing( _method, *arg)
_method = _method.to_sym
if (_method.to_s[_method.to_s.size - 1] == ?=) && ( arg[0].class == Proc)
target = (self.class == Class ? self : self.class)
target.class_eval do
define_method( _method.to_s[0, _method.to_s.size - 1].to_sym, arg[0].binding)
end
else
raise NoMethodError, "undefined method `#{_method}' for #{self.inspect}:#{self.class}", caller(1)
end
end
end
# Reference URL:
# http://d.hatena.ne.jp/javascripter/20081121/1227216175
# http://d.hatena.ne.jp/keyesberry/20081022/p1
# http://d.hatena.ne.jp/amachang/20061019/1161201903
# http://blog.livedoor.jp/dankogai/archives/50663122.html
class Rototype
require 'forwardable'
include Enumerable
extend Forwardable
def initialize(obj = nil)
raise TypeError unless obj.class == Hash || obj.class == self.class || obj.nil?
@objects = {}
@objects[:__proto__] = nil
unless obj.nil?
(obj.to_hash || {}).each_pair do | key, val |
self[key] = val
end
end
end
# 別名宣言
def this
self
end
def prototype
@objects[:__proto__]
end
def prototype=(obj)
raise TypeError if obj.class != self.class
@objects[:__proto__] = obj
end
def_delegator :@objects, :each, :each
def +(other)
raise TypeError if other.class != self.class && other.class != Hash
obj = self.class.new(other)
obj[:__proto__] = self
obj
end
def |(other)
obj = self.class.new()
obj[:__proto__] = self
other.each{|k, v|
unless key?(k)
obj[k] = v
end
}
obj
end
def new(obj = nil)
instance = self.class.new(obj)
instance[:__proto__] = self
return instance
end
def inheritance(obj = nil)
instance = self.class.new(obj)
instance[:__proto__] = self.class.new(self)
return instance
end
def merge!(obj)
@objects.merge!(obj || {}); nil
end
def merge(obj)
self.dup.merge!(obj)
end
def key?(data_name)
tmp = @objects.dup
begin
if tmp.key?(data_name.to_s.to_sym)
return true
end
tmp = tmp[:__proto__]
end until tmp.nil?
false
end
def [](data_name)
tmp = @objects.dup
begin
if tmp.key?(data_name.to_s.to_sym)
tmp = tmp[data_name.to_s.to_sym]
break
end
tmp = tmp[:__proto__]
end until tmp.nil?
tmp
end
def []=(data_name, data)
removeMethod(data_name.to_s.to_sym)
@objects[data_name.to_s.to_sym] = data
if data.class == Proc
addMethod(data_name.to_s.to_sym, data.binding)
end
end
def delete(name)
removeMethod(name.to_s.to_sym)
@objects.delete(name.to_s.to_sym)
end
def method_missing(method_name, *method_arg)
if self.key?(method_name.to_s.to_sym)
if respond_to?(method_name.to_s.to_sym)
method(method_name.to_s.to_sym, *method_arg)
else
if self[method_name.to_sym].class == Proc
addMethod(method_name.to_sym, self[method_name.to_sym].binding)
method(method_name.to_sym).call(*method_arg)
else
self[method_name.to_sym]
end
end
else
if method_name.to_s[method_name.to_s.size - 1].chr == '='
self[method_name.to_s[0, method_name.to_s.size - 1].to_sym] = method_arg[0]
else
raise NoMethodError.new('undefined method `'+method_name.to_s+'`')
end
end
end
def to_hash
@objects
end
private
def addMethod(name,bind)
obj_singleton = class << self; self end
obj_singleton.class_eval do
define_method(name, bind)
end
end
def removeMethod(name)
obj_singleton = class << self; self end
obj_singleton.class_eval do
remove_method(name) if respond_to?(name)
end
end
end
require 'prototype'
base = Rototype.new( :price => '$30', :quality => 'low'); # 安いが性能の低い物
quality = base.new( :quality => 'high'); # 安くて性能が良い
low = base.inheritance( :price => '$30'); # 高くて性能が悪い
base.quality = 'better' # baseの性能は普通になった
base.price = '$100' # しかも値段も上がった
p quality.price # qualityの値段もあがった => $100
p low.price # しかしlowは参考にしただけで技術を継承していないので値段もそのまま => $30
p quality.quality # 性能はやっぱりよい => high
p low.quality # 上記の理由で継承してないから性能もそのまま => low
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment