RSpec: specify_negatively

Posted by yrashk

Hello, RSpec fans!

Today I was playing with an idea of negative tests. They are surely a thing one may need while working on a long-term project. For example, you may need negative testing when you plan a future major change. You may want to plan this change as a test, but it should not fail today and it should be quite easy to rewrite it to non-failing test tomorrow.

Of course, you can just create a specification that tests that this planned functionality does not work today. And then, rewrite each test within it to opposite tomorrow.

But what if this could be done easier?

And it could! I’ve spent few minutes to create a quick-n-dirty specify_negatively implementation for rspec. I’m not sure whether it will be useful or even working properly in all cases, but it seems to pass on a simple test:

 
context "Test context" do

  specify "test" do
    (2+2).should == 4
  end

  specify_negatively "negative test" do
    (2+2).should == 5
  end

  specify_negatively "bad negative test" do
    (2+2).should == 4
  end

end
 
 
Test context
- test
- negative test
- bad negative test (FAILED - 1)

1)
'Test context bad negative test' FAILED
This specification was expected to fail, but nothing failed

Finished in 0.041288 seconds

3 specifications, 1 failure
 

What do you think?

Fixturease 0.2.1 + 0.2.2

Posted by yrashk

New Fixturease is finally gem-installable from Rubyforge:

 
  sudo gem install fixturease
 

0.2.1 is a minor upgrade for 0.2: Windows support and bugfix. Enjoy!

0.2.2 is a bugfix upgrade for 0.2.1: Now Fixturease will not attempt to save destroyed object. Sorry for this bug! :D

Better Fixturease

Posted by yrashk

I’ve improved Fixturease today with one major and few minor improvements.

I’d like to show major one. Now you can name your fixtures by assigning instance variables with ActiveRecord objects:

 
$ fixturease.rb
Loading Fixturease console for test mode.
>> @new_document = Document.create
=> #<Document:0x2049244 @new_record_before_save=true, @new_record=false, @attributes={"id"=>44}, errors#<ActiveRecord::Errors:0x203b02c @base=#<Document:0x2049244 ...>, errors{}
>> 
Saving fixtures:
Document [../hereby/spec/fixtures/documents.yml]: new_document
 

Yes, that means that you’ll get

 
new_document: 
  id: 44
 

in your documents.yml instead of usual documents_44 as for unnamed objects. Easy? Yeah! :D

Rubyforge is anyway down now, so download here

P.S. Code inside is still awful. Sorry!

Easy Fixtures

Posted by yrashk

I was doing some research on a future product I plan to develop and found that I extremely dislike creating fixtures for nested_set models. You know, I’m pretty much lazy. I don’t want to calculate lft and rgt. I thought about what can I do to simplify my life.

Attention: may be I was blind again and missed some already made tool. Anyway, I’ve done something, and I would like to share it.

I’ve created Fixturease gem. It is not published at Rubyforge yet, so you can download it here

Now, you can run it as:

 
 $ RAILS_ROOT=/path/to/app RAILS_ENV=development FIXTURES_ROOT=path/to/fixtures fixturease.rb
 
  • if you’re in a root of your rails app, you can omit RAILS_ROOT
  • if you want test mode, you can omit RAILS_ENV
  • FIXTURES_ROOT is relative path to fixtures. By default, it is spec/fixtures (yes, we use RSpec)

What it does? It creates a special console for you. You just create your objects as you want, and when ready, just exit from it:

 
$ fixturease.rb 
Loading Fixturease console for test mode.
>> Clause.create :document => Document.create 
=> #<Clause:0x130e368 @document=#<Document:0x203f5dc @new_record_before_save=true, @errors=#<ActiveRecord::Errors:0x20100e8 @base=#<Document:0x203f5dc ...>, errors{}, attributes{"id"=>31}, new_recordfalse, errors#<ActiveRecord::Errors:0x1301a8c @base=#<Clause:0x130e368 ...>, errors{}, attributes{"created_on"=>Wed Jan 17 20:39:52 0200 2007, "document_id"=>31, "updated_on"=>Wed Jan 17 20:39:52 0200 2007, "lft"=>1, "id"=>25, "content"=>nil, "rgt"=>2, "parent_id"=>nil}, new_recordfalse
>> 
Saving fixtures:
Document [./spec/fixtures/documents.yml]: 31
Clause [./spec/fixtures/clauses.yml]: 25
 

It will append your fixtures files with newly created objects. That’s it. Easy? I assume yes! Useful? I don’t know, but I like it!

P.S. The code inside is awful. I know. It was a quick hack, really.

Update: better version here

Thinking in Functional Ruby 6

Posted by yrashk

This article is a result of yesterday’s code review session I have done.

I have found that I don’t like the following code (well, a code like this):

def topmost_matches(str,limit=3)
  matches = []
  str.each(' ') do |word|
    word = word.strip.downcase
    matches << word if Entity.find_by_name(word)
  end
  return matches[0, limit] if matches.size > limit
  matches
end

Here is what we can do with this code to make it better:

Well, first of all, let’s simplify last two lines. Since if even matches.size is less than limit, matches[0,limit] will return the whole matches array. This means that we don’t need any kind of explicit condition:

  matches[0,limit]

Then, I really can’t say that the rest of the code is easy to read and understand. It is not readable, it is rather interpretable. And here we can use some Ruby power to do this stuff meach easier and nicer:

 str.split(/\s+/).         # here we split str by whitespace characters
      collect(&:downcase). # then we downcase each word
      select{|word| Entity.find_by_name(word)}[0,limit] 
                           # ...and finally we select that words
                           # that are found within Entities names

Also, it is pretty easy to add even a more complex functionality to this single functional “query”. For example, we also may want to sort results according Entities ratings, descending. No problem!

 str.split(/\s+/). 
      collect(&:downcase).
      select{|word| Entity.find_by_name(word)}.
      collect{|word| Entity.find_by_name(word)}. # collect respective Entities
      sort_by(&:rating).reverse.                 # sort them by rating, descending
      collect(&:name)[0,limit]                   # collect their names, and return topmost 
                                                 # of them

Of course, the above code is still a heaven for code reviewer, but it is out of this article’s scope.

Update: According to improvements proposed in comments, it could be even that easy:

 str.split(/\s+/). 
      collect(&:downcase).
      collect{|word| Entity.find_by_name(word)}.compact.
      sort_by(&:rating).reverse.               
      collect(&:name).first(limit)

Continuous Integration: Cerberus 13

Posted by yrashk

Jordan Arentsen said that he would like to read about Continuous Integration. With a great pleasure!

I would like to talk about Cerberus tool and how we apply it in particular. Cerberus is a great simple tool to perform rake tasks continuously on your project whenever it updates.

I will guide you through the setup.

  • First of all, make sure that your subversion client is at least at version 1.2. It will not work with earlier versions.
  • Setup an email alias for notifications, something like dev-foobar@foobar.com that will forward any email (except spam!) to your team.
  • Then, simply install Cerberus from a gem: gem install cerberus
  • Create a user for cerberus: adduser -m cerberus, passwd cerberus
  • Log in as a cerberus (or just use sudo -H -u cerberus as a prefix)
  • Assuming you have a project at file:///var/lib/svn/foobar/foobar/trunk just do
 
cerberus add file:///var/lib/svn/foobar/foobar/trunk  \
               APPLICATION_NAME=FooBar \
              RECIPIENTS=dev-foobar@foobar.com
 
  • Open /home/cerberus/.cerberus/config.yml and specify there such parameters:
 
publisher:
#  active: mail jabber rss campfire irc
  active: mail campfire # you may also use irc, jabber and rss,
                                     # which we are not using at the moment
  mail:
    sender: cerberus@foobar.com
    address: foobar.com
    port: 25
    domain: foobar.com
    #authentication: plain
    #user_name: someuser
    #password: somepassword
  campfire:
    url: http://cerberus@foobar.com:crbrs@foobar.campfirenow.com/room/58153
#  jabber:
#    jid: cerberus@gtalk.google.com
#    port: 5222
#    password: mypass
#    digest: false
#  irc:
#    nick: cerb
#    server: irc.freenode.net
#    channel: cerberus
#  rss:
#    file: /usr/www/rss.xml
builder:
  rake:
    task: db:migrate # we are also adding here 'spec spec_with_rcov ', since we use
                                # both RSpec and RCov
 
* Then, open /home/cerberus/.cerberus/config/FooBar.yml and edit it:
 
---
publisher:
  mail:
      recipients: dev-foobar@foobar.com
  # specify the rest publishers per project parameters here
scm: 
  type: svn
  url: file:///var/lib/svn/foobar/foobar/trunk
changeset_url: http://trac.foobar.com/changeset/  # If you have Trac (you should! :), integrate with it                                                                                  
 
  • You can override system-wide settings (/home/cerberus/.cerberus/config.yml) with project-wide settings (/home/cerberus/.cerberus/config/FooBar.yml), (I’d suggest to pay attention to at least builder: => rake:) (consider looking at a full list)
  • You can perform a test by typing cerberus build FooBar. It will email you about project setup.
* Now, add it to crontab to run it as frequently as you wish. It does not consumes much time if there was no fresh checkins in a repository, it only runs tests against your code if your repository was updated. We use to run Cerberus each 10 minutes:
 
*/10 * * * * cerberus buildall

  • You’re done!

Few more tips:

  • If you want Cerberus to rebuild FooBar from the scratch, simply rm -rf /home/cerberus/.cerberus/work/FooBar
  • I strongly recommend to generate RCov diagram each time Cerberus runs. Here is how you can integrate RCov with RSpec:

lib/tasks/rcov.task:


require 'rake'
require 'spec/rake/spectask'

Spec::Rake::SpecTask.new('spec_with_rcov') do |t|
    t.rcov = true
 end

  • To integrate it without RSpec, look here (not sure it is what you need exactly, however)
  • Then simply symlink generated coverage directory to some web-accessible (preferably httpauth protected)

I will try to talk more on a coverage analysis later. Now it’s too late (or too early, 4:45 AM)

Few Tips About How to Become a More Effective Developer

Posted by yrashk

Today I want to talk a bit about a topic that seemed to be quite trivial for me and people around, but I’ve found that some things that are trivial for us, aren’t obvious for everyone. So I want to share my thoughts about how to become a more effective developer. I do not pretend to be a guru in this area, it is just my own experience.

Planning

Planning is the first thing to think about if you want to become effective. No need to perform a prioritization or long-term planning. What you actually may need is the following path:

  • write down a list of tasks that you need to accomplish
  • pop those that could be completed in a matter of minutes and put them into ‘RightNow’ folder
  • then sort each task according to the milestone it relates to. If a task should be completed by tomorrow’s morning, then put it to ‘Today’ folder. If it should be done by the end of week, put it into ‘ThisWeek’ folder. If it should be done by the end of a month, put it to ‘ThisMonth’ folder and so on.

Simple enough. Few advices on tasks:

  • define them shortly and cleanly
  • be realistic on time consumation estimations

Execution

So, when you have a plan, you need to work properly with it. It is pretty easy to do:

  • first look into RightNow folder. If there is something to do, do it now. If it is empty, proceed to Today. And so on.
  • the rule of thumb is that you shoud not proceed with a next folder until your current folder is empty.
  • of course, you may need re-plan your tasks if some circumstances were changed. Pay attention to keep your plans up-to-date, that’s vital.

Source Code Management

Source code is the most important result of you work, so you need to manage it properly, aren’t you?

  • Use version control management system. It could be Subversion, Darcs, Git, whatever you like the most (Subversion is quite popular among Rails developers, and I will use it here for examples)
  • Check in your changes frequently. Why? First reason is that you will most likely avoid breaking own code. Once you’ve done task, check it in. Another reason is that if you’re working within a team, they surely would like to have all the code integrated as earlier as it is possible.
svn ci -m "Ticket #2: Improving code quality"
  • Keep your checkin messages descriptive. “another change”, “fixed bug” aren’t descriptive at all.

Example:

svn ci -m "Workaround for a defect #267"
  • Install something like a Trac. It will allow you to track your code changes and issues. It will simplify your life greatly.
  • If you’re working within a team, consider updating your repository (svn up) each few hours and reading others’ changesets at least once a day (in a morning). It will keep you up-to-date and you will not trap into a need to resolve a lot of source code conflicts.
  • Once you’ve trapped into a source code conflict (Subversion reports you about it with a ‘C’ tag for a file), resolve it ASAP. Merge changes outlined in a conflict file and then say svn resolve path/to/file

Source Code

Now, about source code itself.

  • Be lazy. Type less. If you are a happy TextMate user, press esc frequently to autocomplete your text. It will help you to avoid mispelled variable/method names.
  • Follow naming conventions. This is particulary easy with Rails, because it has already established common naming conventions. Ruby itself offers some conventions as well, like appending boolean methods with ?. Following naming conventions will simplify your life greatly, believe me.
  • Use descriptive names for your variables, methods, symbols, etc.
  • Write a code that should be readable, not interpretable. Anybody should be able to understand what your code does by just reading it as a subset of English with some mix with programming language constructs. If you need to interpret code in your brain to understand what it is doing, then it’s potentially a bad code. This is quite hard rule to follow, and it should not be applied to every and every bit of your code. But it’s important to not underestimate its value.
  • Shrink your code size. Avoid extra meaningless constructs. Use short forms of them.
Example: do_something if reasonable? instead of

if reasonable?
   do_something
end

  • Review your code before a checkin. If it smells bad even a bit, try to improve it.
  • Ask your colleague to spend 15 minutes reviewing your code.

Tests

It’s a large topic I will surely cover in some of my future. Let me outline few things:

  • Write test strictly before any implementation code. It will a) guarantee you’re implementing what you need exactly b) speed up your actual development significantly
  • Consider using RSpec. It allows you to write tests in a way that is much closer to English and it will also allow you to group your tests with ease:

context "Newly created Issue" do

 setup do
   @issue = Issue.new
 end

 specify "should have at least 2 questions" do
   @issue.should_have_at_least(2).questions
 end
end

  • Make sure your tests (or specifications in a RSpec terminology) are passing before each repository checkin.
  • Setup a continuous integration software like Cerberus. It will alert you if code becomes broken accidentally.
  • Consider generating RCov code coverage diagrams on a regular basis (let Cerberus do this!). This way you will be sure that your code is well covered by tests. Of course, RCov has to say nothing about how qualitative your tests coverage is, but it could say you whether you’re running each piece of your code by your tests or not. This is quite important.

TO BE CONTINUED: I would like to talk more on some tips, like Rails-specific ones, in the future posts. I’m going to add more details on an issues I’ve mentioned above, supply with more details. Stay tuned!

TO BE UPDATED: If I will find that I forgot to mention something important here, I will update this record.

P.S. Please advise me – may be the above issues are obvious for everyone and I should not write about them and save your and my time? :) I’m just not sure whether it have sense. If it has – then great!

We Are Hiring Internationally 0

Posted by yrashk

I’m happy to announce that Railsware is starting hiring internationally. We are obviously not requiring to relocate, we are just comfortable with telecommuting.

We’re building a networked team of decent Ruby on Rails developers. We’re looking for you.

We are fans of Rails. We like smart code. We like smart people. We like agile processes. We prefer to be an an edge.

If you’re interested to join a team of like-minded persons, then contact us at job@railsware.com. We are waiting for you!


Railsware is headquartered in Kiev, Ukraine, one of the top world outsourcing destinations.

Boolean Attributes in Ruby 0

Posted by yrashk

Blog entry about Ruby boolean attributes plugin is removed for some reason back online.

Just thought that an example snippet I’ve posted there as a comment could be useful for someone. I had a bit improved it also.

Anyway, it is pretty simplistic (in a contrary to what was published at PluginAWeek)

Here you are. It is by no means perfect (it’s far from being perfect, actually), but just to give you an idea.

 
class Class
    alias :original_attr_accessor :attr_accessor
    alias :original_attr_reader :attr_reader

    def attr_accessor(sym)
        battr_wrapper :original_attr_accessor, sym
    end

    def attr_reader(sym)
        battr_wrapper :original_attr_reader, sym
    end

    protected

    def battr_wrapper(method,sym)
        name = sym.to_s.gsub(/\?$/,"").to_sym
        send method, name
        define_method("#{sym}") do
            instance_variable_get("@#{name}")
        end unless name == sym
        self
    end

end
 

And, oh yeah, I forgot to show what it is for!

 
>> class A ; attr_reader :hello? ; end
=> A
>> A.new.hello?
=> nil
>> class B ; attr_accessor :hello? ; end
=> B
>> b = B.new
=> #<B:0x12466c4>
>> b.hello = true
=> true
>> b.hello?
=> true
>> 
 
(and it does not work in default Ruby, you’ll get NameError: invalid attribute name `hello?' )

Update: Evan has proposed even better implementation

Micro-management, Naming Conventions and Rails 0

Posted by yrashk

Today I’ve heard yet another story about that bad project manager who was enjoying micro-management in an aspect of naming conventions. He was requiring to start interface names with I letter, he was pushing some database rules for fields naming, foreign keys naming, etc.

And developers didn’t like what he do. I think it is mostly because each developer has his own style, preferences, sensation of reasonabe and beautiful. Common code style is rather good, but there is probably some kind of competition between technically-savvy managers and developers.

But what did Rails offered to both project managers and developers? Common naming conventions. Reasonable naming conventions that simplify life, if you use them. If you don’t use them, you should do something that is not directly related to a problem you should focus on. Now project manager could save his/her time and nerves and developers could stop competing with him/her. It’s a win-win situation, I suppose.


One of my friends asked me yesterday via IM: “What if I want to let Rails path to controllers be CamelCase?” I said “What is the reason for you to want it?” He said “BecauseCustomerWantsSo”.

Most of developers are opposing micro-management, and they have reasons. But I’m rather against blindly opposing micro-management. It’s important to realize that micro-management efforts could differ.

My daily activities in Railsware include technical leadership tasks, just like code review. I review every important commit done, at least briefly. And I supply our developers with tasks/advices about how they should improve their code to make it better, easily readable, manageable, testable, etc. While sometimes I could reasonably expect counteraction to such kind of management, I experience it quite rarely. I strongly believe that this kind of “mentorship” leads us to a better quality. As far as I can understand, this way our developers could benefit by a) resulting in a cleaner and better own code b) learning some patterns they didn’t knew before c) having less time spent on testing and debugging.

Actually, what’s bad with micro-management? I have a supposition that the most bad thing with it is that manager is using a power of his/her position to press on subordinates. This sounds reasonable, at least for me. I should take it into account. I’m going to introduce something like cross-developer/cross-project code review sessions within our team.

Happy hacking!

Nagging Issue Tracker 8

Posted by yrashk

I was thinking about issue tracking a lot for last few weeks. There are a lot of free, commercial and hosted software options that let you track your issues in this or that way. Some of the popular choices are Trac, RT, JIRA and Basecamp.

Though as far as I understand all these solutions, they are pretty passive, just like most of web applications. They are just issue databases with notification capabilities. And that made me to think in a somewhat different way.

Please note that may be I’ve just missed something that is already implemented this way and just re-inventing a wheel

So, what I am talking about? Why I’ve said that solutions I know are passive?

Well, actually—what these solutions are doing? They allow you to collect issues, update them and get notifications about changes made. Basically, that’s all. It’s pretty straightforward, works for numerous companies and individuals, but… the problem is that I’m not very self-disciplined, I’m rather enthusiast, and I could easily lose a focus and finally have problems with own daily or weekly or monthly (yikes!) plan. And as far as I can see, I’m not that alone.

So I came to a simple idea of so called nagging issue tracker (nagit). What it is about? What purpose should it serve? An idea is very simple, really:

  • nagit splits assigned issues into session chunks: rightnow (tasks to be done just now, in a few hours term), today (tasks to be done today), thisweek, thismonth, thisyear.
  • Once you have assigned tasks in a rightnow chunk, it’s your current chunk. When you’re done with them, today chunk is your current one, and so on.
  • nagit should not allow you to view (or at least it should complicate access and make any changes impossible) for any assigned task that is not planned for the current chunk.
  • nagit should nag you via popups, email, IM, SMS, headache stimulator about current session’s tasks quite frequent. Frequency should be calculated using some task’s weight formula, something like:

    weight(task) = (task.chunk.length_in_seconds-task.chunk.time_left_in_seconds) / task.chunk.length_in_seconds *  task.importance

,

where weight and task.importance are in (0..1). If weight is higher, then nagit should remind you about this assignment more frequently.

So. Maybe you’ve got an idea. It’s still a bit rough, but it’s a concept, not a real car (YET!).

Yes, it looks that nagit is a quite aggressive application. But what if it will help me and some of you to focus on your plan (and then, get rich, happy and healthy)?

/me is experimenting with mockups.

object_id_session 0

Posted by yrashk

I’ve developed a very simple plugin that allows to store ActiveRecord models over session using their IDs transparently.

So, for example, you are saving User in a session:

 
                session[:user] = User.find(1)
                session[:newuser] = User.new
 

After this, your session will look like this:

This plugin does not requires you to change your code. To get your object back, you should just ask session for it:

 
                session[:user]
 

and you’ll get User instance. object_id_session is responsible for conversions to be performed.

It is a very early version, its code isn’t perfect and there are probably some bugs, but it seems to pass some basic tests (which are written in RSpec, of course)

You can install this plugin from svn://verbdev.com/rubylibs/object_id_session/trunk

Why it could be useful? Well, I’ve just thought that it is quite stupid to pass big objects around session all the time, checking whether they are still available in the database each time, etc.

May be I’m just missing something and this kind of functionality is already implemented somewhere. In this case, just kill me, yeah! :)

Ruby With 2

Posted by yrashk

It’s definitely what I was missing from Common Lisp:

RSpec on Rails: acts_as_authenticated 1

Posted by yrashk

As you may know, we at Railsware are using RSpec now.

I’ve found that I need ospecifications for a acts_as_authenticated plugin.

While I was able to find a spec for its controller at caboo.se, I haven’t found any spec for a model. May be I’m just blind this night, but anyway I’ve wrote my own

Update: I’ve found Caboo.se implementation of specification being far from perfect, so I have improved it a bit: account_controller_spec.rb

Update:Jonathan used this blog entry to deliver RESTful authentication specifications Nice to hear!

Free Job Ads 1

Posted by yrashk

Happy New Year!

I’ve decided to make job ads on my blog free for 5 months.

Feel free to post a job ad with FREEAD coupon for free :)