Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 10 additions & 6 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ jobs:
go-version: '1.22'

- name: Cache Go modules
uses: actions/cache@v3
uses: actions/cache@v4
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
Expand Down Expand Up @@ -80,10 +80,14 @@ jobs:
- name: Test verify command with solutions (should pass)
run: |
echo "Testing that solution exercises pass..."
# Test a few key exercises with their solutions
./bin/golearn verify 01_hello --solution
./bin/golearn verify 36_json --solution
./bin/golearn verify 37_xml --solution
for ex in 01_hello 36_json 37_xml; do
if [ -d "./internal/exercises/solutions/$ex" ]; then
echo "Running verify --solution for $ex"
./bin/golearn verify "$ex" --solution
else
echo "Skipping $ex: no solution directory present"
fi
done

- name: Test specific template exercises (should fail)
run: |
Expand Down Expand Up @@ -193,4 +197,4 @@ jobs:

- name: Test watch command (timeout after 5 seconds)
run: |
timeout 5s ./bin/golearn watch || true
timeout 5s ./bin/golearn watch || true
5 changes: 5 additions & 0 deletions internal/exercises/Catalog/Concepts/01_hello.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
slug: 01_hello
title: Hello, Go!
test_regex: ".*"
hints:
- Implement Hello() to return 'Hello, Go!'
5 changes: 5 additions & 0 deletions internal/exercises/Catalog/Concepts/02_values.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
slug: 02_values
title: Values
test_regex: ".*"
hints:
- Use fmt.Sprintf to format values.
5 changes: 5 additions & 0 deletions internal/exercises/Catalog/Concepts/03_variables.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
slug: 03_variables
title: Variables
test_regex: ".*"
hints:
- Use short declarations (:=) and return multiple values.
5 changes: 5 additions & 0 deletions internal/exercises/Catalog/Concepts/04_constants.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
slug: 04_constants
title: Constants
test_regex: ".*"
hints:
- Use math.Pi and constant expressions.
5 changes: 5 additions & 0 deletions internal/exercises/Catalog/Concepts/05_for.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
slug: 05_for
title: For
test_regex: ".*"
hints:
- Accumulate a sum with a for loop.
5 changes: 5 additions & 0 deletions internal/exercises/Catalog/Concepts/06_if_else.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
slug: 06_if_else
title: If/Else
test_regex: ".*"
hints:
- Handle negative, zero, and positive cases.
5 changes: 5 additions & 0 deletions internal/exercises/Catalog/Concepts/07_switch.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
slug: 07_switch
title: Switch
test_regex: ".*"
hints:
- Match multiple cases for weekend days.
5 changes: 5 additions & 0 deletions internal/exercises/Catalog/Concepts/08_arrays.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
slug: 08_arrays
title: Arrays
test_regex: ".*"
hints:
- Iterate with range over a fixed-size array.
5 changes: 5 additions & 0 deletions internal/exercises/Catalog/Concepts/09_slices.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
slug: 09_slices
title: Slices
test_regex: ".*"
hints:
- Append values then compute a sum.
5 changes: 5 additions & 0 deletions internal/exercises/Catalog/Concepts/10_maps.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
slug: 10_maps
title: Maps
test_regex: ".*"
hints:
- Use strings.Fields and map[string]int for word counts.
5 changes: 5 additions & 0 deletions internal/exercises/Catalog/Concepts/11_functions.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
slug: 11_functions
title: Functions
test_regex: ".*"
hints:
- Pass a function and call it.
5 changes: 5 additions & 0 deletions internal/exercises/Catalog/Concepts/12_multi_return.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
slug: 12_multi_return
title: Multiple Return Values
test_regex: ".*"
hints:
- Return quotient, remainder, and an error for divide-by-zero.
5 changes: 5 additions & 0 deletions internal/exercises/Catalog/Concepts/13_variadic.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
slug: 13_variadic
title: Variadic Functions
test_regex: ".*"
hints:
- Use '...' to accept any number of ints and sum them.
5 changes: 5 additions & 0 deletions internal/exercises/Catalog/Concepts/14_closures.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
slug: 14_closures
title: Closures
test_regex: ".*"
hints:
- Implement a function that returns a closure, capturing an outer variable.
5 changes: 5 additions & 0 deletions internal/exercises/Catalog/Concepts/15_recursion.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
slug: 15_recursion
title: Recursion
test_regex: ".*"
hints:
- Implement a recursive factorial function.
5 changes: 5 additions & 0 deletions internal/exercises/Catalog/Concepts/16_range_built_in.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
slug: 16_range_built_in
title: Range over Built-in Types
test_regex: ".*"
hints:
- Use range to iterate over a slice and a map.
5 changes: 5 additions & 0 deletions internal/exercises/Catalog/Concepts/17_pointers.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
slug: 17_pointers
title: Pointers
test_regex: ".*"
hints:
- Write a function that takes a pointer, modifies the value, and returns the pointer.
5 changes: 5 additions & 0 deletions internal/exercises/Catalog/Concepts/18_strings_runes.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
slug: 18_strings_runes
title: Strings and Runes
test_regex: ".*"
hints:
- Iterate over a string with range to count runes, and demonstrate string manipulation.
5 changes: 5 additions & 0 deletions internal/exercises/Catalog/Concepts/19_structs.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
slug: 19_structs
title: Structs
test_regex: ".*"
hints:
- Define a struct with fields for name and age, then create an instance.
5 changes: 5 additions & 0 deletions internal/exercises/Catalog/Concepts/20_methods.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
slug: 20_methods
title: Methods
test_regex: ".*"
hints:
- Add a method to a struct that calculates something based on its fields.
5 changes: 5 additions & 0 deletions internal/exercises/Catalog/Concepts/21_interfaces.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
slug: 21_interfaces
title: Interfaces
test_regex: ".*"
hints:
- Define an interface and implement it for a struct.
5 changes: 5 additions & 0 deletions internal/exercises/Catalog/Concepts/22_enums.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
slug: 22_enums
title: Enums
test_regex: ".*"
hints:
- Use iota to create a set of related constants as an enumeration.
5 changes: 5 additions & 0 deletions internal/exercises/Catalog/Concepts/23_struct_embedding.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
slug: 23_struct_embedding
title: Struct Embedding
test_regex: ".*"
hints:
- Embed one struct within another and access the inner struct's fields directly.
5 changes: 5 additions & 0 deletions internal/exercises/Catalog/Concepts/24_generics.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
slug: 24_generics
title: Generics
test_regex: ".*"
hints:
- Write a generic function that works with different types.
5 changes: 5 additions & 0 deletions internal/exercises/Catalog/Concepts/25_range_iterators.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
slug: 25_range_iterators
title: Range over Iterators
test_regex: ".*"
hints:
- Implement a custom iterator and use range over it.
5 changes: 5 additions & 0 deletions internal/exercises/Catalog/Concepts/26_errors.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
slug: 26_errors
title: Errors
test_regex: ".*"
hints:
- Write a function that returns an error and handle it.
5 changes: 5 additions & 0 deletions internal/exercises/Catalog/Concepts/27_custom_errors.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
slug: 27_custom_errors
title: Custom Errors
test_regex: ".*"
hints:
- Define a custom error type and return it from a function.
5 changes: 5 additions & 0 deletions internal/exercises/Catalog/Concepts/28_defer.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
slug: 28_defer
title: Defer
test_regex: ".*"
hints:
- Use `f.Close()` with `defer` keyword.
5 changes: 5 additions & 0 deletions internal/exercises/Catalog/Concepts/29_go_routines.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
slug: 29_go_routines
title: Go Routines
test_regex: ".*"
hints:
- Use `go` keyword to execute functions concurrently using go routines.
5 changes: 5 additions & 0 deletions internal/exercises/Catalog/Concepts/30_channels.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
slug: 30_channels
title: Channels
test_regex: ".*"
hints:
- Use `make(chan T)` to create a channel and `<-` to send and receive on it.
5 changes: 5 additions & 0 deletions internal/exercises/Catalog/Concepts/31_mutexes.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
slug: 31_mutexes
title: Mutexes
test_regex: ".*"
hints:
- Use `sync.Mutex` to synchronize access to a shared resource.
5 changes: 5 additions & 0 deletions internal/exercises/Catalog/Concepts/32_sorting.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
slug: 32_sorting
title: Sorting
test_regex: ".*"
hints:
- Use `slice.Sort` for sorting slices.
5 changes: 5 additions & 0 deletions internal/exercises/Catalog/Concepts/33_string_formatting.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
slug: 33_string_formatting
title: String Formatting
test_regex: ".*"
hints:
- Use `fmt.Sprintf` and `%s`, `%d`, `%f` formatting directives to format strings, integers, and floats.
5 changes: 5 additions & 0 deletions internal/exercises/Catalog/Concepts/34_channel_buffering.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
slug: 34_channel_buffering
title: Channel Buffering
test_regex: ".*"
hints:
- Use `make(chan T, N)` to create a buffered channel and `<-` to send and receive on it.
5 changes: 5 additions & 0 deletions internal/exercises/Catalog/Concepts/35_channel_sync.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
slug: 35_channel_sync
title: Channel Synchronization
test_regex: ".*"
hints:
- Use a buffered boolean channel and wait till go routine completes.
9 changes: 9 additions & 0 deletions internal/exercises/Catalog/Concepts/36_json.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
slug: 36_json
title: JSON
test_regex: ".*"
hints:
- Use the encoding/json package to work with JSON data.
- Implement MarshalPerson to convert a struct into JSON using json.Marshal.
- Implement UnmarshalPerson to convert a JSON string into a struct using json.Unmarshal.
- Handle and return errors properly in both functions.

Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
slug: 37_sorting_by_functions
title: "Sorting by Functions"
hints:
- Implement sort.Interface with Len(), Less(), and Swap() methods
- Create custom slice types like ByName and ByAge (e.g., type ByName []Person)
- Use sort.Sort() to sort slices with your custom comparison logic
- Remember to make copies of slices to avoid modifying the original
8 changes: 8 additions & 0 deletions internal/exercises/Catalog/Concepts/37_xml.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
slug: 37_xml
title: XML Encoding and Decoding
test_regex: ".*"
hints:
- Use encoding/xml package for marshaling and unmarshaling XML data.
- Add XML struct tags using `xml:"fieldname"` to map struct fields to XML elements.
- Use xml.Marshal to convert structs to XML bytes.
- Use xml.Unmarshal to parse XML bytes into structs.
7 changes: 7 additions & 0 deletions internal/exercises/Catalog/Concepts/38_time_formatting.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
slug: 38_time_formatting
title: "Time Formatting"
hints:
- Use time.Now().Format() to format current time with a specific layout
- Use time.Parse() to parse time strings with known layouts
- Use time.LoadLocation() to work with different timezones
- Extract time components using .Date() and .Clock() methods
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
slug: 39_channel_directions
title: Channel Directions
test_regex: ".*"
hints:
- Create two channels, one for sending jobs and one for receiving results.
- Start 5 workers using go routines.
- Send 50 jobs to the worker pool.
- Receive results from the worker pool and store them in a `rs` slice.
- Enforce type safety by specifying the channel directions in worker function.
7 changes: 7 additions & 0 deletions internal/exercises/Catalog/Concepts/39_panic.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
slug: 39_panic
title: Panic and Recover
test_regex: ".*"
hints:
- Use `panic()` to simulate runtime errors when appropriate.
- Use `defer` with `recover()` to catch and handle panics.
- Recovering from panics allows graceful handling of unexpected situations.
6 changes: 6 additions & 0 deletions internal/exercises/Catalog/Concepts/40_channel_select.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
slug: 40_channel_select
title: Channel Select
test_regex: ".*"
hints:
- Use `select` to handle multiple channel operations concurrently.
- Use `time.After` to simulate a 5 microsecond timeout.
8 changes: 8 additions & 0 deletions internal/exercises/Catalog/Concepts/41_time_delay.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
slug: 41_time_delay
title: "Delays and Timers in Go"
test_regex: ".*"
hints:
- Use time.Sleep() to pause execution for a duration.
- Convert milliseconds to time.Duration using time.Millisecond.
- Use a buffered channel to send a signal after waiting.
- Use time.After or time.Sleep to trigger events after delays.
9 changes: 9 additions & 0 deletions internal/exercises/Catalog/Concepts/42_wait_group.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
slug: 42_wait_group
title: WaitGroups
test_regex: ".*"
hints:
- Use sync.WaitGroup to wait for all launched goroutines.
- Call wg.Add(1) before starting a goroutine and wg.Done() when it finishes.
- Close result channels after wg.Wait() so collectors can range over them.
- Capture loop variables correctly inside goroutines (e.g., `n := n`).
- Return results as a slice — order does not need to match input order.
10 changes: 10 additions & 0 deletions internal/exercises/Catalog/Concepts/43_worker_pools.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
slug: 43_worker_pools
title: Worker Pools
test_regex: ".*"
hints:
- Create separate channels for jobs (send work) and results (receive processed data).
- Launch multiple worker goroutines that read from jobs channel and write to results channel.
- Use channel directions (<-chan for receive-only, chan<- for send-only) in worker function signature.
- Close the jobs channel after sending all work to signal workers to finish.
- Use strings.TrimSpace() to clean message strings by removing leading/trailing whitespace.
- Collect exactly len(logs) results to ensure all work is processed.
7 changes: 7 additions & 0 deletions internal/exercises/Catalog/Concepts/44_atomic_counters.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
slug: 44_atomic_counters
title: Atomic Counters
test_regex: ".*"
hints:
- Use `sync/atomic` package to create and increment atomic counter.
- Launch 10,000 anonymous go routines that simultaneously increment the counter.
- Use WaitGroups to wait for all go routines to finish.
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
slug: 45_range_over_channels
title: Range over channels
test_regex: ".*"
hints:
- Use `for i := range ch {...}` syntax to range over a channels.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
slug: 46_non_blocking_channel_operations
title: Non-blocking channel operations
test_regex: ".*"
hints:
- Use `default` case in select to handle non-blocking channel operations.
- Safely increment `dropped` using mutex `Lock()` and `Unlock()`.

13 changes: 13 additions & 0 deletions internal/exercises/Catalog/Concepts/64_timers.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
slug: 64_timers
title: "Timers"
test_regex: ".*"
hints:
- Use a map[string]*time.Timer to track active timers by key.
- Use a mutex to safely access the timers map concurrently.
- Start a timer with time.AfterFunc(d, fn) to run a callback after duration d.
- If Start is called again for an existing key, stop and replace the old timer.
- Stop should remove the timer from the map and prevent the callback from firing.
- Reset can call timer.Reset(d) to reschedule the same callback.
- Remember to remove timers from the map after they fire to avoid memory leaks.
- Write tests to verify Start, Stop, and Reset behavior, including concurrency scenarios.

11 changes: 11 additions & 0 deletions internal/exercises/Catalog/Concepts/68_rate_limiting.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
slug: 68_rate_limiting
title: Rate Limiting
test_regex: ".*"
hints:
- Implement a RateLimiter struct that tracks request timestamps per key using a map[string][]time.Time.
- Use a mutex to safely handle concurrent access to the map.
- In the Allow method, remove timestamps older than the interval and check if the number of recent requests exceeds the limit.
- Reset should clear the request history for a key; if the key does not exist, do nothing.
- Consider edge cases:` multiple keys, concurrent access, and requests exactly at the interval boundary.
- In tests, use time.Sleep with a small buffer above the interval to avoid flakiness.
- Initialize the timestamps map in NewRateLimiter to prevent nil pointer errors.
6 changes: 6 additions & 0 deletions internal/exercises/Catalog/Projects/01_text_analyzer.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
slug: 01_text_analyzer
dir: 101_text_analyzer
title: Text Analyzer (Easy)
test_regex: ".*"
hints:
- Implement functions to count characters, words, and unique words in a given text.
Loading
Loading