Thursday, September 29, 2011

The Bowling Game Kata in PHP

I did the famous Bowling Game Kata and converted it from Java to PHP, and used PHPUnit for unit tests, and thought I'd share my code for anyone who wants to see it.

If you run the tests like:
 $ phpunit --testdox BowlingTest.php
you should see the tests all pass like:

    Bowling
       [x] Should roll gutter game
       [x] Should roll all ones
       [x] Should roll one spare
       [x] Should roll one strike
       [x] Should roll perfect game
 <?php 
      
 class Game
 { 
   private $rolls = array();
  
   public function roll($pins) {
     $this->rolls[] = $pins;
   } 
  
   public function score() {
     $score = 0;
     $rollsMax = count($this->rolls);
     $firstInFrame = 0;
  
     for ($frame = 0; $frame < 10; $frame++) {
       if ($this->isStrike($firstInFrame)) {
         $score += 10 + $this->nextTwoBallsForStrike($firstInFrame);
         $firstInFrame++;
       } else if ($this->isSpare($firstInFrame)) {
           $score += 10 + $this->nextBallForSpare($firstInFrame);
           $firstInFrame += 2;
       } else {
         $score += $this->twoBallsInFrame($firstInFrame);
         $firstInFrame += 2;
       }
     }
  
     return $score; 
   } 
  
   public function nextTwoBallsForStrike($firstInFrame) {
     return $this->rolls[$firstInFrame + 1] + $this->rolls[$firstInFrame + 2];
   }

   public function nextBallForSpare($firstInFrame) {
     return $this->rolls[$firstInFrame + 2];
   } 
  
   public function twoBallsInFrame($firstInFrame) {
     return $this->rolls[$firstInFrame] + $this->rolls[$firstInFrame + 1];
   }

  
   public function isStrike($firstInFrame) {
     return $this->rolls[$firstInFrame] == 10;
   }

   public function isSpare($firstInFrame) {
     return $this->rolls[$firstInFrame] + $this->rolls[$firstInFrame+1] == 10;
   }

   public function rollSpare() {
     $this->roll(5);
     $this->roll(5);
   }
 }


 class BowlingTest extends PHPUnit_Framework_TestCase {
   private $g;

   public function setUp() {
     $this->g = new Game;
   }

   /**
    * @test
    */
   public function Should_roll_gutter_game() {
     $this->rollMany(20, 0);
     $this->assertEquals(0, $this->g->score());
   }

   /**
    * @test
    */
   public function Should_roll_all_ones() {
     $this->rollMany(20, 1);
     $this->assertEquals(20, $this->g->score());
   }

   /**
    * @test
    */
   public function Should_roll_one_spare() {
     $this->g->rollSpare();
     $this->g->roll(3);
     $this->rollMany(17, 0);
     $this->assertEquals(16, $this->g->score());
   }

   /**
     * @test
    **/
   public function Should_roll_one_strike() {
     $this->rollStrike();
     $this->g->roll(3);
     $this->g->roll(4);
     $this->rollMany(16, 0);
     $this->assertEquals(24, $this->g->score());
   }

   /**
    * @test
    **/
   public function Should_roll_perfect_game() {
      $this->rollMany(12, 10);
      $this->assertEquals(300, $this->g->score());
   }

   public function rollMany($n, $pins) {
     for ($i = 0; $i < $n; $i++) {
         $this->g->roll($pins);
     }
   }

   public function rollStrike() {
     $this->g->roll(10);
   }
 }
 

Sunday, September 18, 2011

Creating Code Snippets for any Programming Language

A snippet is a piece of often-typed text (for loops, function definitions, etc.) that you can insert into your document using a trigger word followed by a [Tab]. The snipMate plugin for Vim gives it TextMate style snippet creation abilities for literally any programming language you happen to use. It comes with many default snippets and you can easily tweak them or create your own.

The bottom line is that snipMate will save you a ton of time and is far more powerful than simple code-completion. Some people spend a lot of money on individual IDEs that only work with one or two languages. In this article I will show examples of how Vim can create powerful snippets in C, PHP, Python, Ruby, JavaScript, HTML, and more.

The perfect first example of snipMate's capabilities is generating a for loop by typing nothing more than:
 for[Tab]
Which expands to:
 for (i = 0; i < count; i++) { 
     // code
 }
If you were editing a C language file, anyway. The snipMate plugin is context sensitive, based off of the file type you're editing. For example, if you were editing a PHP file instead, then typing for[Tab] would have produced a PHP for loop:
 for ($i = 0; $i < count; $i++) {
     // code...
 }
What's more, is after expanding to a full for loop it then places your cursor on the first likely edit point - in this case it places your cursor on the word "count" and puts Vim in SELECT mode so you cans start typing to replace it with another word such as "$max", or whatever you require. If you don't want to change the selected word just hit [Tab] without changing it. Typing [Tab] again jumps you to the next edit point, which in this case goes back to the first "$i" in the loop. From there, if you were to type x, it would replace all the $i's in the loop with $x's. Typing [Tab] from there will jump your cursor to the "++" in the "$x++", in case you wanted to change it to something else like "+=2". Typing [Tab] one last time will take you down to the "// code" line. You get the picture.

To scroll backwards, use [Shift+Tab], as you might expect.

You can even enbable multiple filetypes at the same time in Vim by chaining them with dots. For example:

    :set ft=php.html

Will let you use both the PHP and HTML snippets on the file you're editing.

How does this work? Well, behind the scenes there are snippet files. In your ~/.vim/snippets/ directory exists the files: c.snippets (for C code), php.snippets (for PHP code), and so on. The plugin knows what filetype you're editing and then loads the corresponding snippet file based on the prefix of the file name. So if you're editing a PHP file, it looks in the snippets directory with file names starting with "php".

This means you can easily create your own custom additions. For example, to create more PHP snippets, you could either add them to the existing php.snippets file, or better yet, create your own new file called "php-mine.snippets". In it, you input snippets that don't come with the default snippets file. For example, I really wanted to be able to just type th[Tab] to create $this->. So in php-mine.snippets, I made the snippet:
 snippet th
     $this->${1}
It's important that you insert actual Tabstops (\t) when you indent in the snippets file. In Vim, typing Ctrl+v Tab will insert a real tabstop.

The "${1}" in the snippet indicates to snipMate where you want the cursor to jump to after the snippet expands. In the above example, I'm telling it to land directly after the "->". To tell it where to jump when a user starts pressing [Tab] you simply place it where you want and give it the corresponding number. For example: "${2}", "${3}", etc. In order to highlight certain text when your cursor jumps there, then add a colon (:) after the number followed by the text to select: ${2:foo} will jump your cursor to the string "foo", and highlight it.

Note that if you create multiple snippets with the same name, then Vim will prompt you with a drop down selection list to chose from.

Another PHP snippet you might create is:
 snippet substr
     substr(${1:string $string}, ${2:int $start} ${3:[, int $length]})
Which expands to:

    substr(string $string, int $start [, int $length])

This is useful if you often forget the parameters certain functions take.

I also like to create another snippets file called "php-unit.snippets" which contains my PHPUnit framework snippets. In here, I have snippets like:
 snippet test
     /**
     * @test
     **/
     public function ${1:}() {
         ${2:}
     }${3:}
Which, typing test[tab], expands to:

    /**
    * @test
    **/
    public function () {
    
    }

A more involved example is my getMockBuilder() method snippet:
 snippet getmockbuilder
     ${8:}$this->getMockBuilder('${1:string $OriginalCLassName}')
         ->setMethods(${2:array $methods})
         ->setConstructorArgs(${3:array $args})
         ->setMockClassName(${4:string $name})
         ${5:->disableOriginalConstructor(})
         ${6:->disableOriginalClone()}
         ${7:->disableAutoload()}
         ->getMock();
Expands to, when you type getmockbuilder[Tab]:

    $this->getMockBuilder('string $OriginalCLassName')
              ->setMethods(array $methods)
              ->setConstructorArgs(array $args)
              ->setMockClassName(string $name)
              ->disableOriginalConstructor()
              ->disableOriginalClone()
              ->disableAutoload()
              ->getMock();


Tip: To easily search through all the existing snippets of a .snippets file, type this search query in Vim:

     /snippet \zs.*

Some useful Python snippets:
    import             = imp[tab]
    function template  = def[tab]
    for loop           = for[tab]
(Also see the Python code-completion plugin for Vim I wrote called Pydiction.)

Some other useful PHP snippets include:
    php           = <?php  ?>
    echo          = ec[tab] 
    fun           = public function FunctionName() ...
    foreach       = foreach[tab]
    if            = if (/* condition */) { ...
    ife           = if/else
    else          = else { ...
    elseif        = elseif () { ...
    switch/case   = switch[tab]
    case          = case 'value': ...
    t             = $retVal = (condition) ? a : b;
    while         = wh[tab]
    do/while      = do[tab]
    Super Globals = $_[tab]
    docblock      = /*[tab]
    inc1          = include_once
    req           = require
    req1          = require_once
    $_            = List of $_GET[''], $_POST[''], etc
    globals       = $GLOBALS['variable'] = something;
    def           = define('')
    def?          = defined('')
    array         = $arrayName = array('' => );
    /*            = dockblock: /**  *  **/
    doc_h         = file header docblock
    doc_c         = class docblock
    doc_cp        = class post docblock
    doc_d         = constant docblock
    doc_fp        = function docblock
    doc_v         = class variable docblock
    doc_vp        = class variable post docblock
    doc_i         = interface docblock
Some Bash snippets:
#![tab]
expands to: #!/bin/bash
if[tab]
expands to:

        if [[ condition ]]; then
            #statements
        fi


For JavaScript:
    get[Tab]  =  getElementsByTagName('')
    gett[Tab] =  getElementById('')
    timeout   =  setTimeout(function() {}, 10;
    ...
For Ruby:
    ea      =  each { |e|  }
    array   =  Array.new(10) { |i|  }
    gre     =  grep(/pattern/) { |match|  }
    patfh   =  File.join(File.dirname(__FILE__), *%2[rel path here])
    ...
In a previous article I mentioned using Zen Coding for super fast HTML creation. Well, you can also create HTML with snipMate. This is useful when you need to do something that Zen Coding cannot do. For instance, snipMate has all the HTML Doctypes:
    docts  =  (HTML 4.01 strict)
    doct   =  (HTML 4.01 transitional)
    docx   =  (XHTML Doctype 1.1)
    docxt  =  (XHTML DocType 1.0 transitional)
    docxs  =  (XHTML Doctype 1.0 Strict)
    docxf  =  (XHTML Doctype 1.0 Frameset)
    doct5  =  (HTML 5)

Other HTML snippets include:
    head[tab]
    title[tab]
    script[tab]
    scriptsrc[tab]
    r[tab]
    base[tab]
    meta[tab]
    style[tab]
    link[tab]
    body[tab]
    table[tab]
    div[tab]
    form[tab]
    input[tab]
    textarea[tab]
    mailto[tab]
    h1[tab]
    label[tab]
    select[tab] and opt[tab] and optt[tab]
    meta[tab]
    movie[tab]
    nbs[tab]
That's all for now. If you want to share snippets you made please link to them in the comments section below.

Saturday, September 17, 2011

Zen Coding Your HTML, XML and CSS

Zen Coding is a plugin that works with many editors (Vim, Notepad++, TextMate, etc) for writing HTML (and other structured code) very quickly and efficiently. It's currently at version 0.7 but has been very stable for me.

The plugin expands abbreviated code you write. For example, it can expand:

    html>head>title

to:

    <html>
      <head>
         <title></title>
        </head>
    </html>


Installing the Zen Coding plugin for Vim is as easily as downloading zencoding.vim and installing it to your $HOME/vimfiles/ftplugin/html Directory. Now when you're editing an HTML file (:set ft=html) you can type an abbreviation like:

    html:5

Then, while in either insert or normal mode, type:

    Ctrl+y,

Again, that's ^y followed by a comma. And that should expand the HTML 5 template:

    <!DOCTYPE HTML>
    <html lang="en">
        <head>
            <title></title>
            <meta charset="UTF-8">
        </head>
        <body>
            
        </body>
    </html>


There's a lot more you can do with it such as repeating tags. For example, say you want an unordered list containing four list elements with a class of incrementing items. Typing:

    ul>li.item$*4 Ctrl+y,

Should expand to:

    <ul>
      <li class="item1">_</li>
      <li class="item2"></li>
      <li class="item3"></li>
      <li class="item4"></li>
    </ul>


The "*" multiplies the element before with the number after it. And the "$" gets replaced by an incrementing number. Pretty cool, huh?

Notice the underscore inside the first LI tag. This is where your cursor would end up if you run this expression. Zen coding allows you to have jump to edit points. For example, typing "Ctrl+y n" would jump your cursor to to the next LI element. Typing "Ctrl+y N" jumps to the previous element.

Say you want to add a tag but not nest it. For example:

    <p></p>
    <a href=""></a>

Then just add a "+" (plus sign) between the tags to separate:

    p+a Ctrl+y,

You can delete any tag you're in by typing: Ctrl+y k

To create any tag with a closing and end tag, just type the name of the tag:

    foo Ctrl+y,

becomes:

    <foo></foo>

To create:

    <script type="text/javascript"></script>

Just type:

    script Ctrl+y,

To make a DIV with an id of "foo": div#foo Ctrl+y,

To create a nested DIVs. You could, for example type:

    div#foo$*2>div.bar Ctrl+y,

Which would expand to:

    <div id="foo1">
      <div class="bar">_</div>
    </div>
    <div id="foo2">
      <div class="bar"></div>
    </div>


To create tags that close themselves, such as a BR tag:

    br Ctrl+y,

Becomes:

    <br />

To comment out a block of HTML, just move your cursor to the start of the block of HTML and type: Ctrl+y/

If you visually select the block and type Ctrl+y, it will prompt for a tag to wrap the block inside of. You can even enter expressions here to wrap text into HTML. For example, if you had the text:

    line1
    line2
    line3

You could highlight it and type Ctrl+y, ul>li* to convert it to:

    <ul>
      <li>line1</li>
      <li>line2</li>
      <li>line3</li>
    </ul>


You can also apply "filters" at the end of your expressions. For example, adding "|e" will escape your HTML output so that >'s become <'s and so on. So typing a|e Ctrl+y, expands to:

    &lt;a href=""&gt;&lt;/a&gt;

Another filter called "|c" adds HTML comments to important tags, such as tags with ID and/or classes. There's even a HAML filter.

I'll leave you with one more neat thing you can do with Zen Coding. You can add text to your expressions that will be placed in the corresponding position. For example:

    p>{Click }+a{here} Ctrl+y,

Expands to:

    <p>
      Click <a href="">here</a>
    </p>


Enjoy!

Friday, September 16, 2011

Refactoring with Vim Macros

Automation is what computers do best but we often forget to take advantage of this fact. I don't know about you but I love to take shortcuts when it gets me to the same place. In practice though, it often takes a little extra work up front, but the small amount of effort comprises the majority of the end result.

There are some refactoring commands that you may wish to repeat in the Vim editor but don't want to make a permanent mapping for because they're only needed temporarily for the current file. And a complicated regular expression would take you too long to get right - especially with Vim's non-standard regex engine - and you may not feel it safe to run even if you did manage to figure it out.

Fortunately, Vim also supports macros. Knowing just the Vim commands that you already know, plus a couple of commands to record and play them, you can create powerful macros with very little effort.

To record a macro in Vim, type qq to begin recording, followed by the series of commands to record, then "q" to stop recording. You then type @q to execute the recorded macro.

Let's start with a very simple example. Say you have a file with a bunch of lines:

    line1
    line2
    line3
    line4
    ...

and you want to change the first letter of each line to be a capital letter. You might normally do this all manually by going to the beginning of each line and typing ~ (tilde in vim toggles the case of the character under the cursor). Then you might type j repeatedly to scroll down to each line and then type . to repeat the command. I've seen people do stuff like this on lines with 50+ lines and they just sit there like a robot typing the same thing over and over. Well, it doesn't have to be that way. Instead, you could just go to line1 and type:

    qq0~j<ESC>q

That will run the command on just the current line number and position you to the next line so you can easily run the macro. Note that the 0 (zero) I added to the macro is there to jump to the beginning of the line so we always only capitalize the first letter. Now you're ready to repeat the macro on the rest of the lines by typing:

    3@q

The '3' is for the number of times to repeat the macro.

As another example say you need to edit an PHP file that has a bunch of ugly, yet similar, lines like:

    if (@$FOO) someFunction($foo);

and you want to refactor these lines to be like:

    if (isset($foo) && !empty($foo)) {
      someFunction($foo);
    }


to do this, you could type the following (Don't worry if you don't understand it yet, I'll break it down in a minute):

  0f@xyeiisset(<ESC>f)i) && !empty(<ESC>pa)<ESC>la {<ENTER><ESC>o}<ESC>

so now all you need to do to this record it is add two q's to the beginning and one q to the end, like so:

    qq0f@xyeiisset(<ESC>f)i) && !empty(<ESC>pa)<ESC>la {<ENTER><ESC>o}<ESC>q

Now you can put your cursor anywhere on a line containing the if statement you want to refactor and type @q and it will run the macro. To repeat the macro, go to another line and type @@.

Okay, let's break down the command. It may need to be tweaked depending on your Vim setup, but on my set up it works like this:

    qq begins recording
    0 jumps to the beginning of the line
    f@ jumps to the @ sign.
    x deletes the @ sign
    ye yanks from the cursor to the end of the word (copies $foo)
    i puts you in INSERT mode
    isset( inserts the text "isset("
    <ESC> escapes you back to normal mode
    f) jumps to to the closing parenthesis
    i) && !empty( inserts the text ") && !empty("
    <ESC> escapes you back to normal mode
    p pastes the text "$foo"
    a) inserts the closing parenthesis
    <ESC> escapes you back to normal mode
    la moves your cursor passed the ")" and into insert mode
    { inserts the opening brace
    <ENTER< inserts a newline, pushing "somefunc($foo)" to the next line
    <ESC> escapes you back to normal mode
    o jumps your cursor to the next line and puts you in insert mode
    } inserts a closing brace (which should auto-indent depending on your setup)
    <ESC> escapes you back to normal mode
    q ends recording

This may seem intimidating on first glance and make you think it's more trouble than it's worth but the beauty of Vim is how quickly you can type commands. You just need to try it a few times to get the hang of it, trust me.

In the above examples I used qq to begin recording. This is just a convention for single macros. You can actually store multiple macros at the same time by storing them in different registers. For example qa begins recording to the register a, which you can then run with @a. You could then create another macro with qb and run with @b, and so on.

You can even run a macro on a specific range of lines, say 20 to 30, by doing:

    :20,30norm! @q

Similarly, you could visually select just the lines you want to run the macro on and then type"

    :norm @q

If you remember this simple strategy of recording each series of commands you plan to repeat, then you're golden. If you're going to have to type the commands either way, then recording them is very little effort compared to manually typing the commands over and over.

Friday, September 9, 2011

Readability Counts

In 2006, psychologist Daniel Oppenheimer won an Ig Nobel Prize for his research paper "Consequences of Erudite Vernacular Utilized Irrespective of Necessity." He researched vocabulary used in everything from resumes to academic essays, and found that the easier the texts were to read, the higher the readers judged the author's intelligence. This included anything that made the text hard to read, including "big" words and even the font type used.

It helps me to remember that coding is explaining. And not just to the computer, but to yourself and to others.

The nice thing is that you don't have to write perfect code (which is impossible anyway). It just needs to be understandable to you and others. If you can write code simply so that everyone can understand it, then you will come across as a much better programmer than you otherwise would.

The cleaner your code becomes the more side-benefits you will also notice such as having less fatigue when working with it and having less bugs!

If you run the python prompt and enter:

    >>> import this

It will output "The Zen of Python" message by Tim Peters:

     Beautiful is better than ugly.
     Explicit is better than implicit.
     Simple is better than complex.
     Complex is better than complicated.
     Flat is better than nested.
     Sparse is better than dense.
     Readability counts.
     Special cases aren't special enough to break the rules.
     Although practicality beats purity.
     Errors should never pass silently.
     Unless explicitly silenced.
     In the face of ambiguity, refuse the temptation to guess.
     There should be one-- and preferably only one --obvious way to do it.
     Although that way may not be obvious at first unless you're Dutch.
     Now is better than never.
     Although never is often better than *right* now.
     If the implementation is hard to explain, it's a bad idea.
     If the implementation is easy to explain, it may be a good idea.
     Namespaces are one honking great idea -- let's do more of those!


It's pretty sad that we still need to remind each other that readability counts (which was pointed out in the May of 2010 "Zen of Python" episode of the "From Podcast Import Python" podcast).

Sometimes the problem is that the code author has yet to read a book on how to write readable code.  But they are definitely out there.

A book written in the 1970's by Brian Kernighan, a little before I was even born, entitled "The Elements of Programming Style" spoke of how the best documentation for a computer program is a clean structure. It also helps if the code is well formatted--with good mnemonic identifiers and labels. And a smattering of enlightening comments.

And again in 1999, Brian Kernighan coauthored another great book with Rob Pike called "The Practice of Programming" and outlined that the main principles are: "Simplicity," which keeps programs short and manageable; "Clarity," which makes sure they are easy to understand, for people as well as machines; "generality," which means they work well in a broad range of situations and adapt well as new situations arise; and "automation," which lets the machine do the work for us.

A few other seminal works, such as "The Pragmatic Programmer: From journeyman to master", Code Complete: A practical handbook of software construction", and of course Bob Martin's "Clean Code: A handbook of agile software craftsmanship", all go into great detail on how to write readable and maintainable code.

From my experience, a general rule is if you're looking at a piece of code and all you can say about it is "Boy, this sure is convoluted", then it's probably not clean code. If you can understand the code right away, it may or may not be well-written; perhaps you're just used to reading poorly written code. However, if it seems like the code is so nice that it actually gives you a good feeling -- or at least doesn't give you a headache from squinting -- then it's clearly readable code.

A few of the main guidelines for writing readable code are:

     - Your functions / classes should be doing only one thing each.
     - Your variable names should not require comments
     - Use adequate whitespace and consistent indentation.

There are many more things you can do, and that differ between a normal code base and when designing APIs, and I refer you to the aforementioned books.

References:
59 Seconds: Change your life in under a minute
Science Daily
From Python Import Podcast

Saturday, September 3, 2011

Better Than Grep

UPDATE: Also check out the_platinum_searcher, which runs even faster than ack.

I've been using ack instead of grep for about four years now and I'm still loving it. It has saved me countless time and energy searching through large code bases and miscellaneous files and directories. Everyone who has ever used grep knows how useful and necessary a tool it is, so anything that might potentially be better than it is certainly worth a try.

Description from ack's home page: ack is a tool like grep, designed for programmers with large trees of heterogeneous source code. ack is written purely in Perl, and takes advantage of the power of Perl's regular expressions.

So what exactly makes ack better than grep? The main thing for me is that it requires much less typing to do common powerful operations. It's designed to replace 99% of the uses of grep. It can help you avoid complex find/grep/xargs messes and the like.

On the very surface, the two commands print lines that match a pattern:

    $ grep rkulla /etc/passwd
    rkulla:x:1000:1000:Ryan Kulla,,,:/home/rkulla:/bin/bash
    $ ack rkulla /etc/passwd
    rkulla:x:1000:1000:Ryan Kulla,,,:/home/rkulla:/bin/bash

In order to get grep to print with colored output you need to add --color. Which you could just make a shell alias to do implicitly. Ack will show colors automatically.

Where ack really shines is that it searches recursively through directories by default, while ignoring .svn, .git, and other VCS directories. So instead of typing something silly like:

    $ grep foo $(find . -type f | grep -v '\.svn')

You could simply type this instead:

    $ ack foo

ack automatically ignores most of the crap you don't want to search, such as binary files.

Also, instead of typing shell globs like *.txt to search just text files, ack uses command line arguments such as --text. If you were to grep for 'foo' in *.txt, it would only consider files that ended with exactly .txt, whereas ack would consider .txt, .TXT. .text and even text files that don't have file extensions such as README. Conversely, you could type --notext to search for everything except text files. To see a list of the different file type arguments and which file types they affect type:

    $ ack --help=types
    --[no]html .htm .html .shtml .xhtml
    --[no]php .php .phpt .php3 .php4 .php5 .phtml
    --[no]ruby .rb .rhtml .rjs .rxml .erb .rake
    --[no]shell .sh .bash .csh .tcsh .ksh .zsh
    --[no]yaml .yaml .yml
    ...

This is obviously incredibly convenient for any user. It's especially convenient for someone like a System Administrator who may be tasked with searching through all the "Ruby" files on a system, yet he might not know all about all the different file extensions that Ruby might use. With ack, all he has to remember is --ruby.

Use -a to search all files.

Ack will also give you more readable output than grep. It places things onto newlines so you can more easily discern the file name, line number, and pattern matches.

Because ack is written in Perl, it can take advantage of some of the language's features, such as proper Perl Regular Expressions and literal quoting. You can use -Q or --literal with ack to quote literally, similar to q() in Perl. From the ack-grep man page:

    If you're searching for something with a regular expression metacharacter, most often a period in a filename or IP address, add the -Q to avoid false positives without all the backslashing.

    Use ack-grep to watch log files Here's one I used the other day to find trouble spots for a website visitor. The user had a problem loading troublesome.gif, so I took the access log and scanned it with ack-grep twice.

        $ ack-grep -Q aa.bb.cc.dd /path/to/access.log | ack-grep -Q -B5 troublesome.gif

    The first ack-grep finds only the lines in the Apache log for the given IP. The second finds the match on my troublesome GIF, and shows the previous five lines from the log in each case.


You can do a lot of other cool stuff with ack that I won't go into because if I haven't convinced you to use ack by now, I never will. Consult the documentation for ack-grep if you like what you see.

Followers