Skip to content

Instantly share code, notes, and snippets.

@asvid
Last active January 22, 2021 19:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save asvid/5fed8dd3c831c2a72744e8ffe8f7dc0f to your computer and use it in GitHub Desktop.
Save asvid/5fed8dd3c831c2a72744e8ffe8f7dc0f to your computer and use it in GitHub Desktop.
Kotlin DSL
data class Address(
val streetName: String,
val cityName: String,
val streetNumber: String,
val postalCode: String
)
fun address(block: AddressBuilder.() -> Unit) = AddressBuilder().apply(block).build()
@ShopDsl
class AddressBuilder {
var streetName = ""
var cityName = ""
var streetNumber = ""
var postalCode = ""
fun build(): Address = Address(streetName, cityName, streetNumber, postalCode)
}
enum class Feature {
Bakery, Relax, Atm, CardPayment, TaxFreeShopping, EuroAccepted, NewShop
}
@ShopDsl
class FeaturesBuilder(private val features: Array<out Feature>) {
fun build(): Set<Feature> {
return features.toSet()
}
}
data class Location(
val lat: Double,
val lng: Double
)
fun location(block: LocationBuilder.() -> Unit): Location = LocationBuilder().apply(block).build()
@ShopDsl
class LocationBuilder {
var lat: Double = 0.0
var lng: Double = 0.0
fun build(): Location = Location(lat, lng)
}
val shop = shop("ID") {
address = address {
cityName = "Poznań"
streetName = "ul. Półwiejska"
streetNumber = "123/2"
}
location = location {
lat = 53.12
lng = 23.4
}
openHours = openHours {
weekDay = "6:00-22:00"
saturday = "7:00-23:00"
sunday = "closed"
}
features(
Feature.Bakery,
Feature.Atm
)
}
data class OpenHours(
val weekDay: TimeRange?,
val saturday: TimeRange?,
val sunday: TimeRange?
)
fun openHours(block: OpenHoursBuilder.() -> Unit): OpenHours = OpenHoursBuilder().apply(
block).build()
@ShopDsl
class OpenHoursBuilder {
var weekDay: String? = null
var saturday: String? = null
var sunday: String? = null
fun build(): OpenHours = OpenHours(weekDay?.toOpenHours(), saturday?.toOpenHours(),
sunday?.toOpenHours())
}
fun String.toOpenHours(): TimeRange? {
val splitted = this.split("-".toRegex())
if (splitted.size != 2) {
println("Wrong opening hours format: $this")
return null
}
var startDate = splitted[0].toDate("hh:mm")
var endDate = splitted[1].toDate("hh:mm")
if (startDate == null) {
startDate = splitted[0].toDate("hh.mm")
}
if (endDate == null) {
endDate = splitted[1].toDate("hh.mm")
}
if (startDate == null || endDate == null) {
println("couldn't parse start or end dates of: $this")
return null
}
return TimeRange(startDate, endDate)
}
fun String.toDate(format: String): Date? {
return try {
val formatter = SimpleDateFormat(format)
formatter.parse(this.trim().removePrefix("0"))
} catch (e: ParseException) {
println("error parsing time: $this")
null
}
}
data class Shop(
val id: String,
val address: Address,
val name: String?,
var distance: Double?,
val location: Location,
val openHours: OpenHours,
val features: Set<Feature>
)
fun shop(id: String, block: ShopBuilder.() -> Unit): Shop = ShopBuilder(id).apply(block).build()
@DslMarker
annotation class ShopDsl
@ShopDsl
class ShopBuilder(
var id: String
) {
var name: String? = null
var distance: Double? = null
lateinit var address: Address
lateinit var openHours: OpenHours
lateinit var location: Location
var features: Set<Feature> = setOf()
fun address(block: AddressBuilder.() -> Unit) = AddressBuilder().apply(block).build()
fun openHours(block: OpenHoursBuilder.() -> Unit) = OpenHoursBuilder().apply(block).build()
fun location(block: LocationBuilder.() -> Unit) = LocationBuilder().apply(block).build()
fun features(vararg features: Feature) = FeaturesBuilder(features).build()
fun build(): Shop = Shop(id, address, name, distance, location, openHours, features)
}
class TimeRange(val start: LocalTime, val end: LocalTime) {
constructor(startDate: Date, endDate: Date) : this(
LocalTime.of(startDate.hours, startDate.minutes),
LocalTime.of(endDate.hours, endDate.minutes))
override fun toString(): String {
val formatter = DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT).withLocale(Locale.getDefault())
return "${start.format(formatter)} - ${end.format(formatter)}"
}
fun withinRange(inRange: LocalTime?): Boolean {
return (this.start.isBefore(inRange) || this.start == inRange) &&
(this.end.isAfter(inRange) || this.end == inRange)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment