Page RubyLanguage.
C pointers in RubyRuby is fun. Here I implemented a C like "Pointer" object.
Ruby promet le retour du "s'amuser en programmant". D'expérience je peux dire que ça marche. Evidément il faut qu'un jour passé vous vous soyez 'amusé à programmer', sinon il n'y a aucun espoir de 'retour', faut pas rêver. Il y a quelques années j'avais, pour m'amuser donc, produit ma version du "pointeur" façon Ruby. Chacun se souvient de la définition de pointeur en C: "address of a left-expression", en gros. Ruby code:
# A Pointer references a value or a lvalue.
# It has a content that can be changed.
# This is a very general purpose mechanism that add one level
# of indirection when accessing objects. Dereferencing must be
# done manually by the user. See also deref!() method that walks
# some objects to permanently dereference their pointers for you.
class Pointer
# This is the block that gives the Ruby expression for the lvalue.
# It is also the binding context where the lvalue lives.
attr_reader :block
# This is the lvalue expression. It is "self" for anonymous pointer.
# The lvalue expression is computed once only, using the user provided
# block (or a dummy block if the pointer is anonymous).
attr_reader :lvalue
# The Proc object that can get the value of the lvalue (Pointer's content)
attr_reader :getter
# The Proc object that can set the value of the lvalue (Pointer's content).
attr_reader :setter
# This is the value holder for anonymous pointers. It is useless when
# the user provides a block at object creation time.
attr :value
# Creates a new Pointer. If provided, block parameter must
# return a lvalue as a string, or anything that can to_s().
# If no block then the created Pointer is _anonymous_.
# If the init parameter is provided, instead of a block then
# an anonymous Pointer is created with that initial value.
def initialize( init = nil, &block )
ref( init, &block)
end
# Reinitializes a Pointer.
# Sets the lvalue we are referencing/pointing to.
# If none, then this is an anonymous pointer that holds the value itself.
# init parameter is the initial value of the anonymous pointer, unless it is
# a Pointer. When init parameter is a Pointer, This Pointer is made a copy
# of the init Pointer.
# Returns self.
def ref( init = nil, &lvalue_block )
# Regular pointer, using a lvalue
if lvalue_block then
@block = lvalue_block
# Compute the lvalueExpr string/symbol, once only
@lvalue = lvalue_block.call()
# Compile getter & setter
@getter = eval( "proc { #{@lvalue} }", block)
@setter = eval( "proc { |v| #{@lvalue} = v }", block)
# ToDo: Avoid evil eval, but how ?
# Copy constructor, called by initialize_copy()
elsif init.kind_of? self.class() then
@block = init.binding()
@lvalue = init.lvalue()
@getter = init.getter()
@setter = init.getter()
@value = init[] if init.anonymous?
# Anonymous pointer
else
@lvalue = "self"
@getter = proc { @value }
@setter = proc { |v| @value = v }
# For anonymous pointers, @ptrBlock == @ptrGetter, see anonymous?()
@block = @getter
@value = init
end
self
end
# Magical deref!(). Change This object into its content.
# Whatever used to point on This object will now point
# on (a clone of) the content object. Also, whatever used to
# point on the content object, nows points on a clone of This Pointer.
# ToDo: Test that using evil.rubyforge.net
# Here I use swap(), which is not part of Ruby (yet). One
# version is available at http://evil.rubyforge.net
# Up
def deref!
# Deal with potential instance variables in subclasses
super
# Self becomes the original content, weird isn't it ?
content = @getter.call()
swap( content)
# Cloned LogicPointer will point on This
content[] = self
rescue NoMethodError
# Humm... if I can't swap()... then I don't
super
end
# New 1.8 initializer called by dup() and clone()
def initialize_copy proto
ref proto
end
# Tells if This Pointer is anonymous. An anonymous pointer stores its
# content. Non anomymous pointer's content is usually stored in some
# lvalue.
def anonymous?
# See code in ref() where @ptrBlock is assigned
@block == @getter
end
# Returns the content of the pointer.
def []
@getter.call()
end
# Assigns a new value to the content of This Pointer.
def []= new_value
@setter.call( new_value)
end
# Returns the Binding context where the lvalue lives.
# For anonymous pointers, returns a Binding where "self" is the
# anonymous pointer itself.
def binding()
eval( "binding()", @block)
end
# Reset the lvalue of This Pointer so that it now points
# to something new. The block parameter should return the
# lvalue as a string or as a symbol or anything that can to_s().
# Returns self.
# Note: eval( ptr.lvalue(), ptr.binding()) returns the content of ptr.
# This is much less efficient then a plain ptr[] of course.
def lvalue= &block
ref( nil, &block)
end
# Returns the lvalue expression as a string together with the Pointer
# content's inspect().
def inspect()
"<#{self.class()} #{lvalue()}>#{self[].inspect()}"
end
end
|
|
PAGE PRECEDENTE PAGE PRECEDENTE PAGE PRECEDENTE PAGE PRECEDENTE PAGE PRECEDENTE PAGE PRECEDENTE |