Решение на Пета задача - DataModel от Петър Скорчелиев

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

Към профила на Петър Скорчелиев

Резултати

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

Код

class Hash
def satisfy?(request)
request.all? do |key, value|
self[key] == value
end
end
end
class ArrayStore
def initialize
@storage = []
end
def create(record)
@storage.push(record)
end
def find(request)
@storage.select { |hash| hash.satisfy?(request) }
end
def update(id, new_attributes)
updated_index = @storage.find_index { |hash| hash.satisfy?({id: id}) }
@storage[updated_index].merge!(new_attributes) unless updated_index.nil?
end
def delete(request)
@storage.delete_if { |hash| hash.satisfy?(request) }
end
end
class HashStore
def initialize
@storage = {}
end
def create(record)
@storage[record[:id]] = record
end
def find(request)
@storage.values.select { |hash| hash.satisfy?(request) }
end
def update(id, new_attributes)
@storage[id].merge!(new_attributes) if @storage.key?(id)
end
def delete(request)
@storage.delete_if { |_id, hash| hash.satisfy?(request) }
end
end
class DataModel
class << self
attr_accessor :store, :free_id
attr_reader :attributes_list
end
def self.attributes(*attributes_names)
if attributes_names.empty?
@attributes_list.map { |attribute| attribute.to_sym }
else
@free_id = 1
@attributes_list = attributes_names + [:id]
create_accessors_and_finder
end
end
def self.data_store(store_object = nil)
@store = store_object unless store_object.nil?
@store
end
def self.where(request)
@store.find(request).map { |hash| self.new(hash) }
end
def self.create_accessors_and_finder
@attributes_list.each do |key|
define_method (key) { @attributes_hash[key] }
define_method ("#{key}=".to_sym) { |value| @attributes_hash[key] = value }
finder = "find_by_#{key}".to_sym
define_singleton_method (finder) { |value| @store.find({key => value}) }
end
end
def initialize(attributes_values = {})
@attributes_hash = {}
self.class.attributes_list.each do |attribute|
@attributes_hash[attribute] = attributes_values[attribute]
end
end
def save
if id.nil?
self.id = self.class.free_id
self.class.free_id = self.class.free_id + 1
self.class.store.create(@attributes_hash)
else
self.class.store.update(id, @attributes_hash)
end
end
def delete
self.class.store.delete({id: id}) unless self.class.store.nil? || id.nil?
end
def ==(other)
self.equal?(other) || (self.class == other.class && id != nil && id == other.id)
end
end

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

...F..F.....FFF..........

Failures:

  1) DataModel has #find_by_<attribute> methods
     Failure/Error: expect(user_model.find_by_first_name('Ivan').map(&:id)).to eq [record.id]
     NoMethodError:
       undefined method `id' for {:first_name=>"Ivan", :last_name=>"Ivanov", :age=>nil, :id=>1}:Hash
     # /tmp/d20161202-15620-yz0xdt/spec.rb:43:in `map'
     # /tmp/d20161202-15620-yz0xdt/spec.rb:43:in `block (2 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 id generation does not break when there are two models with the same store
     Failure/Error: expect(picture.id).to eq 2
       
       expected: 2
            got: 1
       
       (compared using ==)
     # /tmp/d20161202-15620-yz0xdt/spec.rb:87: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) DataModel.where raises an error if the query is by an unknown key
     Failure/Error: DataModel::UnknownAttributeError,
     NameError:
       uninitialized constant DataModel::UnknownAttributeError
     # /tmp/d20161202-15620-yz0xdt/spec.rb:144: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) DataModel#delete deletes only the record for which it is called
     Failure/Error: ivan.delete
     ArgumentError:
       wrong number of arguments (given 0, expected 1)
     # /tmp/d20161202-15620-yz0xdt/spec.rb:156:in `delete'
     # /tmp/d20161202-15620-yz0xdt/spec.rb:156: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)>'

  5) DataModel#delete raises an error if the record is not saved
     Failure/Error: DataModel::DeleteUnsavedRecordError
     NameError:
       uninitialized constant DataModel::DeleteUnsavedRecordError
     # /tmp/d20161202-15620-yz0xdt/spec.rb:164: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.02327 seconds
25 examples, 5 failures

Failed examples:

rspec /tmp/d20161202-15620-yz0xdt/spec.rb:39 # DataModel has #find_by_<attribute> methods
rspec /tmp/d20161202-15620-yz0xdt/spec.rb:74 # DataModel id generation does not break when there are two models with the same store
rspec /tmp/d20161202-15620-yz0xdt/spec.rb:142 # DataModel.where raises an error if the query is by an unknown key
rspec /tmp/d20161202-15620-yz0xdt/spec.rb:151 # DataModel#delete deletes only the record for which it is called
rspec /tmp/d20161202-15620-yz0xdt/spec.rb:162 # DataModel#delete raises an error if the record is not saved

История (3 версии и 2 коментара)

Петър обнови решението на 30.11.2016 10:51 (преди над 7 години)

+class ArrayStore
+ @storage
+
+ def initialize
+ @storage = []
+ end
+
+ def create(record)
+ @storage.push(record)
+ end
+
+ def find(request)
+ @storage.select do |hash|
+ request.to_a.each do |pair|
+ hash.to_a.include?(pair)
+ end
+ end
+ end
+
+ def update(id_number, new_attributes)
+ updated_index = @storage.find { |hash| hash[:id] = id_number }
+ @storage[updated_index].merge!(new_attributes) unless updated_index.nil?
+ end
+
+ def delete(request)
+ @storage.delete_if do |hash|
+ request.to_a.each do |pair|
+ hash.to_a.include?(pair)
+ end
+ end
+ end
+
+ def id?(id)
+ @storage.any? { |hash| hash.to_a.include?([:id, id]) }
+ end
+end
+
+class HashStore
+ @storage
+
+ def initialize
+ @storage = {}
+ end
+
+ def create(record)
+ @storage[record[:id]] = record
+ end
+
+ def find(request)
+ @storage.values.select do |hash|
+ request.to_a.each do |pair|
+ hash.to_a.include?(pair)
+ end
+ end
+ end
+
+ def update(id_number, new_attributes)
+ # ...
+ end
+
+ def delete(request)
+ # ...
+ end
+end
+
+class DataModel
+ self.class.instance_variable_set(:@store, nil)
+ self.class.instance_variable_set(:@free_id, 1)
+ @attributes_hash
+ @id
+
+ def initialize(attributes_values = {})
+ @attributes_hash.each_key do |key|
+ @attributes_hash[key] = attributes_values[key]
+ end
+ @id = attributes_values[:id]
+ end
+
+ def save
+ unless @store.nil?
+ if id.nil?
+ id = @free_id
+ @free_id += 1
+ @store.create(attributes_hash.merge({id: id}))
+ else
+ @store.update(id, attributes_hash)
+ end
+ end
+ end
+
+ def delete
+ @store.delete({id: id}) unless @store.nil? || id.nil?
+ # Exception needed
+ end
+
+ def ==(other)
+ self.equal?(other) || (self.class == other.class && id.nil? && id == other.id)
+ end
+
+ def self.attributes(*attributes_names)
+ attributes_names.each do |attribute|
+ attributes_hash[attribute] = nil
+ end
+ create_accessors_and_finder
+ end
+
+ def self.data_store(store_object = nil)
+ @store = store_object unless store_object.nil?
+ @store
+ end
+
+ def self.where(request)
+ @store.find(request).map { |hash| self.class.new(hash) }
+ end
+
+ private
+
+ def create_accessors_and_finder
+ attributes_hash.each_key do |key|
+ define_method (key) { attributes_hash[key] }
+ define_method ("#{key}=".to_sym) { |value| attributes_hash[key] = value }
+ finder = "find_by_#{key}".to_sym
+ define_singleton_method (finder) { |value| @store.find({key => value}) }
+ end
+ end
+end

Петър обнови решението на 30.11.2016 12:17 (преди над 7 години)

+class Hash
+ def satisfy(request)
+ request.all? do |key, value|
+ self[key] == value
+ end
+ end
+end
+
class ArrayStore
@storage
def initialize
@storage = []
end
def create(record)
@storage.push(record)
end
def find(request)
- @storage.select do |hash|
- request.to_a.each do |pair|
- hash.to_a.include?(pair)
- end
- end
+ @storage.select { |hash| hash.satisfy(request) }
end
- def update(id_number, new_attributes)
- updated_index = @storage.find { |hash| hash[:id] = id_number }
+ def update(id, new_attributes)
+ updated_index = @storage.find_index { |hash| hash.satisfy({id: id}) }
@storage[updated_index].merge!(new_attributes) unless updated_index.nil?
end
def delete(request)
- @storage.delete_if do |hash|
- request.to_a.each do |pair|
- hash.to_a.include?(pair)
- end
- end
+ @storage.delete_if { |hash| hash.satisfy(request) }
end
-
- def id?(id)
- @storage.any? { |hash| hash.to_a.include?([:id, id]) }
- end
end
class HashStore
@storage
def initialize
@storage = {}
end
def create(record)
@storage[record[:id]] = record
end
def find(request)
- @storage.values.select do |hash|
- request.to_a.each do |pair|
- hash.to_a.include?(pair)
- end
- end
+ @storage.values.select { |hash| hash.satisfy(request) }
end
- def update(id_number, new_attributes)
- # ...
+ def update(id, new_attributes)
+ @storage[id].merge!(new_attributes) if @storage.key?(id)
end
def delete(request)
- # ...
+ @storage.delete_if { |_id, hash| hash.satisfy(request) }
end
end
class DataModel
self.class.instance_variable_set(:@store, nil)
self.class.instance_variable_set(:@free_id, 1)
@attributes_hash
@id

Първият създава класова инстанционна променлива, в която ще се пази информацията за инстанциите на класа-наследник на DataModel. Вторият създава друга такава променлива - за следващото id, което ще бъде използвано. Третият създава хеш, в който ще се пазят атрибутите на конкретната инстанция. Четвъртият е id-то на инстанцията (мисля, че е естествено това да е инстанционна променлива).

Не съм тествал този клас още, но ми се струва, че е ок да го напиша както съм тръгнал. Какво не е наред?

Може би трябва да декларирам тези променливи в initialize?

def initialize(attributes_values = {})
@attributes_hash.each_key do |key|
@attributes_hash[key] = attributes_values[key]
end
@id = attributes_values[:id]
end
def save
unless @store.nil?
if id.nil?
id = @free_id
@free_id += 1
@store.create(attributes_hash.merge({id: id}))
else
@store.update(id, attributes_hash)
end
end
end
def delete
@store.delete({id: id}) unless @store.nil? || id.nil?
# Exception needed
end
def ==(other)
self.equal?(other) || (self.class == other.class && id.nil? && id == other.id)
end
def self.attributes(*attributes_names)
attributes_names.each do |attribute|
attributes_hash[attribute] = nil
end
create_accessors_and_finder
end
def self.data_store(store_object = nil)
@store = store_object unless store_object.nil?
@store
end
def self.where(request)
@store.find(request).map { |hash| self.class.new(hash) }
end
private
def create_accessors_and_finder
attributes_hash.each_key do |key|
define_method (key) { attributes_hash[key] }
define_method ("#{key}=".to_sym) { |value| attributes_hash[key] = value }
finder = "find_by_#{key}".to_sym
define_singleton_method (finder) { |value| @store.find({key => value}) }
end
end
end

Петър обнови решението на 01.12.2016 23:29 (преди над 7 години)

class Hash
- def satisfy(request)
+ def satisfy?(request)
request.all? do |key, value|
self[key] == value
end
end
end
class ArrayStore
- @storage
-
def initialize
@storage = []
end
def create(record)
@storage.push(record)
end
def find(request)
- @storage.select { |hash| hash.satisfy(request) }
+ @storage.select { |hash| hash.satisfy?(request) }
end
def update(id, new_attributes)
- updated_index = @storage.find_index { |hash| hash.satisfy({id: id}) }
+ updated_index = @storage.find_index { |hash| hash.satisfy?({id: id}) }
@storage[updated_index].merge!(new_attributes) unless updated_index.nil?
end
def delete(request)
- @storage.delete_if { |hash| hash.satisfy(request) }
+ @storage.delete_if { |hash| hash.satisfy?(request) }
end
end
class HashStore
- @storage
-
def initialize
@storage = {}
end
def create(record)
@storage[record[:id]] = record
end
def find(request)
- @storage.values.select { |hash| hash.satisfy(request) }
+ @storage.values.select { |hash| hash.satisfy?(request) }
end
def update(id, new_attributes)
@storage[id].merge!(new_attributes) if @storage.key?(id)
end
def delete(request)
- @storage.delete_if { |_id, hash| hash.satisfy(request) }
+ @storage.delete_if { |_id, hash| hash.satisfy?(request) }
end
end
-class DataModel
- self.class.instance_variable_set(:@store, nil)
- self.class.instance_variable_set(:@free_id, 1)
- @attributes_hash
- @id
-
- def initialize(attributes_values = {})
- @attributes_hash.each_key do |key|
- @attributes_hash[key] = attributes_values[key]
- end
- @id = attributes_values[:id]
+class DataModel
+ class << self
+ attr_accessor :store, :free_id
+ attr_reader :attributes_list
end
-
- def save
- unless @store.nil?
- if id.nil?
- id = @free_id
- @free_id += 1
- @store.create(attributes_hash.merge({id: id}))
- else
- @store.update(id, attributes_hash)
- end
- end
- end
-
- def delete
- @store.delete({id: id}) unless @store.nil? || id.nil?
- # Exception needed
- end
-
- def ==(other)
- self.equal?(other) || (self.class == other.class && id.nil? && id == other.id)
- end
-
+
def self.attributes(*attributes_names)
- attributes_names.each do |attribute|
- attributes_hash[attribute] = nil
+ if attributes_names.empty?
+ @attributes_list.map { |attribute| attribute.to_sym }
+ else
+ @free_id = 1
+ @attributes_list = attributes_names + [:id]
+ create_accessors_and_finder
end
- create_accessors_and_finder
end
def self.data_store(store_object = nil)
@store = store_object unless store_object.nil?
@store
end
def self.where(request)
- @store.find(request).map { |hash| self.class.new(hash) }
+ @store.find(request).map { |hash| self.new(hash) }
end
-
- private
-
- def create_accessors_and_finder
- attributes_hash.each_key do |key|
- define_method (key) { attributes_hash[key] }
- define_method ("#{key}=".to_sym) { |value| attributes_hash[key] = value }
+
+ def self.create_accessors_and_finder
+ @attributes_list.each do |key|
+ define_method (key) { @attributes_hash[key] }
+ define_method ("#{key}=".to_sym) { |value| @attributes_hash[key] = value }
finder = "find_by_#{key}".to_sym
define_singleton_method (finder) { |value| @store.find({key => value}) }
end
+ end
+
+ def initialize(attributes_values = {})
+ @attributes_hash = {}
+ self.class.attributes_list.each do |attribute|
+ @attributes_hash[attribute] = attributes_values[attribute]
+ end
+ end
+
+ def save
+ if id.nil?
+ self.id = self.class.free_id
+ self.class.free_id = self.class.free_id + 1
+ self.class.store.create(@attributes_hash)
+ else
+ self.class.store.update(id, @attributes_hash)
+ end
+ end
+
+ def delete
+ self.class.store.delete({id: id}) unless self.class.store.nil? || id.nil?
+ end
+
+ def ==(other)
+ self.equal?(other) || (self.class == other.class && id != nil && id == other.id)
end
end