Last active
April 9, 2024 08:10
-
-
Save guid-empty/9d934f79d9cfed4beb6738b0f5193c30 to your computer and use it in GitHub Desktop.
Template Processor
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'package:models/src/models/participant_descriptor_model.dart'; | |
import 'package:models/src/models/quiz_session_model.dart'; | |
import 'package:models/src/models/quiz_session_result_item_model.dart'; | |
import 'package:models/src/models/templates/context_variables.dart'; | |
typedef LazyValueGetter = Object? Function(); | |
class TemplatesProcessorService { | |
static const _variableExpression = r'(?<variable>\%\w*\%)'; | |
static final _variableExpressionRegex = RegExp(_variableExpression); | |
String processTemplate({ | |
required String template, | |
required QuizSessionModel session, | |
QuizSessionResultItemModel? perUserResults, | |
ParticipantDescriptorModel? participant, | |
Iterable<String>? questionAnswers, | |
}) { | |
final environment = <String, LazyValueGetter>{ | |
ContextVariables.quizSessionId: () => session.id.value, | |
ContextVariables.quizId: () => session.currentQuiz.id.value, | |
ContextVariables.quizTitle: () => session.currentQuiz.title, | |
ContextVariables.participantFullName: () => | |
participant?.name ?? 'Участник', | |
ContextVariables.participantName: () => participant?.name ?? 'Участник', | |
ContextVariables.userName: () => participant?.name ?? 'Участник', | |
ContextVariables.totalCorrectlyAnsweredQuestionsElapsedTime: () => | |
_printDuration( | |
perUserResults?.totalCorrectlyAnsweredQuestionsElapsedTime, | |
), | |
ContextVariables.totalQuestionsCount: () => | |
perUserResults?.totalQuestionsCount, | |
ContextVariables.totalAnsweredQuestionsCount: () => | |
perUserResults?.totalAnsweredQuestionsCount, | |
ContextVariables.totalCorrectlyAnsweredQuestionsCount: () => | |
perUserResults?.totalCorrectlyAnsweredQuestionsCount, | |
ContextVariables.totalIncorrectlyAnsweredQuestionsCount: () => | |
perUserResults?.totalIncorrectlyAnsweredQuestionsCount, | |
ContextVariables.totalCorrectlyAnsweredQuestionsWeight: () => | |
perUserResults?.totalCorrectlyAnsweredQuestionsWeight, | |
ContextVariables.totalSkippedQuestionsCount: () => | |
perUserResults?.totalSkippedQuestionsCount, | |
ContextVariables.participantCurrentQuestionAnswers: () { | |
if (questionAnswers != null && questionAnswers.isNotEmpty) { | |
if (questionAnswers.length == 1) { | |
return questionAnswers.first; | |
} else { | |
return questionAnswers.join(', '); | |
} | |
} | |
return '(Нет данных)'; | |
}, | |
ContextVariables.quizLeaderPosition: () => | |
(perUserResults?.isQuiz ?? false) | |
? perUserResults?.maybeMap( | |
quiz: (q) => q.quizLeaderPosition, | |
orElse: () => 0, | |
) | |
: 0, | |
ContextVariables.isQuizSuccessful: () => (perUserResults?.isQuiz ?? false) | |
? perUserResults?.maybeMap( | |
quiz: (q) => q.isQuizSuccessful, | |
orElse: () => false, | |
) | |
: false, | |
ContextVariables.isTestSuccessful: () => (perUserResults?.isTest ?? false) | |
? perUserResults?.maybeMap( | |
test: (q) => q.isTest, | |
orElse: () => false, | |
) | |
: false, | |
}; | |
final updatedTemplateText = template.replaceAllMapped( | |
_variableExpressionRegex, | |
(match) { | |
final variableName = match[0].toString().replaceAll('%', ''); | |
if (environment.containsKey(variableName)) { | |
return environment[variableName]?.call().toString() ?? ''; | |
} else { | |
return match[0].toString(); | |
} | |
}, | |
); | |
return updatedTemplateText; | |
} | |
String _printDuration(Duration? duration) { | |
if (duration == null) { | |
return ''; | |
} | |
final minutes = duration.inMinutes.remainder(60); | |
final seconds = duration.inSeconds.remainder(60); | |
if (duration.inHours > 0) { | |
return '${duration.inHours} часов и $minutes минут'; | |
} | |
if (duration.inMinutes < 1) { | |
return '$seconds сек'; | |
} else { | |
return '$minutes минут $seconds сек'; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Использую сейчас следующий принцип обработки текстов.
Есть шаблоны, в тексте которых подставляю переменные из сессии/окружения пользователя.
Выглядеть шаблон может примерно так:
Первый алгоритм "в лоб", который был - я каждый раз при вызове метода
processTemplate
передавал необходимые сущности для построения мапки с переменными - environment. И потом по каждому ключу из этой мапки выполнял в цикле replace.Не трудно догадаться, что очень жирное вычисление.
Когда переменных было раз два, не страшно. Когда их перевалило за 20, на каждое сообщение выполнять такое процессинг стало просто постыдным )).
И тут неожиданном пригодились опять Regex.
Сейчас на сроке template.replaceAllMapped выполняю replace только той части строки, которая попадает под условие поиска переменных. Получив имя переменной я дальше вычисляю ее значение из environment опять же только по требованию, лениво, по ключу вызывая необходимый геттер с замыканием.
Оптимизации часто преждевременны. Но тут мне было реально стыдно )