diff --git a/esvapi.d b/esvapi.d index 2178258..6b09644 100644 --- a/esvapi.d +++ b/esvapi.d @@ -3,17 +3,17 @@ * * The GPLv2 License (GPLv2) * Copyright (c) 2024 Jeremy Baxter - * + * * esv is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * esv is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with esv. If not, see . */ @@ -32,18 +32,18 @@ import std.net.curl : HTTP; @safe: -/** Indentation style to use when formatting passages. */ +/++ Indentation style to use when formatting passages. +/ enum ESVIndent { SPACE, TAB } -/** Default URL to use when sending API requests. */ -enum string ESVAPI_URL = "https://api.esv.org/v3/passage"; +/++ Default URL to use when sending API requests. +/ +enum ESVAPI_URL = "https://api.esv.org/v3/passage"; -/** Constant array of all books in the Bible. */ -const string[] BIBLE_BOOKS = [ +/++ Constant array of all books in the Bible. +/ +immutable string[] BIBLE_BOOKS = [ /* Old Testament */ "Genesis", "Exodus", @@ -115,8 +115,8 @@ const string[] BIBLE_BOOKS = [ "Revelation" ]; -/** All allowed API parameters (for text passages). */ -const string[] ESVAPI_PARAMETERS = [ +/++ All allowed API parameters (for text passages). +/ +immutable string[] ESVAPI_PARAMETERS = [ "include-passage-references", "include-verse-numbers", "include-first-verse-numbers", @@ -138,10 +138,10 @@ const string[] ESVAPI_PARAMETERS = [ "indent-using", ]; -/** - * Returns true if the argument book is a valid book of the Bible. - * Otherwise, returns false. - */ +/++ + + Returns true if the argument book is a valid book of the Bible. + + Otherwise, returns false. + +/ bool bookValid(in char[] book) nothrow { @@ -151,10 +151,10 @@ bookValid(in char[] book) nothrow } return false; } -/** - * Returns true if the argument verse is a valid verse format. - * Otherwise, returns false. - */ +/++ + + Returns true if the argument verse is a valid verse format. + + Otherwise, returns false. + +/ bool verseValid(in char[] verse) { @@ -171,12 +171,12 @@ verseValid(in char[] verse) return false; } -/** - * ESV API object containing the authentication key, - * the API URL, any parameters to use when contacting the - * API as well as the temporary directory to use when - * fetching audio passages. - */ +/++ + + ESV API object containing the authentication key, + + the API URL, any parameters to use when contacting the + + API as well as the temporary directory to use when + + fetching audio passages. + +/ class ESVApi { protected { @@ -187,14 +187,14 @@ class ESVApi ESVApiOptions opts; - /** Additional request parameters */ + /++ Additional request parameters +/ string extraParameters; - /** Called whenever progress is made on a request. */ + /++ Called whenever progress is made on a request. +/ int delegate(size_t, size_t, size_t, size_t) onProgress; - /** - * Constructs an ESVApi object using the given authentication key. - */ + /++ + + Constructs an ESVApi object using the given authentication key. + +/ this(string key, string tmpName = "esv") { _key = key; @@ -209,48 +209,43 @@ class ESVApi }; } - /** - * Returns the API authentication key that was given when the object - * was constructed. This authentication key cannot be changed. - */ + /++ + + Returns the API authentication key that was given when the object + + was constructed. This authentication key cannot be changed. + +/ final @property string key() const nothrow pure @nogc - { - return _key; - } - /** - * Returns the subdirectory used to store temporary audio passages. - */ + => _key; + /++ + + Returns the subdirectory used to store temporary audio passages. + +/ final @property string tmpDir() const nothrow pure @nogc - { - return _tmp; - } - /** - * Returns the API URL currently in use. - */ + => _tmp; + /++ + + Returns the API URL currently in use. + +/ final @property string url() const nothrow pure @nogc - { - return _url; - } - /** - * Sets the API URL currently in use to the given url argument. - */ + => _url; + /++ + + Sets the API URL currently in use to the given url argument. + +/ final @property void url(immutable(string) url) in (!url.matchAll(`^https?://.+\\..+(/.+)?`).empty, "Invalid URL format") { _url = url; } - /** - * Requests the passage in text format from the API and returns it. - * The (case-insensitive) name of the book being searched are - * contained in the argument book. The verse(s) being looked up are - * contained in the argument verses. - * - * Example: getPassage("John", "3:16-21") - */ + + /++ + + Requests the passage in text format from the API and returns it. + + The (case-insensitive) name of the book being searched are + + contained in the argument book. The verse(s) being looked up are + + contained in the argument verses. + + + + Example: getPassage("John", "3:16-21") + +/ string getPassage(in char[] book, in char[] verse) in (bookValid(book), "Invalid book") @@ -258,7 +253,7 @@ class ESVApi { char[] params, response; - params = []; + params = []; { string[] parambuf; @@ -289,21 +284,20 @@ class ESVApi } response = makeRequest(format!"text/?q=%s+%s"( - book - .capitalize() - .tr(" ", "+"), - verse) ~ params ~ extraParameters); + book.capitalize().tr(" ", "+"), verse) + ~ params ~ extraParameters); + return response.parseJSON()["passages"][0].str; } - /** - * Requests an audio track of the verse(s) from the API and - * returns a file path containing an MP3 sound track. - * The (case-insensitive) name of the book being searched are - * contained in the argument book. The verse(s) being looked up are - * contained in the argument verses. - * - * Example: getAudioPassage("John", "3:16-21") - */ + /++ + + Requests an audio track of the verse(s) from the API and + + returns a file path containing an MP3 sound track. + + The (case-insensitive) name of the book being searched are + + contained in the argument book. The verse(s) being looked up are + + contained in the argument verses. + + + + Example: getAudioPassage("John", "3:16-21") + +/ string getAudioPassage(in char[] book, in char[] verse) in (bookValid(book), "Invalid book") @@ -313,28 +307,25 @@ class ESVApi tmpFile = File(_tmp, "w"); tmpFile.write(makeRequest(format!"audio/?q=%s+%s"( - book - .capitalize() - .tr(" ", "+"), - verse) - )); + book.capitalize().tr(" ", "+"), verse))); + return _tmp; } - /** - * Requests a passage search for the given query. - * Returns a string containing JSON data representing - * the results of the search. - * - * Example: search("It is finished") - */ + /++ + + Requests a passage search for the given query. + + Returns a string containing JSON data representing + + the results of the search. + + + + Example: search("It is finished") + +/ char[] search(in string query) { return makeRequest("search/?q=" ~ query.tr(" ", "+")); } - /** - * Calls search() and formats the results nicely as plain text. - */ + /++ + + Calls search() and formats the results nicely as plain text. + +/ char[] searchFormat(alias fmt = "\033[1m%s\033[0m\n %s\n") (in string query, int lineLength = 0) /* 0 means default */ @@ -385,52 +376,52 @@ class ESVApi } } -/** - * Structure containing parameters passed to the ESV API. - */ +/++ + + Structure containing parameters passed to the ESV API. + +/ struct ESVApiOptions { bool[string] b; int[string] i; ESVIndent indent_using; - /** - * If initialise is true, initialise an ESVApiOptions - * structure with the default values. - */ + /++ + + If initialise is true, initialise an ESVApiOptions + + structure with the default values. + +/ this(bool initialise) nothrow { if (!initialise) return; - b["include-passage-references"] = true; - b["include-verse-numbers"] = true; - b["include-first-verse-numbers"] = true; - b["include-footnotes"] = true; - b["include-footnote-body"] = true; - b["include-headings"] = true; - b["include-short-copyright"] = true; - b["include-copyright"] = false; + b["include-passage-references"] = true; + b["include-verse-numbers"] = true; + b["include-first-verse-numbers"] = true; + b["include-footnotes"] = true; + b["include-footnote-body"] = true; + b["include-headings"] = true; + b["include-short-copyright"] = true; + b["include-copyright"] = false; b["include-passage-horizontal-lines"] = false; b["include-heading-horizontal-lines"] = false; - b["include-selahs"] = true; - b["indent-poetry"] = true; - i["horizontal-line-length"] = 55; - i["indent-paragraphs"] = 2; - i["indent-poetry-lines"] = 4; - i["indent-declares"] = 40; - i["indent-psalm-doxology"] = 30; - i["line-length"] = 0; + b["include-selahs"] = true; + b["indent-poetry"] = true; + i["horizontal-line-length"] = 55; + i["indent-paragraphs"] = 2; + i["indent-poetry-lines"] = 4; + i["indent-declares"] = 40; + i["indent-psalm-doxology"] = 30; + i["line-length"] = 0; indent_using = ESVIndent.SPACE; } } -/** - * Exception thrown on API errors. - * - * Currently only used when there is no search results - * following a call of searchFormat. - */ +/++ + + Exception thrown on API errors. + + + + Currently only used when there is no search results + + following a call of searchFormat. + +/ class ESVException : Exception { mixin basicExceptionCtors;