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

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

Към профила на Иван Станков

Резултати

  • 4 точки от тестове
  • 1 отнета точка
  • 3 точки общо
  • 17 успешни тест(а)
  • 8 неуспешни тест(а)

Код

class UnknownAttributeError < ArgumentError
end
class DataModel
class <<self
attr_accessor :keys
end
attr_reader :id
def self.attributes(*arguments)
@keys = arguments
arguments.each do |argument|
attr_accessor argument.to_s
define_singleton_method("find_by_#{argument}") do |value|
where(Hash[argument, value])
end
end
end
def self.find_by_id(id)
where(id: id)
end
def self.data_store(data_storage = nil)
@storage = data_storage if @storage.nil?
@storage
end
def self.where(**search)
unknown = (search.keys - @keys) - [:id]
unless unknown.empty?
raise UnknownAttributeError, "Unknown attribute #{unknown[0]}"
end
data_store.find(search)
end
def initialize(**hash)
@id = nil
hash.each do |key, value|
instance_variable_set("@" + key.to_s, value)
end
end
def save
if @id.nil?
@id = self.class.data_store.storage.length + 1
self.class.data_store.create(data_hash)
else
self.class.data_store.update(@id, data_hash)
@saved = true
end
end
def data_hash
hash = {id: @id}
self.class.keys.each { |variable| hash[variable] = send(variable.to_s) }
hash
end
def delete
self.class.data_store.delete(id: @id)
end
end
class DataStore
def storage
@storage = [] if @storage.nil?
@storage
end
def create(**record)
@storage = [] if @storage.nil?
@storage << record
end
def find(**query)
@storage.select { |data| query.select { |key, value| data[key] == value } == query }
end
def update(id, **attributes)
record = @storage.select { |element| element[:id] == id }[0]
attributes.map { |key, value| record[key] = value }
end
def delete(query)
@storage -= find(query)
end
end
class ArrayStore < DataStore
end
class HashStore < DataStore
def storage
@storage = [] if @storage.nil?
hash = {}
@storage.each { |item| hash[item[:id]] = item }
hash
end
end

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

.F.F.F.F.FF./tmp/d20161202-15620-b6vnzz/spec.rb:144: warning: toplevel constant UnknownAttributeError referenced by DataModel::UnknownAttributeError
.FF..........

Failures:

  1) DataModel has attributes and data_model getters
     Failure/Error: expect(user_model.attributes).to include :first_name
       expected [] to include :first_name
       Diff:
       @@ -1,2 +1,2 @@
       -[:first_name]
       +[]
     # /tmp/d20161202-15620-b6vnzz/spec.rb:22: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 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 {:id=>1, :first_name=>"Ivan", :last_name=>"Ivanov", :age=>nil}:Hash
     # /tmp/d20161202-15620-b6vnzz/spec.rb:43:in `map'
     # /tmp/d20161202-15620-b6vnzz/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)>'

  3) DataModel id generation does not reuse ids
     Failure/Error: expect(georgi.id).to eq 2
       
       expected: 2
            got: 1
       
       (compared using ==)
     # /tmp/d20161202-15620-b6vnzz/spec.rb:71: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 equality comparison compares by id if both records are saved
     Failure/Error: modified_ivan.first_name = 'Gosho'
     NoMethodError:
       undefined method `first_name=' for {:id=>1, :first_name=>"Ivan", :last_name=>nil, :age=>nil}:Hash
     # /tmp/d20161202-15620-b6vnzz/spec.rb:103: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.where finds records by attributes
     Failure/Error: records = user_model.where(first_name: 'Ivan').map(&:last_name)
     NoMethodError:
       undefined method `last_name' for {:id=>1, :first_name=>"Ivan", :last_name=>"Ivanov", :age=>nil}:Hash
     # /tmp/d20161202-15620-b6vnzz/spec.rb:125:in `map'
     # /tmp/d20161202-15620-b6vnzz/spec.rb:125: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)>'

  6) DataModel.where finds records by multiple attributes
     Failure/Error: ).map(&:last_name)
     NoMethodError:
       undefined method `last_name' for {:id=>1, :first_name=>"Ivan", :last_name=>"Ivanov", :age=>nil}:Hash
     # /tmp/d20161202-15620-b6vnzz/spec.rb:133:in `map'
     # /tmp/d20161202-15620-b6vnzz/spec.rb:133: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)>'

  7) 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-b6vnzz/spec.rb:156:in `delete'
     # /tmp/d20161202-15620-b6vnzz/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)>'

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

Failed examples:

rspec /tmp/d20161202-15620-b6vnzz/spec.rb:21 # DataModel has attributes and data_model getters
rspec /tmp/d20161202-15620-b6vnzz/spec.rb:39 # DataModel has #find_by_<attribute> methods
rspec /tmp/d20161202-15620-b6vnzz/spec.rb:62 # DataModel id generation does not reuse ids
rspec /tmp/d20161202-15620-b6vnzz/spec.rb:92 # DataModel equality comparison compares by id if both records are saved
rspec /tmp/d20161202-15620-b6vnzz/spec.rb:124 # DataModel.where finds records by attributes
rspec /tmp/d20161202-15620-b6vnzz/spec.rb:129 # DataModel.where finds records by multiple attributes
rspec /tmp/d20161202-15620-b6vnzz/spec.rb:151 # DataModel#delete deletes only the record for which it is called
rspec /tmp/d20161202-15620-b6vnzz/spec.rb:162 # DataModel#delete raises an error if the record is not saved

История (6 версии и 16 коментара)

Иван обнови решението на 27.11.2016 08:26 (преди около 8 години)

+class DataModel
+ class <<self
+ attr_accessor :storage, :last_id, :keys
+ end
+
+ attr_reader :id
+
+ def self.attributes(*arguments)
+ DataModel.keys = arguments
+ arguments.each do |argument|
+ attr_accessor argument.to_s
+ define_method("find_by_#{argument}") do
+ end
+ end
+ end
+
+ def self.data_store(data_storage = nil)
+ DataModel.storage = data_storage if DataModel.storage.nil?
+ DataModel.storage
+ end
+
+ def self.where(**search)
+ search
+ end
+
+ DataModel.last_id = 0
+
+ def initialize(**_hash)
+ @id = nil
+ @saved = false
+ @storage = DataModel.storage
+ end
+
+ def save
+ if @saved == true
+ @storage.update(@id, data_hash)
+ else
+ increment_id
+ @storage.create(data_hash)
+ @saved = true
+ end
+ end
+
+ def data_hash
+ hash = {id: @id}
+ DataModel.keys.each do |variable|
+ hash[variable] = send(variable.to_s)
+ end
+ hash
+ end
+
+ def increment_id
+ DataModel.last_id += 1
+ @id = DataModel.last_id
+ end
+end
+
+class DataStore
+ attr_reader :storage
+
+ def create(**record)
+ @storage = [] if @storage.nil?
+ @storage << record
+ end
+
+ def find(query)
+ # to be implemented
+ end
+
+ def update(id, **_attributes)
+ # to be implemented
+ @storage[id - 1]
+ end
+
+ def delete(query)
+ # to be implemented
+ end
+end
+
+class ArrayStore < DataStore
+end
+
+class HashStore < DataStore
+ def create(**record)
+ @storage = {} if @storage.nil?
+ @storage[record[:id]] = record
+ end
+end

Иван обнови решението на 27.11.2016 11:32 (преди около 8 години)

class DataModel
class <<self
attr_accessor :storage, :last_id, :keys
end
attr_reader :id
def self.attributes(*arguments)
DataModel.keys = arguments
arguments.each do |argument|
attr_accessor argument.to_s
define_method("find_by_#{argument}") do
end
end
end
def self.data_store(data_storage = nil)
DataModel.storage = data_storage if DataModel.storage.nil?
DataModel.storage
end
def self.where(**search)
search
end
DataModel.last_id = 0
+ puts DataModel.last_id.to_s
def initialize(**_hash)
@id = nil
@saved = false
@storage = DataModel.storage
end
def save
if @saved == true
@storage.update(@id, data_hash)
else
increment_id
@storage.create(data_hash)
@saved = true
end
end
def data_hash
hash = {id: @id}
DataModel.keys.each do |variable|
hash[variable] = send(variable.to_s)
end
hash
end
+ def delete
+ end
+
def increment_id
DataModel.last_id += 1
@id = DataModel.last_id
end
end
class DataStore
attr_reader :storage
def create(**record)
@storage = [] if @storage.nil?
- @storage << record
+ @storage = @storage.push record
end
- def find(query)
- # to be implemented
+ def find(**querry)
+ result = []
+ @storage.each do |element|
+ result << element if matches_search?(element, querry) == true
+ end
+ result
end
- def update(id, **_attributes)
- # to be implemented
- @storage[id - 1]
+ def update(id, **attributes)
+ attributes.each do |key, value|
+ @storage[id - 1][key] = value
+ end
end
def delete(query)
- # to be implemented
end
+
+ private
+ def matches_search?(element, querry)
+ match = true
+ querry.each do |key, value|
+ match = false unless element[key] == value
+ end
+ match
+ end
end
class ArrayStore < DataStore
end
class HashStore < DataStore
def create(**record)
- @storage = {} if @storage.nil?
- @storage[record[:id]] = record
+ super
+ @storage.unshift('placeholder')
+ @storage = Hash[(0...@storage.size).zip @storage]
+ @storage.delete(0)
end
end

Иван обнови решението на 27.11.2016 13:32 (преди около 8 години)

class DataModel
class <<self
attr_accessor :storage, :last_id, :keys
+
+ def inherited(subclass)
+ subclass.storage = nil
+ subclass.last_id = 0
+ subclass.keys = nil
+ end
end
attr_reader :id
def self.attributes(*arguments)
- DataModel.keys = arguments
+ self.keys = arguments
arguments.each do |argument|
attr_accessor argument.to_s
define_method("find_by_#{argument}") do

Мерси за бързия отговор. Имам още един въпрос относно #where - грешката трябва да върне съобщение 'Unknown attribute <attribute_name>'. В случай, че имаме повече от един непознат атрибут тук <attribute_name> масив от атрибутите ли трябва да върне, или първият непознат, или всички непознати изредени със запетая ? xD

end
end
end
def self.data_store(data_storage = nil)
- DataModel.storage = data_storage if DataModel.storage.nil?
- DataModel.storage
+ self.storage = data_storage if self.storage.nil?
+ self.storage
end
def self.where(**search)
search
end
- DataModel.last_id = 0
- puts DataModel.last_id.to_s
-
def initialize(**_hash)
@id = nil
- @saved = false
- @storage = DataModel.storage
end
def save
- if @saved == true
- @storage.update(@id, data_hash)
+ if @id.nil?
+ @id = increment_id
+ self.class.storage.create(data_hash)
else
- increment_id
- @storage.create(data_hash)
+ self.class.storage.update(@id, data_hash)
@saved = true
end
end
def data_hash
hash = {id: @id}
- DataModel.keys.each do |variable|
- hash[variable] = send(variable.to_s)
- end
+ self.class.keys.each { |variable| hash[variable] = send(variable.to_s) }
hash
end
def delete
+ self.class.storage.delete(id: @id)
end
def increment_id
- DataModel.last_id += 1
- @id = DataModel.last_id
+ self.class.last_id += 1
end
end
class DataStore
- attr_reader :storage
+ def storage
+ @storage = [] if @storage.nil?
+ @storage
+ end
def create(**record)
@storage = [] if @storage.nil?
- @storage = @storage.push record
+ @storage << record
end
def find(**querry)
result = []
@storage.each do |element|
result << element if matches_search?(element, querry) == true
end
result
end
def update(id, **attributes)
+ record = @storage[id - 1]
attributes.each do |key, value|
- @storage[id - 1][key] = value
+ record[key] = value unless value.nil?
end
end
- def delete(query)
+ def delete(querry)
+ for_delete = find(querry)
+ @storage -= for_delete
end
private
def matches_search?(element, querry)
match = true
querry.each do |key, value|
match = false unless element[key] == value
end
match
end
end
class ArrayStore < DataStore
end
class HashStore < DataStore
- def create(**record)
- super
- @storage.unshift('placeholder')
- @storage = Hash[(0...@storage.size).zip @storage]
- @storage.delete(0)
+ def storage
+ @storage = [] if @storage.nil?
+ hash = {}
+ @storage.map do |item|
+ hash[item[:id]] = item
+ end
+ hash
end
end

Иван обнови решението на 27.11.2016 15:53 (преди около 8 години)

-class DataModel
+class UnknownAttributeError < ArgumentError
+end
+
+class BasicDataModel
class <<self
attr_accessor :storage, :last_id, :keys
def inherited(subclass)
subclass.storage = nil
subclass.last_id = 0
subclass.keys = nil
end
end
attr_reader :id
def self.attributes(*arguments)
self.keys = arguments
arguments.each do |argument|
attr_accessor argument.to_s
- define_method("find_by_#{argument}") do
+ define_singleton_method("find_by_#{argument}") do |value|
+ self.where(Hash[argument, value])
end
end
end
+ def self.find_by_id(id)
+ self.where(id: id)
+ end
+
def self.data_store(data_storage = nil)
self.storage = data_storage if self.storage.nil?
self.storage
end
def self.where(**search)
- search
+ unknown = (search.keys - self.keys) - [:id]
+ unless unknown.empty?
+ raise UnknownAttributeError, "Unknown attribute #{(search.keys - self.keys)[0]}"
+ end
+ self.storage.find(search)
end
+end
- def initialize(**_hash)
+class DataModel < BasicDataModel
+ def initialize(**hash)
@id = nil
+ hash.each do |key, value|
+ instance_variable_set("@" + key.to_s, value) unless value.nil?
+ end
end
def save
if @id.nil?
@id = increment_id
self.class.storage.create(data_hash)
else
self.class.storage.update(@id, data_hash)
@saved = true
end
end
def data_hash
hash = {id: @id}
self.class.keys.each { |variable| hash[variable] = send(variable.to_s) }
hash
end
def delete
self.class.storage.delete(id: @id)
end
def increment_id
self.class.last_id += 1
end
end
class DataStore
def storage
@storage = [] if @storage.nil?
@storage
end
def create(**record)
@storage = [] if @storage.nil?
@storage << record
end
def find(**querry)
result = []
@storage.each do |element|
result << element if matches_search?(element, querry) == true
end
result
end
def update(id, **attributes)
record = @storage[id - 1]
attributes.each do |key, value|
record[key] = value unless value.nil?
end
end
def delete(querry)
for_delete = find(querry)
@storage -= for_delete
end
private
def matches_search?(element, querry)
match = true
querry.each do |key, value|
match = false unless element[key] == value
end
match
end
end
class ArrayStore < DataStore
end
class HashStore < DataStore
def storage
@storage = [] if @storage.nil?
hash = {}
@storage.map do |item|
hash[item[:id]] = item
end

Благодаря за коментарите! Като цяло за някои от нещата не се бях замислил, стараех се да докарам функционалността и просто така ми тече мисълта. Сега ще започна да рефрактурирам!

hash
end
end

Тук не ми харесват няколко неща:

  • Вместо map и select правиш цикли. Не пишеш на C или PHP.
  • Това наследяване на DataStore е супер измъчено и се опитваш да заобикаляш условието на задачата. Направи напълно отделни, без да наследяваш. Вътрешното представяне на HashStore трябва да е хеш, не да го генерираш когато го искаме.
  • Този ред attr_accessor :storage, :last_id, :keys не прави нищо специално. Създава гетър и сетър за инстанционни променливи. Можеш да достъпваш тези променливи и директно, няма нужда постоянно да пишеш self.storage = <whatever>

Иван обнови решението на 27.11.2016 19:28 (преди около 8 години)

class UnknownAttributeError < ArgumentError
end
class BasicDataModel
- class <<self
- attr_accessor :storage, :last_id, :keys
+end
- def inherited(subclass)
- subclass.storage = nil
- subclass.last_id = 0
- subclass.keys = nil
- end
+class DataModel
+ class <<self
+ attr_accessor :keys
end
attr_reader :id
def self.attributes(*arguments)
- self.keys = arguments
+ @keys = arguments
arguments.each do |argument|
attr_accessor argument.to_s
define_singleton_method("find_by_#{argument}") do |value|
- self.where(Hash[argument, value])
+ where(Hash[argument, value])
end
end
end
def self.find_by_id(id)
- self.where(id: id)
+ where(id: id)
end
def self.data_store(data_storage = nil)
- self.storage = data_storage if self.storage.nil?
- self.storage
+ @storage = data_storage if @storage.nil?
+ @storage
end
def self.where(**search)
unknown = (search.keys - self.keys) - [:id]
unless unknown.empty?
- raise UnknownAttributeError, "Unknown attribute #{(search.keys - self.keys)[0]}"
+ raise UnknownAttributeError, "Unknown attribute #{unknown[0]}"
end
- self.storage.find(search)
+ data_store.find(search)
end
-end
-class DataModel < BasicDataModel
def initialize(**hash)
@id = nil
hash.each do |key, value|
instance_variable_set("@" + key.to_s, value) unless value.nil?
end
end
def save
if @id.nil?
- @id = increment_id
- self.class.storage.create(data_hash)
+ @id = self.class.data_store.storage.length + 1
+ self.class.data_store.create(data_hash)
else
- self.class.storage.update(@id, data_hash)
+ self.class.data_store.update(@id, data_hash)
@saved = true
end
end
def data_hash
hash = {id: @id}
self.class.keys.each { |variable| hash[variable] = send(variable.to_s) }
hash
end
def delete
- self.class.storage.delete(id: @id)
+ self.class.data_store.delete(id: @id)
end
-
- def increment_id
- self.class.last_id += 1
- end
end
class DataStore
def storage
@storage = [] if @storage.nil?
@storage
end
def create(**record)
@storage = [] if @storage.nil?
@storage << record
end
def find(**querry)
- result = []
- @storage.each do |element|
- result << element if matches_search?(element, querry) == true
- end
- result
+ @storage.select { |element| matches_search?(element, querry) }
end
def update(id, **attributes)
- record = @storage[id - 1]
- attributes.each do |key, value|
- record[key] = value unless value.nil?
- end
+ record = @storage.select { |element| element[:id] == id }[0]
+ attributes.map { |key, value| record[key] = value }
end
def delete(querry)
for_delete = find(querry)
@storage -= for_delete
end
private
def matches_search?(element, querry)
match = true
querry.each do |key, value|
match = false unless element[key] == value
end
match
end
end
class ArrayStore < DataStore
end
class HashStore < DataStore
def storage
@storage = [] if @storage.nil?
hash = {}
@storage.map do |item|
hash[item[:id]] = item
end
hash
end
end

Иван обнови решението на 27.11.2016 19:58 (преди около 8 години)

class UnknownAttributeError < ArgumentError
end
-class BasicDataModel
-end
-
class DataModel
class <<self
attr_accessor :keys
end
attr_reader :id
def self.attributes(*arguments)
@keys = arguments
arguments.each do |argument|
attr_accessor argument.to_s
define_singleton_method("find_by_#{argument}") do |value|
where(Hash[argument, value])
end
end
end
def self.find_by_id(id)
where(id: id)
end
def self.data_store(data_storage = nil)
@storage = data_storage if @storage.nil?
@storage
end
def self.where(**search)
- unknown = (search.keys - self.keys) - [:id]
+ unknown = (search.keys - @keys) - [:id]
unless unknown.empty?
raise UnknownAttributeError, "Unknown attribute #{unknown[0]}"
end
data_store.find(search)
end
def initialize(**hash)
@id = nil
hash.each do |key, value|
- instance_variable_set("@" + key.to_s, value) unless value.nil?
+ instance_variable_set("@" + key.to_s, value)
end
end
def save
if @id.nil?
@id = self.class.data_store.storage.length + 1
self.class.data_store.create(data_hash)
else
self.class.data_store.update(@id, data_hash)
@saved = true
end
end
def data_hash
hash = {id: @id}
self.class.keys.each { |variable| hash[variable] = send(variable.to_s) }
hash
end
def delete
self.class.data_store.delete(id: @id)
end
end
class DataStore
def storage
@storage = [] if @storage.nil?
@storage
end
def create(**record)
@storage = [] if @storage.nil?
@storage << record
end
- def find(**querry)
- @storage.select { |element| matches_search?(element, querry) }
+ def find(**query)
+ @storage.select { |data| query.select { |key, value| data[key] == value } == query }
end
def update(id, **attributes)
record = @storage.select { |element| element[:id] == id }[0]
attributes.map { |key, value| record[key] = value }
end
- def delete(querry)
- for_delete = find(querry)
- @storage -= for_delete
+ def delete(query)
+ @storage -= find(query)
end
-
- private
- def matches_search?(element, querry)
- match = true
- querry.each do |key, value|
- match = false unless element[key] == value
- end
- match
- end
end
class ArrayStore < DataStore
end
class HashStore < DataStore
def storage
@storage = [] if @storage.nil?
hash = {}
- @storage.map do |item|
- hash[item[:id]] = item
- end
+ @storage.each { |item| hash[item[:id]] = item }
hash
end
end

Привет!

Взел съм ти точка заради използването на масив в HashStore (втората точка от предния ми коментар). Ако ще пази масив - HashStore губи смисъла си.

Виж си грешките от тестовете и внимавай какво пише в задачата - има доста пропуски по нещата от условието.