Skip to content

Instantly share code, notes, and snippets.

@wojtekmach
Created July 8, 2012 09:37
Show Gist options
  • Save wojtekmach/3070184 to your computer and use it in GitHub Desktop.
Save wojtekmach/3070184 to your computer and use it in GitHub Desktop.
ActiveModel::ValueObject
class Address
include ActiveModel::ValueObject
attribute :street
attribute :city
end
class User < ActiveRecord::Base
attr_accessible :address
serialize :address, Address
def address=(new_address)
super Address(new_address)
end
end
class Venue < ActiveRecord::Base
attr_accessible :address
serialize :address, Address
def address=(new_address)
super Address(new_address)
end
end
user = User.new address: {city: 'NYC', street: '5th Ave'}
user.address.street # => "5th Ave"
user.address.city = 'LA' # Raises RuntimeError because object is frozen
venue = Venue.new
venue.address = Address.new city: 'NYC', street: 'Madison Ave'
user.address == venue.address # => false
venue.address = Address.new city: 'NYC', street: '5th Ave'
user.address == venue.address # => true
module ActiveModel
module ValueObject
def self.included(base)
base.class_eval do
include ActiveModel::Model
extend ClassMethods
include InstanceMethods
end
Kernel.send :define_method, base.name do |params|
base.new(base === params ? params.attributes : params)
end
end
module ClassMethods
def load(data)
new JSON.load(data)
end
def dump(object)
JSON.dump object.attributes
end
def attributes
@attributes ||= []
end
def attribute(name)
attributes << name
attr_accessor name
end
end
module InstanceMethods
def initialize(params = {})
super
@attributes = self.class.attributes.each_with_object({}) { |attr, hash|
hash[attr] = send(attr)
}
freeze
end
end
attr_reader :attributes
def to_s
attrs_str = attributes.map { |attr, val| "#{attr}: #{val.inspect}"}.join(', ')
"#{self.class.name}(#{attrs_str})"
end
def ==(other)
attributes == other.attributes
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment