README.md in tiny_hooks-0.3.0 vs README.md in tiny_hooks-1.0.0
- old
+ new
@@ -18,15 +18,15 @@
$ gem install tiny_hooks
## Usage
-`extend TinyHooks` in your class/module and you're all set to use `define_hook`!
+`include TinyHooks` in your class/module and you're all set to use `define_hook`!
```ruby
class MyClass
- extend TinyHooks
+ include TinyHooks
def my_method
puts 'my method'
end
@@ -39,18 +39,173 @@
# => "my before hook\nmy method\n"
```
TinyHooks shines when the class/module is the base class/module of your library and your users will inherit/include it. In these cases, end users can define hooks to the methods you provide. The only thing you have to do is to provide the list of methods.
-## Difference between TinyHooks and ActiveSupport::Callbacks
+### Halting
+You can halt hook and method body execution by `throw`ing `:abort`.
+
+```ruby
+class MyClass
+ include TinyHooks
+
+ def my_method
+ puts 'my method'
+ end
+
+ define_hook :before, :my_method do
+ throw :abort
+ puts 'my before hook'
+ end
+end
+
+MyClass.new.my_method
+# => ""
+```
+
+You can change how to halt from two options: throwing `:abort` and returning `false`. This can be done via `terminator` option.
+
+```ruby
+class MyClass
+ include TinyHooks
+
+ def my_method
+ puts 'my method'
+ end
+
+ define_hook :before, :my_method, terminator: :return_false do
+ false
+ end
+end
+
+MyClass.new.my_method
+# => ""
+```
+
+### Targeting for hooks
+
+You can limit the targets for hooks in two ways. You can enable hooks for public methods only by using `public_only!` method and include/exclude targets with Regexp pattern by using `targets!` method.
+
+```ruby
+class MyClass
+ include TinyHooks
+
+ def my_method
+ puts 'my method'
+ end
+
+ private
+
+ def my_private_method
+ puts 'my private method'
+ end
+end
+
+class MyClassWithPublicOnly < MyClass
+ public_only!
+
+ define_hook :before, :my_private_method do
+ puts 'my_private_method'
+ end
+ # => This causes PrivateError
+end
+
+class MyClassWithExclude < MyClass
+ target! exclude_pattern: /my_method/
+
+ define_hook :before, :my_method do
+ puts 'my_method'
+ end
+ # => This causes TargetError
+end
+```
+
+You can call `include_private!` method to disable the effect of `public_only!`.
+
+### Conditional hooks
+
+You can add `if` option to `define_hook` call. `if` option must be a Proc and is evaluated in context of an instance.
+
+```ruby
+class MyClass
+ include TinyHooks
+
+ def initialize(hook_enabled = true)
+ @hook_enabled = hook_enabled
+ end
+
+ def my_method
+ puts 'my method'
+ end
+
+ def hook_enabled?
+ @hook_enabled
+ end
+
+ define_hook :before, :my_method, if: -> { hook_enabled? } do
+ puts 'my before hook'
+ end
+end
+
+MyClass.new(true).my_method
+# => "my before hook\nmy method\n"
+
+MyClass.new(false).my_method
+# => "my method\n"
+```
+
+## Differences between TinyHooks and ActiveSupport::Callbacks
+
While `TinyHooks` and `ActiveSupport::Callbacks` share the same purpose, there are a few major differences.
-* `TinyHooks` doesn’t support halting, but will support in the future.
+### Differences in usage
+
* While `ActiveSupport::Callbacks` has a set of methods for callbacks to work, `TinyHooks` has only one method.
* You can apply callbacks/hooks into any existing methods without any changes with `TinyHooks`, while you need to change methods to call `run_callbacks` method within them to apply callbacks with `ActiveSupport::Callbacks`.
-In short, `TinyHooks` is simpler while `ActiveSupport::Callbacks` allows more control over callbacks.
+### Differences in performance
+
+According to the [benchmark](https://github.com/okuramasafumi/tiny_hooks/blob/main/benchmark/compare_to_as_callbacks.rb), `TinyHooks` is 1.6 times as fast as `ActiveSupport::Callbacks` when before and after callbacks are applied, and twice as fast when no callbacks are applied.
+
+The result on my machine:
+
+```
+Warming up --------------------------------------
+ ActiveSupport 246.181k i/s - 256.956k times in 1.043769s (4.06μs/i)
+ TinyHooks 282.834k i/s - 293.502k times in 1.037719s (3.54μs/i)
+Calculating -------------------------------------
+ ActiveSupport 230.196k i/s - 738.542k times in 3.208320s (4.34μs/i)
+ TinyHooks 373.057k i/s - 848.501k times in 2.274453s (2.68μs/i)
+
+Comparison:
+ TinyHooks: 373057.2 i/s
+ ActiveSupport: 230195.9 i/s - 1.62x slower
+
+Warming up --------------------------------------
+ActiveSupport no callback set 1.992M i/s - 2.096M times in 1.052258s (501.99ns/i)
+ TinyHooks no callback set 3.754M i/s - 3.791M times in 1.009753s (266.39ns/i)
+ Plain 3.852M i/s - 3.955M times in 1.026654s (259.57ns/i)
+Calculating -------------------------------------
+ActiveSupport no callback set 2.005M i/s - 5.976M times in 2.980861s (498.79ns/i)
+ TinyHooks no callback set 4.025M i/s - 11.262M times in 2.798054s (248.46ns/i)
+ Plain 3.765M i/s - 11.557M times in 3.069944s (265.63ns/i)
+
+Comparison:
+ TinyHooks no callback set: 4024854.4 i/s
+ Plain: 3764695.4 i/s - 1.07x slower
+ActiveSupport no callback set: 2004848.9 i/s - 2.01x slower
+```
+
+### Differences in functionality
+
+There are few things TinyHooks doesn't cover. For example, TinyHooks doesn't support `unless` option in `define_hook` method or Symbol as a callback body since they are just syntax sugar.
+
+One of the features TinyHooks doesn't have is `reset_callbacks` which resets all callbacks with given condition. In order to do this, you must call `restore_original` method in iteration.
+
+### Conclusion
+
+In short, in most cases, TinyHooks is simpler, easier and faster solution.
## Development
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.