esse-hooks 0.0.1.beta1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: b702dd473e90d0f68a109b65f5a561051f7b2778c467eb438d0ef88f09ef9211
4
+ data.tar.gz: 5387dee13603073cfb9fb30af8cfdf855f09f76902040d512cf6554f0446c7d8
5
+ SHA512:
6
+ metadata.gz: 01d4d906bda088c82b28c011fdb07e0a74b98cd9255564ff7d7058d96218233935d5011ce9267452b13c3e61aa98ed9bd236e5d5ffea2b39973bf758df1b60bc
7
+ data.tar.gz: 783f2bca4c6ab24e9f667deb2da4086a66fe593a5d35867332eb25f66c946b82b0ce599fea56fe24bb8831e2eb6143ea6b22a74f27582de8768add22e139ce51
data/.rubocop.yml ADDED
@@ -0,0 +1,35 @@
1
+ inherit_mode:
2
+ merge:
3
+ - Exclude
4
+
5
+ require:
6
+ - rubocop-performance
7
+ - rubocop-rspec
8
+ - standard/cop/block_single_line_braces
9
+
10
+ inherit_gem:
11
+ standard: config/base.yml
12
+
13
+ AllCops:
14
+ TargetRubyVersion: 2.6
15
+ SuggestExtensions: false
16
+ Exclude:
17
+ - "db/**/*"
18
+ - "tmp/**/*"
19
+ - "vendor/**/*"
20
+ NewCops: enable
21
+
22
+ RSpec/MultipleExpectations:
23
+ Enabled: false
24
+
25
+ RSpec/ExampleLength:
26
+ Enabled: false
27
+
28
+ RSpec/MultipleMemoizedHelpers:
29
+ Enabled: false
30
+
31
+ RSpec/MessageSpies:
32
+ Enabled: false
33
+
34
+ RSpec/StubbedMock:
35
+ Enabled: false
data/CHANGELOG.md ADDED
@@ -0,0 +1,9 @@
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/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
+
7
+ ## 0.0.1.beta1
8
+ The first release of the esse-hooks gem.
9
+ * Added: Initial implementation of the hooks extension.
data/Gemfile ADDED
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+
5
+ git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
6
+
7
+ gem "esse"
8
+ gem "esse-rspec"
9
+ gem "pry"
10
+ gem "dotenv"
11
+ gem "rubocop"
12
+ gem "rubocop-performance"
13
+ gem "rubocop-rspec"
14
+ gem "standard"
15
+ gem "elasticsearch", "~> 7.17", ">= 7.17.10"
16
+ gem "webmock"
17
+
18
+ # Specify your gem"s dependencies in esse-hooks.gemspec
19
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,131 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ esse-hooks (0.0.1.beta1)
5
+ esse (>= 0.3.0)
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ addressable (2.8.7)
11
+ public_suffix (>= 2.0.2, < 7.0)
12
+ ast (2.4.2)
13
+ base64 (0.2.0)
14
+ bigdecimal (3.1.9)
15
+ coderay (1.1.3)
16
+ crack (1.0.0)
17
+ bigdecimal
18
+ rexml
19
+ diff-lcs (1.5.1)
20
+ dotenv (2.8.1)
21
+ elasticsearch (7.17.11)
22
+ elasticsearch-api (= 7.17.11)
23
+ elasticsearch-transport (= 7.17.11)
24
+ elasticsearch-api (7.17.11)
25
+ multi_json
26
+ elasticsearch-transport (7.17.11)
27
+ base64
28
+ faraday (>= 1, < 3)
29
+ multi_json
30
+ esse (0.3.5)
31
+ multi_json
32
+ thor (>= 0.19)
33
+ esse-rspec (0.0.6)
34
+ esse (>= 0.2.4)
35
+ rspec (>= 3)
36
+ faraday (2.8.1)
37
+ base64
38
+ faraday-net_http (>= 2.0, < 3.1)
39
+ ruby2_keywords (>= 0.0.4)
40
+ faraday-net_http (3.0.2)
41
+ hashdiff (1.1.0)
42
+ json (2.9.1)
43
+ language_server-protocol (3.17.0.3)
44
+ lint_roller (1.1.0)
45
+ method_source (1.1.0)
46
+ multi_json (1.15.0)
47
+ parallel (1.26.3)
48
+ parser (3.3.7.0)
49
+ ast (~> 2.4.1)
50
+ racc
51
+ pry (0.15.2)
52
+ coderay (~> 1.1)
53
+ method_source (~> 1.0)
54
+ public_suffix (5.1.1)
55
+ racc (1.8.1)
56
+ rainbow (3.1.1)
57
+ regexp_parser (2.10.0)
58
+ rexml (3.3.1)
59
+ strscan
60
+ rspec (3.13.0)
61
+ rspec-core (~> 3.13.0)
62
+ rspec-expectations (~> 3.13.0)
63
+ rspec-mocks (~> 3.13.0)
64
+ rspec-core (3.13.2)
65
+ rspec-support (~> 3.13.0)
66
+ rspec-expectations (3.13.3)
67
+ diff-lcs (>= 1.2.0, < 2.0)
68
+ rspec-support (~> 3.13.0)
69
+ rspec-mocks (3.13.2)
70
+ diff-lcs (>= 1.2.0, < 2.0)
71
+ rspec-support (~> 3.13.0)
72
+ rspec-support (3.13.2)
73
+ rubocop (1.70.0)
74
+ json (~> 2.3)
75
+ language_server-protocol (>= 3.17.0)
76
+ parallel (~> 1.10)
77
+ parser (>= 3.3.0.2)
78
+ rainbow (>= 2.2.2, < 4.0)
79
+ regexp_parser (>= 2.9.3, < 3.0)
80
+ rubocop-ast (>= 1.36.2, < 2.0)
81
+ ruby-progressbar (~> 1.7)
82
+ unicode-display_width (>= 2.4.0, < 4.0)
83
+ rubocop-ast (1.37.0)
84
+ parser (>= 3.3.1.0)
85
+ rubocop-performance (1.21.1)
86
+ rubocop (>= 1.48.1, < 2.0)
87
+ rubocop-ast (>= 1.31.1, < 2.0)
88
+ rubocop-rspec (3.4.0)
89
+ rubocop (~> 1.61)
90
+ ruby-progressbar (1.13.0)
91
+ ruby2_keywords (0.0.5)
92
+ standard (1.35.0.1)
93
+ language_server-protocol (~> 3.17.0.2)
94
+ lint_roller (~> 1.0)
95
+ rubocop (~> 1.62)
96
+ standard-custom (~> 1.0.0)
97
+ standard-performance (~> 1.3)
98
+ standard-custom (1.0.2)
99
+ lint_roller (~> 1.0)
100
+ rubocop (~> 1.50)
101
+ standard-performance (1.4.0)
102
+ lint_roller (~> 1.1)
103
+ rubocop-performance (~> 1.21.0)
104
+ strscan (3.1.0)
105
+ thor (1.3.2)
106
+ unicode-display_width (3.1.4)
107
+ unicode-emoji (~> 4.0, >= 4.0.4)
108
+ unicode-emoji (4.0.4)
109
+ webmock (3.23.1)
110
+ addressable (>= 2.8.0)
111
+ crack (>= 0.3.2)
112
+ hashdiff (>= 0.4.0, < 2.0.0)
113
+
114
+ PLATFORMS
115
+ x86_64-linux
116
+
117
+ DEPENDENCIES
118
+ dotenv
119
+ elasticsearch (~> 7.17, >= 7.17.10)
120
+ esse
121
+ esse-hooks!
122
+ esse-rspec
123
+ pry
124
+ rubocop
125
+ rubocop-performance
126
+ rubocop-rspec
127
+ standard
128
+ webmock
129
+
130
+ BUNDLED WITH
131
+ 2.3.26
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2022 Marcos G. Zimmermann
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
13
+ all 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
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,81 @@
1
+ # Esse Hooks Extension
2
+
3
+ This gem is an internal component for the [esse](https://github.com/marcosgz/esse) project. It provides a plugin to add hooks to the [esse-active_record](https://github.com/marcosgz/esse-active_record) and [esse-sequel](https://github.com/marcosgz/esse-sequel) plugins.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'esse-hooks'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle install
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install esse-hooks
20
+
21
+ ## Usage
22
+
23
+ Using the `esse-active_record` as example. It adds hooks to the `Esse::ActiveRecord::Hooks` module.
24
+
25
+ ```ruby
26
+ module Esse::ActiveRecord::Hooks
27
+ include Esse::Hooks[store_key: :esse_active_record_hooks]
28
+ end
29
+ ```
30
+
31
+ and then you can use the hooks to change activeness of the indexing process.
32
+
33
+ ```ruby
34
+ Esse::ActiveRecord::Hooks.disable!
35
+ Esse::ActiveRecord::Hooks.with_indexing do
36
+ 10.times { User.create! }
37
+ end
38
+
39
+ Esse::ActiveRecord::Hooks.enable!
40
+ Esse::ActiveRecord::Hooks.without_indexing do
41
+ 10.times { User.create! }
42
+ end
43
+ ```
44
+
45
+ or by some specific list of index or index's repository
46
+
47
+ ```ruby
48
+ Esse::ActiveRecord::Hooks.disable!(UsersIndex.repo)
49
+ Esse::ActiveRecord::Hooks.with_indexing(AccountsIndex, UsersIndex.repo) do
50
+ 10.times { User.create! }
51
+ end
52
+ Esse::ActiveRecord::Hooks.enable!(UsersIndex.repo)
53
+ Esse::ActiveRecord::Hooks.without_indexing(AccountsIndex, UsersIndex.repo) do
54
+ 10.times { User.create! }
55
+ end
56
+ ```
57
+
58
+ In case you are using both `esse-active_record` and `esse-sequel` plugins, you can use the `Esse::Hooks` module directly to interact with both hooks at the same time.
59
+
60
+ ```ruby
61
+ Esse::Hooks.disable!
62
+ Esse::Hooks.with_indexing do
63
+ 10.times { User.create! }
64
+ end
65
+ Esse::Hooks.enable!
66
+ ```
67
+
68
+
69
+ ## Development
70
+
71
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake none` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
72
+
73
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
74
+
75
+ ## Contributing
76
+
77
+ Bug reports and pull requests are welcome on GitHub at https://github.com/marcosgz/esse-hooks.
78
+
79
+ ## License
80
+
81
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ task default: :spec
@@ -0,0 +1,257 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Esse::Hooks::Mixin < Module
4
+ attr_reader :store_key
5
+
6
+ def initialize(store_key:)
7
+ @store_key = store_key
8
+ end
9
+
10
+ def included(base)
11
+ store_store_key = store_key # closure
12
+ base.define_singleton_method(:store_key) { store_store_key }
13
+ base.extend(ClassMethods)
14
+ end
15
+
16
+ module ClassMethods
17
+ def register_model(model_class)
18
+ unless model_class.respond_to?(:esse_callbacks)
19
+ raise ArgumentError, "Model class #{model_class} should have a `esse_callbacks' method"
20
+ end
21
+
22
+ @models ||= []
23
+ @models |= [model_class]
24
+ end
25
+
26
+ def models
27
+ @models || []
28
+ end
29
+
30
+ def model_names
31
+ models.map(&:to_s)
32
+ end
33
+
34
+ # Global enable indexing callbacks. If no repository is specified, all repositories will be enabled.
35
+ # @param repos [Array<String, Esse::Index, Esse::Repo>]
36
+ # @return [void]
37
+ def enable!(*repos)
38
+ filter_repositories(*repos).each do |repo|
39
+ state[:repos][repo] = true
40
+ end
41
+ end
42
+
43
+ # Global disable indexing callbacks. If no repository is specified, all repositories will be disabled.
44
+ # @param repos [Array<String, Esse::Index, Esse::Repo>]
45
+ # @return [void]
46
+ def disable!(*repos)
47
+ filter_repositories(*repos).each do |repo|
48
+ state[:repos][repo] = false
49
+ end
50
+ end
51
+
52
+ # Check if the given repository is enabled for indexing. If no repository is specified, all repositories will be checked.
53
+ #
54
+ # @param repos [Array<String, Esse::Index, Esse::Repo>]
55
+ # @return [Boolean]
56
+ def disabled?(*repos)
57
+ filter_repositories(*repos).all? { |repo| !state[:repos][repo] }
58
+ end
59
+
60
+ # Check if the given repository is enabled for indexing. If no repository is specified, all repositories will be checked.
61
+ #
62
+ # @param repos [Array<String, Esse::Index, Esse::Repo>]
63
+ # @return [Boolean]
64
+ def enabled?(*repos)
65
+ filter_repositories(*repos).all? { |repo| state[:repos][repo] }
66
+ end
67
+
68
+ # Enable model indexing callbacks for the given model. If no repository is specified, all repositories will be enabled.
69
+ #
70
+ # @param model_class [Class]
71
+ # @param repos [Array<String, Esse::Index, Esse::Repo>]
72
+ # @raise [ArgumentError] if model repository is not registered for the given model
73
+ # @return [void]
74
+ def enable_model!(model_class, *repos)
75
+ ensure_registered_model_class!(model_class)
76
+ filter_model_repositories(model_class, *repos).each do |repo|
77
+ state[:models][model_class][repo] = true
78
+ end
79
+ end
80
+
81
+ # Disable model indexing callbacks for the given model. If no repository is specified, all repositories will be disabled.
82
+ #
83
+ # @param model_class [Class]
84
+ # @param repos [Array<String, Esse::Index, Esse::Repo>]
85
+ # @raise [ArgumentError] if model repository is not registered for the given model
86
+ # @return [void]
87
+ def disable_model!(model_class, *repos)
88
+ ensure_registered_model_class!(model_class)
89
+ filter_model_repositories(model_class, *repos).each do |repo|
90
+ state[:models][model_class][repo] = false
91
+ end
92
+ end
93
+
94
+ def ensure_registered_model_class!(model_class)
95
+ return if registered_model_class?(model_class)
96
+
97
+ raise ArgumentError, "Model class #{model_class} is not registered. The model should inherit from Esse::ActiveRecord::Model and have a `index_callback' callback defined"
98
+ end
99
+
100
+ # Check if the given model is enabled for indexing. If no repository is specified, all repositories will be checked.
101
+ #
102
+ # @param model_class [Class]
103
+ # @param repos [Array<String, Esse::Index, Esse::Repo>]
104
+ # @return [Boolean]
105
+ def enabled_for_model?(model_class, *repos)
106
+ return false unless registered_model_class?(model_class)
107
+
108
+ filter_model_repositories(model_class, *repos).all? do |repo|
109
+ state.dig(:models, model_class, repo) != false
110
+ end
111
+ end
112
+
113
+ # Disable indexing callbacks execution for the block execution.
114
+ # Example:
115
+ # Esse::ActiveRecord::Hooks.without_indexing { User.create! }
116
+ # Esse::ActiveRecord::Hooks.without_indexing(UsersIndex, AccountsIndex.repo(:user)) { User.create! }
117
+ def without_indexing(*repos)
118
+ state_before_disable = state[:repos].dup
119
+ disable!(*repos)
120
+
121
+ yield
122
+ ensure
123
+ state[:repos] = state_before_disable
124
+ end
125
+
126
+ # Enable the indexing callbacks execution for the block execution.
127
+ # Example:
128
+ # Esse::ActiveRecord::Hooks.with_indexing { User.create! }
129
+ # Esse::ActiveRecord::Hooks.with_indexing(UsersIndex, AccountsIndex.repo(:user)) { User.create! }
130
+ def with_indexing(*repos)
131
+ state_before_enable = state[:repos].dup
132
+ enable!(*repos)
133
+
134
+ yield
135
+ ensure
136
+ state[:repos] = state_before_enable
137
+ end
138
+
139
+ # Disable model indexing callbacks execution for the block execution for the given model.
140
+ # Example:
141
+ # BroadcastChanges.without_indexing_for_model(User) { }
142
+ # BroadcastChanges.without_indexing_for_model(User, :datasync, :other) { }
143
+ def without_indexing_for_model(model_class, *repos)
144
+ state_before_disable = state[:models].dig(model_class).dup
145
+ disable_model!(model_class, *repos)
146
+ yield
147
+ ensure
148
+ if state_before_disable.nil?
149
+ state[:models].delete(model_class)
150
+ else
151
+ state[:models][model_class] = state_before_disable
152
+ end
153
+ end
154
+
155
+ # Enable model indexing callbacks execution for the block execution for the given model.
156
+ # Example:
157
+ # BroadcastChanges.with_indexing_for_model(User) { }
158
+ # BroadcastChanges.with_indexing_for_model(User, :datasync, :other) { }
159
+ def with_indexing_for_model(model_class, *repos)
160
+ state_before_enable = state[:models].dig(model_class).dup
161
+ enable_model!(model_class, *repos)
162
+ yield
163
+ ensure
164
+ if state_before_enable.nil?
165
+ state[:models].delete(model_class)
166
+ else
167
+ state[:models][model_class] = state_before_enable
168
+ end
169
+ end
170
+
171
+ def resolve_index_repository(name)
172
+ index_name, repo_name = Esse::Hooks::Primitives::String.new(name).underscore.split("::").join("/").split(":", 2)
173
+ if index_name !~ /(I|_i)ndex$/ && index_name !~ /_index\/([\w_]+)$/
174
+ index_name = format("%<index_name>s_index", index_name: index_name)
175
+ end
176
+ klass = Esse::Hooks::Primitives::String.new(index_name).classify.constantize
177
+ return klass if klass <= Esse::Repository
178
+
179
+ repo_name ? klass.repo(repo_name) : klass.repo
180
+ end
181
+
182
+ private
183
+
184
+ def all_repos
185
+ models.flat_map { |model_class| model_repos(model_class) }.uniq
186
+ end
187
+
188
+ # Returns a list of all repositories for the given model
189
+ # @return [Array<Symbol>]
190
+ def model_repos(model_class)
191
+ expand_index_repos(*model_class.esse_callbacks.keys)
192
+ end
193
+
194
+ # Returns a list of all repositories for the given model
195
+ # If no repository is specified, all repositories will be returned.
196
+ # @return [Array<*Esse::Repository>] List of repositories
197
+ def filter_repositories(*repos)
198
+ filtered_repos = expand_index_repos(*repos) & all_repos
199
+ filtered_repos.empty? ? all_repos : filtered_repos
200
+ end
201
+
202
+ # Return repositorys for the given model. If no repository is specified, all repositories will be returned.
203
+ #
204
+ # @param model_class [Class]
205
+ # @param repos [Array<*Esse::Repository>] List of repositories to check for the given model
206
+ # @return [Array<*Esse::Repository>] List of repositories
207
+ def filter_model_repositories(model_class, *repos)
208
+ model_repos = model_repos(model_class) & all_repos
209
+ filtered_repos = expand_index_repos(*repos) & model_repos
210
+ filtered_repos.empty? ? model_repos : filtered_repos
211
+ end
212
+
213
+ def expand_index_repos(*repos)
214
+ repos.flat_map do |repo_name|
215
+ case repo_name
216
+ when Class
217
+ (repo_name <= Esse::Index) ? repo_name.repo_hash.values : repo_name
218
+ when String, Symbol
219
+ resolve_index_repository(repo_name)
220
+ else
221
+ raise ArgumentError, "Invalid index or repository name: #{repo_name.inspect}"
222
+ end
223
+ end
224
+ end
225
+
226
+ # Check if model class is registered
227
+ # @return [Boolean] true if model class is registered
228
+ def registered_model_class?(model_class)
229
+ models.include?(model_class)
230
+ end
231
+
232
+ # Data Structure:
233
+ #
234
+ # repos: { <Esse::Repository class> => <true|false>, ... }
235
+ # models: {
236
+ # <ActiveRecord::Base class> => {
237
+ # <Esse::Repository class> => <true|false>
238
+ # }
239
+ # }
240
+ def state
241
+ global_store[store_key] ||= {
242
+ repos: all_repos.map { |k| [k, true] }.to_h, # Control global state of the index repository level
243
+ models: Hash.new { |h, k| h[k] = {} } # Control the state of the model & index repository level
244
+ }
245
+ end
246
+
247
+ def global_store
248
+ Thread.current
249
+ end
250
+
251
+ private
252
+
253
+ def store_key
254
+ raise NotImplementedError, "You must implement the `store_key` method"
255
+ end
256
+ end
257
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ begin
4
+ require "dry/inflector"
5
+ rescue LoadError
6
+ # noop
7
+ end
8
+
9
+ begin
10
+ require "active_support/inflector"
11
+ rescue LoadError
12
+ # noop
13
+ end
14
+
15
+ module Esse::Hooks::Primitives
16
+ class String < ::String
17
+ def classify
18
+ new_str = if defined?(Dry::Inflector)
19
+ Dry::Inflector.new.classify(self)
20
+ elsif defined?(ActiveSupport::Inflector)
21
+ ActiveSupport::Inflector.classify(self)
22
+ else
23
+ split("/").collect do |c|
24
+ c.split("_").collect(&:capitalize).join
25
+ end.join("::")
26
+ end
27
+
28
+ self.class.new(new_str)
29
+ end
30
+
31
+ def constantize
32
+ if defined?(Dry::Inflector)
33
+ Dry::Inflector.new.constantize(self)
34
+ elsif defined?(ActiveSupport::Inflector)
35
+ ActiveSupport::Inflector.constantize(self)
36
+ else
37
+ Object.const_get(self)
38
+ end
39
+ end
40
+
41
+ def underscore
42
+ new_str = sub(/^::/, "")
43
+ .gsub("::", "/")
44
+ .gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
45
+ .gsub(/([a-z\d])([A-Z])/, '\1_\2')
46
+ .tr("-", "_")
47
+ .tr(".", "_")
48
+ .gsub(/\s/, "_")
49
+ .gsub(/__+/, "_")
50
+ .downcase
51
+
52
+ self.class.new(new_str)
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Esse
4
+ module Hooks
5
+ VERSION = "0.0.1.beta1"
6
+ end
7
+ end
data/lib/esse/hooks.rb ADDED
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "esse"
4
+ require_relative "hooks/version"
5
+ require_relative "hooks/mixin"
6
+ require_relative "hooks/primitives/string"
7
+
8
+ module Esse
9
+ # Esse::Hooks is a module that extends Esse with hooks capabilities.
10
+ #
11
+ # @example
12
+ # module Esse::ActiveRecord::Hooks
13
+ # include Esse::Hooks[store_key: :esse_active_record_hooks]
14
+ module Hooks
15
+ @@hooks = {}.freeze
16
+
17
+ module_function
18
+
19
+ # Global variable with list of hooks.
20
+ #
21
+ # @return [Hash{Symbol => Module}]
22
+ def hooks
23
+ @@hooks
24
+ end
25
+
26
+ # Register a hook.
27
+ #
28
+ # @param [Symbol] name The hook name.
29
+ # @param [Module] hook The hook module.
30
+ def [](store_key:)
31
+ mixin = Mixin.new(store_key: store_key)
32
+ dup = @@hooks.dup
33
+ dup[mixin.store_key] = mixin
34
+ @@hooks = dup.freeze
35
+ mixin
36
+ end
37
+
38
+ %i[
39
+ enable!
40
+ disable!
41
+ with_indexing
42
+ with_indexing_for_model
43
+ without_indexing
44
+ without_indexing_for_model
45
+ ].each do |method_name|
46
+ define_method(method_name) do |*args, &block|
47
+ hooks.each_value do |mixin|
48
+ mixin.public_send(method_name, *args, &block)
49
+ end
50
+ end
51
+ end
52
+
53
+ %i[
54
+ disabled?
55
+ enabled?
56
+ ].each do |method_name|
57
+ define_method(method_name) do
58
+ hooks.values.all?(&method_name)
59
+ end
60
+ end
61
+ end
62
+ end
data/mise.toml ADDED
@@ -0,0 +1,2 @@
1
+ [tools]
2
+ ruby = "2.7.7"
metadata ADDED
@@ -0,0 +1,73 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: esse-hooks
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1.beta1
5
+ platform: ruby
6
+ authors:
7
+ - Marcos G. Zimmermann
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2025-01-21 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: esse
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 0.3.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 0.3.0
27
+ description: A set of hooks extensions for Esse, the Ruby ElasticSearch and OpenSearch
28
+ client.
29
+ email:
30
+ - mgzmaster@gmail.com
31
+ executables: []
32
+ extensions: []
33
+ extra_rdoc_files: []
34
+ files:
35
+ - ".rubocop.yml"
36
+ - CHANGELOG.md
37
+ - Gemfile
38
+ - Gemfile.lock
39
+ - LICENSE.txt
40
+ - README.md
41
+ - Rakefile
42
+ - lib/esse/hooks.rb
43
+ - lib/esse/hooks/mixin.rb
44
+ - lib/esse/hooks/primitives/string.rb
45
+ - lib/esse/hooks/version.rb
46
+ - mise.toml
47
+ homepage: https://github.com/marcosgz/esse-hooks
48
+ licenses:
49
+ - MIT
50
+ metadata:
51
+ homepage_uri: https://github.com/marcosgz/esse-hooks
52
+ source_code_uri: https://github.com/marcosgz/esse-hooks
53
+ changelog_uri: https://github.com/marcosgz/esse-hooks/blob/main/CHANGELOG.md
54
+ post_install_message:
55
+ rdoc_options: []
56
+ require_paths:
57
+ - lib
58
+ required_ruby_version: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: 2.4.0
63
+ required_rubygems_version: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">"
66
+ - !ruby/object:Gem::Version
67
+ version: 1.3.1
68
+ requirements: []
69
+ rubygems_version: 3.1.6
70
+ signing_key:
71
+ specification_version: 4
72
+ summary: Hooks extensions for Esse
73
+ test_files: []