Stuff about software development, agile and testing

Showing posts with label ruby. Show all posts
Showing posts with label ruby. Show all posts

Thursday, January 7, 2010

Ruby inject in Scala

Do you have your favorite line in Ruby. Mine will be

(1..100).inject(&:+)

and I first saw that in Reg Braithwaite blog (very good read)

So what's going on here? Here is the explanation from Reg Braithwaite's blog


Explanation: (1..100) creates a Range. For our purposes, this is equivalent to a collection of the whole numbers from one to one hundred, inclusive (The major way in which it differs from an array for us is that it doesn’t actually require one hundred spots in memory. Ranges are also useful for matching.) The #inject method is called fold or reduce in other languages. Expressed like this, it applies the “+” function to the elements of our range, giving us the sum. Primary school students could tell you an easier way to obtain the sum, of course, but we will ignore that for now.

Ruby doesn’t actually have a function called +. What actually happens is that #inject wants a block. The & operator converts Proc objects into blocks and block into Proc objects. In this case, it tries to convert the symbol :+ into a block. The conversion uses Ruby’s built-in coercion mechanism. That mechanism checks to see whether we have a Proc object. If not, it sends the #to_proc method to the argument to make a Proc. If the Symbol :+ has a #to_proc method, it will be called. In Ruby 1.9 it has a #to_proc method. That method returns a Proc that takes its first argument and sends the + method to it along with any other arguments that may be present.



Well even though there are plenty different way you could add entries in collection, this line of code demonstrates the power of the language and what you could do with it.

Being Scala is my favorite programming language right now I wanted to implement something very similar in it. By default in Scala if you want some apply some binary operator to a range you could do

(1 until 100).reduceLeft { _ + _} and if you want your range to be inclusive then

(1 until 100).inclusive.reduceLeft { _ + _}

But still it is little bit verbose. So with some implicit trick I was able to come quite a bit close to the actual Ruby line above

1 ⟞ 10 inject '+

'⟞' is a unicode character and yes you could define method names with unicode characters. '+ is symbol is Scala. And here is rest of the implementation...

implicit def rich_range(r: Range) = new {
def inject(s:Symbol) = {
s match {
case '+ => r.reduceLeft { _ + _ }
case _ => //not supported yet
}
}
}

implicit def rich_int(start: Int) = new { def ⟞(end:Int) = (start until end).inclusive }




Well again point is not about using binary operator on a collection or range. Its about powerful and expressiveness of a programming language.

Monday, January 12, 2009

Testing File upload with Watir

For uploading file from watir test we have to do something like following

@browser.file_field(:name, "fileUploadFieldName").set "path.to.file"

But when I was running my test(on windows) I was getting the following error

Watir::Exception::WatirException, "The AutoIt dll must be correctly registered for this feature to work properly"

Apparently what this means is you have to install AutoIt and once you do that everything works as you expected. I kind of discovered it in a hard way but maybe some else will find this little information useful.





Thursday, November 29, 2007

jruby closure decompiled

Its quite interesting to look into the compiled class file generated by JRuby. Following is the sample java code generated for a closure (1.times { puts 'in closure' }) .

private static ByteList __18 = ByteList.create("in closure");
.....
.....
public IRubyObject closure0(ThreadContext threadcontext, IRubyObject irubyobject, IRubyObject airubyobject[])
{
Ruby ruby;
IRubyObject irubyobject1 = (ruby = threadcontext.getRuntime()).getNil();
DynamicScope dynamicscope = threadcontext.getCurrentScope();
IRubyObject _tmp = irubyobject1;
do
{
try
{
threadcontext.setPosition(__15);
return _17.call(threadcontext, irubyobject, RuntimeHelpers.constructObjectArray(ruby.newStringShared(__18)));
}
catch(org.jruby.exceptions.JumpException.RedoJump _ex) { }
} while(true);
}

RedoJump exception is used to simulate ruby redo

Tuesday, November 27, 2007

inpsect gem file

Playing around with RubyGems source code. So first thing I wanted to know is the gemspec.

Here is a small script to inspect any gem file

require 'yaml'
require 'rubygems/source_info_cache'

Gem::SourceInfoCache.cache
spec = Gem::SourceInfoCache.search('#{gem}')
p spec.to_yaml

You could also use Gem::SourceIndex to spec out locally installed gems

Sunday, August 26, 2007

Five different ways to test equality

It's bit confusing when it comes to test equality of objects in Ruby. It has five different ways to do it and each one has a different purpose and context in which it should be used.

equal? returns true if receiver and the parameter object have same object_id. Object ids are unique and its not shared among the objects. This method should not be overridden

== returns true if the receiver and parameter object has same values. This is most intuitive and should be overridden in your sub-classes

eq? Like == it compares objects but is more strict about type. Only reason this exists is to compare Hash keys

=== This is used for Switch Case statement. It compares target in case statement with each selectors. You can override it to control the way case statements are matched inside the switch block

=~ Pattern matching (Side note: In Erlang = does the pattern matching)

== and =~ does have a negated version and since ruby is a great language if you implement == you != for free, isn't that great.

Next time when you have to equate objects you know which one to use

Friday, July 20, 2007

eval vs define_method

There are many ways you could dynamically define methods and eval should be your last option. I really don't care how many variations of eval ruby provides but don't use it. Writing code inside string cannot help anyone not even you.
Please remember "with more power comes more responsibility".
define_method is much cleaner way of defining methods in meta world and gives much more readability.

Labels