Gray Soft

The programming blog of James Edward Gray II (JEG2).
  • 1

    DEC
    2006

    What is the Ruby Talk Gateway?

    [Update: The Ruby Gateway was retired in June of 2011. Our community simply grew past the point were we needed to combine the various groups, in my opinion.]

    The Ruby community makes use of both email and Usenet communication, in addition to other resources. The primary mailing list is Ruby Talk and the primary Usenet group is comp.lang.ruby. These two services are joined by the Ruby Gateway.

    In 2001 The Pragmatic Programmers wrote the initial version of the Ruby Gateway to ferry messages back and forth between these two resources. Emails sent to Ruby Talk are posted as Usenet messages and Usenet posts are forwarded to Ruby Talk by the Gateway. The Gateway has had a few guardians and code changes since then, but the functionality remains the same.

    I'm am the current caretaker of the Ruby Gateway. Highgroove Studios generously provides hosting for it and I monitor the system for problems. I also wrote the current version of the Gateway.

    You are free to report Gateway problems for me to look into. Before you do though, please read the following notes:

    Read more…

  • 7

    NOV
    2006

    Doing It All!

    I'm not really in the habit of putting non-code content on this blog, but more than one person asked me the same question at RubyConf. If people really want to know, I'll try to answer. Paraphrasing, the question was:

    How do you keep up with so many Ruby projects?

    First, this question surprised me. Do I really do that much? If you just said yes to that, I would like to introduce you to Ryan Davis. He easily doubles my output and his projects are wicked complex compared to mine.

    That doesn't answer the question though.

    In short, I do as much as I possibly can with the time I have. The truth is that I would like to do a lot more. I turn down at least as many damn cool Ruby projects as I accept because I'm a wimp and not willing to give up my sleep. There are so many crazy cool Ruby projects out there that I would love to be a part of. There just aren't enough hours in the day.

    I guess I still didn't answer the question.

    The question was "How…" and the answer to that is actually trivial. Masayoshi Takahashi summed it up with a single slide in his presentation at RubyConf:

    Read more…

    In: Non-code | Tags: Process | 0 Comments
  • 1

    OCT
    2006

    I Just Want One Character!

    Every so often a person asks the question on Ruby Talk, "How can I get just one character from the keyboard (without needing the user to hit return)?" Everyone is always quick to post solutions, but sadly there are some issues with almost every one of them.

    The general consensus is that this is a tough problem to solve correctly. I say that's the exact reason to let HighLine handle this for you:

    #!/usr/bin/env ruby -w
    
    require "highline/system_extensions"
    include HighLine::SystemExtensions
    
    print "Enter one character:  "
    char = get_character
    puts char.chr
    

    That doesn't look too tough, does it?

    What's terrific about this solution is that under-the-hood HighLine will check your platform and libraries and then try to use the solution that makes the most sense for your environment. The code is really pretty robust too, because people a lot smarter than me have been sending in patches for over a year, slowly eliminating all of those tricky edge cases.

    As you can see, I've split this functionality of HighLine into a separate module so you don't even need to load the full HighLine system. This was done just because this is such a real and common problem. This section of HighLine is one pure Ruby file, so feel free to vendor it if the external dependency is an issue.

    Read more…

  • 2

    AUG
    2006

    RegexpChallenge

    Just recently I have been working with two different people to improve their regular expression skills. To help me in this endeavor, I built a trivial little script we have been using in IRb. To get started, you construct a new challenge object and add a couple of challenges:

    >> reg_chal = RegexpChallenge.new
    No challenges.
    => 
    >> reg_chal.challenge("Gray, James", "James", "The names can vary.")
    => nil
    >> reg_chal.challenge("abbbbbbbc bc", 10)
    => nil
    >> reg_chal.challenge( "    \n\t  ", nil,
    ?>                     "We want to test for non-space data." )
    => nil
    >> reg_chal.challenge( "cogs 9, widgets 12, ...", "12",
    ?>                     "The numbers can vary." )
    => nil
    >> reg_chal.challenge( "I'm a simple sentence, with words.",
    ?>                     %w[I'm a simple sentence with words] )
    => nil
    

    You can ask for challenges to see what you would like to solve:

    >> reg_chal.challenges
    Challenge #0:
       Input:  "Gray, James"
      Output:  "James"
        Note:  "The names can vary."
    Challenge #1:
       Input:  "abbbbbbbc bc"
      Output:  10
    Challenge #2:
       Input:  "    \n\t  "
      Output:  nil
        Note:  "We want to test for non-space data."
    Challenge #3:
       Input:  "cogs 9, widgets 12, ..."
      Output:  "12"
        Note:  "The numbers can vary."
    Challenge #4:
       Input:  "I'm a simple sentence, with words."
      Output:  ["I'm", "a", "simple", "sentence", "with", "words"]
    => nil
    

    Read more…

  • 30

    JUL
    2006

    PStore Meets YAML

    I love the PStore standard library. It's a very graceful interface to get some fairly robust serialized mini-database handling in just a few lines. With it you get:

    1. Transactions with commit and rollbacks (automatic on exception).
    2. File locking, shared and exclusive.
    3. Multiprocessing safety.

    PStore does even more, including some file mode checking and MD5 hashing to avoid unneeded writes, but the above are the major selling points for me.

    Now, if I had to level any one complaint at PStore, it would be that because it uses Marshal under the hood it doesn't create files you can easily browse or tweak by hand. (Marshal is a feature, don't get me wrong. It's fast, which is very helpful.) Sometimes though I want PStore protection with the YAML file format.

    I'm embarrassed to admit that I use to use a hack for this:

    require "pstore"
    require "yaml"
    class PStore; Marshal = YAML; end
    

    That just redefines the Marshal constant in a scope that should only alter PStore. The library only uses dump() and load() and those methods work the same with Marshal and YAML.

    Read more…

  • 29

    JUL
    2006

    YARV Looking Promising, James's C is Not

    I participated in the ICFP programming contest last weekend with a group of friends. We had a great time with the event and learned a ton. I thought I should share two interesting insights with others that might appreciate them.

    First, YARV looks very promising for some general speed increases in Ruby. If you are not familiar with YARV, that's the virtual machine that will run Ruby 1.9. During the contest, we ran into some performance issues with our Ruby solution and after we had optimized all we could think of, we decided to try running our entry on the experimental YARV VM to see if it was faster there. Good news: it was a lot faster.

    Please do not take these numbers as anything more than very non-scientific observations, but we did notice a huge speed increase on YARV. We were reliably waiting around 15 minutes for one section of our program to run on Ruby 1.8.4, but when we introduced YARV the same section generally ran in just under seven minutes. You heard me right there, it was over twice as fast. I think that's very promising news for the future of Ruby.

    Read more…

  • 16

    JUL
    2006

    String Has Other Methods Besides =~/match() and sub()

    Ask anyone who knows me and they will tell you I'm a huge fan of regular expressions. I use them all the time and my FasterCSV library is a regular expression powered parser. However, even I know they are not for everything, and lately I keep running into almost comical examples of misuse. Here are some of my favorites.

    First, we have:

    str =~ /=/
    

    That snippet is like calling for a military escort (the regular expression engine) to see you safely to the grocery store down the block. That's fun, but probably overkill. In this case, a call to include?() will do the trick:

    str.include?("=")
    

    That may be more like riding your bike to the grocery store, but it gets the job done and is a bit faster to boot.

    Funny example number two. I've seen this before:

    str =~ /\Aquit\Z/
    

    Again, the regular expression engine appreciates the love, but you really just want ==:

    str == "quit"
    

    Even for some of the fancier stuff, you don't need a full blown regular expression. For example, this:

    Read more…

  • 8

    JUL
    2006

    The Books are Wrong About Logger

    I've read several books that introduced the standard Logger library and they all agree on one thing: you can't customize the output. That's so last version in thinking! Behold…

    Here's a trivial Logger script, showing basic functionality:

    #!/usr/bin/env ruby -w
    
    require "logger"
    
    def expensive_error_report
      sleep 3  # Heavy Computation Simulation (patent pending)
      "YOU BROKE IT!"
    end
    
    log       = Logger.new(STDOUT)
    log.level = Logger::INFO  # set out output level above the DEBUG default
    
    log.debug("We're not in the verbose debug mode.")
    log.info("We do see informative logs though.")
    if log.error?  # check that this will be printed, before waste time
      log.error(expensive_error_report)
    end
    

    If you run that you will see:

    I, [2006-07-08T11:17:19.531943 #340]  INFO -- : We do see informative logs though.
    E, [2006-07-08T11:17:22.532424 #340] ERROR -- : YOU BROKE IT!
    

    Now everyone has always known you can format the date and time display using a strftime() compatible pattern:

    #!/usr/bin/env ruby -w
    
    require "logger"
    
    def expensive_error_report
      sleep 3
      "YOU BROKE IT!"
    end
    
    log                 = Logger.new(STDOUT)
    log.level           = Logger::INFO
    log.datetime_format = "%Y-%m-%d %H:%M "  # simplify time output
    
    log.debug("We're not in the verbose debug mode.")
    log.info("We do see informative logs though.")
    if log.error?
      log.error(expensive_error_report)
    end
    

    Read more…

  • 13

    JUN
    2006

    Do I Need (These Parentheses()?)

    If you came to Ruby via the Learn to Program book or just don't yet have a consistent set of rules for when you do and don't need parentheses in Ruby code, this post is for you.

    I have nothing against Learn to Program, just to be clear. A member of my family is learning Ruby from it and it's going pretty well. I recommend it. However, Chris is a little inconsistent with his use of parentheses in the code samples, and worse, he doesn't really give you a good set of rules to decide when to make the choice. No problem. Let me give you the rules.

    I'm a chess player. In learning chess, you really go through two phases. First, you learn the rules of strategy. These will make you good because the rules are designed to help you avoid common mistakes. Now, to get great, you go through the second phase: learning when to break the strategy rules. Ruby is exactly the same.

    Here's the only rule of strategy you need to learn to get good: methods need parentheses around their arguments.

    Read more…

  • 21

    APR
    2006

    Unit Testers Get More Chicks

    Just recently, a developer I respect very much was caught uttering the this surprising statement: "Unit tests just really aren't my thing." Now, I still respect this developer very much and I can tell you that the person single-handedly created one of my very favorite pieces of software. However, I do think the developer is dead wrong on this point. This is my attempt to change the mind of everyone that thinks similar things about unit testing.

    My belief is that unit testing is for everyone and, in fact, I'll go so far as to say that I believe becoming a test-driven developer is the single best change a programmer can make in their day to day routine. Here are just some of the reasons why:

    • Though counterintuitive, I swear that it makes you code faster. No one tends to believe me on this, but most test-driven developers come to this realization eventually. The reason is simple: you spend much less time debugging the 935 errors from your two hour code sprees.
    • The tests are my memory. My head is too full of all the languages, frameworks, APIs, and family birthdays I am expected to know to remember everything I've ever done on top of that. This week at work I've touched three separate projects all with over 1,000 lines of code. I'm sure I had good ideas when I wrote those lines, but now I doubt I can tell you what they are. My tests can though. They remember so I don't have to. If I go into the code and change something I don't remember was needed or why, my tests will remind me immediately.
    • In team development, my test powered memory even travels to the machines of the other developers! How cool is that? When someone goes into the code and says, "Why on Earth did James do this? We don't need this. I'm going to change that…" my tests will look after my interests for me.
    • I'm a lot more confident in my software. I use to say things like, "I just finished this, so it hasn't been used much yet and probably still has plenty of issues." Now by the time I finish something my tests have been using the heck out of it. I won't kid you and tell you that my software now springs fully formed from the head of my tests, but it definitely comes out farther along the track.
    • Environment changes seldom surprise me anymore. When I move my software to a different box and it can't cope for whatever reason, I not only know the first time I run the tests, I have an excellent idea of exactly where the problem is.

    Read more…