-
Notifications
You must be signed in to change notification settings - Fork 6
Handle date/time conversion in runtime via instantiable FormattedResources
#390
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Handle date/time conversion in runtime via instantiable FormattedResources
#390
Conversation
| .addProperty( | ||
| PropertySpec.builder( | ||
| name = "dateTimeConverter", | ||
| type = Types.DateTimeConverter.parameterizedBy(ANY), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's not a more concise way to share the ParameterSpec and the PropertySpec that have the same name and type, is there?
| .addImport(packageName = packageName, "R") | ||
| .addProperty( | ||
| PropertySpec.builder( | ||
| name = "AndroidFormattedResources", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I went back and forth on how to name these:
BaseFormattedResourcesandFormattedResourceswas Patrick's original suggestion, and allows for the simplest transition for current consumers. But it's the base class that most consumers would probably deal with, so giving it the longer name feels clunky. And having many different classes generated with the same prefixBasemight be confusing since it is not a common base.FormattedResourcesandAndroidFormattedResourcesis what I've gone with. The generic type has the snappier name. But it makes the transition for current consumers more involved. And using the prefixAndroidmight seem redundant for an Android-targeted library.- Another idea: Rename
AndroidFormattedResourcestoFR. This makes static invocations somewhat parallel to static invocations of the standard Android resource:R.string.whatever→FR.whatever(args). But it's still an involved transition from the previous Paraphrase API. And maybe too cute.
Curious what others think for naming these two.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't love the Base prefix either, I'm happy to go with either of the other two options. Another option might be a base of ParaphraseResources and implementations of AndroidResources and JvmResources.
I'm not sure there's a perfect naming scheme and I'm also not sure it's a big deal. I'm cool with just picking something and shipping it!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like ParaphraseResources because it steps around the verb-tense problem with "Formatted" and also reminds you what this thing is.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That would also let me include a deprecated val FormattedResources with a built-in ReplaceWith to the new name, if we want to get fancy and make the transition easy.
sample/library/src/test/kotlin/app/cash/paraphrase/sample/library/JvmDateTimeConverter.kt
Outdated
Show resolved
Hide resolved
tests/src/main/kotlin/app/cash/paraphrase/tests/JvmDateTimeConverter.kt
Outdated
Show resolved
Hide resolved
f4873dc to
0070c19
Compare
theisenp
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice, seems like this worked out pretty well! Thanks for putting it together 🙏
Now that we have both this and #258, does one approach feel better than the other?
| private fun appSamples( | ||
| formattedResources: AppFormattedResources, | ||
| ): List<Sample> = listOf( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we wanted to keep this as a val with static references to AppAndroidFormattedResources that would still work right? Are we just switching to a fun to demonstrate that you can pass the resources as the interface type?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah exactly, just demonstrating interaction with the interface type.
| private val stringResolver = FakeStringResolver( | ||
| R.string.library_date_argument to "{release_date, date, short}", | ||
| R.string.library_time_argument to "{showtime, time, short}", | ||
| ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is the resolver type here useful, or could we just have the Map<Int, String>?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can switch to a map if you prefer. I think I was just writing what felt like a real app might do; write a fake stand-in for an Android resource-resolving interface.
| import java.util.Locale | ||
| import org.junit.Test | ||
|
|
||
| class FormattedResourcesTest { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is the idea here just to show people how they might override the FormattedResources type in tests?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This tests that date/time resolution works in a JVM test. This test fails on main because of the ICU4J/android.icu discrepancy.
| .addImport(packageName = packageName, "R") | ||
| .addProperty( | ||
| PropertySpec.builder( | ||
| name = "AndroidFormattedResources", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't love the Base prefix either, I'm happy to go with either of the other two options. Another option might be a base of ParaphraseResources and implementations of AndroidResources and JvmResources.
I'm not sure there's a perfect naming scheme and I'm also not sure it's a big deal. I'm cool with just picking something and shipping it!
This one feels better. We've all been through the swapping-static-references-in-tests phase before and agree it's painful, so let's not go there. |
to handle converting to ICU Calendar
This prevents the ULocale from being instantiated at class-loading time, which would crash JVM tests due to the missing Android implementation.
…attedResources This supports testing with an injected JvmDateTimeFormatter, rather than setting it on a static instance.
0070c19 to
12d4335
Compare
Implements Patrick's idea from #258. Closes #230.
This pulls all
android.icuimports out of generated code and into the runtime, allowing substitution of non-Android ICU dependencies in JVM unit tests. A genericDateTimeConverterinterface is introduced to format date/time parameters. The defaultAndroidDateTimeConverterimplementation instantiatesandroid.icu.util.Calendars. JVM tests can substitute aJvmDateTimeConverterinto theirFormattedResourcesinstance to instantiatecom.ibm.icu.util.Calendars, avoiding the need for Robolectric to format date/time strings.This also makes the generated
FormattedResourcesan instantiableclass, rather than anobject, so the appropriateDateTimeConvertercan be injected. A defaultAndroidFormattedResourcesproperty is introduced so simple static access is still supported.