Add OnSymlink options: Shallow/Deep/Skip
diff --git a/all_test.go b/all_test.go
index 5232557..8f41734 100644
--- a/all_test.go
+++ b/all_test.go
@@ -73,28 +73,39 @@
 		Expect(t, info.Mode()&os.ModeSymlink).Not().ToBe(0)
 	})
 
-	When(t, "source directory includes a dangling symbolic link, but with option to follow it", func(t *testing.T) {
-		err := Copy("testdata/case03", "testdata.copy/case03", Opts{FollowSymlink: func(string) bool { return true }})
-		Expect(t, err).Not().ToBe(nil)
-	})
+	When(t, "symlink with Opt.OnSymlink provided", func(t *testing.T) {
+		opt := Options{OnSymlink: func(string) SymlinkAction { return Deep }}
+		err := Copy("testdata/case03", "testdata.copy/case03.deep", opt)
+		Expect(t, err).ToBe(nil)
+		info, err := os.Lstat("testdata.copy/case03.deep/case01")
+		Expect(t, err).ToBe(nil)
+		Expect(t, info.Mode()&os.ModeSymlink).ToBe(os.FileMode(0))
 
-	When(t, "source directory includes a symbolic link, but with option not to follow it", func(t *testing.T) {
-		err := Copy("testdata/case06", "testdata.copy/case06-2", Opts{FollowSymlink: func(string) bool { return true }})
+		opt = Options{OnSymlink: func(string) SymlinkAction { return Shallow }}
+		err = Copy("testdata/case03", "testdata.copy/case03.shallow", opt)
 		Expect(t, err).ToBe(nil)
+		info, err = os.Lstat("testdata.copy/case03.shallow/case01")
 		Expect(t, err).ToBe(nil)
-		info, err := os.Lstat("testdata.copy/case06-2/README.md")
-		Expect(t, err).ToBe(nil)
-		Expect(t, int(info.Mode()&os.ModeSymlink)).ToBe(0)
-	})
+		Expect(t, info.Mode()&os.ModeSymlink).Not().ToBe(os.FileMode(0))
 
-	When(t, "source directory includes a symbolic link, but with option to follow it", func(t *testing.T) {
-		err := Copy("testdata/case06", "testdata.copy/case06")
+		opt = Options{OnSymlink: func(string) SymlinkAction { return Skip }}
+		err = Copy("testdata/case03", "testdata.copy/case03.skip", opt)
 		Expect(t, err).ToBe(nil)
+		_, err = os.Stat("testdata.copy/case03.skip/case01")
+		Expect(t, os.IsNotExist(err)).ToBe(true)
+
+		err = Copy("testdata/case03", "testdata.copy/case03.default")
 		Expect(t, err).ToBe(nil)
-		info, err := os.Lstat("testdata.copy/case06/README.md")
+		info, err = os.Lstat("testdata.copy/case03.default/case01")
 		Expect(t, err).ToBe(nil)
-		Expect(t, info.Mode()&os.ModeSymlink).ToBe(os.ModeSymlink)
-		os.RemoveAll("testdata.copy/case06")
+		Expect(t, info.Mode()&os.ModeSymlink).Not().ToBe(os.FileMode(0))
+
+		opt = Options{OnSymlink: nil}
+		err = Copy("testdata/case03", "testdata.copy/case03.not-specified", opt)
+		Expect(t, err).ToBe(nil)
+		info, err = os.Lstat("testdata.copy/case03.not-specified/case01")
+		Expect(t, err).ToBe(nil)
+		Expect(t, info.Mode()&os.ModeSymlink).Not().ToBe(os.FileMode(0))
 	})
 
 	When(t, "try to copy to an existing path", func(t *testing.T) {
@@ -103,7 +114,7 @@
 	})
 
 	When(t, "try to copy READ-not-allowed source", func(t *testing.T) {
-		err := Copy("testdata/case07", "testdata.copy/case07")
+		err := Copy("testdata/case06", "testdata.copy/case06")
 		Expect(t, err).Not().ToBe(nil)
 	})
 
diff --git a/copy.go b/copy.go
index bd339c4..2fdb3ea 100644
--- a/copy.go
+++ b/copy.go
@@ -14,41 +14,25 @@
 	tmpPermissionForDirectory = os.FileMode(0755)
 )
 
-type Opts struct {
-	// FollowSymlink is called with a source path it is found to be a symlink. If
-	// this function returns false, Copy copies the symlink itself. Else, Copy
-	// follows the link.  If this field is not set, Copy never follows symlinks.
-	FollowSymlink func(path string) bool
-}
-
-// Copy copies src to dest, doesn't matter if src is a directory or a file.  An
-// optional arg opts specifies the options to the copy operations.  There can be
-// at most one opts.
-func Copy(src, dest string, opts ...Opts) error {
-	var opt Opts
-	if len(opts) > 0 {
-		if len(opts) > 1 {
-			panic("too many opts")
-		}
-		opt = opts[0]
-	}
+// Copy copies src to dest, doesn't matter if src is a directory or a file.
+func Copy(src, dest string, opt ...Options) error {
+	opt = append(opt, DefaultOptions)
 	info, err := os.Lstat(src)
 	if err != nil {
 		return err
 	}
-	return copy(src, dest, opt, info)
+	return copy(src, dest, info, opt[0])
 }
 
 // copy dispatches copy-funcs according to the mode.
 // Because this "copy" could be called recursively,
 // "info" MUST be given here, NOT nil.
-func copy(src, dest string, opts Opts, info os.FileInfo) error {
-	if info.Mode()&os.ModeSymlink != 0 &&
-		(opts.FollowSymlink == nil || !opts.FollowSymlink(src)) {
-		return lcopy(src, dest, info)
+func copy(src, dest string, info os.FileInfo, opt Options) error {
+	if info.Mode()&os.ModeSymlink != 0 {
+		return onsymlink(src, dest, info, opt)
 	}
 	if info.IsDir() {
-		return dcopy(src, dest, opts, info)
+		return dcopy(src, dest, info, opt)
 	}
 	return fcopy(src, dest, info)
 }
@@ -85,7 +69,7 @@
 // dcopy is for a directory,
 // with scanning contents inside the directory
 // and pass everything to "copy" recursively.
-func dcopy(srcdir, destdir string, opts Opts, info os.FileInfo) (err error) {
+func dcopy(srcdir, destdir string, info os.FileInfo, opt Options) (err error) {
 
 	originalMode := info.Mode()
 
@@ -103,7 +87,7 @@
 
 	for _, content := range contents {
 		cs, cd := filepath.Join(srcdir, content.Name()), filepath.Join(destdir, content.Name())
-		if err := copy(cs, cd, opts, content); err != nil {
+		if err := copy(cs, cd, content, opt); err != nil {
 			// If any error, exit immediately
 			return err
 		}
@@ -112,9 +96,35 @@
 	return nil
 }
 
+func onsymlink(src, dest string, info os.FileInfo, opt Options) error {
+
+	if opt.OnSymlink == nil {
+		opt.OnSymlink = DefaultOptions.OnSymlink
+	}
+
+	switch opt.OnSymlink(src) {
+	case Shallow:
+		return lcopy(src, dest)
+	case Deep:
+		orig, err := os.Readlink(src)
+		if err != nil {
+			return err
+		}
+		info, err = os.Lstat(orig)
+		if err != nil {
+			return err
+		}
+		return copy(orig, dest, info, opt)
+	case Skip:
+		fallthrough
+	default:
+		return nil // do nothing
+	}
+}
+
 // lcopy is for a symlink,
 // with just creating a new symlink by replicating src symlink.
-func lcopy(src, dest string, info os.FileInfo) error {
+func lcopy(src, dest string) error {
 	src, err := os.Readlink(src)
 	if err != nil {
 		return err
diff --git a/options.go b/options.go
new file mode 100644
index 0000000..4053a3f
--- /dev/null
+++ b/options.go
@@ -0,0 +1,26 @@
+package copy
+
+// Options specifies optional actions on copying.
+type Options struct {
+	// OnSymlink can specify what to do on symlink
+	OnSymlink func(p string) SymlinkAction
+}
+
+// SymlinkAction represents what to do on symlink.
+type SymlinkAction int
+
+const (
+	// Deep creates hard-copy of contents.
+	Deep SymlinkAction = iota
+	// Shallow creates new symlink to the dest of symlink.
+	Shallow
+	// Skip does nothing with symlink.
+	Skip
+)
+
+// DefaultOptions by default.
+var DefaultOptions = Options{
+	OnSymlink: func(string) SymlinkAction {
+		return Shallow
+	},
+}
diff --git a/testdata/case06/README.md b/testdata/case06/README.md
deleted file mode 120000
index ea72647..0000000
--- a/testdata/case06/README.md
+++ /dev/null
@@ -1 +0,0 @@
-../case05/README.md
\ No newline at end of file