Three till Seven

Archive for the “Ruby” Category

1 Feb 08 chmodding and Ruby

Note: If you enjoy this article, you might also check out the Geeky Stuff section.

Recently, I switched from a Powerbook to a Macbook, and to copy my files from one to the other, I used a pen drive. Since my pen drive has a FAT file system, it treats everything as being executable. This, however, is not the case on a UNIX-like file system like OS X. In order to save myself the hassle of manually chmodding thousands of files, I wrote this Ruby script:

Ruby

#!/usr/bin/env ruby
require 'find'
require 'fileutils'

# Append to/remove from this list as necessary
Plain = ['php', 'txt', 'jpg', 'jpeg', 'gif', 'png', 'html', 'pdf', 'css', 'mp3', 'zip', 'tar.gz', 'tar', 'htm', 'psd', 'ai', 'ptg', 'cgi.pl', 'sphp', 'svn-base', 'default'].collect do |ext|
    ".#{ext}"
end.freeze

# Append to/remove from this list as necessary
Executable = ['pl', 'rb', 'cgi', 'sh'].collect do |ext|
    ".#{ext}"
end.freeze
$num_chmodded = 0

def chmod_and_puts( cmd )
    puts cmd
    system cmd
    $num_chmodded += 1
end

def chmodder( start_dir )
    num_skipped = 0
    num_plain = 0
    num_executable = 0
   
    Find.find( start_dir ) do |path|
        unless File.symlink?( path )
            if FileTest.file? path
                if is_plain? path
                    chmod_and_puts "chmod 644 \"#{path}\""
                    num_plain += 1
                elsif is_executable? path
                    chmod_and_puts "chmod 755 \"#{path}\""
                    num_executable += 1
                else
                    num_skipped += 1
                end
            elsif File.directory? path
                chmod_and_puts "chmod 755 \"#{path}\""
                num_executable += 1
            else
                num_skipped += 1
            end
        else
            num_skipped += 1
        end
    end
   
    puts "----------------------------------------------"
    puts "Chmodded #{$num_chmodded} total:"
    puts "\tExecutable: #{num_executable}"
    puts "\tPlain: #{num_plain}"
    puts "Skipped #{num_skipped} files/directories/symlinks"
end

def get_extension( path )
    File.extname( path ).downcase
end

def is_executable?( path )
    extension = get_extension( path )
   
    if Executable.include? extension
        true
    else
        false
    end
end

def is_plain?( path )
    extension = get_extension( path )
   
    if Plain.include? extension
        true
    else
        false
    end
end

chmodder( '.' )

This goes through all the files and directories within the directory from which you run the script and chmods non-executable files to 644 (read+write on User, read on Group and Other) and executable files to 755 (read+write+execute on User, read+execute on Group and Other). If you're unfamiliar with the chmod command, you might want to read my beginning Linux guide.

21 Nov 07 using Ruby to rename files and edit their content

Note: If you enjoy this article, you might also check out the Geeky Stuff section.

Recently at work, the web admin for the computer science department came into our lab and told us that my employer's site was broken. The admin had need to make all .php files not act as PHP scripts, and instead, all files with the extension .sphp would now run as PHP scripts. Since my employer's site was built using PHP, that meant all of its pages were showing the source code instead of actually executing. I had to whip up a quick Ruby script in order to:

  1. Rename all .php files to have .sphp as their extension;
  2. Replace all instances of ".php" within those files with ".sphp", to take care of include statements, links, etc.

Here's what I came up with:

Ruby

#!/usr/bin/env ruby
require 'find'
require 'fileutils'

# Used to go through, starting at the directory start_dir and working
# recursively, and rename all files that end in .php to end in .sphp
# because the CS admin got a wild hair.  Also goes through all .php
# and .sphp files and replaces all instances of ".php" in them with
# ".sphp".
def finder( start_dir )
  Find.find( start_dir ) do |path|
    if FileTest.file?( path )
      if path =~ /\.php$/i
        old_name = File.basename( path )
        new_name = old_name.gsub( /\.php$/, '.sphp' )
        dir = path.gsub( /#{old_name}$/, '' )
       
        if File.exists?( dir + old_name )
          puts "#{dir + old_name} to #{dir + new_name}\n"
         
          # Since the code is part of a Subversion repository, we use
          # the 'svn' command to let Subversion rename the file
          system( "svn mv #{dir + old_name} #{dir + new_name}" )
        end
      elsif path =~ /\.sphp$/i || path =~ /\.php$/i
        puts "Replacing instances of '.php' in #{path}\n"
        system( %Q{ruby -pe 'gsub(/\\.php/, ".sphp")' -i #{path} } )
      end
    end
  end
end

finder( '.' )

15 Nov 07 finding invalid foreign keys in Rails

Note: If you enjoy this article, you might also check out the Geeky Stuff section.

Sometimes it would be useful to tell users of your Ruby on Rails application if there is a problem in the database, such as some foreign keys are invalid. As an example, let's assume you have two models, Book and Author, such that each Book has an author_id which connects with Author via its primary key, id. That is, the tables are: books(id, author_id) and authors(id). Each table probably has fields other than that, but those are the only fields we need to worry about. Below is a method that generates an unordered HTML list for display to the users:

Ruby

class Book < ActiveRecord::Base
  # Returns HTML about which rows have invalid foreign keys
  def self.find_bad_foreigners
    msg = ''

    find( :all ).each do |book|
      unless Author.exists?( book.author_id )
        author_id = ( book.author_id || 'NULL' ).to_s
        msg << '<li>Book with ID ' << book.id.to_s + ' has a non-existent
          author ID: ' << author_id + '</li>'
      end
    end
   
    if msg.blank?
      nil
    else
      '<ul class="error">' << msg + '</ul>'
    end
  end
end

You could have similar methods in your Rails models. Maybe on the main page of your application, the above method could be displayed. If there are no invalid foreign keys, nothing will show up. Otherwise, the user will see a list of the invalid keys that need fixing.

22 Nov 06 the many methods to #find things in Rails

Note: If you enjoy this article, you might also check out the Geeky Stuff section.

For the longest time, I didn’t understand the full power of the various #find methods in Rails. I probably still don’t, but my view of them has certainly expanded. I used to use plain ol’ #find for everything. If I wanted to find all rows in the table ‘groups’ that had an ‘id’ field value of 1, 2, 3, or 4, I would do something like this:

Ruby

Group.find(
  :all,
  :conditions => ["id=? OR id=? OR id=? OR ID=?", 1, 2, 3, 4]
)


Now, while this is a perfectly valid way to find those rows, it’s a little too… verbose. There’s a cleaner, shorter way to get the same result:

Ruby

Group.find(
  [1, 2, 3, 4]
)

This works because #find can take any of the following as primary ID’s to look up:

  • a single ID:

    Ruby

    Group.find( 1 )
  • an array of ID’s:

    Ruby

    Group.find( [1, 2, 3, 4] )
  • an expanded array of ID’s:

    Ruby

    Group.find( *[1, 2, 3, 4] )
  • multiple ID’s:

    Ruby

    Group.find( 1, 2, 3, 4 )

Beyond the regular #find method, there are also auto-generated methods for each of your Rails models. Say you have a UserGroup model that associates a user to a group (i.e. group membership). The table ‘users_groups’ has the fields ‘id’, ‘user_id’, and ‘group_id’. What’s an easy way to find all users belonging to the group with ID #3?

Ruby

UserGroup.find_all_by_group_id(
  3,
  :include => :user,
  :order => ‘users.name ASC’
).map( &:user )

With that, you’re telling the UserGroup model to find all rows based on the group ID, which you give it as the first parameter. You’re also telling it to eagerly load the associated rows from the ‘users’ table, ordering the results by the user’s name. Then, you’re using #map on the returned array to grab just the results of each row’s #user method. Thus, you end up with an array of User objects, all of whom belong to the group with ID #3.

If you just want to 1) find a single row and 2) have the returned value be that row, and not an array, use a #find_by_FIELD_NAME method, instead of a #find_all_by_FIELD_NAME:

Ruby

UserGroup.find_by_user_id( 1 )

14 Nov 06 #post method in tests with a different controller

Note: If you enjoy this article, you might also check out the Geeky Stuff section.

I wanted a #login method in test_helper that would allow me to easily login from any of my functional tests. However, the #post method won’t allow you to set a different controller than the one in the @controller instance variable that’s defined in your test’s #setup. Well, by looking at how the #process method works, you can see that it just grabs the controller from @controller. Redefine that, and you’re good to go:

Ruby

old_controller = @controller
@controller = LoginController.new
post(
  :attempt_login,
  {:user => {:name => ‘joe’, :password => ‘password’}}
)
@controller = old_controller


If you have several login methods, such as a #login_admin and #login_regular, you could make a wrapper to reduce duplication:

Ruby

def wrap_with_controller( new_controller = LoginController )
  old_controller = @controller
  @controller = new_controller.new
  yield
  @controller = old_controller
end

def login_admin
  wrap_with_controller do
    post(
      :attempt_login,
      {:user => {:name => ‘root’, :password => ‘password’}}
    )
  end
end

def login_regular
  wrap_with_controller do
    post(
      :attempt_login,
      {:user => {:name => ‘joe’, :password => ‘password’}}
    )
  end
end

Cross-posted on my BigBold account.

31 Aug 06 go from model to associated table name and back

Note: If you enjoy this article, you might also check out the Geeky Stuff section.

Given a table object, it returns the related string object; e.g. SubAttribute => ’sub-attribute’. Useful if you want to make a list of all your tables with perhaps their fields listed out to the side.

Ruby

def stringify_table( table, replace_char = ‘-’, pluralize = false )
  string = table.to_s.gsub( /([A-Za-z])([A-Z])/, ‘\1‘ << replace_char.to_s << ‘\2)
  string = string.pluralize if pluralize
  string
end


Given a string akin to the name of a table, it returns the related table object; e.g. ’sub_attributes’ => SubAttribute.

Ruby

def tablify_string( string )
  eval( string.to_s.gsub( /_id/, ” ).singularize.split( ‘_’ ).collect { |word| word.capitalize }.join )
end

This entry was cross-posted to my Code Snippets page.

31 Aug 06 conditioner for ActiveRecord-friendly conditions from a collection

Note: If you enjoy this article, you might also check out the Geeky Stuff section.

I frequently have a collection of values that I want to match in an ActiveRecord query, but it would be nice if I could let ActiveRecord handle checking the data and escaping it properly. So, I wrote this method to return ActiveRecord-friendly conditions, such as:
["user_id=? AND job_id=?", 3, 4]
based on the ‘raw’ conditions you feed to it, such as:
[['user_id', 3], ['job_id', 4]]

# Returns ActiveRecord-friendly conditions based on the given
# raw conditions; handles grouping based on like field names;
# allows different boolean operators in raw conditions;
# allows different comparison operators in raw conditions;
# raw conditions setup:
# [[field name, desired value, bool. op., comp. op.], …]
# raw conditions example:
# [['type_id', '4', 'OR'], ['created_on', Date.new, 'AND', '<=']]
def conditioner( raw_conditions )
  conditions = ["("]
  count = 0
  prev_name = raw_conditions[0][0]
  raw_conditions.each do |condition|
    name = condition[0]
    value = condition[1]
      
    if condition[2]
      bool_type = condition[2]
    else
      bool_type = ‘OR’
    end
      
    if condition[3]
      comparison = condition[3]
    else
      comparison = ‘=’
    end
      
    conditions[0] << ‘) AND ‘ if prev_name != name
    conditions[0] << ‘ ‘ << bool_type.to_s << ‘ ‘ unless count == 0 || prev_name != name
    conditions[0] << ‘(’ if prev_name != name
    conditions[0] << “#{name} #{comparison} ?”
      
    conditions << value
      
    prev_name = name
    count += 1
  end
  conditions[0] << ‘)’

  conditions
end

This way, you can do something like the following:
model_ids = Model.find( :all ).map( &:id )
raw_conditions = model_ids.collect { |id| ['model_id', id] }
conditions = conditioner( raw_conditions )
desired_collection = OtherModel.find( :all, :conditions => conditions )

This entry was cross-posted to my Code Snippets page.

11 Aug 06 simple Rails preference storage

Note: If you enjoy this article, you might also check out the Geeky Stuff section.

So you’ve got some Rails application and you need to store information from the users across their interactions with the app. Here’s a simple, straightforward way to do that.

In your controller:

if params[:option]
  @option = session[:option] = params[:option]
elsif session[:option]
  @option = session[:option]
else
  @option = ‘default value’
end

This checks to see if ‘option’ was passed via a parameter in the URI (e.g. /view?option=jim) or from a form. If it is, then we want to save that option in both the session, so we can access it later, as well as in a variable specifically for use in our view.

However, if params[:option] is nil but we still have it in session[:option] from some previous interaction, then we’ll set our variable @option for use in our view from the session copy.

If all else fails, then we know the user hasn’t tried to set this option in any way, and we can give it some default value.

Now, in our view:

<%= form_tag :action => 'view' %>
<label for=”option”>Choose:</label>
<%= text_field_tag ‘option’, @option, :size => 10 %>
<%= submit_tag ‘Change’ %>
</form>

This provides a simple form for our user to set the value of this option, and if the value is already set from a previous interaction with this form, then it shows up in the text field.

7 Jun 06 if succinctly

Note: If you enjoy this article, you might also check out the Geeky Stuff section.

In Ruby, if is an expression, not a statement, thus it returns a value. This may not seem useful at first glance, but it lends itself to forming neat, concise code… Like most things in Ruby, actually.

Setting Values Concisely

Say you want to define a variable differently based on the result of an if expression. If you’re not a native to Ruby, you may find yourself coding something like this:

if name == 'Susie'
  age = 12
else
  age = 14
end

This breaks from the DRY principle because age = is repeated in each case. Since if is an expression, however, you could write something like this:

age = if name == 'susie'
  12
else
  14
end

This evaluates the condition name == 'susie' and if it’s true, dumps the value 12 into age; oppositely, if it’s false, it dumps the value 14 into age. To be even more succinct about it, try:

age = name == 'susie' ? 12 : 14

One-Line if’s

A lot of the time it may be necessary to write out a one-line block of code within an if. There are several ways to do this without being as verbose as

if expression
  action
end

Three lines! How wasteful. Instead, try one of the following:

  1. if expression then action

    or more concisely:

  2. if expression: action

    or my personal favorite:

  3. action if expression

    or for the C fan:

  4. expression ? if result is true : if result is false

For a negated if (i.e. if !expression), it may make more sense to you to use unless:

unless expression
  action
end

You can use unless in the same way that you use if: all the one-liners above will work. Note, however, that elsif is not available with an unless expression, though else is.

Doubling Up

You can have expressions all over the place, following and preceding blocks. For example:

while condition
  action
end if expression

That while loop will only get executed if expression is true. This may not be the most readable chunk of code, however, since the while is a multi-line block. However, if and unless expressions following one-line blocks are handy.

28 May 06 the power of yield

Note: If you enjoy this article, you might also check out the Geeky Stuff section.

…and super. These two keywords allow you to pass control back and forth between parent and child methods, to weave power between a more general method (in the parent class) and a more specific method (in the child class) with ease and logic. Using yield and super effectively can help you maintain the DRY (Don’t repeat yourself) principle, keeping your code easier to maintain.

Say you have three classes for image creation: a parent class, Image, and two children: Raster and Vector. Now for your raster images, you’re going to be using the GD2 library for Ruby, and for your vector images, you’re going to be creating SVG images. Some of the functionality used to create any given image will be different, naturally, since with the raster images, you’re creating an image object, and with the vector images, you’re concatenating strings of XML SVG code. However, a lot of the code will be the same, and should thus be shared between the two children to avoid duplication. For example, the logic used to determine what color some text should be, or what shape you should draw, can be shared between the two child classes. Any shared code should go in the one common class between the two children: the parent class, Image.

Accessing Shared Code

That is, accessing code in a parent class method from a child class method of the same name. The trick is with super.

write_text() in Raster

def write_text( text, color )
  super() do |width, height, left, top|
    image = Image.new( width, height )
    image.draw do |canvas|
      canvas.color = color
      canvas.font = Font::TrueType['/usr/share/fonts/times.ttf', 20]
      canvas.move_to( left, top )
      canvas.text( text )
    end
  end

  image
end

write_text() in Vector

def write_text( text, color )
  image = '<?xml version="1.0" encoding="UTF-8" standalone="no"?>'
  image << '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/SVG/DTD/svg10.dtd">'

  super() do |width, height, left, top|
    image << '<svg viewBox="0 0 ' + width.to_s + ' ' + height.to_s + '" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">'
    image << '<text font-family="Times" x="' + left.to_s + '" y="' + top.to_s + '" fill="' + color.to_s + '">'
  end

  image << text.to_s
  image << '</text>'
  image << '</svg>'

  image
end

While these two methods accomplish the same thing, they do it differently. However, each of them has a call to super. That will access a method of the same name in the parent class:

write_text() in Image

def write_text
  yield( 300, 100, 5, 5 )
end

All that Image’s write_text() is doing is passing values back to the child method that called it. Each child method’s super call defines variables in the block: width, height, left, and top in the line that says super() do |width, height, left, top|. The yield call in Image defines those values to be width = 300, height = 100, left = 5, and top = 5. To Image’s write_text(), however, it’s just throwing some numbers at the child method: it doesn’t know that the child method is going to use those numbers to define the dimensions of the image and the starting position of its text.

The definition of write_text() in Image is very simple, but it doesn’t have to be that way. There could be a great deal of calculation involved in determining what values the child methods should use for whichever variables are being passed to it. The parent class’s shared method is a place to store shared logic and shared data; let the child classes do the specific stuff with that general data.

Shared Variables Sans yield

Values can also be reached in the child class methods without using yield if instance variables are defined in the parent method:

write_text() in Image

def write_text
  @width = 300
  @height = 100
  @left = @top = 5
end

Then write_text() in both Raster and Vector would be able to access Image’s @width, @height, @left, and @top, as defined in its write_text().

Multiple Calls to super

Sometimes it may be useful to let the parent class’s method do some work, then the child class’s, then the parent’s again. In this case, you can call super and yield as many times as necessary:

Method in Child Class

def my_method
  return1 = super( 'a string' ) do |my_var|
    # Do some stuff with my_var
  end

  return2 = super( ['array', 'of', 'strings'] ) do |my_other_var|
    # Do some stuff with my_other_var
  end
end

Method in Parent Class

def my_method( value )
  if value.class == String
    yield( 'this is my_var' )
  elsif value.class == Array
    yield( 'this is my_other_var' )
  end

  # Checks to see if value can work with the <<
  # method, which both Array and String objects
  # have, and if so, adds another string to it;
  # this value is returned since it's the last
  # line of the method
  value << ' appended to value' if value.respond_to?( :<< )
end

yield Returns Data to super

The child class method can also throw data back to the parent class method by returning a value from the super block:

Method in Child Class

def my_method
  value_from_parent = super do |my_var|
    'this gets thrown back to the parent class method'
  end
end

Method in Parent Class

def my_method
  value_from_child = yield( 'becomes my_var' )
  'this gets thrown back to the child class method'
end

More Information