Never been to DZone Snippets before?

Snippets is a public source code repository. Easily build up your personal collection of code snippets, categorize them with tags / keywords, and share them with the world

About this user

Sharon Rosner http://hiperu.blogspot.com

« Newer Snippets
Older Snippets »
Showing 1-10 of 10 total  RSS 

Ruby password strength calculator

This method returns the password lifetime in years. Based on this:
http://www.codeandcoffee.com/2007/06/27/how-to-make-a-password-strength-meter-like-google

class String
  PASSWORD_SETS = {
    /[a-z]/ => 26,
    /[A-Z]/ => 26,
    /[0-9]/ => 10,
    /[^\w]/ => 32
  }
  
  def password_strength
    set_size = 0
    PASSWORD_SETS.each_pair {|k,v| set_size += v if self =~ k}
    
    combinations = set_size ** length
    
    # assuming 1000 tries per second
    days = combinations.to_f / 1000 / 86400
    
    days / 365
  end
end

Better than methodphitamine?

Original discussion here: http://jicksta.com/articles/2007/08/04/the-methodphitamine

I think this one is prettier (but maybe not as sophisticated):

module Enumerable
  def method_missing(sym, *args)
    if (sym.to_s =~ /^(.+)_with$/) && (msg = args.shift)
      send($1.to_sym) do |x|
        x.send(msg, *args)
      end
    end
  end
end

[1, 2, 3].map_with :to_s

Check for primality with a regexp

Original perl code here:

http://montreal.pm.org/tech/neil_kandalgaonkar.shtml

class Fixnum
  def prime?
    ('1' * self) !~ /^1?$|^(11+?)\1+$/
  end
end

Ruby Thread Pool

This is useful for a variety of scenarios. You create a thread pool, give it a maximum size, and pass a block to it everytime you need something processed. If all threads are busy, you block until a thread becomes free.

For example:

pool = ThreadPool.new(10) # up to 10 threads
email_addresses.each do |addr|
  pool.process {send_mail_to addr}
end


require 'thread'

class ThreadPool
  class Worker
    def initialize
      @mutex = Mutex.new
      @thread = Thread.new do
        while true
          sleep 0.001
          block = get_block
          if block
            block.call
            reset_block
          end
        end
      end
    end
    
    def get_block
      @mutex.synchronize {@block}
    end
    
    def set_block(block)
      @mutex.synchronize do
        raise RuntimeError, "Thread already busy." if @block
        @block = block
      end
    end
    
    def reset_block
      @mutex.synchronize {@block = nil}
    end
    
    def busy?
      @mutex.synchronize {!@block.nil?}
    end
  end
  
  attr_accessor :max_size
  attr_reader :workers

  def initialize(max_size = 10)
    @max_size = max_size
    @workers = []
    @mutex = Mutex.new
  end
  
  def size
    @mutex.synchronize {@workers.size}
  end
  
  def busy?
    @mutex.synchronize {@workers.any? {|w| w.busy?}}
  end
  
  def join
    sleep 0.01 while busy?
  end
  
  def process(&block)
    wait_for_worker.set_block(block)
  end
  
  def wait_for_worker
    while true
      worker = find_available_worker
      return worker if worker
      sleep 0.01
    end
  end
  
  def find_available_worker
    @mutex.synchronize {free_worker || create_worker}
  end
  
  def free_worker
    @workers.each {|w| return w unless w.busy?}; nil
  end
  
  def create_worker
    return nil if @workers.size >= @max_size
    worker = Worker.new
    @workers << worker
    worker
  end
end

foldr and foldl in Ruby

module Enumerable
  def foldr(o, m = nil)
    reverse.inject(m) {|m, i| m ? i.send(o, m) : i}
  end

  def foldl(o, m = nil)
    inject(m) {|m, i| m ? m.send(o, i) : i}
  end
end

[1, 2, 3, 4, 5].foldl(:+) #=> 15
[1, 2, 3, 4, 5].foldl(:*) #=> 120

[1, 2, 3, 4, 5].foldr(:-, 0) #=> 3
[1, 2, 3, 4, 5].foldl(:-, 0) #=> -15


A Fast Ruby XML Builder

Here's something I wrote this evening. It's a simple and fast XML builder. Some benchmark I ran show it to be about 4 times faster than <a>Builder. Usage example:

items = ['abc', 'def', 'ghi']
xml = XML.new do
  instruct!
  reality(:time => Time.now) do
  event do
    type 1
    path "/sharon"
    value "abcdefg"
  end
  list.each {|i| item i}
end
puts xml.to_s


The XML class:

class XML
  # blank slate
  instance_methods.each { |m| undef_method m unless (m =~ /^__|instance_eval$/)}
  
  # Each item in @doc is an array containing three values: type, value, attributes
  
  def initialize(&block)
    @doc = []
    instance_eval(&block)
  end
  
  def method_missing(tag, *args, &block)
    value = block ? nil : args.pop
    attributes = args.pop
    @__to_s = nil # invalidate to_s cache
    if value
      @doc << [:open, tag, attributes] << [:value, value] << [:close, tag]
    else
      @doc << [:open, tag, attributes]
      instance_eval(&block)
      @doc << [:close, tag]
    end
  end
  
  def instruct!(atts = nil)
    @doc << [:instruct, atts || {:version => "1.0", :encoding => "UTF-8"}]
  end

  def to_s
    @__to_s ||= @doc.map{|i| _fmt_part i}.join
  end
  
  alias_method :inspect, :to_s
  
  def _fmt_part(part)
    case part[0]
    when :instruct
      "<?xml #{_fmt_atts(part[1])}?>"
    when :open
      part[2] ? "<#{part[1]} #{_fmt_atts(part[2])}>" :
        "<#{part[1]}>"
    when :close
      "</#{part[1]}>"
    when :value
      part[1].to_s
    end
  end

  def _fmt_atts(atts)
    atts.inject([]) {|m, i| m << "#{i[0]}=#{i[1].to_s.inspect}"}.join(' ')
  end
end

A replacement for Ruby's File.join

File.join is ugly, there I've said it. So how about being able to replace this:

require File.join(LOAD_PATH, 'foobar')


With this:

require LOAD_PATH/:foobar


Trivial, really:

class String
  def /(o)
    File.join(self, o.to_s)
  end
end

Full information for Ruby errors

Sometimes I want to be able to print out everything about an error: it's class, message and the stack trace. So how about this:

Update: followed suggestion by onarap and changed the line breaks to $/. No syntax highlighting because the code breaks the snippet parser.


class StandardError
def info
"#{self.class}: #{message}#$/#{backtrace.join($/)}"
end
end

High-performance Ruby: faster Symbol.to_s

Here's something that I found useful for shaving a few microseconds off. The performance gain ranges between 10% and 35%! YMMV.

Note: updated with suggestion by trans.

class Symbol
  def to_s
    @str_rep || (@str_rep = id2name.freeze)
  end
end

Ruby Daemon Module

The following code lets you implement a daemon very easily, and also lets you write cleanup code.

Update: I made some small changes to make it look slightly better.

require 'fileutils'

module Daemon
  WorkingDirectory = File.expand_path(File.dirname(__FILE__))  

  class Base
    def self.pid_fn
      File.join(WorkingDirectory, "#{name}.pid")
    end
    
    def self.daemonize
      Controller.daemonize(self)
    end
  end
  
  module PidFile
    def self.store(daemon, pid)
      File.open(daemon.pid_fn, 'w') {|f| f << pid}
    end
    
    def self.recall(daemon)
      IO.read(daemon.pid_fn).to_i rescue nil
    end
  end
  
  module Controller
    def self.daemonize(daemon)
      case !ARGV.empty? && ARGV[0]
      when 'start'
        start(daemon)
      when 'stop'
        stop(daemon)
      when 'restart'
        stop(daemon)
        start(daemon)
      else
        puts "Invalid command. Please specify start, stop or restart."
        exit
      end
    end
    
    def self.start(daemon)
      fork do
        Process.setsid
        exit if fork
        PidFile.store(daemon, Process.pid)
        Dir.chdir WorkingDirectory
        File.umask 0000
        STDIN.reopen "/dev/null"
        STDOUT.reopen "/dev/null", "a"
        STDERR.reopen STDOUT
        trap("TERM") {daemon.stop; exit}
        daemon.start
      end
    end
  
    def self.stop(daemon)
      if !File.file?(daemon.pid_fn)
        puts "Pid file not found. Is the daemon started?"
        exit
      end
      pid = PidFile.recall(daemon)
      FileUtils.rm(daemon.pid_fn)
      pid && Process.kill("TERM", pid)
    end
  end
end


To use it, you can do something like the following:

class Counter < Daemon::Base
  def self.start
    @a = 0
    loop do
      @a += 1
    end
  end

  def self.stop
    File.open('result', 'w') {|f| f.puts "a = #{@a}"}
  end
end

Counter.daemonize
« Newer Snippets
Older Snippets »
Showing 1-10 of 10 total  RSS