Create callable objects on the fly.
It's easy to create a callable object in Ruby (understanding callable
as an object that supports the #call
method), you just wrap it in a
lambda and that's it.
Although this approach is correct, it lacks some expressiveness. Wouldn't it be better to just say:
Callable( :i_wasnt_callable_but_i_am_now )
This line of code tells you exacly what it's doing.
This gem allows you to do exactly that (see Usage)
To use this library, you first need to require it. That's all the setup you need.
require "callable"
If you need to return a callable object for some reason, you can do it by invoking the callable method:
c = Callable( :ret_val )
c.call
# => ret_val
Take into account that if you pass a callable object (such as a lambda), you'll get it back as the return value:
c = Callable( ->{ :ret_val } )
c.call
# => ret_val
c
# => #<Proc:0x0000000261e138@-:6 (lambda)>
The gem also ships with a #callable? method that returns true if the object is callable and false if it's not.
:not_callable.callable?
=> false
->{ :not_callable }.callable?
=> true
This is the same as saying
xxx.respond_to? :call
But I felt it would be more illustrative of its purpose.
If you don't like to deal with nil
s, callable ships with a default
option for when Callable
wraps nil
.
Callable(nil).call
# => nil
Callable(nil, default: "I'm not 'nil' anymore!").call
# => "I'm not 'nil' anymore!"
I think the main use for this library is handling actions as options.
For example, imagine we have a very reduced authorization library that provides a method called do_if
.
This method receives:
- a symbol representing a permission name
- a Hash that represents the available authorization policies
- a block with the actions to perform
The premise is that the method will execute the block if the selected policy returns true when we send the call
message.
Our first approach is:
def do_if(permission, policies=POLICIES)
yield if policies[permission].call
end
So, if our POLICIES hash is:
POLICIES = {
development: -> { true }
}
do_if(:development) do
puts "Debugging"
end
# >> Debugging
And if we switch the policy value:
POLICIES = {
development: -> { false }
}
do_if(:development) do
puts "Debugging"
end
# >>
This allows us to have a lot of flexibility. But we could provide the user a way to say the same with a little less code.
If we wrap the policy to call with the Callable method:
def do_if(permission, policies=POLICIES)
yield if Callable(policies[permission]).call
end
Now we can put the raw value we want to get back without the need of the lambda
POLICIES = {
development: true
}
Even though using a lambda adds just a few more characters, in my opinion, it clutters the code. By being able to leave it out, the code reads much better.
Add this line to your application's Gemfile:
gem 'callable'
And then execute:
$ bundle
Or install it yourself as:
$ gem install callable
- Fork it ( https://github.com/[my-github-username]/callable/fork )
- Create your feature branch (
git checkout -b my-new-feature
) - Commit your changes (
git commit -am 'Add some feature'
) - Push to the branch (
git push origin my-new-feature
) - Create a new Pull Request