Flowdock

Notes posted to Ruby

RSS feed
February 12, 2010
0 thanks

Example

Delete all files in log

require 'FileUtils'
FileUtils.rm_rf(Dir.glob("log/*"))
February 11, 2010 - (v1_8_6_287 - v1_8_7_72)
1 thank

Using Unshift with Load Path's

Using unshift on your load path’s for Rails, Sinatra, etc, is a good way of ensuring that the file your including is going to be first.

Example

vendor = File.join(File.dirname(__FILE__), 'vendor')
$LOAD_PATH.unshift File.expand_path(File.join(vendor, 'ultraviolet-0.10.5',  'lib'))
February 11, 2010 - (v1_8_7_72)
0 thanks

Odd Number of padding characters

In the case of an odd number of empty spaces in a length, Ruby will append the extra character to the right-hand side of the string.

Example:

irb(main):002:0> "Hello".center(10,"-")
=> "--Hello---"
February 11, 2010 - (v1_8_6_287 - v1_8_7_72)
0 thanks

Clarification of argument

The description should read:

The argument is the salt string, which must be at least two characters long, each character drawn from [a-zA-Z0-9./].

February 5, 2010
3 thanks

Rmoving preceding 0's

In most *nix system, adding a - after the % will remove preceding 0s.

So %-d for a single digit day, or %-I for a single digit hour, etc.

February 4, 2010
1 thank

Warning! Be aware of Active Record TimeZone

With the timezone support introduced in Rails 2.1 the idea is that all dates in the database are stored in UTC and all dates in Ruby are in a local timezone.

Time.zone.now == Time.now # => false

http://marklunds.com/articles/one/402

January 27, 2010
1 thank

File name without the extension

To get the file name without the extension you can use File.extname in combination with File.basename

File.basename("test.rb", File.extname("test.rb"))             #=> "test"
File.basename("a/b/d/test.rb", File.extname("a/b/d/test.rb")) #=> "test"
File.basename("test", File.extname("test"))                   #=> "test"
File.basename(".profile", File.extname(".profile"))           #=> ".profile"
January 27, 2010
3 thanks
January 25, 2010
2 thanks

custom uniq method

Build hash from elements of your Array using attribute as key and the element as value and return values of Hash:

Hash[*ary.map {|obj| [obj.name, obj]}.flatten].values
January 22, 2010
1 thank

Interesting usage for polymorphic asset model :)

…to automatically define default scopes of inherited classes.

 class Asset < ActiveRecord::Base

  belongs_to :resource, :polymorphic => true
  before_save :set_asset_type

  def set_asset_type
   self.asset_type = self.class.name
  end

  def self.inherited(subclass)
    super
    subclass.send(:default_scope, :conditions => "asset_type='#{subclass.name}'")
  end
end
January 19, 2010
2 thanks

Argument Accepted

Accepts a single argument record_separator which is the character or string to chomp.

Why isn’t this shown in the method def at the top?

January 19, 2010
2 thanks

Argument Accepted

Accepts a single argument sep_string

January 11, 2010
0 thanks

Includes all ancestors

May be helpful to know that this returns true if B is any ancestor of A, not just a direct one. As an example:

class Foo; end
class Bar < Foo; end
class Baz < Bar; end

Foo >= Bar #=> true
Foo >= Baz #=> true
January 11, 2010
0 thanks

Includes all ancestors

May be helpful to know that this returns true if B is any ancestor of A, not just a direct one. As an example:

class Foo; end
class Bar < Foo; end
class Baz < Bar; end

Foo > Bar #=> true
Foo > Baz #=> true
January 11, 2010
0 thanks

Includes descendants

May be helpful to know that this returns true if A is any descendant of B, not just a direct one. As an example:

class Foo; end
class Bar < Foo; end
class Baz < Bar; end

Bar <= Foo #=> true
Baz <= Foo #=> true
January 11, 2010
0 thanks

Includes descendants

May be helpful to know that this returns true if A is any descendant of B, not just a direct one. As an example:

class Foo; end
class Bar < Foo; end
class Baz < Bar; end

Bar < Foo #=> true
Baz < Foo #=> true

If you want direct descendance try Class#superclass:

Bar.superclass == Foo #=> true
Baz.superclass == Foo #=> false
December 31, 2009
2 thanks

Replacing with "\" and match — a simple solution

A somewhat different approach to the same problem:

v.gsub(/(?=\W)/, '\\') #=> Foo\ Bar\!

But from what you are trying to achieve I suspect you might be interested in Regexp.escape method :)

December 3, 2009
2 thanks

Replacing with "\" and match

If you’re trying to place a “" in front of your matches, you’ll quickly see that it is a pain in the ass to add the quoting in the replacement string.

Here’s an example:

v = "Foo Bar!"  # Target: Foo\ Bar\!
# Resulting strings will not be quoted to decrease
# the amount of backslashes. Compare \\! to "\\\\!"

v.gsub(/\W/, '\0') #=> Foo Bar!

# \\ escapes to a literal \, which next to the 0 becomes \0
v.gsub(/\W/, '\\0') #=> Foo Bar!

# \\\0, means "\ \0", or "escaped \0"
v.gsub(/\W/, '\\\0') #=> Foo\0Bar\0

# Same mechanism as before. \\ → \
v.gsub(/\W/, '\\\\0') #=> Foo\0Bar\0

# Finally! We have now an escaped \ before \0 and
# we get the results we want.
v.gsub(/\W/, '\\\\\0') #=> Foo\ Bar\!

# It's very tempting to just write it like this now, right?
v.gsub(/\W/) { |m| "\\#{m}" } #=> Foo\ Bar\!
# It might not be shorter, but anyone can understand it.

Surely, there must be an easier way to do this. I haven’t found it, though. Hopefully, this makes it easier for you to understand why it behaves the way it does. :-)

December 3, 2009 - (v1_8_6_287 - v1_8_7_72)
0 thanks

Testing Regular Expressions?

Writing regular expressions is never easy. You may use http://rubular.com to test and optimize your regular expressions.

November 23, 2009
3 thanks

Make directory if not exists

If the directory already exists, mkdir raises exception. To prevent this:

Dir.mkdir(dir) unless File.exists?(dir)
November 18, 2009 - (>= v1_8_6_287)
4 thanks

Example

code:

class Klass
  def set(string)
    var_name = "@#{string}"  # the '@' is required
    self.instance_variable_set(var_name, 'bar')
  end
  def puts_foo
    puts @foo
  end
end
k = Klass.new
k.puts_foo  # nil
k.set('foo')
k.puts_foo  # 'bar'
November 10, 2009
1 thank

lower case am/pm

With DateTime#strftime you can also use %P to get a lowercase am/pm. Not so with Time#strftime though!

November 9, 2009
0 thanks

overwrite

Replacing old value with new one

>> Module.const_set('MY_CONSTANT', 'value')
=> "value"
>> Module::MY_CONSTANT
=> "value"
>> Module.const_set('MY_CONSTANT', 'new value')
(irb):3: warning: already initialized constant MY_CONSTANT
=> "new value"
>> Module::MY_CONSTANT
=> "new value"

or

>> Kernel.const_set('MY_CONSTANT', 'value')
=> "value"
>> MY_CONSTANT
=> "value"
>> Kernel.const_set('MY_CONSTANT', 'new value')
(irb):3: warning: already initialized constant MY_CONSTANT
=> "new value"
>> MY_CONSTANT
=> "new value"
November 5, 2009
4 thanks

define_method with parameters

Just to be clear, you can do this:

define_method(:my_method) do |foo, bar| # or even |*args|
  # do something
end

This means same as:

def my_method(foo, bar)
  # do something
end

If you want to define method with parameters that have default values, you need to get a bit more creative and do something like this:

define_method(:my_method) do |foo, bar|
  bar ||= {}
  # do something
end
October 31, 2009
2 thanks

Don't forget to require 'tmpdir'

If you simply say Dir.tmpdir you might get a nice surprise:

irb> Dir.tmpdir
NoMethodError: undefined method `tmpdir' for Dir:Class

from (irb):1

Strangely, this method seems to be stored in a file that Ruby doesn’t require by default. Just require 'tmpdir' and all should be well.

irb> require 'tmpdir'
=> true
irb> Dir.tmpdir
=> "/var/folders/An/AnwlXPZFH2aRLCERERQDKE+++TI/-Tmp-"
October 30, 2009
2 thanks

Map-like Manipulation of Hash Values

Let’s say you want to multiply all values of the following hash by 2:

hash = { :a => 1, :b => 2, :c => 3 }

You can’t use map to do so:

hash.map {|k, v| v*2 }   # => [6, 2, 4]

However, with merge you can:

hash.merge(hash) {|k,v| v*2 }   => {:c=>6, :a=>2, :b=>4}

(The above is Ruby 1.8, in Ruby 1.9 the order is preserved.)

October 20, 2009
3 thanks

See Dir#glob

See glob for more usage information and comments.

October 20, 2009
2 thanks

Getting relative path from absolute globbing

Say you want to scan for files in directory base_dir and you want to use the relative path from this base dir, you could do it like this:

base_dir = '/path/to/dir'
files = Dir[File.join(base_dir, '**', '*.yml')]

# files now contain absolute paths:
files.first # => "/path/to/dir/foo/bar.yml"

# let's make them relative
base_pathname = Pathname.new(base_dir)
files = files.collect do |file|
  Pathname.new(file).relative_path_from(base_pathname)
end

files.first # => "foo/bar.yml"

Of course, a more common use-case could be the following:

def scan_for_documents!
  base_path = Pathname.new(self.base_path)
  self.contained_files = []
  Dir[File.join(self.base_path, '**', '*.pdf')].each do |full_path|
    path = Pathname.new(full_path).relative_path_from(base_path)
    self.contained_files << path
  end
end
October 19, 2009
1 thank

Get all inner texts

Extend REXML::Element so that it can get the first text and following inner texts (child texts included) of the current element as array and as string:

class REXML::Element

 def inner_texts
  REXML::XPath.match(self,'.//text()')
 end

 def inner_text
  REXML::XPath.match(self,'.//text()').join 
 end

end
October 18, 2009
1 thank

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"]]