Решение на Пета задача - DataModel от Светослав Годжев

Обратно към всички решения

Към профила на Светослав Годжев

Резултати

  • 5 точки от тестове
  • 0 бонус точки
  • 5 точки общо
  • 21 успешни тест(а)
  • 4 неуспешни тест(а)

Код

module DataModelClassMethods
def data_store(store = nil)
if store == nil
@data_store
else
@data_store = store
end
end
def attributes(*args)
if args.empty?
@attributes
else
@attributes = [] if @attributes == nil
args.each do |attr_name|
@attributes << attr_name
generate_methods(attr_name)
end
end
end
def where(query = {})
query.each do |attr_name, _|
unless @attributes.include?(attr_name)
raise DataModel::UnknownAttributeError, "Unknown attribute #{attr_name}"
end
end
where_helper(query)
end
private
def generate_methods(attr_name)
attr_accessor attr_name
finder_method = ('find_by_' + attr_name.to_s).to_sym
define_singleton_method finder_method do |attr_value|
where({attr_name => attr_value})
end
end
def where_helper(query)
result = []
@data_store.find(query).each do |record|
object = self.new
record.each do |attr_name, attr_value|
assign = attr_name.to_s.insert(0, '@').to_sym
object.instance_variable_set(assign, attr_value)
end
result << object
end
result
end
end
class DataModel
extend DataModelClassMethods
class DeleteUnsavedRecordError < RuntimeError; end
class UnknownAttributeError < RuntimeError; end
attr_reader :id
def initialize(initial_values = {})
@id = nil
initial_values.each do |attr_name, attr_value|
assign = attr_name.to_s.insert(0, '@').to_sym
if self.class.attributes.include? attr_name
self.instance_variable_set(assign, attr_value)
end
end
end
def save
query = {}
self.class.attributes.each { |attr_name| query[attr_name] = self.send(attr_name) }
if @id == nil
@id = self.class.data_store.current_id
query[:id] = @id
self.class.data_store.create(query)
else
self.class.data_store.update(@id, query)
end
self
end
def delete
if @id == nil
raise DataModel::DeleteUnsavedRecordError.new
else
self.class.data_store.delete({id: @id})
@id = nil
end
self
end
def ==(other)
if self.class == other.class
if self.id != nil && self.id == other.id
return true
elsif self.object_id == other.object_id
return true
end
end
false
end
end
class ArrayStore
attr_reader :storage, :current_id
def initialize
@storage = []
@current_id = 1
end
def create(record)
@current_id += 1
@storage << record
end
def find(query)
result = []
@storage.each do |record|
result << record if query.all? { |key, _| query[key] == record[key] }
end
result
end
def update(id, new_attributes)
@storage.each do |record|
if record[:id] == id
new_attributes.each { |key, value| record[key] = value }
end
end
end
def delete(query)
@storage.each do |record|
@storage.delete(record) if query.all? { |key, _| query[key] == record[key] }
end
end
end
class HashStore
attr_reader :storage, :current_id
def initialize
@storage = {}
@current_id = 1
end
def create(record)
@current_id += 1
@storage[record[:id]] = record
end
def find(query)
result = []
@storage.each do |_, record|
result << record if query.all? { |key, _| query[key] == record[key] }
end
result
end
def update(id, new_attributes)
@storage.each do |_, record|
if record[:id] == id
new_attributes.each { |key, value| record[key] = value }
end
end
end
def delete(query)
@storage.each do |_, record|
@storage.delete(record) if query.all? { |key, _| query[key] == record[key] }
end
end
end

Лог от изпълнението

.......F.....F.....F....F

Failures:

  1) DataModel equality comparison compares by id if both records are saved
     Failure/Error: modified_ivan = user_model.where(id: ivan.id).first
     DataModel::UnknownAttributeError:
       Unknown attribute id
     # /tmp/d20161202-15620-1uinayg/solution.rb:25:in `block in where'
     # /tmp/d20161202-15620-1uinayg/solution.rb:23:in `each'
     # /tmp/d20161202-15620-1uinayg/solution.rb:23:in `where'
     # /tmp/d20161202-15620-1uinayg/spec.rb:102:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:7:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:7:in `block (2 levels) in <top (required)>'

  2) DataModel#delete deletes only the record for which it is called
     Failure/Error: expect(all_records).to match_array ['Petar', 'Georgi']
       expected collection contained:  ["Georgi", "Petar"]
       actual collection contained:    ["Georgi", "Ivan", "Petar"]
       the extra elements were:        ["Ivan"]
     # /tmp/d20161202-15620-1uinayg/spec.rb:159:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:7:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:7:in `block (2 levels) in <top (required)>'

  3) HashStore behaves like a data store #delete can delete multiple records with a single query
     Failure/Error: expect(store.find({})).to eq [gosho]
       
       expected: [{:id=>3, :name=>"Gosho"}]
            got: [{:id=>1, :name=>"Pesho"}, {:id=>2, :name=>"Pesho"}, {:id=>3, :name=>"Gosho"}]
       
       (compared using ==)
       
       Diff:
       @@ -1,2 +1,2 @@
       -[{:id=>3, :name=>"Gosho"}]
       +[{:id=>1, :name=>"Pesho"}, {:id=>2, :name=>"Pesho"}, {:id=>3, :name=>"Gosho"}]
     Shared Example Group: "a data store" called from /tmp/d20161202-15620-1uinayg/spec.rb:235
     # /tmp/d20161202-15620-1uinayg/spec.rb:229:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:7:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:7:in `block (2 levels) in <top (required)>'

  4) ArrayStore behaves like a data store #delete can delete multiple records with a single query
     Failure/Error: expect(store.find({})).to eq [gosho]
       
       expected: [{:id=>3, :name=>"Gosho"}]
            got: [{:id=>2, :name=>"Pesho"}, {:id=>3, :name=>"Gosho"}]
       
       (compared using ==)
       
       Diff:
       @@ -1,2 +1,2 @@
       -[{:id=>3, :name=>"Gosho"}]
       +[{:id=>2, :name=>"Pesho"}, {:id=>3, :name=>"Gosho"}]
     Shared Example Group: "a data store" called from /tmp/d20161202-15620-1uinayg/spec.rb:239
     # /tmp/d20161202-15620-1uinayg/spec.rb:229:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:7:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:7:in `block (2 levels) in <top (required)>'

Finished in 0.02556 seconds
25 examples, 4 failures

Failed examples:

rspec /tmp/d20161202-15620-1uinayg/spec.rb:92 # DataModel equality comparison compares by id if both records are saved
rspec /tmp/d20161202-15620-1uinayg/spec.rb:151 # DataModel#delete deletes only the record for which it is called
rspec /tmp/d20161202-15620-1uinayg/spec.rb:218 # HashStore behaves like a data store #delete can delete multiple records with a single query
rspec /tmp/d20161202-15620-1uinayg/spec.rb:218 # ArrayStore behaves like a data store #delete can delete multiple records with a single query

История (1 версия и 0 коментара)

Светослав обнови решението на 01.12.2016 22:42 (преди около 8 години)

+module DataModelClassMethods
+ def data_store(store = nil)
+ if store == nil
+ @data_store
+ else
+ @data_store = store
+ end
+ end
+
+ def attributes(*args)
+ if args.empty?
+ @attributes
+ else
+ @attributes = [] if @attributes == nil
+ args.each do |attr_name|
+ @attributes << attr_name
+ generate_methods(attr_name)
+ end
+ end
+ end
+
+ def where(query = {})
+ query.each do |attr_name, _|
+ unless @attributes.include?(attr_name)
+ raise DataModel::UnknownAttributeError, "Unknown attribute #{attr_name}"
+ end
+ end
+ where_helper(query)
+ end
+
+ private
+
+ def generate_methods(attr_name)
+ attr_accessor attr_name
+ finder_method = ('find_by_' + attr_name.to_s).to_sym
+ define_singleton_method finder_method do |attr_value|
+ where({attr_name => attr_value})
+ end
+ end
+
+ def where_helper(query)
+ result = []
+ @data_store.find(query).each do |record|
+ object = self.new
+ record.each do |attr_name, attr_value|
+ assign = attr_name.to_s.insert(0, '@').to_sym
+ object.instance_variable_set(assign, attr_value)
+ end
+ result << object
+ end
+ result
+ end
+end
+
+class DataModel
+ extend DataModelClassMethods
+ class DeleteUnsavedRecordError < RuntimeError; end
+ class UnknownAttributeError < RuntimeError; end
+
+ attr_reader :id
+
+ def initialize(initial_values = {})
+ @id = nil
+ initial_values.each do |attr_name, attr_value|
+ assign = attr_name.to_s.insert(0, '@').to_sym
+ if self.class.attributes.include? attr_name
+ self.instance_variable_set(assign, attr_value)
+ end
+ end
+ end
+
+ def save
+ query = {}
+ self.class.attributes.each { |attr_name| query[attr_name] = self.send(attr_name) }
+ if @id == nil
+ @id = self.class.data_store.current_id
+ query[:id] = @id
+ self.class.data_store.create(query)
+ else
+ self.class.data_store.update(@id, query)
+ end
+ self
+ end
+
+ def delete
+ if @id == nil
+ raise DataModel::DeleteUnsavedRecordError.new
+ else
+ self.class.data_store.delete({id: @id})
+ @id = nil
+ end
+ self
+ end
+
+ def ==(other)
+ if self.class == other.class
+ if self.id != nil && self.id == other.id
+ return true
+ elsif self.object_id == other.object_id
+ return true
+ end
+ end
+ false
+ end
+end
+
+class ArrayStore
+ attr_reader :storage, :current_id
+
+ def initialize
+ @storage = []
+ @current_id = 1
+ end
+
+ def create(record)
+ @current_id += 1
+ @storage << record
+ end
+
+ def find(query)
+ result = []
+ @storage.each do |record|
+ result << record if query.all? { |key, _| query[key] == record[key] }
+ end
+ result
+ end
+
+ def update(id, new_attributes)
+ @storage.each do |record|
+ if record[:id] == id
+ new_attributes.each { |key, value| record[key] = value }
+ end
+ end
+ end
+
+ def delete(query)
+ @storage.each do |record|
+ @storage.delete(record) if query.all? { |key, _| query[key] == record[key] }
+ end
+ end
+end
+
+class HashStore
+ attr_reader :storage, :current_id
+
+ def initialize
+ @storage = {}
+ @current_id = 1
+ end
+
+ def create(record)
+ @current_id += 1
+ @storage[record[:id]] = record
+ end
+
+ def find(query)
+ result = []
+ @storage.each do |_, record|
+ result << record if query.all? { |key, _| query[key] == record[key] }
+ end
+ result
+ end
+
+ def update(id, new_attributes)
+ @storage.each do |_, record|
+ if record[:id] == id
+ new_attributes.each { |key, value| record[key] = value }
+ end
+ end
+ end
+
+ def delete(query)
+ @storage.each do |_, record|
+ @storage.delete(record) if query.all? { |key, _| query[key] == record[key] }
+ end
+ end
+end