Решение на Пета задача - DataModel от Лазар Дилов

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

Към профила на Лазар Дилов

Резултати

  • 3 точки от тестове
  • 0 бонус точки
  • 3 точки общо
  • 12 успешни тест(а)
  • 13 неуспешни тест(а)

Код

module InstanceOperators
def ==(other)
return true if self.equal? other
if self.class == other.class
return self.id == other.id unless self.id.nil? || other.id.nil?
end
false
end
def equal?(x)
true if self.object_id == x.object_id && self.saved == true && x.saved == true
false
end
end
class ArrayStore
def initialize
@storage = []
end
def create(record = {})
@storage.push(record)
end
def find(request = {})
@storage.select { |obj| (request.to_a - obj.to_a).empty? }
end
def update(id, attributes = {})
attributes.select { |k, _v| @storage[id].key?(k) }.map { |k, v| @storage[id][k] = v }
end
def delete(request = {})
@storage.map { |v| @storage.delete[v] if (request.to_a - obj.to_a).empty? }
end
end
class HashStore
class<<self
attr_accessor :id
end
self.id = 0
def initialize
@storage = {}
end
def create(record = {})
@storage.store(self.class.id, record)
self.class.id += 1
end
def find(request = {})
@storage.select { |_k, val| (request.to_a - val.to_a).empty? }.values
end
def update(id, attributes = {})
attributes.map { |k, v| @storage[id][k] = v if @storage[id].key?(k) }
end
def delete(request = {})
@storage.map { |_k, obj| @storage.delete(obj) if (request.to_a - obj.to_a).empty? }
end
end
class DataModel
include InstanceOperators
attr_accessor :id, :saved
def initialize(data = {})
@saved = false
self.class.attributes.each { |a, _v| self.class.class_eval { attr_accessor a } }
unless data.empty?
self.class.attributes_hash.select { |a, _v| data.key?(a) }.map do |a, _v|
instance_variable_set("@#{a}", data[a])
end
end
end
class<< self
def data_store(store = nil)
return @storage if store.nil?
instance_variable_set(:@storage, store)
end
def attributes(*atrs)
return @attributes.keys if atrs.empty?
instance_variable_set(:@attributes, Hash[atrs.map { |x| [x, nil] }])
@attributes.keys.each do |attribute|
define_singleton_method "find_by_#{attribute}" do |arg|
where(attribute => arg)
end
end
end
def attributes_hash
@attributes
end
def where(names = {})
arr = []
ObjectSpace.each_object(self) { |x| arr.push(x) }
names.each do |a, v|
arr = arr.select { |u| u.instance_variable_get("@#{a}") == v && u.saved == true }
end
arr
end
attr_accessor :current_id
end
self.current_id = 0
def save
@saved = true
self.class.superclass.current_id += 1
@id = self.class.superclass.current_id
self.class.data_store.create(self.class.attributes_hash)
self
end
end

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

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

Failures:

  1) DataModel id generation creates id on first save and does not change it
     Failure/Error: expect(record.id).to eq id
       
       expected: 2
            got: 3
       
       (compared using ==)
     # /tmp/d20161202-15620-1og6i95/spec.rb:59: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 id generation does not reuse ids
     Failure/Error: expect(ivan.id).to eq 1
       
       expected: 1
            got: 4
       
       (compared using ==)
     # /tmp/d20161202-15620-1og6i95/spec.rb:65: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 id generation does not break when there are two models with the same store
     Failure/Error: expect(ivan.id).to eq 1
       
       expected: 1
            got: 5
       
       (compared using ==)
     # /tmp/d20161202-15620-1og6i95/spec.rb:83: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 uses #equal? if there are no ids
     Failure/Error: expect(first_user).to eq first_user
       
       expected: #<#<Class:0x007f1fad25c2a8>:0x007f1fad2630a8 @saved=false, @first_name="Ivan">
            got: #<#<Class:0x007f1fad25c2a8>:0x007f1fad2630a8 @saved=false, @first_name="Ivan">
       
       (compared using ==)
       
       Diff:
     # /tmp/d20161202-15620-1og6i95/spec.rb:113: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 raises an error if the query is by an unknown key
     Failure/Error: DataModel::UnknownAttributeError,
     NameError:
       uninitialized constant DataModel::UnknownAttributeError
     # /tmp/d20161202-15620-1og6i95/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)>'

  6) DataModel#delete deletes only the record for which it is called
     Failure/Error: ivan.delete
     NoMethodError:
       undefined method `delete' for #<#<Class:0x007f1fad2a4260>:0x007f1fad2ab3f8>
     # /tmp/d20161202-15620-1og6i95/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)>'

  7) DataModel#delete raises an error if the record is not saved
     Failure/Error: DataModel::DeleteUnsavedRecordError
     NameError:
       uninitialized constant DataModel::DeleteUnsavedRecordError
     # /tmp/d20161202-15620-1og6i95/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)>'

  8) HashStore behaves like a data store #update updates the attributes of a record with a given ID
     Failure/Error: store.update(2, {id: 2, name: 'Georgi'})
     NoMethodError:
       undefined method `key?' for nil:NilClass
     Shared Example Group: "a data store" called from /tmp/d20161202-15620-1og6i95/spec.rb:235
     # /tmp/d20161202-15620-1og6i95/solution.rb:55:in `block in update'
     # /tmp/d20161202-15620-1og6i95/solution.rb:55:in `each'
     # /tmp/d20161202-15620-1og6i95/solution.rb:55:in `map'
     # /tmp/d20161202-15620-1og6i95/solution.rb:55:in `update'
     # /tmp/d20161202-15620-1og6i95/spec.rb:199: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)>'

  9) HashStore behaves like a data store #update only updates records with the correct IDs
     Failure/Error: store.update(2, {id: 2, name: 'Sasho'})
     NoMethodError:
       undefined method `key?' for nil:NilClass
     Shared Example Group: "a data store" called from /tmp/d20161202-15620-1og6i95/spec.rb:235
     # /tmp/d20161202-15620-1og6i95/solution.rb:55:in `block in update'
     # /tmp/d20161202-15620-1og6i95/solution.rb:55:in `each'
     # /tmp/d20161202-15620-1og6i95/solution.rb:55:in `map'
     # /tmp/d20161202-15620-1og6i95/solution.rb:55:in `update'
     # /tmp/d20161202-15620-1og6i95/spec.rb:210: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)>'

  10) 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-1og6i95/spec.rb:235
     # /tmp/d20161202-15620-1og6i95/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)>'

  11) ArrayStore behaves like a data store #update updates the attributes of a record with a given ID
     Failure/Error: store.update(2, {id: 2, name: 'Georgi'})
     NoMethodError:
       undefined method `key?' for nil:NilClass
     Shared Example Group: "a data store" called from /tmp/d20161202-15620-1og6i95/spec.rb:239
     # /tmp/d20161202-15620-1og6i95/solution.rb:29:in `block in update'
     # /tmp/d20161202-15620-1og6i95/solution.rb:29:in `select'
     # /tmp/d20161202-15620-1og6i95/solution.rb:29:in `update'
     # /tmp/d20161202-15620-1og6i95/spec.rb:199: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)>'

  12) ArrayStore behaves like a data store #update only updates records with the correct IDs
     Failure/Error: store.update(2, {id: 2, name: 'Sasho'})
     NoMethodError:
       undefined method `key?' for nil:NilClass
     Shared Example Group: "a data store" called from /tmp/d20161202-15620-1og6i95/spec.rb:239
     # /tmp/d20161202-15620-1og6i95/solution.rb:29:in `block in update'
     # /tmp/d20161202-15620-1og6i95/solution.rb:29:in `select'
     # /tmp/d20161202-15620-1og6i95/solution.rb:29:in `update'
     # /tmp/d20161202-15620-1og6i95/spec.rb:210: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)>'

  13) ArrayStore behaves like a data store #delete can delete multiple records with a single query
     Failure/Error: store.delete(name: 'Pesho')
     NameError:
       undefined local variable or method `obj' for #<ArrayStore:0x007f1fad66dba8>
     Shared Example Group: "a data store" called from /tmp/d20161202-15620-1og6i95/spec.rb:239
     # /tmp/d20161202-15620-1og6i95/solution.rb:33:in `block in delete'
     # /tmp/d20161202-15620-1og6i95/solution.rb:33:in `map'
     # /tmp/d20161202-15620-1og6i95/solution.rb:33:in `delete'
     # /tmp/d20161202-15620-1og6i95/spec.rb:227: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.05313 seconds
25 examples, 13 failures

Failed examples:

rspec /tmp/d20161202-15620-1og6i95/spec.rb:48 # DataModel id generation creates id on first save and does not change it
rspec /tmp/d20161202-15620-1og6i95/spec.rb:62 # DataModel id generation does not reuse ids
rspec /tmp/d20161202-15620-1og6i95/spec.rb:74 # DataModel id generation does not break when there are two models with the same store
rspec /tmp/d20161202-15620-1og6i95/spec.rb:108 # DataModel equality comparison uses #equal? if there are no ids
rspec /tmp/d20161202-15620-1og6i95/spec.rb:142 # DataModel.where raises an error if the query is by an unknown key
rspec /tmp/d20161202-15620-1og6i95/spec.rb:151 # DataModel#delete deletes only the record for which it is called
rspec /tmp/d20161202-15620-1og6i95/spec.rb:162 # DataModel#delete raises an error if the record is not saved
rspec /tmp/d20161202-15620-1og6i95/spec.rb:196 # HashStore behaves like a data store #update updates the attributes of a record with a given ID
rspec /tmp/d20161202-15620-1og6i95/spec.rb:204 # HashStore behaves like a data store #update only updates records with the correct IDs
rspec /tmp/d20161202-15620-1og6i95/spec.rb:218 # HashStore behaves like a data store #delete can delete multiple records with a single query
rspec /tmp/d20161202-15620-1og6i95/spec.rb:196 # ArrayStore behaves like a data store #update updates the attributes of a record with a given ID
rspec /tmp/d20161202-15620-1og6i95/spec.rb:204 # ArrayStore behaves like a data store #update only updates records with the correct IDs
rspec /tmp/d20161202-15620-1og6i95/spec.rb:218 # ArrayStore behaves like a data store #delete can delete multiple records with a single query

История (5 версии и 9 коментара)

Лазар обнови решението на 28.11.2016 09:00 (преди около 8 години)

+class ArrayStore
+ def initialize
+ @storage = []
+ end
+
+ def create(record = {})
+ @storage.push(record)
+ end
+
+ def find(request = {})
+ result = []
+ @storage.each_with_index do |obj, _id|
+ result.push(obj) if (request.to_a - obj.to_a).empty?
+ end
+ result
+ end
+
+ def update(id, attributes = {})
+ attributes.each do |key, value|
+ @storage[id][key] = value if @storage[id].key?(key)
+ end
+ end
+
+ def delete(request = {})
+ @storage.each_with_index do |obj, _id|
+ @storage.delete(obj) if (request.to_a - obj.to_a).empty?
+ end
+ end
+end
+
+class HashStore
+ class<<self
+ attr_accessor :id
+ end
+ self.id = 0
+ def initialize
+ @storage = {}
+ end
+
+ def create(record = {})
+ @storage.store(self.class.id, record)
+ self.class.id += 1
+ end
+
+ def find(request = {})
+ result = []
+ @storage.each do |_key, value|
+ result.push(value) if (request.to_a - value.to_a).empty?
+ end
+ result
+ end
+
+ def update(id, attributes = {})
+ attributes.each do |key, value|
+ @storage[id][key] = value if @storage[id].key?(key)
+ end
+ end
+
+ def delete(request = {})
+ @storage.each_with_index do |obj, _id|
+ @storage.delete(obj) if (request.to_a - obj.to_a).empty?
+ end
+ end
+end
+
+class DataModel
+ attr_accessor :id
+ def initialize(data = {})
+ @@attributes.each { |attrib, _value| self.class.class_eval { attr_accessor attrib } }

Разликата между двете ми е ясна, май сега разбирам че не съм схванал идеята на DataModel както трябва. Представях си атрибутите като глобална променлива за всички обекти , тоест class variable за всички инстанции на класа.

+ unless data.empty?
+ @@attributes.each do |attribute, _value|
+ if data.key?(attribute)
+ @@attributes[attribute] = data[attribute]
+ instance_variable_set("@#{attribute}", data[attribute])
+ end
+ end
+ end
+ end
+ class<< self
+ def attributes(*atrs)
+ return @@attributes.keys if atrs.empty?
+ DataModel.class_variable_set(:@@attributes, Hash[atrs.collect { |x| [x, nil] }])
+ @@attributes.keys.each do |attribute|
+ define_singleton_method "find_by_#{attribute}" do |arg|
+ where(attribute => arg)
+ end
+ end
+ end
+
+ def data_store(store = nil)
+ return @@storage if store.nil?
+ DataModel.class_variable_set(:@@storage, store)
+ end
+
+ def where(names = {})
+ @@storage.find(names)
+ end
+ attr_accessor :current_id
+ end
+ self.current_id = 1
+ def save
+ @id = self.class.superclass.current_id
+ @@storage.create(@@attributes)
+ self.class.superclass.current_id = self.class.superclass.current_id + 1
+ self
+ end
+end

Не разбирам две неща:

  1. Защо използваш each_with_index и игнорираш индекса, вместо да ползваш each?
  2. Защо изобщо ползваш each вместо map/select и другите по-подходящи методи?

Не ни хвърляй първото решение, за което се сетиш в 9 сутринта. Прегледай си пак кода и виж кое можеш да замениш с нещо по-подходящо (хинт - всички each-ове)

Освен това, заради класовите променливи, които между другото ти чупят решението, ти се налага да пишеш по-сложен код от необходимото.

Лазар обнови решението на 28.11.2016 21:05 (преди около 8 години)

class ArrayStore
def initialize
@storage = []
end
def create(record = {})
@storage.push(record)
end
def find(request = {})
- result = []
- @storage.each_with_index do |obj, _id|
- result.push(obj) if (request.to_a - obj.to_a).empty?
- end
- result
+ @storage.select { |obj| (request.to_a - obj.to_a).empty? }
end
def update(id, attributes = {})
- attributes.each do |key, value|
- @storage[id][key] = value if @storage[id].key?(key)
- end
+ attributes.select { |k, _v| @storage[id].key?(k) }.map { |k, v| @storage[id][k] = v }
end
def delete(request = {})
- @storage.each_with_index do |obj, _id|
- @storage.delete(obj) if (request.to_a - obj.to_a).empty?
- end
+ @storage.map { |v| @storage.delete[v] if (request.to_a - obj.to_a).empty? }
end
end
class HashStore
class<<self
attr_accessor :id
end
self.id = 0
def initialize
@storage = {}
end
def create(record = {})
@storage.store(self.class.id, record)
self.class.id += 1
end
def find(request = {})
- result = []
- @storage.each do |_key, value|
- result.push(value) if (request.to_a - value.to_a).empty?
- end
- result
+ @storage.select { |_k, val| (request.to_a - val.to_a).empty? }.values
end
def update(id, attributes = {})
- attributes.each do |key, value|
- @storage[id][key] = value if @storage[id].key?(key)
- end
+ attributes.map { |k, v| @storage[id][k] = v if @storage[id].key?(k) }
end
def delete(request = {})
- @storage.each_with_index do |obj, _id|
- @storage.delete(obj) if (request.to_a - obj.to_a).empty?
- end
+ @storage.map { |_k, obj| @storage.delete(obj) if (request.to_a - obj.to_a).empty? }
end
end
class DataModel
attr_accessor :id
def initialize(data = {})
- @@attributes.each { |attrib, _value| self.class.class_eval { attr_accessor attrib } }
+ self.class.attributes.each { |a, _v| self.class.class_eval { attr_accessor a } }
unless data.empty?
- @@attributes.each do |attribute, _value|
- if data.key?(attribute)
- @@attributes[attribute] = data[attribute]
- instance_variable_set("@#{attribute}", data[attribute])
- end
+ self.class.attributes_hash.select { |a, _v| data.key?(a) }.map do |a, _v|
+ self.class.attributes_hash[a] = data[a]
end
end
end
class<< self
+ def data_store(store = nil)
+ return @storage if store.nil?
+ instance_variable_set(:@storage, store)
+ end
+
def attributes(*atrs)
- return @@attributes.keys if atrs.empty?
- DataModel.class_variable_set(:@@attributes, Hash[atrs.collect { |x| [x, nil] }])
- @@attributes.keys.each do |attribute|
+ return @attributes.keys if atrs.empty?
+ instance_variable_set(:@attributes, Hash[atrs.collect { |x| [x, nil] }])
+ @attributes.keys.each do |attribute|
define_singleton_method "find_by_#{attribute}" do |arg|
where(attribute => arg)
end
end
end
- def data_store(store = nil)
- return @@storage if store.nil?
- DataModel.class_variable_set(:@@storage, store)
+ def attributes_hash
+ @attributes
end
def where(names = {})
- @@storage.find(names)
+ @storage.find(names)
end
attr_accessor :current_id
end
self.current_id = 1
def save
@id = self.class.superclass.current_id
- @@storage.create(@@attributes)
- self.class.superclass.current_id = self.class.superclass.current_id + 1
+ self.class.data_store.create(self.class.get_attributes)
+ self.class.superclass.current_id += 1
self
end
-end
+end

Постарах се да няма еаch-ове. Някой неща в DataModel са пренаписани, avoid-нах класовите променливи от миналото ми решение. Този път се надявам да няма нещо, което да ми чупи решението. Естествено преди крайния срок ще го погледна отново на свежа глава.

Лазар обнови решението на 30.11.2016 15:51 (преди около 8 години)

class ArrayStore
def initialize
@storage = []
end
def create(record = {})
@storage.push(record)
end
def find(request = {})
@storage.select { |obj| (request.to_a - obj.to_a).empty? }
end
def update(id, attributes = {})
attributes.select { |k, _v| @storage[id].key?(k) }.map { |k, v| @storage[id][k] = v }
end
def delete(request = {})
@storage.map { |v| @storage.delete[v] if (request.to_a - obj.to_a).empty? }
end
end
class HashStore
class<<self
attr_accessor :id
end
self.id = 0
def initialize
@storage = {}
end
def create(record = {})
@storage.store(self.class.id, record)
self.class.id += 1
end
def find(request = {})
@storage.select { |_k, val| (request.to_a - val.to_a).empty? }.values
end
def update(id, attributes = {})
attributes.map { |k, v| @storage[id][k] = v if @storage[id].key?(k) }
end
def delete(request = {})
@storage.map { |_k, obj| @storage.delete(obj) if (request.to_a - obj.to_a).empty? }
end
end
class DataModel
attr_accessor :id
def initialize(data = {})
self.class.attributes.each { |a, _v| self.class.class_eval { attr_accessor a } }
unless data.empty?
self.class.attributes_hash.select { |a, _v| data.key?(a) }.map do |a, _v|
self.class.attributes_hash[a] = data[a]
end
end
end
class<< self
def data_store(store = nil)
return @storage if store.nil?
instance_variable_set(:@storage, store)
end
def attributes(*atrs)
return @attributes.keys if atrs.empty?
- instance_variable_set(:@attributes, Hash[atrs.collect { |x| [x, nil] }])
+ instance_variable_set(:@attributes, Hash[atrs.map { |x| [x, nil] }])
@attributes.keys.each do |attribute|
define_singleton_method "find_by_#{attribute}" do |arg|
where(attribute => arg)
end
end
end
def attributes_hash
@attributes
end
def where(names = {})
@storage.find(names)
end
attr_accessor :current_id
end
self.current_id = 1
def save
@id = self.class.superclass.current_id
self.class.data_store.create(self.class.get_attributes)
self.class.superclass.current_id += 1
self
end
end

Лазар обнови решението на 30.11.2016 16:32 (преди около 8 години)

+module InstanceOperators
+ def ==(other)
+ return true if self.equal? other
+ if self.class == other.class
+ return self.id == other.id unless self.id.nil? || other.id.nil?
+ end
+ false
+ end
+end
+
class ArrayStore
def initialize
@storage = []
end
def create(record = {})
@storage.push(record)
end
def find(request = {})
@storage.select { |obj| (request.to_a - obj.to_a).empty? }
end
def update(id, attributes = {})
attributes.select { |k, _v| @storage[id].key?(k) }.map { |k, v| @storage[id][k] = v }
end
def delete(request = {})
@storage.map { |v| @storage.delete[v] if (request.to_a - obj.to_a).empty? }
end
end
class HashStore
class<<self
attr_accessor :id
end
self.id = 0
def initialize
@storage = {}
end
def create(record = {})
@storage.store(self.class.id, record)
self.class.id += 1
end
def find(request = {})
@storage.select { |_k, val| (request.to_a - val.to_a).empty? }.values
end
def update(id, attributes = {})
attributes.map { |k, v| @storage[id][k] = v if @storage[id].key?(k) }
end
def delete(request = {})
@storage.map { |_k, obj| @storage.delete(obj) if (request.to_a - obj.to_a).empty? }
end
end
class DataModel
+ include InstanceOperators
attr_accessor :id
def initialize(data = {})
self.class.attributes.each { |a, _v| self.class.class_eval { attr_accessor a } }
unless data.empty?
self.class.attributes_hash.select { |a, _v| data.key?(a) }.map do |a, _v|
self.class.attributes_hash[a] = data[a]
end
end
end
class<< self
def data_store(store = nil)
return @storage if store.nil?
instance_variable_set(:@storage, store)
end
def attributes(*atrs)
return @attributes.keys if atrs.empty?
instance_variable_set(:@attributes, Hash[atrs.map { |x| [x, nil] }])
@attributes.keys.each do |attribute|
define_singleton_method "find_by_#{attribute}" do |arg|
where(attribute => arg)
end
end
end
def attributes_hash
@attributes
end
def where(names = {})
@storage.find(names)
end
attr_accessor :current_id
end
self.current_id = 1
def save
@id = self.class.superclass.current_id
- self.class.data_store.create(self.class.get_attributes)
+ self.class.data_store.create(self.class.attributes_hash)
self.class.superclass.current_id += 1
self
end
end

Лазар обнови решението на 30.11.2016 18:47 (преди около 8 години)

module InstanceOperators
def ==(other)
return true if self.equal? other
if self.class == other.class
return self.id == other.id unless self.id.nil? || other.id.nil?
end
false
end
-end
+ def equal?(x)
+ true if self.object_id == x.object_id && self.saved == true && x.saved == true
+ false
+ end
+end
class ArrayStore
def initialize
@storage = []
end
def create(record = {})
@storage.push(record)
end
def find(request = {})
@storage.select { |obj| (request.to_a - obj.to_a).empty? }
end
def update(id, attributes = {})
attributes.select { |k, _v| @storage[id].key?(k) }.map { |k, v| @storage[id][k] = v }
end
def delete(request = {})
@storage.map { |v| @storage.delete[v] if (request.to_a - obj.to_a).empty? }
end
end
-
class HashStore
class<<self
attr_accessor :id
end
self.id = 0
def initialize
@storage = {}
end
def create(record = {})
@storage.store(self.class.id, record)
self.class.id += 1
end
def find(request = {})
@storage.select { |_k, val| (request.to_a - val.to_a).empty? }.values
end
def update(id, attributes = {})
attributes.map { |k, v| @storage[id][k] = v if @storage[id].key?(k) }
end
def delete(request = {})
@storage.map { |_k, obj| @storage.delete(obj) if (request.to_a - obj.to_a).empty? }
end
end
-
class DataModel
include InstanceOperators
- attr_accessor :id
+ attr_accessor :id, :saved
def initialize(data = {})
+ @saved = false
self.class.attributes.each { |a, _v| self.class.class_eval { attr_accessor a } }
unless data.empty?
self.class.attributes_hash.select { |a, _v| data.key?(a) }.map do |a, _v|
- self.class.attributes_hash[a] = data[a]
+ instance_variable_set("@#{a}", data[a])
end
end
end
class<< self
def data_store(store = nil)
return @storage if store.nil?
instance_variable_set(:@storage, store)
end
def attributes(*atrs)
return @attributes.keys if atrs.empty?
instance_variable_set(:@attributes, Hash[atrs.map { |x| [x, nil] }])
@attributes.keys.each do |attribute|
define_singleton_method "find_by_#{attribute}" do |arg|
where(attribute => arg)
end
end
end
def attributes_hash
@attributes
end
def where(names = {})
- @storage.find(names)
+ arr = []
+ ObjectSpace.each_object(self) { |x| arr.push(x) }
+ names.each do |a, v|
+ arr = arr.select { |u| u.instance_variable_get("@#{a}") == v && u.saved == true }
+ end
+ arr
end
attr_accessor :current_id
end
- self.current_id = 1
+ self.current_id = 0
def save
+ @saved = true
+ self.class.superclass.current_id += 1
@id = self.class.superclass.current_id
self.class.data_store.create(self.class.attributes_hash)
- self.class.superclass.current_id += 1
self
end
end