-
Notifications
You must be signed in to change notification settings - Fork 176
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
Add PluralRules #119
Add PluralRules #119
Conversation
a30e352
to
af8f0b1
Compare
Pull Request Test Coverage Report for Build 0fd58a5041a6d641108f81bbae60cb40c0680c8f-PR-119
💛 - Coveralls |
I'll get to this tomorrow. |
The other thing I'm planning to do it to make |
Looking at this now. |
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 have substantial remarks. All nits inside, or discussion items.
impl TryFrom<$ty> for PluralOperands { | ||
type Error = &'static str; | ||
fn try_from(input: $ty) -> Result<Self, Self::Error> { | ||
// XXXManishearth converting from i64 to isize may wrap |
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.
How about keeping the more precise value, and down-converting at output time?
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.
what is "output" time here?
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.
What I mean is, if the params kept the value of x in the widest type that would contain any of the values, we could avoid the need to make the wrapping decision here. However, since the fields n
and i
are public, we have to make that deliberation here.
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.
What is x
?
PluralOperands
are only used in plural rules resolution. I struggle to see a case where we'd benefit from lazy resolving them later, because I don't see a use case where we'd construct a PluralOperands
but not want to get it's i
or n
.
And if we do, we'll want it for many rules as we test against them. So having them eagerly resolved seems like a cleaned API which caves to nice further optimizations.
For example, I can imagine scenarios where an instance of PluralOperands
gets stored and passed around for use in PluralRules
, and proc_macros will allow us to construct the operands at build time and have them validated and calculated at runtime for free.
@zbraniecki first review done. |
I want to also point out, especially for @sffc and @filmil that I am intentionally moving away from having Instead, I offer them on This allows for the following use: let pr = PluralRules::new(loc!("en"), PluralCategory::Ordinal);
pr.select(5); // used `Into<PluralOperands> for usize` - infallible
let operandsOptions = PluralOperandsOptions {
min_fraction_digits: 3,
..Default::default()
};
let op = PluralOperands::new_with_options(5, operandsOptions);
pr.select(op); // now I passed Operands resolved with `minFractionDigits` 3 I think it's an improvement to have digits rounding and trimming when constructing Operands from input, because we're producing those Operands either implicitly for infallible, or explicitly for fallible or for cases where we want to go for non-default options. How does it sound? |
b1fa8b6
to
c8a1470
Compare
d9af87f
to
d7a0e40
Compare
d2fb9f4
to
7eded50
Compare
After discussion with @sffc, I'm moving this to be based on |
@sffc - I think this is mostly ready. It works, and it implements 4 "data sources" - json, bincode, inline source and rust functions. I'd like to plug this into Can you onramp me on how to write the binding based on my |
@zbraniecki done as requested |
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 mostly looked at overall code architecture, not the specific lexer and selection algorithms. If you want me to look at the algorithms, I will do that.
I expect the data code to be imminently replaced, so I was not too picky about that.
} | ||
} | ||
|
||
pub fn get_resource( |
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.
FYI, this is code I hope can be deleted once #182 is landed and wired up. Loading strings into a static JSON is hard to do correctly and should be done in a centralized place, not deeply embedded inside a component.
Thank you for the first round of feedback! I applied most of it, and tried to keep comments open where I wanted the reviewer to verify my fix, while in trivial cases like spellings I closed it myself. I left one open bit - the removal of conversion from I'm going to open a number of issues based on all the comments - ranging from I'm looking now for anything that has not yet been mentioned and may require changes before this PR is mergable, so re-requesting reviews. |
I think this is ready for re-review! |
I approved quite a while ago but am glad to reconfirm. |
Fixes #116.
This is the initial WIP for the plural rules component.
I'm going to include the rules parser/ast/resolver for runtime resolution based on input string, but we could also compile AST into JSON if we wanted and then data provider could load an already parsed AST.
Finally, it should be possible to compose Rust functions out of the AST and store them as one of the optional data providers.
I didn't use
Options
constructor model because it seems like this struct will have really only two variables -locale
andtype
.Depending on how we'll hook in the
DataProvider
we may want to make the constructor fallible because it may not have locale/type for a given request.I'm also not sure if I should keep the
IntoOperands
external toselect
or internal. In my original code I had it internal: https://github.com/zbraniecki/pluralrules/blob/master/intl_pluralrules/src/lib.rs#L140but that means that
select
is fallible, which is not needed forusize
etc. where theIntoOperands
is not fallible.Alternatively, we could have infallible
select
which acceptsInto<Operands>
and fallibletry_select
which acceptsTryInto<Operands>
, or even infallible select only, and then if someone wants to pass something fallible, they'll have totry_into
explicitly before passing the result and handle the errors.@sffc, @filmil - can you skim through and let me know if it looks like a good start?