Add large examples and questions

This commit is contained in:
Alexander Nozik 2023-10-08 10:42:35 +03:00
parent 97bbddbdfc
commit b0e181aaae
Signed by: altavir
GPG Key ID: B10A55DCC7B9AEBB
10 changed files with 169 additions and 4 deletions

View File

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GradleMigrationSettings" migrationVersion="1" />
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>

6
.idea/kotlinc.xml Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="KotlinJpsPluginSettings">
<option name="version" value="1.9.10" />
</component>
</project>

View File

@ -1,5 +1,6 @@
plugins {
kotlin("jvm") version "1.9.10"
kotlin("plugin.serialization") version "1.9.10"
}
group = "center.sciprog"
@ -11,6 +12,8 @@ repositories {
dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.4.1")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.0")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3")
testImplementation(kotlin("test"))
}

10
questions.md Normal file
View File

@ -0,0 +1,10 @@
* Создание объектов
* Стоит ли использовать вторичные конструкторы или лучше фабричные методы в компаньоне
* Что лучше - публичный конструктор или приватный с фабричным методом в компаньоне
* Проверка параметров в публичном конструкторе или в фабричном методе с передачей в приватный конструктор
* init блок или специальный метод init() в классах и object
* Enum VS sealed
* Когда использовать `T.() -> R`, а когда `(T) -> R`, а если два параметра, то `T.(T2) -> R`, `T2.(T) -> R`, или `(T, T2) -> R`
* Обновление кэша
* Выбор обработчика по объекту событию/полю объекта
* `a.b!! -> a.b ?: error("b should be not a null")`

View File

@ -0,0 +1,92 @@
import kotlinx.coroutines.*
import kotlinx.coroutines.channels.Channel
import java.util.concurrent.ConcurrentHashMap
/**
* Смотреть доклад тут: https://jokerconf.com/talks/726fdf3540524be28c8f5901c1800583
*/
interface WikiGame {
fun play(startPageTitle: String, endPageTitle: String, maxDepth: Int): List<String?>
}
data class Page(val title: String, val parentPage: Page?) : Comparable<Page> {
override fun compareTo(other: Page): Int {
return title.compareTo(other.title)
}
}
interface WikiRemoteDataSource {
suspend fun getLinksByTitle(title: String): List<String>
suspend fun getBacklinksByTitle(title: String): List<String>
}
class WikiGameCoroImpl : WikiGame {
private val wikiRemoteDataSource: WikiRemoteDataSource = TODO()
override fun play(startPageTitle: String, endPageTitle: String, maxDepth: Int): List<String> = runBlocking {
val visitedPages: MutableMap<String, Boolean> = ConcurrentHashMap()
val startPage = Page(startPageTitle, null)
val resultPage = processPage(startPage, endPageTitle, 0, maxDepth, visitedPages)
val path = mutableListOf<String>()
var curPg: Page? = resultPage
do {
path.add(curPg!!.title)
curPg = curPg.parentPage
} while (curPg != null)
return@runBlocking path.reversed()
}
private suspend fun processPage(
page: Page,
endPageTitle: String,
curDepth: Int,
maxDepth: Int,
visitedPages: MutableMap<String, Boolean>,
): Page {
if (visitedPages.putIfAbsent(page.title, true) != null) {
throw RuntimeException("Already visited")
}
if (page.title == endPageTitle) {
return page
}
if (curDepth == maxDepth) {
throw RuntimeException("Depth reached")
}
val links = wikiRemoteDataSource.getLinksByTitle(page.title)
val pageChannel = Channel<Page>()
val scope = CoroutineScope(SupervisorJob() + CoroutineExceptionHandler { _, _ -> })
links.forEach { link ->
scope.launch {
val pageResult = processPage(
Page(link, page),
endPageTitle,
curDepth + 1,
maxDepth,
visitedPages,
)
pageChannel.send(pageResult)
}
}
val resultPage = pageChannel.receive()
scope.cancel()
return resultPage
}
}

View File

@ -1,4 +1,4 @@
package com.jokerconf.kotlin.idiomatik
package com.jokerconf.kotlin.idiomatik.conference
import kotlinx.datetime.Instant
import kotlin.time.Duration.Companion.minutes

View File

@ -1,4 +1,4 @@
package com.jokerconf.kotlin.idiomatik
package com.jokerconf.kotlin.idiomatik.conference
import kotlinx.datetime.Instant
import kotlin.time.Duration

View File

@ -1,4 +1,4 @@
package com.jokerconf.kotlin.idiomatik
package com.jokerconf.kotlin.idiomatik.conference
import kotlinx.datetime.Instant
import kotlin.time.Duration

View File

@ -1,4 +1,4 @@
package com.jokerconf.kotlin.idiomatik
package com.jokerconf.kotlin.idiomatik.conference
class Speaker {
var name: String? = null

View File

@ -0,0 +1,53 @@
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json
import java.net.URI
const val token = "********"
const val BASE_API_URL = "http://gitlab.com/api/v4"
const val SECURITY_QUERY_PARAM = "private_token=${token}"
const val GET_PROJECT_BY_NAME_PATH_TEMPLATE = "$BASE_API_URL/projects?search=%s&$SECURITY_QUERY_PARAM"
const val GET_ALL_TAGS_BY_PROJECT_ID_PATH_TEMPLATE = "$BASE_API_URL/projects/%d/repository/tags?$SECURITY_QUERY_PARAM"
fun main() {
val json = Json { ignoreUnknownKeys = true }
listOf(
"ProjectA",
"ProjectB",
"ProjectC",
).forEach { projectName ->
val projectsJson = httpGet(GET_PROJECT_BY_NAME_PATH_TEMPLATE.format(projectName))
val projects = json.decodeFromString<List<Project>>(projectsJson)
projects
.filter { it.name == projectName }
.forEach {
val tagsJson = httpGet(GET_ALL_TAGS_BY_PROJECT_ID_PATH_TEMPLATE.format(it.id))
val tags = json.decodeFromString<List<Tag>>(tagsJson)
val lastTag = tags.map(Tag::name).maxWith(::semVerComparator)
println("Project ${it.name}: last tag = $lastTag")
}
}
}
fun httpGet(url: String): String = URI.create(url).toURL().readText()
fun semVerComparator(a: String, b: String): Int {
val aParts = a.split('.').map(String::toInt)
val bParts = b.split('.').map(String::toInt)
for (i in 0..2) {
if (aParts[i] > bParts[i]) {
return 1
}
if (aParts[i] < bParts[i]) {
return -1
}
}
return 0
}
@Serializable
data class Project(val id: Int, val name: String)
@Serializable
data class Tag(val name: String, val message: String)