What is Ruby power_assert gem & why you may need it
Latest update:
After upgrading from Ruby 2.1.3 to 2.2.2 I've noticed a new bundled
gem called power_assert
. It turned out that test-unit
requires it
for like a year now. It was a 2nd surprise, because I thought that
everyone's moved to minitest
many years ago & test-unit
was left
alone for a backward-compatibility sake.
A 'power assert' enabled test-unit
has an enhanced version of
assert()
that can take a block & in a case of failure print values
for an each object in a method chain. If no block is given to this new
assert()
, the old one version is invoked.
$ cat example-1.rb
require 'test/unit'
class Hello < Test::Unit::TestCase
def test_smoke
assert { 3.times.include? 10 }
end
end
$ ruby example-1.rb | sed -n '/==/,/==/p'
===============================================================================
Failure:
assert { 3.times.include? 10 }
| |
| false
#<Enumerator: 3:times>
test_smoke(Hello)
/home/alex/.rvm/gems/ruby-2.2.2@global/gems/power_assert-0.2.2/lib/power_assert.
rb:29:in `start'
example-1.rb:5:in `test_smoke'
2:
3: class Hello < Test::Unit::TestCase
4: def test_smoke
=> 5: assert { 3.times.include? 10 }
6: end
7: end
===============================================================================
As I understand, Kazuki Tsujimoto (the author of power_assert
gem)
got the idea for a pretty picture for a method chain from the Groovy
language. Before power_assert
gem we could only use Object.tap()
for
peeking into the chain:
> ('a'..'c').to_a.tap {|i| p i}.map {|i| i.upcase }
["a", "b", "c"]
[
[0] "A",
[1] "B",
[2] "C"
]
Using power_assert
we can write a enhanced version of Kernel.p()
,
where in the spirit of the new assert()
, it prints a fancy picture
if a user provides a block for it:
$ cat super_duper_p.rb
require 'power_assert'
def p *args
if block_given?
PowerAssert.start(Proc.new, assertion_method: __callee__) do |pa|
val = pa.yield
str = pa.message_proc.call
if str == "" then Kernel.p(val) else puts str end
val
end
else
Kernel.p(*args)
end
end
$ cat example-2.rb
require './super_duper_p'
p {3.times.to_a.map {|i| "i=#{i}" }.include? 3}
p [1,2,3], [4,5,6], "7"
p { [1,2,3] }
$ ruby example-2.rb
p {3.times.to_a.map {|i| "i=#{i}" }.include? 3}
| | | |
| | | false
| | ["i=0", "i=1", "i=2"]
| [0, 1, 2]
#<Enumerator: 3:times>
[1, 2, 3]
[4, 5, 6]
"7"
[1, 2, 3]
Unfortunately, it won't work in irb.
If you're like the rest of us who prefer minitest
instead of
test-unit, you'll need a separate
gem for it.
Tags: ойті
Authors: ag