Added round parameter. Closes #1

This commit is contained in:
Erik C. Thauvin 2021-05-30 17:40:03 -07:00
parent d99218f43b
commit 6cabd2e723
7 changed files with 102 additions and 93 deletions

View file

@ -22,7 +22,17 @@ To get the estimated reading time in seconds use the `calcReadingTimeInSec()` fu
- View [Kotlin](https://github.com/ethauvin/readingtime/blob/master/examples/src/main/kotlin/com/example/ReadingTimeExample.kt) or [Java](https://github.com/ethauvin/readingtime/blob/master/examples/src/main/java/com/example/ReadingTimeSample.java) Examples.
### Gradle, Maven, etc.
To use with [Gradle](https://gradle.org/), include the following dependency in your [build](https://github.com/ethauvin/readingtime/blob/master/examples/build.gradle.kts) file:
```gradle
dependencies {
implementation("net.thauvin.erik:readingtime:0.9.1")
}
```
Instructions for using with Maven, Ivy, etc. can be found on [Maven Central](https://search.maven.org/artifact/net.thauvin.erik/readingtime/0.9.0/jar).
### Properties
@ -30,24 +40,26 @@ The following properties are available:
```kotlin
ReadingTime(
text = "some_text",
text,
wpm = 275,
postfix = "min read",
plural = "min read",
excludeImages = false,
extra = 0
extra = 0,
round = RoundingMode.HALF_DOWN
)
```
Property | Description
:-------------------------- |:-------------------------------------------------------------------
`text` | The text to be evaluated.
Property | Description
:-------------------------- |:-----------------------------------------------------------------------------------------------------------------------
`text` | The text to be evaluated. (Required)
`wpm` | The words per minute reading average.
`postfix` | The value to be appended to the reading time.
`plural` | The value to be appended if the reading time is more than 1 minute.
`excludeImages` | Images are excluded from the reading time when set.
`extra` | Additional seconds to be added to the total reading time.
`round` | The [rounding mode](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/math/RoundingMode.html) to apply.
### Functions
@ -73,15 +85,3 @@ A JSP tag is also available for easy incorporation into web applications:
```
None of the attributes are required.
### Gradle, Maven, etc.
To use with [Gradle](https://gradle.org/), include the following dependency in your [build](https://github.com/ethauvin/readingtime/blob/master/examples/build.gradle.kts) file:
```gradle
dependencies {
implementation("net.thauvin.erik:readingtime:0.9.0")
}
```
Instructions for using with Maven, Ivy, etc. can be found on [Maven Central](https://search.maven.org/artifact/net.thauvin.erik/readingtime/0.9.0/jar).

View file

@ -6,16 +6,16 @@ import java.io.FileInputStream
import java.util.*
plugins {
id("com.github.ben-manes.versions") version "0.38.0"
id("com.github.ben-manes.versions") version "0.39.0"
id("io.gitlab.arturbosch.detekt") version "1.17.1"
id("jacoco")
id("java")
id("java-library")
id("maven-publish")
id("org.jetbrains.dokka") version "1.4.32"
id("org.jetbrains.kotlin.jvm") version "1.5.0"
id("org.sonarqube") version "3.2.0"
java
`java-library`
`maven-publish`
jacoco
signing
id("signing")
kotlin("jvm") version "1.5.10"
}
description = "Estimated Reading Time for Blog Posts, Articles, etc."
@ -34,12 +34,12 @@ repositories {
}
dependencies {
implementation(platform("org.jetbrains.kotlin:kotlin-bom"))
implementation(platform(kotlin("bom")))
implementation("org.jsoup:jsoup:1.13.1")
testImplementation("org.jetbrains.kotlin:kotlin-test")
testImplementation("org.jetbrains.kotlin:kotlin-test-junit")
testImplementation(kotlin("test"))
testImplementation(kotlin("test-junit"))
}
java {

View file

@ -1,11 +1,11 @@
<?xml version="1.0" ?>
<?xml version='1.0' encoding='UTF-8'?>
<SmellBaseline>
<ManuallySuppressedIssues/>
<CurrentIssues>
<ID>LongParameterList:ReadingTime.kt$ReadingTime$( text: String, wpm: Int = 275, var postfix: String = "min read", var plural: String = "min read", excludeImages: Boolean = false, extra: Int = 0, var round: RoundingMode = RoundingMode.HALF_DOWN )</ID>
<ID>MagicNumber:ReadingTime.kt$ReadingTime$10</ID>
<ID>MagicNumber:ReadingTime.kt$ReadingTime$12</ID>
<ID>MagicNumber:ReadingTime.kt$ReadingTime$3</ID>
<ID>MagicNumber:ReadingTime.kt$ReadingTime$60</ID>
<ID>MagicNumber:ReadingTime.kt$ReadingTime$60.0</ID>
</CurrentIssues>
</SmellBaseline>

View file

@ -1,7 +1,7 @@
plugins {
id("org.jetbrains.kotlin.jvm") version "1.5.0"
id("com.github.ben-manes.versions") version "0.38.0"
application
id("application")
id("com.github.ben-manes.versions") version "0.39.0"
kotlin("jvm") version "1.5.10"
}
// ./gradlew run

View file

@ -40,7 +40,7 @@
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-bom</artifactId>
<version>1.5.0</version>
<version>1.5.10</version>
<type>pom</type>
<scope>import</scope>
</dependency>
@ -50,7 +50,7 @@
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib-jdk8</artifactId>
<version>1.5.0</version>
<version>1.5.10</version>
<scope>compile</scope>
</dependency>
<dependency>

View file

@ -49,6 +49,7 @@ import java.math.RoundingMode
* @param plural The value to be appended if the reading time is more than 1 minute.
* @param excludeImages Images are excluded from the reading time when set.
* @param extra Additional seconds to be added to the total reading time.
* @param round The [RoundingMode] to apply. Default is [RoundingMode.HALF_DOWN].
*/
class ReadingTime @JvmOverloads constructor(
text: String,
@ -56,7 +57,8 @@ class ReadingTime @JvmOverloads constructor(
var postfix: String = "min read",
var plural: String = "min read",
excludeImages: Boolean = false,
extra: Int = 0
extra: Int = 0,
var round: RoundingMode = RoundingMode.HALF_DOWN
) {
companion object {
private const val INVALID: Double = -1.0
@ -108,7 +110,9 @@ class ReadingTime @JvmOverloads constructor(
}
/**
* Calculates and returns the reading time in seconds.
* Calculates and returns the reading time in seconds.
*
* `((word count / wpm) * 60) + images + extra`
*/
fun calcReadingTimeInSec(): Double {
if (readTime == INVALID) {
@ -121,9 +125,11 @@ class ReadingTime @JvmOverloads constructor(
/**
* Calculates and returns the reading time. (eg. 1 min read)
*
* `(reading time in sec / 60) + postfix`
*/
fun calcReadingTime(): String {
val time = BigDecimal((calcReadingTimeInSec() / 60.0)).setScale(0, RoundingMode.HALF_DOWN)
val time = BigDecimal((calcReadingTimeInSec() / 60.0)).setScale(0, round)
return if (time.compareTo(BigDecimal.ONE) == 1) {
"$time $plural".trim()
} else {
@ -131,6 +137,10 @@ class ReadingTime @JvmOverloads constructor(
}
}
/**
* 12 seconds for the first image, 11 for the second, and minus an additional second for each subsequent image.
* Any images after the tenth image are counted at 3 seconds.
*/
private fun calcImgReadingTime(): Int {
var time = 0
val imgCount = imgCount(text)

View file

@ -33,28 +33,16 @@
package net.thauvin.erik.readingtime
import java.io.File
import java.math.RoundingMode
import kotlin.test.Test
import kotlin.test.assertEquals
class ReadingTimeTest {
private val rt = ReadingTime("This is a <b>test</b>.\nWith an image: <img src=\"#\">")
private val img = """<img src="#">"""
private val rt = ReadingTime("This is a <b>test</b>.\nWith an image: $img")
private val blogPost = File("src/test/resources/post.html").readText()
private val mediumPost = File("src/test/resources/medium.html").readText()
private val twoSeventyFive = """one two three four five six seven eight nine ten one two three four five six seven
eight nine ten one two three four five six seven eight nine ten one two three four five six seven eight nine
ten one two three four five six seven eight nine ten one two three four five six seven eight nine ten one two
three four five six seven eight nine ten one two three four five six seven eight nine ten one two three four
five six seven eight nine ten one two three four five six seven eight nine ten one two three four five six
seven eight nine ten one two three four five six seven eight nine ten one two three four five six seven eight
nine ten one two three four five six seven eight nine ten one two three four five six seven eight nine ten
one two three four five six seven eight nine ten one two three four five six seven eight nine ten one two
three four five six seven eight nine ten one two three four five six seven eight nine ten one two three four
five six seven eight nine ten one two three four five six seven eight nine ten one two three four five six
seven eight nine ten one two three four five six seven eight nine ten one two three four five six seven eight
nine ten one two three four five six seven eight nine ten one two three four five six seven eight nine ten
one two three four five six seven eight nine ten one two three four five"""
private val tenImages = "<img src=\"#\"> <img src=\"#\"> <img src=\"#\"> <img src=\"#\"> <img src=\"#\"> " +
"<img src=\"#\"> <img src=\"#\"> <img src=\"#\"> <img src=\"#\"> <img src=\"#\">"
private val twoSeventyFive = "word ".repeat(275)
private fun calcImgTime(imgCount: Int): Double {
var time = 0.0
@ -75,100 +63,111 @@ one two three four five six seven eight nine ten one two three four five"""
@Test
fun testWordCount() {
assertEquals(0, ReadingTime.wordCount(" "))
assertEquals(3, ReadingTime.wordCount("one two three"))
assertEquals(2, ReadingTime.wordCount(" one two "))
assertEquals(7, ReadingTime.wordCount(rt.text))
assertEquals(505, ReadingTime.wordCount(blogPost))
assertEquals(391, ReadingTime.wordCount(mediumPost))
assertEquals(275, ReadingTime.wordCount(twoSeventyFive))
assertEquals(275, ReadingTime.wordCount("$twoSeventyFive <img src=\"#\""))
assertEquals(0, ReadingTime.wordCount(" "), "empty")
assertEquals(3, ReadingTime.wordCount("one two three"), "one two three")
assertEquals(2, ReadingTime.wordCount(" one two "), "one two")
assertEquals(7, ReadingTime.wordCount(rt.text), "text")
assertEquals(505, ReadingTime.wordCount(blogPost), "blogPost")
assertEquals(391, ReadingTime.wordCount(mediumPost), "mediumPost")
assertEquals(275, ReadingTime.wordCount(twoSeventyFive), "275")
assertEquals(275, ReadingTime.wordCount("$twoSeventyFive $img"), "275 + image")
}
@Test
fun testImgCount() {
assertEquals(1, ReadingTime.imgCount(rt.text))
assertEquals(11, ReadingTime.imgCount(blogPost))
assertEquals(3, ReadingTime.imgCount(mediumPost))
assertEquals(1, ReadingTime.imgCount("$twoSeventyFive <img src=\"#\""))
assertEquals(2, ReadingTime.imgCount("$twoSeventyFive <img src=\"#\"> <img src=\"#\">"))
assertEquals(1, ReadingTime.imgCount(rt.text), "text")
assertEquals(11, ReadingTime.imgCount(blogPost), "blogPost")
assertEquals(3, ReadingTime.imgCount(mediumPost), "mediumPost")
assertEquals(1, ReadingTime.imgCount("$twoSeventyFive $img"), "275 + image")
assertEquals(2, ReadingTime.imgCount("$twoSeventyFive $img $img"), "275 + 2 images")
}
@Test
fun testReadingTimeInSec() {
assertEquals(calcReadingTime(rt.text, rt.wpm) + calcImgTime(1), rt.calcReadingTimeInSec())
assertEquals(calcReadingTime(rt.text, rt.wpm) + calcImgTime(1), rt.calcReadingTimeInSec(), "text + image")
rt.text = "<img src=\"#\"> <IMG src=\"#\">"
assertEquals(calcImgTime(2), rt.calcReadingTimeInSec())
rt.text = "$img ${img.uppercase()}"
assertEquals(calcImgTime(2), rt.calcReadingTimeInSec(), "2 images")
rt.excludeImages = true
assertEquals(0.0, rt.calcReadingTimeInSec())
assertEquals(0.0, rt.calcReadingTimeInSec(), "image uppercase")
rt.excludeImages = false
rt.text = blogPost
assertEquals(
calcReadingTime(rt.text, rt.wpm) + calcImgTime(11), rt.calcReadingTimeInSec()
calcReadingTime(rt.text, rt.wpm) + calcImgTime(11), rt.calcReadingTimeInSec(), "blogPost"
)
rt.excludeImages = true
assertEquals(calcReadingTime(rt.text, rt.wpm), rt.calcReadingTimeInSec())
assertEquals(calcReadingTime(rt.text, rt.wpm), rt.calcReadingTimeInSec(), "exclude images")
rt.extra = 60
assertEquals(calcReadingTime(rt.text, rt.wpm) + 60L, rt.calcReadingTimeInSec())
assertEquals(calcReadingTime(rt.text, rt.wpm) + 60L, rt.calcReadingTimeInSec(), "extra 60")
rt.extra = 0
rt.excludeImages = false
rt.text = mediumPost
rt.wpm = 300
assertEquals(calcReadingTime(rt.text, 300) + calcImgTime(3), rt.calcReadingTimeInSec())
assertEquals(calcReadingTime(rt.text, 300) + calcImgTime(3), rt.calcReadingTimeInSec(), "mediumPost 300 wpm")
rt.wpm = 275
rt.text = "This is a test"
assertEquals(0.0, rt.calcReadingTimeInSec())
assertEquals(0.0, rt.calcReadingTimeInSec(), "test")
rt.text = twoSeventyFive
assertEquals(60.0, rt.calcReadingTimeInSec())
assertEquals(60.0, rt.calcReadingTimeInSec(), "275")
rt.text = "$twoSeventyFive <img src=\"#\">"
assertEquals(72.0, rt.calcReadingTimeInSec())
rt.text = "$twoSeventyFive $img"
assertEquals(72.0, rt.calcReadingTimeInSec(), "275 + image")
rt.text = "$twoSeventyFive <img src=\"#\"> <img src=\"#\">"
assertEquals(83.0, rt.calcReadingTimeInSec())
rt.text = "$twoSeventyFive $img $img"
assertEquals(83.0, rt.calcReadingTimeInSec(), "275 + 2 images")
rt.text = "$twoSeventyFive $tenImages"
assertEquals(60.0 + 12 + 11 + 10 + 9 + 8 + 7 + 6 + 5 + 4 + 3, rt.calcReadingTimeInSec())
rt.text = "$twoSeventyFive ${img.repeat(10)}"
assertEquals(60.0 + 12 + 11 + 10 + 9 + 8 + 7 + 6 + 5 + 4 + 3, rt.calcReadingTimeInSec(), "10 images")
rt.text = "$twoSeventyFive $tenImages <img src=\"#\">"
assertEquals(135.0 + 3, rt.calcReadingTimeInSec())
rt.text = "$twoSeventyFive ${img.repeat(10)} $img"
assertEquals(135.0 + 3, rt.calcReadingTimeInSec(), "11 images")
rt.text = "$twoSeventyFive $twoSeventyFive"
assertEquals(120.0, rt.calcReadingTimeInSec())
assertEquals(120.0, rt.calcReadingTimeInSec(), "275*2")
rt.text = ""
assertEquals(0.0, rt.calcReadingTimeInSec())
assertEquals(0.0, rt.calcReadingTimeInSec(), "empty")
}
@Test
fun testReadingTime() {
rt.text = blogPost
assertEquals("2 min read", rt.calcReadingTime())
assertEquals("2 min read", rt.calcReadingTime(), "blogPost")
rt.plural = "mins read"
assertEquals("2 mins read", rt.calcReadingTime())
assertEquals("2 mins read", rt.calcReadingTime(), "plural")
rt.text = mediumPost
rt.plural = ""
assertEquals("2", rt.calcReadingTime())
assertEquals("2", rt.calcReadingTime(), "mediumPost")
rt.text = "This is a test."
rt.postfix = ""
assertEquals("0", rt.calcReadingTime())
assertEquals("0", rt.calcReadingTime(), "test")
rt.text = ""
assertEquals("0", rt.calcReadingTime())
assertEquals("0", rt.calcReadingTime(), "empty")
rt.text = twoSeventyFive
assertEquals("1", rt.calcReadingTime())
assertEquals("1", rt.calcReadingTime(), "275")
rt.text = "$twoSeventyFive $twoSeventyFive"
assertEquals("2", rt.calcReadingTime())
assertEquals("2", rt.calcReadingTime(), "275 * 2")
}
@Test
fun testRoundingMode() {
rt.text = blogPost
rt.round = RoundingMode.UP
assertEquals("3 min read", rt.calcReadingTime(), "UP")
rt.text = mediumPost
rt.round = RoundingMode.DOWN
assertEquals("1 min read", rt.calcReadingTime(), "DOWN")
}
}