a gleam implementation of a CS assignment originally written in cpp

Compare changes

Choose any two refs to compare.

+2 -7
.gitignore
···
-
#ignore all files
-
*
-
-
# Include project specific files
-
!lab66.cpp
-
!coversheet.md
-
!.gitignore
···
+
build/
+
.DS_Store
+27
LICENSE.md
···
···
+
The MIT License (MIT)
+
=====================
+
+
Copyright © `2025` `Kieran Klukas`
+
+
Permission is hereby granted, free of charge, to any person
+
obtaining a copy of this software and associated documentation
+
files (the “Software”), to deal in the Software without
+
restriction, including without limitation the rights to use,
+
copy, modify, merge, publish, distribute, sublicense, and/or sell
+
copies of the Software, and to permit persons to whom the
+
Software is furnished to do so, subject to the following
+
conditions:
+
+
The above copyright notice and this permission notice shall be
+
included in all copies or substantial portions of the Software.
+
+
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+
OTHER DEALINGS IN THE SOFTWARE.
+
+
+98 -11
README.md
···
-
# Lab 6
-
## Part 1
-
Review the lab write-ups in ZyBooks for Section 6.6.
-
Edit your code using vi.
-
Compile your code using
-
g++ lab66.cpp -o lab66
-
-
## Part 2
-
Complete the [Coversheet](coversheet.md) file and submit it with your final solution
-
## Part 3
-
Ensure all code is committed and pushed to GitHub along with running it in ZyLabs.
···
+
# Lab 6 - Gleamified
+
+
[![Package Version](https://img.shields.io/hexpm/v/bible_search)](https://hex.pm/packages/bible_search)
+
[![Hex Docs](https://img.shields.io/badge/hex-docs-ffaff3)](https://hexdocs.pm/bible_search/)
+
+
```gleam
+
pub fn bible_scan(
+
reference reference: Reference,
+
bible bible: String,
+
) -> ScanResult {
+
let inital_state =
+
ScanState(
+
phase: Book,
+
ref: reference,
+
found_book: False,
+
found_chapter: False,
+
verse_text: Error("Verse not found"),
+
)
+
+
let bible_lines = string.split(bible, "\n")
+
+
let result =
+
list.fold(bible_lines, inital_state, fn(state, line) -> ScanState {
+
case state.phase {
+
Done -> state
+
Book ->
+
case line {
+
"THE BOOK OF " <> book ->
+
case book == state.ref.book {
+
True -> ScanState(..state, phase: Chapter, found_book: True)
+
False -> state
+
}
+
_ -> state
+
}
+
Chapter ->
+
case line {
+
"CHAPTER " <> chapter ->
+
case result.unwrap(int.parse(chapter), 0) == state.ref.chapter {
+
True -> ScanState(..state, phase: Verse, found_chapter: True)
+
False -> state
+
}
+
_ -> state
+
}
+
Verse ->
+
fn() {
+
let parts = string.split(line, " ")
+
case parts {
+
[first, ..rest] ->
+
case result.unwrap(int.parse(first), 0) == state.ref.verse {
+
True ->
+
ScanState(
+
..state,
+
phase: Done,
+
verse_text: Ok(string.join(rest, " ")),
+
)
+
False -> state
+
}
+
_ -> state
+
}
+
}()
+
}
+
})
+
ScanResult(ref: reference, verse: result.verse_text)
+
}
+
```
+
For this lab the program must parse `OT.txt` (format below) to find specific references and produce scoped errors if the reference isn't found.
+
```text
+
THE BOOK OF GENESIS
+
CHAPTER 1
+
1 In the beginning God created the heaven and the earth.
+
2 And the earth was without form, and void; and darkness [was] upon the face of the deep. And the Spirit of God moved upon the face of the waters.
+
3 And God said, Let there be light: and there was light.
+
4 And God saw the light, that [it was] good: and God divided the light from the darkness.
+
THE BOOK OF PSALMS
+
PSALM 1
+
1 Blessed [is] the man that walketh not in the counsel of the ungodly, nor standeth in the way of sinners, nor sitteth in the seat of the scornful.
+
2 But his delight [is] in the law of the LORD; and in his law doth he meditate day and night.
+
3 And he shall be like a tree planted by the rivers of water, that bringeth forth his fruit in his season; his leaf also shall not wither; and whatsoever he doeth shall prosper.
+
```
+
+
## Development
+
+
You need to have the [gleam runtime](https://gleam.run/getting-started/installing/) installed as well as erlang for the beam runtime.
+
+
```sh
+
gleam run
+
gleam test # runs all the test functions in /tests postfixed with _test
+
```
+
+
<p align="center">
+
<img src="https://raw.githubusercontent.com/taciturnaxolotl/carriage/main/.github/images/line-break.svg" />
+
</p>
+
<p align="center">
+
<i><code>&copy 2025-present <a href="https://github.com/taciturnaxololt">Kieran Klukas</a></code></i>
+
</p>
+
<p align="center">
+
<a href="https://github.com/cu-cs1210/lab-6-kieranklukas/blob/main/LICENSE.md"><img src="https://img.shields.io/static/v1.svg?style=for-the-badge&label=License&message=MIT&logoColor=d9e0ee&colorA=363a4f&colorB=b7bdf8"/></a>
+
</p>
-32
coversheet.md
···
-
Project #X <Name>
-
CS 1210 – Fall 20XX
-
<Your Name>
-
-
# Requirements
-
Restate the problem specifications in your own words
-
-
# Design
-
How did you attack the problem? What choices did you make in your design, and why?
-
-
# Implementation
-
Outline any interesting implementation details.
-
-
# Testing
-
Explain how you tested your program, enumerating the tests if possible.
-
Explain why your test set was sufficient to believe that the software is working properly,
-
i.e., what were the range of possibilities of errors that you were testing for.
-
-
# Outside Help
-
Did you get help from anyone else on this project? Document their contribution to your learning.
-
-
# AI Use
-
How did you use Generative AI in this project?
-
-
# Summary/Conclusion
-
Present your results. Did it work properly? Are there any limitations?
-
-
# Lessons Learned
-
List any lessons learned. What might you have done differently if you were going to attack this again.
-
-
# Time Spent
-
Approximately how many hours did you spend on this project?
···
+15
gleam.toml
···
···
+
name = "bible_search"
+
version = "0.1.0"
+
+
description = "search through the OT.txt bible format for a specific reference"
+
licences = ["MIT"]
+
repository = { type = "github", user = "cu-cs1210", repo = "lab-6-kieranklukas" }
+
links = [{ title = "Website", href = "https://dunkirk.sh" }]
+
+
[dependencies]
+
gleam_stdlib = ">= 0.44.0 and < 2.0.0"
+
simplifile = ">= 2.3.0 and < 3.0.0"
+
input = ">= 1.0.1 and < 2.0.0"
+
+
[dev-dependencies]
+
gleeunit = ">= 1.0.0 and < 2.0.0"
-20
lab66.cpp
···
-
/*********************************************************
-
* Summary:
-
*
-
* Author:
-
* Created:
-
*
-
********************************************************/
-
-
#include <iostream>
-
#include <cstdlib>
-
#include <fstream>
-
-
using namespace std;
-
-
int main() {
-
-
/* your code here */
-
-
return 0;
-
}
···
-3
lab66.input
···
-
Genesis
-
1
-
1
···
-2
lab66_exp.output
···
-
Please enter the reference of the verse you would like
-
the book: the chapter: the verse: GENESIS 1:1 In the beginning God created the heaven and the earth.
···
-10
makefile
···
-
all: lab66 test clean
-
-
lab66: lab66.cpp
-
g++ lab66.cpp -Wall -o lab66
-
-
test:
-
./test.sh
-
-
clean:
-
rm -f lab66
···
+16
manifest.toml
···
···
+
# This file was generated by Gleam
+
# You typically do not need to edit this file
+
+
packages = [
+
{ name = "filepath", version = "1.1.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "filepath", source = "hex", outer_checksum = "B06A9AF0BF10E51401D64B98E4B627F1D2E48C154967DA7AF4D0914780A6D40A" },
+
{ name = "gleam_stdlib", version = "0.65.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "7C69C71D8C493AE11A5184828A77110EB05A7786EBF8B25B36A72F879C3EE107" },
+
{ name = "gleeunit", version = "1.6.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "FDC68A8C492B1E9B429249062CD9BAC9B5538C6FBF584817205D0998C42E1DAC" },
+
{ name = "input", version = "1.0.1", build_tools = ["gleam"], requirements = [], otp_app = "input", source = "hex", outer_checksum = "FE84CDADC78A1367E4AFD561A529825A8FEC88D165CBDF511FD3226CABCDEE6F" },
+
{ name = "simplifile", version = "2.3.0", build_tools = ["gleam"], requirements = ["filepath", "gleam_stdlib"], otp_app = "simplifile", source = "hex", outer_checksum = "0A868DAC6063D9E983477981839810DC2E553285AB4588B87E3E9C96A7FB4CB4" },
+
]
+
+
[requirements]
+
gleam_stdlib = { version = ">= 0.44.0 and < 2.0.0" }
+
gleeunit = { version = ">= 1.0.0 and < 2.0.0" }
+
input = { version = ">= 1.0.1 and < 2.0.0" }
+
simplifile = { version = ">= 2.3.0 and < 3.0.0" }
+151
src/bible_search.gleam
···
···
+
import gleam/int
+
import gleam/io
+
import gleam/list
+
import gleam/result
+
import gleam/string
+
import input.{input}
+
import simplifile
+
+
const filepath = "./OT.txt"
+
+
pub type Reference {
+
Reference(book: String, chapter: Int, verse: Int)
+
}
+
+
pub type Phase {
+
Book
+
Chapter
+
Verse
+
Done
+
}
+
+
pub type ScanState {
+
ScanState(
+
phase: Phase,
+
ref: Reference,
+
found_book: Bool,
+
found_chapter: Bool,
+
verse_text: Result(String, String),
+
)
+
}
+
+
pub type ScanResult {
+
ScanResult(ref: Reference, verse: Result(String, String))
+
}
+
+
pub fn parse_reference(input: String) -> Result(Reference, String) {
+
let parts = string.split(input, on: " ")
+
+
case parts {
+
[book, chapter_s, verse_s] ->
+
case int.parse(chapter_s) {
+
Ok(chapter) ->
+
case int.parse(verse_s) {
+
Ok(verse) ->
+
Ok(Reference(book: string.uppercase(book), chapter:, verse:))
+
Error(_) -> Error("Invalid verse: " <> verse_s)
+
}
+
Error(_) -> Error("Invalid chapter: " <> chapter_s)
+
}
+
[book_p1, book_p2, chapter_s, verse_s] ->
+
case int.parse(chapter_s) {
+
Ok(chapter) ->
+
case int.parse(verse_s) {
+
Ok(verse) ->
+
Ok(Reference(
+
book: string.uppercase(book_p1 <> " " <> book_p2),
+
chapter:,
+
verse:,
+
))
+
Error(_) -> Error("Invalid verse: " <> verse_s)
+
}
+
Error(_) -> Error("Invalid chapter: " <> chapter_s)
+
}
+
+
_ -> Error("invalid parse")
+
}
+
}
+
+
pub fn bible_scan(
+
reference reference: Reference,
+
bible bible: String,
+
) -> ScanResult {
+
let inital_state =
+
ScanState(
+
phase: Book,
+
ref: reference,
+
found_book: False,
+
found_chapter: False,
+
verse_text: Error("Verse not found"),
+
)
+
+
let bible_lines = string.split(bible, "\n")
+
+
let result =
+
list.fold(bible_lines, inital_state, fn(state, line) -> ScanState {
+
case state.phase {
+
Done -> state
+
Book ->
+
case line {
+
"THE BOOK OF " <> book ->
+
case book == state.ref.book {
+
True -> ScanState(..state, phase: Chapter, found_book: True)
+
False -> state
+
}
+
_ -> state
+
}
+
Chapter ->
+
case line {
+
"CHAPTER " <> chapter ->
+
case result.unwrap(int.parse(chapter), 0) == state.ref.chapter {
+
True -> ScanState(..state, phase: Verse, found_chapter: True)
+
False -> state
+
}
+
_ -> state
+
}
+
Verse ->
+
fn() {
+
let parts = string.split(line, " ")
+
case parts {
+
[first, ..rest] ->
+
case result.unwrap(int.parse(first), 0) == state.ref.verse {
+
True ->
+
ScanState(
+
..state,
+
phase: Done,
+
verse_text: Ok(string.join(rest, " ")),
+
)
+
False -> state
+
}
+
_ -> state
+
}
+
}()
+
}
+
})
+
+
ScanResult(ref: reference, verse: result.verse_text)
+
}
+
+
pub fn main() -> Nil {
+
let assert Ok(bible) = simplifile.read(from: filepath)
+
+
let assert Ok(search) = input(prompt: "> ")
+
+
let assert Ok(reference) = parse_reference(search)
+
+
let scan = bible_scan(reference, bible)
+
+
case scan.verse {
+
Ok(text) ->
+
io.println(
+
scan.ref.book
+
<> " "
+
<> int.to_string(scan.ref.chapter)
+
<> ":"
+
<> int.to_string(scan.ref.verse)
+
<> " "
+
<> text,
+
)
+
Error(e) -> io.println_error(e)
+
}
+
}
+151
test/bible_search_test.gleam
···
···
+
import bible_search
+
import gleeunit
+
import gleeunit/should
+
+
pub fn main() -> Nil {
+
gleeunit.main()
+
}
+
+
// gleeunit test functions end in `_test`
+
pub fn parse_reference_test() {
+
let ref = bible_search.parse_reference("FIRST KINGS 10 10")
+
should.be_ok(ref)
+
+
let expected_ref =
+
Ok(bible_search.Reference(book: "FIRST KINGS", chapter: 10, verse: 10))
+
+
should.be_true(ref == expected_ref)
+
}
+
+
pub fn parse_reference_single_word_book_test() {
+
let ref = bible_search.parse_reference("GENESIS 1 1")
+
should.be_ok(ref)
+
+
let expected_ref =
+
Ok(bible_search.Reference(book: "GENESIS", chapter: 1, verse: 1))
+
+
should.be_true(ref == expected_ref)
+
}
+
+
pub fn parse_reference_invalid_chapter_test() {
+
let ref = bible_search.parse_reference("GENESIS abc 1")
+
should.be_error(ref)
+
+
let expected_error = Error("Invalid chapter: abc")
+
+
should.be_true(ref == expected_error)
+
}
+
+
pub fn parse_reference_invalid_verse_test() {
+
let ref = bible_search.parse_reference("GENESIS 1 xyz")
+
should.be_error(ref)
+
let expected_error = Error("Invalid verse: xyz")
+
+
should.be_true(ref == expected_error)
+
}
+
+
pub fn parse_reference_too_few_parts_test() {
+
let ref = bible_search.parse_reference("GENESIS 1")
+
should.be_error(ref)
+
let expected_error = Error("invalid parse")
+
+
should.be_true(ref == expected_error)
+
}
+
+
pub fn parse_reference_too_many_parts_test() {
+
let ref = bible_search.parse_reference("SONG OF SOLOMON 1 1")
+
should.be_error(ref)
+
let expected_error = Error("invalid parse")
+
+
should.be_true(ref == expected_error)
+
}
+
+
pub fn parse_reference_lowercase_book_test() {
+
let ref = bible_search.parse_reference("genesis 1 1")
+
should.be_ok(ref)
+
+
let expected_ref =
+
Ok(bible_search.Reference(book: "GENESIS", chapter: 1, verse: 1))
+
+
should.be_true(ref == expected_ref)
+
}
+
+
pub fn bible_scan_found_verse_test() {
+
let bible =
+
"THE BOOK OF GENESIS
+
+
CHAPTER 1
+
+
1 In the beginning God created the heaven and the earth.
+
2 And the earth was without form, and void; and darkness was upon the face of the deep."
+
+
let ref = bible_search.Reference(book: "GENESIS", chapter: 1, verse: 1)
+
let result = bible_search.bible_scan(reference: ref, bible: bible)
+
+
should.be_true(
+
result.verse == Ok("In the beginning God created the heaven and the earth."),
+
)
+
}
+
+
pub fn bible_scan_verse_not_found_test() {
+
let bible =
+
"THE BOOK OF GENESIS
+
+
CHAPTER 1
+
+
1 In the beginning God created the heaven and the earth."
+
+
let ref = bible_search.Reference(book: "GENESIS", chapter: 1, verse: 99)
+
let result = bible_search.bible_scan(reference: ref, bible: bible)
+
+
should.be_true(result.verse == Error("Verse not found"))
+
}
+
+
pub fn bible_scan_book_not_found_test() {
+
let bible =
+
"THE BOOK OF GENESIS
+
+
CHAPTER 1
+
+
1 In the beginning God created the heaven and the earth."
+
+
let ref = bible_search.Reference(book: "EXODUS", chapter: 1, verse: 1)
+
let result = bible_search.bible_scan(reference: ref, bible: bible)
+
+
should.be_true(result.verse == Error("Verse not found"))
+
}
+
+
pub fn bible_scan_chapter_not_found_test() {
+
let bible =
+
"THE BOOK OF GENESIS
+
+
CHAPTER 1
+
+
1 In the beginning God created the heaven and the earth."
+
+
let ref = bible_search.Reference(book: "GENESIS", chapter: 99, verse: 1)
+
let result = bible_search.bible_scan(reference: ref, bible: bible)
+
+
should.be_true(result.verse == Error("Verse not found"))
+
}
+
+
pub fn bible_scan_multiple_verses_test() {
+
let bible =
+
"THE BOOK OF GENESIS
+
+
CHAPTER 1
+
+
1 In the beginning God created the heaven and the earth.
+
2 And the earth was without form, and void; and darkness was upon the face of the deep.
+
3 And God said, Let there be light: and there was light."
+
+
let ref = bible_search.Reference(book: "GENESIS", chapter: 1, verse: 2)
+
let result = bible_search.bible_scan(reference: ref, bible: bible)
+
+
should.be_true(
+
result.verse
+
== Ok(
+
"And the earth was without form, and void; and darkness was upon the face of the deep.",
+
),
+
)
+
}
-53
test.sh
···
-
#!/bin/bash
-
temp_file="lab66.output"
-
inp_file="lab66.input"
-
-
rm -f verses.txt
-
./lab66 < "$inp_file" > "$temp_file"
-
verses=$(< verses.txt)
-
echo "verses.txt : ${verses} "
-
-
resp=$(./lab66 < "$inp_file")
-
-
if [ $? -eq 0 ] ; then
-
echo "Pass: Program exited zero"
-
else
-
echo "Fail: Program did not exit zero"
-
exit 1
-
fi
-
-
exp_resp=$(< lab66_exp.output)
-
-
-
if [[ $resp = $exp_resp ]]; then
-
echo "Pass: Program output matched expected string"
-
else
-
# Check if the strings are the same length
-
if [ "${#resp}" -ne "${#exp_resp}" ]; then
-
echo "Strings are different lengths : ${#resp} vs ${#exp_resp}"
-
fi
-
-
# Iterate over the characters in the strings
-
for (( i=0; i<${#resp}; i++ )); do
-
# Extract the character at position i from each string
-
char1="${resp:$i:1}"
-
char2="${exp_resp:$i:1}"
-
ch1_ascii=$(printf "%d" "'$char1")
-
ch2_ascii=$(printf "%d" "'$char2")
-
-
# Compare the characters
-
if [ "$char1" != "$char2" ]; then
-
echo "First difference at position $i: $ch1_ascii vs $ch2_ascii"
-
break
-
fi
-
done
-
echo Error : Expected \"$exp_resp\", your output was \"$resp\"
-
exit 1
-
fi
-
-
rm -f "$temp_file"
-
-
echo
-
echo "All tests passed."
-
-
exit 0
···