mudis-rails 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: 3bfa9942e1a544cbccc6beccddfef7ebc1cd4a45efcea25169a8dcf8431dbb17
4
+ data.tar.gz: 8e881b4869355fb3bb80d10ad30498ff4ae86b2ac0fa2e622b4246eabb936b83
5
+ SHA512:
6
+ metadata.gz: 517ac684b354633e78dc2c5518373cfbe4e7ddf6ae4ba334318f8723c10ca81e1a11209ab51934d36cbbed13230f3e4ea7134cd034095e1d727b256486b969dc
7
+ data.tar.gz: 6b542052a56b0d3ddedefda58a53756e67c677eb985b6c5b77507856fea69a917f0e7379d93bf516824e6e1a80e8777048da9fb432016076430958ec4f7f3d68
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 kiebor81
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,136 @@
1
+ [![RubyMine](https://www.elegantobjects.org/rubymine.svg)](https://www.jetbrains.com/ruby/)
2
+
3
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
4
+
5
+ # Mudis-Rails
6
+
7
+ A small Rails plugin for [Mudis](https://github.com/kiebor81/mudis) that gives you a one-command install and an optional Rails cache store wrapper.
8
+
9
+ ## Install
10
+
11
+ Add to your Gemfile:
12
+
13
+ ```ruby
14
+ gem "mudis"
15
+ gem "mudis-rails"
16
+ ```
17
+
18
+ Then install the initializer:
19
+
20
+ ```bash
21
+ bin/rails g mudis:install
22
+ ```
23
+
24
+ ## Quickstart
25
+
26
+ The generator creates `config/initializers/mudis.rb` with sensible defaults:
27
+
28
+ ```ruby
29
+ require "mudis"
30
+ require "mudis-rails"
31
+
32
+ Mudis::Rails.install(
33
+ use_as_cache_store: true,
34
+ cache_store_options: { namespace: "mudis" },
35
+ mudis_options: {
36
+ serializer: JSON,
37
+ compress: true,
38
+ max_value_bytes: 2_000_000,
39
+ hard_memory_limit: true,
40
+ max_bytes: 1_073_741_824,
41
+ eviction_threshold: 0.9
42
+ }
43
+ )
44
+ ```
45
+
46
+ This will:
47
+
48
+ - Configure Mudis using `mudis_options`.
49
+ - Start the expiry thread.
50
+ - Stop the expiry thread at shutdown.
51
+ - Wire `Rails.cache` to a `Mudis::Rails::Store` wrapper if `use_as_cache_store` is true.
52
+
53
+ ## IPC Mode (Puma)
54
+
55
+ IPC is configured from `config/puma.rb`, not a Rails initializer. The plugin provides helpers that match the Mudis README flow:
56
+
57
+ ```ruby
58
+ # config/puma.rb
59
+ preload_app!
60
+
61
+ before_fork do
62
+ require "mudis-rails"
63
+
64
+ Mudis::Rails.puma_before_fork!(
65
+ mudis_options: {
66
+ serializer: JSON,
67
+ compress: true,
68
+ max_value_bytes: 2_000_000,
69
+ hard_memory_limit: true,
70
+ max_bytes: 1_073_741_824
71
+ }
72
+ )
73
+ end
74
+
75
+ on_worker_boot do
76
+ require "mudis-rails"
77
+
78
+ Mudis::Rails.puma_on_worker_boot!(proxy: true)
79
+ end
80
+ ```
81
+
82
+ Notes:
83
+
84
+ - `puma_before_fork!` starts the expiry thread and `MudisServer`.
85
+ - `puma_on_worker_boot!` creates `$mudis` and optionally requires `mudis_proxy`.
86
+
87
+ ## Persistence
88
+
89
+ If you enable Mudis persistence, you can auto-load the snapshot on boot:
90
+
91
+ ```ruby
92
+ Mudis::Rails.install(
93
+ persistence_load_on_boot: true,
94
+ mudis_options: {
95
+ persistence_enabled: true,
96
+ persistence_path: "tmp/mudis_snapshot.dump",
97
+ persistence_format: :marshal,
98
+ persistence_safe_write: true
99
+ }
100
+ )
101
+ ```
102
+
103
+ ## Manual Install
104
+
105
+ If you prefer to control configuration in your own initializer:
106
+
107
+ ```ruby
108
+ Mudis::Rails.configure do |c|
109
+ c.enabled = true
110
+ c.use_as_cache_store = true
111
+ c.override_cache_store = false
112
+ c.cache_store_options = { namespace: "mudis" }
113
+ c.mudis_options = {
114
+ serializer: JSON,
115
+ compress: true,
116
+ max_bytes: 512 * 1024 * 1024
117
+ }
118
+ c.persistence_load_on_boot = false
119
+ end
120
+
121
+ Mudis::Rails.install
122
+ ```
123
+
124
+ ## Compatibility
125
+
126
+ Mudis Core Plugin Version Status
127
+ >= 0.9 0.1.x Supported
128
+
129
+ ## Notes
130
+
131
+ - The plugin does not auto-install on `require`. Use the generator or call `Mudis::Rails.install` explicitly.
132
+ - If you already set `config.cache_store`, `Mudis::Rails.install` will not override it unless `override_cache_store` is true.
133
+
134
+ ## License
135
+
136
+ MIT
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "mudis"
4
+ require "mudis-rails"
5
+
6
+ Mudis::Rails.install(
7
+ use_as_cache_store: true,
8
+ cache_store_options: {
9
+ namespace: "mudis"
10
+ },
11
+ # persistence_load_on_boot: true,
12
+ mudis_options: {
13
+ serializer: JSON,
14
+ compress: true,
15
+ max_value_bytes: 2_000_000,
16
+ hard_memory_limit: true,
17
+ max_bytes: 1_073_741_824,
18
+ eviction_threshold: 0.9
19
+ }
20
+ )
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails/generators"
4
+
5
+ module Mudis
6
+ module Generators
7
+ class InstallGenerator < ::Rails::Generators::Base
8
+ source_root File.expand_path("install/templates", __dir__)
9
+ desc "Creates a Mudis initializer."
10
+
11
+ def copy_initializer
12
+ template "mudis.rb", "config/initializers/mudis.rb"
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Mudis
4
+ module Rails
5
+ class Config
6
+ attr_accessor :enabled,
7
+ :auto_install,
8
+ :auto_start_expiry_thread,
9
+ :expiry_thread_interval,
10
+ :auto_stop_expiry_thread,
11
+ :use_as_cache_store,
12
+ :override_cache_store,
13
+ :cache_store_options,
14
+ :mudis_options,
15
+ :ipc_proxy,
16
+ :persistence_load_on_boot
17
+
18
+ def initialize
19
+ @enabled = true
20
+ @auto_install = false
21
+ @auto_start_expiry_thread = true
22
+ @expiry_thread_interval = 60
23
+ @auto_stop_expiry_thread = true
24
+ @use_as_cache_store = false
25
+ @override_cache_store = false
26
+ @cache_store_options = {}
27
+ @mudis_options = {}
28
+ @ipc_proxy = true
29
+ @persistence_load_on_boot = false
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails/railtie"
4
+
5
+ class Mudis
6
+ module Rails
7
+ class Railtie < ::Rails::Railtie
8
+ initializer "mudis-rails.install", after: :load_config_initializers do
9
+ next unless Mudis::Rails.config.auto_install
10
+
11
+ Mudis::Rails.install
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,83 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/cache"
4
+
5
+ class Mudis
6
+ module Rails
7
+ class Store < ::ActiveSupport::Cache::Store
8
+ def initialize(options = nil)
9
+ options ||= {}
10
+ @mudis = options.delete(:mudis) || ::Mudis
11
+ super(options)
12
+ end
13
+
14
+ def read_entry(key, **options)
15
+ ns = options[:namespace]
16
+ key = denamespaced_key(key, ns)
17
+ value = @mudis.read(key, namespace: ns)
18
+ return if value.nil?
19
+
20
+ ::ActiveSupport::Cache::Entry.new(value, expires_in: options[:expires_in], version: options[:version])
21
+ end
22
+
23
+ def write_entry(key, entry, **options)
24
+ ns = options[:namespace]
25
+ key = denamespaced_key(key, ns)
26
+ @mudis.write(key, entry.value, expires_in: options[:expires_in], namespace: ns)
27
+ true
28
+ end
29
+
30
+ def delete_entry(key, **options)
31
+ ns = options[:namespace]
32
+ key = denamespaced_key(key, ns)
33
+ @mudis.delete(key, namespace: ns)
34
+ true
35
+ end
36
+
37
+ def clear(options = nil)
38
+ options ||= {}
39
+ namespace = options[:namespace]
40
+ if namespace
41
+ @mudis.clear_namespace(namespace: namespace)
42
+ return true
43
+ end
44
+
45
+ @mudis.all_keys.each { |key| @mudis.delete(key) }
46
+ true
47
+ end
48
+
49
+ def fetch_multi(*names)
50
+ return super if names.empty?
51
+
52
+ options = names.extract_options!
53
+ results = {}
54
+
55
+ names.each do |name|
56
+ value = read(name, **options)
57
+ results[name] = value if value
58
+ end
59
+
60
+ if block_given?
61
+ names.each do |name|
62
+ next if results.key?(name)
63
+
64
+ results[name] = yield(name)
65
+ write(name, results[name], **options)
66
+ end
67
+ end
68
+
69
+ results
70
+ end
71
+
72
+ private
73
+
74
+ def denamespaced_key(key, namespace)
75
+ return key if namespace.nil?
76
+ return key unless key.is_a?(String)
77
+
78
+ prefix = "#{namespace}:"
79
+ key.start_with?(prefix) ? key.delete_prefix(prefix) : key
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Mudis
4
+ module Rails
5
+ VERSION = "0.1.0"
6
+ end
7
+ end
@@ -0,0 +1,117 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "rails/version"
4
+ require_relative "rails/config"
5
+
6
+ class Mudis
7
+ module Rails
8
+ class << self
9
+ def configure
10
+ yield(config)
11
+ end
12
+
13
+ def config
14
+ @config ||= Config.new
15
+ end
16
+
17
+ def install(mudis: ::Mudis, **options)
18
+ apply_options!(options)
19
+ return unless config.enabled
20
+
21
+ ensure_rails!
22
+ apply_mudis_options!(mudis)
23
+ install_cache_store!(mudis)
24
+ load_persistence!(mudis)
25
+ start_expiry_thread!(mudis)
26
+ install_shutdown_hook!(mudis)
27
+ end
28
+
29
+ def puma_before_fork!(mudis: ::Mudis, **options)
30
+ apply_options!(options)
31
+ return unless config.enabled
32
+
33
+ apply_mudis_options!(mudis)
34
+ load_persistence!(mudis)
35
+ start_expiry_thread!(mudis)
36
+ require "mudis_server" unless defined?(MudisServer)
37
+ MudisServer.start!
38
+ end
39
+
40
+ def puma_on_worker_boot!(proxy: nil)
41
+ proxy = config.ipc_proxy if proxy.nil?
42
+
43
+ require "mudis_client" unless defined?(MudisClient)
44
+ $mudis = MudisClient.new
45
+ require "mudis_proxy" if proxy
46
+ end
47
+
48
+ def uninstall(mudis: ::Mudis)
49
+ return unless defined?(::Rails)
50
+
51
+ if config.use_as_cache_store && config.override_cache_store
52
+ ::Rails.application.config.cache_store = nil
53
+ end
54
+
55
+ mudis.stop_expiry_thread if config.auto_stop_expiry_thread
56
+ end
57
+
58
+ private
59
+
60
+ def apply_options!(options)
61
+ options.each do |key, value|
62
+ next unless config.respond_to?("#{key}=")
63
+
64
+ config.public_send("#{key}=", value)
65
+ end
66
+ end
67
+
68
+ def ensure_rails!
69
+ return if defined?(::Rails)
70
+
71
+ raise "Mudis::Rails.install requires Rails to be loaded"
72
+ end
73
+
74
+ def apply_mudis_options!(mudis)
75
+ return if config.mudis_options.empty?
76
+
77
+ mudis.configure do |c|
78
+ config.mudis_options.each do |key, value|
79
+ setter = "#{key}="
80
+ c.public_send(setter, value) if c.respond_to?(setter)
81
+ end
82
+ end
83
+ end
84
+
85
+ def install_cache_store!(mudis)
86
+ return unless config.use_as_cache_store
87
+
88
+ require_relative "rails/store"
89
+ cache_store = ::Rails.application.config.cache_store
90
+ return if cache_store && !config.override_cache_store
91
+
92
+ options = { mudis: mudis }.merge(config.cache_store_options)
93
+ ::Rails.application.config.cache_store = [Mudis::Rails::Store, options]
94
+ end
95
+
96
+ def start_expiry_thread!(mudis)
97
+ return unless config.auto_start_expiry_thread
98
+
99
+ mudis.start_expiry_thread(interval: config.expiry_thread_interval)
100
+ end
101
+
102
+ def load_persistence!(mudis)
103
+ return unless config.persistence_load_on_boot
104
+
105
+ mudis.load_snapshot!
106
+ end
107
+
108
+ def install_shutdown_hook!(mudis)
109
+ return unless config.auto_stop_expiry_thread
110
+
111
+ at_exit { mudis.stop_expiry_thread }
112
+ end
113
+ end
114
+ end
115
+ end
116
+
117
+ require_relative "rails/railtie" if defined?(::Rails::Railtie)
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "mudis"
4
+ require_relative "mudis/rails"
metadata ADDED
@@ -0,0 +1,119 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mudis-rails
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - kiebor81
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 2026-02-08 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: mudis
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - "~>"
17
+ - !ruby/object:Gem::Version
18
+ version: '0.9'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - "~>"
24
+ - !ruby/object:Gem::Version
25
+ version: '0.9'
26
+ - !ruby/object:Gem::Dependency
27
+ name: activesupport
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - "~>"
31
+ - !ruby/object:Gem::Version
32
+ version: '6.0'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '6.0'
40
+ - !ruby/object:Gem::Dependency
41
+ name: railties
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '6.0'
47
+ type: :runtime
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '6.0'
54
+ - !ruby/object:Gem::Dependency
55
+ name: rspec
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '3.12'
61
+ type: :development
62
+ prerelease: false
63
+ version_requirements: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '3.12'
68
+ - !ruby/object:Gem::Dependency
69
+ name: simplecov
70
+ requirement: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: '0.22'
75
+ type: :development
76
+ prerelease: false
77
+ version_requirements: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: '0.22'
82
+ description: Rails plugin for Mudis with an installer, generator, and cache store
83
+ wrapper.
84
+ executables: []
85
+ extensions: []
86
+ extra_rdoc_files: []
87
+ files:
88
+ - LICENSE.txt
89
+ - README.md
90
+ - lib/generators/mudis/install/templates/mudis.rb
91
+ - lib/generators/mudis/install_generator.rb
92
+ - lib/mudis-rails.rb
93
+ - lib/mudis/rails.rb
94
+ - lib/mudis/rails/config.rb
95
+ - lib/mudis/rails/railtie.rb
96
+ - lib/mudis/rails/store.rb
97
+ - lib/mudis/rails/version.rb
98
+ homepage: https://github.com/kiebor81/mudis
99
+ licenses:
100
+ - MIT
101
+ metadata: {}
102
+ rdoc_options: []
103
+ require_paths:
104
+ - lib
105
+ required_ruby_version: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - ">="
108
+ - !ruby/object:Gem::Version
109
+ version: '3.3'
110
+ required_rubygems_version: !ruby/object:Gem::Requirement
111
+ requirements:
112
+ - - ">="
113
+ - !ruby/object:Gem::Version
114
+ version: '0'
115
+ requirements: []
116
+ rubygems_version: 3.6.2
117
+ specification_version: 4
118
+ summary: Rails integration helpers for Mudis.
119
+ test_files: []