# = snapshot.rb # # == 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. # # == Author(s) # # * Michael Neumann # # == Developer Notes # # 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. # # TODO Convert to Kernel#to_data ? # Author:: Michael Neumann # Copyright:: Copyright (c) 2004 Michael Neumann # License:: Ruby License # = 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. 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 # Simplist form of a snapshot. # #module SnapshotMixin # 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 Snapshot::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 def take_snapshot() dup end def restore_snapshot(snap) replace(snap) end end class String def take_snapshot() dup end def restore_snapshot(snap) replace(snap) end end class Hash def take_snapshot() dup end def restore_snapshot(snap) replace(snap) end 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 # _____ _ # |_ _|__ ___| |_ # | |/ _ \/ __| __| # | | __/\__ \ |_ # |_|\___||___/\__| # =begin testing require 'test/unit' class TC_Snapshot < Test::Unit::TestCase def setup customer = Struct.new("Customer", :name, :address, :zip) joe = customer.new( "Joe Pitare", "1115 Lila Ln.", 47634 ) @joe_snap = joe.take_snapshot end def test_storage assert_equal( "Joe Pitare", @joe_snap[:name] ) assert_equal( "1115 Lila Ln.", @joe_snap[:address] ) assert_equal( 47634, @joe_snap[:zip] ) end end =end