toggly-cache 0.1.0

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
+ SHA256:
3
+ metadata.gz: 98811a45f8402f5bf321cd854cf39856d9bce478e946033c968c126c5abd7814
4
+ data.tar.gz: f9b84d051d6c332eee50b463cdbe481e67cd0af34363aa8f50b53c6974cea2c0
5
+ SHA512:
6
+ metadata.gz: 7fa421237fd34448a03c1a9eef6f4c5e55bae773b2879242b753d4a8c3ec7c28ef0c362ce0196706bdc78a2c66f179ad928bbe56e55f61e6adb457b07e13ddb5
7
+ data.tar.gz: a1f5be53e00f43efdeb7f0a49a33e10e673d64f8a12b07886b2ea88a066779f134c1b0432d4750138e9bd1c22c8a178ebf163d9f038a729c0e091130073aedcb
data/CHANGELOG.md ADDED
@@ -0,0 +1,40 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [0.1.0] - 2024-XX-XX
9
+
10
+ ### Added
11
+
12
+ - Initial release of Toggly Ruby SDK
13
+ - `toggly` - Core SDK with zero dependencies
14
+ - Client for feature flag evaluation
15
+ - Context for user identity, groups, and traits
16
+ - Evaluation engine with multiple rule types
17
+ - Percentage rollouts with consistent hashing
18
+ - User and group targeting
19
+ - Contextual targeting with operators
20
+ - Time window rules
21
+ - Memory and file snapshot providers
22
+ - Background refresh support
23
+ - Offline mode with defaults
24
+
25
+ - `toggly-rails` - Rails integration
26
+ - Railtie for auto-configuration
27
+ - Controller concern with `feature_enabled?` helper
28
+ - View helpers (`when_feature_enabled`, `feature_switch`)
29
+ - Rack middleware for request context
30
+ - Context builder from current_user
31
+ - Rails.cache snapshot provider
32
+ - Generator for initializer
33
+ - Rake tasks (list, check, refresh, config)
34
+ - RSpec and Minitest helpers
35
+
36
+ - `toggly-cache` - Redis caching support
37
+ - Redis snapshot provider
38
+ - Connection pool support
39
+ - TTL configuration
40
+ - Touch/extend TTL support
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Ops.ai
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,33 @@
1
+ # toggly-cache
2
+
3
+ Redis caching support for [Toggly](https://toggly.io) feature flag management.
4
+
5
+ ## Installation
6
+
7
+ ```ruby
8
+ gem 'toggly-cache'
9
+ ```
10
+
11
+ ## Quick Start
12
+
13
+ ```ruby
14
+ require 'toggly'
15
+ require 'toggly-cache'
16
+ require 'redis'
17
+
18
+ redis = Redis.new(url: ENV['REDIS_URL'])
19
+ provider = Toggly::Cache::RedisSnapshotProvider.new(redis: redis)
20
+
21
+ client = Toggly::Client.new(
22
+ app_key: 'your-app-key',
23
+ snapshot_provider: provider
24
+ )
25
+ ```
26
+
27
+ ## Documentation
28
+
29
+ See the [main README](../README.md) for full documentation.
30
+
31
+ ## License
32
+
33
+ MIT
@@ -0,0 +1,152 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "json"
4
+
5
+ module Toggly
6
+ module Cache
7
+ # Redis-based snapshot provider for Toggly.
8
+ #
9
+ # Stores feature definitions in Redis for persistence and sharing
10
+ # across multiple processes or servers.
11
+ #
12
+ # @example Basic usage
13
+ # redis = Redis.new(url: "redis://localhost:6379")
14
+ # provider = Toggly::Cache::RedisSnapshotProvider.new(redis: redis)
15
+ #
16
+ # @example With connection pool
17
+ # pool = ConnectionPool.new(size: 5) { Redis.new }
18
+ # provider = Toggly::Cache::RedisSnapshotProvider.new(redis: pool)
19
+ #
20
+ # @example With TTL
21
+ # provider = Toggly::Cache::RedisSnapshotProvider.new(
22
+ # redis: redis,
23
+ # ttl: 3600, # 1 hour
24
+ # key_prefix: "myapp:toggly"
25
+ # )
26
+ class RedisSnapshotProvider < Toggly::SnapshotProviders::Base
27
+ # @return [String] Key prefix for Redis keys
28
+ attr_reader :key_prefix
29
+
30
+ # @return [Integer, nil] TTL in seconds (nil = no expiration)
31
+ attr_reader :ttl
32
+
33
+ # Create a new Redis snapshot provider
34
+ #
35
+ # @param redis [Redis, ConnectionPool] Redis client or connection pool
36
+ # @param key_prefix [String] Prefix for Redis keys
37
+ # @param ttl [Integer, nil] TTL in seconds (nil = no expiration)
38
+ def initialize(redis:, key_prefix: "toggly", ttl: nil)
39
+ super()
40
+ @redis = redis
41
+ @key_prefix = key_prefix
42
+ @ttl = ttl
43
+ end
44
+
45
+ # Save definitions to Redis
46
+ #
47
+ # @param definitions [Hash<String, FeatureDefinition>] Definitions to save
48
+ # @param metadata [Hash] Optional metadata
49
+ def save(definitions, metadata = {})
50
+ data = {
51
+ "definitions" => serialize_definitions(definitions),
52
+ "metadata" => metadata.merge("saved_at" => Time.now.utc.iso8601)
53
+ }
54
+
55
+ json = JSON.generate(data)
56
+
57
+ with_redis do |redis|
58
+ if @ttl
59
+ redis.setex(snapshot_key, @ttl, json)
60
+ else
61
+ redis.set(snapshot_key, json)
62
+ end
63
+ end
64
+ rescue StandardError => e
65
+ raise Toggly::SnapshotError, "Failed to save snapshot to Redis: #{e.message}"
66
+ end
67
+
68
+ # Load definitions from Redis
69
+ #
70
+ # @return [Hash, nil] Hash with :definitions and :metadata, or nil if not found
71
+ def load
72
+ json = with_redis { |redis| redis.get(snapshot_key) }
73
+ return nil unless json
74
+
75
+ data = JSON.parse(json)
76
+
77
+ {
78
+ definitions: deserialize_definitions(data["definitions"]),
79
+ metadata: symbolize_keys(data["metadata"] || {})
80
+ }
81
+ rescue JSON::ParserError => e
82
+ raise Toggly::SnapshotError, "Failed to parse Redis snapshot: #{e.message}"
83
+ rescue StandardError => e
84
+ raise Toggly::SnapshotError, "Failed to load snapshot from Redis: #{e.message}"
85
+ end
86
+
87
+ # Clear the snapshot from Redis
88
+ def clear
89
+ with_redis { |redis| redis.del(snapshot_key) }
90
+ rescue StandardError => e
91
+ raise Toggly::SnapshotError, "Failed to clear Redis snapshot: #{e.message}"
92
+ end
93
+
94
+ # Check if snapshot exists in Redis
95
+ #
96
+ # @return [Boolean]
97
+ def exists?
98
+ result = with_redis { |redis| redis.exists?(snapshot_key) }
99
+ # Handle both Redis 4.x (returns Integer) and 5.x (returns Boolean)
100
+ result.is_a?(Integer) ? result.positive? : result
101
+ rescue StandardError
102
+ false
103
+ end
104
+
105
+ # Get TTL of the snapshot
106
+ #
107
+ # @return [Integer, nil] Remaining TTL in seconds, or nil if no TTL
108
+ def remaining_ttl
109
+ ttl = with_redis { |redis| redis.ttl(snapshot_key) }
110
+ return nil if ttl.nil? || ttl.negative?
111
+
112
+ ttl
113
+ rescue StandardError
114
+ nil
115
+ end
116
+
117
+ # Touch the snapshot to extend its TTL
118
+ #
119
+ # @return [Boolean] Whether the operation succeeded
120
+ def touch
121
+ return false unless @ttl
122
+
123
+ with_redis { |redis| redis.expire(snapshot_key, @ttl) }
124
+ true
125
+ rescue StandardError
126
+ false
127
+ end
128
+
129
+ private
130
+
131
+ def snapshot_key
132
+ "#{@key_prefix}:snapshot"
133
+ end
134
+
135
+ def with_redis(&block)
136
+ if @redis.respond_to?(:with)
137
+ # ConnectionPool
138
+ @redis.with(&block)
139
+ else
140
+ # Direct Redis client
141
+ yield @redis
142
+ end
143
+ end
144
+
145
+ def symbolize_keys(hash)
146
+ return {} unless hash.is_a?(Hash)
147
+
148
+ hash.transform_keys(&:to_sym)
149
+ end
150
+ end
151
+ end
152
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Toggly
4
+ module Cache
5
+ VERSION = "0.1.0"
6
+ end
7
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "toggly"
4
+ require_relative "toggly/cache/version"
5
+ require_relative "toggly/cache/redis_snapshot_provider"
6
+
7
+ module Toggly
8
+ # Redis caching module for Toggly.
9
+ #
10
+ # Provides a Redis-based snapshot provider for storing and sharing
11
+ # feature definitions across processes and servers.
12
+ #
13
+ # @example Basic usage
14
+ # redis = Redis.new(url: ENV["REDIS_URL"])
15
+ # provider = Toggly::Cache::RedisSnapshotProvider.new(redis: redis)
16
+ #
17
+ # client = Toggly::Client.new(
18
+ # app_key: "your-app-key",
19
+ # snapshot_provider: provider
20
+ # )
21
+ #
22
+ # @example With connection pool
23
+ # require "connection_pool"
24
+ #
25
+ # pool = ConnectionPool.new(size: 5) { Redis.new(url: ENV["REDIS_URL"]) }
26
+ # provider = Toggly::Cache::RedisSnapshotProvider.new(redis: pool)
27
+ #
28
+ # @example With Rails
29
+ # # config/initializers/toggly.rb
30
+ # Toggly::Rails.configure do |config|
31
+ # config.app_key = Rails.application.credentials.toggly_app_key
32
+ # config.snapshot_provider = Toggly::Cache::RedisSnapshotProvider.new(
33
+ # redis: Redis.new(url: ENV["REDIS_URL"]),
34
+ # key_prefix: "myapp:toggly"
35
+ # )
36
+ # end
37
+ module Cache
38
+ class << self
39
+ # Create a Redis snapshot provider with sensible defaults
40
+ #
41
+ # @param redis [Redis, ConnectionPool] Redis client or connection pool
42
+ # @param options [Hash] Additional options
43
+ # @return [RedisSnapshotProvider]
44
+ def redis_provider(redis:, **options)
45
+ RedisSnapshotProvider.new(redis: redis, **options)
46
+ end
47
+ end
48
+ end
49
+ end
metadata ADDED
@@ -0,0 +1,83 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: toggly-cache
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Ops.ai
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2026-03-03 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: redis
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: toggly
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0.1'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0.1'
41
+ description: Redis-based snapshot provider for Toggly feature flags. Enables persistent
42
+ caching and sharing of feature definitions across processes.
43
+ email:
44
+ - support@ops.ai
45
+ executables: []
46
+ extensions: []
47
+ extra_rdoc_files: []
48
+ files:
49
+ - CHANGELOG.md
50
+ - LICENSE
51
+ - README.md
52
+ - lib/toggly-cache.rb
53
+ - lib/toggly/cache/redis_snapshot_provider.rb
54
+ - lib/toggly/cache/version.rb
55
+ homepage: https://toggly.io
56
+ licenses:
57
+ - MIT
58
+ metadata:
59
+ homepage_uri: https://toggly.io
60
+ source_code_uri: https://github.com/ops-ai/toggly-ruby
61
+ changelog_uri: https://github.com/ops-ai/toggly-ruby/blob/main/CHANGELOG.md
62
+ documentation_uri: https://docs.toggly.io/sdks/ruby
63
+ rubygems_mfa_required: 'true'
64
+ post_install_message:
65
+ rdoc_options: []
66
+ require_paths:
67
+ - lib
68
+ required_ruby_version: !ruby/object:Gem::Requirement
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ version: 3.0.0
73
+ required_rubygems_version: !ruby/object:Gem::Requirement
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ requirements: []
79
+ rubygems_version: 3.5.22
80
+ signing_key:
81
+ specification_version: 4
82
+ summary: Redis caching support for Toggly feature flags
83
+ test_files: []