Теодор обнови решението на 01.12.2016 04:22 (преди около 8 години)
+module DataModelClassMethods
+ def where(a_pattern)
+ raise UnknownAttributeError unless a_pattern.all? do |key, _|
+ attributes.include? key
+ end
+ data_store.find(a_pattern).map do |h|
+ model = self.new h
+ model.id = h[:id]
+ model
+ end
+ end
+
+ def attributes(*a_attributes)
+ return @attributes if a_attributes.empty?
+ @attributes = a_attributes
+ generate_methods
+ end
+
+ def generate_methods
+ attributes.each do |attr|
+ define_method(attr.to_sym) { instance_variable_get("@#{attr}") }
+ define_method((attr.to_s + '=').to_sym) do |value|
+ instance_variable_set("@#{attr}", value)
+ end
+ define_singleton_method("find_by_#{attr}".to_sym) do |value|
+ where({attr.to_sym => value})
+ end
+ end
+ end
+
+ def data_store(a_store = @store)
+ @store = a_store
+ end
+end
+
+class DataModel
+ attr_accessor :id
+
+ extend DataModelClassMethods
+ def initialize(a_hash = {})
+ a_hash.select { |key, _| attributes.include? key }
+ .each { |key, value| send("#{key}=", value) }
+ end
+
+ def ==(model)
+ return false if model.id.nil? && id.nil? && (model.object_id != self.object_id)
+ return true if (model.instance_of? self.class) && (model.id == id)
+ false
+ end
+
+ def attributes
+ self.class.attributes
+ end
+
+ def data_store
+ self.class.data_store
+ end
+
+ def save
+ record_map = populate_record_map
+ if !storage_contains_id?(@id)
+ @id = data_store.create record_map
+ else
+ data_store.update @id, record_map
+ end
+ end
+
+ def delete
+ raise DataModel::DeleteUnsavedRecordError if @id.nil?
+ data_store.delete(populate_record_map)
+ end
+
+ private
+ def storage_contains_id?(id)
+ return true unless data_store.find({id: id}).empty?
+ false
+ end
+
+ def populate_record_map
+ map = {}
+ attributes.map { |attribute| map[attribute] = send(attribute.to_sym) }
+ map.delete(:attributes)
+ map.delete(:store)
+ map
+ end
+
+ class DeleteUnsavedRecordError < StandardError; end
+ class UnknownAttributeError < StandardError; end
+end
+
+class DataStore
+ def delete(a_pattern)
+ end
+
+ private
+
+ def record_matches_pattern?(a_record, a_pattern)
+ return false if a_record.nil?
+ a_record.select { |key, _| a_pattern.key? key }.eql? a_pattern
+ end
+
+ def create(a_record)
+ a_record[:id] = @id
+ storage[@id] = a_record
+ @id += 1
+ end
+
+ def find(a_pattern)
+ storage.select { |record| record_matches_pattern? record, a_pattern }
+ end
+
+ def update(a_id, a_record)
+ storage[a_id] = a_record
+ end
+end
+
+class ArrayStore < DataStore
+ def initialize
+ @array_store = []
+ @id = 1
+ end
+
+ def storage
+ @array_store
+ end
+
+ def create(a_record)
+ a_record[:id] = @id
+ @array_store[@id] = a_record
+ @id += 1
+ @id - 1
+ end
+
+ def find(a_pattern)
+ @array_store.select { |record| record_matches_pattern? record, a_pattern }
+ end
+
+ def update(a_id, a_record)
+ @array_store[a_id] = a_record
+ end
+
+ def delete(a_pattern)
+ @array_store.select { |record| record_matches_pattern? record, a_pattern }
+ .map { |record| record[:id] }.each { |id| @array_store[id] = nil }
+ end
+end
+
+class HashStore < DataStore
+ def initialize
+ @hash_store = {}
+ @id = 1
+ end
+
+ def storage
+ @hash_store
+ end
+
+ def create(a_record)
+ a_record[:id] = @id
+ @hash_store[@id] = a_record
+ @id += 1
+ @id - 1
+ end
+
+ def find(a_pattern)
+ @hash_store.select { |_, record| record_matches_pattern? record, a_pattern }
+ .map { |_, record| record }
+ end
+
+ def update(a_id, a_record)
+ @hash_store[a_id] = a_record
+ end
+
+ def delete(a_pattern)
+ @hash_store.select { |_, record| record_matches_pattern? record, a_pattern }
+ .map { |_, record| record[:id] }.each { |id| @hash_store.delete id }
+ end
+end