langalex / culerity

Culerity integrates Cucumber and Celerity in order to test your application's full stack including Javascript. Your Rails app doesn't have to run in JRuby.
http://groups.google.com/group/culerity-dev
MIT License
259 stars 33 forks source link

.each not working on a links collection #24

Open cimm opened 14 years ago

cimm commented 14 years ago

In irb I try to loop over a list of all the links on the Google homepage:

server = Culerity::run_server
browser = Culerity::RemoteBrowserProxy.new server
browser.goto("http://www.google.com")
browser.links.each do |link|
   link.inspect
end

The each block throws the following error:

warning: multiple values for a block parameter (0 for 1)
    from /Users/john/.bundle/ruby/1.8/gems/culerity-0.2.10/lib/culerity/remote_object_proxy.rb:65
=> 28

It seems Culerity is forwarding the method in the remote_object_proxy where it fails for some reason.

Using Rails 3 beta 4.

cimm commented 14 years ago

I tried this in JRuby with Celerity and there it works so it really seems related to the remote proxy object.

ghost commented 13 years ago

I can totally verify this. It happens to any Celerity::ElementCollections object using one of Culerity's remote proxy calls that uses a block argument, such as 'each'. This means that despite the fact that Celerity::ElementCollections is Enumerable, none of the Enumerable methods which take blocks work (e.g., 'detect'). I speculate that the problem is in the 'block_to_string' method in RemoteObjectProxy.rb: def block_to_string &block result = block.call.to_s.strip unless result.is_a?(String) && result[/^lambda\s*({|do).+(}|end)/xm] result = "lambda { #{result} }" end result.gsub("\n", ";") end

The line "result = block.call.to_s.strip" is the problem, I speculate. For instance, in the case of the 'each' method in the example above, 'each' has yet to be sent via the send_remote method to Celerity, so it hasn't had a chance to return a link. And when block.call is executed it expects, in this case, a link object to be present and that object will have a .inspect method. However, at this point in the call chain, the link in the block is unbound, so an error occurs. In my experience, it usually says that object nil does not have a particular method name.

ghost commented 13 years ago

I have created a patch on my personal branch to show how this problem can be fixed.

https://github.com/chad-medi/culerity/commit/9e65312dd86e893ef86b90df39e4a2310f46a12a

The fix is pretty brutal, removing the possibility of explicitly passing a block to a remote call (of course, Ruby always allows you to pass blocks, but in this case, they are now ignored). The patch also transforms Culerity's RemoteObjectProxy to an Enumerable object, which means methods based on 'each' iteration now work. This solution is not ideal, since not all all objects returned by RemoteObjectProxy are collections that could be enumerated. A less 'hacky' patch would, I believe, require significant architectural changes to Culerity making it less of a proxy library.