esse-hooks 0.0.1.beta1

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: 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: []