» tagged pages
» logout
Ruby
Return to Ruby

Code Snippets: ruby

(or Cancel)

(Editing anonymously: to be credited for your changes, login or register a new account)

other page actions:

Tags Applied to this Topic

No one has tagged this page.

Wednesday, July 23, 2008

Generating YAML hashes sorted by key

I needed to store YAML structures in version control, so I wanted the YAML output of hashes to be sorted by the key name (this way, when using "diff" between two versions, you'll get a minimal changeset).

Of course a Hash object in Ruby doesn't have any ordering on its keys, which is fine. I just want to make sure that when I output the YAML serialization of a Hash object, it will serialize the keys in alphabetic order.

Put this code somewhere before you actually serialize your hashes:


require 'yaml'

class Hash
# Replacing the to_yaml function so it'll serialize hashes sorted (by their keys)
#
# Original function is in /usr/lib/ruby/1.8/yaml/rubytypes.rb
def to_yaml( opts = {} )
YAML::quick_emit( object_id, opts ) do |out|
out.map( taguri, to_yaml_style ) do |map|
sort.each do |k, v| #

Wednesday, July 23, 2008

Sharing has_many extensions

Sometimes you extend an ActiveRecord association this way:


has_many :things do
def active
find :all, :conditions => ['active = ?', true]
end
end


You can share the same extensions using a lambda:



extensions = lambda {
def active
find :all, :conditions => ['active = ?', true]
end
}

has_many :things, &extensions
has_many :more_things, &extensions


Thursday, July 17, 2008

messenger de linha de comando em ruby


#!/usr/bin/ruby

require "socket"

porta = 14143

server = UDPSocket.new
server.bind("208.97.177.80", porta)

t = Thread.new do
loop do
msg, sender = server.recvfrom(256)
host = sender[3]
puts “#{host} diz: #{msg}”
break unless msg.chomp != “falow..”
end
end

cliente = UDPSocket.open
cliente.connect(”201.58.157.200″, porta)
loop do
msg = gets
cliente.send(msg, 0)
break unless ! “kill, quit, bye!, falow..” . include? msg.chomp
end
cliente.close

Tuesday, July 15, 2008

Automatic Expiration of Rails Action Caching

Would love to get some feedback on this...

No doubt, 5 minutes after posting this, someone will tell me of the built-in Rails way of doing this, but alas I could not find it.

Usage looks like this:


class PeopleController caches_action :show, :for => 1.hour, :cache_path => Proc.new { |c| "people/#{c.params[:id]}_for_#{Person.logged_in.id}" }
end


The ":for => 1.hour" part is where the magic happens.

Basically, this bit of code adds a before_filter that checks the last modified time of the cache entry, and expires it if it is older than the specified time period.


module ActionController
module Caching
module Fragments
# expire a cache key only if the block returns true or
# if the age of the fragment is more than the specified age argument.
def expire_fragment_by_mtime(key, age=nil, &block)
block = Proc.new { |m| m if (m = cache_store.mtime(fragment_cache_key(key))) and block.call(m)
expire_fragment(key)
end
end
end
module Actions
module ClassMethods
# adds an option :for
# caches_action :show, :for => 2.hours, :cache_path => ...
# :cache_path is required, unfortunately
def caches_action_with_for(*actions)
original_actions = actions.clone
options = actions.extract_options!
if for_time = options.delete(:for)
cache_path = options[:cache_path]
before_filter do |controller|
cache_path = cache_path.call(controller) if cache_path.respond_to?(:call)
controller.expire_fragment_by_mtime(cache_path, for_time)
end
end
caches_action_without_for(*original_actions)
end
alias_method_chain :caches_action, :for
end
end
end
end

# Add a method to grab the last modified time of the cache key.
# If you use a store other than the FileStore, you'll need to add
# a method like this to your store.
module ActiveSupport
module Cache
class FileStore
def mtime(name)
File.mtime(real_file_path(name)) rescue nil
end
end
end
end

Monday, July 14, 2008

Rake task to set all S3 files public_read

// If you ever need to make sure all your Amazon S3 files are set to public_read, here's a rake task



namespace :s3 do
desc "Make all objects in S3 public_read"
task :make_public_readable do
require 'aws/s3'
# you might have this setup as env vars, doesn't work for me as i have more than one AWS account
AWS::S3::Base.establish_connection!(:access_key_id => '',:secret_access_key => '')

marker = ""

loop do
objects = AWS::S3::Bucket.objects('your_bucket', :marker=>marker, :max_keys=>100)
puts "found #{objects.size} objects"

break if objects.size == 0

marker = objects.last.key
puts "new marker is \"#{marker}\""

public_grant = AWS::S3::ACL::Grant.grant :public_read

objects.each do |o|
if not o.acl.grants.include? public_grant
puts "\"#{o.key}\" does not include public_read"
o.acl.grants o.acl(o.acl)
end
end
end
end

end

Sunday, July 13, 2008

Permutations of letters in a word

I've been programming for a while but for some reason figuring this out was really hard - it took me 2 and a half hours. Unsurprisingly, the solution is extremely simple...


#!/usr/bin/ruby
# permute - takes a word and returns all the permutations of the letters in the word

def permute(word="")
permutations_among(word.split(//))
end
def permutations_among(letters)
permutations = []
if letters.size == 1
permutations else
letters.each_with_index do |letter, i|
surrounding_letters = letters.dup; surrounding_letters.delete_at(i)
permutations += permutations_among(surrounding_letters).map {|permutation| letter + permutation }
end
end
permutations
end

permute(ARGV.shift).each {|permutation| puts permutation }


Some benchmarks against other implementations:

* Array#permutations: http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/32844
* Array#perm: http://blade.nagaokaut.ac.jp/~sinara/ruby/math/combinatorics/array-perm.rb
* geta: http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/139290
* String#perm (based on geta)
* Array#each_permutation: http://knanshon.blogspot.com/2006/08/ruby-permutations.html
* permutation: http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/140345


user system total real
permutations_among: 1.680000 0.010000 1.690000 ( 1.700779)
Array#permutations: 1.740000 0.010000 1.750000 ( 1.798288)
geta: 2.430000 0.010000 2.440000 ( 2.506668)
String#perm: 2.260000 0.010000 2.270000 ( 2.280652)
Array#each_permutation: 0.820000 0.000000 0.820000 ( 0.827463)
permutation: 2.140000 0.010000 2.150000 ( 2.171966)


Benchmark code:


require 'benchmark'

N = 1_000
Benchmark.bm(40) do |x|
letters = %w(a b c d e)
string = "abcde"
x.report("permutations_among:") do
N.times { permutations_among(letters) }
end
x.report('Array#permutations:') do
N.times { letters.permutations }
end
x.report('geta:') do
N.times { geta(string) }
end
x.report('String#perm:') do
N.times { string.perm }
end
x.report('Array#each_permutation:') do
N.times { letters.each_permutation {|perm| } }
end
x.report('permutation:') do
N.times { 0.upto(string.length.factorial-1) {|i| permutation(string, i)} }
end
end


So, not bad for a first try ;)

Sunday, July 13, 2008

Detecting bluetooth devices with hcitool scan

A trivial Ruby script to store the bluetooth devices found with the shell command 'hcitool scan'.


#!/usr/bin/ruby

#file: bt_scan.rb

require 'rexml/document'
include REXML

while true
filein = File.new('bt_found.xml','r')
doc = Document.new(filein)
filein.close

fileout = File.new('bt_found.xml','w')

result = `hcitool scan`
found = result.split(/\n/) # retrieve each found device
found.delete_at(0) # remove the item containing 'scanning ...'

found.each do |b|
node_found = Element.new('found')
p = b.split(/\t/) # retrieve device details
id = p[1]
name = p[2]
puts "name #{name} --- id #{id}"
node_id = Element.new('id')
node_name = Element.new('name')
node_date = Element.new('date')

node_id.text = id
node_name.text = name
node_date.text = Time.now

node_found node_found node_found doc.root end


fileout.puts doc
fileout.close
puts 'sleeping'
sleep 10 # during this time we can kill the script,
# otherwise we risk losing the contents of the xml file.
puts 'awake'
end


Note: Shell commands don't really have much to do with Ruby, however if there is no easy to use bluetooth libraries then I will of course use what's available.

Sunday, July 13, 2008

Array#replace_pattern

# If you are treating Arrays like s-expressions, you might want to replace a particular pattern.


Array.class_eval do
def replace_pattern(pattern, value)
copy = self.dup
(0..copy.length).each do |i|
if copy[i] == pattern
copy[i] = value
elsif copy[i].is_a? Array
copy[i] = copy[i].replace_pattern(pattern, value)
end
end
copy
end
end

Friday, July 11, 2008

Build your own Twitter 'track' feature

This script retrieves the latest tweet for the keyword 'Ruby' and then sends you the IM. This is similar to the twitterbot command 'track ruby'.


#!/usr/bin/ruby

#file: tweet-tracker.rb

require 'open-uri'
require 'rexml/document'
include REXML

keyword = 'ruby'

summize_url = 'http://summize.com/search.atom?q=' + keyword
puts 'getting the latest tweet ...'

buffer = open(summize_url,
'User-Agent' => 'RTweet-Tracker').read

doc = Document.new(buffer)
title = doc.root.elements['//entry/title'].text.to_s
user = doc.root.elements['//entry/author/name'].text.to_s
url = 'http://192.168.1.104:9090/jeeves?msg=' + URI.escape(user + ': ' + title)

buffer = open(url,
'User-Agent' => 'RTweet-Tracker').read


You need to create your own IM web server [dzone.com] for this script to work.

sample output:
[13:21:16] jeeves: askegg (askegg): Wishes he knew enough ruby to fix things

Thursday, July 10, 2008

Monitor disk usage with a simple Ruby script


dev = 'sda1'
report = `df -h`
disk_remaining = report[/sda\w+\s+\d+?.?\dG\s+\d+?.?\dG\s+(\d+.?\d+?G)/,1]
puts "running low on disk space (#{dev}: #{disk_remaining })" if disk_remaining.to_i

Wednesday, July 09, 2008

Set Gajim's away message to your last tweet

This Ruby code fetches the latest tweet from the Twitter RSS feed and then uses it to update the autoaway message in Gajim.


#!/usr/bin/ruby
# file: RGajim-updater.rb

require 'open-uri'
require 'rexml/document'
include REXML


class GajimUpdater

attr_accessor :url, :user

def initialize_doc()
@user = 'jrobertson'
@url = 'http://twitter.com/statuses/user_timeline/763224.rss'
end

def write_config(msg)
filepath = '/home/james/.gajim/'
filein = File.new(filepath + 'config','r')
buffer = filein.read
filein.close

am = 'autoaway_message = '
new_buffer = buffer.gsub(/#{am}.*/,am + msg)

fileout = File.new(filepath + 'config','w')
fileout.puts new_buffer
fileout.close
puts 'config file updated!'
end

def get_latest_msg()

puts 'getting the latest tweet ...'
buffer = open(@url,
'User-Agent' => 'RGajim-updater').read

doc = Document.new(buffer)
doc.root.elements['//item/title'].text.to_s[/[^#{@user} :].*/]
end
end

if __FILE__ == $0 then

g = GajimUpdater.new()
g.url = 'http://twitter.com/statuses/user_timeline/763224.rss'
g.user = 'jrobertson'
title = g.get_latest_msg()
g.write_config(title)

end

Wednesday, July 09, 2008

Play audio with a Ruby shell script

Play an ogg file from the command-line using the program ogg123 from the software package 'vorbis-tools'.


#!/usr/bin/ruby

#file: ogg-play.rb

`ogg123 #{ARGV[0]} > /dev/null 2>&1`



e.g.

wget http://upload.wikimedia.org/wikipedia/en/4/4d/Elo_blue_sky.ogg
./ogg-play.rb Elo_blue_sky.ogg

Wednesday, July 09, 2008

A Ruby script for MPD

Install MPD along with phpMp and control your music media centre from a Ruby script.


#!/usr/bin/ruby
#file: mp_control.rb

require 'open-uri'
cmd = ARGV[0]
open("http://192.168.1.107/phpMp/playlist.php?hide=1&command=#{cmd}", 'User-Agent' => 'Ruby-MPClient').read



Example: mp_control.rb play

Tuesday, July 08, 2008

Post a message to identi.ca using XMPP via HTTP

This Ruby code posts a message to identi.ca using XMPP which uses a simple web server.


#!/usr/bin/ruby

require 'rubygems'
require 'socket'
require 'open-uri'
require 'xmpp4r-simple'

server = TCPServer.new('127.0.0.1', 9090)
messenger = Jabber::Simple.new('my-bot@gmail.com', "bot-password")

while (session = server.accept)
request = session.gets
project = request[/(\w+)\?msg=(.*) HTTP\/1.1/,1]
msg = URI.unescape($2)

puts request
session.print "HTTP/1.1 200/OK\rContent-type: text/html\r\n\r\n"
session.print "Response from Jeeves\r\n"
session.print ""

if project != '' and msg != '' then
case project
when 'identica'
messenger.deliver("update@identi.ca", msg)
else
puts "Project #{project} wasn't found on this server"
end
end
session.print URI.unescape(request)

session.print ""
session.close
end


To post the message you would type your message within the browser URL e.g. http://127.0.0.1:9090/identica?msg=just%20testing%20xmpp4r-simple%20from%20tcpserver1

Tuesday, July 08, 2008

Acronym Builder

// Generates an acronym from a string. For example "Hello World Ruby SCrIpT" goes to "HWRS".


acronym = ''
bytes = [] # Byte array
long_string = ' ' + long_string # so the first letter, if capital, is included
long_string.each_byte {|byte| bytes.push(byte)} # Build array of bytes
bytes.each_with_index do |byte, index|
if byte > 64 and byte # Capital letter
if bytes[index-1] == 32 # We check behind to see if the letter is preceded by a space. Again, encoding may vary. 32 is ASCII space.
acronym = acronym + long_string[index,1]
end
end
end

Monday, July 07, 2008

Configuring Apache for Ruby CGI

When using Apache on Ubuntu add the following configuration to the httpd.conf file within the file directory /etc/apache2.


ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/


AllowOverride None
Options +ExecCGI +Indexes
Order allow,deny
Allow from all




Note: Don't forget to make the script file executable.

Sunday, July 06, 2008

Using Ruby for IMAP with Gmail

This uses the code from CodeClimber: using Ruby for IMAP with Gmail [blogspot.com] and net/imap: Ruby Standard Library Documentation [ruby-doc.org]


require 'net/imap'

username = 'your gmail address'
password = 'gmail password'

imap = Net::IMAP.new('imap.gmail.com','993',true)
imap.login(username, password)
imap.select('INBOX')
imap.search(["NOT", "DELETED"]).each do |message_id|
envelope = imap.fetch(message_id, "ENVELOPE")[0].attr["ENVELOPE"]
puts "#{envelope.from[0].name}: \t#{envelope.subject}"
end
imap.logout()
imap.disconnect()

output:

James Robertson: Just a test!

Wednesday, July 02, 2008

Determine Week Days in a Month

Find out how many week days are in any given month.
Uses the call Date.new(year, month, -1).day to determine how many days there are exactly in that month.


def self.days_in_month(year, month)
Date.new(year, month, -1).day
end

def self.week_days_in_month(year, month)
(1..days_in_month(year, month)).select { |e|
(1..5).include?((Date.new(year, month, e).wday))
}
end

Wednesday, July 02, 2008

nslookup.rb

Does a web-based DNS lookup. Useful for those of us behind corporate firewalls that block fun sites based on DNS queries, i.e. OpenDNS.


#!/usr/bin/env ruby

LOOKUP_URL = 'http://toolbar.netcraft.com/site_report?url=%s'
MATCH_RE = /IP address([\d\.]+)/
HOSTS_FILE_PATH = '/etc/hosts'

require 'open-uri'

host = ARGV.select { |arg| arg !~ /^\-/ }.first
update_hosts_file = ARGV.select { |arg| arg == '--hosts' }.any?

if open(LOOKUP_URL % host).read =~ MATCH_RE
ip = $1
puts ip
if update_hosts_file
File.open(HOSTS_FILE_PATH, 'a') do |file|
file.write("\n#{ip} #{host}")
end
end
else
puts 'There was an error looking up this host.'
end


Usage:


./nslookup.rb youtube.com


To add the entry to your hosts file:


sudo ./nslookup.rb youtube.com --hosts

Monday, June 30, 2008

A user friendly elapsed time with Ruby

This Ruby code outputs a user friendly elapsed time or a historical date if the event was more than 24 hours ago.

def didwhen(old_time)

val = Time.now - old_time
#puts val
if val result = 'just a moment ago'
elsif val result = 'less than ' + (val * 1.5).to_i.to_s.slice(0,1) + '0 seconds ago'
elsif val result = 'less than a minute ago'
elsif val result = "1 minute ago"
elsif val result = "#{(val / 60).to_i} minutes ago"
elsif val result = 'about 1 hour ago'
elsif val result = "about #{(val / 60 / 60 * 1.02).to_i} hours ago"
else
result = old_time.strftime("%H:%M %p %B %d, %Y")

end
result
end


Inspired by Twitter.
Page 1 | Next >>
Username:
Password:
(or Cancel)