RSpec 2 Matcher Fun

Posted by Nick Sieger Thu, 20 Jan 2011 17:47:21 GMT

I was troubleshooting some JRuby code that transforms Java camelCase method names into Ruby snake_case form. We had a bunch of specs that did this, for example:

describe "Java instance method names" do
  it "should present javabean properties as attribute readers and writers" do
    methods = MethodNames.instance_methods

    methods.should include("getValue2")
    methods.should include("get_value2")
    methods.should include("value2")

    methods.should include("setValue2")
    methods.should include("set_value2")
    methods.should include("value2=")
  end
end

The problem comes when these specs fail. The default error message made by the #include matcher looks like:

Failures:

  1) Java instance method names should present javabean properties as attribute readers and writers
     Failure/Error: methods.should include("get_value2")
       expected [...full contents of array here...] to include "get_value2"
       Diff:
       @@ -1,2 +1,186 @@
       -get_value2
       +[...all entries, one per line here...]

That’s not a terrible message, but when your array contains over 100 entries (like an array of method names), it could be a lot better. In particular, I kept scanning the failure message’s big list, unable to clearly see why the methods I was expecting weren’t there.

What I wanted to see was how my changes to the regex which splits a Java camelCase name affected the conversion. So, what I needed was a report of which method names were the closest to the ones that were not in the list. Hey, sounds like a good reason to implement a custom matcher, and take a diversion into fuzzy string matching algorithms!

I settled on porting the pseudocode in Wikipedia for the Levenshtein distance, which calculates how close in content two strings are to each other. I looked around and there are existing Levenshtein ports for Ruby, but they use native code for performance. I don’t need performance because I’m only using the Levenshtein function when there is a failure. Of course, pure Ruby code is more portable too!.

The other change I made in the specs was to pass all strings in a single matcher rather than one name per expectation, so we can see all names that fail, not just the first.

So now, the new spec looks more like this:

describe "Java instance method names" do
  let(:members) { MethodNames.instance_methods }

  it "should present javabean properties as attribute readers and writers" do
    members.should have_strings("getValue2",
                                "get_value2",
                                "value2",
                                "setValue2",
                                "set_value2",
                                "value2=")
  end
end

The custom RSpec matcher #have_strings is declared like so:

RSpec::Matchers.define :have_strings do |*strings|
  match do |container|
    @included, @missing = [], []
    strings.flatten.each do |s|
      if container.include?(s)
        @included << s
      else
        @missing << s
      end
    end
    @missing.empty?
  end

  failure_message_for_should do |container|
    "expected array of #{container.length} elements to include #{@missing.inspect}.\n" +
      "#{closest_match_message(@missing, container)}"
  end

  failure_message_for_should_not do |container|
    "expected array of #{container.length} elements to not include #{@included.inspect}."
  end

  def closest_match_message(missing, container)
    missing.map do |m|
      groups = container.group_by {|x| levenshtein(m, x) }
      "  closest match for #{m.inspect}: #{groups[groups.keys.min].inspect}"
    end.join("\n")
  end
end

I omitted the #levenshtein function here for brevity. (You can view the full source for details.) Now our failing spec output looks like:

Failures:

  1) Java instance method names should present javabean properties as attribute readers and writers
     Failure/Error: members.should have_strings("getValue2",
       expected array of 185 elements to include ["get_my_value", "my_value", "set_my_value", "my_value="].
         closest match for "get_my_value": ["get_myvalue", "set_myvalue"]
         closest match for "my_value": ["myvalue"]
         closest match for "set_my_value": ["get_myvalue", "set_myvalue"]
         closest match for "my_value=": ["myvalue="]

Now the failure message is giving me exactly the information I need. Much better, don’t you think?

Tags ,

War on Perfect

Posted by Nick Sieger Mon, 22 Nov 2010 18:30:00 GMT

I intended to give this brief as a lightning talk at RubyConf 2010, but unfortunately did not get a chance. Though I kept the message simple, I think if you sympathize with being a perfectionist you can find some part of these points that rings true. I know I still have a ways to go in heeding my own advice, and not only in software but in my life as a whole.

Thanks to Hiro Asari for the Japanese translations and Jeremy Hinegardner for the Rubygems.org numbers.

War on Perfect

I want to start a war.

宣戦布告

A war on Perfection!

完璧主義への宣戦布告!

Perfect.

完璧

I hate this word.

この言葉が大嫌いです。

I want to eliminate it from our vocabulary.

私達の語彙から抹消したいのです。

What is Perfect?

そもそも完璧とは何でしょう。

Ask 10 people, get 10 answers.

訊けば十人十色の答えが返ってくるでしょう。

Different answers means disagreement.

答えが違うという事は、いずれ食い違いが起こるという事に他なりません。

Perfection cannot accept compromise.

完璧主義には妥協の余地がありません。

Without compromise, we cannot get along, or get anything done.

妥協無しには、仲良くやって行ったり 何かを成し遂げる事は出来ないでしょう。

(Just look at politics in the USA.)

アメリカの政治を見れば解りますね。

Perfect is lonely if you can’t agree or share with anyone else.

他人と合意や共有が出来ないので 完璧主義とは孤独でもあります。

We are human. No one wants to be alone.

僕らは人間。孤独は厭です。

Perfect is contagious

完璧主義は伝染し易い。

If you’re not embarrassed when you ship your first version you waited too long.

「初めのリリースで恥ずかしくないのはリリースを遅らせ過ぎた証。」

-- Matt Mullenweg マット・マレンウェグ

How many Ruby gems have never seen 1.0?

Rubyのgemで1.0に到達しないものは幾つありますか。

Any guesses?

けんとうはつきますか。

17864 Rubygems 86837 versions バージョン

13496 gems without a version that does not start with “0”. 75 Percent!

75%

I challenge you all to release 1.0 on your first push to Rubygems next time.

この次にRubygemsにプッシュする時はバージョンを1.0にしましょう。

Perfect is impossible

完璧は不可能

If you seek it, you will never quite attain it.

求めても得る事は難しい。

You will worry it’s not perfect enough, and it will escape your grasp.

あなたが完璧か心配しているうちに完璧は逃げて行ってしまう。

Perfect keeps you too focused on one thing.

完璧主義は視野を狭くする。

Your mind will cripple you.

そして足枷になる。

You won’t be able to finish it.

プロジェクトを完成出来ずに

You’ll feel helpless because nothing is ever good enough.

よくやったと思えずに、絶望感に襲われる。

Perfect ruins your productivity.

完璧主義では生産性が損なわれる。

You’ll feel like your work is never done.

いつまで経っても仕事が終わらないように思えるから。

Perfect is harmful to your health.

完璧主義は健康に悪い。

We work too hard to achieve perfection.

完璧を求め、働き過ぎる。

We set our personal standards too high.

水準が高過ぎる。

And rarely reach them.

しかも滅多に到達する事もない。

So we worry about not being good enough.

だから、「これで充分」と思えずに心労する。

This makes us ANXIOUS.

それで不安になる。

Anxiety can give you stress,

不安はストレスに繋がり

make you sick,

病気に繋がることもある。

or even kill you.

最悪の場合死ぬことすらある。

We can’t be happy if we’re anxious or unhealthy.

不安だったり不健康では幸せにはなれない。

We can’t be happy if we accept no compromises.

妥協無しには幸せにはなれない。

We can’t be happy if we’re alone.

独りぼっちでは幸せにはなれない。

We can’t be happy if we strive for perfection.

完璧主義では幸せにはなれない。

Matz knows this. He is WISE!

Matzはこのことを知っています。聡明なまっつ。

Ruby is not perfect.

Rubyは完璧ではない。

(Matz knows this too!)

これもMatzは知っています。

Matz made Ruby so we could be happy.

まっつは私達の幸せのためRubyを作りました。

Perfection keeps us from:

完璧主義では

making compromises,

妥協は許されない。

getting things done,

何かを成し遂げる事は出来ない。

enjoying each other’s company,

他人と同じ時間を過ごす喜びを見いだせない。

being happy.

幸せになれない。

And that’s why I hate it.

私が完璧主義を嫌う理由です。

So you can either try to be:

選択肢は二つ

Perfect [and be]

完璧である換わりに

Lonely

独りぼっちで

Unproductive

非生産的で

Unhealthy

不健康であるか

or you can be HAPPY.

或いは、幸せであるか。

I’ll choose to be happy. I hope you do too.

私は後者を選びます。あなたはどうですか。

ありがとうございました!

Tags , , , ,

RubyConf India 2010!

Posted by Nick Sieger Fri, 12 Mar 2010 23:21:04 GMT

I’m honored to be heading to the first ever RubyConf India in Bangalore next week. I’ll be delivering an update on Rails 3, JRuby, and what’s in store for the future of the combined platform in 2010. I’m looking forward to meeting you there!

I'm speaking at RubyConf India 2010

Tags , ,  | 2 comments

Gem clash: activerecord-jdbc-adapter and pg

Posted by Nick Sieger Thu, 28 Jan 2010 15:16:49 GMT

I got a note from a community member about an annoying problem that a few people have run into when installing activerecord-jdbc-adapter (AR-JDBC) into a C Ruby implementation:

NameError: uninitialized constant
ActiveRecord::ConnectionAdapters::PostgreSQLAdapter::PGconn

Turns out it’s pretty easy to momentarily forget to use jruby -S gem or jgem and just gem install activerecord-jdbc-adapter and suddenly your pg Postgres gems are not working properly. I thought it was worth documenting here in case others run into this problem.

I apologize for the clash. I had to provide a stub pg.rb in AR-JDBC inside of JRuby so that I could get active_record/connection_adapters/postgresql_adapter.rb to load with a database adapter type of postgresql. Because of load path order issues, I couldn’t get AR-JDBC’s code to load before ActiveRecord’s. At the time I was thinking this wouldn’t be a problem because the pg library won’t work on JRuby anyway, right? Wrong.

I can think of a couple options going forward:

  1. Submit a patch to ActiveRecord so that active_record/connection_adapters/postgresql_adapter.rb can load without requiring pg up front and then AR-JDBC won’t have to stub it out.
  2. Display a big fat warning message when AR-JDBC is installed into anything other than JRuby.

Any other thoughts?

Tags ,  | 2 comments

New Hpricot Release

Posted by Nick Sieger Fri, 06 Nov 2009 16:06:37 GMT

It’s with a modicum of fanfare and a cocktail of orange peel, maraschino, bitters, bourbon and vermouth that I announce the 0.8.2 release of Hpricot.

hpricot

The angly thingies are just two martini glasses turned on their side, see? Pouring out hpricoty goodness for you. (I don’t know if _why imbibed alcoholic beverages but I feel the desire to raise a glass to him.)

This release is mostly a refresh; the previous release was way back in April. From the Git logs I can see that there were a few bug fixes since then. Otherwise, the main addition is a modern JRuby release, thanks to Ola Bini. (the previous was the 0.6 series). This does fix a fairly old, popular JRuby bug.

As for the future of Hpricot, it’s up to you. I know it’s still a trusty tool for many; I have no grand plans to change it. So if you encounter bugs and want to send patches, I’m happy to serve as your curator.

Tags , , ,  | 2 comments

Which Tool Would You Use?

Posted by Nick Sieger Fri, 12 Jun 2009 20:34:27 GMT

I started in on the twice-yearly task of pruning our hedges today. So confronted with this task:

Shearing the shrubs

Which tool would you use?

Which tool?

I used both today, but realized I enjoy using the hand trimmers much more. With the electric trimmers, you can buzz through a lot of hedge quickly, but sometimes this happens:

Too close

With the hand trimmers, I can take my time and make precise cuts. The end result may take more time, but it turns out much, much better.

Software tools have similar feels to me. Java feels an awful lot like the electric trimmers. It’s heavy and powerful, but sometimes by the time you’ve finished with it, you’ve cut so far in that you may have missed a simpler, lighter solution.

Ruby feels like the hand trimmers. Precision, less code, more intent, and I can take my time to think through and arrive at a solution without leaving a huge trail of trimmings (code) behind me.

Tags  | 4 comments

Three Years of JRuby on Rails

Posted by Nick Sieger Wed, 13 May 2009 21:21:37 GMT

Just yesterday the 3-year mark of JRuby running Rails passed by. In the intervening period since JRuby first started to run Rails, we’ve seen:

And yet, JRuby still has plenty of untapped potential and room for growth and adoption: in the existing Ruby and Rails communities where JRuby is showing promise as a stable, performant, concurrency-enabled, and leak-proof platform; and as a transformative force to capture the mindshare of a huge army of Java developers who aren’t even aware that there’s a language and runtime that allows them to preserve their skills and existing code while developing new applications faster and with much greater enjoyment.

Here’s looking to the future of continued growth for JRuby over the next three years. The best is yet to come!

Tags , ,  | 4 comments

My Article for Ruby Advent 2008

Posted by Nick Sieger Fri, 19 Dec 2008 05:04:00 GMT

I wrote an article for Ruby Advent 2008 about using JRuby, RMagick4J, Gruff, and JMX to create a simple JVM memory monitoring application. Go check it out and let me know what you think.

I’ve also posted the source for the article.

Happy Holidays!

rubyadvent

Tags , , , ,  | 1 comment

QCon: Interviewed by Fabio Akita

Posted by Nick Sieger Mon, 24 Nov 2008 18:51:00 GMT

Fabio Akita played the role of the Energizer Bunny, making a blur around the hallways at QCon. He managed to catch me on Thursday morning, and we had a great chat.

Fabio Bunny

Go check out our conversation on Akita On Rails to hear my take on JRuby and Rails 2.2 and more. Thanks for doing the interview Fabio!

Tags , , ,  | no comments

QCon Wrap-up: Enterprise, Have You Met Ruby?

Posted by Nick Sieger Sun, 23 Nov 2008 08:51:03 GMT

This year’s QCon San Francisco conference was my first time attending, and it was an eye-opener for me for several reasons.

First, the tutorial Ola and I gave on Monday went well, though I was mildly surprised to find that only about 10% of the attendees at our talk had any familiarity with Ruby. This turned out to work just fine as we were able to adjust and fill in a little bit of the back story on both Ruby and Rails. Still, to try to convey a sense of Ruby, Rails, and JRuby all in the span of a 2.5 hour session is a tall order!

Next, I was impressed with the diversity the conference organizers were able to achieve. There were tracks on agile development, cloud computing, REST, DSLs, design and clean code, Ruby, functional programming, real-world architectures, storage rethinking, and more. Tracks were relevant and topical even if the quality of talks was mixed.

The last item relates to my perception that Ruby is not yet seen as a worthwhile tool for enterprise software development. It leaves me with some cause for concern, though it reflects more on the state of the industry rather than on the way Ruby was presented at the conference itself.

What does it mean for Ruby to be “ready for the enterprise”? Does that imply JRuby? Running on the JVM or a Java application server, or even .NET? Reams of XML? Presence of buzzwords, such as JMS, Spring/Hibernate? Or ability to adapt to or leverage legacy code? All of these?

I would argue that Ruby already has everything it needs to be a successful enterprise software development platform, even without using JRuby. Ruby has a mature standard library, a large and ever-growing list of gems and extensions, and a vibrant community. Testing tooling, certainly seen more and more as a critical piece of software development, is also an area where Ruby excels (and brings a strong culture bias toward testing as well). Add JRuby to the mix and the ability to leverage existing infrastructure as well as code, and the picture gets even stronger. Best of all, Ruby the language is a malleable medium perfectly suited for gluing enterprise components together, creating DSLs on top of stable layers and remaining clean enough to be eminently readable and maintainable. Yet behind-the-firewall deployments appear to be elusive; if they do exist, they’re small, isolated apps that work so well, the community doesn’t hear about them. Judging from the low level of participation in Ruby-related talks at QCon, I’m inclined to believe the former.

I was speaking with Jay Fields about this topic on Friday. Jay also noticed that the the Ruby and DSL tracks were sparsely attended. (For that matter, so was the functional programming track.) His observation was that the track content was not marketed and tailored enough toward toward solving enterprise-class problems, or being approachable enough in that regard. We can certainly do better.

Do we have an issue here? Are we, the Ruby community, being too insular and not concerning ourselves enough with bringing Ruby-based solutions to the enterprise? Or perhaps businesses are waiting for more organizations that can provide services, support and indemnification? Does there need to be a Ruby, Inc. (or even a JRuby, Inc.) that looks at common enterprise problems and devises best-of-breed solutions (a sort of SpringSource for Ruby) for things like enterprise integration, security and identity, reporting, business workflow, decision support, etc. ad infinitum? Ruby should be able to do all of those while bringing the increased agility and productivity that we’ve all experienced.

I seem to have raised more questions than I am able to answer at this time. Of course, the obvious answer is that adoption of Ruby will just need more time, but I’m not willing to accept that as the only reason. I’d love to hear your opinions on contributing factors and what can be done to mitigate them. It seems like there’s a huge opportunity waiting to be tapped to help make Ruby more enterprise-worthy.

And yet, despite the less-than-stellar turnout for Ruby at QCon among conference attendees, I still had a great week, and would go back again. QCon is a fun and well-organized event overall, and I got the impression that the folks present were on the leading edge of “the enterprise”, which is exactly the people we need to engage to bring about growth in adoption of Ruby. For that reason, I hope we can kick it up a notch and take another shot at pimping Ruby at the next one. Maybe I’ll see you there!

Tags ,  | 12 comments

Older posts: 1 2 3 ... 5