-
Notifications
You must be signed in to change notification settings - Fork 5
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
Handle date/time conversion in runtime via instantiable FormattedResources
#390
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?
@@ -59,8 +60,35 @@ internal fun writeResources( | |||
""".trimIndent(), | |||
) | |||
.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:
BaseFormattedResources
andFormattedResources
was 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 prefixBase
might be confusing since it is not a common base.FormattedResources
andAndroidFormattedResources
is 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 prefixAndroid
might seem redundant for an Android-targeted library.- Another idea: Rename
AndroidFormattedResources
toFR
. 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
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.
@@ -59,8 +60,35 @@ internal fun writeResources( | |||
""".trimIndent(), | |||
) | |||
.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.icu
imports out of generated code and into the runtime, allowing substitution of non-Android ICU dependencies in JVM unit tests. A genericDateTimeConverter
interface is introduced to format date/time parameters. The defaultAndroidDateTimeConverter
implementation instantiatesandroid.icu.util.Calendar
s. JVM tests can substitute aJvmDateTimeConverter
into theirFormattedResources
instance to instantiatecom.ibm.icu.util.Calendar
s, avoiding the need for Robolectric to format date/time strings.This also makes the generated
FormattedResources
an instantiableclass
, rather than anobject
, so the appropriateDateTimeConverter
can be injected. A defaultAndroidFormattedResources
property is introduced so simple static access is still supported.