Ruby Snippets
A small collection of handy one-liners and useful snippets that I've written or collected for Ruby & Ruby on Rails.
Sum & Product of an Array
How to sum all the numbers in an array, or get the multiplication product of the same numbers, without resorting to an ugly for loop? Ruby's inject to the rescue; this snippet extends the array class with the methods sum and product, which can hereafter be used on any array in Ruby. Note that the parameter to inject is the initial value of s, the result, and thus obviously different depending on whether we're doing addition or multiplication.
class Array def sum; inject(0) { |s, v| s += v }; end def product; inject(1) { |s, v| s *= v }; end end [1, 1, 2, 3, 5, 8].sum => 20 [1, 1, 2, 3, 5, 8].product => 240
Generate Random Password
Generates a secure, entirely random password of the specified length (by default, 16 characters long). Note that the generated password doesn't include similar characters (e.g. i, l, o, 1, 0, I), facilitating reading it back correctly when written down on paper. This is a straightforward translation of my PHP version -- I'll need to rewrite it in a more Rubyesque style at some point.
def generate_passwd(length=16) chars = 'abcdefghjkmnpqrstuvwxyzABCDEFGHJKLMNOPQRSTUVWXYZ23456789' password = '' length.downto(1) { |i| password << chars[rand(chars.length - 1)] } password end generate_passwd() => "3HGkQcOdrH2kTBAn" generate_passwd() => "H7PpTEUeEwfuyAGH"
Useful Regular Expressions
This still needs some polishing, but useful nonetheless. The original version of these regexes came from RubyGarden.
class String NUM = /[-+]?(\d+\.)?\d+([eE][-+]?\d+)?/ DEC = /[-+]?(0d\d([\d_]*\d)?)|([1-9]([\d_]*\d)?)|0/ BIN = /[-+]?[01]([01_]*[01])?/ OCT = /[-+]?0([0-7_]*[0-7])?/ HEX = /[-+]?0x[\da-fA-F]([\da-fA-F_]*[\da-fA-F])?/ def number?; (self =~ NUM) != nil; end def decimal?; (self =~ DEC) != nil; end def binary?; (self =~ BIN) != nil; end def octal?; (self =~ OCT) != nil; end def hex?; (self =~ HEX) != nil; end end
Simple RSS Parsing
A simple method I've used to return the latest n items from a specified RSS feed, using only the libraries built into Ruby.
def fetch_rss_items(url, max_items = nil) %w{open-uri rss/0.9 rss/1.0 rss/2.0 rss/parser}.each do |lib| require(lib) end rss = RSS::Parser.parse(open(url).read) rss.items[0...(max_items ? max_items : rss.items.length)] end items = fetch_rss_items('http://www.digg.com/rss/index.xml', 5) items.collect { |item| item.title } => ["Understanding AJAX - A Beginner's Guide", "Anti-cancer Compound In Beer", ...]
Determine Image Size
Credits to Sam Stephenson for this handy one-liner, which can be used to quickly determine the width and height of a PNG image file:
def get_png_size(filename) IO.read(filename)[0x10..0x18].unpack('NN') end get_png_size('image.png') => [640, 480]
Factorial Numbers
This snippet extends the integer type, giving all integers the ability to factorial themselves. Note that I've included both recursive and iterative versions: while the recursive method is arguably cleaner, for larger factorials you might run into a SystemStackError: stack level too deep error in Ruby; in that case, you'll want to use the iterative version.
class Integer def factorial_recursive self <= 1 ? 1 : self * (self - 1).factorial end def factorial_iterative f = 1; for i in 1..self; f *= i; end; f end alias :factorial, :factorial_recursive end (0..9).collect { |n| n.factorial } => [1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880]
Ordinals for All Numeric Types
This snippet will extend all numerical types with a method for returning the English ordinal, i.e. 1st, 2nd, 3rd, 4th, etc. Note that floating-point types will suffer an implicit integer coercion without rounding. The method is based on this page, where you can find similar code in short-hand style as well (not that rewriting the following in ternary logic should prove an unsurmountable problem for anyone).
class Numeric def ordinal cardinal = self.to_i.abs if (10...20).include?(cardinal) then cardinal.to_s << 'th' else cardinal.to_s << %w{th st nd rd th th th th th th}[cardinal % 10] end end end [1, 22, 123, 10, -3.1415].collect { |i| i.ordinal } => ["1st", "22nd", "123rd", "10th", "3rd"]
