Skip to content

Commit

Permalink
Now with README
Browse files Browse the repository at this point in the history
  • Loading branch information
fastfadingviolets committed Feb 1, 2024
1 parent 48beb12 commit 9cb35f6
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 25 deletions.
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Qwertyflip

qwertyflip transforms input files by flipping their characters based on keyboard positions.

You can run it as:

```bash
./qwertyflip <command file> <input file>
```

where `command file` is a file containing a string of comma-separated transforms. The transforms can
be one of `H` for a horizontal keyboard flip, `V` for a vertical keyboard flip, or `+/-N` for a shift
by N positions. So the command `H,-3,V` would flip an input of `1` first horizontally to `0`, then
shift by -3 positions to `7`, then flip vertically to `m`.

Output is produced to standard out.
41 changes: 28 additions & 13 deletions flip/flip.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ const (
ROWS = 4
)

func NewFlipper() Flipper {
flipper := Flipper{
func NewFlipper() *Flipper {
flipper := &Flipper{
keyboard: "1234567890qwertyuiopasdfghjkl;zxcvbnm,./",
keyMap: make(map[rune]int),
builder: strings.Builder{},
Expand Down Expand Up @@ -77,18 +77,33 @@ func (f *Flipper) Shift(places int, line string) string {
return f.builder.String()
}

func (f *Flipper) RunCommand(command, line string) (string, error) {
components := strings.Split(command, ",")
for _, component := range components {
if component == "H" {
line = f.HorizontalFlip(line)
} else if component == "V" {
line = f.VerticalFlip(line)
} else if places, err := strconv.Atoi(component); err == nil {
line = f.Shift(places, line)
type flipperFunction func(string) string

type Transform []flipperFunction

func (f *Flipper) ParseCommand(command string) (Transform, error) {
parts := strings.Split(command, ",")
retval := make([]flipperFunction, len(parts))
for i, part := range parts {
if part == "H" {
retval[i] = f.HorizontalFlip
} else if part == "V" {
retval[i] = f.VerticalFlip
} else if places, err := strconv.Atoi(part); err == nil {
retval[i] = func(line string) string { return f.Shift(places, line) }
} else if part == "" {
// just in case there's a trailing comma or similar
retval[i] = func(line string) string { return line }
} else {
return "", fmt.Errorf("%s is an invalid command", component)
return nil, fmt.Errorf("%s is an invalid command", part)
}
}
return line, nil
return retval, nil
}

func (t Transform) Apply(line string) string {
for _, funct := range t {
line = funct(line)
}
return line
}
22 changes: 21 additions & 1 deletion flip/flip_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,16 +86,36 @@ func TestCommands(t *testing.T) {
{"asdf", "V,-3"}: "890q",
{"3 Dragons?", "V,-8,H"}: "h Dt84;c7?",
{"ミaカbサc", "-28,H"}: "ミ,カ4サ6",
{"1", "H,-3,V"}: "m",
{"1", ""}: "1",
}
for test, expected := range tests {
t.Run(test.line+"_"+test.command, func(t *testing.T) {
result, err := flipper.RunCommand(test.command, test.line)
transform, err := flipper.ParseCommand(test.command)
if err != nil {
t.Fatal(err)
}
result := transform.Apply(test.line)
if result != expected {
t.Fatalf("Expected %s got %s", expected, result)
}
})
}
}

func TestBadCommands(t *testing.T) {
flipper := flip.NewFlipper()
tests := []string{
"HOORAY",
"H,V,T",
"-30,-3f",
}
for _, test := range tests {
t.Run(test, func(t *testing.T) {
_, err := flipper.ParseCommand(test)
if err == nil {
t.Fatalf("Expected %s to error but it didn't", test)
}
})
}
}
19 changes: 8 additions & 11 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,18 @@ import (
"github.com/fastfadingviolets/qwertyflip/flip"
)

func getCommand(fromFile string) (string, error) {
func getTransform(flipper *flip.Flipper, fromFile string) (flip.Transform, error) {
cmdFile, err := os.Open(fromFile)
if err != nil {
return "", fmt.Errorf("Unable to open command file %s: %v", fromFile, err)
return nil, fmt.Errorf("Unable to open command file %s: %v", fromFile, err)
}
defer cmdFile.Close()
bytes, err := io.ReadAll(cmdFile)
if err != nil {
return "", fmt.Errorf("Unable to read command file %s: %v", fromFile, err)
return nil, fmt.Errorf("Unable to read command file %s: %v", fromFile, err)
}
return strings.TrimSpace(string(bytes)), nil
cmdString := strings.TrimSpace(string(bytes))
return flipper.ParseCommand(cmdString)
}

func main() {
Expand All @@ -29,13 +30,13 @@ func main() {
os.Exit(1)
}
commandFile, inputFile := os.Args[1], os.Args[2]
command, err := getCommand(commandFile)
flipper := flip.NewFlipper()
transform, err := getTransform(flipper, commandFile)
if err != nil {
fmt.Fprint(os.Stderr, err)
os.Exit(1)
}

flipper := flip.NewFlipper()
file, err := os.Open(inputFile)
if err != nil {
fmt.Fprintf(os.Stderr, "Unable to open input file %s: %v", inputFile, err)
Expand All @@ -44,11 +45,7 @@ func main() {
defer file.Close()
scanner := bufio.NewScanner(file)
for scanner.Scan() {
line, err := flipper.RunCommand(command, scanner.Text())
if err != nil {
fmt.Fprint(os.Stderr, err)
os.Exit(1)
}
line := transform.Apply(scanner.Text())
fmt.Println(line)
}
}

0 comments on commit 9cb35f6

Please sign in to comment.