Here is a naive attempt to create such a class. It seems to work fine for "basic" usage:
class AppendOnlyHash < Hash
def []=(key, value)
raise "APPEND ONLY!!" if keys.include?(key)
super
end
end
However, this certainly has some flaws.
Firstly, what happens if you call a destructive method on the object, which tries to delete some keys? Perhaps you could override all such methods - i.e. filter!
, keep_if
, delete
, compact!
, reject!
, select!
, transform_keys!
and transform_values!
. (Did I miss any?...)
Then, what to do with Hash#merge!
? I guess that could be handled specially too; since it's valid to use if the no keys are being redefined.
And lastly, how can you ensure that the "append-only" hash values are never mutated? Consider the following:
capitals = AppendOnlyHash.new
str = "paris"
capitals['france'] = str
str << " CHANGED"
You could call .freeze
on each value as it gets added to the hash, but even that's not 100% bulletproof - since the value may in turn be another Hash
, which is susceptible to the same behaviour.
So in summary, I think this is possible via my basic implementation above, but I'd be cautious of increasingly-complex edge cases caused by objected mutation in "weird ways".