2

Learning Go – Miniblog #7 – Creating Packages | Late Developer

 2 years ago
source link: https://latedev.wordpress.com/2013/01/13/learning-go-miniblog-7-creating-packages/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Learning Go – Miniblog #7 – Creating Packages

January 13, 2013

This carries on from here.

OK, so I have a directory listing function, but what I really want is a list of .CSV files in a particular directory that I can get my putative server to serve as HTML tables. It turned out to be fairly simple to write a function to do this:

func csvlist( dirname string )  ([]string, error) {

    dirf,err := os.Open( dirname )
    if err != nil {
        return nil, err
    }
    defer dirf.Close()

    dir,err := dirf.Readdir(-1)
    if err != nil {
        return nil, err
    }

    var csvfiles []string
    for _,val := range( dir ) {
        if  (! val.IsDir()) && hasCSVExt( val.Name() ) {
            csvfiles = append( csvfiles, val.Name() )
        }
    }

    return csvfiles, nil
}

This is like the directory listing code, but looks for things that are not directories and have a .CSV extension – the code for testing the extension is:

func hasCSVExt( fname string ) bool {
    match,_ := regexp.MatchString( "\\.[Cc][Ss][Vv]$",  fname )
    return match
}

which uses the Go regular expression package to test the last 4 characters of the filename. The csvlist() function returns the CSV file names in a slice, which is a wrapper around a Go array which adds some convenient features.

So far so good, but I would really like to put my server code into a Go package so that I can do things like use the Go unit test framework and build system on it. This turned out to be a slightly fraught thing to do.

The first thing I did was to read this documentation on building Go applications and packages. The source(s) for a package needs to be in a directory called src which would normally (I guess) be in your project root. Within that directory will be subdirectories containing the packages. I intended only to have one package, called csvsrv, so I only needed one sub-directory. Within that subdirectory you put the source files for the package (and any subdirectories you fancy, containing sub-packages). Each source file says the name of the package it belongs to (this seems somewhat redundant to me). For example, I created a utils.go source file, basically containing the two functions above. The first statement in that source file was:

package csvsrv

// rest of code here

saying that this source code was part of the csvsrv package. So my eventual directory structure looked like this (learngo is the project root):

learngo
  src
    csvsrv
      utils.go

As I write more code, I’ll add more files to the csvsrv directory – all the functions in these files will be part of the csvsrv package.

Next thing to do was to set up the GOPATH environment variable which needs to point to the directory that contains the src directory containing the package code (note this is distinct from the GOROOT variable set up during installation). I use bash as my shell on Windows, so I did this:

export GOPATH='c:/users/neilb/home/devel/learngo'

Time to build and install the package! I did this with Go install command:

go install csvsrv

which compiles the package’s source files and places the resulting compiled code in a directory called pkg. I then wrote a simple test program, which I placed in the project root (not in the package source) called ptest.go:

package  main
import "fmt"
import "os"
import "csvsrv"
func main() {
    var err error
    var csvfiles []string
    csvfiles,err = csvsrv.CSVList( os.Args[1] )
    if err != nil {
        fmt.Println( "Error: ", err )
    }
    for _,val := range( csvfiles ) {
        fmt.Printf( "%s\n", val )
    }
}

Notice that I import the csvsrv  package, and that to call the functions in the package I have to use the dot-notation to say things like:

csvsrv.CSVList( os.Args[1] )

I then compiled and ran the program:

go run ptest.go csvdata

where csvdata is the name of a directory containing some CSV data files. And it worked! Hurrah!

One caveat; I may have made it seem that this was all very straightforward to accomplish, but it actually took me a couple of hours to get it it all working. I seem to have a fatal inability to get names right when it’s possible to get things wrong, and the error messages from the Go build system were not always terribly informative, though to be fair the messages from a C or C++ compiler/linker would likely be no better.

Anyway, with that done, I can hopefully start using some good software engineering principles, like writing some unit tests. I wonder how that will go…

Advertisements
Report this ad

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK