Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[gem] Configuration layer #3

Merged
merged 3 commits into from
Aug 30, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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