Displaying articles with tag ruby

Ruby Gets Possessive

Posted by code_monkey_steve, Fri May 07 16:10:00 UTC 2010

I debated whether this code snippet was significant enough to bother blogging about, but it is useful if for no other reason that as an example of one of the great features of Ruby: the ability to reopen any class, even a standard class, and add methods.

In this case, we needed a method to apply the English rules for the possessive apostrophy to a string, e.g. a person’s name. I looked-up the rules on Wikipedia and coded up the following three-liner:

Now in my site I can do things like:

  "Steve".possessive + " Profile"  ==  "Steve's Profile" 
  "Alex".possessive + " Profile"  ==  "Alex' Profile" 

(Cross-posted to the Conceivian Blog)

0 comments | Filed Under: | Tags: ruby

String Conversions in Ruby

Posted by code_monkey_steve, Thu Sep 17 12:53:00 UTC 2009

Here’s a tip so simple and elegant it’s amazing I ever got along without it. Consider String#to_f:
  --> '12.34'.to_f
  ==> 12.34
Which works great, so long as the string is a valid number, but if not:
  --> 'splat'.to_f
  ==> 0.0

#to_f doesn’t throw an exception with invalid input, making it dangerous to use with any user-supplied data. I’ve seen various solutions that involve regular expressions, but these are kludgy and don’t handle all proper numeric representations.

Fortunately, Ruby provides type-cast-style methods to do proper conversions with validation:
  --> Float('12.34')
  ==> 12.34
  --> Float('splat')
  ArgumentError: invalid value for Float(): "splat" 

It might look weird, until you realize that Float is both a class (::Float) and a kernel method (Kernel.Float). There are also methods for converting to an Integer, Array, or even back to a String (which is essentially just #to_s).

0 comments | Filed Under: | Tags: ruby

Word of the Day: Duck-punching

Posted by code_monkey_steve, Tue Apr 28 09:48:00 UTC 2009

I may be showing how out of date I am with the Rubyverse, but I just discovered Duck Punching:

Well, I was just totally sold by Adam, the idea being that if it walks like a duck and talks like a duck, it’s a duck, right? So if this duck is not giving you the noise that you want, you’ve got to just punch that duck until it returns what you expect. – Patrick Ewing

Awesome.

As for show the whale: meh.

0 comments | Filed Under: | Tags: ruby

Safety Feature

Posted by code_monkey_steve, Sun May 11 15:43:00 UTC 2008

require 'mathn'
loop do
  puts "Enter an 11 digit prime number to continue:"
  n = $stdin.gets.chomp.to_i
  break  if n.to_s.size == 11  and
            n.prime_division.size == 1
end

0 comments | Filed Under: | Tags: ruby

Linking Outside of the Box: Optimizing Ruby with C/C++

Posted by code_monkey_steve, Thu Sep 28 05:55:00 UTC 2006

Prototyping

My first attempt at a routine to XOR blocks (stored as Strings) looked something like this:

class String def xor!( str1, str2 ) BLOCK_SIZE = 128.kilobytes (0…BLOCK_SIZE).each { |i| self[i] ^= str1[i] ^ str2[i] } end end

There may very well be a faster way of doing this in pure Ruby, but I couldn’t find it (and didn’t want to waste the time). This worked well enough to finish the basic implementation and unit tests. And even though this prototype version was way too slow, it allowed me to build-out the higher-level code and tests so that went I went to replace it with the faster version, I had already established extensive code coverage (which revealed several bugs in my optimized implementation). Once the prototype is complete it’s time for …

Profiling

Premature optimization is the root of all evil.
- Donald Knuth

Even though I knew that XOR was going to be the biggest cycle-sink, I decided that now would be a good time to learn about Ruby profiling. ruby-prof makes this fairly easy. I chose my biggest, most involved unit test, and wrapped it like so:

require ‘ruby-prof’ def profile_lotsofstuff res = RubyProf.profile do test_lotsofstuff end RubyProf::GraphPrinter.new(res).print(STDOUT, 2) end alias_method :test_profile_lotsofstuff, :profile_lotsofstuff if ENV[‘PROFILE’]
This allows me to easily profile by running that unit test from the command line:
clear ; PROFILE=1 ruby test/unit/stuff_test.rb

While I’m still working on tweaking the various output parameters, the result did confirm my suspicions:

  %total   %self     total      self    children             calls   Name
--------------------------------------------------------------------------------
                      8.04      4.97      3.07                 4/4     String#xor!
  96.87%  59.88%      8.04      4.97      3.07                   4     Range#each
                      1.07      1.07      0.00     1048576/1048576     Fixnum#^
                      1.53      1.53      0.00     1572864/1572880     String#[]
                      0.47      0.47      0.00       524288/524288     String#[]=

Extending with C

Especially for tight nested loops like this, you quickly take a bit performance hit just from the loop overhead. In this case, I also couldn’t find an easy way to iterate through two strings simultaneously. After a while, it became quite annoying knowing that I could do the whole thing in a short little C function.

So that’s what I did. I created a small Rails plugin (xor), with appropriate init.rb, and added a lib/xor.c that looks something like:

VALUE string_xor( int argc, VALUE *argv, VALUE self ) { const char *src1 = STR2CSTR(argv[0]); const char *src2 = STR2CSTR(argv[1]); const char *dest = STR2CSTR(self); size_t len = RSTRING(self)->len; for ( ; len--; ++dest, ++src1, ++src2 ) *dest ^= *src ^ *src2; return self; } void Init_xor( void ) { rb_define_method( rb_cString, "xor!", ((VALUE (*)(ANYARGS)) string_xor), -1 ); }

Using the Rake task for Ruby extensions from my RDBXML project makes it trivial to build with a small Rakefile:

require ‘rake/extensiontask’ desc “Build the XOR extension” Rake::ExtensionTask.new :xor do |t| t.dir = ‘lib’ end

Added some test cases for the various XOR identities (e.g. x^0 = x, x^x = 0, etc.) and that was it. I kept the pure Ruby version of the function for later (renamed to slow_xor!).

Benchmarking

A few runs through the higher-level tests show a huge improvement in speed. But just how much is that? It’s easy to tell with Ruby’s built-in benchmarking support. As with the profiling, I find it convenient to hack it onto the existing unit tests, as they already prove a good source of stress-tests.

def benchmark_xor n = 10 Benchmark.bm(8) do |bm| bm.report( “XOR© :” ) { n.times { test_xor } } String.module_eval { alias_method :xor!, :slow_xor! } bm.report( “XOR (rb):” ) { n.times { test_xor } } end end alias_method :test_benchmark_xor, :benchmark_xor if ENV[‘BENCHMARK’]
              user     system      total        real
XOR (c) :  1.200000   0.116667   1.316667 (  0.817143)
XOR (rb): 81.433333   0.683333  82.116667 ( 50.567826)

This shows a speed-up of a little over 60x. This changes the execution times for just about every operation from “minutes” into “seconds”. Not bad, eh?

Your Milleage May Vary

0 comments | Filed Under: Projects | Tags: ruby

ODIN: Secure P2P on the Web

Posted by code_monkey_steve, Mon Sep 25 09:11:00 UTC 2006

The first thing you need to understand for this to make sense is that the magic of OFF is all in the block encoding which turns meaningful bits into ownerless, quasi-random blocks identified by their SHA1 hashes. Once this transformation is performed, there is no way for anyone to know the content of a block on the network, as it has no meaning until it’s combined with other blocks (and, in that way, may actually “belong” to multiple files, simultaneously).

The thing that first screamed “Rails app!” to me is the fact that, once the content has been OFF-encoded into blocks, any transport mechanism can be used to move these blocks around, allowing for a network-agnostic peer-to-peer system. Using HTTP, I could write my own smart, caching web peer (with combined web UI) in Rails, but since it’s using HTTP, I could also use dumb web server file servers as mass block stores (no CGI required!). Eventually, I could add (trivial) support to talk to the existing OFF network (also HTTP, AFAIK). If I watned to get really crazy, I could make the app a 3-way network bridge with BitTorrent (which also uses SHA1-identified data blocks).

This is an extension of earlier musings about extending HTTP (or coming up with some other standard) for enumerating mirrors of a particular web resource, something like a per-directory MIRROR file (in XML). A local web-proxy/daemon would cache the status, speed, and locality of various mirrors, and attempt to provide the best location for a particular resource (Use Case #1: Linux RPM repositories). Throw in resource discovery, and you have a basic peer-to-peer network, all over HTTP. While this project assumes that each peer is serving OFF-encoded blocks, there’s no reason why this assumption couldn’t be refactored-out, leaving a generic HTTP P2P system.

To date I’ve already completed most of the functionality of ODIN: fast block encoding (more on that later), file insertion and extraction, basic file transfer and peer discovery. I’ll post more when I have something to show-off. ;)

0 comments | Filed Under: Projects | Tags: ruby

Building Ruby Extensions with Rake

Posted by code_monkey_steve, Sat Sep 09 12:36:00 UTC 2006

At the moment, the tasks are a part of the RDBXML project, hosted by RubyForge . There is documentation, and you can view the latest version in SVN here.

Usage is simple enough:
require ‘rake/swigextensiontask’ desc “Build the BDB interface extension” Rake::SWIGExtensionTask.new :db do |t| t.dir = ‘ext’ t.link_libs += [‘db’, ‘db_cxx’] end

This will build db.so, from the db.i SWIG interface file in the ext directory, linking-aginst db.so and db_cxx.so. For a full usage example, see the Rakefile for RDBXML.

0 comments | Filed Under: Projects | Tags: ruby

A Few of My Favorite Things

Posted by code_monkey_steve, Sun Jul 02 09:33:33 UTC 2006

Ruby Development

The barest of essentials. If you don’t already have Ruby and RubyGems, you’ve come to the wrong place.

I highly recommend the KDevelop IDE for all of your bit-flinging needs. I grew to love it when doing C++ code, and it works just as well for Ruby. For times when you just want to tweak a config file, and a full IDE is overkill, nano is your best bet. An excellent lightweight text editor with syntax highlighting, multiple file buffers, and search-n-replace.

Finally, Subversion is by far the best source control system I’ve ever used (including CVS, SourceSafe, Continuus, and Perforce). Aside from its sane handling of symlinks and binary files, the ability to include external Subervsion repositories by reference makes it a must for including Rails plugins.

Rails

The only-slightly-nude essentials. I don’t bother with EdgeRails as I’m still playing catch-up trying to grok all the spiffy features in 1.1.

If you only use one Rails plugin … you’re an idiot. But if it’s assert_valid_markup, at least you’re an idiot with standards-compliant web sites. Adding assert_valid_markup to your functional tests ensures that the XHTML content validates using the W3C validator. I’ve also added an assert_val id_css function to validate stylesheets as well (need to get that added, one of these days).

If you’re running multiple websites, you’ll also want the request_routing plugin. It makes it easy to create routes that look at things like domain (for virtual hosting). Very handy.

Databases

I use MySQL almost exclusively, only because it’s th easiest to setup and administer for small sites. PostgresQL is good for that grown-up, Oracle feeling, but also comes with that Oracle footprint.

With Web Services being all the rage these days, big monolithic databases are looking more and more like they’re more trouble than they’re worth. What’s wrong with nimble, embedded DBS? And sure, tables work great for accounting, but if you want that juicy XQuery goodness, BDB XML is the new hotness.

Administration

So you’ve got your Google-killing website writen, tested, validated, and checked-in. Now you actually need to get it on the IntarWeb. First you need a webserver (what, you want Rails to do everything?). I’ve used Apache for many many moons, but recently made the switch to Lighttpd, and haven’t looked back. With memory usage less than one-tenth of Apache, is a must for shared/leased hosts where memory is scarce. It supports virtual hosting, SSL, FastCGI, rewrite/redirect, anti-deep-linking measures, and all with a config format that’s simple and pleasantly script-like.

Now that we have our website and web server, we need to get the former onto the later. That’s where Capistrano comes in. With a simple Ruby config file, you can easily deploy your website to any number of web/db/application host machines (and then roll it back when you discover some horrific bug). No professional Rails setup should be without it.

The IntarWeb

I have residential DSL services through Speakeasy, on which I run my secondary web server. Speakeasy has good prices and service, especially for geeks who have outrageous demands like static IPs.

Once I hit the critical mass of websites such that I didn’t want to host them on my home server, I looked around for a decent hosting company, and discovered RimuHosting. They provide virtual servers, with your choice of OS, for dirt-cheap (e.g. $20/mo.). In fact, I just upgraded my server (MySQL is such a RAM-hog), and they threw in another 32MB free, just because they could. We like free stuff (and companies that aren’t afraid to give it). I recommend highly.

0 comments | Filed Under: | Tags: ruby