{"id":26525245,"url":"https://github.com/ryz310/redis-objects-periodical","last_synced_at":"2025-09-02T22:43:58.103Z","repository":{"id":46828799,"uuid":"405659878","full_name":"ryz310/redis-objects-periodical","owner":"ryz310","description":"Extends Redis::Objects to switch automatically the save destination within Redis on changing dates.","archived":false,"fork":false,"pushed_at":"2024-05-13T01:09:58.000Z","size":279,"stargazers_count":8,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-05-13T02:26:48.922Z","etag":null,"topics":["redis","redis-objects","ruby"],"latest_commit_sha":null,"homepage":"","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ryz310.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-09-12T14:11:15.000Z","updated_at":"2024-05-13T02:26:50.409Z","dependencies_parsed_at":"2022-08-30T11:32:31.648Z","dependency_job_id":"ef1c0c3e-b086-48c6-a774-805424c0ed4d","html_url":"https://github.com/ryz310/redis-objects-periodical","commit_stats":{"total_commits":159,"total_committers":3,"mean_commits":53.0,"dds":"0.13207547169811318","last_synced_commit":"63f37707a77565f3343b80bc976770a6036ff14e"},"previous_names":["ryz310/redis-objects-daily-counter"],"tags_count":8,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ryz310%2Fredis-objects-periodical","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ryz310%2Fredis-objects-periodical/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ryz310%2Fredis-objects-periodical/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ryz310%2Fredis-objects-periodical/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ryz310","download_url":"https://codeload.github.com/ryz310/redis-objects-periodical/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244816616,"owners_count":20515127,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["redis","redis-objects","ruby"],"created_at":"2025-03-21T14:55:17.356Z","updated_at":"2025-03-21T14:55:18.636Z","avatar_url":"https://github.com/ryz310.png","language":"Ruby","readme":"[![CircleCI](https://circleci.com/gh/ryz310/redis-objects-periodical.svg?style=svg)](https://circleci.com/gh/ryz310/redis-objects-periodical) [![Gem Version](https://badge.fury.io/rb/redis-objects-periodical.svg)](https://badge.fury.io/rb/redis-objects-periodical) [![Maintainability](https://api.codeclimate.com/v1/badges/deebb6c406c306a6f337/maintainability)](https://codeclimate.com/github/ryz310/redis-objects-periodical/maintainability) [![Test Coverage](https://api.codeclimate.com/v1/badges/deebb6c406c306a6f337/test_coverage)](https://codeclimate.com/github/ryz310/redis-objects-periodical/test_coverage)\n\n# Redis::Objects::Periodical\n\nThis is a gem which extends [Redis::Objects](https://github.com/nateware/redis-objects) gem. Once install this gem, you can use the periodical counter, the periodical set, etc. in addition to the standard features of Redis::Objects. These counters and sets are useful for measuring conversions, implementing API rate limiting, MAU, DAU, and more.\n\n## Installation\n\nAdd this line to your application's Gemfile:\n\n```ruby\ngem 'redis-objects-periodical'\n```\n\nIf you want to know about installation and standard usage, please see Redis::Objects' GitHub page.\n\n## Usage\n\n`daily_counter` and `daily_set` automatically creates keys that are unique to each object, in the format:\n\n```\nmodel_name:id:field_name:yyyy-mm-dd\n```\n\nI recommend using with `expireat` option.\nFor illustration purposes, consider this stub class:\n\n```rb\nclass Homepage\n  include Redis::Objects\n\n  daily_counter :pv, expireat: -\u003e { Time.now + 2_678_400 } # about a month\n  daily_hash_key :browsing_history, expireat: -\u003e { Time.now + 2_678_400 } # about a month\n  daily_set :dau, expireat: -\u003e { Time.now + 2_678_400 } # about a month\n  daily_value :cache, expireat: -\u003e { Time.now + 2_678_400 } # about a month\n\n  def id\n    1\n  end\nend\n\n# 2021-04-01\nhomepage = Homepage.new\nhomepage.id # 1\n\nhomepage.pv.increment\nhomepage.pv.increment\nhomepage.pv.increment\nputs homepage.pv.value # 3\n\n# 2021-04-02 (next day)\nputs homepage.pv.value # 0\nhomepage.pv.increment\nhomepage.pv.increment\nputs homepage.pv.value # 2\n\nstart_date = Date.new(2021, 4, 1)\nend_date = Date.new(2021, 4, 2)\nhomepage.pv.range(start_date, end_date) # [3, 2]\n```\n\n### Periodical Counters\n\nThe periodical counters automatically switches the save destination when the date changes.\nYou can access past dates counted values like Ruby arrays:\n\n```rb\n# 2021-04-01\nhomepage.pv.increment(3)\n\n# 2021-04-02 (next day)\nhomepage.pv.increment(2)\n\n# 2021-04-03 (next day)\nhomepage.pv.increment(5)\n\nhomepage.pv[Date.new(2021, 4, 1)] # =\u003e 3\nhomepage.pv[Date.new(2021, 4, 1), 3] # =\u003e [3, 2, 5]\nhomepage.pv[Date.new(2021, 4, 1)..Date.new(2021, 4, 2)] # =\u003e [3, 2]\n\nhomepage.pv.delete_at(Date.new(2021, 4, 1))\nhomepage.pv.range(Date.new(2021, 4, 1), Date.new(2021, 4, 3)) # =\u003e [0, 2, 5]\nhomepage.pv.at(Date.new(2021, 4, 2)) # =\u003e #\u003cRedis::Counter key=\"homepage:1:pv:2021-04-02\"\u003e\nhomepage.pv.at(Date.new(2021, 4, 2)).value # 2\n```\n\n#### Periodical Counters Family\n\n- `annual_counter`\n  - Key format: `model_name:id:field_name:yyyy`\n  - Redis is a highly volatile key-value store, so I don't recommend using it.\n- `monthly_counter`\n  - Key format: `model_name:id:field_name:yyyy-mm`\n- `weekly_counter`\n  - Key format: `model_name:id:field_name:yyyyWw`\n- `daily_counter`\n  - Key format: `model_name:id:field_name:yyyy-mm-dd`\n- `hourly_counter`\n  - Key format: `model_name:id:field_name:yyyy-mm-ddThh`\n- `minutely_counter`\n  - Key format: `model_name:id:field_name:yyyy-mm-ddThh:mi`\n\n### Periodical Values\n\nThe periodical values automatically switches the save destination when the date changes.\n\n```rb\n# 2021-04-01\nhomepage.cache.value = 'a'\n\n# 2021-04-02 (next day)\nhomepage.cache.value = 'b'\n\n# 2021-04-03 (next day)\nhomepage.cache.value = 'c'\n\nhomepage.cache[Date.new(2021, 4, 1)] # =\u003e 'a'\nhomepage.cache[Date.new(2021, 4, 1), 3] # =\u003e ['a', 'b', 'c']\nhomepage.cache[Date.new(2021, 4, 1)..Date.new(2021, 4, 2)] # =\u003e ['a', 'b']\n\nhomepage.cache.delete_at(Date.new(2021, 4, 1))\nhomepage.cache.range(Date.new(2021, 4, 1), Date.new(2021, 4, 3)) # =\u003e [nil, 'b', 'c']\nhomepage.cache.at(Date.new(2021, 4, 2)) # =\u003e #\u003cRedis::Value key=\"homepage:1:cache:2021-04-02\"\u003e\nhomepage.cache.at(Date.new(2021, 4, 2)).value # 'b'\n```\n\n#### Periodical Values Family\n\n- `annual_value`\n  - Key format: `model_name:id:field_name:yyyy`\n  - Redis is a highly volatile key-value store, so I don't recommend using it.\n- `monthly_value`\n  - Key format: `model_name:id:field_name:yyyy-mm`\n- `weekly_value`\n  - Key format: `model_name:id:field_name:yyyyWw`\n- `daily_value`\n  - Key format: `model_name:id:field_name:yyyy-mm-dd`\n- `hourly_value`\n  - Key format: `model_name:id:field_name:yyyy-mm-ddThh`\n- `minutely_value`\n  - Key format: `model_name:id:field_name:yyyy-mm-ddThh:mi`\n\n### Periodical Hashes\n\nThe periodical hashes also automatically switches the save destination when the date changes.\n\n```rb\n# 2021-04-01\nhomepage.browsing_history.incr('item1')\nhomepage.browsing_history.incr('item2')\nhomepage.browsing_history.incr('item2')\nputs homepage.browsing_history.all # { 'item1' =\u003e '1', 'item2' =\u003e '2' }\n\n# 2021-04-02 (next day)\nputs homepage.browsing_history.all # {}\n\nhomepage.browsing_history.bulk_set('item1' =\u003e 3, 'item3' =\u003e 5)\nputs homepage.browsing_history.all # { 'item1' =\u003e '3', 'item3' =\u003e '5' }\n\n# 2021-04-03 (next day)\nhomepage.browsing_history.incr('item2')\nhomepage.browsing_history.incr('item4')\nputs homepage.browsing_history.all # { 'item2' =\u003e '1', 'item4' =\u003e '1' }\n\nhomepage.browsing_history[Date.new(2021, 4, 1)] # =\u003e { 'item1' =\u003e '1', 'item2' =\u003e '2' }\nhomepage.browsing_history[Date.new(2021, 4, 1), 3] # =\u003e { 'item1' =\u003e '4', 'item2' =\u003e '3', 'item3' =\u003e '5', 'item4' =\u003e '1' }\nhomepage.browsing_history[Date.new(2021, 4, 1)..Date.new(2021, 4, 2)] # =\u003e { 'item1' =\u003e '4', 'item2' =\u003e '2', 'item3' =\u003e '5' }\n\nhomepage.browsing_history.delete_at(Date.new(2021, 4, 1))\nhomepage.browsing_history.range(Date.new(2021, 4, 1), Date.new(2021, 4, 3)) # =\u003e { 'item1' =\u003e '3', 'item2' =\u003e '1', 'item3' =\u003e '5', 'item4' =\u003e '1' }\nhomepage.browsing_history.at(Date.new(2021, 4, 2)) # =\u003e #\u003cRedis::HashKey key=\"homepage:1:browsing_history:2021-04-02\"\u003e\nhomepage.browsing_history.at(Date.new(2021, 4, 2)).all # { 'item1' =\u003e '3', 'item3' =\u003e '5' }\n```\n\n#### Periodical Hashes Family\n\n- `annual_hash_key`\n  - Key format: `model_name:id:field_name:yyyy`\n  - Redis is a highly volatile key-value store, so I don't recommend using it.\n- `monthly_hash_key`\n  - Key format: `model_name:id:field_name:yyyy-mm`\n- `weekly_hash_key`\n  - Key format: `model_name:id:field_name:yyyyWw`\n- `daily_hash_key`\n  - Key format: `model_name:id:field_name:yyyy-mm-dd`\n- `hourly_hash_key`\n  - Key format: `model_name:id:field_name:yyyy-mm-ddThh`\n- `minutely_hash_key`\n  - Key format: `model_name:id:field_name:yyyy-mm-ddThh:mi`\n\n### Periodical Sets\n\nThe periodical sets also automatically switches the save destination when the date changes.\n\n```rb\n# 2021-04-01\nhomepage.dau \u003c\u003c 'user1'\nhomepage.dau \u003c\u003c 'user2'\nhomepage.dau \u003c\u003c 'user1' # dup ignored\nputs homepage.dau.members # ['user1', 'user2']\nputs homepage.dau.length # 2\nputs homepage.dau.count # alias of #length\n\n# 2021-04-02 (next day)\nputs homepage.dau.members # []\n\nhomepage.dau.merge('user2', 'user3')\nputs homepage.dau.members # ['user2', 'user3']\n\n# 2021-04-03 (next day)\nhomepage.dau.merge('user4')\n\nhomepage.dau[Date.new(2021, 4, 1)] # =\u003e ['user1', 'user2']\nhomepage.dau[Date.new(2021, 4, 1), 3] # =\u003e ['user1', 'user2', 'user3', 'user4']\nhomepage.dau[Date.new(2021, 4, 1)..Date.new(2021, 4, 2)] # =\u003e ['user1', 'user2', 'user3']\n\nhomepage.dau.delete_at(Date.new(2021, 4, 1))\nhomepage.dau.range(Date.new(2021, 4, 1), Date.new(2021, 4, 3)) # =\u003e ['user2', 'user3', 'user4']\nhomepage.dau.at(Date.new(2021, 4, 2)) # =\u003e #\u003cRedis::Set key=\"homepage:1:dau:2021-04-02\"\u003e\nhomepage.dau.at(Date.new(2021, 4, 2)).members # ['user2', 'user3']\n```\n\n#### Periodical Sets Family\n\n- `annual_set`\n  - Key format: `model_name:id:field_name:yyyy`\n  - Redis is a highly volatile key-value store, so I don't recommend using it.\n- `monthly_set`\n  - Key format: `model_name:id:field_name:yyyy-mm`\n- `weekly_set`\n  - Key format: `model_name:id:field_name:yyyyWw`\n- `daily_set`\n  - Key format: `model_name:id:field_name:yyyy-mm-dd`\n- `hourly_set`\n  - Key format: `model_name:id:field_name:yyyy-mm-ddThh`\n- `minutely_set`\n  - Key format: `model_name:id:field_name:yyyy-mm-ddThh:mi`\n\n### Timezone\n\nThis gem follows Ruby process' time zone, but if you extends Time class by ActiveSupport (e.g. `Time.current`), follows Rails process' timezone.\n\n## Development\n\nThe development environment for this gem is configured with docker-compose.\nPlease use the following command:\n\n    $ docker-compose up -d\n    $ docker-compose run --rm ruby bundle\n    $ docker-compose run --rm ruby rspec .\n    $ docker-compose run --rm ruby rubocop -a\n\n## Contributing\n\nBug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/redis-objects-periodical. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/[USERNAME]/redis-objects-periodical/blob/master/CODE_OF_CONDUCT.md).\n\n## License\n\nThe gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).\n\n## Code of Conduct\n\nEveryone interacting in the Redis::Objects::Daily::Counter project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/redis-objects-periodical/blob/master/CODE_OF_CONDUCT.md).\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fryz310%2Fredis-objects-periodical","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fryz310%2Fredis-objects-periodical","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fryz310%2Fredis-objects-periodical/lists"}