Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature(rna-transcription): add rna-transcription practice exercise #22

Merged
merged 1 commit into from
May 5, 2024
Merged
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
8 changes: 8 additions & 0 deletions config.json
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,14 @@
"practices": [],
"prerequisites": [],
"difficulty": 2
},
{
"slug": "rna-transcription",
"name": "RNA Transcription",
"uuid": "be6ab475-6c0c-4320-a12d-3fe3648fd82c",
"practices": [],
"prerequisites": [],
"difficulty": 3
}
]
},
Expand Down
16 changes: 16 additions & 0 deletions exercises/practice/rna-transcription/.docs/instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Instructions

Given a DNA strand, return its RNA complement (per RNA transcription).

Both DNA and RNA strands are a sequence of nucleotides.

The four nucleotides found in DNA are adenine (**A**), cytosine (**C**), guanine (**G**) and thymine (**T**).

The four nucleotides found in RNA are adenine (**A**), cytosine (**C**), guanine (**G**) and uracil (**U**).

Given a DNA strand, its transcribed RNA strand is formed by replacing each nucleotide with its complement:

- `G` -> `C`
- `C` -> `G`
- `T` -> `A`
- `A` -> `U`
11 changes: 11 additions & 0 deletions exercises/practice/rna-transcription/.meta/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"authors": ["ajborla"],
"files": {
"solution": ["rna_transcription.prg"],
"test": ["rna_transcription_test.prg"],
"example": [".meta/example.prg"]
},
"blurb": "Given a DNA strand, return its RNA Complement Transcription.",
"source": "Hyperphysics",
"source_url": "https://web.archive.org/web/20220408112140/http://hyperphysics.phy-astr.gsu.edu/hbase/Organic/transcription.html"
}
28 changes: 28 additions & 0 deletions exercises/practice/rna-transcription/.meta/example.prg
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
* ----------------------------------------------------------------------------
* exercism.org
* Harbour Track Exercise: rna-transcription
* Contributed: Anthony J. Borla ([email protected])
* ----------------------------------------------------------------------------

function Transcribe(strand)
local i, nucleotide, newStrand := "", slen := LEN(strand)

* Traverse strand (note start index of 1)
for i := 1 to slen
* Extract nucleotide at current index, transcribe, append to new (RNA)
* strand. Note use of 'exit' keyword (equivalent of C's 'break')
nucleotide := SUBSTR(strand, i, 1)

switch nucleotide
case "A" ; nucleotide := "U" ; exit
case "C" ; nucleotide := "G" ; exit
case "G" ; nucleotide := "C" ; exit
case "T" ; nucleotide := "A" ; exit
otherwise ; return NIL
endswitch

newStrand := newStrand + nucleotide
next

return newStrand

28 changes: 28 additions & 0 deletions exercises/practice/rna-transcription/.meta/tests.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# This is an auto-generated file.
#
# Regenerating this file via `configlet sync` will:
# - Recreate every `description` key/value pair
# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications
# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion)
# - Preserve any other key/value pair
#
# As user-added comments (using the # character) will be removed when this file
# is regenerated, comments can be added via a `comment` key.

[b4631f82-c98c-4a2f-90b3-c5c2b6c6f661]
description = "Empty RNA sequence"

[a9558a3c-318c-4240-9256-5d5ed47005a6]
description = "RNA complement of cytosine is guanine"

[6eedbb5c-12cb-4c8b-9f51-f8320b4dc2e7]
description = "RNA complement of guanine is cytosine"

[870bd3ec-8487-471d-8d9a-a25046488d3e]
description = "RNA complement of thymine is adenine"

[aade8964-02e1-4073-872f-42d3ffd74c5f]
description = "RNA complement of adenine is uracil"

[79ed2757-f018-4f47-a1d7-34a559392dbf]
description = "RNA complement"
153 changes: 153 additions & 0 deletions exercises/practice/rna-transcription/PRGUNIT.prg
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
* ----------------------------------------------------------------------------
* Harbour Unit Test Worker
* Anthony J. Borla ([email protected])
* ----------------------------------------------------------------------------

#ifndef UTILS_PRG
#include "utils.prg"
#endif

procedure MakeTestDatabaseStructure(dbfName)
* Creation overwites any existing database
create &dbfName

* Each record describes the structure of a FIELD
append blank
replace Field_name with "NAME", Field_type with "C",;
Field_Len with 80, Field_dec with 0
append blank
replace Field_name with "CMPOP", Field_type with "C",;
Field_Len with 2, Field_dec with 0
append blank
replace Field_name with "EXPVALUE", Field_type with "C",;
Field_Len with 80, Field_dec with 0
append blank
replace Field_name with "CMDSTR", Field_type with "C",;
Field_Len with 80, Field_dec with 0

* Ensure data written to disk
close &dbfName
return

procedure MakeTestDatabase(dbfName)
local dbfStructure := dbfName + "_STRUCTURE"

* Build test database from database structure file
do MakeTestDatabaseStructure with dbfStructure
create &dbfName from &dbfStructure

* Ensure database structure file is removed
dbfStructure := dbfStructure + ".dbf"
erase &dbfStructure
return

procedure AddTestDatabase(dbfName, testName, cmpOp, expValue, cmdStr)
* Load a test data record into tests database (note use of 'Wrap' to
* preserve spaces in expected value string)
use &dbfName
append blank
replace &dbfName->NAME with testName
replace &dbfName->CMPOP with cmpOp
replace &dbfName->EXPVALUE with Wrap(expValue)
replace &dbfName->CMDSTR with cmdStr
close &dbfName
return

function RunTests(dbfName, keepTestDBF, outputJSON)
local testName, cmpOp, expValue, cmdStr, retValue, testExpr
local success := .T.

use &dbfName

* Determine, and print, number of tests (required for TAP)
if outputJSON == NIL .OR. !outputJSON
? "1.." + LTRIM(STR(LASTREC()))
endif

* Execute unit tests
do while !EOF()
* Extract test data (note use of 'Unwrap' to extract space-preserved
* expected value string)
testName := ALLTRIM(&dbfName->NAME)
cmpOp := &dbfName->CMPOP
expValue := Unwrap(ALLTRIM(&dbfName->EXPVALUE))
cmdStr := ALLTRIM(&dbfName->CMDSTR)

* Execute test, and build test expression
retValue := TypeToS(&cmdStr)
testExpr := '"' + retValue + '" ' + cmpOp + ' "' + expValue + '"'

* If the parameter flag, outputJSON, is omitted, or set to .F., then
* emit test report in TAP format
if outputJSON == NIL .OR. !outputJSON
* Report test outcome - TAP
if &testExpr
? "OK " + LTRIM(STR(RECNO())) + " - " + testName
else
* Single test failure signals failure of whole suite
success := .F.
? "FAIL " + LTRIM(STR(RECNO())) + " - " + testName
endif
else
* Report test outcome - JSON
? "JSON"
endif

* ... next test
skip
enddo

close &dbfName

* If the parameter flag, keepTestDBF, is omitted, or set to .F., then
* remove the tests database
if keepTestDBF == NIL .OR. !keepTestDBF
dbfName := dbfName + ".dbf"
erase &dbfName
endif

return success

function TypeToS(value)
* Use VALTYPE() instead of TYPE() to check type
local typeValue := VALTYPE(value)

switch typeValue
* Array type (assume 1D array of non-aggregate elements),
* returns the concatenation of elements as a string
case "A" ; return ArrToS(value)

* Character type returned untouched
case "C" ; return value

* Date as "yyyymmdd"
case "D" ; return DTOS(value)

* Logical as literal string representation of self
case "L" ; return IIF(value, ".T.", ".F.")

* String-converted numerics are right-justified, so ensure are
* returned trimmed
case "N" ; return ALLTRIM(STR(value))

* Support use of NIL return type (usually to indicate error)
case "U" ; return "NIL"
endswitch

* Ignore the remaining types, just return NIL (likely runtime error)
return NIL

* Utilities to preserve leading and trailing spaces in strings as they
* are stored into, and extracted from, database fields
function Wrap(string) ; return WrapString(string, .F., "[", "]")
function Unwrap(string) ; return WrapString(string, .T.)

function WrapString(string, doUnwrap, wrapStart, wrapEnd)
local uws
if doUnwrap
uws := SUBSTR(SUBSTR(string, 2), 1, LEN(string) - 2)
else
uws := wrapStart + string + wrapEnd
endif
return uws

8 changes: 8 additions & 0 deletions exercises/practice/rna-transcription/rna_transcription.prg
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
* ----------------------------------------------------------------------------
* exercism.org
* Harbour Track Exercise: rna-transcription
* ----------------------------------------------------------------------------

function Transcribe(strand)
return ""

48 changes: 48 additions & 0 deletions exercises/practice/rna-transcription/rna_transcription_test.prg
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
* ----------------------------------------------------------------------------
* Harbour Unit Test Runner [rna_transcription.prg]
* ----------------------------------------------------------------------------

* Variable declarations
memvar TESTS, SUCCESS

* Test database name
TESTS := IIF(PCOUNT() > 0, hb_PValue(1), "TESTS")

* Create tests database
do MakeTestDatabase with TESTS

* Add test data into tests database. Each test case stub should be altered
* to follow this format:
*
* do AddTestDatabase with TESTS, "say Hi!", "==", "Hello, World!", "HelloWorld()"
* do AddTestDatabase with TESTS, "add 5 and 3", "==", "8", "Add_5_And_3(5, 3)"
*
* Note:
* 1st field is the test description (already supplied)
* 2nd field is comparator operator, usually "=="
* 3rd field is the function return result, always written as a string
* 4th field is the function (optionally with arguments), always written as a string
*

* Add test data into tests database
do AddTestDatabase with TESTS, "Empty RNA sequence", "==", "", "Transcribe('')"
do AddTestDatabase with TESTS, "RNA complement of cytosine is guanine", "==", "G", "Transcribe('C')"
do AddTestDatabase with TESTS, "RNA complement of guanine is cytosine", "==", "C", "Transcribe('G')"
do AddTestDatabase with TESTS, "RNA complement of thymine is adenine", "==", "A", "Transcribe('T')"
do AddTestDatabase with TESTS, "RNA complement of adenine is uracil", "==", "U", "Transcribe('A')"
do AddTestDatabase with TESTS, "RNA complement", "==", "UGCACCAGAAUU", "Transcribe('ACGTGGTCTTAA')"

* Execute unit tests. Arguments:
* - Tests database name
* - Database retention flag (.T. to not delete test database on test end)
* - JSON output flag (.T. to emit test results in JSON format [default is TAP])
SUCCESS := RunTests(TESTS, SToBool(hb_PValue(2)), SToBool(hb_PValue(3)))

* Return success status to OS
ERRORLEVEL(IIF(SUCCESS, 0, 1))

* Code under test (CUT)
#include "rna_transcription.prg"

* Unit Test Framework
#include "PRGUNIT.prg"
Loading