« Newer Snippets
Older Snippets »
Showing 21-40 of 70 total

Changed File Analysis

//Search through a directory looking for modified files - uses one-way hash function. Run once to initalize files, then run at a later date for analysis.

#
#   A ruby script to detect changed/added/deleted files
#     using one-way hash function - MD5 used, but could be changed
#
#    Written by:  Studlee2 at gmail dot com
#
# Usage: changed.rb <path>
#      Output files will be dumped into <path>
#
# MUST BE ABLE TO READ AND WRITE FILES
# Must have Digest::base installed

require 'digest/md5'

#initialize all hashes, regexp, and path array
oldfile_hash = Hash.new()
newfile_hash = Hash.new()
valid = /(.*)\s{5}(\w{32})/
#This array will store each directory to traverse
dir_array = Array.new()
dir_array[0] = ARGV.shift or raise "Missing path to traverse"

#Ensure the path is correct for file output
file_report = "#{dir_array[0]}\\file_report.txt"
file_output = "#{dir_array[0]}\\changed.files"
oldfile_output = "#{dir_array[0]}\\old_changed.files"

#Determine if the script has been run on the path before, if so change the file name
  if File.exists?(file_output)
    File.rename( file_output, oldfile_output)       #archive the file to make room for a new one
    File.open(oldfile_output, 'r+b') do |infile|   #open old_file to compare to new_file
      #read in the old files and md5 sums for each line in the file
      while (old_line = valid.match(infile.gets))
       oldfile_hash[old_line[1]] = old_line[2]
      end
    end
end

    #initialize the files to be used to write to
    report = File.new(file_report, 'wb')
    changed_files = File.new(file_output, 'wb')

  #Go through the directory and compute MD5 Hash until there aren't anymore items in directory array
  begin
    p = dir_array.shift   #remove one item from directory array 
    Dir.chdir(p)            #change to new directory to search
    #for each file in the dir, compute md5 sum and add to new hash
    Dir.foreach(p) do |filename|
      next if filename == '.' or filename == '..'   #go to next folder if '.' or '..'
      unless File::directory?(filename)                    #if not a folder, then process file
        file = File.open(filename, 'rb')
        newfile_hash[filename] = Digest::MD5.new(File.open(filename, 'rb').read).hexdigest
        file.close unless file.closed?
      else
        dir_array << p + "\\" + filename      #if nat a file, put the directories into array for later
      end
    end
  end while !dir_array.empty?
#write files found to changed.files
newfile_hash.each do |file, md5|
  changed_files.write "#{file}     #{md5}\n"
end
#remove files that are the same from hash tables
newfile_hash.keys.select {|file| newfile_hash[file] == oldfile_hash[file] }.each do |file|
  newfile_hash.delete(file)
  oldfile_hash.delete(file)
end
#write files that have been changed or added, then remove from has table
newfile_hash.each do |file, md5|
  report.write "#{oldfile_hash[file] ? "Changed" : "Added"} file: #{file} #{md5}\n"
  oldfile_hash.delete(file)
end
#write files that are left over the the oldfile_hash table - these are files that weren't found in the <path>
oldfile_hash.each do |file, md5|
  report.write "Deleted/Moved file: #{file} #{md5}\n"
end

Currency Converter

// A simple ruby script to convert currency

#
#   A simple ruby script to convert currency
#     can be edited to check stocks, highs, lows, etc.
#
#    Written by:  Studlee2 at gmail dot com
#
# Usage: money.rb <amount><from-code><to-code>
# Where:  <from-code>,<to_code> -- ISO Currency codes
#
# MUST BE CONNECTED TO THE INTERNET
# Must have ruby-finance installed
require 'finance/currency'

#Take arguments in from command line
c = ARGV

#Ensure that usage is proper
valid = /^([\+-]?\d*(?:\.\d*)?)(\S+)\s(\S+)/
if exchange = valid.match(c)
amount = exchange[1]
from_code = exchange[2]
to_code = exchange[3]

#Let Finance::Currency do its magic
puts Finance::Currency::convert(to_code.to_s, from_code.to_s, amount)
else
#if usage is invalid - inform the user
  puts '-----USAGE IS-----'
  puts '<amount><from-code> <to-code>'
  puts '<from-code>,<to-code> -- ISO Currency codes'
end

Decrypt a File *Blowfish*

// A simple ruby script to decrypt a file

#
#   A simple ruby script to decrypt a file
#     can be edited to decrypt directories also
#
#    Written by:  Studlee2 at gmail dot com
#
#    Using the blowfish algorithm
#         several algorithms exist, just substitute for 'blowfish'
#         make sure it matches the encryption algorithm
require 'crypt/blowfish'

begin
#take in the file name to decrypt as an argument
  filename = ARGV.shift
  puts "Decrypting #{filename}"
  p = "Decrypted_#{filename}"
#User specifies the original key from 1-56 bytes (or guesses)
  print 'Enter your encryption key: '
  kee = gets
#initialize the decryption method using the user input key  
  blowfish = Crypt::Blowfish.new(kee)
  blowfish.decrypt_file(filename.to_str, p)
#decrypt the file  
  puts 'Decryption SUCCESS!'
rescue
#if the script busts for any reason this will catch it
  puts "\n\n\nSorry the decryption was unsuccessful"
  puts "USAGE: ruby decryption.rb <plaintext file>\n\n\n"
  raise
end

Encrypt a File *Blowfish*

// A simple ruby script to encrypt a file

#
#   A simple ruby script to encrypt a file
#     can be edited to encrypt directories also
#
#    Written by:  Studlee2 at gmail dot com
#
#    Using the blowfish algorithm
#        several algorithms exist, just substitute for 'blowfish'
#
require 'crypt/blowfish'

begin
#take in the file name to encrypt as an argument
  filename = ARGV.shift
  puts filename
  c = "Encrypted_#{filename}"
#User specifies a key from 1-56 bytes (Don't forget this or your stuff is history)
  print 'Enter your encryption key (1-56 bytes): '
  kee = gets
#initialize the encryption method using the user input key
  blowfish = Crypt::Blowfish.new(kee)
  blowfish.encrypt_file(filename.to_str, c)
#encrypt the file
  puts 'Encryption SUCCESS!'
rescue
#if the script busts for any reason this will catch it
  puts "\n\n\nSorry the encryption was unsuccessful"
  puts "USAGE: ruby encryption.rb <plaintext file>\n\n\n"
  raise
end

Simple Temperature Converter

// Temperature Converter

#
#   A simple ruby script to convert temperatures
#    Written by:  Studlee2 at gmail dot com
#

puts "Enter a temprature: "
t = gets
#regexp to make sure the entry is valid
valid = /^([\+-]?)(\d+)([CcFf]?)/
degree = valid.match(t)
#determines if you input celsius or farenheit
if (degree[3] == "c" || degree[3] == "C")
  puts "Converting from Celsius to Farenheit"
  puts "#{degree[0]} to #{((9.0/5.0) * degree[2].to_f + 32.0).to_i} F"
elsif (degree[3] == "f" || degree[3] == "F")
  puts "Converting from Farenheit to Celsius"
  puts "#{degree[0]} to #{((5.0/9.0) * (degree[2].to_f - 32.0)).to_i} C"
#Displays the usage if you didn't enter anything correctly
else 
  puts "Usage is: [+|-]<deg>[C|F]"
end

update a working copy and all externals in parallel

If you have an app in subversion with many externals, it may take a bit too long to update it, as updates happen one after another.

This bit of script updates the app and each external in parallel, making it oh so much faster.


#!/usr/local/bin/ruby

puts(
  ( `svn pl -R`.scan(/\S.*'(.*)':\n((?:  .*\n)+)/)\
    .inject({}) { |h, (d, p)| h[d] = p.strip.split(/\s+/); h }\
    .select { |d, ps| ps.include? 'svn:externals' }\
    .map { |xd, ps| [xd, `svn pg svn:externals #{xd}`] }\
    .map { |xd, exts| exts.strip.split(/\s*\n/).map { |l| xd + '/' + l.split(/\s+/).first } }\
    .inject { |a, b| a + b }\
    .map { |d| "cd #{d} && svn up 2>&1" } \
    << 'svn up . --ignore-externals 2>&1'
  )\
  .map { |cmd| [cmd, Thread.new { `#{cmd}` }] }\
  .map { |cmd, thread| "#{cmd}\n#{thread.value}" }.join("\n")
)


(note: if you add an external or change an external property in another way, you'll need to run the standard svn up once)

Rake task that adds all unversioned files to the repository

task :add_all_to_svn do
  `svn status --show-updates`.each { |l|
    l = l.split
    system("svn add #{l.last}") if l.first == "?" # File is not under version control
  }
end

Test helper for colorfull logging

Helper methods defined in this test_helper.rb make test.log colorfull and allow to easy find specific test cases and failures. To log test names use following template for test method:

def test_creates_entry
  log_test_name
  # Rest of your test code goes here
  # ...
end


test/test_helper.rb

ENV["RAILS_ENV"] = "test"
require File.expand_path(File.dirname(__FILE__) + "/../config/environment")
require 'test_help'

module Test::Unit::Assertions
  def assert_block(message="assert_block failed.") # :yields:
    _wrap_assertion do
      if (! yield)
        logger.debug("\e[0;41mFailure:\e[m #{message}")
        raise Test::Unit::AssertionFailedError.new(message.to_s)
      else
        logger.debug("\e[0;32mSuccess\e[m")
      end
    end
  end
end

class Test::Unit::TestCase
  # Transactional fixtures accelerate your tests by wrapping each test method
  # in a transaction that's rolled back on completion.  This ensures that the
  # test database remains unchanged so your fixtures don't have to be reloaded
  # between every test method.  Fewer database queries means faster tests.
  #
  # Read Mike Clark's excellent walkthrough at
  #   http://clarkware.com/cgi/blosxom/2005/10/24#Rails10FastTesting
  #
  # Every Active Record database supports transactions except MyISAM tables
  # in MySQL.  Turn off transactional fixtures in this case; however, if you
  # don't care one way or the other, switching from MyISAM to InnoDB tables
  # is recommended.
  self.use_transactional_fixtures = true

  # Instantiated fixtures are slow, but give you @david where otherwise you
  # would need people(:david).  If you don't want to migrate your existing
  # test cases which use the @david style and don't mind the speed hit (each
  # instantiated fixtures translates to a database query per test method),
  # then set this back to true.
  self.use_instantiated_fixtures  = false

  def logger
    RAILS_DEFAULT_LOGGER
  end

  def log_test_name(test_name=nil)
    test_name = caller[0].match(/`(test_[a-z_]+)'$/) unless test_name
    logger.debug "\n\e[1m#{self.class}::\e[0;31m#{test_name}\e[m\n"
  end
end

class ActionController::Integration::Session
  def logger
    RAILS_DEFAULT_LOGGER
  end

  def log_step_name(step_name=nil)
    step_name = caller[0].match(/`(test_[a-z_]+)'$/) unless step_name
    logger.debug "\n\e[1m#{step_name}\e[m"
  end
end

Copy and rename files with wildcards (globs)

To copy files jgarner_* to Alias_*:

Dir.glob("jgarner_*") { |name| `cp #{name} #{name.sub(/jgarner_/, "Alias_")}`}

or

ruby -e 'Dir.glob("jgarner_*") { |name| `cp #{name} #{name.sub(/jgarner_/, "Alias_")}`}'


Copy files matching a regular expression to a new name

// copy similar files to a new name given a regular expression in ruby

for i in `ls *_1.png`; do echo $i; cp $i `echo $i|ruby -pe '$_.sub!(/_1/, "_0")'`; done

Dynamic time based finder for ActiveRecord

I think it's pretty nice. Get all records within a railsified period of time (7.days.ago, 12.months.ago). I can do cool things like Workout.within_12_days or Workout.within_12_hours. Further conditions can be given as a hash, and will be transposed onto the end of the :conditions.

Workout.within_n_units(:user_id => 12) #-> Workout.find(:all, :conditions => 'created_at > n.units.ago and user_id = 12')


class Workout < ActiveRecord::Base
  class << self
    def within_n_temporal_units(number, units, further_conds={})
      conds = "created_at > '#{eval("#{number}.#{units}.ago").to_s(:db)}'"
      further_conds.each {|key, val| conds << " and #{key} = #{val}"}
      Workout.find(:all, :conditions => conds)
    end
    
    def method_missing(name, *args)
      return within_n_temporal_units($~[1], $~[2], args[0] || {}) if name.to_s =~ /within_(\d+)_(\w+)/
      raise NoMethodError, "undefined method `#{name}' for #{self}:Class"
    end
  end
end

ruby stored procedures

There are alot of reasons to use stored procedures. One of the most compelling reasons is that a system has already been built with stored procedures and interfacing with it cannot be by raw SQL. This situation is mainly caused by DBA’s whose job it is to control the flow of information into and out of the database. In “enterprise” situations this is the norm.


  @connection = OCI8.new("db_user", "db_password", "db_name")

  plsql = @connection.parse("BEGIN P_MYPROCEDURE.my_method(:out); END;")
  plsql.bind_param(':out', OCI8::Cursor) 
  plsql.exec

  cursor = plsql[':out']
  plsql.close

  x = ''
  while r = cursor.fetch()
    x = x + r.join(', ') + '<br>'
  end

  @out = x

  @connection.logout


This code assumes you are using Rails 1.1 as an engine and that you have setup the database.yml for Oracle (10g in this post). The OCI8 object instantiated on the first line is in the OCI8 library which is loaded by Rails, specified in database.yml.

Interfacing with Oracle and its stored procedures pretty much requires some knowledge about Oracle which has some very specific concepts that something like MySQL does not.

First, to pass local variables to the stored procedure’s “in” and “out” variables, you must explicitly “bind” them.

Second is the notion of “cursor”.

Author: hksintl on http://blog.hksintl.com/

Modify acts_as_urlnameable to un-accentuate unicode chars

The acts as urlnameable plugin (used to create permalinks) removes accentuated chars by default.

Change the urlnameify method in lib/acts_as_urlnameable.rb:74

def urlnameify(text)
  t = Iconv.new('ASCII//TRANSLIT', 'utf-8').iconv(text)
  t = t.downcase.strip.gsub(/[^-_\s[:alnum:]]/, '').squeeze(' ').tr(' ', '-')
  (t.blank?) ? '-' : t
end

DRY up empty controller actions

Ever create Rails views that don't user the controller at all just to take advantage of an application layout?
If you have, you may have a lot of code that looks like this:


class HelpController < ApplicationController
  def index
  end

  def tutorial
  end

  def faq
  end
end


Well, there's a simple way to make this a lot cleaner...


class ApplicationController < ActionController::Base
  def self.simple_action(*actions)
    actions.each {|action| class_eval("def #{action}; end")}
  end
end

Now your controller can look like this instead...

class HelpController < ApplicationController
  simple_action :index, :tutorial, :faq
end

Recursively add file extensions in OSX using Magic and your own filetypes

ExtensionAdder v.1

ExtensionAdder is an OSX ruby script that recursively traverses a folder, adding extensions to approprate files. The script uses the Magic file, but you can extend the behavior by adding your own shell scripts (see the "includes" folder) to grep into files that Magic only classifies as "data".

At this time you have to explicitly state which file types you want to add extensions to.

Download it here


Sandon Jurowski
[email protected]

Make a subversion release

Ruby script to make a release from SVN trunk.

Assumes a repository structure of:

/path/to/Trunk
/path/to/Releases/YYYY-MM-DD--XX

Should be easy enough to modify to suit your needs. Comments welcome :)

Example usage:
vi /usr/local/bin/release (and dump snippet into it)
chmod +x /usr/local/bin/release
cd /path/to/checked-out-trunk
release


#!/usr/bin/ruby

today = Time.now.strftime('%Y-%m-%d')

if `svn info`.to_a[1] !~ /^URL: (.*)\/Trunk$/
        puts "Repository invalid. Must be in Trunk."
        exit
end

repo_url = $1

repo = repo_url.split('/').last

release_url = repo_url + "/Releases"

if `svn ls #{release_url}`.to_a.last =~ /#{today}--(\d+)/
        num = $1.to_i + 1
else
        num = 1
end

release = "#{today}--#{num}"

cmd = "svn copy #{repo_url}/Trunk #{release_url}/#{release} -m 'copy #{repo} trunk to release #{release}'"
puts cmd
puts

print "Execute command? "

if gets.chomp.upcase != 'Y'
        puts "Nothing done."
        exit
end

`#{cmd}`
puts "Copied as #{release}."
puts "Execute on the remote machine:"
puts "svn switch #{release_url}/#{release}"

Replacing all shebangs in a rails app

perl -pi -e 's|^#!/.*|#!/usr/bin/env ruby|;' script/* script/*/* public/dispatch.*

Camel case a string ( removing accents )

# input str = " j'ai écris l'œuvre de ma vie "
# output str :"JAiEcrisLOeuvreDeMaVie"

accents = { ['á','à','â','ä','ã','Ã','Ä','Â','À'] => 'a',
  ['é','è','ê','ë','Ë','É','È','Ê'] => 'e',
  ['í','ì','î','ï','I','Î','Ì'] => 'i',
  ['ó','ò','ô','ö','õ','Õ','Ö','Ô','Ò'] => 'o',
  ['œ'] => 'oe',
  ['ß'] => 'ss',
  ['ú','ù','û','ü','U','Û','Ù'] => 'u'
  }
accents.each do |ac,rep|
  ac.each do |s|
    str.gsub!(s, rep)
  end
end
str.gsub!(/[^a-zA-Z_\- ]/," ")
str = " " + str.split.join(" ")
str.gsub!(/ (.)/) { $1.upcase }

Convert numbers to words

Ugly code. <strike>But it works.</strike> If you have something better, then post it.

This code is probably (definitely :-) buggy, so if you want to get real work done, just use the Linguistics gem instead.

class Number
  
  def self.to_words(number)
    Number.new.to_s(number)
  end
  
  def self.commify(number)
    (s=number.to_s;x=s.length;s).rjust(x+(3-(x%3))).gsub(/(\d)(?=\d{3}+(\.\d*)?$)/,'\1,')
  end
    
  def initialize
    @unit = %w[zero one two three four five six seven eight nine]
    @teen = %w[ten eleven twelve thirteen fourteen fifteen sixteen seventeen eighteen nineteen]
    @tens = %w[zero ten twenty thirty fourty fifty sixty seventy eighty ninety]
    @qtys = %w[hundred thousand million billion trillion quadrillion quintillion]
    @zero = ["zero"]
    @hundred = "hundred"
    @sepr = "and"
  end
    
  def to_s(number)
    out = quantify(number).flatten
    for x in 0 .. out.length - 1
      out[x] = nil if out[x] == @sepr && out[x+1] == @sepr
    end
    out.compact!
    out = @zero if out.length == 1 && out[0] == @sepr
    out.pop while out.last == @sepr
    out.shift while out.first == @sepr    
    out.join(' ').gsub(/ ,/,',')
  end
        
  private 
  
  def padded_groups(v)
    out = []
    padded = (s=v.to_s;x=s.length;s).rjust(x+(3-(x%3))).gsub(//,'0')
    padded.scan(/.{3}/)
  end
  
  def wordify(v)
    out = []
    zero = '0'[0]
    h, t, u = v[0] - zero, v[1] - zero, v[2] - zero
    if h != 0
      out << @unit[h]
      out << @hundred
    end
    out << @sepr if h != 0 && (t != 0 || u != 0)
    out << @sepr if h == 0 && t == 0 && u != 0
    if t == 1
      out << @teen[u]
    else
      out << @tens[t] if t != 0
      out << @unit[u] if u != 0
    end
    return out
  end
  
  def quantify(v)
    v = padded_groups(v).reverse
    pos = v.length - 1
    out = []
    while pos >= 0
      word = wordify(v[pos])
      if word[0] != nil
        out << word
        out << @qtys[pos] if pos != 0                
      else
        out << @sepr
      end
      pos -= 1
    end
    return out
  end

end

# for number in [
#     0, 
#     1, 
#     3, 
#     11, 
#     100,
#     1000, 
#     1001, 
#     1100, 
#     1101, 
#     1_000_001, 
#     8_000_000_000, 
#     8_000_000_001, 
#     4_567_890_923, 
#     6_804_567_890_903, 
#     5_006_804_567_890_903
#   ]
#   print "#{Number.commify(number)}: #{Number.to_words(number)}\n"
# end

Substitute for the :spacer_template option to rail's "render" method

when working with the :collection option, it seems silly to have to have an entire file just for a spacer, which would probably just be something like "<hr />" for most, so this is a great substitute for
<%= render :partial => "thing", :collection => @coll, :spacer_template => "filename_to_file_with_hr_inside_it" %>


New version with code embedded:
  <%= @coll.map { |item| render :partial => "thing", :locals => {:thing => item} }.join("<hr />") %>
« Newer Snippets
Older Snippets »
Showing 21-40 of 70 total