-
Notifications
You must be signed in to change notification settings - Fork 5
Multi clause printf #336
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
Multi clause printf #336
Conversation
|
@balhoff - would be great if you could take a look soon. Thanks! |
|
Thanks! I'll try to get it done. Awesome to get a contribution! |
balhoff
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.
@hkir-dev I just made a few quick style comments, before trying out the functionality. One general thing, please use camelCase variables everywhere, except specifically in DOSDP fields that get turned to JSON.
| def replaced(text: String, vars: Option[List[String]], bindings: Option[Map[String, SingleValue]], quote: Boolean): Option[String] = { | ||
| def replaced(text: Option[String], vars: Option[List[String]], multi_clause: Option[MultiClausePrintf], bindings: Option[Map[String, SingleValue]], quote: Boolean): Option[String] = { | ||
| if(text.isDefined) { | ||
| return replace_text(text, vars, bindings, quote) |
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.
Never use return (https://tpolecat.github.io/2014/05/09/return.html).
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.
All returns removed from code.
| None | ||
| } | ||
|
|
||
| private def replace_text(text: Option[String], vars: Option[List[String]], bindings: Option[Map[String, SingleValue]], quote: Boolean) = { |
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.
It seems like text should be String, not Option[String] (handle missing text outside of this method). Also, I like to add type signatures to method definitions.
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.
Based on the new schema text or multi_clause can be used to define printf formats.
oneOf:
- required: [ text, vars ]
- required: [ multi_clause ]Text is not a mandatory field now, we can use multi_clause instead of text.
| if(text.isDefined) { | ||
| return replace_text(text, vars, bindings, quote) | ||
| } else if (multi_clause.isDefined) { | ||
| val replaced_texts = for { | ||
| multi_clauses <- multi_clause.toSeq | ||
| printf_clauses <- multi_clauses.clauses.toSeq | ||
| printf_clause <- printf_clauses | ||
| printf_clause_text <- replaced(Some(printf_clause.text), printf_clause.vars, None, bindings, quote) | ||
| sub_clauses = printf_clause.sub_clauses.getOrElse(List.empty[MultiClausePrintf]) | ||
| sub_clauses_texts = sub_clauses.flatMap(mc => replaced(None, None, Some(mc), bindings, quote)) | ||
| clause_text = (printf_clause_text :: sub_clauses_texts).mkString(multi_clauses.sep.getOrElse(" ")) | ||
| } yield clause_text | ||
| val result = replaced_texts.filter(_.nonEmpty).mkString(multi_clause.get.sep.getOrElse(" ")) | ||
| val trimmed = result.trim | ||
| if (trimmed.isEmpty) return None else return Some(trimmed) | ||
| } | ||
| None | ||
| } |
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.
Maybe the optionality of text should be handled outside of this method, and you could break this into two separate methods? I would not use isDefined (they should remove it from the Option type); I prefer an expression-oriented style.
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.
replaceMultiClause method extracted. isDefined bassed logic replaced with flatMap and list operations.
| annotations: Option[List[Annotations]], | ||
| axiom_type: AxiomType, | ||
| text: String, | ||
| text: Option[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.
Was this changed in the spec? Just want to make sure!
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.
Now, the printf format can be given through text or a multi_clause. Updated spec is here: https://github.com/INCATools/dead_simple_owl_design_patterns/blob/e5d69a6f3e17ec464e6942ccf0f05991694cd671/spec/DOSDP_schema_full.yaml#L135
| val internalVarBindings = (for { | ||
| internalVars <- dosdp.internal_vars.toSeq | ||
| internalVar <- internalVars | ||
| function <- internalVar.apply.toSeq | ||
| value = function.apply(Some(dataListBindings.getOrElse(internalVar.input, listVarBindings.getOrElse(internalVar.input, MultiValue(Set.empty[String]))))) | ||
| if value.isDefined | ||
| } yield internalVar.var_name -> SingleValue(value.get) ).toMap |
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.
Instead, avoid isDefined and get (I didn't test this):
val internalVarBindings = (for {
internalVars <- dosdp.internal_vars.toSeq
internalVar <- internalVars
function <- internalVar.apply.toSeq
value <- function.apply(Some(dataListBindings.getOrElse(internalVar.input, listVarBindings.getOrElse(internalVar.input, MultiValue(Set.empty[String])))))
} yield internalVar.var_name -> SingleValue(value) ).toMapThere 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.
Recommended logic worked perfectly, changed accordingly.
|
|
||
| final case class JoinFunction(join: Join) extends Function { | ||
| override def apply(input_var:Option[Binding]): Option[String] = { | ||
| val joined_values = input_var.getOrElse(MultiValue(Set.empty[String])).asInstanceOf[MultiValue].value.mkString(join.sep) |
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.
Can this be written without casting (asInstanceOf)?
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.
asInstanceOf based logic re-implemented with collect { case a: MultiValue => a }
|
|
||
| final case class RegexFunction(regex: RegexSub) extends Function { | ||
| override def apply(input_var:Option[Binding]): Option[String] = { | ||
| val applied_value = input_var.getOrElse(SingleValue("")).asInstanceOf[SingleValue].value |
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.
Can this be written without casting (asInstanceOf)?
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.
asInstanceOf based logic re-implemented with collect { case a: SingleValue => a }
|
Looks great, thank you for also writing tests! |
In relation with the issue: INCATools/dead_simple_owl_design_patterns#71
and relatedly updated ontology schema, implementations to add multi-clause printf and internal_vars.
With this implementation:
Backing usecase is obophenotype/brain_data_standards_ontologies#98