Consenter
Enumerable#each_consented is an opinionated but idiomatic way to filter elements of an Enumerable by user consent.
Installation
Add this line to your application's Gemfile:
gem 'consenter'And then execute:
$ bundle
Or install it yourself as:
$ gem install consenter
Usage
Enumerable#each_consented works exactly like Enumerable#each, but before yielding each element of the collection, it prompts the user (via the IO#console, ie. /dev/tty) for confirmation, using the prompt provided as an argument.
A simple example: puts 0.upto(9).each_consented('Pick %d?').sum will print out the sum of all numbers between 0 and 9 which the user has picked.
The following example shows the interaction:
- each element is passed to
Kernel#formatto generate the customizable prompt - answering
ywill cause the current element to be yielded - answering
Ywill cause the current element and all remaining ones to be yielded - answering
nwill cause the current element to be skipped - answering
Nwill cause the current element and all remaining ones to be skipped - answering
qwill cause the iteration to be aborted - answering
?will print out a help message - answering anything else will also print out the help message
$ ruby -r consenter -e 'puts 0.upto(9).each_consented("Pick %d?").sum'
Pick 0? [y,n,Y,N,q,?] ?
y - yes to this
n - no to this
Y - yes to this and all remaining
N - no to this and all remaining
q - quit
? - help
Pick 0? [y,n,Y,N,q,?] y
Pick 1? [y,n,Y,N,q,?] n
Pick 2? [y,n,Y,N,q,?] n
Pick 3? [y,n,Y,N,q,?] n
Pick 4? [y,n,Y,N,q,?] y
Pick 5? [y,n,Y,N,q,?] y
Pick 6? [y,n,Y,N,q,?] N
9
$ _Automation
To use the consenter logic in Ruby scripts that are run non-interactively, e.g. via cron, where a human cannot be prompted for answers, you can provide options to pick all or none of the objects in the Enumerable without invoking the prompt:
$ ruby -r consenter -e 'puts 0.upto(9).each_consented("Pick %d?", all: true).sum'
45
$ _Alternatively:
$ ruby -r consenter -e 'puts 0.upto(9).each_consented("Pick %d?", none: true).sum'
0
$ _Obviously, instead of providing hard-coded true values for the all: or none: options, you would provide a boolean check, e.g. one that checks an environment variable:
$ ruby -r consenter -e 'puts 0.upto(9).each_consented("Pick %d?", all: ENV.fetch("CI", false)).sum'This version would prompt like demoed above when the script is run interactively:
$ ruby -r consenter -e 'puts 0.upto(9).each_consented("Pick %d?", all: ENV.fetch("CI", false)).sum'
Pick 0? [y,n,Y,N,q,?] y
Pick 1? [y,n,Y,N,q,?] y
Pick 2? [y,n,Y,N,q,?] y
Pick 3? [y,n,Y,N,q,?] n
Pick 4? [y,n,Y,N,q,?] N
3
$ _... but would default to selecting all objects in the Enumerable when it is running in a CI environment like SemaphoreCI or Jenkins:
$ CI=true ruby -r consenter -e 'puts 0.upto(9).each_consented("Pick %d?", all: ENV.fetch("CI", false)).sum'
45
$ _Another possible scenario is that you prompt the user if the script is running in interactive mode, but decide to select all: or none: of the enumerable elements if the script is run non-interactively, e.g. as part of a cron job.
So, to select all: of the elements when in non-interactive mode you can use:
$ </dev/null ruby -r consenter -e 'puts 0.upto(9).each_consented("Pick %d?", all: !STDIN.tty?).sum'
45
$ _... and to select none: of the elements you would use this instead:
$ </dev/null ruby -r consenter -e 'puts 0.upto(9).each_consented("Pick %d?", none: !STDIN.tty?).sum'
0
$ _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.
To install this gem onto your local machine, run bundle exec rake install. To release a new version, update the version number in version.rb, and then run bundle exec rake release, which will create a git tag for the version, push git commits and tags, and push the .gem file to rubygems.org.
Contributing
Bug reports and pull requests are welcome on GitHub at https://github.com/pvdb/consenter.