quick_store 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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