activefunction-core 0.2.0 → 0.2.3

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: 0b2cfe13205db0147f98083ea9d83b4f6ee0a1a1baaec08f848bf7a650a6e844
4
- data.tar.gz: 136a5559b4c123ba50c384cfaf4beb05a5a9dca14ae398866e9a98a32d72338c
3
+ metadata.gz: a1f66462455352552a6c2746a76a215f3a497b04610d05ad43db175d2ac9b811
4
+ data.tar.gz: ce06fea28a775ef62692599895ca6e96035efa69f7ba02a0f659c7baf499ca48
5
5
  SHA512:
6
- metadata.gz: 5b2a5470029dc54aab1677f6d08af01d1eaca7673d38003745630a82355e44d810085a66c4f4dbafe50409fb4f2e730e3cacc17384883093943e97169ed4ddfe
7
- data.tar.gz: 8865302a689494285e6ffc23ba6197aca98b2ae6ee3049364c8c0084bfeb3a5507df4e5d3d674277037e5b0621b1a42afacad08d94d2604b13c30a7f496af26c
6
+ metadata.gz: 44a481313a83af1eaf5dd6de1356f8ff7e16d7d49572a812da8eee33b76618dd2afb3811a19d35d6bb1fb75e701d41b62d4b10bc06cef79caef29e278cc4ec0c
7
+ data.tar.gz: e2a37509372b1d0762b1412eb1ad52b7ed83fa7c2d1ef410e27c308324a0d544095653934ff2c0727e4fc97dcbe7892a303483b3da134cc05cd192c6943edbb7
data/CHANGELOG.md CHANGED
@@ -11,3 +11,14 @@
11
11
  - Added Plugins support
12
12
  - Added Hooks plugin - refactored ActiveFunction::Functions::Callbacks implementation.
13
13
 
14
+ ## [0.2.1] - Yanked due to invalid .rbnext files
15
+
16
+ - Fixed Plugins options handling
17
+
18
+ ## [0.2.2]
19
+
20
+ - Republish 0.2.1
21
+
22
+ ## [0.2.3]
23
+
24
+ - YARD Doc Added
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)
@@ -31,7 +76,7 @@ module ActiveFunctionCore
31
76
 
32
77
  private def normalized_options(options, context)
33
78
  options.map do |option|
34
- name, arg = option.first
79
+ name, arg = option
35
80
  -> { context.class.callback_options[name].call(arg, context: context) }
36
81
  end
37
82
  end
@@ -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,21 +168,35 @@ 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
- raise(ArgumentError, "Hook Callback accepts only #{options.keys} options") if (options.keys - callback_options.keys).any?
185
+ raise(ArgumentError, "Hook Callback accepts only #{callback_options.keys} options") if (options.keys - callback_options.keys).any?
112
186
 
113
187
  hooks[method_name].add_callback(type: type, target: target, options: options)
114
188
  end
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)
@@ -31,7 +76,7 @@ module ActiveFunctionCore
31
76
 
32
77
  private def normalized_options(options, context)
33
78
  options.map do |option|
34
- name, arg = option.first
79
+ name, arg = option
35
80
  -> { context.class.callback_options[name].call(arg, context: context) }
36
81
  end
37
82
  end
@@ -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,21 +168,35 @@ 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
- raise(ArgumentError, "Hook Callback accepts only #{options.keys} options") if (options.keys - callback_options.keys).any?
185
+ raise(ArgumentError, "Hook Callback accepts only #{callback_options.keys} options") if (options.keys - callback_options.keys).any?
112
186
 
113
187
  hooks[method_name].add_callback(type: type, target: target, options: options)
114
188
  end
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)
@@ -31,7 +76,7 @@ module ActiveFunctionCore
31
76
 
32
77
  private def normalized_options(options, context)
33
78
  options.map do |option|
34
- name, arg = option.first
79
+ name, arg = option
35
80
  -> { context.class.callback_options[name].call(arg, context: context) }
36
81
  end
37
82
  end
@@ -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,21 +168,35 @@ 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
- raise(ArgumentError, "Hook Callback accepts only #{options.keys} options") if (options.keys - callback_options.keys).any?
185
+ raise(ArgumentError, "Hook Callback accepts only #{callback_options.keys} options") if (options.keys - callback_options.keys).any?
112
186
 
113
187
  hooks[method_name].add_callback(type: type, target: target, options: options)
114
188
  end
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)
@@ -31,7 +76,7 @@ module ActiveFunctionCore
31
76
 
32
77
  private def normalized_options(options, context)
33
78
  options.map do |option|
34
- name, arg = option.first
79
+ name, arg = option
35
80
  -> { context.class.callback_options[name].call(arg, context:) }
36
81
  end
37
82
  end
@@ -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,21 +168,35 @@ 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
- raise(ArgumentError, "Hook Callback accepts only #{options.keys} options") if (options.keys - callback_options.keys).any?
185
+ raise(ArgumentError, "Hook Callback accepts only #{callback_options.keys} options") if (options.keys - callback_options.keys).any?
112
186
 
113
187
  hooks[method_name].add_callback(type:, target:, options:)
114
188
  end
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)
@@ -31,7 +76,7 @@ module ActiveFunctionCore
31
76
 
32
77
  private def normalized_options(options, context)
33
78
  options.map do |option|
34
- name, arg = option.first
79
+ name, arg = option
35
80
  -> { context.class.callback_options[name].call(arg, context:) }
36
81
  end
37
82
  end
@@ -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,21 +168,35 @@ 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
- raise(ArgumentError, "Hook Callback accepts only #{options.keys} options") if (options.keys - callback_options.keys).any?
185
+ raise(ArgumentError, "Hook Callback accepts only #{callback_options.keys} options") if (options.keys - callback_options.keys).any?
112
186
 
113
187
  hooks[method_name].add_callback(type:, target:, options:)
114
188
  end
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.0"
4
+ VERSION = "0.2.3"
5
5
  end
@@ -7,7 +7,5 @@ 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"
13
11
  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.0
4
+ version: 0.2.3
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-10 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