activefunction-core 0.0.1 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
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