quandl_location 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ language: ruby
2
+ rvm:
3
+ - "1.9.2"
4
+ - "1.9.3"
5
+ script: bundle exec rspec
data/CHANGELOG.md ADDED
@@ -0,0 +1,9 @@
1
+ # quandl_location changelog
2
+
3
+ ## 0.1.1
4
+
5
+ * Update gemspec.
6
+
7
+ ## 0.1.0
8
+
9
+ * Initial release.
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in quandl_location.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Jason Byck
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,98 @@
1
+ # Quandl Location
2
+
3
+ [![Build Status](https://magnum.travis-ci.com/quandl/quandl_location.png?token=Jqe6yYPbokJgKw6u73eU&branch=master)](https://magnum.travis-ci.com/quandl/quandl_location)
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'quandl_location'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install quandl_location
18
+
19
+
20
+ ## About
21
+
22
+ quandl_location provides a getter/setter class to store key-value data, but abstracts the storage engine used to store the data.
23
+
24
+ Any supported storage engine can be configured at run time. Currently supports Redis and Unix file system.
25
+
26
+
27
+ ## Usage
28
+
29
+
30
+
31
+ #### Configure Redis storage
32
+
33
+ ``` ruby
34
+ Quandl::Location.use(:redis) do
35
+ with_options { host: localhost, port: 6379 }
36
+ end
37
+ ```
38
+ Redis storage takes two optional configuration settings: expiry and encoding.
39
+
40
+ For example:
41
+
42
+ ```yaml
43
+ production:
44
+ host: localhost
45
+ port: 6379
46
+ expiry: 3600
47
+ encoding: ASCII-8BIT
48
+ ```
49
+
50
+ This configuration will set a timeout of 1 day for each key in Redis created by Quandl::Location, and force the encoding for all retreived objects to 'ASCII-8BIT'.
51
+
52
+ There is no default expiry. If it is not included in configuration, then no timeout will be set for the created key.
53
+
54
+ If encoding is not included, retrieved data from Redis will be encoded with Encoding::default_external (which is default behaviour of the redis-rb gem).
55
+
56
+ #### Configure file system storage
57
+
58
+ ``` ruby
59
+ Quandl::Location.use(:file_system) do
60
+ with_options { data_dir: '/data/locations/' }
61
+ end
62
+ ```
63
+
64
+ File system stores location data using the location_id as the file name.
65
+
66
+ #### Save data
67
+
68
+ Creates new key, or overwrites existing key with new data.
69
+
70
+ ``` ruby
71
+ location_data = Quandl::Location::Data.find(location_id)
72
+ location_data.data = [1,2,3]
73
+ location_data.save
74
+ ```
75
+ #### Retrieve data
76
+
77
+ Returns the data, or returns nil if data does not exist.
78
+
79
+ ```ruby
80
+ raw_data = Quandl::Location::Data.find(location_id).data
81
+ ```
82
+
83
+ #### Check for data
84
+
85
+ Use exists? method to check if the data exits in the storage engine. The get method returns nil if exists? is false, so it is not necessary to check for existance before using get.
86
+
87
+ Quandl::Storage::Redis returns true if there is a key with value location_id, and Quandl::Storage::FileSystem returns true if there is a file present with name location_id.
88
+
89
+ ```ruby
90
+ location_data = Quandl::Location::Data.find(new_location_id)
91
+ location_data.exists?
92
+ => false
93
+ location_data.data = [1,2,3]
94
+ location_data.exists?
95
+ => false
96
+ location_data.save
97
+ location_data.exists?
98
+ => true
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,65 @@
1
+ require 'active_support/core_ext/hash'
2
+ require 'active_support/core_ext/object'
3
+ require 'active_support/core_ext/string/inflections'
4
+ require 'active_support/inflector'
5
+
6
+ require 'quandl/location/exceptions'
7
+ require 'quandl/location/data'
8
+ require 'quandl/location/storage'
9
+
10
+ module Quandl
11
+ module Location
12
+
13
+ STORAGE_ENGINES = [:redis, :file_system]
14
+
15
+ class << self
16
+
17
+ # The list of supported storage engines for locations
18
+ #
19
+ # Returns array
20
+ def storage_engines
21
+ STORAGE_ENGINES
22
+ end
23
+
24
+ # The name of the current active storage engine, or nil if not set
25
+ #
26
+ # Returns string or nil
27
+ def storage_engine_type
28
+ @@storage_engine_type || nil
29
+ end
30
+
31
+ # Set the storage engine for the location module
32
+ #
33
+ # Returns Quandl::Location::Storage
34
+ # Raises Quandl::Location::UnknownStorageEngineError
35
+ def use(storage_engine, &block)
36
+ unless storage_engines.include?(storage_engine.to_sym)
37
+ error_message = %Q{
38
+ Unknown storage engine #{storage_engine}.
39
+ Please use one of supported engines #{storage_engines.collect{|s| s.to_s}.join}
40
+ }
41
+ raise(Quandl::Location::UnknownStorageEngineError, error_message)
42
+ end
43
+ @@storage_engine_type = storage_engine
44
+ storage_engine_class = storage_engine.to_s.downcase.camelize
45
+ @@storage_engine = "Quandl::Location::Storage::#{storage_engine_class}".constantize.new
46
+ @@storage_engine.instance_eval(&block) if block_given?
47
+ end
48
+
49
+
50
+ # The intance of the Storage class that was configured
51
+ #
52
+ # Returns Quandl::Location::Storage
53
+ # Raises Quandl::Location::UninitializedStorageEngineError
54
+ def storage_engine
55
+ unless @@storage_engine.present?
56
+ raise(Quandl::Location::UninitializedStorageEngineError, "You must configure a valid storage engine.")
57
+ end
58
+ @@storage_engine
59
+ end
60
+
61
+ end
62
+
63
+ end
64
+ end
65
+
@@ -0,0 +1,77 @@
1
+ module Quandl
2
+ module Location
3
+ class Data
4
+
5
+ class << self
6
+
7
+ # Create a new location data instance
8
+ #
9
+ # id - The location id
10
+ #
11
+ # Returns Quandl::Location::Data
12
+ def find(id)
13
+ self.new(id)
14
+ end
15
+
16
+ end
17
+
18
+ attr_accessor :id, :data
19
+
20
+ # Constructor
21
+ #
22
+ # Returns Quandl::Location::Data
23
+ def initialize(*args)
24
+ self.id = args.first
25
+ end
26
+
27
+ # Set the data for the location, through the storage engine
28
+ #
29
+ # data - The raw location data as a string
30
+ #
31
+ # Returns .
32
+ def data=(data)
33
+ @raw_data = data
34
+ @data_changed = true
35
+ end
36
+
37
+ # Get the location data, through the storage engine
38
+ #
39
+ # Returns string
40
+ def data
41
+ storage.get(id)
42
+ end
43
+
44
+ # Has the raw data changed
45
+ #
46
+ # Return boolean
47
+ def changed?
48
+ @data_changed == true
49
+ end
50
+
51
+ # Save the raw_data that was set through data=
52
+ #
53
+ # Returns boolean
54
+ def save
55
+ return false unless @data_changed
56
+ storage.set(id, @raw_data)
57
+ end
58
+
59
+ # Check if data exists in storage engine
60
+ #
61
+ # Return boolean
62
+ def exists?
63
+ storage.exists?(id)
64
+ end
65
+
66
+ protected
67
+
68
+ # Access to currently configured storage engine
69
+ #
70
+ # Returns Quandl::Location::Storage
71
+ def storage
72
+ @storage ||= Quandl::Location.storage_engine
73
+ end
74
+
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,24 @@
1
+ module Quandl
2
+ module Location
3
+
4
+ # Unknown storage engine
5
+ class UnknownStorageEngineError < RuntimeError; end
6
+
7
+ # Storage not initialized
8
+ class UninitializedStorageEngineError < RuntimeError; end
9
+
10
+ # Storage options
11
+ class InvalidStorageOptionsError < RuntimeError; end
12
+
13
+ # Storage engine not complete
14
+ class IncompleteStorageEngineError < RuntimeError; end
15
+
16
+ # Locaiton data not present when expected
17
+ class MissingLocationDataError < RuntimeError; end
18
+
19
+ # Bad storage configuration
20
+ class StorageConfigurationError < RuntimeError; end
21
+
22
+
23
+ end
24
+ end
@@ -0,0 +1,48 @@
1
+ module Quandl
2
+ module Location
3
+
4
+ class Storage
5
+
6
+ # Auto assign storage options from configuration
7
+ #
8
+ # storage_options - A hash of key value options to configure the storage engine
9
+ #
10
+ # Return nil
11
+ def with_options(storage_options)
12
+ unless storage_options.present? and storage_options.kind_of?(Hash)
13
+ raise(Quandl::Location::InvalidStorageOptionsError, "Storage options must be present and kind of Hash")
14
+ end
15
+ storage_options.collect do |k,v|
16
+ self.send("#{k}=", v) if self.respond_to?("#{k}=")
17
+ end
18
+ end
19
+
20
+ # Get the data from the storage engine
21
+ # This is a method stub that raises an error unless get has been implemented in the child class.
22
+ #
23
+ # Raises Quandl::Location::IncompleteStorageEngineError
24
+ def get
25
+ raise(Quandl::Location::IncompleteStorageEngineError, "get method must be implemented in class.")
26
+ end
27
+
28
+ # Set the data in the storage engine
29
+ # This is a method stub that raises an error unless set has been implemented in the child class.
30
+ #
31
+ # Raises Quandl::Location::IncompleteStorageEngineError
32
+ def set
33
+ raise(Quandl::Location::IncompleteStorageEngineError, "set method must be implemented in class.")
34
+ end
35
+
36
+ # Check if the location_id exists in the storage engine
37
+ # This is a method stub that raises an error unless set has been implemented in the child class.
38
+ def exists?
39
+ raise(Quandl::Location::IncompleteStorageEngineError, "exists? method must be implemented in class.")
40
+ end
41
+
42
+ end
43
+
44
+ end
45
+ end
46
+
47
+ require 'quandl/location/storage/file_system'
48
+ require 'quandl/location/storage/redis'
@@ -0,0 +1,43 @@
1
+ module Quandl
2
+ module Location
3
+
4
+ class Storage::FileSystem < Storage
5
+
6
+ attr_accessor :data_dir
7
+
8
+ def get(location_id)
9
+ return nil unless self.exists?(location_id)
10
+ file = File.open(location_file_name(location_id), 'rb')
11
+ file.read
12
+ end
13
+
14
+ def set(location_id, data)
15
+ ensure_file_location_exists(location_id)
16
+ File.open(location_file_name(location_id), 'w') { |file| file.write(data) }
17
+ true
18
+ end
19
+
20
+ def exists?(location_id)
21
+ File.exists?(location_file_name(location_id))
22
+ end
23
+
24
+ protected
25
+
26
+ def ensure_file_location_exists(location_id)
27
+ FileUtils.mkdir_p location_directory
28
+ FileUtils.touch location_file_name(location_id.to_s)
29
+ end
30
+
31
+ def location_directory
32
+ @location_directory ||= ::File.join(data_dir, 'location')
33
+ end
34
+
35
+ def location_file_name(location_id)
36
+ File.join(location_directory, location_id.to_s)
37
+ end
38
+
39
+ end
40
+
41
+
42
+ end
43
+ end
@@ -0,0 +1,81 @@
1
+ require 'redis'
2
+
3
+ module Quandl
4
+ module Location
5
+
6
+ class Storage::Redis < Storage
7
+
8
+ attr_accessor :host, :port, :expiry, :encoding
9
+
10
+ # Retrieve the Redis store location id
11
+ #
12
+ # Returns string
13
+ def get(location_id)
14
+ data = connection.get location_id
15
+ data.force_encoding(encoding) if encodable?
16
+ data
17
+ end
18
+
19
+ # Save the data to Redis key location_id
20
+ # If Storage::Redis instance has expiry setting, then set expire time for the location
21
+ #
22
+ # Returns boolean
23
+ def set(location_id, data)
24
+ connection.set location_id, data
25
+ connection.expire(location_id, expiry) if expirable?
26
+ true
27
+ end
28
+
29
+ # Check if key exists in Redis
30
+ #
31
+ # location_id - The Redis key to
32
+ #
33
+ # Returns boolean
34
+ def exists?(location_id)
35
+ connection.exists location_id
36
+ end
37
+
38
+ # Establish a connection to redis
39
+ #
40
+ # Returns boolean
41
+ def connect
42
+ connection
43
+ return true
44
+ end
45
+
46
+ protected
47
+
48
+ # Determines if Storage instance is configured to override default encoding
49
+ #
50
+ # Returns boolean
51
+ def encodable?
52
+ self.encoding.present? and self.encoding.kind_of?(String)
53
+ end
54
+
55
+ # Determines if the Storage instance is configured to set TTL for keys
56
+ #
57
+ # Returns boolean
58
+ def expirable?
59
+ self.expiry.present? and self.expiry.kind_of?(Fixnum)
60
+ end
61
+
62
+ # Return a Redis connection
63
+ #
64
+ # Returns Redis::Client
65
+ # Raises Quandl::Location::StorageConfigurationError
66
+ def connection
67
+ unless @connection
68
+ unless host.present? and port.present?
69
+ raise(Quandl::Location::StorageConfigurationError, "Redis port and host required.")
70
+ end
71
+ @connection = ::Redis.new(host: host, port: port)
72
+ end
73
+ @connection
74
+ end
75
+
76
+ end
77
+
78
+
79
+
80
+ end
81
+ end
@@ -0,0 +1,5 @@
1
+ module Quandl
2
+ module Location
3
+ VERSION = "0.1.1"
4
+ end
5
+ end
@@ -0,0 +1,28 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'quandl/location/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "quandl_location"
8
+ spec.version = Quandl::Location::VERSION
9
+ spec.authors = ["Jason Byck"]
10
+ spec.email = ["jasonbyck@gmail.com"]
11
+ spec.description = %q{Provides a library for accessing data from arbitrary key-value storage}
12
+ spec.summary = %q{Abstracted key value storage library}
13
+ spec.homepage = "https://github.com/quandl/quandl_location"
14
+
15
+ spec.files = `git ls-files`.split($/)
16
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
17
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
18
+ spec.require_paths = ["lib"]
19
+
20
+ spec.add_development_dependency "bundler", "~> 1.3"
21
+ spec.add_development_dependency 'rspec'
22
+ spec.add_development_dependency "rake"
23
+ spec.add_development_dependency "pry"
24
+ spec.add_development_dependency "fakeredis"
25
+
26
+ spec.add_runtime_dependency "redis"
27
+ spec.add_runtime_dependency "activesupport", "~> 3"
28
+ end
@@ -0,0 +1,101 @@
1
+ require 'spec_helper'
2
+
3
+ describe Quandl::Location::Data do
4
+
5
+ let(:location_id) { (1..1000).to_a.sample }
6
+ let(:fake_data) { (0...8).map { (65 + rand(26)).chr }.join }
7
+ let(:data_object) { Quandl::Location::Data.new(location_id) }
8
+ let(:storage_mock) { storage_double = double('Quandl::Location::Storage') }
9
+
10
+ # Mock the storage implentation
11
+ before(:each) do
12
+ Quandl::Location::Data.any_instance.stub(:storage).and_return(storage_mock)
13
+ end
14
+
15
+ describe '#find' do
16
+
17
+ it 'should return a new Quandl::Location::Data instance' do
18
+ Quandl::Location::Data.find(230).should be_kind_of(Quandl::Location::Data)
19
+ end
20
+
21
+ end
22
+
23
+ describe '#data=' do
24
+
25
+ before(:each) do
26
+ data_object.data = fake_data
27
+ end
28
+
29
+ it 'assign the data to be saved as raw_data' do
30
+ data_object.instance_variable_get(:@raw_data).should be fake_data
31
+ end
32
+
33
+ it 'should mark the data as changed' do
34
+ data_object.changed?.should be true
35
+ end
36
+
37
+ end
38
+
39
+ describe '#changed?' do
40
+
41
+ subject { data_object }
42
+
43
+ context 'data has been set' do
44
+
45
+ before(:each) { subject.data = fake_data }
46
+
47
+ its(:changed?) { should be true }
48
+
49
+ end
50
+
51
+ context 'data has not been set' do
52
+
53
+ its(:changed?) { should be false }
54
+
55
+ end
56
+
57
+ end
58
+
59
+ describe '#data' do
60
+
61
+ it 'should request the data through the storage engine' do
62
+ storage_mock.should_receive(:get).with(location_id)
63
+ data_object.data
64
+ end
65
+
66
+ end
67
+
68
+ describe '#save' do
69
+
70
+ context 'data is ready to be saved' do
71
+
72
+ before(:each) { data_object.data = fake_data }
73
+
74
+ it 'should persist data through the storage engine' do
75
+ storage_mock.should_receive(:set).with(location_id, fake_data)
76
+ data_object.save
77
+ end
78
+
79
+ end
80
+
81
+ context 'data is not ready to be saved' do
82
+
83
+ it 'should return false' do
84
+ data_object.save.should be false
85
+ end
86
+
87
+ end
88
+
89
+
90
+ end
91
+
92
+ describe '#exists?' do
93
+
94
+ it 'should return status through storage engine' do
95
+ storage_mock.should_receive(:exists?).with(location_id)
96
+ data_object.exists?
97
+ end
98
+
99
+ end
100
+
101
+ end
@@ -0,0 +1,90 @@
1
+ require 'spec_helper'
2
+
3
+ describe Quandl::Location::Storage::FileSystem do
4
+
5
+ let(:data_dir) { '/etc/data' }
6
+ let(:location_id) { (1..1000).to_a.sample }
7
+ let(:fake_data) { (0...8).map { (65 + rand(26)).chr }.join }
8
+ let(:file_storage) do
9
+ f = Quandl::Location::Storage::FileSystem.new
10
+ f.with_options({ data_dir: data_dir })
11
+ f
12
+ end
13
+
14
+ it { should respond_to(:data_dir) }
15
+
16
+ before(:each) do
17
+ FileUtils.stub(:touch).and_return(true)
18
+ FileUtils.stub(:mkdir_p).and_return(true)
19
+ File.stub(:open).and_return(double('File'))
20
+ end
21
+
22
+ describe '#set' do
23
+
24
+ it 'should ensure the file location exists before writing data' do
25
+ FileUtils.should_receive(:touch).once
26
+ file_storage.set(location_id, fake_data)
27
+ end
28
+
29
+ it 'should return true if successful' do
30
+ file_storage.set(location_id, fake_data).should be true
31
+ end
32
+
33
+ end
34
+
35
+ describe '#exists?' do
36
+
37
+ context 'location file exists' do
38
+
39
+ before(:each) { File.stub(:exists?).and_return(true) }
40
+
41
+ it 'should return true' do
42
+ file_storage.exists?(location_id).should be true
43
+ end
44
+
45
+ end
46
+
47
+ context 'location file does not exist' do
48
+
49
+ before(:each) { File.stub(:exists?).and_return(false) }
50
+
51
+ it 'should return false' do
52
+ File.stub(:exists?).and_return(false)
53
+ file_storage.exists?(location_id).should be false
54
+ end
55
+
56
+ end
57
+
58
+ end
59
+
60
+ describe '#get' do
61
+
62
+ context 'location file exists' do
63
+
64
+ before(:each) do
65
+ File.stub(:exists?).and_return(true)
66
+ Object.any_instance.stub(:read).and_return(fake_data)
67
+ end
68
+
69
+ it 'should return the saved location data' do
70
+ file_storage.get(location_id).should be fake_data
71
+ end
72
+
73
+ end
74
+
75
+ context 'location file does not exist' do
76
+
77
+ before(:each) do
78
+ File.stub(:exists?).and_return(false)
79
+ end
80
+
81
+ it 'should return nil' do
82
+ file_storage.get(location_id).should be nil
83
+ end
84
+
85
+ end
86
+
87
+ end
88
+
89
+ end
90
+
@@ -0,0 +1,120 @@
1
+ require 'spec_helper'
2
+
3
+ describe Quandl::Location::Storage::Redis do
4
+
5
+ let(:redis_storage) do
6
+ r = Quandl::Location::Storage::Redis.new
7
+ r.with_options(host: 'localhost', port: 6379)
8
+ r
9
+ end
10
+
11
+ let(:redis_storage_expiry) do
12
+ r = Quandl::Location::Storage::Redis.new
13
+ r.with_options(host: 'localhost', port: 6379, expiry: 1)
14
+ r
15
+ end
16
+
17
+ let(:redis_storage_encoding) do
18
+ r = Quandl::Location::Storage::Redis.new
19
+ r.with_options(host: 'localhost', port: 6379, encoding: 'ASCII-8BIT')
20
+ r
21
+ end
22
+
23
+
24
+ let(:location_id) { (1..1000).to_a.sample }
25
+ let(:fake_data) { (0...8).map { (65 + rand(26)).chr }.join }
26
+
27
+ it { should respond_to(:host) }
28
+ it { should respond_to(:port) }
29
+
30
+
31
+ describe '#get' do
32
+
33
+ it 'should fetch data from Redis' do
34
+ Redis.any_instance.should_receive(:get)
35
+ redis_storage.get(location_id)
36
+ end
37
+
38
+ it 'should return data saved to a location' do
39
+ redis_storage.set(location_id, fake_data)
40
+ redis_storage.get(location_id).should eq fake_data
41
+ end
42
+
43
+ context 'encoding is configured' do
44
+
45
+ it 'should use force encoding from configuration' do
46
+ redis_storage_encoding.set(location_id, fake_data)
47
+ redis_storage_encoding.get(location_id).encoding.name.should eq redis_storage_encoding.encoding
48
+ end
49
+
50
+ end
51
+
52
+ end
53
+
54
+ describe '#exists?' do
55
+
56
+ context 'key is present in Redis' do
57
+
58
+ before(:each) { Redis.any_instance.stub(:exists).and_return(true) }
59
+
60
+ it 'should return true' do
61
+ redis_storage.exists?(location_id).should be true
62
+ end
63
+
64
+ end
65
+
66
+ context 'key is not present in Redis' do
67
+
68
+ before(:each) { Redis.any_instance.stub(:exists).and_return(false) }
69
+
70
+ it 'should return false' do
71
+ redis_storage.exists?(location_id).should be false
72
+ end
73
+
74
+ end
75
+
76
+ end
77
+
78
+ describe '#set' do
79
+
80
+ it 'should persit the data to Redis' do
81
+ Redis.any_instance.should_receive(:set)
82
+ redis_storage.set(location_id, fake_data)
83
+ end
84
+
85
+ it 'should return true if save was successful' do
86
+ redis_storage.set(location_id, fake_data).should be true
87
+ end
88
+
89
+ it 'should set expiry time if option present' do
90
+ Redis.any_instance.should_receive(:expire)
91
+ redis_storage_expiry.set(location_id, fake_data)
92
+ end
93
+
94
+ it 'should not set expiry time if expiry option is not present' do
95
+ Redis.any_instance.should_not_receive(:expire)
96
+ redis_storage.set(location_id, fake_data)
97
+ end
98
+
99
+
100
+ end
101
+
102
+
103
+ describe '#connect' do
104
+
105
+ it 'should raise an error unless host and port are present' do
106
+ r = Quandl::Location::Storage::Redis.new
107
+ expect { r.connect }.to raise_error
108
+ r.host = 'test'
109
+ expect { r.connect }.to raise_error
110
+ r.host = nil
111
+ r.port = 'test'
112
+ expect { r.connect }.to raise_error
113
+ r.host = 'test'
114
+ expect { r.connect }.not_to raise_error
115
+ end
116
+
117
+
118
+ end
119
+
120
+ end
@@ -0,0 +1,43 @@
1
+ require 'spec_helper'
2
+
3
+ describe Quandl::Location::Storage do
4
+
5
+ let(:storage) { Quandl::Location::Storage.new }
6
+
7
+ describe '#get' do
8
+
9
+ it 'should raise exception for incomplete implementation' do
10
+ expect { storage.get }.to raise_error
11
+ end
12
+
13
+ end
14
+
15
+ describe '#exists?' do
16
+
17
+ it 'should raiser for incomplete implentation' do
18
+ expect { storage.exists? }.to raise_error
19
+ end
20
+
21
+ end
22
+
23
+ describe '#set' do
24
+
25
+ it 'should raise exception for incomplete implementation' do
26
+ expect { storage.set }.to raise_error
27
+ end
28
+
29
+ end
30
+
31
+ describe '#with_options' do
32
+
33
+ context 'storage options not provided' do
34
+
35
+ it 'should raise exception' do
36
+ expect { storage.with_options }.to raise_error
37
+ end
38
+
39
+ end
40
+
41
+ end
42
+
43
+ end
@@ -0,0 +1,61 @@
1
+ require 'spec_helper'
2
+
3
+ describe Quandl::Location do
4
+
5
+ before(:each) do
6
+ # Clear class variables between tests
7
+ Quandl::Location.class_variable_set(:@@storage_engine, nil)
8
+ Quandl::Location.class_variable_set(:@@storage_engine_type, nil)
9
+ end
10
+
11
+ let(:valid_storage_engine) { Quandl::Location::storage_engines.sample }
12
+
13
+ describe '#storage_engines' do
14
+
15
+ it 'should return the supported storage engines' do
16
+ Quandl::Location.storage_engines.should be Quandl::Location::STORAGE_ENGINES
17
+ end
18
+
19
+ end
20
+
21
+ describe '#use' do
22
+
23
+ it 'it should raise an error for unsupported storage engines' do
24
+ expect { Quandl::Location.use(:quandl_fake_storage) }.to raise_error
25
+ end
26
+
27
+ it 'should allow supported storage engines' do
28
+ Quandl::Location.storage_engines.each do |engine|
29
+ expect { Quandl::Location.use(engine) }.not_to raise_error
30
+ end
31
+ end
32
+
33
+ it 'should send provided block as configuration to Storage instance' do
34
+ Quandl::Location::Storage.any_instance.should_receive(:my_configuration_function)
35
+ Quandl::Location.use(valid_storage_engine) { my_configuration_function }
36
+ end
37
+
38
+ end
39
+
40
+ describe '#storage_engine' do
41
+
42
+ context 'a storage engine has been initialized' do
43
+
44
+ it 'should raise an error' do
45
+ expect { Quandl::Location.storage_engine }.to raise_error
46
+ end
47
+
48
+ end
49
+
50
+ context 'a storage engine has not been initialized' do
51
+
52
+ it 'should not raise an error' do
53
+ Quandl::Location.use(valid_storage_engine)
54
+ expect { Quandl::Location.storage_engine }.not_to raise_error
55
+ end
56
+
57
+ end
58
+
59
+ end
60
+
61
+ end
File without changes
@@ -0,0 +1,18 @@
1
+ $LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + "../lib")
2
+
3
+ # Testing
4
+ require 'rspec'
5
+ require 'fakeredis/rspec'
6
+
7
+ # Application
8
+ require 'quandl/location'
9
+
10
+ # Configure RSpec
11
+ RSpec.configure do |config|
12
+
13
+ config.treat_symbols_as_metadata_keys_with_true_values = true
14
+ config.formatter = :documentation
15
+ config.tty = true
16
+ config.color_enabled = true
17
+
18
+ end
@@ -0,0 +1,2 @@
1
+ test:
2
+ data_dir: '/data/dir'
@@ -0,0 +1,4 @@
1
+ test:
2
+ host: 127.0.0.1
3
+ port: 5959
4
+
metadata ADDED
@@ -0,0 +1,190 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: quandl_location
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Jason Byck
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-10-21 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: bundler
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '1.3'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: '1.3'
30
+ - !ruby/object:Gem::Dependency
31
+ name: rspec
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: rake
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ - !ruby/object:Gem::Dependency
63
+ name: pry
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ - !ruby/object:Gem::Dependency
79
+ name: fakeredis
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ type: :development
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ - !ruby/object:Gem::Dependency
95
+ name: redis
96
+ requirement: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ! '>='
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ type: :runtime
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ - !ruby/object:Gem::Dependency
111
+ name: activesupport
112
+ requirement: !ruby/object:Gem::Requirement
113
+ none: false
114
+ requirements:
115
+ - - ~>
116
+ - !ruby/object:Gem::Version
117
+ version: '3'
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ none: false
122
+ requirements:
123
+ - - ~>
124
+ - !ruby/object:Gem::Version
125
+ version: '3'
126
+ description: Provides a library for accessing data from arbitrary key-value storage
127
+ email:
128
+ - jasonbyck@gmail.com
129
+ executables: []
130
+ extensions: []
131
+ extra_rdoc_files: []
132
+ files:
133
+ - .gitignore
134
+ - .travis.yml
135
+ - CHANGELOG.md
136
+ - Gemfile
137
+ - LICENSE.txt
138
+ - README.md
139
+ - Rakefile
140
+ - lib/quandl/location.rb
141
+ - lib/quandl/location/data.rb
142
+ - lib/quandl/location/exceptions.rb
143
+ - lib/quandl/location/storage.rb
144
+ - lib/quandl/location/storage/file_system.rb
145
+ - lib/quandl/location/storage/redis.rb
146
+ - lib/quandl/location/version.rb
147
+ - quandl_location.gemspec
148
+ - spec/quandl/location/data_spec.rb
149
+ - spec/quandl/location/storage/file_system_spec.rb
150
+ - spec/quandl/location/storage/redis_spec.rb
151
+ - spec/quandl/location/storage_spec.rb
152
+ - spec/quandl/location_spec.rb
153
+ - spec/quandl/support/fake_redis.rb
154
+ - spec/spec_helper.rb
155
+ - spec/support/config/file_storage.yml
156
+ - spec/support/config/redis.yml
157
+ homepage: https://github.com/quandl/quandl_location
158
+ licenses: []
159
+ post_install_message:
160
+ rdoc_options: []
161
+ require_paths:
162
+ - lib
163
+ required_ruby_version: !ruby/object:Gem::Requirement
164
+ none: false
165
+ requirements:
166
+ - - ! '>='
167
+ - !ruby/object:Gem::Version
168
+ version: '0'
169
+ required_rubygems_version: !ruby/object:Gem::Requirement
170
+ none: false
171
+ requirements:
172
+ - - ! '>='
173
+ - !ruby/object:Gem::Version
174
+ version: '0'
175
+ requirements: []
176
+ rubyforge_project:
177
+ rubygems_version: 1.8.23
178
+ signing_key:
179
+ specification_version: 3
180
+ summary: Abstracted key value storage library
181
+ test_files:
182
+ - spec/quandl/location/data_spec.rb
183
+ - spec/quandl/location/storage/file_system_spec.rb
184
+ - spec/quandl/location/storage/redis_spec.rb
185
+ - spec/quandl/location/storage_spec.rb
186
+ - spec/quandl/location_spec.rb
187
+ - spec/quandl/support/fake_redis.rb
188
+ - spec/spec_helper.rb
189
+ - spec/support/config/file_storage.yml
190
+ - spec/support/config/redis.yml