Code Smell : Copying objects

While copying a two dimensional array in Ruby, both Object#dup and Object#clone were creating the problem of “shallow copying”. Separate copies of the array elements were created but the same reference for any Object type attributes were used inside the element. Hence, any changes to objects inside one array were showing in the copied one as well .

A solution to shallow copying seemed to be Marshal. Forums were littered with caution against the usage of Marshal for copying. I ignored the warning and enjoyed a working output from my implementation of Conways's Game of Life. This is how Marshal was used:

@cell_grid = Marshal.load(Marshal.dump(@new_grid))

I introduced objects (instead of strings) as constants inside the Cell class that was used as the basic element of an array.

The output started behaving in an unpredictable manner and I was stuck for hours before giving up and asking for help. Turned out, that the way Marshal works is that it serialises and deserialises the objects DEAD and ALIVE and thus changes the object id.

So how do you solve the issue of copying objects or data structures in Ruby after having being let down by Object#dup, Object#clone and Marshal? The simple answer is – you avoid copying! This may sound too harsh, but as pointed out :

“generally, if you’re trying to make a copy of an object, you’re probably thinking about the problem wrong. Copying can be avoided by exploiting the way ruby references work and designing the function APIs accordingly”.

Gregory Brown, author of Best Practises in Ruby

Inspired but still dubious, I set out to remove any instances of copying in my Game of Life implementation. Instead of copying the two dimensional grid, I changed the state of the grid for the next generation based on the current generation's grid.

We intutively use copying in our code for situations which might seem like they need copying. But reducing instances of copying will ensure less buggy code base.


Aditya is an engineer at C42 Engineering. If you liked this post, please consider...

/

Code smells : getters and setters

A way of thinking about writing a good piece of code is to remember that not everything out there is good. Not all language features will help you write quality code. Some features may in fact be considered harmful (a code smell) and are hence discouraged.

Let’s consider the case of getters and setters. They are common in most languages. You might say what’s wrong about getters and setters? Well everything!

Getters and setters break the very concept of encapsulation and data abstraction. They essentially give access to the internal implementations which should never happen in any good OO design. Only place where you might think of using getters is comparison between same type of objects.


Vijay Dhama is an engineer at C42 Engineering. If you liked this post, please consider...

/

Chef Recipe for Capistrano setup

Capistrano sometimes throws errors like "cannot create XYZ folder because of inadequate permissions" . These irritating and trivial errors can be avoided by writing a Chef recipe to set up the machine for Capistrano deployment.

The recipe for setting up the machine for Capistrano would need to create the deployment folder and set the folder's owner to the Capistrano user. Then Capistrano can create all the folders it needs to manage the release version. We also need to add authorized SSH keys and add the RSA key for github to the list of known hosts as mentioned here. Additionally, config files like database.yml, secrets.yml can also be created.

Before writing the recipe, enter the deployment folder and the username used for deployment in the attributes/default.rb file.

The recipe for the setup is

Please note that it is not recommended to check in the database.yml, secret.yml or the SSH keys in any repository. You should add the contents into corresponding templates before running the recipe.


Shishir is an engineer at C42 Engineering. If you liked this post, please consider...

/

Setting Environment Variables with Figaro

You may want to use environment variables to store your secret credentials so that when you check your source code to a public repository, let's say github, your credentials aren't made public. The problem is, the rails server has to be restarted every time changes are made to the yaml file.

Meet Figaro, a gem which neatly does the job for you. First you'll need to add this line to yourGemfile and then run bundle update.

gem "figaro"

All you need to do now is run this on terminal

$ figaro install

This will create a config/application.yml file and also add it to .gitignore. Now you can just open up the application.yml file and set your environment variables. If you have to set value for ENV['MY_SECRET_IDENTITY'], in the file you will write

MY_SECRET_IDENTITY: 'Batman'

Happy Coding!

/

Writing specs for OmniAuth using Rspec

Recently, I used omniauth to implement google login in my rails application. Integrating and getting omniauth to work is pretty easy, if you are facing problems with that, you can check out another blog post which talks about just that. Now that you have knowledge of how omniauth will work in your project, you might want to write some specs for the same!

Here is where it gets a little tricky, for you to write specs for omniauth you'll have to mock it and insert omniauth.hash in the request environment.

Open your rails_helper.rb and add the following code to it.

OmniAuth.config.test_mode = true omniauth_hash = { 'provider' => 'google_oauth2', 'uid' => '12345', 'info' => { 'name' => 'Tony Stark', 'email' => 'tony@stark.com', 'nickname' => 'Iron Man' }, 'extra' => {'raw_info' => { 'location' => 'New York', 'gravatar_id' => '123456789' } } } OmniAuth.config.add_mock(:google_oauth2, omniauth_hash)

Now whenever you need the omniauth hash in your specs, all you need to do is to call this line of code. After that your spec might look like this

before do
 request.env['omniauth.auth'] = OmniAuth.config.mock_auth[:google_oauth2]
end

it 'should redirect to admin user' do
  get :create, :provider => :google_oauth2
  expect(response).to redirect_to(User.last)
end
/