Skip to content

Instantly share code, notes, and snippets.

@lucaong
Last active August 29, 2015 13:56
Show Gist options
  • Save lucaong/9211580 to your computer and use it in GitHub Desktop.
Save lucaong/9211580 to your computer and use it in GitHub Desktop.
ClosedStruct

ClosedStruct

A stupidly simple implementation of a kind of "sorta immutable" struct that can be instantiated as conveniently as an OpenStruct but after instantiation it doesn't let me (easily) add fields or mutate them:

guy = ClosedStruct.new( name: "John", age: 23 )

# readers:
guy.name             #=> "John"
guy.age              #=> 23
guy.xxx              #=> NoMethodError: undefined method `xxx'...

# respond_to? and methods work as expected:
guy.respond_to? :age #=> true
guy.methods(false)   #=> [:name, :age]

# in-place modification is prevented, but you can create modified copies with #merge:
guy.name = "Jack"      #=> NoMethodError: undefined method `name='...
guy.merge name: "Jack" #=> a new ClosedStruct instance with name: "Jack", age: 23
class ClosedStruct
def initialize( attr_hash )
@_field_names = attr_hash.keys.map(&:to_sym)
attr_hash.each do |attr_name, attr_value|
instance_variable_set :"@#{attr_name}", attr_value
eigenclass.send :attr_reader, attr_name.to_sym
end
end
def to_h
field_values = @_field_names.map { |field| send field }
Hash[ @_field_names.zip( field_values ) ]
end
def merge( modified_attrs = {} )
ClosedStruct.new to_h.merge( modified_attrs )
end
private
def eigenclass
class << self
self
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment