yup - is there any way to set the default value for a string field to be something without defining it for each one - yup

I want that every time I use yup.string(), it will add a specific default value for it
for example:
const schema = yup.object({
text: yup.string()// I want it to also do .default('some string') in the background,
});
or - another option - is there any way to set the default value after creating the scheme? something like setDefault('text', 'some string')

The closest solution I came across to solve your issue is extending your string with a custom method that implements your needs. To do that you need to use addMethod from yup:
import { addMethod, string } from 'yup';
addMethod(string, 'append', function append(appendStr) {
return this.transform((value) => `${value}${appendStr}`);
});
Now, you can use your custom method (append) and apply it to any string you want:
string().append('~~~~').cast('hi'); // 'hi~~~~'
If you want to add the custom method to all your schema types like date, number, etc..., you need to extend the abstract base class Schema:
import { addMethod, Schema } from 'yup';
addMethod(Schema, 'myCustomMethod', ...)
Extra
For Typescript
In your type definition file, you need to declare module yup with your custom method's arguments and return types:
// globals.d.ts
import { StringSchema } from "yup";
declare module 'yup' {
interface StringSchema<TType, TContext, TDefault, TFlags> {
append(appendStr: string): this;
}
}
Unknow behavior for transform method
While I was trying to extend the functionality of the date schema with a custom method that transform the date that user enters from DD-MM-YYY to YYYY-MM-DD, the custom method broke after I used it with other methods like min, max for example.
// `dayMonthYear` should transform "31-12-2022"
// to "2022-12-31" but for some reason it kept
// ignoring the `cast` date and tried to transform
// `1900` instead!
Yup.date().dayMonthYear().min(1900).max(2100).required().cast("31-12-2022") // error
To work around this issue, I appended my custom method at the end of my schema chain:
Yup.date().min(1900).max(2100).required().cast("31-12-2022").dayMonthYear() // works as expected
This issue is mentioned in this GH ticket which I recommend going through it as it's going more in-depth on how to add custom methods with Typescript.
References
addMethod
Extending built-in schema with new methods
Example of addMethod in Typescript (GH ticket)

Related

A way to read a String as dart code inside flutter?

I want to build a method to dynamically save attributes on a specific object
given the attribute name and the value to save I call the "save()" function to update the global targetObj
var targetObj = targetClass();
save(String attribute, String value){
targetObj.attribute = value;
print(targetObj.attribute);
}
But I'm getting the following error:
Class 'targetClass' has no instance setter 'attribute='.
Receiver: Instance of 'targetClass'
Tried calling: attribute="Foo"
The only thing that I can think of is that "attribute" due to being type String results in an error.
That lead me to think if there is a way to read a String as code, something like eval for php.
As #Randal mentioned, you cannot create class..method at runtime. Still, you can try something like this.
A certain class
class Foo {
dynamic bar1;
dynamic bar2;
// ...
}
Your save method
save(Foo fooObject, String attribute, dynamic value) {
if ("bar1" == attribute) fooObject.bar1 = value;
else if ("bar2" == attribute) fooObject.bar2 == value;
// ...
}
Dart (and thus flutter) does not have a way to compile and execute code at runtime (other than dart:mirrors, which is deprecated). You can build additional code that derives from other code using the various builder mechanisms, although it can be rather complicated to implement (and use!).

AG-GRID value formatter not working for dynamically generated currency

I am trying to use a value-formatter in my AG-GRID table for displaying currency information.
This works perfectly when I have a hardcoded value in the formatter, in this case the unicode for 'Euros'
currencyFormatter(params) {
return '\u20ac' + params.value;
}
However, I dont know in advance what currency I will need to format the data in, as it is dynamically generated. If I try an use a value that is available in my component (like below) it doesn't like it!
currencyFormatter(params) {
return this.currencyUnicode + params.value;
}
There it throws in the console is:
TypeError: Cannot read property 'defaultCurrency' of undefined
It seems like all 'this' component variables are not available inside the currencyFormatter. Is there a way to make this work?
In order to access your component variables, you will have to bind your component context - this to the valueFormatter
...
name : 'Currency',
field : 'currency',
valueFormatter: this.currencyFormatter.bind(this) //bind your component's context here
...
currencyFormatter(params) {
return this.currencyUnicode + params.value;
}
This is a common javascript problem. Here is a good read
Also, this answer describes the 2 ways you can reference this.

Unity3D & YamlDotNet Deserializing Data into Monobehaviour-derived classes

I'm trying to serialize data into / from my classes, derived from MonoBehaviour, which cannot be created from client code (e.g., with the new keyword), but rather must be created by a Unity3D-specific method, GameObject.AddComponent<T>(). How can I use the YamlDotNet framework to populate my classes with values without having to create an adapter for each one? Is there some sort of built-in adapter that I can configure, such that YamlDotNet doesn't instantiate the class it's trying to serialize to?
A typical file might contain a mapping of items, e.g.,
%YAML 1.1
%TAG !invt! _PathwaysEngine.Inventory.
%TAG !intf! _PathwaysEngine.Adventure.
---
Backpack_01: !invt!Item+yml
mass: 2
desc:
nouns: /^bag|(back)?pack|sack|container$/
description: |
Your backpack is only slightly worn, and...
rand_descriptions:
- "It's flaps twirl in the breeze."
- "You stare at it. You feel enriched."
MagLite_LR05: !invt!Lamp+yml
cost: 56
mass: 2
time: 5760
desc:
nouns: /^light|flashlight|maglite|lr_05$/
description: |
On the side of this flashlight is a label...
(Type "light" to turn it on and off.)
...
Where the tags are the fully specified class names of my Items, e.g., PathwaysEngine.Inventory.Lamp+yml, PathwaysEngine is the namespace I use for my game engine code, Inventory deals with items & whatnot, and Lamp+yml is how the compiler denotes a nested class, yml inside Lamp. Lamp+yml might look like this:
public partial class Lamp : Item, IWearable {
public new class yml : Item.yml {
public float time {get;set;}
public void Deserialize(Lamp o) {
base.Deserialize((Item) o);
o.time = time;
}
}
}
I call Deserialize() on all objects that derive from Thing from Awake(), i.e., once the MonoBehaviour classes exist in the game. Elsewhere, I've already created a pretty complicated Dictionary filled with objects of type Someclass+yml, and then Deserialize takes an instance of the real, runtime class Someclass and populates it with values. There's got to be a cleaner way to do this, right?
How can I:
Tell the Deserializer what my classes are?
See the second edit for a good solution for the above issue
Get the data without it attempting to create my MonoBehaviour-derived classes?
Edit: I've since worked at the problem, and have found out a good way of dealing with custom data (in my particular case of trying to parse regexes out of my data, and having them not be considered strings & therefore, un-castable to regex) is to use a IYamlTypeConverter for that particular string. Using YamlDotNet with Unity3D MonoBehaviours, however, is still an issue.
Another Edit: The above examples use a pretty ugly way of determining types. In my case, the best thing to do was to register the tags first with the deserializer, e.g.,
var pre = "tag:yaml.org,2002:";
var tags = new Dictionary<string,Type> {
{ "regex", typeof(Regex) },
{ "date", typeof(DateTime) },
{ "item", typeof(Item) }};
foreach (var tag in tags)
deserializer.RegisterTagMapping(
pre+tag.Key, tag.Value);
Then, I use the !!tag notation in the *.yml file, e.g.,
%YAML 1.1
---
Special Item: !!item
nouns: /thing|item|object/
someBoolean: true
Start Date: !!date 2015-12-17
some regex: !!regex /matches\s+whatever/
...
You can pass a custom implementation of IObjectFactory to the constructor of the Deserializer class. Every time the deserializer needs to create an instance of an object, it will use the IObjectFactory to create it.
Notice that your factory will be responsible for creating instances of every type that is deserialized. The easiest way to implement it is to create a decorator around DefaultObjectFactory, such as:
class UnityObjectFactory : IObjectFactory
{
private readonly DefaultObjectFactory DefaultFactory =
new DefaultObjectFactory();
public object Create(Type type)
{
// You can use specific types manually
if (type == typeof(MyCustomType))
{
return GameObject.AddComponent<MyCustomType>();
}
// Or use a marker interface
else if (typeof(IMyMarkerInterface).IsAssignableFrom(type))
{
return typeof(GameObject)
.GetMethod("AddComponent")
.MakeGenericMethod(type)
.Invoke();
}
// Delegate unknown types to the default factory
else
{
return DefaultFactory(type);
}
}
}

Dozer Mapping with custom argument

I would need to map classA fields to classB fields along with localization i.e ClassA field values needs to be converted to localized value before it mapped to classB field. Locale should be passed as an argument to mapper in order get the localized value. Is there any option to pass runtime argument to mapper along with Source and Target classes?
Thanks.
Yes, you can do this. Let's get this example from Dozer docs
BeanMappingBuilder builder = new BeanMappingBuilder() {
protected void configure() {
mapping(Bean.class, Bean.class,
TypeMappingOptions.oneWay(),
mapId("A"),
mapNull(true)
)
.exclude("excluded")
.fields("src", "dest",
copyByReference(),
collectionStrategy(true,
RelationshipType.NON_CUMULATIVE),
hintA(String.class),
hintB(Integer.class),
FieldsMappingOptions.oneWay(),
useMapId("A"),
customConverterId("id")
)
.fields("src", "dest",
customConverter("org.dozer.CustomConverter")
);
}
};
Here we can find an example of dynamically configuration definition. Take a look at this part
customConverter("org.dozer.CustomConverter")
Here you can define a custom converter using this method
FieldsMappingOption customConverter(final String type)
But it has another version
customConverter(final Class<? extends CustomConverter> type, final String parameter)
And that's your case. You can write smth like
customConverter(com.yourproject.TranslatorConverter.class, "en")
in your dynamic code base config to define a parameter for you converter. How to write an implementation of CustumConverter which apply a parameter - take a look here

Display all enums from an EMF model in a CheckBoxTable ?

I am trying to display a CheckBoxTable in an Eclipse page which enables the user to select any one of a number of items - the items that are available come from an EMF model and are enums.
I've got the content provider and the label provider set up correctly (I think) but I can't figure what to use to set the input in order to display the full list of enums.
So say my model has an enum called MyEnum which has values of ONE, TWO and THREE - I want to be able to display all three of those enums to the user as check boxes.
I need to call setInput(...) on the viewer but what do I pass into it to get those enums?
Although I've never done it for a CheckboxTableViewer, I have set an EEnum as the source of values for other StructuredViewer classes like ComboViewer. What I did was create a custom IStructuredContentProvider that is a subclass of ArrayList and takes the EEnum as a constructor argument (call this class EEnumContentProvider). In the constructor, I iterate over the EEnum's getELiterals() and call add() on each of their getInstance() values. Like this:
public EEnumContentProvider(EEnum source) {
List<EEnumLiteral> literals = source.getELiterals();
for (EEnumLiteral aLiteral : literals) {
add(aLiteral.getInstance());
}
}
You can easily implement IStructuredContentProvider.getElements(Object) by using returning the result of toArray() and you don't care about IContentProvider.setInput() because the contents aren't based on the input, they're static.
Then you can set an instance of EEnumContentProvider as the content provider for the viewer.
Simply you need to get the literals and add them to the control as follows:
/* Populate the Combo Box with the Literals */
EEnum cFEnum = Package.Literals.LITERAL_ENUMERATION;
/*
* Add an EMPTY item value so that the user can disable the specific
* feature
*/
this.cmbNames.add( EMPTY_STRING );
/*
* Add the Enumeration Literals to the
* appropriate SWT Combo widget.
*/
for (int i=0; i<cFEnum.getELiterals().size(); i++){
this.cmbNames.add( cFEnum.getEEnumLiteral( i ).toString() );
}
cFEnum = null;
String[] sortedTypes = this.cmbNames.getItems();
Arrays.sort( sortedTypes );
this.cmbNames.setItems( sortedTypes );