Bookmarker - This calls for a unit test

When practicing TDD one of the principles you learn in order to do TDD right is to

Write the simplest thing that could possibly work.

Here’s an example of code I wrote for my Bookmarker application that allowed me to pass an integration test.

  
  def keep
    site = Site.find_or_create_by(domain: domain)

    @bookmark.site = site
    @bookmark.save
  end
  

That code was the simplest thing I could have written. However, if you take your time to step through it you’d notice there’s a subtle bug.

And that’s quite okay since it is part of the business logic of the application and an integration test isn’t meant to fully exercise a method at that level in the system.

But we definitely can’t leave the bug there. To ferret it out we should use a unit test.

A unit test is an automated piece of code that invokes a unit of work in the system and then checks a single assumption about the behavior of that unit of work.

What’s the bug?

Well, it turns out that if a new site was created and the bookmark failed to save due to, for instance, a validation error then the site would have existed in the system without that bookmark belonging to it.

This is a problem because one of the requirements of the system is that every site that exists must have at least one bookmark.

Here’s a unit test to expose that problem.

  
  context "when the bookmark is invalid" do
    
    it "does not create a site" do
      # create an invalid bookmark
      bookmark = FactoryGirl.build(:bookmark, url: '')
      
      bookmark_collector = Bookmark::Collector.new(bookmark)
      
      expect {
        bookmark_collector.keep
      }.not_to change(Site, :count)
      
      # since no bookmark is saved,
      # then no site should be saved
      # and so Site.count should not change
      # but it does
    end
  end
  

What do you think is the fix?

Think about it for a while and see what you come up with before looking at my approach to solving the problem.

Hint: Transactions.

References

Happy hacking!

Written by .

Build good habits

image

Talking to myself:

Don’t rush!

Take your time and consistently build your products, improve your health, improve your fitness, increase your wealth and improve your relationships.

Toil daily!

Even in the days when you think you can do more it’s better to stop and pace yourself. Life is a marathon, not a sprint.

Enjoy the journey! Don’t live for the end. Live for the moment.

Build a habit.

A habit is more powerful than motivation.

Remember what Daddy always says:

The race is not for the swiftest, but for those who can endure till the end.

Swinging Price Tag

Swinging Price Tag is a homework assignment that came out of discussions Denzil Doyle and I were having about HTML5, Sass and building reusable widgets. We wanted to see how each of us would approach building such a thing. My results are in the pen below.

image

See the Pen Swinging Price Tag by Dwayne R. Crooks (@dwayne) on CodePen.

Join in the fun and show us how you would do it. Tweet your results to me or Denzil on Twitter.

Happy hacking!

Written by .

Photo ASCII in Ruby - Improved quality

It turned out that reducing the ASCII space from 95 characters (32 - space to 126 - tilde) to a carefully selected 12 character set resulted in huge wins. The quality of the conversion drastically improved.

The other change I tried was converting to grayscale before performing the mapping. However, the resulting differences aren’t that dramatic and I’m thinking of leaving that as a config option.

Here’s the updated code and you can see the results below.

Real Ruby

image

ASCII Ruby

image

Real Me

image

ASCII Me

image

Reference

If you’re wondering where I found the set of 12 characters, then check out this text document.

Happy hacking!

Written by .

Photo ASCII in Ruby - The spike

As I indicated in my previous post, I’m working on a fun side project suggested to me by Chenoa.

Here’s the short of it.

A few weeks ago at the office we had a selfie promotion that Lerielle was pumping on for Pizza Hut. Practically everyone contributed selfies to the promotion (except me, shame). Chinaka being Chinaka took an ASCII selfie. I thought this was ingenious and felt a little disappointed I didn’t think of it first :(. I mean this is something I’d do. Anyway I sent an email indicating as such and Chenoa responded

Why don’t you create an app that does it?

Well as you can guess the challenge was accepted and I’m happy to say that Photo ASCII is my attempt at creating a tool to convert photographs to ASCII.

The first version of Photo ASCII is just a spike I did to see if my thoughts on how it could be done made sense.

My thoughts

If I could somehow convert the pixels to integer values. Then map those integers to the printable ASCII character range then that should work. So if I get that to work I may get acceptable results and I can iterate to improve the quality of the output from that point.

How it works

Well RMagick allows me to open any image format and convert pixels to intensity values (essentially integers). Let’s say that the minimum intensity is i_min and the maximum intensity is i_max. Now the printable ASCII character range is from 32 (space) to 126 (tilde). We simply map i_min to 32, i_max to 126 and every value in-between i_min and i_max to a value in-between 32 and 126.

Let i represent any intensity within i_min and i_max and let a represent the corresponding ASCII character. Then, using some simple CXC Mathematics to find the equation of a line given two points on the line we get

a(94 * i + 32 * i_max - 126 * i_min) / (i_max - i_min).

One thing to note is the possibility of division by zero when i_min is equal to i_max. This occurs when the image is all one color. The code I wrote handles this case by just using spaces.

And, that’s it.

I got okay results.

Real Ruby

image

ASCII Ruby

image

Real Me

image

ASCII Me

image

I have some ideas for improvement.

  • Convert the image to a grayscale one before going to ASCII.
  • Tune the mapping so that for example, the character that looks the darkest, I think #, maps to black. The character that looks the second darkest maps to another appropriate character. And so on.
  • If greyscale doesn’t work then maybe edge detection might be the way to go.

Conclusion

I’m fully aware of other solutions out there that already does what I’m trying to do much better than I have done here. But what’s the fun in reusing those solutions. I rather build something on my own to learn first hand the challenges involved in doing such a thing.

For those of you needing a quality solution right now, I’d recommend picascii.

And finally, if you’re interested, you can view the full source code.

Happy hacking!

Written by .

Installing RMagick on Ubuntu 14.04 LTS

I’m working on a fun project suggested to me by a colleague. To spike it I decided to implement a quick test script to figure out what will be needed to implement its core feature. I’d talk more about it in the future but suffice it to say that one of the requirements is image manipulation.

The best game in town where image manipulation is concerned seems to be ImageMagick. And based on my limited research the best Ruby binding is RMagick.

I had a little trouble while installing the RMagick gem so I thought I’d just document the process for future me (and whoever else).

  1. sudo apt-get install imagemagick
  2. sudo apt-get install libmagickwand-dev
  3. gem install rmagick

The problem occurred in Step 2 for me and it took me a while to find that solution.