Skip to content

Commit

Permalink
Merge pull request #3 from 0exp/feature/configuration-layer
Browse files Browse the repository at this point in the history
[gem] Configuration layer
  • Loading branch information
0exp committed Aug 30, 2018
2 parents 9383ae1 + f874245 commit 699a680
Show file tree
Hide file tree
Showing 26 changed files with 490 additions and 77 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Changelog
All notable changes to this project will be documented in this file.

## [Unreleased]
- configuration layer `AnyCache.configure`: an ability to choose and configure a necessary cache client
without any explicit client object instantiation (client object will be instantiated implicitly);

## [0.1.0] - 2018-08-26
- Release :)
161 changes: 159 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,17 @@ require 'any_cache'
## Usage / Table of Contents

- [Creation](#creation)
- **Operations**
- [Manual creation](#manual-creation)
- [Config-based creation](#config-based-creation)
- [AnyCache with Redis](#anycache-with-redis)
- [AnyCache with Redis::Store](#anycache-with-redisstore)
- [AnyCache with Dalli::Client](#anycache-with-dalliclient)
- [AnyCache with ActiveSupport::Cache::FileStore](#anycache-with-activesupportcachefilestore)
- [AnyCache with ActiveSupport::Cache::MemoryStore](#anycache-with-activesupportcachememorystore)
- [AnyCache with ActiveSupport::Cache::RedisCacheStore](#anycache-with-activesupportcacherediscachestore)
- [Many cache storages](#many-cache-storages)
- [Custom cache clients](#custom-cache-clients)
- [Operations](#operations)
- [Read](#read)
- [Write](#write)
- [Delete](#delete)
Expand All @@ -51,6 +61,7 @@ require 'any_cache'

To instantiate AnyCache instance you have to provide a client.
Client - an independent driver that works with a corresponding cache storage (external dependency).

Supported clients:

- `Redis`
Expand All @@ -60,7 +71,14 @@ Supported clients:
- `ActiveSupport::Cache::FileStore`
- `ActiveSupport::Cache::MemoryStore`

`AnyCache` instantiation:
`AnyCache` can be instantiated by two ways:

- with explicit client object instantiated manually;
- via configuration;

#### Manual creation

Custom instantiation with explicit client objects:

```ruby
# 1) create client object
Expand All @@ -80,6 +98,114 @@ client = ActiveSupport::Cache::MemoryStore.new(...)
any_cache = AnyCache.build(client) # => <AnyCache:0x00007f990527f268 ...>
```

#### Config-based creation

You can configure `AnyCache` globally or create subclasses and configure each of them. After that
storage instantiation works via `.build` method without explicit attributes.

- `AnyCache.configure` is used for configuration;
- `config.driver` is used for determine which client should be used;
- `config.__driver_name__.options` stores client-related options;

Supported drivers:

- `:redis` - Redis;
- `:redis_tore` - Redis::Client;
- `:dalli` - Dalli::Client
- `:as_redis_cache_store` - ActiveSupport::Cache::RedisCacheStore;
- `:as_file_store` - ActiveSupport::Cache::FileStore;
- `:as_memory_store` - ActiveSupport::Cache::MemoryStore;

##### `AnyCache` with `Redis`:

```ruby
AnyCache.configure do |conf|
conf.driver = :redis
conf.redis.options = { ... } # Redis-related options
end

AnyCache.build
```

##### `AnyCache` with `Redis::Store`:

```ruby
AnyCache.configure do |conf|
conf.driver = :redis_store
conf.redis_store.options = { ... } # Redis::Store-related options
end

AnyCache.build
```

##### `AnyCache` with `Dalli::Client`:

```ruby
AnyCache.configure do |conf|
conf.driver = :dalli
conf.dalli.options = { ... } # Dalli::Client-related options
end

AnyCache.build
```

##### `AnyCache` with `ActiveSupport::Cache::FileStore`:

```ruby
AnyCache.configure do |conf|
conf.driver = :as_file_store
conf.as_file_store.cache_path = '/path/to/cache'
conf.as_file_store.options = { ... } # ActiveSupport::Cache::FileStore-related options
end

AnyCache.build
```

##### `AnyCache` with `ActiveSupport::Cache::MemoryStore`:

```ruby
AnyCache.configure do |conf|
conf.driver = :as_memory_store
conf.as_memory_store.options = { ... } # ActiveSupport::Cache::MemoryStore-related options
end

AnyCache.build
```

##### `AnyCache` with `ActiveSupport::Cache::RedisCacheStore`:

```ruby
AnyCache.configure do |conf|
conf.driver = :as_redis_cache_store
conf.as_redis_cache_store.options = { ... } # ActiveSupport::Cache::RedisCacheStore-related options
end

AnyCache.build
```

#### Many cache storages

You can inherit `AnyCache` class and create and configure as many cache storages as you want:

```ruby
class RedisCache < AnyCache
configure do |conf|
conf.driver = :redis
end
end

class DalliCache < AnyCache
configure do |conf|
conf.driver = :dalli
end
end

redis_cache = RedisCache.build
dalli_cache = DalliCache.build
```

#### Custom cache clients

If you want to use your own cache client implementation, you should provide an object that responds to:

- `#read(key, [**options])` ([doc](#read))
Expand All @@ -91,6 +217,37 @@ If you want to use your own cache client implementation, you should provide an o
- `#persist(key, [**options])` ([doc](#persist))
- `#clear([**options])` ([doc](#clear))

```ruby
class MyCacheClient
# ...

def read
# ...
end

def write
# ...
end

# ...
end

AnyCache.build(MyCacheClient.new)
```

## Operations

`AnyCache` provides a following operation set:

- [read](#read)
- [write](#write)
- [delete](#delete)
- [increment](#increment)
- [decrement](#decrement)
- [expire](#expire)
- [persist](#persist)
- [clear](#clear)

---

### Read
Expand Down
4 changes: 2 additions & 2 deletions any_cache.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,13 @@ Gem::Specification.new do |spec|
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(spec|features)/}) }
end

spec.add_dependency 'concurrent-ruby', '~> 1.0'
spec.add_dependency 'concurrent-ruby', '~> 1.0'
spec.add_development_dependency 'qonfig', '~> 0.6'

spec.add_development_dependency 'coveralls', '~> 0.8'
spec.add_development_dependency 'simplecov', '~> 0.16'
spec.add_development_dependency 'armitage-rubocop', '~> 0.6'
spec.add_development_dependency 'rspec', '~> 3.8'
spec.add_development_dependency 'qonfig', '~> 0.6'

spec.add_development_dependency 'bundler'
spec.add_development_dependency 'rake'
Expand Down
5 changes: 1 addition & 4 deletions bin/rspec
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,7 @@ module AnyCacheSpecRunner
extend self

def expand_gemfile_path(gemfile_name)
File.expand_path(
File.join('..', '..', 'gemfiles', gemfile_name),
Pathname.new(__FILE__).realpath
)
File.expand_path(File.join('..', 'gemfiles', gemfile_name), __dir__)
end

GEMFILES = {
Expand Down
38 changes: 37 additions & 1 deletion lib/any_cache.rb
Original file line number Diff line number Diff line change
@@ -1,24 +1,60 @@
# frozen_string_literal: true

require 'qonfig'
require 'securerandom'
require 'concurrent/atomic/reentrant_read_write_lock'

# @api public
# @since 0.1.0
class AnyCache
require_relative 'any_cache/version'
require_relative 'any_cache/drivers'
require_relative 'any_cache/adapters'

# @since 0.1.0
extend Forwardable

# @since 0.2.0
include Qonfig::Configurable

# @since 0.2.0
configuration do
setting :driver

setting :redis do
setting :options, {}
end

setting :redis_store do
setting :options, {}
end

setting :dalli do
setting :servers, nil
setting :options, {}
end

setting :as_file_store do
setting :cache_path
setting :options, {}
end

setting :as_memory_store do
setting :options, {}
end

setting :as_redis_cache_store do
setting :options, {}
end
end

class << self
# @param driver [Object]
# @return [AnyCache]
#
# @api private
# @since 0.1.0
def build(driver)
def build(driver = Drivers.build(config))
new(Adapters.build(driver))
end
end
Expand Down
3 changes: 1 addition & 2 deletions lib/any_cache/adapters/active_support_file_store.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,7 @@ class << self
# @api private
# @since 0.1.0
def supported_driver?(driver)
defined?(::ActiveSupport::Cache::FileStore) &&
driver.is_a?(::ActiveSupport::Cache::FileStore)
AnyCache::Drivers::ActiveSupportFileStore.supported_source?(driver)
end
end
end
Expand Down
3 changes: 1 addition & 2 deletions lib/any_cache/adapters/active_support_memory_store.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,7 @@ class << self
# @api private
# @since 0.1.0
def supported_driver?(driver)
defined?(::ActiveSupport::Cache::MemoryStore) &&
driver.is_a?(::ActiveSupport::Cache::MemoryStore)
AnyCache::Drivers::ActiveSupportMemoryStore.supported_source?(driver)
end
end
end
Expand Down
4 changes: 1 addition & 3 deletions lib/any_cache/adapters/active_support_redis_cache_store.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,7 @@ class << self
# @api private
# @since 0.1.0
def supported_driver?(driver)
defined?(::Redis) &&
defined?(::ActiveSupport::Cache::RedisCacheStore) &&
driver.is_a?(::ActiveSupport::Cache::RedisCacheStore)
AnyCache::Drivers::ActiveSupportRedisCacheStore.supported_source?(driver)
end
end

Expand Down
2 changes: 1 addition & 1 deletion lib/any_cache/adapters/dalli.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ class << self
# @api private
# @since 0.1.0
def supported_driver?(driver)
defined?(::Dalli::Client) && driver.is_a?(::Dalli::Client)
AnyCache::Drivers::Dalli.supported_source?(driver)
end
end

Expand Down
2 changes: 1 addition & 1 deletion lib/any_cache/adapters/redis.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ class << self
# @api private
# @since 0.1.0
def supported_driver?(driver)
defined?(::Redis) && driver.is_a?(::Redis)
AnyCache::Drivers::Redis.supported_source?(driver)
end
end

Expand Down
2 changes: 1 addition & 1 deletion lib/any_cache/adapters/redis_store.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ class << self
# @api private
# @since 0.1.0
def supported_driver?(driver)
defined?(::Redis::Store) && driver.is_a?(::Redis::Store)
AnyCache::Drivers::RedisStore.supported_source?(driver)
end
end

Expand Down
42 changes: 42 additions & 0 deletions lib/any_cache/drivers.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# frozen_string_literal: true

# @api private
# @since 0.2.0
module AnyCache::Drivers
require_relative 'drivers/dalli'
require_relative 'drivers/redis'
require_relative 'drivers/redis_store'
require_relative 'drivers/active_support_file_store'
require_relative 'drivers/active_support_memory_store'
require_relative 'drivers/active_support_redis_cache_store'

class << self
# @param config [Qonfig::DataSet]
# @return [Object]
#
# @raise [AnyCache::UnsupportedDriverError]
#
# @api private
# @since 0.2.0
def build(config)
driver = config[:driver]

case driver
when :redis
Redis.build(config[:redis])
when :redis_store
RedisStore.build(config[:redis_store])
when :dalli
Dalli.build(config[:dalli])
when :as_file_store
ActiveSupportFileStore.build(config[:as_file_store])
when :as_memory_store
ActiveSupportMemoryStore.build(config[:as_memory_store])
when :as_redis_cache_store
ActiveSupportRedisCacheStore.build(config[:as_redis_cache_store])
else
raise AnyCache::UnsupportedDriverError
end
end
end
end
Loading

0 comments on commit 699a680

Please sign in to comment.