Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
# Ripped out of ActiveSupport 2.3.8 and modified.
# MIT LICENSE
# Copyright (c) 2005-2012 David Heinemeier Hansson
# Copyright (c) 2012 Zencoder
#
# Allow inheritable class attributes, but marshal/unmarshal the value when it is
# inherited to prevent object modifications from being passed onto children.
# With ActiveSupport's class_attribute, objects that are modified via accessing
# them will be passed on to all child classes. Only assignment to a class
# attribute will cause the child to have a different value than the parent.
#
# Example with ActiveSupport's class_attribute:
#
# class Foo
# class_attribute :settings
# self.settings = {:some => "thing"}
# end
#
# class Bar < Foo
# self.settings[:some] = "thing else"
# end
#
# Foo.settings # => {:some => "thing else"}
# Bar.settings = {:some => "other thing"}
# Foo.settings # => {:some => "thing else"}
# Bar.settings # => {:some => "other thing"}
# Example with marshaled class_attribute:
#
# class Foo
# extend MarshaledClassAttribute
# marshaled_class_attribute :settings
# self.settings = {:some => "thing"}
# end
#
# class Bar < Foo
# self.settings[:some] = "thing else"
# end
#
# Foo.settings # => {:some => "thing"}
# Bar.settings # => {:some => "thing else"}
#
module MarshaledClassAttribute
def marshaled_class_attribute(*attrs)
options = attrs.last.is_a?(Hash) ? attrs.pop : {}
instance_reader = options.fetch(:instance_reader, true)
instance_writer = options.fetch(:instance_writer, true)
attrs.each do |name|
class_eval <<-RUBY, __FILE__, __LINE__ + 1
def self.#{name}() nil end
def self.#{name}?() !!#{name} end
def self.#{name}=(val)
@#{name} = val
(class << self; self; end).class_eval do
if method_defined?(:#{name}) || private_method_defined?(:#{name})
begin
remove_method(:#{name})
rescue NameError
end
end
define_method(:#{name}) do
if defined?(@#{name})
@#{name}
else
@#{name} = Marshal.load(Marshal.dump(val))
end
end
end
if ancestors.first != self
class_eval do
if method_defined?(:#{name}) || private_method_defined?(:#{name})
begin
remove_method(:#{name})
rescue NameError
end
end
def #{name}
if defined?(@#{name})
@#{name}
else
@#{name} = Marshal.load(Marshal.dump((class << self; self; end).#{name}))
end
end
end
end
val
end
if instance_reader
if method_defined?(:#{name}) || private_method_defined?(:#{name})
begin
remove_method(:#{name})
rescue NameError
end
end
def #{name}
if defined?(@#{name})
@#{name}
else
@#{name} = Marshal.load(Marshal.dump(self.class.#{name}))
end
end
def #{name}?
!!#{name}
end
end
RUBY
attr_writer name if instance_writer
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.