From 9b3ab6566722126dba2fce114ddf9581f57dad93 Mon Sep 17 00:00:00 2001 From: malvads Date: Tue, 27 Feb 2024 13:58:34 +0000 Subject: [PATCH 01/13] first easycache version --- .github/worflows/lint.yml | 21 +++++++++++ .github/worflows/tests.yml | 23 ++++++++++++ README.md | 44 +++++++++++++++++++++-- Rakefile | 9 +++++ easycache.gemspec | 11 ++++++ lib/easycache.rb | 71 ++++++++++++++++++++++++++++++++++++++ test/test_easycache.rb | 31 +++++++++++++++++ 7 files changed, 208 insertions(+), 2 deletions(-) create mode 100644 .github/worflows/lint.yml create mode 100644 .github/worflows/tests.yml create mode 100644 Rakefile create mode 100644 easycache.gemspec create mode 100644 lib/easycache.rb create mode 100644 test/test_easycache.rb diff --git a/.github/worflows/lint.yml b/.github/worflows/lint.yml new file mode 100644 index 0000000..ec4248f --- /dev/null +++ b/.github/worflows/lint.yml @@ -0,0 +1,21 @@ +name: RuboCop + +on: + push: + pull_request: + branches: + - master + +jobs: + rubocop: + if: github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.pull_request.user.login == 'dependabot[bot]') + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + + - name: Install RuboCop + run: sudo gem install rubocop -v 1.59.0 + + - name: Run RuboCop + run: rubocop ./lib \ No newline at end of file diff --git a/.github/worflows/tests.yml b/.github/worflows/tests.yml new file mode 100644 index 0000000..8991f4d --- /dev/null +++ b/.github/worflows/tests.yml @@ -0,0 +1,23 @@ +name: Tests + +on: + push: + pull_request: + branches: + - main + +jobs: + build: + if: github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.pull_request.user.login == 'dependabot[bot]') + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Set up Ruby 2.1.9 + uses: ruby/setup-ruby@v1 + with: + ruby-version: '2.1.9' + - name: Bundle Install + run: bundle install + + - name: Run tests + run: rake test \ No newline at end of file diff --git a/README.md b/README.md index c81cfb7..e3b8ef6 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,42 @@ -# easy-cache -Easy to use in-mem cache system for ruby +# EasyCache + +EasyCache is an in-memory cache system for Ruby designed for situations where you don't want to set up Redis or Memcached but still need a simple solution for caching key-value data. + +## Usage + +To use EasyCache in your Ruby project, require the library and include it in your code: + +```ruby +require 'easycache' + +cache = EasyCache.new +``` + +## Storing data + +```ruby +key = "my_key" +cache_ttl = 3600 +store_in_mem = true +data = cache.fetch(cache_key, cache_ttl, store_in_mem) do + my_http_get +end +``` + +Now data is in-mem for the next 3600 second (store_in_mem variable is important for storing data first time), if i want to get the data stored in mem i do + +```ruby +data = cache.fetch("my_key") +``` + +or i can also re-call the same function + +```ruby +data = cache.fetch("my_key", cache_ttl, store_in_mem) do + my_http_get +end +``` + +because the data is already cached, so it will not call the block, it will return the cached data instead. + +This will output the cached data, remember that cached data is stored here for only 3600 seconds diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..e4acc73 --- /dev/null +++ b/Rakefile @@ -0,0 +1,9 @@ +require 'rake/testtask' + +Rake::TestTask.new(:test) do |test| + test.libs << '.' + test.pattern = 'test/test_*.rb' + test.verbose = true +end + +task default: :test diff --git a/easycache.gemspec b/easycache.gemspec new file mode 100644 index 0000000..e09a36c --- /dev/null +++ b/easycache.gemspec @@ -0,0 +1,11 @@ +Gem::Specification.new do |s| + s.name = "easy-cache" + s.version = "0.0.1" + s.summary = "Easy to use in-mem cache system for ruby" + s.description = "A simple gem for store and manage data in mem" + s.authors = ["Miguel Álvarez"] + s.email = "thegexi@gmail.com" + s.files = Dir['lib/**/*', 'LICENSE', 'README.md'] + s.homepage = "https://rubygems.org/gems/easycache" + s.license = "AGPL-3.0" +end diff --git a/lib/easycache.rb b/lib/easycache.rb new file mode 100644 index 0000000..13e54e8 --- /dev/null +++ b/lib/easycache.rb @@ -0,0 +1,71 @@ +# frozen_string_literal: true + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. + +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +# +# This is the core of EasyCache. +# EasyCache provides an easy-to-use, in-memory cache system for Ruby. +# It is designed for situations where you don't want to set up Redis or Memcached but still want +# a simple solution for caching key-value data. +# +class EasyCache + def initialize + @cache = {} + @mutex = Mutex.new + end + + def fetch(key, expiration = 3600, store_in_cache = false) # rubocop:disable Style/OptionalBooleanParameter + @mutex.synchronize do + return cached_value(key, store_in_cache) if cache_contains_valid_data?(key) && !block_given? + + if should_fetch_from_block?(key, store_in_cache) + value = block_given? ? yield : nil + cache_value(key, value, expiration) if value && store_in_cache + value + else + cached_value(key, store_in_cache) + end + end + end + + private + + def cache_contains_valid_data?(key) + @cache.key?(key) && !expired?(key) + end + + def should_fetch_from_block?(key, store_in_cache) + !store_in_cache || (!@cache.key?(key) || expired?(key)) + end + + def cached_value(key, _store_in_cache) + @cache[key][:value] + end + + def cache_value(key, value, expiration) + @cache[key] = { value: value, timestamp: Time.now, expiration: expiration } + end + + def expired?(key) + return false unless @cache.key?(key) && @cache[key].key?(:timestamp) && @cache[key].key?(:expiration) + + expiration_date = @cache[key][:timestamp] + @cache[key][:expiration] + if Time.now > expiration_date + @cache.delete(key) + true + else + false + end + end +end diff --git a/test/test_easycache.rb b/test/test_easycache.rb new file mode 100644 index 0000000..1df54ad --- /dev/null +++ b/test/test_easycache.rb @@ -0,0 +1,31 @@ +require_relative '../lib/easycache' +require 'test/unit' + +# Test EasyCache class +class EasyCacheTest < Test::Unit::TestCase + def setup + @cache = EasyCache.new + end + + def test_fetch_caches_value_for_given_key + @cache.fetch('test_key', 3600, true) { 'test_value' } + assert_instance_of(Time, @cache.instance_variable_get(:@cache)['test_key'][:timestamp]) + end + + def test_fetch_retrieves_cached_value_for_given_key_if_not_expired + @cache.fetch('test_key', 3600, true) { 'test_value' } + assert_equal 'test_value', @cache.fetch('test_key') + end + + def test_fetch_expires_cached_value_after_specified_expiration_time + @cache.fetch('test_key', 1, true) { 'test_value' } + sleep(2) + assert_nil @cache.fetch('test_key') + end + + def test_fetch_recomputes_expired_value_if_fetched_again + @cache.fetch('test_key', 1, true) { 'test_value' } + sleep(2) + assert_equal 'new_test_value', @cache.fetch('test_key') { 'new_test_value' } + end +end From ed7b1e0a976c6979897e4ce0e897fe9f6920c135 Mon Sep 17 00:00:00 2001 From: malvads Date: Tue, 27 Feb 2024 14:04:48 +0000 Subject: [PATCH 02/13] Fix workflows --- .github/worflows/lint.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/worflows/lint.yml b/.github/worflows/lint.yml index ec4248f..c12e27e 100644 --- a/.github/worflows/lint.yml +++ b/.github/worflows/lint.yml @@ -4,7 +4,7 @@ on: push: pull_request: branches: - - master + - main jobs: rubocop: From 07c388a8f67fb3c86a91e75437bfedb9541550ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20=C3=81lvarez?= <128592227+malvads@users.noreply.github.com> Date: Tue, 27 Feb 2024 14:07:41 +0000 Subject: [PATCH 03/13] Update README.md --- README.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index e3b8ef6..909253d 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,11 @@ data = cache.fetch(cache_key, cache_ttl, store_in_mem) do end ``` -Now data is in-mem for the next 3600 second (store_in_mem variable is important for storing data first time), if i want to get the data stored in mem i do +Now data is in-mem for the next 3600 second (store_in_mem variable is important for storing data first time). + +## Getting data + +If i want to get the data stored in mem i do ```ruby data = cache.fetch("my_key") @@ -39,4 +43,4 @@ end because the data is already cached, so it will not call the block, it will return the cached data instead. -This will output the cached data, remember that cached data is stored here for only 3600 seconds +This will output the cached data, remember that cached data is stored in mem for only 3600 seconds From a800ea6f2121c0598f7270acb41921cf5f559663 Mon Sep 17 00:00:00 2001 From: malvads Date: Tue, 27 Feb 2024 14:09:35 +0000 Subject: [PATCH 04/13] Update workflows folder name --- .github/{worflows => workflows}/lint.yml | 0 .github/{worflows => workflows}/tests.yml | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename .github/{worflows => workflows}/lint.yml (100%) rename .github/{worflows => workflows}/tests.yml (100%) diff --git a/.github/worflows/lint.yml b/.github/workflows/lint.yml similarity index 100% rename from .github/worflows/lint.yml rename to .github/workflows/lint.yml diff --git a/.github/worflows/tests.yml b/.github/workflows/tests.yml similarity index 100% rename from .github/worflows/tests.yml rename to .github/workflows/tests.yml From e4ca28e62e6460f657f388ad5b42b5ccca05564c Mon Sep 17 00:00:00 2001 From: malvads Date: Tue, 27 Feb 2024 14:12:26 +0000 Subject: [PATCH 05/13] Add build workflow --- .github/workflows/build.yml | 20 ++++++++++++++++++++ .github/workflows/tests.yml | 4 ++-- 2 files changed, 22 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/build.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..af674d4 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,20 @@ +name: Tests + +on: + push: + pull_request: + branches: + - main + +jobs: + build: + if: github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.pull_request.user.login == 'dependabot[bot]') + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: '3.0.0' + - name: Gem build + run: gem build easycache.gemspec \ No newline at end of file diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 8991f4d..6582cd3 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -12,10 +12,10 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - - name: Set up Ruby 2.1.9 + - name: Set up Ruby uses: ruby/setup-ruby@v1 with: - ruby-version: '2.1.9' + ruby-version: '3.0.0' - name: Bundle Install run: bundle install From 0c2808424fd59b310893f20542568c49d3781f00 Mon Sep 17 00:00:00 2001 From: malvads Date: Tue, 27 Feb 2024 14:13:25 +0000 Subject: [PATCH 06/13] Fix tests workflows --- .github/workflows/tests.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 6582cd3..066ab54 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -16,8 +16,6 @@ jobs: uses: ruby/setup-ruby@v1 with: ruby-version: '3.0.0' - - name: Bundle Install - run: bundle install - + - name: Run tests run: rake test \ No newline at end of file From 6ec9e1605deda2be644f10e72ca89beb10f7cd62 Mon Sep 17 00:00:00 2001 From: malvads Date: Tue, 27 Feb 2024 14:13:53 +0000 Subject: [PATCH 07/13] Update workflows --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index af674d4..7d8c227 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,4 +1,4 @@ -name: Tests +name: Build gem on: push: From 07328c2488537850cf804374440f29b20ff1ba4d Mon Sep 17 00:00:00 2001 From: malvads Date: Tue, 27 Feb 2024 14:16:13 +0000 Subject: [PATCH 08/13] Update workflows --- .github/workflows/build.yml | 12 ++++++++---- .github/workflows/tests.yml | 15 +++++++++------ 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 7d8c227..4caf9ea 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -10,11 +10,15 @@ jobs: build: if: github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.pull_request.user.login == 'dependabot[bot]') runs-on: ubuntu-latest + strategy: + matrix: + ruby-version: ['3.1', '3.0', '2.7'] + name: Build gem with Ruby ${{ matrix.ruby-version }} steps: - uses: actions/checkout@v2 - - name: Set up Ruby + - name: Set up Ruby ${{ matrix.ruby-version }} uses: ruby/setup-ruby@v1 with: - ruby-version: '3.0.0' - - name: Gem build - run: gem build easycache.gemspec \ No newline at end of file + ruby-version: ${{ matrix.ruby-version }} + - name: Gem build with Ruby ${{ matrix.ruby-version }} + run: gem build easycache.gemspec diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 066ab54..2083e77 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -7,15 +7,18 @@ on: - main jobs: - build: + test: if: github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.pull_request.user.login == 'dependabot[bot]') runs-on: ubuntu-latest + strategy: + matrix: + ruby-version: ['3.1', '3.0', '2.7'] + name: Test with Ruby ${{ matrix.ruby-version }} steps: - uses: actions/checkout@v2 - - name: Set up Ruby + - name: Set up Ruby ${{ matrix.ruby-version }} uses: ruby/setup-ruby@v1 with: - ruby-version: '3.0.0' - - - name: Run tests - run: rake test \ No newline at end of file + ruby-version: ${{ matrix.ruby-version }} + - name: Run tests with Ruby ${{ matrix.ruby-version }} + run: rake test From 100ef1841deec244d55cb3648f45626fd6268737 Mon Sep 17 00:00:00 2001 From: malvads Date: Tue, 27 Feb 2024 14:17:51 +0000 Subject: [PATCH 09/13] Add missing ruby versions --- .github/workflows/build.yml | 2 +- .github/workflows/tests.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4caf9ea..685dd72 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - ruby-version: ['3.1', '3.0', '2.7'] + ruby-version: ['3.3', '3.2', '3.1', '3.0', '2.7'] name: Build gem with Ruby ${{ matrix.ruby-version }} steps: - uses: actions/checkout@v2 diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 2083e77..8f0b4d0 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - ruby-version: ['3.1', '3.0', '2.7'] + ruby-version: ['3.3', '3.2', '3.1', '3.0', '2.7'] name: Test with Ruby ${{ matrix.ruby-version }} steps: - uses: actions/checkout@v2 From bb0ec9378495cc4f12e48f54ba8e4f67808303e3 Mon Sep 17 00:00:00 2001 From: malvads Date: Tue, 27 Feb 2024 14:21:04 +0000 Subject: [PATCH 10/13] Update readme --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 909253d..835e92a 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,11 @@ # EasyCache +[![Gem Version](https://badge.fury.io/rb/easycache.svg)](https://badge.fury.io/rb/easycache) +![License](https://img.shields.io/badge/license-AGPL%203.0-blue.svg) +[![Lint](https://github.com/malvads/easycache/actions/workflows/lint.yml/badge.svg)](https://github.com/malvads/easycache/actions/workflows/lint.yml) +[![Tests](https://github.com/malvads/easycache/actions/workflows/tests.yml/badge.svg)](https://github.com/malvads/easycache/actions/workflows/tests.yml) +[![Build](https://github.com/malvads/easycache/actions/workflows/build.yml/badge.svg)](https://github.com/malvads/easycache/actions/workflows/build.yml) + EasyCache is an in-memory cache system for Ruby designed for situations where you don't want to set up Redis or Memcached but still need a simple solution for caching key-value data. ## Usage From d1ea4a2cf051692d3865847d20281dab577c1880 Mon Sep 17 00:00:00 2001 From: malvads Date: Tue, 27 Feb 2024 14:21:42 +0000 Subject: [PATCH 11/13] Fix readme --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 835e92a..fdb3f1d 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,12 @@ # EasyCache +

[![Gem Version](https://badge.fury.io/rb/easycache.svg)](https://badge.fury.io/rb/easycache) ![License](https://img.shields.io/badge/license-AGPL%203.0-blue.svg) [![Lint](https://github.com/malvads/easycache/actions/workflows/lint.yml/badge.svg)](https://github.com/malvads/easycache/actions/workflows/lint.yml) [![Tests](https://github.com/malvads/easycache/actions/workflows/tests.yml/badge.svg)](https://github.com/malvads/easycache/actions/workflows/tests.yml) [![Build](https://github.com/malvads/easycache/actions/workflows/build.yml/badge.svg)](https://github.com/malvads/easycache/actions/workflows/build.yml) - +

EasyCache is an in-memory cache system for Ruby designed for situations where you don't want to set up Redis or Memcached but still need a simple solution for caching key-value data. ## Usage From 2a9622a01a159d7ab86a838266e06019d5b6aea8 Mon Sep 17 00:00:00 2001 From: malvads Date: Tue, 27 Feb 2024 14:23:00 +0000 Subject: [PATCH 12/13] Update readme --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index fdb3f1d..a075165 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,11 @@ # EasyCache

-[![Gem Version](https://badge.fury.io/rb/easycache.svg)](https://badge.fury.io/rb/easycache) +[![Gem Version](https://badge.fury.io/rb/easy-cache.svg)](https://badge.fury.io/rb/easy-cache) ![License](https://img.shields.io/badge/license-AGPL%203.0-blue.svg) -[![Lint](https://github.com/malvads/easycache/actions/workflows/lint.yml/badge.svg)](https://github.com/malvads/easycache/actions/workflows/lint.yml) -[![Tests](https://github.com/malvads/easycache/actions/workflows/tests.yml/badge.svg)](https://github.com/malvads/easycache/actions/workflows/tests.yml) -[![Build](https://github.com/malvads/easycache/actions/workflows/build.yml/badge.svg)](https://github.com/malvads/easycache/actions/workflows/build.yml) +[![Lint](https://github.com/malvads/easy-cache/actions/workflows/lint.yml/badge.svg)](https://github.com/malvads/easy-cache/actions/workflows/lint.yml) +[![Tests](https://github.com/malvads/easy-cache/actions/workflows/tests.yml/badge.svg)](https://github.com/malvads/easy-cache/actions/workflows/tests.yml) +[![Build](https://github.com/malvads/easy-cache/actions/workflows/build.yml/badge.svg)](https://github.com/malvads/easy-cache/actions/workflows/build.yml)

EasyCache is an in-memory cache system for Ruby designed for situations where you don't want to set up Redis or Memcached but still need a simple solution for caching key-value data. From a9e7b3b6ba5aa654c7823508fa096493f706ee2a Mon Sep 17 00:00:00 2001 From: malvads Date: Tue, 27 Feb 2024 14:25:48 +0000 Subject: [PATCH 13/13] Add install on readme --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index a075165..a94a83f 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,12 @@

EasyCache is an in-memory cache system for Ruby designed for situations where you don't want to set up Redis or Memcached but still need a simple solution for caching key-value data. +## Install + +``` +gem install easy-cache +``` + ## Usage To use EasyCache in your Ruby project, require the library and include it in your code: