activefunction-core 0.2.2 → 0.2.4

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: 3a045fbb4310661d2138bc88e36d439cc3550ad2cc624ff3926a5fb318b401be
4
- data.tar.gz: 4998dcbf2e70ccd30faf4dae572c4603eebb7089bf779a1e12722a7f3a1b78c7
3
+ metadata.gz: 8a465c40b90d43fd3c76b4317525e8d17e3550eca9d63b17f876bf020bb9a32c
4
+ data.tar.gz: a97b604efa34aa7ddc56bc0c9bf15becbbe50fe953e572a1195d0cdf5a0585b0
5
5
  SHA512:
6
- metadata.gz: 2dd8fd3d26f7a265de9b86d514697b12d6eda475cafbd06fb09918a0aa67d0b0aed7245b0c785a8689e4d7f3ccf678c6f4522790c4c1084607e06545a9eeff91
7
- data.tar.gz: aef48c75c71d2b71e72489e63480c5565e445ee0483e42444789303b9f82b217af0d862f7d541699eb1407ac321605c99d0edfda017e05697034eeaed40ba782
6
+ metadata.gz: 03d8ae8f232799054b8452a71fb070021cd44b10d0b6dbcf1ee4dd85308266ede988cffdcf9d8447bd60a5eb2d92601bd740c5eb4d9775c885e8434ce4760f61
7
+ data.tar.gz: 623a32ed667bd7ef18006b619b6aafb025ebd232fe12bc111a9a8f5526e61cc23216a7637b6d31546b56cd379a0878374d00a8183e6c7737f121ebbdf3e246eb
data/CHANGELOG.md CHANGED
@@ -19,3 +19,9 @@
19
19
 
20
20
  - Republish 0.2.1
21
21
 
22
+ ## [0.2.3]
23
+
24
+ - YARD Doc Added
25
+
26
+ ## [0.2.4]
27
+ - Fix Plugins
data/README.md CHANGED
@@ -57,7 +57,7 @@ Supports options for `before_[method_name]` & `after_[method_name]` callbacks. E
57
57
  ```ruby
58
58
 
59
59
  class YourClass
60
- include ActiveFunction::Core::Plugins::Hooks
60
+ include ActiveFunctionCore::Plugins::Hooks
61
61
 
62
62
  define_hooks_for :your_method
63
63
 
@@ -11,15 +11,60 @@ end
11
11
 
12
12
  module ActiveFunctionCore
13
13
  module Plugins
14
+ # Provides ActiveSupport::Callbacks like DSL for defining before and after callbacks around methods
15
+ # @see ClassMethods DSL methods.
16
+ # @example Hooks with default callback options
17
+ # class YourClass
18
+ # include ActiveFunctionCore::Plugins::Hooks
19
+ #
20
+ # define_hooks_for :your_method
21
+ #
22
+ # before_your_method :do_something_before, if: :condition_met?
23
+ # after_your_method :do_something_after, unless: :condition_met?
24
+ #
25
+ # def your_method
26
+ # # Method implementation here...
27
+ # end
28
+ #
29
+ # private
30
+ #
31
+ # def condition_met?
32
+ # # Condition logic here...
33
+ # end
34
+ #
35
+ # def do_something_before
36
+ # # Callback logic to execute before your_method
37
+ # end
38
+ #
39
+ # def do_something_after
40
+ # # Callback logic to execute after your_method
41
+ # end
42
+ # end
43
+ # @example Hooks with custom callback options
44
+ # class YourClass
45
+ # include ActiveFunction::Core::Plugins::Hooks
46
+ #
47
+ # set_callback_options only: ->(only_methods, context:) { only_methods.include?(context.action) }
48
+ #
49
+ # define_hooks_for :your_method
50
+ #
51
+ # before_your_method :do_something_before, only: %[foo bar]
52
+ #
53
+ # def action = "foo"
54
+ # end
14
55
  module Hooks
56
+ # Represents a hook with callbacks for a specific method.
15
57
  class Hook < Data.define(:method_name, :callbacks)
16
58
  DEFAULT_CALLBACK_OPTIONS = {
17
59
  if: ->(v, context:) { context.send(v) if context.respond_to?(v, true) },
18
60
  unless: ->(v, context:) { !context.send(v) if context.respond_to?(v, true) }
19
61
  }.freeze
20
62
  SUPPORTED_CALLBACKS = %i[before after].freeze
21
-
22
- Callback = Data.define(:options, :target) do
63
+ # Represents a callback with options.
64
+ Callback = Data.define(:options, :target) do
65
+ # Runs the callback within the specified contex.
66
+ #
67
+ # @param context [Object] instance of class with callbacks.
23
68
  def run(context)
24
69
  raise ArgumentError, "Callback target #{target} is not defined" unless context.respond_to?(target, true)
25
70
  raise ArgumentError, ":callback_options is not defined in #{context.class}" unless context.class.respond_to?(:callback_options)
@@ -41,6 +86,14 @@ module ActiveFunctionCore
41
86
  super(callbacks: callbacks.to_h { |_1| [_1, []] }, **__kwrest__)
42
87
  end
43
88
 
89
+ # Adds a callback to the hook.
90
+ #
91
+ # @param type [Symbol] the type of callback, `:before` or `:after`
92
+ # @param target [Symbol] the name of the callback method.
93
+ # @param options [Hash] the options for the callback.
94
+ # @options options [Symbol] :if the name of the method to check before executing the callback.
95
+ # @options options [Symbol] :unless the name of the method to check before executing the callback.
96
+ # @raise [ArgumentError] if callback already defined.
44
97
  def add_callback(type:, target:, options: {})
45
98
  callbacks[type] << Callback[options, target].tap do |callback|
46
99
  next unless callbacks[type].map(&:hash).to_set === callback.hash
@@ -49,6 +102,11 @@ module ActiveFunctionCore
49
102
  end
50
103
  end
51
104
 
105
+ # Runs all callbacks for the hook.
106
+ #
107
+ # @param context [Object] instance of class with defined hook.
108
+ # @yield [*args] block of code around which callbacks will be executed.
109
+ # @return the result of the block.
52
110
  def run_callbacks(context, &block)
53
111
  callbacks[:before].each { |it| it.run(context) }
54
112
 
@@ -60,24 +118,33 @@ module ActiveFunctionCore
60
118
  end
61
119
  end
62
120
 
63
- def self.included(base)
64
- base.extend(ClassMethods)
65
- end
66
-
121
+ # DSL method for {ActiveFunctionCore::Plugins::Hooks}
67
122
  module ClassMethods
123
+ # Returns all setuped hooks for the class.
68
124
  def hooks ; @__hooks ||= {}; end
125
+
126
+ # Returns all setuped custom callback options for the class.
69
127
  def callback_options ; @__callback_options ||= Hook::DEFAULT_CALLBACK_OPTIONS.dup; end
70
128
 
129
+ # Inherited callback to ensure that callbacks are inherited from the base class.
71
130
  def inherited(subclass)
72
131
  subclass.instance_variable_set(:@__hooks, Marshal.load(Marshal.dump(hooks)))
73
132
  subclass.instance_variable_set(:@__callback_options, callback_options.dup)
74
133
  end
75
134
 
135
+ # Setups hooks for provided method.
76
136
  # Redefines method providing callbacks calls around it.
77
- # Defines `before_[name]` and `after_[name]` methods for setting callbacks.
137
+ # Defines *before_[name]* and *after_[name]* methods for setting callbacks.
138
+ #
139
+ # @example
140
+ # define_hooks_for :process, name: :action
141
+ # before_action :set_first
142
+ # after_action :set_last, if: :ok?
78
143
  #
79
144
  # @param method [Symbol] the name of the callbackable method.
80
145
  # @param name [Symbol] alias for hooked method before_[name] & after_[name] methods.
146
+ # @raise [ArgumentError] if hook for method already defined.
147
+ # @raise [ArgumentError] if method is not defined.
81
148
  def define_hooks_for(method, name: method)
82
149
  raise(ArgumentError, "Hook for #{method} are already defined") if hooks.key?(method)
83
150
  raise(ArgumentError, "Method #{method} is not defined") unless method_defined?(method)
@@ -101,11 +168,18 @@ module ActiveFunctionCore
101
168
 
102
169
  # Sets a callback for an existing hook'ed method.
103
170
  #
171
+ # @example
172
+ # define_hooks_for :action
173
+ # set_callback :before, :action, :set_first
174
+ #
104
175
  # @param type [Symbol] the type of callback, `:before` or `:after`
105
176
  # @param method_name [Symbol] the name of the callbackable method.
106
177
  # @param target [Symbol] the name of the callback method.
107
178
  # @param options [Hash] the options for the callback.
108
- # @options options [Symbol] :if the name of the method to check before executing the callback.
179
+ # @option options [Symbol] :if the name of the booled method to call before executing the callback.
180
+ # @option options [Symbol] :unless the name of the booled method to call before executing the callback.
181
+ # @raise [ArgumentError] if hook for provided method is not setuped via ::define_hooks_for.
182
+ # @raise [ArgumentError] if unsupported @options was passed.
109
183
  def set_callback(type, method_name, target, options = {})
110
184
  raise(ArgumentError, "Hook for :#{method_name} is not defined") unless hooks.key?(method_name)
111
185
  raise(ArgumentError, "Hook Callback accepts only #{callback_options.keys} options") if (options.keys - callback_options.keys).any?
@@ -115,7 +189,14 @@ module ActiveFunctionCore
115
189
 
116
190
  # Sets a custom callback option.
117
191
  #
118
- # @param name [Symbol] the name of the option.
192
+ # @example
193
+ # set_callback_option only: ->(args, context:) { args.to_set === context.current_action }
194
+ # define_hooks_for :action
195
+ # before_action :set_first, only: :index
196
+ #
197
+ # @param option [Hash{Symbol => Proc}] The custom callback option as a single-value hash.
198
+ # - :name [Symbol] The name of the option.
199
+ # - :block [Proc] The block to call.
119
200
  # @yield [*attrs, context:] the block to call.
120
201
  # @yieldparam attrs [*] the attributes passed to the option.
121
202
  # @yieldparam context [Object] the instance context (optional).
@@ -125,6 +206,10 @@ module ActiveFunctionCore
125
206
  callback_options[name] = block
126
207
  end
127
208
  end
209
+
210
+ def self.included(base)
211
+ base.extend(ClassMethods)
212
+ end
128
213
  end
129
214
  end
130
215
  end
@@ -11,15 +11,60 @@ end
11
11
 
12
12
  module ActiveFunctionCore
13
13
  module Plugins
14
+ # Provides ActiveSupport::Callbacks like DSL for defining before and after callbacks around methods
15
+ # @see ClassMethods DSL methods.
16
+ # @example Hooks with default callback options
17
+ # class YourClass
18
+ # include ActiveFunctionCore::Plugins::Hooks
19
+ #
20
+ # define_hooks_for :your_method
21
+ #
22
+ # before_your_method :do_something_before, if: :condition_met?
23
+ # after_your_method :do_something_after, unless: :condition_met?
24
+ #
25
+ # def your_method
26
+ # # Method implementation here...
27
+ # end
28
+ #
29
+ # private
30
+ #
31
+ # def condition_met?
32
+ # # Condition logic here...
33
+ # end
34
+ #
35
+ # def do_something_before
36
+ # # Callback logic to execute before your_method
37
+ # end
38
+ #
39
+ # def do_something_after
40
+ # # Callback logic to execute after your_method
41
+ # end
42
+ # end
43
+ # @example Hooks with custom callback options
44
+ # class YourClass
45
+ # include ActiveFunction::Core::Plugins::Hooks
46
+ #
47
+ # set_callback_options only: ->(only_methods, context:) { only_methods.include?(context.action) }
48
+ #
49
+ # define_hooks_for :your_method
50
+ #
51
+ # before_your_method :do_something_before, only: %[foo bar]
52
+ #
53
+ # def action = "foo"
54
+ # end
14
55
  module Hooks
56
+ # Represents a hook with callbacks for a specific method.
15
57
  class Hook < Data.define(:method_name, :callbacks)
16
58
  DEFAULT_CALLBACK_OPTIONS = {
17
59
  if: ->(v, context:) { context.send(v) if context.respond_to?(v, true) },
18
60
  unless: ->(v, context:) { !context.send(v) if context.respond_to?(v, true) }
19
61
  }.freeze
20
62
  SUPPORTED_CALLBACKS = %i[before after].freeze
21
-
22
- Callback = Data.define(:options, :target) do
63
+ # Represents a callback with options.
64
+ Callback = Data.define(:options, :target) do
65
+ # Runs the callback within the specified contex.
66
+ #
67
+ # @param context [Object] instance of class with callbacks.
23
68
  def run(context)
24
69
  raise ArgumentError, "Callback target #{target} is not defined" unless context.respond_to?(target, true)
25
70
  raise ArgumentError, ":callback_options is not defined in #{context.class}" unless context.class.respond_to?(:callback_options)
@@ -41,6 +86,14 @@ module ActiveFunctionCore
41
86
  super(callbacks: callbacks.to_h { [_1, []] }, **__kwrest__)
42
87
  end
43
88
 
89
+ # Adds a callback to the hook.
90
+ #
91
+ # @param type [Symbol] the type of callback, `:before` or `:after`
92
+ # @param target [Symbol] the name of the callback method.
93
+ # @param options [Hash] the options for the callback.
94
+ # @options options [Symbol] :if the name of the method to check before executing the callback.
95
+ # @options options [Symbol] :unless the name of the method to check before executing the callback.
96
+ # @raise [ArgumentError] if callback already defined.
44
97
  def add_callback(type:, target:, options: {})
45
98
  callbacks[type] << Callback[options, target].tap do |callback|
46
99
  next unless callbacks[type].map(&:hash).to_set === callback.hash
@@ -49,6 +102,11 @@ module ActiveFunctionCore
49
102
  end
50
103
  end
51
104
 
105
+ # Runs all callbacks for the hook.
106
+ #
107
+ # @param context [Object] instance of class with defined hook.
108
+ # @yield [*args] block of code around which callbacks will be executed.
109
+ # @return the result of the block.
52
110
  def run_callbacks(context, &block)
53
111
  callbacks[:before].each { |it| it.run(context) }
54
112
 
@@ -60,24 +118,33 @@ module ActiveFunctionCore
60
118
  end
61
119
  end
62
120
 
63
- def self.included(base)
64
- base.extend(ClassMethods)
65
- end
66
-
121
+ # DSL method for {ActiveFunctionCore::Plugins::Hooks}
67
122
  module ClassMethods
123
+ # Returns all setuped hooks for the class.
68
124
  def hooks ; @__hooks ||= {}; end
125
+
126
+ # Returns all setuped custom callback options for the class.
69
127
  def callback_options ; @__callback_options ||= Hook::DEFAULT_CALLBACK_OPTIONS.dup; end
70
128
 
129
+ # Inherited callback to ensure that callbacks are inherited from the base class.
71
130
  def inherited(subclass)
72
131
  subclass.instance_variable_set(:@__hooks, Marshal.load(Marshal.dump(hooks)))
73
132
  subclass.instance_variable_set(:@__callback_options, callback_options.dup)
74
133
  end
75
134
 
135
+ # Setups hooks for provided method.
76
136
  # Redefines method providing callbacks calls around it.
77
- # Defines `before_[name]` and `after_[name]` methods for setting callbacks.
137
+ # Defines *before_[name]* and *after_[name]* methods for setting callbacks.
138
+ #
139
+ # @example
140
+ # define_hooks_for :process, name: :action
141
+ # before_action :set_first
142
+ # after_action :set_last, if: :ok?
78
143
  #
79
144
  # @param method [Symbol] the name of the callbackable method.
80
145
  # @param name [Symbol] alias for hooked method before_[name] & after_[name] methods.
146
+ # @raise [ArgumentError] if hook for method already defined.
147
+ # @raise [ArgumentError] if method is not defined.
81
148
  def define_hooks_for(method, name: method)
82
149
  raise(ArgumentError, "Hook for #{method} are already defined") if hooks.key?(method)
83
150
  raise(ArgumentError, "Method #{method} is not defined") unless method_defined?(method)
@@ -101,11 +168,18 @@ module ActiveFunctionCore
101
168
 
102
169
  # Sets a callback for an existing hook'ed method.
103
170
  #
171
+ # @example
172
+ # define_hooks_for :action
173
+ # set_callback :before, :action, :set_first
174
+ #
104
175
  # @param type [Symbol] the type of callback, `:before` or `:after`
105
176
  # @param method_name [Symbol] the name of the callbackable method.
106
177
  # @param target [Symbol] the name of the callback method.
107
178
  # @param options [Hash] the options for the callback.
108
- # @options options [Symbol] :if the name of the method to check before executing the callback.
179
+ # @option options [Symbol] :if the name of the booled method to call before executing the callback.
180
+ # @option options [Symbol] :unless the name of the booled method to call before executing the callback.
181
+ # @raise [ArgumentError] if hook for provided method is not setuped via ::define_hooks_for.
182
+ # @raise [ArgumentError] if unsupported @options was passed.
109
183
  def set_callback(type, method_name, target, options = {})
110
184
  raise(ArgumentError, "Hook for :#{method_name} is not defined") unless hooks.key?(method_name)
111
185
  raise(ArgumentError, "Hook Callback accepts only #{callback_options.keys} options") if (options.keys - callback_options.keys).any?
@@ -115,7 +189,14 @@ module ActiveFunctionCore
115
189
 
116
190
  # Sets a custom callback option.
117
191
  #
118
- # @param name [Symbol] the name of the option.
192
+ # @example
193
+ # set_callback_option only: ->(args, context:) { args.to_set === context.current_action }
194
+ # define_hooks_for :action
195
+ # before_action :set_first, only: :index
196
+ #
197
+ # @param option [Hash{Symbol => Proc}] The custom callback option as a single-value hash.
198
+ # - :name [Symbol] The name of the option.
199
+ # - :block [Proc] The block to call.
119
200
  # @yield [*attrs, context:] the block to call.
120
201
  # @yieldparam attrs [*] the attributes passed to the option.
121
202
  # @yieldparam context [Object] the instance context (optional).
@@ -125,6 +206,10 @@ module ActiveFunctionCore
125
206
  callback_options[name] = block
126
207
  end
127
208
  end
209
+
210
+ def self.included(base)
211
+ base.extend(ClassMethods)
212
+ end
128
213
  end
129
214
  end
130
215
  end
@@ -11,15 +11,60 @@ end
11
11
 
12
12
  module ActiveFunctionCore
13
13
  module Plugins
14
+ # Provides ActiveSupport::Callbacks like DSL for defining before and after callbacks around methods
15
+ # @see ClassMethods DSL methods.
16
+ # @example Hooks with default callback options
17
+ # class YourClass
18
+ # include ActiveFunctionCore::Plugins::Hooks
19
+ #
20
+ # define_hooks_for :your_method
21
+ #
22
+ # before_your_method :do_something_before, if: :condition_met?
23
+ # after_your_method :do_something_after, unless: :condition_met?
24
+ #
25
+ # def your_method
26
+ # # Method implementation here...
27
+ # end
28
+ #
29
+ # private
30
+ #
31
+ # def condition_met?
32
+ # # Condition logic here...
33
+ # end
34
+ #
35
+ # def do_something_before
36
+ # # Callback logic to execute before your_method
37
+ # end
38
+ #
39
+ # def do_something_after
40
+ # # Callback logic to execute after your_method
41
+ # end
42
+ # end
43
+ # @example Hooks with custom callback options
44
+ # class YourClass
45
+ # include ActiveFunction::Core::Plugins::Hooks
46
+ #
47
+ # set_callback_options only: ->(only_methods, context:) { only_methods.include?(context.action) }
48
+ #
49
+ # define_hooks_for :your_method
50
+ #
51
+ # before_your_method :do_something_before, only: %[foo bar]
52
+ #
53
+ # def action = "foo"
54
+ # end
14
55
  module Hooks
56
+ # Represents a hook with callbacks for a specific method.
15
57
  class Hook < Data.define(:method_name, :callbacks)
16
58
  DEFAULT_CALLBACK_OPTIONS = {
17
59
  if: ->(v, context:) { context.send(v) if context.respond_to?(v, true) },
18
60
  unless: ->(v, context:) { !context.send(v) if context.respond_to?(v, true) }
19
61
  }.freeze
20
62
  SUPPORTED_CALLBACKS = %i[before after].freeze
21
-
22
- Callback = Data.define(:options, :target) do
63
+ # Represents a callback with options.
64
+ Callback = Data.define(:options, :target) do
65
+ # Runs the callback within the specified contex.
66
+ #
67
+ # @param context [Object] instance of class with callbacks.
23
68
  def run(context)
24
69
  raise ArgumentError, "Callback target #{target} is not defined" unless context.respond_to?(target, true)
25
70
  raise ArgumentError, ":callback_options is not defined in #{context.class}" unless context.class.respond_to?(:callback_options)
@@ -41,6 +86,14 @@ module ActiveFunctionCore
41
86
  super(callbacks: callbacks.to_h { [_1, []] }, **__kwrest__)
42
87
  end
43
88
 
89
+ # Adds a callback to the hook.
90
+ #
91
+ # @param type [Symbol] the type of callback, `:before` or `:after`
92
+ # @param target [Symbol] the name of the callback method.
93
+ # @param options [Hash] the options for the callback.
94
+ # @options options [Symbol] :if the name of the method to check before executing the callback.
95
+ # @options options [Symbol] :unless the name of the method to check before executing the callback.
96
+ # @raise [ArgumentError] if callback already defined.
44
97
  def add_callback(type:, target:, options: {})
45
98
  callbacks[type] << Callback[options, target].tap do |callback|
46
99
  next unless callbacks[type].map(&:hash).to_set === callback.hash
@@ -49,6 +102,11 @@ module ActiveFunctionCore
49
102
  end
50
103
  end
51
104
 
105
+ # Runs all callbacks for the hook.
106
+ #
107
+ # @param context [Object] instance of class with defined hook.
108
+ # @yield [*args] block of code around which callbacks will be executed.
109
+ # @return the result of the block.
52
110
  def run_callbacks(context, &block)
53
111
  callbacks[:before].each { |it| it.run(context) }
54
112
 
@@ -60,24 +118,33 @@ module ActiveFunctionCore
60
118
  end
61
119
  end
62
120
 
63
- def self.included(base)
64
- base.extend(ClassMethods)
65
- end
66
-
121
+ # DSL method for {ActiveFunctionCore::Plugins::Hooks}
67
122
  module ClassMethods
123
+ # Returns all setuped hooks for the class.
68
124
  def hooks = @__hooks ||= {}
125
+
126
+ # Returns all setuped custom callback options for the class.
69
127
  def callback_options = @__callback_options ||= Hook::DEFAULT_CALLBACK_OPTIONS.dup
70
128
 
129
+ # Inherited callback to ensure that callbacks are inherited from the base class.
71
130
  def inherited(subclass)
72
131
  subclass.instance_variable_set(:@__hooks, Marshal.load(Marshal.dump(hooks)))
73
132
  subclass.instance_variable_set(:@__callback_options, callback_options.dup)
74
133
  end
75
134
 
135
+ # Setups hooks for provided method.
76
136
  # Redefines method providing callbacks calls around it.
77
- # Defines `before_[name]` and `after_[name]` methods for setting callbacks.
137
+ # Defines *before_[name]* and *after_[name]* methods for setting callbacks.
138
+ #
139
+ # @example
140
+ # define_hooks_for :process, name: :action
141
+ # before_action :set_first
142
+ # after_action :set_last, if: :ok?
78
143
  #
79
144
  # @param method [Symbol] the name of the callbackable method.
80
145
  # @param name [Symbol] alias for hooked method before_[name] & after_[name] methods.
146
+ # @raise [ArgumentError] if hook for method already defined.
147
+ # @raise [ArgumentError] if method is not defined.
81
148
  def define_hooks_for(method, name: method)
82
149
  raise(ArgumentError, "Hook for #{method} are already defined") if hooks.key?(method)
83
150
  raise(ArgumentError, "Method #{method} is not defined") unless method_defined?(method)
@@ -101,11 +168,18 @@ module ActiveFunctionCore
101
168
 
102
169
  # Sets a callback for an existing hook'ed method.
103
170
  #
171
+ # @example
172
+ # define_hooks_for :action
173
+ # set_callback :before, :action, :set_first
174
+ #
104
175
  # @param type [Symbol] the type of callback, `:before` or `:after`
105
176
  # @param method_name [Symbol] the name of the callbackable method.
106
177
  # @param target [Symbol] the name of the callback method.
107
178
  # @param options [Hash] the options for the callback.
108
- # @options options [Symbol] :if the name of the method to check before executing the callback.
179
+ # @option options [Symbol] :if the name of the booled method to call before executing the callback.
180
+ # @option options [Symbol] :unless the name of the booled method to call before executing the callback.
181
+ # @raise [ArgumentError] if hook for provided method is not setuped via ::define_hooks_for.
182
+ # @raise [ArgumentError] if unsupported @options was passed.
109
183
  def set_callback(type, method_name, target, options = {})
110
184
  raise(ArgumentError, "Hook for :#{method_name} is not defined") unless hooks.key?(method_name)
111
185
  raise(ArgumentError, "Hook Callback accepts only #{callback_options.keys} options") if (options.keys - callback_options.keys).any?
@@ -115,7 +189,14 @@ module ActiveFunctionCore
115
189
 
116
190
  # Sets a custom callback option.
117
191
  #
118
- # @param name [Symbol] the name of the option.
192
+ # @example
193
+ # set_callback_option only: ->(args, context:) { args.to_set === context.current_action }
194
+ # define_hooks_for :action
195
+ # before_action :set_first, only: :index
196
+ #
197
+ # @param option [Hash{Symbol => Proc}] The custom callback option as a single-value hash.
198
+ # - :name [Symbol] The name of the option.
199
+ # - :block [Proc] The block to call.
119
200
  # @yield [*attrs, context:] the block to call.
120
201
  # @yieldparam attrs [*] the attributes passed to the option.
121
202
  # @yieldparam context [Object] the instance context (optional).
@@ -125,6 +206,10 @@ module ActiveFunctionCore
125
206
  callback_options[name] = block
126
207
  end
127
208
  end
209
+
210
+ def self.included(base)
211
+ base.extend(ClassMethods)
212
+ end
128
213
  end
129
214
  end
130
215
  end
@@ -11,15 +11,60 @@ end
11
11
 
12
12
  module ActiveFunctionCore
13
13
  module Plugins
14
+ # Provides ActiveSupport::Callbacks like DSL for defining before and after callbacks around methods
15
+ # @see ClassMethods DSL methods.
16
+ # @example Hooks with default callback options
17
+ # class YourClass
18
+ # include ActiveFunctionCore::Plugins::Hooks
19
+ #
20
+ # define_hooks_for :your_method
21
+ #
22
+ # before_your_method :do_something_before, if: :condition_met?
23
+ # after_your_method :do_something_after, unless: :condition_met?
24
+ #
25
+ # def your_method
26
+ # # Method implementation here...
27
+ # end
28
+ #
29
+ # private
30
+ #
31
+ # def condition_met?
32
+ # # Condition logic here...
33
+ # end
34
+ #
35
+ # def do_something_before
36
+ # # Callback logic to execute before your_method
37
+ # end
38
+ #
39
+ # def do_something_after
40
+ # # Callback logic to execute after your_method
41
+ # end
42
+ # end
43
+ # @example Hooks with custom callback options
44
+ # class YourClass
45
+ # include ActiveFunction::Core::Plugins::Hooks
46
+ #
47
+ # set_callback_options only: ->(only_methods, context:) { only_methods.include?(context.action) }
48
+ #
49
+ # define_hooks_for :your_method
50
+ #
51
+ # before_your_method :do_something_before, only: %[foo bar]
52
+ #
53
+ # def action = "foo"
54
+ # end
14
55
  module Hooks
56
+ # Represents a hook with callbacks for a specific method.
15
57
  class Hook < Data.define(:method_name, :callbacks)
16
58
  DEFAULT_CALLBACK_OPTIONS = {
17
59
  if: ->(v, context:) { context.send(v) if context.respond_to?(v, true) },
18
60
  unless: ->(v, context:) { !context.send(v) if context.respond_to?(v, true) }
19
61
  }.freeze
20
62
  SUPPORTED_CALLBACKS = %i[before after].freeze
21
-
22
- Callback = Data.define(:options, :target) do
63
+ # Represents a callback with options.
64
+ Callback = Data.define(:options, :target) do
65
+ # Runs the callback within the specified contex.
66
+ #
67
+ # @param context [Object] instance of class with callbacks.
23
68
  def run(context)
24
69
  raise ArgumentError, "Callback target #{target} is not defined" unless context.respond_to?(target, true)
25
70
  raise ArgumentError, ":callback_options is not defined in #{context.class}" unless context.class.respond_to?(:callback_options)
@@ -41,6 +86,14 @@ module ActiveFunctionCore
41
86
  super(callbacks: callbacks.to_h { [_1, []] }, **__kwrest__)
42
87
  end
43
88
 
89
+ # Adds a callback to the hook.
90
+ #
91
+ # @param type [Symbol] the type of callback, `:before` or `:after`
92
+ # @param target [Symbol] the name of the callback method.
93
+ # @param options [Hash] the options for the callback.
94
+ # @options options [Symbol] :if the name of the method to check before executing the callback.
95
+ # @options options [Symbol] :unless the name of the method to check before executing the callback.
96
+ # @raise [ArgumentError] if callback already defined.
44
97
  def add_callback(type:, target:, options: {})
45
98
  callbacks[type] << Callback[options, target].tap do |callback|
46
99
  next unless callbacks[type].map(&:hash).to_set === callback.hash
@@ -49,6 +102,11 @@ module ActiveFunctionCore
49
102
  end
50
103
  end
51
104
 
105
+ # Runs all callbacks for the hook.
106
+ #
107
+ # @param context [Object] instance of class with defined hook.
108
+ # @yield [*args] block of code around which callbacks will be executed.
109
+ # @return the result of the block.
52
110
  def run_callbacks(context, &block)
53
111
  callbacks[:before].each { |it| it.run(context) }
54
112
 
@@ -60,24 +118,33 @@ module ActiveFunctionCore
60
118
  end
61
119
  end
62
120
 
63
- def self.included(base)
64
- base.extend(ClassMethods)
65
- end
66
-
121
+ # DSL method for {ActiveFunctionCore::Plugins::Hooks}
67
122
  module ClassMethods
123
+ # Returns all setuped hooks for the class.
68
124
  def hooks = @__hooks ||= {}
125
+
126
+ # Returns all setuped custom callback options for the class.
69
127
  def callback_options = @__callback_options ||= Hook::DEFAULT_CALLBACK_OPTIONS.dup
70
128
 
129
+ # Inherited callback to ensure that callbacks are inherited from the base class.
71
130
  def inherited(subclass)
72
131
  subclass.instance_variable_set(:@__hooks, Marshal.load(Marshal.dump(hooks)))
73
132
  subclass.instance_variable_set(:@__callback_options, callback_options.dup)
74
133
  end
75
134
 
135
+ # Setups hooks for provided method.
76
136
  # Redefines method providing callbacks calls around it.
77
- # Defines `before_[name]` and `after_[name]` methods for setting callbacks.
137
+ # Defines *before_[name]* and *after_[name]* methods for setting callbacks.
138
+ #
139
+ # @example
140
+ # define_hooks_for :process, name: :action
141
+ # before_action :set_first
142
+ # after_action :set_last, if: :ok?
78
143
  #
79
144
  # @param method [Symbol] the name of the callbackable method.
80
145
  # @param name [Symbol] alias for hooked method before_[name] & after_[name] methods.
146
+ # @raise [ArgumentError] if hook for method already defined.
147
+ # @raise [ArgumentError] if method is not defined.
81
148
  def define_hooks_for(method, name: method)
82
149
  raise(ArgumentError, "Hook for #{method} are already defined") if hooks.key?(method)
83
150
  raise(ArgumentError, "Method #{method} is not defined") unless method_defined?(method)
@@ -101,11 +168,18 @@ module ActiveFunctionCore
101
168
 
102
169
  # Sets a callback for an existing hook'ed method.
103
170
  #
171
+ # @example
172
+ # define_hooks_for :action
173
+ # set_callback :before, :action, :set_first
174
+ #
104
175
  # @param type [Symbol] the type of callback, `:before` or `:after`
105
176
  # @param method_name [Symbol] the name of the callbackable method.
106
177
  # @param target [Symbol] the name of the callback method.
107
178
  # @param options [Hash] the options for the callback.
108
- # @options options [Symbol] :if the name of the method to check before executing the callback.
179
+ # @option options [Symbol] :if the name of the booled method to call before executing the callback.
180
+ # @option options [Symbol] :unless the name of the booled method to call before executing the callback.
181
+ # @raise [ArgumentError] if hook for provided method is not setuped via ::define_hooks_for.
182
+ # @raise [ArgumentError] if unsupported @options was passed.
109
183
  def set_callback(type, method_name, target, options = {})
110
184
  raise(ArgumentError, "Hook for :#{method_name} is not defined") unless hooks.key?(method_name)
111
185
  raise(ArgumentError, "Hook Callback accepts only #{callback_options.keys} options") if (options.keys - callback_options.keys).any?
@@ -115,7 +189,14 @@ module ActiveFunctionCore
115
189
 
116
190
  # Sets a custom callback option.
117
191
  #
118
- # @param name [Symbol] the name of the option.
192
+ # @example
193
+ # set_callback_option only: ->(args, context:) { args.to_set === context.current_action }
194
+ # define_hooks_for :action
195
+ # before_action :set_first, only: :index
196
+ #
197
+ # @param option [Hash{Symbol => Proc}] The custom callback option as a single-value hash.
198
+ # - :name [Symbol] The name of the option.
199
+ # - :block [Proc] The block to call.
119
200
  # @yield [*attrs, context:] the block to call.
120
201
  # @yieldparam attrs [*] the attributes passed to the option.
121
202
  # @yieldparam context [Object] the instance context (optional).
@@ -125,6 +206,10 @@ module ActiveFunctionCore
125
206
  callback_options[name] = block
126
207
  end
127
208
  end
209
+
210
+ def self.included(base)
211
+ base.extend(ClassMethods)
212
+ end
128
213
  end
129
214
  end
130
215
  end
@@ -11,15 +11,60 @@ end
11
11
 
12
12
  module ActiveFunctionCore
13
13
  module Plugins
14
+ # Provides ActiveSupport::Callbacks like DSL for defining before and after callbacks around methods
15
+ # @see ClassMethods DSL methods.
16
+ # @example Hooks with default callback options
17
+ # class YourClass
18
+ # include ActiveFunctionCore::Plugins::Hooks
19
+ #
20
+ # define_hooks_for :your_method
21
+ #
22
+ # before_your_method :do_something_before, if: :condition_met?
23
+ # after_your_method :do_something_after, unless: :condition_met?
24
+ #
25
+ # def your_method
26
+ # # Method implementation here...
27
+ # end
28
+ #
29
+ # private
30
+ #
31
+ # def condition_met?
32
+ # # Condition logic here...
33
+ # end
34
+ #
35
+ # def do_something_before
36
+ # # Callback logic to execute before your_method
37
+ # end
38
+ #
39
+ # def do_something_after
40
+ # # Callback logic to execute after your_method
41
+ # end
42
+ # end
43
+ # @example Hooks with custom callback options
44
+ # class YourClass
45
+ # include ActiveFunction::Core::Plugins::Hooks
46
+ #
47
+ # set_callback_options only: ->(only_methods, context:) { only_methods.include?(context.action) }
48
+ #
49
+ # define_hooks_for :your_method
50
+ #
51
+ # before_your_method :do_something_before, only: %[foo bar]
52
+ #
53
+ # def action = "foo"
54
+ # end
14
55
  module Hooks
56
+ # Represents a hook with callbacks for a specific method.
15
57
  class Hook < Data.define(:method_name, :callbacks)
16
58
  DEFAULT_CALLBACK_OPTIONS = {
17
59
  if: ->(v, context:) { context.send(v) if context.respond_to?(v, true) },
18
60
  unless: ->(v, context:) { !context.send(v) if context.respond_to?(v, true) }
19
61
  }.freeze
20
62
  SUPPORTED_CALLBACKS = %i[before after].freeze
21
-
22
- Callback = Data.define(:options, :target) do
63
+ # Represents a callback with options.
64
+ Callback = Data.define(:options, :target) do
65
+ # Runs the callback within the specified contex.
66
+ #
67
+ # @param context [Object] instance of class with callbacks.
23
68
  def run(context)
24
69
  raise ArgumentError, "Callback target #{target} is not defined" unless context.respond_to?(target, true)
25
70
  raise ArgumentError, ":callback_options is not defined in #{context.class}" unless context.class.respond_to?(:callback_options)
@@ -41,6 +86,14 @@ module ActiveFunctionCore
41
86
  super(callbacks: callbacks.to_h { [_1, []] }, **)
42
87
  end
43
88
 
89
+ # Adds a callback to the hook.
90
+ #
91
+ # @param type [Symbol] the type of callback, `:before` or `:after`
92
+ # @param target [Symbol] the name of the callback method.
93
+ # @param options [Hash] the options for the callback.
94
+ # @options options [Symbol] :if the name of the method to check before executing the callback.
95
+ # @options options [Symbol] :unless the name of the method to check before executing the callback.
96
+ # @raise [ArgumentError] if callback already defined.
44
97
  def add_callback(type:, target:, options: {})
45
98
  callbacks[type] << Callback[options, target].tap do |callback|
46
99
  next unless callbacks[type].map(&:hash).to_set === callback.hash
@@ -49,6 +102,11 @@ module ActiveFunctionCore
49
102
  end
50
103
  end
51
104
 
105
+ # Runs all callbacks for the hook.
106
+ #
107
+ # @param context [Object] instance of class with defined hook.
108
+ # @yield [*args] block of code around which callbacks will be executed.
109
+ # @return the result of the block.
52
110
  def run_callbacks(context, &block)
53
111
  callbacks[:before].each { |it| it.run(context) }
54
112
 
@@ -60,24 +118,33 @@ module ActiveFunctionCore
60
118
  end
61
119
  end
62
120
 
63
- def self.included(base)
64
- base.extend(ClassMethods)
65
- end
66
-
121
+ # DSL method for {ActiveFunctionCore::Plugins::Hooks}
67
122
  module ClassMethods
123
+ # Returns all setuped hooks for the class.
68
124
  def hooks = @__hooks ||= {}
125
+
126
+ # Returns all setuped custom callback options for the class.
69
127
  def callback_options = @__callback_options ||= Hook::DEFAULT_CALLBACK_OPTIONS.dup
70
128
 
129
+ # Inherited callback to ensure that callbacks are inherited from the base class.
71
130
  def inherited(subclass)
72
131
  subclass.instance_variable_set(:@__hooks, Marshal.load(Marshal.dump(hooks)))
73
132
  subclass.instance_variable_set(:@__callback_options, callback_options.dup)
74
133
  end
75
134
 
135
+ # Setups hooks for provided method.
76
136
  # Redefines method providing callbacks calls around it.
77
- # Defines `before_[name]` and `after_[name]` methods for setting callbacks.
137
+ # Defines *before_[name]* and *after_[name]* methods for setting callbacks.
138
+ #
139
+ # @example
140
+ # define_hooks_for :process, name: :action
141
+ # before_action :set_first
142
+ # after_action :set_last, if: :ok?
78
143
  #
79
144
  # @param method [Symbol] the name of the callbackable method.
80
145
  # @param name [Symbol] alias for hooked method before_[name] & after_[name] methods.
146
+ # @raise [ArgumentError] if hook for method already defined.
147
+ # @raise [ArgumentError] if method is not defined.
81
148
  def define_hooks_for(method, name: method)
82
149
  raise(ArgumentError, "Hook for #{method} are already defined") if hooks.key?(method)
83
150
  raise(ArgumentError, "Method #{method} is not defined") unless method_defined?(method)
@@ -101,11 +168,18 @@ module ActiveFunctionCore
101
168
 
102
169
  # Sets a callback for an existing hook'ed method.
103
170
  #
171
+ # @example
172
+ # define_hooks_for :action
173
+ # set_callback :before, :action, :set_first
174
+ #
104
175
  # @param type [Symbol] the type of callback, `:before` or `:after`
105
176
  # @param method_name [Symbol] the name of the callbackable method.
106
177
  # @param target [Symbol] the name of the callback method.
107
178
  # @param options [Hash] the options for the callback.
108
- # @options options [Symbol] :if the name of the method to check before executing the callback.
179
+ # @option options [Symbol] :if the name of the booled method to call before executing the callback.
180
+ # @option options [Symbol] :unless the name of the booled method to call before executing the callback.
181
+ # @raise [ArgumentError] if hook for provided method is not setuped via ::define_hooks_for.
182
+ # @raise [ArgumentError] if unsupported @options was passed.
109
183
  def set_callback(type, method_name, target, options = {})
110
184
  raise(ArgumentError, "Hook for :#{method_name} is not defined") unless hooks.key?(method_name)
111
185
  raise(ArgumentError, "Hook Callback accepts only #{callback_options.keys} options") if (options.keys - callback_options.keys).any?
@@ -115,7 +189,14 @@ module ActiveFunctionCore
115
189
 
116
190
  # Sets a custom callback option.
117
191
  #
118
- # @param name [Symbol] the name of the option.
192
+ # @example
193
+ # set_callback_option only: ->(args, context:) { args.to_set === context.current_action }
194
+ # define_hooks_for :action
195
+ # before_action :set_first, only: :index
196
+ #
197
+ # @param option [Hash{Symbol => Proc}] The custom callback option as a single-value hash.
198
+ # - :name [Symbol] The name of the option.
199
+ # - :block [Proc] The block to call.
119
200
  # @yield [*attrs, context:] the block to call.
120
201
  # @yieldparam attrs [*] the attributes passed to the option.
121
202
  # @yieldparam context [Object] the instance context (optional).
@@ -125,6 +206,10 @@ module ActiveFunctionCore
125
206
  callback_options[name] = block
126
207
  end
127
208
  end
209
+
210
+ def self.included(base)
211
+ base.extend(ClassMethods)
212
+ end
128
213
  end
129
214
  end
130
215
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActiveFunctionCore
4
- VERSION = "0.2.2"
4
+ VERSION = "0.2.4"
5
5
  end
@@ -7,7 +7,6 @@ RubyNext::Language.setup_gem_load_path(transpile: true)
7
7
  module ActiveFunctionCore
8
8
  Error = Class.new(StandardError)
9
9
 
10
- require "plugins/hooks"
11
-
12
10
  require "active_function_core/version"
11
+ require "active_function_core/plugins/hooks"
13
12
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activefunction-core
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.2
4
+ version: 0.2.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nerbyk
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-01-11 00:00:00.000000000 Z
11
+ date: 2024-01-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ruby-next
@@ -34,22 +34,23 @@ files:
34
34
  - CHANGELOG.md
35
35
  - LICENSE.txt
36
36
  - README.md
37
- - lib/.rbnext/2.7/plugins/hooks.rb
38
- - lib/.rbnext/3.0/plugins/hooks.rb
39
- - lib/.rbnext/3.1/plugins/hooks.rb
40
- - lib/.rbnext/3.2/plugins/hooks.rb
37
+ - lib/.rbnext/2.7/active_function_core/plugins/hooks.rb
38
+ - lib/.rbnext/3.0/active_function_core/plugins/hooks.rb
39
+ - lib/.rbnext/3.1/active_function_core/plugins/hooks.rb
40
+ - lib/.rbnext/3.2/active_function_core/plugins/hooks.rb
41
41
  - lib/active_function_core.rb
42
+ - lib/active_function_core/plugins/hooks.rb
42
43
  - lib/active_function_core/version.rb
43
- - lib/plugins/hooks.rb
44
44
  - sig/active_function_core.rbs
45
45
  - sig/manifest.yml
46
46
  homepage: https://github.com/DanilMaximov/activefunction
47
47
  licenses:
48
48
  - MIT
49
49
  metadata:
50
- homepage_uri: https://github.com/DanilMaximov/activefunction-core
51
- source_code_uri: https://github.com/DanilMaximov/activefunction-core
52
- changelog_uri: https://github.com/DanilMaximov/activefunction-core/CHANGELOG.md
50
+ homepage_uri: https://github.com/DanilMaximov/activefunction/tree/master/gems/activefunction-core
51
+ source_code_uri: https://github.com/DanilMaximov/activefunction/tree/master/gems/activefunction-core
52
+ changelog_uri: https://github.com/DanilMaximov/activefunction/tree/master/gems/activefunction-core/CHANGELOG.md
53
+ documentation_uri: https://github.com/DanilMaximov/activefunction/tree/master/gems/activefunction-core
53
54
  post_install_message:
54
55
  rdoc_options: []
55
56
  require_paths:
@@ -65,7 +66,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
65
66
  - !ruby/object:Gem::Version
66
67
  version: '0'
67
68
  requirements: []
68
- rubygems_version: 3.1.6
69
+ rubygems_version: 3.5.4
69
70
  signing_key:
70
71
  specification_version: 4
71
72
  summary: ActiveFunction core gem