Saturday, December 22, 2012

Clojure, Selenium-WebDriver, and PhantomJS

The following is a small manual of how to setup PhantomJS and use it from Clojure via clj-webdriver  - Clojure API for Selenium-WebDriver.


1. Start a new project using Leiningen:

2. Download PhantomJS from http://phantomjs.org/download.html and unpack it into your project's directory:

3. Now add the following to your project.clj file:


By the way, there is an awesome Leiningen plugin that checks if your dependencies are up to date.

4. Tell Leiningen to update dependencies:

5. Now let's start a REPL to check if everything's in its right place:

Hope it works! If not, ping me and I'll update the tutorial.

Wednesday, October 31, 2012

What to ask a client before you start creating their website?

Recently, I was asked by a friend of mine to create a website for a local travel agency. It's certainly not the hardest thing to do, but I decided to make something differently this time.

Before starting implementing anything I asked my potential customer the following four questions:

  • Why have you decided to create a website?
  • What problems should it solve?
  • Who are the potential visitors of the website?
  • What is unique about your website?
Each question was asked with some intent. Now, I will try to explain it.

Why have you decided to create a website?

All decisions we make are emotional in nature. Especially decision about buying something. The rationalization comes only after we've made it on emotional level. The strongest commitment one can make about a decision is to find a logical reason to make it.
The most important thing you need to figure out before starting anything is what caused your potential client to buy a website. If you find it, then you can easily assess the strength of commitment the person have made and how far they are going to go with it. You don't want a client that calls you next morning to cancel a project because they are no longer sure if it's a good idea. Ain't you?

What problems should it solve?

Website without a clear set of problems to solve is doomed to join the endless army of zombies that nobody wants to meet with. Also, without problems to solve you have no goals to achieve and no way to measure how far your solution is from the ideal one the customer has dreamt about. If so, why don't you ask about them beforehand to ensure that there are some?

Who are the potential visitors of the website?

Every website intended to have some audience, otherwise it's just a useless and strange way to spend time and money. To attract the audience you need to understand it. Ideally, you should be a part of it. How could you make any design decision without knowing who and how will judge them?

What is unique about your website?

There are literally thousands of travel agencies around the world. Good part of them have websites. In such market conditions it is vital for a website to have some unique content, otherwise it can't get to first few pages of search results and might equally not exist at all. There is no point in spending money and time on a website that nobody will ever find.


If you found this list useful and are interested in improving it, please don't hesitate to criticize it heartlessly!

Friday, July 27, 2012

Sending ICQ messages via Jabber-to-ICQ transport (JRuby + Smack API)


Lets assume that you already have JRuby on your machine. To gain access to Java libraries distributed via Maven you need to install a special gem :


jruby -S gem install ruby-maven


Then you should install Smack API library:


jruby -S gem install mvn:org.igniterealtime.smack:smack


Please notice the special prefix "mvn:". You can also use it in Bundler's Gemfile to reference Java libraries once you have ruby-maven gem installed.


Now lets write a simple program to utilize the just installed library. Make sure you already have a valid Jabber and ICQ account. Also don't forget to register the latter via some Jabber-to-ICQ transport.


require 'java'
require 'rubygems'
require 'mvn:org.igniterealtime.smack:smack'

jabber_server = "jabber.dn.ua"
jabber_account_id = "my_jabber_id"
jabber_account_password = "**********"

icq_transport_server = "icq.jabber.dn.ua"
icq_account_id = "1234567890"

conn = org.jivesoftware.smack.XMPPConnection.new(jabber_server)
conn.connect
conn.login(jabber_account_id, jabber_account_password)

cm = conn.chat_manager

def self.processMessage(chat, message)
  puts message
end

chat = cm.create_chat("#{icq_account_id}@#{icq_transport_server}", self)
chat.send_message("Hello!")


To find more about Smack API check its page.

Thursday, June 28, 2012

Making variable dynamic in Clojure

As a full-time Ruby developer studying Clojure I was curious how one can monkey-patch 3rd-party's code in the runtime. The answer is to utilize Clojure's dynamic scoping to redefine a variable that holds a reference to the function of interest. But starting from version 1.3 only variables that are explicitly tagged by ^:dynamic meta tag can be dynamically bind (usage of lexical scoping has positive performance impact).

So, maybe we could change variable metadata to make the variable dynamic. Unfortunately, changing metadata using alter-meta! doesn't trigger its re-evaluation. Consider the following:

user=> (def x 42)
#'user/x

user=> (alter-meta! #'x assoc :dynamic true)
{:ns #, :name x, :dynamic true, :line 1, :file "NO_SOURCE_PATH"}

user=> (.isDynamic #'x)
false

user=> (binding [x 32] (println x))
IllegalStateException Can't dynamically bind non-dynamic var: user/x clojure.lang.Var.pushThreadBindings (Var.java:353)

Instead we can call .setDynamic directly:

user=> (.setDynamic #'x)
#'user/x

user=> (binding [x 32] (println x))
32
nil

If you want to redefine variables temporarily, without making them dynamic (e.g., for mocking out functions during testing), you can use new functions that were added to cover such use case - with-redefs-fn and with-redefs.

Thursday, April 05, 2012

Adding Norwegian (Bokmål) Dictionary to JetBrains RubyMine on Ubuntu

Firstly, install the aspell-no package:

sudo apt-get install aspell-no

Secondly, convert the just installed Norwegian Bokmål dictionary to the format appropriate for RubyMine:

aspell --lang nb dump master | aspell --lang nb expand | tr ' ' '\n' > nb.dic

Thirdly, open the RubyMine settings dialog, find "Spelling" in the "Project Settings" section and switch to the "Dictionaries" tab. Then press "Add" in the "Custom Dictionaries Folder" section and choose the folder where you've just created the nb.dic file.

The process of converting and adding dictionary for any other language should be similar.

WhatFont: the easiest way to find out the fonts used in a webpage

WhatFont helps you easily get font information about the text you are hovering on.

Many thanks to Sacha Greif for mantioning it on his blog. Check the "Tools of the Trade" post to find other useful tools.

Wednesday, April 04, 2012

Keyboard shortcut for "inspect" button

Have you ever tried to "catch" an element that shows only on hover using "inspect" tool in Google Chrome? No luck, right? Finally, there is a way to select it without clicking the toolbar button!

The shortcut is Ctrl-Shift-C for Win/Linux, Cmd-Shift-C for Mac.

As of Chrome 18, it's not mentioned on help overlay (press F1 to view it).

Check the related issue in the Chromium bugtracker.

Tuesday, March 06, 2012

Datomic Has Been Announced

Datomic moves powerful data manipulation capabilities, and the data itself, into applications, coupling them with a sound and flexible data model. This provides the basis for the next generation of elastic, intelligent applications, free from the bounds of traditional databases.

Read the whitepaper

It looks really interesting, especially for someone who is already concerned with entity/state/value/time modeling problem of traditional object-oriented programming languages.