activefunction-core 0.0.1 → 0.1.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a64c7260d306142ff9c0b5e48d0cd34c9258e65af3e19bbd7aa6b1121a8a3eff
4
- data.tar.gz: 14514dbbad34d5f8b64fadd0b146c5a1f90a955578cbf5e51fe161af4d5939ad
3
+ metadata.gz: 7598948c858b823027e2c33a190a17920f466ce55ea96138bc9a01ac75899e74
4
+ data.tar.gz: 57b9189b07f384420404db190dcea2cd2b7aa40e714f732713f252fddb34590d
5
5
  SHA512:
6
- metadata.gz: 13038598288b048965d93d6299bc7fe1feda28f28bcee220c87d5361f59060e43c07d44089279840da2c3877dd8a100aacad5b32216a692b9497f431ebab0cdc
7
- data.tar.gz: 3522dd0d9db78ac518093fc9b7f4bf9be48da2593ef63fe0766e7a51b04ab729b63ef521fdc5a0f115fabac0f7207268d02cb586f3aabd50561408adabd47464
6
+ metadata.gz: 10c87d5b48dcbb1fc3e0aa0711d4dcc4125f6210bbd0b1f96d081e4aadb6bf0feb6028abc0161fa69ca3fd380b5001ec044bc833cc83f5da9479772da16ad133
7
+ data.tar.gz: 124281e35afce65ca63ca07a4e80ac32167b97104f2c22ab70578fdf280989ef75fc1131dbeef003991857f1462dd0f9eb87b5c00197080573c1cd71ed3a7f09
data/CHANGELOG.md CHANGED
@@ -1,3 +1,7 @@
1
1
  ## [0.1.0]
2
2
 
3
3
  - Introduce ruby-next integration
4
+
5
+ ## [0.1.1]
6
+
7
+ - Bump ruby-next to 1.0.0
@@ -0,0 +1,138 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveFunctionCore
4
+ module Plugins
5
+ module Hooks
6
+ class MissingCallbackContext < Error
7
+ MESSAGE_TEMPLATE = "Missing callback context: %s"
8
+
9
+ attr_reader :message
10
+
11
+ def initialize(context)
12
+ @message = MESSAGE_TEMPLATE % context
13
+ end
14
+ end
15
+
16
+ class MissingHookableMethod < Error
17
+ MESSAGE_TEMPLATE = "Method %s is not defined"
18
+
19
+ attr_reader :message
20
+
21
+ def initialize(method_name)
22
+ @message = MESSAGE_TEMPLATE % method_name
23
+ end
24
+ end
25
+
26
+ def self.included(base)
27
+ base.extend(ClassMethods)
28
+ base.include(InstanceMethods)
29
+ end
30
+
31
+ module InstanceMethods
32
+ private
33
+
34
+ def with_callbacks(method_name, &block)
35
+ callbacks = _callbacks(method_name)
36
+
37
+ _run_callbacks(callbacks.before)
38
+
39
+ result = yield
40
+
41
+ _run_callbacks(callbacks.after)
42
+
43
+ result
44
+ end
45
+
46
+ def _callbacks(method_name)
47
+ self.class.hooks[method_name].callbacks
48
+ end
49
+
50
+ def _run_callbacks(callbacks)
51
+ callbacks.each do |callback|
52
+ raise(MissingCallbackContext, callback) unless respond_to?(callback.target, true)
53
+
54
+ send(callback.target) if _executable?(callback.options)
55
+ end
56
+ end
57
+
58
+ def _executable?(options)
59
+ return false if options[:if] && !send(options[:if])
60
+
61
+ true
62
+ end
63
+ end
64
+
65
+ module ClassMethods
66
+ TYPES = %i[before after].freeze
67
+ # rubocop:disable Lint/ConstantDefinitionInBlock
68
+ Hooks = Data.define(:hooks) do
69
+ def initialize(hooks: {}) ; super; end
70
+ def deep_dup ; Marshal.load(Marshal.dump(self)); end
71
+ def all ; hooks; end
72
+ def [](method_name) ; hooks[method_name]; end
73
+
74
+ def add_hook(method_name)
75
+ hooks[method_name] = Hook[method_name]
76
+ end
77
+ end
78
+
79
+ Hook = Data.define(:method_name, :callbacks) do
80
+ Callbacks = Data.define(:before, :after) do
81
+ def initialize(before: [], after: []) ; super; end
82
+ def [](type) ; public_send(type); end
83
+ end
84
+ Callback = Data.define(:target, :options)
85
+
86
+ def initialize(method_name:, callbacks: Callbacks.new) ; super; end
87
+ def hashes(type) ; Set.new callbacks[type].map(&:hash); end
88
+
89
+ def add_callback(type:, target:, options: {})
90
+ new_callbacks = Callback[target, options]
91
+ callbacks[type] << new_callbacks unless hashes(type) === new_callbacks.hash
92
+ end
93
+ end
94
+ # rubocop:enable Lint/ConstantDefinitionInBlock
95
+
96
+ def define_hooks_for(*method_names)
97
+ method_names.each do |method_name|
98
+ override_hookable_method(method_name)
99
+
100
+ hooks.add_hook(method_name)
101
+
102
+ define_callback_methods_for(method_name)
103
+ end
104
+ end
105
+
106
+ def set_callback(type, method_name, target, options = {})
107
+ hooks[method_name].add_callback(type: type, target: target, options: options)
108
+ end
109
+
110
+ def hooks
111
+ @__hooks ||= Hooks.new
112
+ end
113
+
114
+ private
115
+
116
+ def inherited(subclass)
117
+ subclass.instance_variable_set(:@__hooks, @__hooks.deep_dup)
118
+ end
119
+
120
+ def override_hookable_method(method_name)
121
+ raise(MissingHookableMethod, method_name) unless method_defined?(method_name)
122
+
123
+ define_method(method_name) do |*args|
124
+ with_callbacks(method_name) { super(*args) }
125
+ end
126
+ end
127
+
128
+ def define_callback_methods_for(method_name)
129
+ TYPES.each do |type|
130
+ define_singleton_method("#{type}_#{method_name}") do |target, options = {}|
131
+ set_callback(type, method_name, target, options)
132
+ end
133
+ end
134
+ end
135
+ end
136
+ end
137
+ end
138
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActiveFunctionCore
4
- VERSION = "0.0.1"
4
+ VERSION = "0.1.1"
5
5
  end
@@ -7,5 +7,7 @@ RubyNext::Language.setup_gem_load_path(transpile: true)
7
7
  module ActiveFunctionCore
8
8
  class Error < StandardError; end
9
9
 
10
+ require "plugins/hooks"
11
+
10
12
  require "active_function_core/version"
11
13
  end
@@ -0,0 +1,138 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveFunctionCore
4
+ module Plugins
5
+ module Hooks
6
+ class MissingCallbackContext < Error
7
+ MESSAGE_TEMPLATE = "Missing callback context: %s"
8
+
9
+ attr_reader :message
10
+
11
+ def initialize(context)
12
+ @message = MESSAGE_TEMPLATE % context
13
+ end
14
+ end
15
+
16
+ class MissingHookableMethod < Error
17
+ MESSAGE_TEMPLATE = "Method %s is not defined"
18
+
19
+ attr_reader :message
20
+
21
+ def initialize(method_name)
22
+ @message = MESSAGE_TEMPLATE % method_name
23
+ end
24
+ end
25
+
26
+ def self.included(base)
27
+ base.extend(ClassMethods)
28
+ base.include(InstanceMethods)
29
+ end
30
+
31
+ module InstanceMethods
32
+ private
33
+
34
+ def with_callbacks(method_name, &block)
35
+ callbacks = _callbacks(method_name)
36
+
37
+ _run_callbacks(callbacks.before)
38
+
39
+ result = yield
40
+
41
+ _run_callbacks(callbacks.after)
42
+
43
+ result
44
+ end
45
+
46
+ def _callbacks(method_name)
47
+ self.class.hooks[method_name].callbacks
48
+ end
49
+
50
+ def _run_callbacks(callbacks)
51
+ callbacks.each do |callback|
52
+ raise(MissingCallbackContext, callback) unless respond_to?(callback.target, true)
53
+
54
+ send(callback.target) if _executable?(callback.options)
55
+ end
56
+ end
57
+
58
+ def _executable?(options)
59
+ return false if options[:if] && !send(options[:if])
60
+
61
+ true
62
+ end
63
+ end
64
+
65
+ module ClassMethods
66
+ TYPES = %i[before after].freeze
67
+ # rubocop:disable Lint/ConstantDefinitionInBlock
68
+ Hooks = Data.define(:hooks) do
69
+ def initialize(hooks: {}) = super
70
+ def deep_dup = Marshal.load(Marshal.dump(self))
71
+ def all = hooks
72
+ def [](method_name) = hooks[method_name]
73
+
74
+ def add_hook(method_name)
75
+ hooks[method_name] = Hook[method_name]
76
+ end
77
+ end
78
+
79
+ Hook = Data.define(:method_name, :callbacks) do
80
+ Callbacks = Data.define(:before, :after) do
81
+ def initialize(before: [], after: []) = super
82
+ def [](type) = public_send(type)
83
+ end
84
+ Callback = Data.define(:target, :options)
85
+
86
+ def initialize(method_name:, callbacks: Callbacks.new) = super
87
+ def hashes(type) = Set.new callbacks[type].map(&:hash)
88
+
89
+ def add_callback(type:, target:, options: {})
90
+ new_callbacks = Callback[target, options]
91
+ callbacks[type] << new_callbacks unless hashes(type) === new_callbacks.hash
92
+ end
93
+ end
94
+ # rubocop:enable Lint/ConstantDefinitionInBlock
95
+
96
+ def define_hooks_for(*method_names)
97
+ method_names.each do |method_name|
98
+ override_hookable_method(method_name)
99
+
100
+ hooks.add_hook(method_name)
101
+
102
+ define_callback_methods_for(method_name)
103
+ end
104
+ end
105
+
106
+ def set_callback(type, method_name, target, options = {})
107
+ hooks[method_name].add_callback(type: type, target: target, options: options)
108
+ end
109
+
110
+ def hooks
111
+ @__hooks ||= Hooks.new
112
+ end
113
+
114
+ private
115
+
116
+ def inherited(subclass)
117
+ subclass.instance_variable_set(:@__hooks, @__hooks.deep_dup)
118
+ end
119
+
120
+ def override_hookable_method(method_name)
121
+ raise(MissingHookableMethod, method_name) unless method_defined?(method_name)
122
+
123
+ define_method(method_name) do |*args|
124
+ with_callbacks(method_name) { super(*args) }
125
+ end
126
+ end
127
+
128
+ def define_callback_methods_for(method_name)
129
+ TYPES.each do |type|
130
+ define_singleton_method("#{type}_#{method_name}") do |target, options = {}|
131
+ set_callback(type, method_name, target, options)
132
+ end
133
+ end
134
+ end
135
+ end
136
+ end
137
+ end
138
+ end
metadata CHANGED
@@ -1,35 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activefunction-core
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nerbyk
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-08-20 00:00:00.000000000 Z
11
+ date: 2023-12-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ruby-next-core
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
18
- - !ruby/object:Gem::Version
19
- version: '0.15'
20
17
  - - ">="
21
18
  - !ruby/object:Gem::Version
22
- version: 0.15.3
19
+ version: 1.0.0
23
20
  type: :runtime
24
21
  prerelease: false
25
22
  version_requirements: !ruby/object:Gem::Requirement
26
23
  requirements:
27
- - - "~>"
28
- - !ruby/object:Gem::Version
29
- version: '0.15'
30
24
  - - ">="
31
25
  - !ruby/object:Gem::Version
32
- version: 0.15.3
26
+ version: 1.0.0
33
27
  description: Provides core functionality, plugins and ruby-next integration for ActiveFunction
34
28
  email:
35
29
  - danil.maximov2000@gmail.com
@@ -40,8 +34,10 @@ files:
40
34
  - CHANGELOG.md
41
35
  - LICENSE.txt
42
36
  - README.md
37
+ - lib/.rbnext/3.0/plugins/hooks.rb
43
38
  - lib/active_function_core.rb
44
39
  - lib/active_function_core/version.rb
40
+ - lib/plugins/hooks.rb
45
41
  - sig/active_function_core.rbs
46
42
  - sig/manifest.yml
47
43
  homepage: https://github.com/DanilMaximov/activefunction