quick_store 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: dc979e2e5e8ac6debcf84aedacbdddef39abfaa4
4
+ data.tar.gz: c65348865e6a22cc2facd0556b46a7673aff600d
5
+ SHA512:
6
+ metadata.gz: 2bfea78a041c46588bc532a3ad04588dff6a1baed59edaabec645b93de63a2f4e78b98976501e05caf5db9dbfce4c4e18b7b7e9d2b9e44ac5395e03b106ccba9
7
+ data.tar.gz: db7808449b82ce2d1be9a4b82702ce6e83f7a50daf3743c6e660d683c668ae71d3936897990f0acdf323cb9e826074811c495ceb430a7fb8e499d66a2faca27f
data/.gitignore ADDED
@@ -0,0 +1,14 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
data/README.md ADDED
@@ -0,0 +1,65 @@
1
+ # QuickStore
2
+
3
+ Simple local key-value store based on YAML::Store.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'quick_store'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install quick_store
20
+
21
+ ## Usage
22
+
23
+ ```ruby
24
+ require 'quick_store'
25
+ ```
26
+
27
+ ### Configuration
28
+
29
+ ```ruby
30
+ QuickStore.configure do |config|
31
+ config.file_path = 'path/to/store/file.yml'
32
+ config.key_separator = '|' # default is '/'
33
+ end
34
+ ```
35
+
36
+ ### Storing and fetching data
37
+ You can store and receive data from the store using different methods:
38
+
39
+ ```ruby
40
+ # Using dynamic setters and getters
41
+ QuickStore.store.arbitrary_key = 'value' # => "value"
42
+ QuickStore.store.arbitrary_key # => "value"
43
+
44
+ # Using the ::set and ::get methods
45
+ QuickStore.store.set(:arbitrary_key, 'value') # => "value"
46
+ QuickStore.store.get(:arbitrary_key) # => "value"
47
+
48
+ # Example for a nested key ('/' is the default key separator)
49
+ QuickStore.store.set('a/b/c', 'value') # => {"b"=>{"c"=>"value"}}
50
+ QuickStore.store.get('a/b/c') # => "value"
51
+ QuickStore.store.get('a/b') # => {"c"=>"value"}
52
+ QuickStore.store.get('a') # => {"b"=>{"c"=>"value"}}
53
+ ```
54
+
55
+ ## Contributing
56
+
57
+ 1. Fork it ( https://github.com/[my-github-username]/quick_store/fork )
58
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
59
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
60
+ 4. Push to the branch (`git push origin my-new-feature`)
61
+ 5. Create a new Pull Request
62
+
63
+ ## License
64
+
65
+ The quick_store gem is released under the [MIT License](http://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
@@ -0,0 +1,121 @@
1
+ require 'active_support'
2
+ require 'yaml/store'
3
+ require 'fileutils'
4
+ require 'singleton'
5
+
6
+ module QuickStore
7
+
8
+ class Store
9
+ include Singleton
10
+
11
+ attr_reader :file
12
+
13
+ def initialize
14
+ @file = QuickStore.config.file_path
15
+
16
+ raise(QuickStore::NO_FILE_PATH_CONFIGURED) unless @file
17
+
18
+ directory = File.dirname(@file)
19
+ FileUtils.makedirs(directory) unless Dir.exist?(directory)
20
+
21
+ @db = YAML::Store.new(@file)
22
+ end
23
+
24
+ # Sets the value for the given key.
25
+ # If the key is of structure "a/b/c" then the value is saved as a
26
+ # nested Hash.
27
+ #
28
+ # QuickStore::Store.instance.set('a', 'value')
29
+ # # => "value"
30
+ #
31
+ # QuickStore::Store.instance.set('a/b', 'value')
32
+ # # => { "c": "value" }
33
+ #
34
+ # QuickStore::Store.instance.set('a/b/c', 'value')
35
+ # # => { "b": { "c": "value" } }
36
+ def set(key, value)
37
+ keys = key.to_s.split(QuickStore.config.key_separator)
38
+ base_key = keys.shift
39
+
40
+ if keys.empty?
41
+ final_value = value
42
+ else
43
+ final_value = keys.reverse.inject(value) { |v, k| { k => v } }
44
+ end
45
+
46
+ old_value = get(base_key)
47
+
48
+ if old_value.is_a? Hash
49
+ updated_values = old_value ? old_value.deep_merge(final_value) : final_value
50
+ else
51
+ updated_values = final_value
52
+ end
53
+
54
+ @db.transaction { @db[base_key.to_s] = updated_values }
55
+ end
56
+
57
+ # Gets the value for the given key.
58
+ # If the value was saved for a key of structure "a/b/c" then the value is
59
+ # searched in a nested Hash, like: {"a"=>{"b"=>{"c"=>"value"}}}.
60
+ # If there is a value stored within a nested hash, it returns the appropriate
61
+ # Hash if a partial key is used.
62
+ #
63
+ # QuickStore::Store.instance.get('a')
64
+ # # => {"b"=>{"c"=>"value"}}
65
+ #
66
+ # QuickStore::Store.instance.get('a/b')
67
+ # # => {"c"=>"value"}
68
+ #
69
+ # QuickStore::Store.instance.get('a/b/c')
70
+ # # => "value"
71
+ def get(key)
72
+ keys = key.to_s.split(QuickStore.config.key_separator)
73
+ base_key = keys.shift
74
+
75
+ @db.transaction do
76
+ data = @db[base_key.to_s]
77
+
78
+ if data
79
+ keys.reduce(data) { |value, key| value ? value = value[key] : nil }
80
+ end
81
+ end
82
+ end
83
+
84
+ def self.get(key)
85
+ instance.get(key)
86
+ end
87
+
88
+ def self.set(key, value)
89
+ instance.set(key, value)
90
+ end
91
+
92
+ def self.file
93
+ instance.file
94
+ end
95
+
96
+ # Defines getter and setter methods for arbitrarily named methods.
97
+ #
98
+ # QuickStore::Store.answer = 42 # saves 'answer: 42' to the store
99
+ # # => 42
100
+ #
101
+ # QuickStore::Store.answer
102
+ # # => 42
103
+ def self.method_missing(method, *args, &block)
104
+ if method =~ /.*=$/
105
+ if singleton_methods.include?(method.to_s.chop.to_sym)
106
+ raise "There is a \"#{method.to_s.chop}\" instance method already " +
107
+ "defined. This will lead to problems while getting values " +
108
+ "from the store. Please use another key than " +
109
+ "#{singleton_methods.map(&:to_s)}."
110
+ end
111
+
112
+ instance.set(method.to_s.gsub(/=$/, ''), args[0])
113
+ elsif args.count == 0
114
+ instance.get(method)
115
+ else
116
+ super
117
+ end
118
+ end
119
+ end
120
+
121
+ end
@@ -0,0 +1,3 @@
1
+ module QuickStore
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,57 @@
1
+ require "quick_store/version"
2
+ require "quick_store/store"
3
+
4
+ module QuickStore
5
+
6
+ NO_FILE_PATH_CONFIGURED = "Please configure a file_path for your QuickStore!"
7
+
8
+ class << self
9
+ attr_accessor :configuration
10
+ end
11
+
12
+ # Configures the QuickStore::Store
13
+ #
14
+ # QuickStore.configure do |config|
15
+ # config.file_path = 'path/to/store/file.yml'
16
+ # config.key_separator = '|' # default is '/'
17
+ # end
18
+ def self.configure
19
+ yield(self.config)
20
+ raise(NO_FILE_PATH_CONFIGURED) unless self.config.file_path
21
+ self.config
22
+ end
23
+
24
+ # Returns the QuickStore::Configuration.
25
+ def self.config
26
+ self.configuration ||= Configuration.new
27
+ end
28
+
29
+ # Returns the QuickStore::Store.
30
+ # You can store and receive data from the store using different methods:
31
+ #
32
+ # # Using dynamic setters and getters
33
+ # QuickStore.store.arbitrary_key = 'value' # => "value"
34
+ # QuickStore.store.arbitrary_key # => "value"
35
+ #
36
+ # # Using the ::set and ::get methods
37
+ # QuickStore.store.set(:arbitrary_key, 'value') # => "value"
38
+ # QuickStore.store.get(:arbitrary_key) # => "value"
39
+ #
40
+ # # Example for a nested key ('/' is the default key separator)
41
+ # QuickStore.store.set('a/b/c', 'value') # => {"b"=>{"c"=>"value"}}
42
+ # QuickStore.store.get('a/b/c') # => "value"
43
+ # QuickStore.store.get('a/b') # => {"c"=>"value"}
44
+ # QuickStore.store.get('a') # => {"b"=>{"c"=>"value"}}
45
+ def self.store
46
+ QuickStore::Store
47
+ end
48
+
49
+ class Configuration
50
+ attr_accessor :key_separator, :file_path
51
+
52
+ def initialize
53
+ @key_separator = '/'
54
+ end
55
+ end
56
+
57
+ end
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'quick_store/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "quick_store"
8
+ spec.version = QuickStore::VERSION
9
+ spec.authors = ["Paul Götze"]
10
+ spec.email = ["paul.christoph.goetze@gmail.com"]
11
+ spec.summary = %q{Simple local key-value store based on YAML::Store.}
12
+ spec.description = %q{Simple local key-value store based on YAML::Store.}
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency "activesupport", "~> 4.0"
22
+
23
+ spec.add_development_dependency "bundler", "~> 1.7"
24
+ spec.add_development_dependency "rake", "~> 10.0"
25
+ spec.add_development_dependency "rspec", "~> 3.0"
26
+ end
@@ -0,0 +1,109 @@
1
+ require 'spec_helper'
2
+
3
+ describe QuickStore::Store do
4
+
5
+ subject { QuickStore::Store.send(:new) }
6
+
7
+ it { is_expected.to respond_to :get }
8
+ it { is_expected.to respond_to :set }
9
+ it { is_expected.to respond_to :file }
10
+
11
+ it "raises an error if used without a configured file_path" do
12
+ allow_any_instance_of(QuickStore::Configuration).to receive(:file_path) { nil }
13
+ expect { QuickStore::Store.send(:new) }.to raise_error
14
+ end
15
+
16
+ it "creates the store file in the given directory on access" do
17
+ QuickStore::Store.call_an_arbitrary_method
18
+ expect(File.exist?(file_path)).to be_truthy
19
+ end
20
+
21
+ it "allows setting arbitrary keys by setter methods" do
22
+ expect { QuickStore::Store.brownie = "brownie" }.not_to raise_error
23
+ end
24
+
25
+ it "allows getting subsequently set keys" do
26
+ QuickStore::Store.carrots = "carrots"
27
+ expect(QuickStore::Store.carrots).to eq "carrots"
28
+ end
29
+
30
+ it "returns nil for not set simple keys" do
31
+ expect(QuickStore::Store.hamburger).to be_nil
32
+ end
33
+
34
+ it "returns nil for not set nested keys" do
35
+ key = "pastries/muffins/savory"
36
+ expect(QuickStore::Store.get(key)).to be_nil
37
+ end
38
+
39
+ it "raises an method missing errror for non getter/setter methods" do
40
+ expect { QuickStore::Store.arbitrary_method(1, 2) }
41
+ .to raise_error NoMethodError
42
+ end
43
+
44
+ it "responds to ::get" do
45
+ expect(QuickStore::Store).to respond_to :get
46
+ end
47
+
48
+ it "responds to ::set" do
49
+ expect(QuickStore::Store).to respond_to :set
50
+ end
51
+
52
+ it "responds to ::file" do
53
+ expect(QuickStore::Store).to respond_to :file
54
+ end
55
+
56
+ describe "::get" do
57
+ it "returns the value of the given key" do
58
+ toast = 'toast'
59
+ QuickStore::Store.toast = toast
60
+ expect(QuickStore::Store.get(:toast)).to eq toast
61
+ end
62
+
63
+ it "gets the value hash for a given partly key" do
64
+ base_key = 'pastries'
65
+ second_key = 'muffins'
66
+ third_key = 'sweet'
67
+ key = "#{base_key}/#{second_key}/#{third_key}"
68
+ muffin = 'raspberry cream muffin'
69
+ hash = { second_key => { third_key => muffin } }
70
+
71
+ QuickStore::Store.set(key, muffin)
72
+ expect(QuickStore::Store.get(base_key)).to eq hash
73
+ end
74
+ end
75
+
76
+ describe "::set" do
77
+ it "sets the value for the given key" do
78
+ juice = 'orange juice'
79
+ QuickStore::Store.set(:juice, juice)
80
+ expect(QuickStore::Store.juice).to eq juice
81
+ end
82
+
83
+ it "sets the value for the given nested key" do
84
+ key = "pastries/muffins/sweet"
85
+ muffin = 'blueberry muffin'
86
+
87
+ QuickStore::Store.set(key, muffin)
88
+ expect(QuickStore::Store.get(key)).to eq muffin
89
+ end
90
+
91
+ it "sets the value for the given nested key" do
92
+ key = "pastries/muffins/sweet"
93
+ muffin = 'apple walnut muffin'
94
+
95
+ QuickStore::Store.set(key, muffin)
96
+ expect(QuickStore::Store.get(key)).to eq muffin
97
+ end
98
+ end
99
+
100
+ describe "::file" do
101
+ it "returns the storage file path" do
102
+ expect(QuickStore::Store.file).to eq QuickStore.config.file_path
103
+ end
104
+ end
105
+
106
+ it "raises an error if the related getter for a setter is already defined" do
107
+ expect { QuickStore::Store.clone = 'defined' }.to raise_error
108
+ end
109
+ end
@@ -0,0 +1,49 @@
1
+ require 'spec_helper'
2
+
3
+ describe QuickStore do
4
+
5
+ describe '::config' do
6
+ it "returns a QuickStore::Configuration instance" do
7
+ expect(QuickStore.config).to be_a QuickStore::Configuration
8
+ end
9
+ end
10
+
11
+ describe '::store' do
12
+ it "retuns the QuickStore::Store class" do
13
+ expect(QuickStore.store).to be QuickStore::Store
14
+ end
15
+
16
+ it "can be used to set values" do
17
+ expect { QuickStore.store.muffin = 'blueberry muffin' }.not_to raise_error
18
+ end
19
+ end
20
+
21
+ describe '::configure' do
22
+ it "allows passing in a block" do
23
+ expect { QuickStore.configure { |config| } }.not_to raise_error
24
+ end
25
+
26
+ it "allows setting the file_path" do
27
+ QuickStore.configure do |config|
28
+ config.file_path = file_path
29
+ end
30
+
31
+ expect(QuickStore.config.file_path).to eq file_path
32
+ end
33
+
34
+ it "allows setting the key_separator" do
35
+ QuickStore.configure do |config|
36
+ config.key_separator = '.'
37
+ end
38
+
39
+ expect(QuickStore.config.key_separator).to eq '.'
40
+ end
41
+
42
+ it "returns the QuickStore::Configuration" do
43
+ config = QuickStore.configure do |config|
44
+ end
45
+
46
+ expect(config).to be_a QuickStore::Configuration
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,21 @@
1
+ require 'rspec'
2
+
3
+ def require_files_from(paths = [])
4
+ paths.each do |path|
5
+ Dir[File.join(File.expand_path("#{path}*.rb", __FILE__))].sort.each do |file|
6
+ require file
7
+ end
8
+ end
9
+ end
10
+
11
+ RSpec.configure do |config|
12
+ config.color = true
13
+
14
+ require File.expand_path('../../lib/quick_store', __FILE__)
15
+ require_files_from ["../support/**/"]
16
+
17
+ config.include TestHelpers
18
+
19
+ config.before(:all) { use_test_store }
20
+ config.after(:all) { remove_test_files }
21
+ end
@@ -0,0 +1,17 @@
1
+ module TestHelpers
2
+
3
+ def file_path
4
+ File.expand_path('../../test_files/store.yml', __FILE__)
5
+ end
6
+
7
+ def use_test_store
8
+ QuickStore::Configuration.send(:new)
9
+ QuickStore.config.instance_variable_set(:@file_path, file_path)
10
+ QuickStore::Store.send(:new)
11
+ end
12
+
13
+ def remove_test_files
14
+ dir = File.dirname(file_path)
15
+ FileUtils.remove_dir(dir) if Dir.exist?(dir)
16
+ end
17
+ end
metadata ADDED
@@ -0,0 +1,116 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: quick_store
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Paul Götze
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-04-08 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '4.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '4.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.7'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.7'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '10.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '10.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '3.0'
69
+ description: Simple local key-value store based on YAML::Store.
70
+ email:
71
+ - paul.christoph.goetze@gmail.com
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - ".gitignore"
77
+ - Gemfile
78
+ - README.md
79
+ - Rakefile
80
+ - lib/quick_store.rb
81
+ - lib/quick_store/store.rb
82
+ - lib/quick_store/version.rb
83
+ - quick_store.gemspec
84
+ - spec/quick_store/store_spec.rb
85
+ - spec/quick_store_spec.rb
86
+ - spec/spec_helper.rb
87
+ - spec/support/macros/test_helpers.rb
88
+ homepage: ''
89
+ licenses:
90
+ - MIT
91
+ metadata: {}
92
+ post_install_message:
93
+ rdoc_options: []
94
+ require_paths:
95
+ - lib
96
+ required_ruby_version: !ruby/object:Gem::Requirement
97
+ requirements:
98
+ - - ">="
99
+ - !ruby/object:Gem::Version
100
+ version: '0'
101
+ required_rubygems_version: !ruby/object:Gem::Requirement
102
+ requirements:
103
+ - - ">="
104
+ - !ruby/object:Gem::Version
105
+ version: '0'
106
+ requirements: []
107
+ rubyforge_project:
108
+ rubygems_version: 2.4.3
109
+ signing_key:
110
+ specification_version: 4
111
+ summary: Simple local key-value store based on YAML::Store.
112
+ test_files:
113
+ - spec/quick_store/store_spec.rb
114
+ - spec/quick_store_spec.rb
115
+ - spec/spec_helper.rb
116
+ - spec/support/macros/test_helpers.rb