Skip to content

Instantly share code, notes, and snippets.

@7even
Created October 23, 2011 14:44
Show Gist options
  • Save 7even/1307430 to your computer and use it in GitHub Desktop.
Save 7even/1307430 to your computer and use it in GitHub Desktop.
Struct instantiated with a hash
Kernel.module_eval do
def HashStruct(*attributes)
Class.new do
# keeping keys array in class
@keys = attributes.map(&:to_sym)
class << self
attr_reader :keys
end
# passing keys to the child class if inherited
define_singleton_method :inherited do |child|
child.instance_variable_set :@keys, attributes.map(&:to_sym)
end
# accesors for all attributes
attr_accessor *attributes
# constructor that takes a hash of values
# absent keys are filled with nil values
# extra keys raise an ArgumentError
def initialize(hash)
# uncommenting this line allows to pass a hash with String keys to Klass.new
# but requires ActiveSupport::HashWithIndifferentAccess
# hash = hash.with_indifferent_access
self.class.keys.each do |attr_name|
var_name = "@#{attr_name}"
var_value = hash.delete(attr_name)
instance_variable_set(var_name, var_value)
end
raise ArgumentError, "Attributes #{hash.keys.inspect} unknown" unless hash.empty?
end
end
end
end
User = HashStruct(:name, :email)
puts "User class has keys: #{User.keys}"
u1 = User.new(name: 'Vasya', email: '[email protected]')
puts "name: '#{u1.name}', email: '#{u1.email}'"
u2 = User.new(name: 'ololo')
puts "name: '#{u2.name}', email: '#{u2.email}'"
begin
u3 = User.new(name: 'trololo', avatar: 'trollface.jpg')
rescue ArgumentError => e
puts "ArgumentError: '#{e}'"
end
class Book < HashStruct(:name, :author)
end
b1 = Book.new(name: 'The Lord of the Rings', author: 'JRRT')
puts "name: '#{b1.name}', author: '#{b1.author}'"
b2 = Book.new(author: 'Petya')
puts "name: '#{b2.name}', author: '#{b2.author}'"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment