##################################################
# Filename:	libMarshalable.rb
# Author:	David Ljung Madison Stellar <DaveSource.com>
# See License:	http://MarginalHacks.com/License/
#
# Marshal.dump support with exclusion ability
#
# Ruby has builtin object marshalling support, but it can't
# dump certain things, like IO/file pointers, singletons, etc..
#
# Any object that inherits this can exclude instance variables that
# shouldn't be marshalled using 'marshal_exclude' (similar to attr_accessor)
#
# Example:
#		class Joe < Marshalable
#			marshal_exclude :log
#			def initialize
#				@log = File.open("/tmp/foo")  # We can't marshal this
#				@name = "Joseph"              # This will be marshalled
#			end
#		end
#
# Based off anser by photoionized:
#		https://stackoverflow.com/questions/32876672/how-to-exclude-an-instance-variable-from-marshal-dump
#
##################################################
class Marshalable
	# Add items to the *class* variable "marshal_exclude"
	# (Each class that inherits Marshalable will have it's own list)
	def self.marshal_exclude(*names)
		@marshal_exclude ||= []
		names.map { |name| @marshal_exclude.push("@#{name}".to_sym) }
	end

	# Access to the *class* variable "marshal_exclude"
	def self.get_marshal_exclude
		@marshal_exclude || []
	end

	# When Marshal.dump is called, it will see this
	# and dump this data structure instead.  We'll make
	# a hash of instance vars to each value, excluding 'marshal_exclude'
  def marshal_dump
		exclude = self.class.get_marshal_exclude
		# Create a 'vars' hash that contains the value
		# of all 
    instance_variables.reject { |instvar|
			exclude.include? instvar
		}.inject({}) do |vars, attr|
      vars[attr] = instance_variable_get(attr)
      vars
    end
  end

  def marshal_load(vars)
    vars.each do |attr, value|
      instance_variable_set(attr, value)
    end
  end
end
