From 1fa3a25a6851da90a2f30fd22a97a13b26dd1b6e Mon Sep 17 00:00:00 2001 From: =?utf8?q?David=20=E2=80=98Bombe=E2=80=99=20Roden?= Date: Sun, 29 May 2016 19:35:20 +0200 Subject: [PATCH] Use a single hour state for all weather services --- .../rhynodge/webpages/weather/HourState.kt | 22 +++++++ .../webpages/weather/wettercom/HourState.kt | 77 ---------------------- .../webpages/weather/wettercom/WetterComFilter.kt | 51 +++++++------- .../webpages/weather/wettercom/WetterComState.kt | 3 +- .../webpages/weather/wetterde/HourState.kt | 24 ------- .../webpages/weather/wetterde/WetterDeFilter.kt | 1 + .../webpages/weather/wetterde/WetterDeState.kt | 1 + .../webpages/weather/wetterde/WetterDeTrigger.kt | 12 +++- .../weather/wettercom/WetterComFilterTest.kt | 49 +++++++------- .../weather/wettercom/WetterComStateTest.kt | 17 ++--- .../weather/wettercom/WetterComTriggerTest.kt | 5 +- .../weather/wetterde/WetterDeFilterTest.kt | 1 + .../webpages/weather/wetterde/WetterDeStateTest.kt | 1 + .../weather/wetterde/WetterDeTriggerTest.kt | 1 + 14 files changed, 102 insertions(+), 163 deletions(-) create mode 100644 src/main/kotlin/net/pterodactylus/rhynodge/webpages/weather/HourState.kt delete mode 100644 src/main/kotlin/net/pterodactylus/rhynodge/webpages/weather/wettercom/HourState.kt delete mode 100644 src/main/kotlin/net/pterodactylus/rhynodge/webpages/weather/wetterde/HourState.kt diff --git a/src/main/kotlin/net/pterodactylus/rhynodge/webpages/weather/HourState.kt b/src/main/kotlin/net/pterodactylus/rhynodge/webpages/weather/HourState.kt new file mode 100644 index 0000000..1a14783 --- /dev/null +++ b/src/main/kotlin/net/pterodactylus/rhynodge/webpages/weather/HourState.kt @@ -0,0 +1,22 @@ +package net.pterodactylus.rhynodge.webpages.weather + +import com.fasterxml.jackson.annotation.JsonProperty +import net.pterodactylus.rhynodge.webpages.weather.WindDirection + +/** + * Container for weather conditions of a single hour. + * + * @author [David ‘Bombe’ Roden](mailto:bombe@pterodactylus.net) + */ +data class HourState( + @JsonProperty("hourIndex") val hourIndex: Int, + @JsonProperty("temperature") val temperature: Int, + @JsonProperty("feltTemperature") val feltTemperature: Int? = null, + @JsonProperty("rainProbability") val rainProbability: Double, + @JsonProperty("rainAmount") val rainAmount: Double, + @JsonProperty("windDirection") val windDirection: WindDirection, + @JsonProperty("windSpeed") val windSpeed: Int, + @JsonProperty("gustSpeed") val gustSpeed: Int? = null, + @JsonProperty("humidity") val humidity: Double? = null, + @JsonProperty("description") val description: String, + @JsonProperty("image") val image: String) diff --git a/src/main/kotlin/net/pterodactylus/rhynodge/webpages/weather/wettercom/HourState.kt b/src/main/kotlin/net/pterodactylus/rhynodge/webpages/weather/wettercom/HourState.kt deleted file mode 100644 index cd21a92..0000000 --- a/src/main/kotlin/net/pterodactylus/rhynodge/webpages/weather/wettercom/HourState.kt +++ /dev/null @@ -1,77 +0,0 @@ -package net.pterodactylus.rhynodge.webpages.weather.wettercom - -import com.fasterxml.jackson.annotation.JsonProperty -import net.pterodactylus.rhynodge.webpages.weather.WindDirection - -/** - * Container for weather conditions of a single hour. - * - * @author [David ‘Bombe’ Roden](mailto:bombe@pterodactylus.net) - */ -data class HourState( - @JsonProperty("hourIndex") val hourIndex: Int, - @JsonProperty("temperature") val temperature: Double, - @JsonProperty("rainProbability") val rainProbability: Double, - @JsonProperty("rainAmount") val rainAmount: Double, - @JsonProperty("windDirection") val windDirection: WindDirection, - @JsonProperty("windSpeed") val windSpeed: Double, - @JsonProperty("description") val description: String, - @JsonProperty("image") val image: String) { - - class Builder(private val hourIndex: Int) { - - fun temperature(temperature: Double) = _1(temperature) - - inner class _1(private val temperature: Double) { - - fun rainProbability(rainProbability: Double) = _2(rainProbability) - - inner class _2(private val rainProbability: Double) { - - fun rainAmount(rainAmount: Double) = _3(rainAmount) - - inner class _3(private val rainAmount: Double) { - - fun windFrom(windDirection: WindDirection) = _4(windDirection); - - inner class _4(private val windDirection: WindDirection) { - - fun at(windSpeed: Double) = _5(windSpeed) - - inner class _5(private val windSpeed: Double) { - - fun describedAs(description: String) = _6(description) - - inner class _6(private val description: String) { - - fun withImage(imageUrl: String) = _7(imageUrl) - - inner class _7(private val imageUrl: String) { - - fun build(): HourState { - return HourState(hourIndex, temperature, rainProbability, rainAmount, windDirection, windSpeed, description, imageUrl) - } - - } - - } - - } - - } - - } - - } - - } - - } - - companion object { - - fun atHour(hourIndex: Int) = Builder(hourIndex) - - } - -} diff --git a/src/main/kotlin/net/pterodactylus/rhynodge/webpages/weather/wettercom/WetterComFilter.kt b/src/main/kotlin/net/pterodactylus/rhynodge/webpages/weather/wettercom/WetterComFilter.kt index dc33b65..d6e1a08 100644 --- a/src/main/kotlin/net/pterodactylus/rhynodge/webpages/weather/wettercom/WetterComFilter.kt +++ b/src/main/kotlin/net/pterodactylus/rhynodge/webpages/weather/wettercom/WetterComFilter.kt @@ -4,6 +4,8 @@ import net.pterodactylus.rhynodge.Filter import net.pterodactylus.rhynodge.State import net.pterodactylus.rhynodge.states.FailedState import net.pterodactylus.rhynodge.states.HtmlState +import net.pterodactylus.rhynodge.webpages.weather.HourState +import net.pterodactylus.rhynodge.webpages.weather.WindDirection import net.pterodactylus.rhynodge.webpages.weather.toWindDirection import org.jsoup.nodes.Document import org.jsoup.nodes.Element @@ -35,7 +37,7 @@ class WetterComFilter : Filter { private fun parseWetterComState(state: HtmlState): State { val dateTime = parseDateTime(state.document()) ?: return FailedState(IllegalArgumentException("no date present")) val wetterComState = WetterComState(dateTime) - parseHourStates(state.document()).forEach { wetterComState.addHour(it) } + parseHourStates(state.document()).forEach { wetterComState += it } return wetterComState } @@ -52,37 +54,38 @@ class WetterComFilter : Filter { } private fun parseHourState(index: Int, hourElement: Element): HourState { - return HourState.atHour(index) - .temperature(parseTemperature(hourElement)) - .rainProbability(parseRainProbability(hourElement)) - .rainAmount(parseRainAmount(hourElement)) - .windFrom(parseWindDirection(hourElement)) - .at(parseWindSpeed(hourElement)) - .describedAs(parseDescription(hourElement)) - .withImage(parseImageUrl(hourElement)) - .build() + return HourState( + hourIndex = index, + temperature = hourElement.temperature, + rainProbability = hourElement.rainProbability, + rainAmount = hourElement.rainAmount, + windDirection = hourElement.windDirection, + windSpeed = hourElement.windSpeed, + description = hourElement.description, + image = hourElement.imageUrl + ) } - private fun parseTemperature(hourElement: Element) = - hourElement.extractText(".weather-strip__2 .item-weathericon .palm-hide").filter { (it >= '0') and (it <= '9') }.toDouble() + private val Element.temperature: Int + get() = extractText(".weather-strip__2 .item-weathericon .palm-hide").filter { (it >= '0') and (it <= '9') }.toInt() - private fun parseRainProbability(hourElement: Element) = - hourElement.extractText(".weather-strip__3 .text--left:eq(0) .flag__body span:eq(0)").filter { (it >= '0') and (it <= '9') }.toDouble() / 100.0 + private val Element.rainProbability: Double + get() = extractText(".weather-strip__3 .text--left:eq(0) .flag__body span:eq(0)").filter { (it >= '0') and (it <= '9') }.toDouble() / 100.0 - private fun parseRainAmount(hourElement: Element) = - hourElement.extractText(".weather-strip__3 .text--left:eq(0) .flag__body span:eq(1)").trim().split(" ").getOrNull(1)?.toDouble() ?: 0.0 + private val Element.rainAmount: Double + get() = extractText(".weather-strip__3 .text--left:eq(0) .flag__body span:eq(1)").trim().split(" ").getOrNull(1)?.toDouble() ?: 0.0 - private fun parseWindDirection(hourElement: Element) = - hourElement.extractText(".weather-strip__3 .text--left:eq(1) .flag__body span:eq(0)").trim().split(",")[0].toWindDirection() + private val Element.windDirection: WindDirection + get() = extractText(".weather-strip__3 .text--left:eq(1) .flag__body span:eq(0)").trim().split(",")[0].toWindDirection() - private fun parseWindSpeed(hourElement: Element) = - hourElement.extractText(".weather-strip__3 .text--left:eq(1) .flag__body span:eq(0)").split(Regex("[, ]+"))[1].toDouble() + private val Element.windSpeed: Int + get() = extractText(".weather-strip__3 .text--left:eq(1) .flag__body span:eq(0)").split(Regex("[, ]+"))[1].toInt() - private fun parseDescription(hourElement: Element) = - hourElement.extractText(".weather-strip__1 .vhs-text--small") + private val Element.description: String + get() = extractText(".weather-strip__1 .vhs-text--small") - private fun parseImageUrl(hourElement: Element) = - hourElement.select(".weather-strip__2 img").firstOrNull()?.attr("src") ?: "" + private val Element.imageUrl: String + get() = select(".weather-strip__2 img").firstOrNull()?.attr("src") ?: "" private fun Element.extractText(selector: String) = select(selector).firstOrNull()?.text() ?: "" diff --git a/src/main/kotlin/net/pterodactylus/rhynodge/webpages/weather/wettercom/WetterComState.kt b/src/main/kotlin/net/pterodactylus/rhynodge/webpages/weather/wettercom/WetterComState.kt index be18847..e6c2b5e 100644 --- a/src/main/kotlin/net/pterodactylus/rhynodge/webpages/weather/wettercom/WetterComState.kt +++ b/src/main/kotlin/net/pterodactylus/rhynodge/webpages/weather/wettercom/WetterComState.kt @@ -3,6 +3,7 @@ package net.pterodactylus.rhynodge.webpages.weather.wettercom import com.fasterxml.jackson.annotation.JsonGetter import com.fasterxml.jackson.annotation.JsonProperty import net.pterodactylus.rhynodge.states.AbstractState +import net.pterodactylus.rhynodge.webpages.weather.HourState import java.time.Instant import java.time.ZoneId import java.time.ZonedDateTime @@ -24,7 +25,7 @@ class WetterComState(val dateTime: ZonedDateTime) : AbstractState(true), Iterabl @JsonGetter("dateTime") get() = dateTime.toInstant().toEpochMilli() - fun addHour(hourState: HourState) { + operator fun plusAssign(hourState: HourState) { (hours as MutableList).add(hourState) } diff --git a/src/main/kotlin/net/pterodactylus/rhynodge/webpages/weather/wetterde/HourState.kt b/src/main/kotlin/net/pterodactylus/rhynodge/webpages/weather/wetterde/HourState.kt deleted file mode 100644 index f8e7dc6..0000000 --- a/src/main/kotlin/net/pterodactylus/rhynodge/webpages/weather/wetterde/HourState.kt +++ /dev/null @@ -1,24 +0,0 @@ -package net.pterodactylus.rhynodge.webpages.weather.wetterde - -import com.fasterxml.jackson.annotation.JsonProperty -import net.pterodactylus.rhynodge.webpages.weather.WindDirection - -/** - * Container for weather conditions of a single hour. - * - * @author [David ‘Bombe’ Roden](mailto:bombe@pterodactylus.net) - */ -data class HourState( - @JsonProperty("hourIndex") val hourIndex: Int, - @JsonProperty("temperature") val temperature: Int, - @JsonProperty("feltTemperature") val feltTemperature: Int, - @JsonProperty("rainProbability") val rainProbability: Double, - @JsonProperty("rainAmount") val rainAmount: Double, - @JsonProperty("windDirection") val windDirection: WindDirection, - @JsonProperty("windSpeed") val windSpeed: Int, - @JsonProperty("gustSpeed") val gustSpeed: Int, - @JsonProperty("humidity") val humidity: Double, - @JsonProperty("description") val description: String, - @JsonProperty("image") val image: String) { - -} diff --git a/src/main/kotlin/net/pterodactylus/rhynodge/webpages/weather/wetterde/WetterDeFilter.kt b/src/main/kotlin/net/pterodactylus/rhynodge/webpages/weather/wetterde/WetterDeFilter.kt index 4e7010e..245a8a4 100644 --- a/src/main/kotlin/net/pterodactylus/rhynodge/webpages/weather/wetterde/WetterDeFilter.kt +++ b/src/main/kotlin/net/pterodactylus/rhynodge/webpages/weather/wetterde/WetterDeFilter.kt @@ -4,6 +4,7 @@ import net.pterodactylus.rhynodge.Filter import net.pterodactylus.rhynodge.State import net.pterodactylus.rhynodge.states.FailedState import net.pterodactylus.rhynodge.states.HtmlState +import net.pterodactylus.rhynodge.webpages.weather.HourState import net.pterodactylus.rhynodge.webpages.weather.WindDirection import net.pterodactylus.rhynodge.webpages.weather.toWindDirection import org.jsoup.nodes.Document diff --git a/src/main/kotlin/net/pterodactylus/rhynodge/webpages/weather/wetterde/WetterDeState.kt b/src/main/kotlin/net/pterodactylus/rhynodge/webpages/weather/wetterde/WetterDeState.kt index 2651ed5..74b7ef0 100644 --- a/src/main/kotlin/net/pterodactylus/rhynodge/webpages/weather/wetterde/WetterDeState.kt +++ b/src/main/kotlin/net/pterodactylus/rhynodge/webpages/weather/wetterde/WetterDeState.kt @@ -2,6 +2,7 @@ package net.pterodactylus.rhynodge.webpages.weather.wetterde import com.fasterxml.jackson.annotation.JsonProperty import net.pterodactylus.rhynodge.states.AbstractState +import net.pterodactylus.rhynodge.webpages.weather.HourState import java.time.Instant import java.time.ZoneId.of import java.time.ZonedDateTime diff --git a/src/main/kotlin/net/pterodactylus/rhynodge/webpages/weather/wetterde/WetterDeTrigger.kt b/src/main/kotlin/net/pterodactylus/rhynodge/webpages/weather/wetterde/WetterDeTrigger.kt index 39ec116..178fce4 100644 --- a/src/main/kotlin/net/pterodactylus/rhynodge/webpages/weather/wetterde/WetterDeTrigger.kt +++ b/src/main/kotlin/net/pterodactylus/rhynodge/webpages/weather/wetterde/WetterDeTrigger.kt @@ -62,13 +62,19 @@ class WetterDeTrigger : Trigger { div("hour-state") { div("time") { +"%tH:%)) } @@ -50,8 +51,8 @@ class WetterComStateTest { val objectMapper = ObjectMapper() val now = Instant.now().atZone(ZoneId.of("Europe/Berlin")) val originalState = WetterComState(ZonedDateTime.from(now)) - originalState.addHour(HourState(0, 10.0, 0.05, 0.0, WindDirection.NORTH, 5.0, "Fine", "http://1")) - originalState.addHour(HourState(1, 12.0, 0.1, 2.0, WindDirection.WEST, 8.0, "Superb", "http://2")) + originalState += HourState(0, 10, null, 0.05, 0.0, WindDirection.NORTH, 5, null, null, "Fine", "http://1") + originalState += HourState(1, 12, null, 0.1, 2.0, WindDirection.WEST, 8, null, null, "Superb", "http://2") val json = objectMapper.writeValueAsString(originalState) println(json) val parsedState = objectMapper.readValue(json, WetterComState::class.java) diff --git a/src/test/kotlin/net/pterodactylus/rhynodge/webpages/weather/wettercom/WetterComTriggerTest.kt b/src/test/kotlin/net/pterodactylus/rhynodge/webpages/weather/wettercom/WetterComTriggerTest.kt index 5cc3f06..aa69a07 100644 --- a/src/test/kotlin/net/pterodactylus/rhynodge/webpages/weather/wettercom/WetterComTriggerTest.kt +++ b/src/test/kotlin/net/pterodactylus/rhynodge/webpages/weather/wettercom/WetterComTriggerTest.kt @@ -1,6 +1,7 @@ package net.pterodactylus.rhynodge.webpages.weather.wettercom import net.pterodactylus.rhynodge.Reaction +import net.pterodactylus.rhynodge.webpages.weather.HourState import net.pterodactylus.rhynodge.webpages.weather.WindDirection import org.hamcrest.MatcherAssert.assertThat import org.hamcrest.Matchers.`is` @@ -62,8 +63,8 @@ class WetterComTriggerTest { @Test fun outputHtmlContainsHourStates() { val currentState = WetterComState(now.minusDays(1)) - currentState.addHour(HourState(0, 10.0, 0.11, 12.0, WindDirection.NORTH, 13.0, "Rain", "http://1")) - currentState.addHour(HourState(1, 14.0, 0.15, 16.0, WindDirection.SOUTH, 17.0, "Sun", "http://2")) + currentState += HourState(0, 10, null, 0.11, 12.0, WindDirection.NORTH, 13, null, null, "Rain", "http://1") + currentState += HourState(1, 14, null, 0.15, 16.0, WindDirection.SOUTH, 17, null, null, "Sun", "http://2") trigger.mergeStates(previousState, currentState) as WetterComState val reaction = Mockito.mock(Reaction::class.java) val output = trigger.output(reaction) diff --git a/src/test/kotlin/net/pterodactylus/rhynodge/webpages/weather/wetterde/WetterDeFilterTest.kt b/src/test/kotlin/net/pterodactylus/rhynodge/webpages/weather/wetterde/WetterDeFilterTest.kt index 3e7a25a..fc435c2 100644 --- a/src/test/kotlin/net/pterodactylus/rhynodge/webpages/weather/wetterde/WetterDeFilterTest.kt +++ b/src/test/kotlin/net/pterodactylus/rhynodge/webpages/weather/wetterde/WetterDeFilterTest.kt @@ -4,6 +4,7 @@ import net.pterodactylus.rhynodge.filters.ResourceLoader import net.pterodactylus.rhynodge.states.AbstractState import net.pterodactylus.rhynodge.states.FailedState import net.pterodactylus.rhynodge.states.HtmlState +import net.pterodactylus.rhynodge.webpages.weather.HourState import net.pterodactylus.rhynodge.webpages.weather.WindDirection import org.hamcrest.MatcherAssert.assertThat import org.hamcrest.Matchers.`is` diff --git a/src/test/kotlin/net/pterodactylus/rhynodge/webpages/weather/wetterde/WetterDeStateTest.kt b/src/test/kotlin/net/pterodactylus/rhynodge/webpages/weather/wetterde/WetterDeStateTest.kt index b3de810..aa21c0c 100644 --- a/src/test/kotlin/net/pterodactylus/rhynodge/webpages/weather/wetterde/WetterDeStateTest.kt +++ b/src/test/kotlin/net/pterodactylus/rhynodge/webpages/weather/wetterde/WetterDeStateTest.kt @@ -1,6 +1,7 @@ package net.pterodactylus.rhynodge.webpages.weather.wetterde import com.fasterxml.jackson.databind.ObjectMapper +import net.pterodactylus.rhynodge.webpages.weather.HourState import net.pterodactylus.rhynodge.webpages.weather.WindDirection import org.hamcrest.MatcherAssert.assertThat import org.hamcrest.Matchers.`is` diff --git a/src/test/kotlin/net/pterodactylus/rhynodge/webpages/weather/wetterde/WetterDeTriggerTest.kt b/src/test/kotlin/net/pterodactylus/rhynodge/webpages/weather/wetterde/WetterDeTriggerTest.kt index ba5bf46..1dac1ab 100644 --- a/src/test/kotlin/net/pterodactylus/rhynodge/webpages/weather/wetterde/WetterDeTriggerTest.kt +++ b/src/test/kotlin/net/pterodactylus/rhynodge/webpages/weather/wetterde/WetterDeTriggerTest.kt @@ -2,6 +2,7 @@ package net.pterodactylus.rhynodge.webpages.weather.wetterde import net.pterodactylus.rhynodge.Reaction import net.pterodactylus.rhynodge.State +import net.pterodactylus.rhynodge.webpages.weather.HourState import net.pterodactylus.rhynodge.webpages.weather.WindDirection import org.hamcrest.MatcherAssert.assertThat import org.hamcrest.Matchers.`is` -- 2.7.4