Notes posted to Ruby

RSS feed
February 23, 2012
0 thanks

Be careful with path vs. endpoint

URI.join uses a delimiter – forward slash (/) – to decide if joined strings are a path or endpoint. In order to include strings as part of the path, they must end with a forward slash (/). Otherwise, they are assumed to be an endpoint and are overritten by your new “endpoint”.

Used this way, it (kind of) makes sense:

1.9.2p290 :021 > URI.join("http://localhost/test","main.json")
 => #<URI::HTTP:0x007fa68e81c270 URL:http://localhost/main.json> 

1.9.2p290 :022 > URI.join("http://localhost/test/","main.json")
 => #<URI::HTTP:0x007fa68e80e0d0 URL:http://localhost/test/main.json> 

It is especially confusing when you pass 3 strings and the 3rd (your endpoint) overwrites the 2nd (which you expected to be part of the path).

1.9.2p290 :023 > URI.join("http://localhost/", "test", "main.json")
 => #<URI::HTTP:0x007fa68cec0ba0 URL:http://localhost/main.json> 

1.9.2p290 :024 > URI.join("http://localhost/", "test/", "main.json")
 => #<URI::HTTP:0x007fa68ce14c60 URL:http://localhost/test/main.json> 

Now, consider that you are probably using a variable for the string value of ‘test’.

1.9.2p290 :025 > controller = 'test'
1.9.2p290 :026 > URI.join("http://localhost/", controller, "main.json")
 => #<URI::HTTP:0x007fa68cec0ba0 URL:http://localhost/main.json> 

Your `controller` is simply ignored. Or rather, your endpoint(?) was overwritten.

I’m not sure what versions of ruby this affects. As you can see I am using 1.9.2p290.

February 12, 2012 - (v1_8_6_287 - v1_9_2_180)
2 thanks

More Examples


class User < Struct.new(:name, :age, :gender) 

user = User.new("Matz", 43, "male")
January 11, 2012
0 thanks

Total Unique Elements: Set Union

For total unique elements, see set union: http://apidock.com/ruby/Array/|

January 4, 2012
0 thanks

Total Unique Elements from Two Arrays

Simple but thought it was worth mentioning:

( [ 1, 2, 3 ] + [ 3, 4, 5 ] ).uniq    #=> [ 1, 2, 3, 4, 5 ]
January 4, 2012 - (v1_9_2_180)
0 thanks


I use this in views when I need to join a array of objects from a sql request here is a basic version of what I mean.

Code example

<%= @blogs.map{ |blog| blog.comment }.join(“ | ”) %>

December 30, 2011
0 thanks

See also: sample

sample randomly picks 1 or n elements from the array

December 29, 2011
0 thanks

Use kill 0 to find out if process is running


#!/usr/bin/env ruby

pid = ARGV[0].to_i

  Process.kill(0, pid)
  puts "#{pid} is running"
rescue Errno::EPERM                     # changed uid
  puts "No permission to query #{pid}!";
rescue Errno::ESRCH
  puts "#{pid} is NOT running.";      # or zombied
  puts "Unable to determine status for #{pid} : #{$!}"

Thanks to http://stackoverflow.com/a/200568/51209

December 5, 2011
0 thanks

Not available

Actually, this method is not available now.(github.com/ruby/ruby/blob/trunk/rational.c#L2352)

November 16, 2011
1 thank

Change in clone for ActiveRecord objects in ruby-1.9.3

I noticed that cloning an active record object in ruby-1.9.3 and then changing an attribute on the original object will actually change the cloned object as well. This was not the case in ruby-1.9.2.

November 16, 2011
1 thank

Alternative definition

a.flat_map(&b) works exactly like a.map(&b).flatten!(1).

October 6, 2011
1 thank

Difference in the way returns are handled

Also, there is a difference in the way returns are handled from the Proc. A return from Proc.new returns from the enclosing method. Return in lambda-block acts like in regular method.

return example

def proc_return
  Proc.new { return "Proc.new"}.call
  return "proc_return method finished"

def lambda_return
  lambda { return "lambda" }.call
  return "lambda_return method finished"
puts proc_return
puts lambda_return
# => Proc.new
# => lambda_return method finished
October 4, 2011
1 thank

Unexpected rounding behavior

Both 2.5 and 1.5 are rounded to 2…

ree-1.8.7-2010.02 > sprintf("%.f", 0.5) 
=> "0" 
ree-1.8.7-2010.02 > sprintf("%.f", 1.5)
=> "2" 
ree-1.8.7-2010.02 > sprintf("%.f", 2.5)
=> "2" 
ree-1.8.7-2010.02 > sprintf("%.f", 3.5)
=> "4" 
ree-1.8.7-2010.02 > sprintf("%.f", 4.5)
=> "4" 

use round instead to get proper behavior

October 3, 2011 - (>= v1_9_1_378)
0 thanks

example will not work in 1.9+

Since 1.9 introduces native threads, we cannot assume the order of exectution and the example above is not thread safe and fails with a “deadlock detected (fatal)” error. Also Thread.pass is pointless in the context of native threads.

This will work as intended with native threads:

a = Thread.new { print "a"; Thread.stop; print "c" } 
sleep(0.1) until a.status == 'sleep'
print "b"
August 19, 2011
0 thanks

Alternative way to show relative paths from absolute globbing

An alternative to show relative paths is using the well known String#sub! method

base_dir = File.expand_path("my_dir") << "/" # don't miss adding "/"
files = Dir[File.join(base_dir, '**', '*.html.gz')]
p files.map {|f| f.sub!(base_dir,"")}
August 4, 2011
0 thanks

Tempfile extension


f = Tempfile.new(['graph','.json'])
July 30, 2011 - (>= v1_9_1_378)
0 thanks

now they are built-in

in ruby 1.9 and afterwards, the to_enum and enum_for(synonym for to_enum) methods are buil-in to the language. so there’s no need to require that any more.

July 15, 2011 - (v1_8_6_287 - v1_9_2_180)
1 thank

Dup vs Clone difference

As for me main difference between .dup and .clone , that first one doesn’t not freeze result object if initial object was frozen.

June 28, 2011 - (v1_9_2_180)
1 thank
June 13, 2011
0 thanks

Generalized Zip

My 5 cents.

I find trully useful this. Is a kind of generalized zip. You can combine 2 or more enumerables (arrays or others) of any size into a hash, array of arrays, .… The size of the result is the size of the bigest of the enumerables. For the shortests enumerables nil elements are used at the end.

# method compose
def compose(*enumerables)
  enumerables.map(&:size).max.times do
    for enumerable in enumerables
      tupla << enumerable.shift
    res << (block_given? ? yield(tupla) : tupla)

some examples:

en1= [1, 2, 3, 4]
en2= ['a', 'b', 'c', 'd', 'e']
en3= {:elem1 => "1", :elem2 => "2", :elem3 => "3"}

p compose en1.dup, en2.dup, en3.dup
p a1=compose(en2.dup, en1.dup) {|a,b| {a.to_sym => b}}

p a1.inject({}) {|ac,item| ac.merge item}
p a1.flatten

p a2=compose(en2.dup, en1.dup).flatten
p Hash[*a2]

p a3=compose(en2.dup, en3.dup).flatten

Their outputs are:

#[[1, "a", [:elem1, "1"]], [2, "b", [:elem2, "2"]], [3, "c", [:elem3, "3"]], [4, "d", nil], [nil, "e", nil]]
#[{:a=>1}, {:b=>2}, {:c=>3}, {:d=>4}, {:e=>nil}]
#{:b=>2, :d=>4, :e=>nil, :c=>3, :a=>1}
#[{:a=>1}, {:b=>2}, {:c=>3}, {:d=>4}, {:e=>nil}]
#["a", 1, "b", 2, "c", 3, "d", 4, "e", nil]
#{"a"=>1, "b"=>2, "c"=>3, "d"=>4, "e"=>nil}
#["a", :elem1, "1", "b", :elem2, "2", "c", :elem3, "3", "d", nil, "e", nil]
May 6, 2011
0 thanks

Using New

-rails new ProjectName -switch directories -git repo “git init”, then commit -add gems, bundle install -rails g scaffold TableName attribute:type attribute:type….. -authentication -add attribute_accessible/relationships/validations -get rid of index.html in public, set root “table#index” -rails g nifty:layout -rake db:migrate -git repo -rails s, see if works -change id’s to names in show and indexes -images go to public/images -partials are rendered in application.html.erb

April 28, 2011
1 thank

Backport from 1.9

Below is a backport of the Ruby 1.9 implementation (minus some encoding stuff). The main thing this provides you is the ability to say :foo => [‘bar’, ‘baz’] and have that turn into foo=bar&foo=baz (i.e. multiple values for the same key).

Just require into your project and use it like you are on 1.9.

module Net
  module HTTPHeader

    def set_form_data(params, sep = '&')
      query = URI.encode_www_form(params)
      query.gsub!(/&/, sep) if sep != '&'
      self.body = query
      self.content_type = 'application/x-www-form-urlencoded'
    alias form_data= set_form_data


module URI

  def self.encode_www_form(enum)
    enum.map do |k,v|
      if v.nil?
      elsif v.respond_to?(:to_ary)
        v.to_ary.map do |w|
          str = k.dup
          unless w.nil?
            str << '='
            str << w
        str = k.dup
        str << '='
        str << v

April 22, 2011
0 thanks

Remove non empty directories

To remove a non empty directory use FileUtils:

April 14, 2011
0 thanks


Chops the last character off a string.

> a = "12345"
> a.chop
=> "1234"
> a
=> "12345"
> a.chop!
=> "1234"
> a
=> "1234
April 4, 2011
2 thanks

Working with match captures

Let’s say you wanted to filter out passwords from:

s = "password=bob&password=jim&password=jane"

You’d do this:

r = /password\=([^\&]+)/
s.gsub!(r) { |m| m.gsub!($1, "[FILTERED]") }

Which would return

March 23, 2011
1 thank

Handling nested hashes and arrays

You can use this code to handle nested hashes and arrays. I’m not sure if it handles every case, and it could probably be refactored better, but it’s working quite well for us.

require 'active_support/core_ext/hash'

def normalize_params(params, key=nil)
  params = params.flatten_keys if params.is_a?(Hash)
  result = {}
  params.each do |k,v|
    case v
      when Hash
        result[k.to_s] = normalize_params(v)
      when Array
        v.each_with_index do |val,i|
          result["#{k.to_s}[#{i}]"] = val.to_s
        result[k.to_s] = v.to_s

# Adapted from http://snippets.dzone.com/posts/show/6776
class Hash
  def flatten_keys(newhash={}, keys=nil)
    self.each do |k, v|
      k = k.to_s
      keys2 = keys ? keys+"[#{k}]" : k
      if v.is_a?(Hash)
        v.flatten_keys(newhash, keys2)
        newhash[keys2] = v