How can I refactor the following? I have some values stored in my YAML file as nested arrays, but I want to pull all my transactions into two get and set methods. This works, but is obviously limited and bulky. It feels wrong.
module Persistance
@store = YAML::Store.new('store.yml')
def self.get_transaction(key)
@store.transaction { @store[key] }
end
def self.get_nested_transaction(key, sub)
@store.transaction { @store[key][sub] }
end
end
Bonus credit: I also have an additional method for incrementing values in my YAML file. Is there a further way to refactor this code? Does it make sense to just pass blocks to a single database accessing method?
Hey I remember thinking about this when I was practicing PStore a little while ago. I didn't figure out a working approach then but I managed to get one now. By the way, yaml/store is pretty cool and you can take credit for introducing me to it.
Anyway, on with the code. Basically here's a couple important concepts:
@store
is similar to a hash in that you can use []
and []=
but it's not actually a hash, it's a YAML::Store
. get
and set
, as my code shows@store
were a true hash that would be the end of it but's not, so for this answer I added a YAML::Store#dig
method which has the same usage as the original. require 'yaml/store'
class YAML::Store
def dig(*keys)
first_val = self[keys.shift]
if keys.empty?
first_val
else
keys.reduce(first_val) do |result, key|
first_val[key]
end
end
end
end
class YamlStore
attr_reader :store
def initialize filename
@store = YAML::Store.new filename
end
def get *keys
@store.transaction do
@store.dig *keys
end
end
def set *keys, val
@store.transaction do
final_key = keys.pop
hash_to_set = keys.empty? ? @store : @store.dig(*keys)
hash_to_set.send :[]=, final_key, val
end
end
end
filename = 'store.yml'
db = YamlStore.new filename
db.set :a, {}
puts db.get :a
# => {}
db.set :a, :b, 1
puts db.get :a, :b
# => 1