Notes posted by mutru
RSS feed
Testing Net:HTTP connections
You can use this excellent library to stub Net:HTTP connections in your automatic tests:

Receiving data over UDP
It’s perfectly normal to receive ‘X’ strings with Ruby’s UDP sockets before the actual content.
Consider the following example:
require 'socket' PORT = 5500 socket = UDPSocket.new socket.bind('', PORT) for i in 1..10 IO.select([socket]) p socket.recvfrom_nonblock(4096) end
Now, sending data with netcat:
echo "Hello APIdock" | nc -vv -u 127.0.0.1 5500
The application would output:
["X", ["AF_INET", 61755, "localhost", "127.0.0.1"]] ["X", ["AF_INET", 61755, "localhost", "127.0.0.1"]] ["X", ["AF_INET", 61755, "localhost", "127.0.0.1"]] ["X", ["AF_INET", 61755, "localhost", "127.0.0.1"]] ["Hello APIdock\n", ["AF_INET", 61755, "localhost", "127.0.0.1"]]

Streaming XML with Builder
To generate larger XMLs, it’s a good idea to a) stream the XML and b) use Active Record batch finders.
Here’s one way of doing it:
def my_action @items = Enumerable::Enumerator.new( Item.some_named_scope, :find_each, :batch_size => 500) respond_to do |format| format.xml do render :text => lambda { |response, output| extend ApplicationHelper xml = Builder::XmlMarkup.new( :target => StreamingOutputWrapper.new(output), :indent => 2) eval(default_template.source, binding, default_template.path) } end end end
The Builder template does not need to be modified.


Test if one array includes the elements of another v2
Maybe a bit more readable way to write the previous snippet would’ve been
puts "yay" if [1, 2, 3].all? { |i| (1..9).include?(i) } # => "yay" puts "nope" if [1, 2, 3, 'A'].any? { |i| not (1..9).include?(i) } # => "nope"

Usage examples
Basic usage:
User.should_receive(:find).with(:all, anything).and_return("hello world")
Now:
User.find(:all, :conditions => "foo") #=> "hello world"
But you can also use blocks for more complex matching logic. For example:
User.should_receive(:find) { |*args| if args.size == 2 "received two arguments" else "something else" end }.at_least(:once)
Now:
User.find(:all, :conditions => "bar") #=> "received two arguments" User.find(5) #=> "something else"
Of course normally you’d return mocks instead of strings.

Multiline regexps
A shortcut for multiline regular expressions is
/First line.*Other line/m
(notice the trailing /m)
For example:
text = <<-END Hello world! This is a test. END text.match(/world.*test/m).nil? #=> false text.match(/world.*test/).nil? #=> true

Implemented in database adapters
These methods are not implemented in the abstract classes. Instead, all database adapters implement these separately, if the feature is supported.

Convert strings to Dates
Uses the undocumented Date._parse method. Some usage examples:
'06/15/2008'.to_date # => Sun, 15 Jun 2008 '20080615'.to_date # => Sun, 15 Jun 2008 '2008-06-15'.to_date # => Sun, 15 Jun 2008 'Sun, 15 Jun 2008'.to_date # => Sun, 15 Jun 2008

Using counters with collections
When you’re rendering a collection partial, the partial_name_counter variable contains the position of the current element in the collection. For example:
<%= render(:partial => 'example', :collection => %w(rails-doc is cool)) %>
Now in _example.html.erb:
<p>Element: <%= example %> (index: <%= example_counter %>)</p>
It would produce:
<p>Element: rails-doc (index: 1)</p> <p>Element: is (index: 2)</p> <p>Element: cool (index: 3)</p>
As you can see, indexing starts from 1.

around_filter code example
This is how it’s used:
around_filter do |controller, action| do_your(:stuff) do action.call end end

Rails 2.1 caching internals
Rails 2.1 caching features are pretty much undocumented. Rob Anderton has documented some internal stuff here:
http://www.thewebfellas.com/blog/2008/6/9/rails-2-1-now-with-better-integrated-caching

Using memcached as a session store
Because of Ruby’s CGI library limitations, store cannot have any configuration options. Basically this means that you cannot easily run memcached on a different port (or with any non-default settings for that matter).
You can bypass this limitation with this ugly hack (environment.rb):
cache_params = *([memcache_servers, memcache_options].flatten) CACHE = MemCache.new(*cache_params) ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS.merge!({ 'cache' => CACHE })
In your initializer block, just configure session_store normally:
config.session_store = :mem_cache_store
I think this should be fixed to work like cache_store= does.