Мариян обнови решението на 01.12.2016 17:16 (преди около 8 години)
+module DynamicMethods
+ private
+ def make_getter(attributes)
+ (attributes << :id).each do |name|
+ define_method name do
+ @hash.fetch(name)
+ end
+ end
+ end
+
+ def make_setter(attributes)
+ attributes.each do |name|
+ define_method "#{name}=" do |value|
+ @hash[name] = value
+ end
+ end
+ end
+
+ def make_find_by_attribute(attributes)
+ (attributes << :id).each do |name|
+ define_singleton_method "find_by_#{name}" do |value|
+ where({name => value})
+ end
+ end
+ end
+end
+
+module SingletonMethods
+ def attributes(*attributes_given)
+ unless attributes_given.empty?
+ @attributes = Array.new(attributes_given)
+ make_getter(@attributes.dup)
+ make_setter(@attributes)
+ make_find_by_attribute(@attributes.dup)
+ end
+ @attributes.dup
+ end
+
+ def data_store(data_store = nil)
+ @storage = data_store unless data_store.nil?
+ @storage.dup
+ end
+
+ private
+ def make_array_of_found_records(records)
+ records.map do |record|
+ object = self.new
+ object.instance_variable_set(:@hash, record)
+ object
+ end
+ end
+end
+
+class DataModel
+ extend DynamicMethods
+ extend SingletonMethods
+
+ class UnknownAttributeError < StandardError
+ end
+ class DeleteUnsavedRecordError < StandardError
+ end
+
+ def initialize(hash = {})
+ @hash = {id: nil}
+ self.class.attributes.each do |item|
+ @hash[item] = hash[item]
+ end
+ end
+
+ def save(hash = @hash)
+ if id.nil? && hash == @hash
+ self.class.data_store.create(@hash)
+ elsif !self.class.data_store.find(@hash).empty? && @hash != hash
+ self.class.data_store.update(id, hash)
+ else
+ self.class.data_store.create(@hash)
+ self.class.data_store.update(id, hash)
+ end
+ self.dup
+ end
+
+ def ==(other)
+ other.is_a?(self.class) &&
+ self.id == other.id ||
+ self.equal?(other)
+ end
+
+ def delete
+ raise DeleteUnsavedRecordError.new if id.nil?
+ self.class.data_store.delete(@hash)
+ end
+
+ def self.where(search)
+ if search.keys.all? { |key| attributes.include?(key) }
+ make_array_of_found_records(data_store.find(search))
+ else
+ unknown_attributes = search.keys.select { |key| !attributes.include?(key) }
+ raise UnknownAttributeError.new, "Unknown attribute #{unknown_attributes.first}"
+ end
+ end
+end
+
+class HashStore
+ def initialize
+ @records = {}
+ end
+
+ def create(hash)
+ if hash.fetch(:id).nil?
+ id = ID.next
+ hash[:id] = id
+ end
+ @records[id] = hash
+ end
+
+ def find(hash)
+ @records.values.select do |value|
+ hash.keys.all? do |key|
+ value.key?(key) &&
+ value.fetch(key) == hash.fetch(key)
+ end
+ end
+ end
+
+ def update(id, hash)
+ hash.each_key { |key| @records[id][key] = hash[key] }
+ end
+
+ def delete(hash)
+ @records.delete(hash.fetch(:id))
+ end
+
+ def storage
+ @records.dup
+ end
+ private
+ ID = (1...Float::INFINITY).to_enum
+end
+
+class ArrayStore
+ def initialize
+ @records = []
+ end
+
+ def create(hash)
+ hash[:id] = ID.next if hash.fetch(:id).nil?
+ @records.push(hash)
+ end
+
+ def find(hash)
+ @records.select do |value|
+ hash.keys.all? do |key|
+ value.key?(key) &&
+ value.fetch(key) == hash.fetch(key)
+ end
+ end
+ end
+
+ def update(id, hash)
+ current_object = @records.select { |item| item.fetch(:id) == id }
+ hash.each_key { |key| current_object.first[key] = hash[key] }
+ end
+
+ def delete(hash)
+ @records.delete(hash)
+ end
+
+ def storage
+ @records.dup
+ end
+ private
+ ID = (1...Float::INFINITY).to_enum
+end