Skip to content

Commit

Permalink
Add command to create a .md file including the entire contents (#156)
Browse files Browse the repository at this point in the history
  • Loading branch information
spring1843 authored Dec 28, 2024
1 parent 32ff2cd commit f179129
Show file tree
Hide file tree
Showing 19 changed files with 234 additions and 27 deletions.
2 changes: 1 addition & 1 deletion .github/cmd/main.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package main

import "github.com/spring1843/go-dsa/.github/cmd/cmd"
import "github.com/spring1843/go-dsa/.github/cmd/pkg/cmd"

func main() {
cmd.Execute()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import (
"os"
"path/filepath"

"github.com/spring1843/go-dsa/.github/cmd/pkg/problems"

"github.com/spf13/cobra"
)

Expand All @@ -20,7 +22,7 @@ var countRehearsalsCommand = &cobra.Command{
}

count := 0
for _, section := range sections {
for _, section := range problems.OrderedSections {
matches, err := filepath.Glob(filepath.Join(dir, section, "*_test.go"))
if err != nil {
log.Fatalf("Error while globbing: %s", err)
Expand Down
17 changes: 12 additions & 5 deletions .github/cmd/cmd/export_md.go → .github/cmd/pkg/cmd/export_md.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import (
"os"
"path/filepath"

"github.com/spring1843/go-dsa/.github/cmd/pkg/problems"

"github.com/spf13/cobra"
)

Expand All @@ -19,21 +21,26 @@ var exportMDCommand = &cobra.Command{
log.Fatalf("Error finding current directory: %s", err)
}

allFiles := []string{
nonSectionMDFiles := []string{
"README.md",
"preface.md",
"complexity.md",
}
for _, section := range sections {
allFiles = append(allFiles, filepath.Join(section, "README.md"))
}

for _, file := range allFiles {
for _, file := range nonSectionMDFiles {
content, err := os.ReadFile(filepath.Join(dir, file))
if err != nil {
log.Fatalf("Error reading file: %s", err)
}
fmt.Println(string(content))
}

for _, section := range problems.OrderedSections {
parsedSection, err := problems.ParseSection(dir, section)
if err != nil {
log.Fatalf("Error parsing section: %s", err)
}
fmt.Println(parsedSection)
}
},
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"path/filepath"

"github.com/spf13/cobra"
"github.com/spring1843/go-dsa/.github/cmd/pkg/problems"
)

const (
Expand Down Expand Up @@ -39,7 +40,7 @@ var randomChallengeCommand = &cobra.Command{
}

allChallenges := []string{}
for _, section := range sections {
for _, section := range problems.OrderedSections {
matches, err := filepath.Glob(filepath.Join(dir, section, "*_test.go"))
if err != nil {
log.Fatalf("Error while globbing: %s", err)
Expand Down
File renamed without changes.
44 changes: 44 additions & 0 deletions .github/cmd/pkg/problems/parse.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package problems

import (
"errors"
"fmt"
"log"
"os"
"path/filepath"
"regexp"
)

func ParseSection(dir, section string) (string, error) {
content, err := os.ReadFile(filepath.Join(dir, section, "README.md"))
if err != nil {
return "", fmt.Errorf("error reading file: %w", err)
}

preparedContent, err := replaceRehearsal(string(content), dir, section)
if err != nil {
return "", fmt.Errorf("error replacing the rehearsal section in file: %w", err)
}

return preparedContent, nil
}

func replaceRehearsal(input, dir, section string) (string, error) {
rehearsalRegex := regexp.MustCompile(`(?s)(## Rehearsal\n.*?)(\n##|\z)`)

match := rehearsalRegex.FindStringSubmatch(input)
if match == nil {
return "", errors.New("no rehearsal section found")
}

rehearsalContent := match[1]
newRehearsals, err := newRehearsalEntry(rehearsalContent)
if err != nil {
return "", fmt.Errorf("error parsing rehearsal entry: %w", err)
}
if len(newRehearsals) == 0 {
log.Printf("no rehearsals found %s, %s", section, rehearsalContent)
}
replacement := fmt.Sprintf("## Rehearsal\n%s", stringRehearsalEntries(dir, section, newRehearsals))
return rehearsalRegex.ReplaceAllString(input, replacement), nil
}
82 changes: 82 additions & 0 deletions .github/cmd/pkg/problems/rehearsal.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package problems

import (
"fmt"
"os"
"path/filepath"
"regexp"
"strings"
)

type rehearsalEntry struct {
Name string
TestFileName string
SolutionFileName string
}

func (r *rehearsalEntry) String() string {
return fmt.Sprintf("### %s\n", r.Name)
}

/*
newRehearsalEntry parses the rehearsal section of the README.md file that looks like:
## Rehearsal
* [Some Name 1](./problem_test1.go), [Solution](./solution1.go)
* [Some Name 2](./problem_test2.go), [Solution](./solution2.go).
*/
func newRehearsalEntry(input string) ([]rehearsalEntry, error) {
lines := strings.Split(input, "\n")
entries := []rehearsalEntry{}
re := regexp.MustCompile(`\* \[([^\]]+)\]\(\.\/([^\)]+)\), \[Solution\]\(\.\/([^\)]+)\)`)

for _, line := range lines {
line = strings.TrimSpace(line)
if line == "" || strings.HasPrefix(line, "##") {
continue // Skip empty lines and heading lines
}
matches := re.FindStringSubmatch(line)
if len(matches) != 4 {
return nil, fmt.Errorf("invalid line format: %s, %d", line, len(matches))
}

entry := rehearsalEntry{
Name: matches[1],
TestFileName: matches[2],
SolutionFileName: matches[3],
}
entries = append(entries, entry)
}

return entries, nil
}

func stringRehearsalEntries(dir, section string, entries []rehearsalEntry) string {
output := ""
for _, entry := range entries {
output += fmt.Sprintf("\n### %s\n", entry.Name)

testFileContent, err := os.ReadFile(filepath.Join(dir, section, entry.TestFileName))
if err != nil {
output += fmt.Sprintf("Error reading test file: %s\n", err)
continue
}
output += "```GO\n" + string(testFileContent) + "\n```\n"
}

output += "\n## Rehearsal Solutions\n"

for _, entry := range entries {
output += fmt.Sprintf("\n### %s\n", entry.Name)

testFileContent, err := os.ReadFile(filepath.Join(dir, section, entry.SolutionFileName))
if err != nil {
output += fmt.Sprintf("Error reading test file: %s\n", err)
continue
}
output += "```GO\n" + string(testFileContent) + "\n```\n"
}

return output
}
28 changes: 28 additions & 0 deletions .github/cmd/pkg/problems/rehearsal_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package problems

import "testing"

func TestNewRehearsalEntry(t *testing.T) {
input := `## Rehearsal
* [Bubble Sort](./bubble_sort_test.go), [Solution](./bubble_sort.go)
* [Reverse Array In-place](./reverse_inplace_test.go), [Solution](./reverse_inplace.go)
* [Add Two Numbers](./add_two_numbers_test.go), [Solution](./add_two_numbers.go)
* [Find Duplicate in Array](./find_duplicate_in_array_test.go), [Solution](./find_duplicate_in_array.go)
* [Zero Sum Triplets](./zero_sum_triplets_test.go), [Solution](./zero_sum_triplets.go)
* [Product of All Other Elements](./product_of_all_other_elements_test.go), [Solution](./product_of_all_other_elements.go)`

entries, err := newRehearsalEntry(input)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}

if len(entries) != 6 {
t.Fatalf("expected 5 entries, got %d", len(entries))
}

strOutput := stringRehearsalEntries(entries)
if strOutput == "" {
t.Fatal("expected non-empty string, got empty string")
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package cmd
package problems

var sections = []string{
// OrderedSections list of sections in go-dsa corresponding to directory names.
var OrderedSections = []string{
"array",
"strings",
"linkedlist",
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ jobs:
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
- run: go test -v -coverprofile=profile.cov ./...
- run: make ci
- uses: shogo82148/actions-goveralls@v1
with:
path-to-profile: profile.cov
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ profile.cov
.pre-commit-config.yaml
.vscode
.idea
bin
27 changes: 27 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
all: build

build:
mkdir -p ./bin
go run ./.github/cmd/main.go export-md > ./bin/go-dsa.md

test:
go test --race -v -coverprofile=profile.cov ./...

clean:
go clean
rm -f ./bin/*

fmt:
go fmt ./...
gofmt -w -s -r 'interface{} -> any' .

deps:
go mod tidy
go mod download

vet:
go vet ./...

ci: fmt vet test build clean

.PHONY: all build run test bench clean fmt deps update
2 changes: 1 addition & 1 deletion array/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,5 +93,5 @@ Arrays are used wherever sequential data or more than one piece of data is neede
* [Product of All Other Elements](./product_of_all_other_elements_test.go), [Solution](./product_of_all_other_elements.go)
* [Equal Sum Sub-arrays](./equal_sum_subarrays_test.go), [Solution](./equal_sum_subarrays.go)
* [Rotate K Times](./rotate_k_steps_test.go), [Solution](./rotate_k_steps.go)
* [Bubble Sort](./bubble_sort_test.go), [Solution](bubble_sort.go)
* [Bubble Sort](./bubble_sort_test.go), [Solution](./bubble_sort.go)
* [Insertion Sort](./insertion_sort_test.go), [Solution](./insertion_sort.go)
4 changes: 1 addition & 3 deletions backtracking/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,7 @@ Backtracking is widely used to solve board games and computers use it to select

## Rehearsal

## Permutations

* [Permutations](./permutations_test.go), [Solution](./permutations.go)
* [Permutations](./permutations_test.go), [Solution](./permutations.go)
* [Generate Parentheses](./generate_parentheses_test.go), [Solution](./generate_parentheses.go)
* [Phone Letter Combinations](./phone_letter_combinations_test.go), [Solution](./phone_letter_combinations.go)
* [Maze](./maze_test.go), [Solution](./maze.go)
Expand Down
10 changes: 5 additions & 5 deletions bit/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,9 +108,9 @@ Negation can be used to invert a set of flags or find the two's complement of a

## Rehearsal

* [Division without multiplication or division operators](division_without_operators_test.go), [Solution](division_without_operators.go)
* [Middle without division](middle_without_division_test.go), [Solution](middle_without_division.go)
* [Addition without using plus (+) or any other arithmetic operators](addition_without_operators_test.go), [Solution](addition_without_operators.go)
* [Division without multiplication or division operators](./division_without_operators_test.go), [Solution](./division_without_operators.go)
* [Middle without division](./middle_without_division_test.go), [Solution](./middle_without_division.go)
* [Addition without using plus (+) or any other arithmetic operators](./addition_without_operators_test.go), [Solution](./addition_without_operators.go)
* [Power of Two](./is_power_of_two_test.go), [Solution](./is_power_of_two.go)
* [Maximum without if conditions](max_function_without_conditions_test.go), [Solution](max_function_without_conditions.go)
* [Oddly Repeated Number](oddly_repeated_number_test.go), [Solution](oddly_repeated_number.go)
* [Maximum without if conditions](./max_function_without_conditions_test.go), [Solution](./max_function_without_conditions.go)
* [Oddly Repeated Number](./oddly_repeated_number_test.go), [Solution](./oddly_repeated_number.go)
12 changes: 6 additions & 6 deletions dnc/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,9 +92,9 @@ DNC algorithms are suitable for solving problems that can be divided into smalle

## Rehearsal

* [Binary Search](binary_search_test.go), [Solution](binary_search.go)
* [Square Root with Binary Search](square_root_test.go), [Solution](square_root.go)
* [Rate Limit](rate_limit_test.go), [Solution](rate_limit.go)
* [Towers of Hanoi](towers_of_hanoi_test.go), [Solution](towers_of_hanoi.go)
* [Merge Sort](merge_sort_test.go), [Solution](merge_sort.go)
* [Quick Sort](quick_sort_test.go), [Solution](quick_sort.go)
* [Binary Search](./binary_search_test.go), [Solution](./binary_search.go)
* [Square Root with Binary Search](./square_root_test.go), [Solution](./square_root.go)
* [Rate Limit](./rate_limit_test.go), [Solution](./rate_limit.go)
* [Towers of Hanoi](./towers_of_hanoi_test.go), [Solution](./towers_of_hanoi.go)
* [Merge Sort](./merge_sort_test.go), [Solution](./merge_sort.go)
* [Quick Sort](./quick_sort_test.go), [Solution](./quick_sort.go)
6 changes: 6 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
module github.com/spring1843/go-dsa

go 1.22

require (
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/spf13/cobra v1.8.1 // indirect
github.com/spf13/pflag v1.0.5 // indirect
)
10 changes: 10 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
2 changes: 1 addition & 1 deletion stack/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,4 +90,4 @@ During process execution, a portion of memory known as the "stack" is reserved t
* [Infix to Postfix Conversion](./infix_to_postfix_test.go), [Solution](./infix_to_postfix.go)
* [Evaluate Postfix](./evaluate_postfix_test.go), [Solution](./evaluate_postfix.go)
* [Longest Valid Parentheses](./longest_valid_parentheses_test.go), [Solution](./longest_valid_parentheses.go)
* [Basic Calculator](./basic_calculator_test.go), [Solution](basic_calculator.go)
* [Basic Calculator](./basic_calculator_test.go), [Solution](./basic_calculator.go)

0 comments on commit f179129

Please sign in to comment.