#-- # Snapshot # # Copyright (c) 2004 Michael Neumann # # Ruby License # # This module is free software. You may use, modify, and/or redistribute this # software under the same terms as Ruby. # # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS # FOR A PARTICULAR PURPOSE. # # ========================================================================== # Revision History :: # -------------------------------------------------------------------------- # 2005.04.28 trans * Ported to mega Modules # ========================================================================== # # :TODO: Perhaps extend to offer multiple depths. # # :TODO: Should key consitancy be enforced? Currently # Struct's will have symobl keys while other classes # will have string keys in the form of "@name". # # :TODO: Add other core classes. # #++ ##:title: Snapshot # # A lightweight single-depth object state capture. # The #take_snapshot method reads the object's state, # which is generally it's collection of instance variables, # and returns them in a hash. The state can be restored # with #apply_snapshot. # # == Usage # # Customer = Struct.new("Customer", :name, :address, :zip) # joe = Customer.new( "Joe Pitare", "1115 Lila Ln.", 47634 ) # # # simple transactions # joe_snap = joe.take_snapshot # begin # do_something_with( joe ) # rescue # joe.apply_snapshot( joe_snap ) # end # # joe_snap[:name] => "Joe Pitare" # joe_snap[:address] => "1115 Lila Ln." # joe_snap[:zip] => 47634 # # == Details # # Class Snapshot simply represents a collection of objects from # which snapshots were taken via their methods #take_snapshot. # It provides methods to add an object to a snapshot # (Snapshot#add) as well as to restore all objects # of the snapshot to their state stored in the snapshot (method # Snapshot#restore). # # In Wee, this class is used to backtracking the state of # components (or decorations/presenters). Components that want # an undo-facility to be implemented (triggered for example by # a browsers back-button), have to overwrite the # Wee::Component#backtrack_state method. # # == Author(s) # # * Michael Neumann # class Snapshot def initialize @objects = Hash.new end def add(object) oid = object.object_id @objects[oid] = [object, object.take_snapshot] unless @objects.include?(oid) end def restore @objects.each_value { |object, value| object.restore_snapshot(value) } end end module DupReplaceSnapshotMixin def take_snapshot dup end def restore_snapshot(snap) replace(snap) end end # Implements a value holder. In Wee this is useful for # backtracking the reference assigned to an instance variable # (not the object itself!). An example where this is used is the # @__decoration attribute of class Wee::Component. class ValueHolder attr_accessor :value def initialize(value=nil) @value = value end def take_snapshot @value end def restore_snapshot(value) @value = value end end #-- # Extend some base classes of Ruby (Object, Array, String, Hash, # Struct) for the two methods #take_snapshot and # #restore_snapshot, required by Snapshot. #++ class Object def take_snapshot snap = Hash.new instance_variables.each do |iv| snap[iv] = instance_variable_get(iv) end snap end def restore_snapshot(snap) instance_variables.each do |iv| instance_variable_set(iv, snap[iv]) end end end class Array ; include DupReplaceSnapshotMixin ; end class String ; include DupReplaceSnapshotMixin ; end class Hash ; include DupReplaceSnapshotMixin ; end class Struct def take_snapshot snap = Hash.new each_pair {|k,v| snap[k] = v} snap end def restore_snapshot(snap) snap.each_pair {|k,v| send(k.to_s + "=", v)} end end