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

Matt Scilipoti

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

Simple mock: override_method

Note: ALL code samples in this post were hijacked from: http://www.karmiccoding.com/articles/2006/03/11/under-the-hood-with-ruby-partial-mock-objects-for-unit-testing
# Overrides the method +method_name+ in +obj+ with the passed block
def override_method(obj, method_name, &block)
  # Get the singleton class/eigenclass for 'obj'
  klass = class <<obj; self; end 

  # Undefine the old method (using 'send' since 'undef_method' is protected)
  klass.send(:undef_method, method_name)

  # Create the new method
  klass.send(:define_method, method_name, block)
end

# Just an example class
class Foo 
  def do_stuff
    "I'm okay!" 
  end
end

# Test code
list = []
5.times { list.push(Foo.new) }

# We override the method here!
override_method(list.first, :do_stuff) { "I'm NOT okay!" }

list.each_with_index { |f, i| puts "(#{i}) #{f.do_stuff}" }


Outputs:
(0) I'm NOT okay!
(1) I'm okay!
(2) I'm okay!
(3) I'm okay!
(4) I'm okay!

Windows Path

Stolen From: http://www.hanselman.com/blog/Reflector5ReleasedWorldDominationAssured.aspx
Tuesday, February 20, 2007 4:54:50 PM (Pacific Standard Time, UTC-08:00)

You mention that reflector should be in your path. That gives me an opportunity to exploit a (ruby) gem I created a few weeks ago which makes managing your path a breeze. Instead of going to My Computer | Properties | Blah blah and adding the path entry using that terrible dialog, just follow these steps:
gem install patheditor
path_editor --add c:\path\to\reflectore

Adding items to the Windows Path is so painful, I created this utility to make it a little easier for everyone.

It uses a WSH object to update your USER path setting, and the change will be permanent - current and future command prompts will see the new path. Unfortunately, slickrun does not respect path updates so you'll have to kill it and restart if you launch prompts from there ...
Justin

Also:
Thursday, February 22, 2007 5:25:22 PM (Pacific Standard Time, UTC-08:00)
@Jon

Updating path that way (Set PATH=) only affects your current command prompt. My script uses WSH objects to propagate the change to all running processes (that respect the update), and future prompts will include the new path.

The script will also not add duplicate entries, and it can even clean duplicate/non-existent directories out of your current path.
Justin

Safely join file parts

Simple way to safely join file parts.

File.join("C:", "osql", "foo.rb")

Tagging Your Test Cases

From http://www.railtie.net/articles/2006/09/17/tagging-your-test-cases:
Here's a quick way to follow your tests a little more closely in your test.log. In your test setup, add the following line:
def setup
  RAILS_DEFAULT_LOGGER.debug "\n\e[0;31mRUNNING TEST CASE: #{name}\e[m\n"
end

smart plaintext wrapping

From http://blog.evanweaver.com/articles/2006/09/03/smart-plaintext-wrapping:
>>>
Very often you need to break plaintext at a specific width while retaining readability.
#!/opt/local/bin/ruby

class String

  def wrap(width, hanging_indent = 0, magic_lists = false)
    lines = self.split(/\n/)

    lines.collect! do |line|

      if magic_lists 
        line =~ /^([\s\-\d\.\:]*\s)/
      else 
        line =~ /^([\s]*\s)/
      end

      indent = $1.length + hanging_indent rescue hanging_indent

      buffer = ""
      first = true

      while line.length > 0
        first ? (i, first = 0, false) : i = indent              
        pos = width - i

        if line.length > pos and line[0..pos] =~ /^(.+)\s/
          subline = $1
        else 
          subline = line[0..pos]
        end
        buffer += " " * i + subline + "\n"
        line.tail!(subline.length)
      end
      buffer[0..-2]
    end

    lines.join("\n")

  end

  def tail!(pos)
    self[0..pos] = ""
    strip!
  end

end

if __FILE__ == $0
  File.open(ARGV[0]) do |f|
    puts f.read.wrap(ARGV[1].to_i, ARGV[2].to_i, ARGV[3] == "true")
  end
end

<<<

full text searching for ri content

From ZenSpider, http://blog.zenspider.com/archives/2006/08/full_text_searc.html:
Check it out. Quick and dirty searching of ri content:

Updated using: http://blog.zenspider.com/archives/2006/08/new_and_improve.html

They added path independence and searching of gems and local installed ri/rdoc. Enjoy!
#!/usr/local/bin/ruby -w

require 'rdoc/ri/ri_paths'
require 'find'
require 'yaml'

search = ARGV.shift

puts "Searching for #{search}"
puts

dirs = RI::Paths::PATH
dirs.each do |dir|
  Dir.chdir dir do
    Find.find('.') do |path|
      next unless test ?f, path
      yaml = File.read path
      if yaml =~ /#{search}/io then
        full_name = $1 if yaml[/full_name: (.*)/]
        puts "** FOUND IN: #{full_name}"
        
        data = YAML.load yaml.gsub(/ \!.*/, '')
        desc = data['comment'].map { |x| x.values }.flatten.join("\n").gsub(/&quot;/, "'").gsub(/&lt;/, "<").gsub(/&gt;/, ">").gsub(/&amp;/, "&")
        puts
        puts desc
        puts
      end
    end
  end
end

Lets you do stuff like:
% ./risearch.rb duplicate
Searching for duplicate
[...]
** FOUND IN: Array#uniq!

Removes duplicate elements from self. Returns nil if no changes are made (that is, no duplicates are found).
   a = [ 'a', 'a', 'b', 'b', 'c' ]
   a.uniq!   #=> ['a', 'b', 'c']
   b = [ 'a', 'b', 'c' ]
   b.uniq!   #=> nil

** FOUND IN: Array#|

Set Union---Returns a new array by joining this array with other_array, removing duplicates.
   [ 'a', 'b', 'c' ] | [ 'c', 'd', 'a' ]
          #=> [ 'a', 'b', 'c', 'd' ]
[...]

Posted by zenspider at August 15, 2006 04:16 PM | Bookmark This
Categories: Rails , Ruby , Toys

ActiveRecord and SQL Server

From http://www.softiesonrails.com/articles/2006/06/28/activerecord-with-sqlserver-without-rails:

Ensure you done the initial setup for SQL Server and ActiveRecord (ADO.rb).

require 'rubygems'
require_gem 'activerecord'

ActiveRecord::Base.establish_connection(
  :adapter  => "sqlserver",
  :dsn => "instance_name_goes_here",
  :host => "machine_name\\instance_name",
  :database =>  "db_name",
  :username =>  "my_username",
  :password =>  "my_password"
)

class MsSqlTable < ActiveRecord::Base
  def method_missing(method, *args)
    respond_to?(method) ? super : send(method.to_s.camelize, *args)
  end
end

class Item < MsSqlTable
  set_primary_key "sku"
  set_table_name "item"
end


I'll walk through it real quick:

1. The :dsn needs to be your SQL Server instance name
2. The :host needs to a path like "myserver\myinstance", even though you've already specified the instance name in the :dsn parameter
3. The rest of the settings should be obvious. If your password is blank, don't specify :password at all.
4. Our legacy column names are things like OldDescription. So I created an intermediate base class that would provide ruby-like aliases. Now I can use item.old_description instead if I want to.
5. Finally, I declare one class for each table I want to access. I have to set the primary key and table name manually, since our tables don't correspond to any Rails conventions.

I saved this script as legacy.rb, and then fired up irb from that directory:
irb> load 'legacy.rb'
=> true
irb> Item.find("191191").old_description
=> "Table In A Bag"
irb>

Hash Tricks

From: http://blog.caboo.se/articles/2006/06/11/stupid-hash-tricks

class Hash

  # lets through the keys in the argument
  # >> {:one => 1, :two => 2, :three => 3}.pass(:one)
  # => {:one=>1}
  def pass(*keys)
    tmp = self.clone
    tmp.delete_if {|k,v| ! keys.include?(k) }
    tmp
  end

  # blocks the keys in the arguments
  # >> {:one => 1, :two => 2, :three => 3}.block(:one)
  # => {:two=>2, :three=>3}
  def block(*keys)
    tmp = self.clone
    tmp.delete_if {|k,v| keys.include?(k) }
    tmp
  end

end


In case you don’t already see the utility of this:
def some_action
    # some script kiddie also passed in :bee, which we don't want tampered with _here_.
    @model = Model.create(params.pass(:foo, :bar))
  end

or those cases where you don’t want to let everything through and don’t want to resort to attr_protected or attr_accessible

call sort with a block

From http://practicalruby.blogspot.com/2006/05/call-sort-with-block.html:

I needed to sort a list of partners today so I added:
class Partner
  def <=>(other)
     self.name <=> other.name
  end
end

However, I could have just done:
Partner.find(:all).sort { |one, other| one.name <=> other.name }

Doc for sort here.

From Comments:
You could also have used sort_by as long as the target supports the spaceship operator. ie:
Partner.find(:all).sort_by { |partner| partner.name }

With active_support required (or 'facet/symbol/to_proc' from the facets library) you can even:
Partner.find(:all).sort_by(&:name)


Sweet.

User Friendly Time Entry

http://www.railtie.net/articles/2006/04/22/user-friendly-time-entry
Posted by Bob Silva Sat, 22 Apr 2006 08:49:00 GMT

Have a need to track time spent on something? Here's an easy way to allow your users to enter their time in a smart way (anyway they want). This example accepts fractional hours, overflowing minutes and converts and displays them as the user would expect. They are stored in your database as minutes (integer) and displayed as hours/minutes (regardless of how they were input).

Model Code (model.rb):

def set_travel_time(hours, minutes)
  self.travel_time = ((hours.to_f * 60) + minutes.to_i).to_i
end

def get_travel_time
  travel_time.to_i.divmod(60)
end


Controller Code (models_controller.rb):

def create
  @model.new(...)
  ...
  @model.set_travel_time(params[:hours], params[:minutes])
  ...
  if @model.save
  ...
end

def edit
  @model = Model.find(...)
  ...
  @hours, @minutes = @model.get_travel_time
  ...
end


View Code (_form.rhtml):

<%= text_field_tag 'hours', @hours -%> hours 
<%= text_field_tag 'minutes', @minutes -%> minutes 



For plugin ideas, see dollars_and_cents: http://blog.codahale.com/2006/05/18/dollars_and_cents-a-rails-plugin/

One of the big problems with a database-agnostic framework like ActiveRecord is that it doesn’t have a decent data type for money. Yes, you can use a FLOAT, but then you end up charging someone $12.3000000000000001, which is just awkward. This plugin stores as INT, but displays as Currency.
« Newer Snippets
Older Snippets »
Showing 1-10 of 14 total  RSS