Documenting discriminated unions in F# - f#

Is there a "best practices" for documenting Discriminated Unions in F#? I've been using the XML tags available at the MSDN website, but there's no mention on documenting DUs, other than the <typeparam name = "x"> Desc. </typeparam> tags.
The tags are helpful for standard types and functions, but which XML tags should be used for DUs?

I mostly just use the <summary> tag for the type and for all its members (and since the compiler adds <summary> automatically, this means I don't have to write any XML by hand):
/// Represents a thumbnail that will appear on the movie web site
type MovieThumbnail =
/// Use a PNG image at the specified URL
| Image of string
/// Use a default image for the specified genre
| Default of Genre
It might be just me, but I find that filing all the other tags is just too much work and it does not give you that much more information.
If you were using F# ProjectScaffold, then the documentation tool also supports Markdown in the XML comments, and so you could write for example:
/// Represents a thumbnail that will appear on the movie web site
///
/// ## Example
/// The following shows simple pattern matching:
///
/// match movieThumb with
/// | Image(url) -> sprintf "<img src='%s' />" url
/// | Default(g) -> defaultImageFor g
///
type MovieThumbnail =
/// Use a PNG image at the specified URL
| Image of string
/// Use a default image for the specified genre
| Default of Genre
At the moment, this does not show very nicely in Visual Studio tooltips, but if you are writing a library and want to have a great documentation for it, then this is a good way to get it.

Each union member is, in effect, its own type, and it can have its own XML comment documentation. So you can write a DU like this:
/// Explain Foo here
type Foo =
/// Explain Bar here
| Bar
/// Explain Baz here
| Baz
and you'll get each comment in the tooltip when hovering over the appropriate type name.

Related

How to use the instance name as a string in Modelica code?

I have a Modelica simulation model composed by some models connected to each other.
I would like to save some data of some of the model instances in my simulation model at a given time using the built-in function
Modelica.Utilities.Streams.writeRealMatrix();
To be sure which instance writes which file, I would like to include the instance name in the writeRealMatrix() output file name, e.g., in case I have an instance called myModel, using the name:
myModelOut.mat.
To do this, I need a way to get the instance name and put it into a string.
I know that Modelica allows using instance names in model icons, through a Text record, using the keyword "%name", but I don't know how to do the same in a regular string (I mean outside any record or icon annotation).
Does anyone know if there is a way to do this?
Thank you in advance.
In your case I think the function getInstanceName() should be a good approach. Using it will need you to edit the model, but given you are writing information from with the class using writeRealMatrix() this shouldn't be an issue.
I have created a small example package with a constant block, that stores its name into final parameter of type String. The example then writes the string to the console at the termination of the simulation:
package GetName
block ConstantNamed "Generate constant signal of type Real"
extends Modelica.Blocks.Sources.Constant;
final parameter String name = getInstanceName();
end ConstantNamed;
model Example
extends Modelica.Icons.Example;
ConstantNamed myConst(k=23) annotation (Placement(transformation(extent={{-10,-10},{10,10}})));
equation
when terminal() then
Modelica.Utilities.Streams.print("### Here is the models full path: '" + myConst.name + "'");
end when;
end Example;
annotation (uses(Modelica(version="4.0.0")));
end GetName;
This should result in a simulation log containing the path of the instance of ConstantNamed, which is Example.myConst:
Note: The print function is added to Example in the above code. It could be added to the ConstantNamed as well. For the case from the question, the print shouldn't be necessary anyways...
Besides that, in case you are using Dymola, there is the ModelManagement library, which contains some functions like ModelManagement.Structure.AST.Classes.ComponentsInClass. But these are more intended to be applied from "outside" to a given model.

Vaadin 22 ComboBox with Lazy Loading and Filtering

I have a tagging system in my application. Now there is one specific entity, for which I want to allow only one tag. Actually I want to assign a parent to a tag.
For this purpose I want to use a VaadinCombobox with lazy loading and filtering.
My data layer is Spring Boot Neo4J Data. There I have a repository like this:
Page<TagListDto> searchPaginated(String searchTerm, Pageable page);
This gives me a data transfer object used for list displays filtered by the searchTerm. The list is pageable. I use the same method for filtering Grids.
So I could do it like this, if I knew where to get the searchTerm from.
ComboBoxLazyDataView<TagListDto> dataView = parentTag.setItems(query ->
tagRepository.searchPaginated(searchTerm,
PageRequest.of(query.getPage(), query.getLimit())).stream());
parentTag.setItemLabelGenerator(TagListDto::getName);
But probably, I'll have to use a DataProvider and a FilterBuilder for the ComboBox, right?
So the answer is to use setItemsWithFilterConverter-method. What you enter into the combo-box field will be sent to the filter converter (2nd method parameter) as a String and then passed as property of the query object to execute the search (1st method parameter).
So if you need to convert the type of the search term from String to some other type, add wildcards or whatever, do it in the 2nd labda.
With query.getFilter() in the 1st lambda you can retrieve the search term and then use that to make the query to your backend.
Here's an example:
ComboBox<Person> personComboBox = new ComboBox<>();
personComboBox.setItemLabelGenerator(Person::getName);
personComboBox.setItemsWithFilterConverter(
query -> personService.searchPaginated(query.getFilter().orElse(""),
PageRequest.of(query.getPage(),
query.getLimit())).stream(),
personSearchTerm -> personSearchTerm
);

Umbraco 7 Custom Media Type Drag and Drop functionality

So just started some work with an Umbraco 7 site.
The site has a custom media type. When adding media (including by dragging and dropping) and selecting this custom type the full path/url of the file added does not appear to be stored anywhere.
I've added a listener to the MediaService.Saved event and this is firing but within this method all the information I appear to have available is the id and the name of the file rather than the file itself.
I was expecting the "umbracoFile" property to be automatically populated but that doesn't appear to be the case. [I even tried editing my custom media type to have a property with alias "umbracoFile" but that just causes the Backend to crash].
Is there anyway to get the url/path of the file or to force Umbraco to set the "umbracoFile" property?
When you perform a drag and drop operation on a Folder Browser control (used in the Media section on Folders, or in the Media Picker dialog), Umbraco inspects the file type that you are dragging onto the upload area, and based on that determines the best media type to create. By default, for any known image type (png, jpg, gif, etc.) that is the Image media type, anything else is automatically assigned to the File media type.
When you hook into the MediaService.Saved event, you have access to the object representing that file in Umbraco Media, but it's already saved as a particular file type based on the description above (this has changed a little in 7.5.9 - see the below note). If you want to enable your own media type and have it set up for drag and drop, you need to dig a bit deeper.
Take a look at this: https://github.com/umbraco/Umbraco-CMS/blob/dev-v7/src/Umbraco.Web/Editors/MediaController.cs#L626-L638
Note: This applies to very recent versions of Umbraco only, as of 7.5.9 - your mileage may vary.
You may need need to look at setting the contentTypeAlias parameter of the post data when uploading the file to your preferred Media type, which may require you to create your own version of the Folder Browser data type.
Got something working in the end thanks to Robert's answer - it's fairly hacky but appears to work so I'm going to leave it here in case it helps anyone else.
Note that it uses a depreciated event handler and reflection to set private variables so I can't recommend that anyone else use it, but it might give people an idea where to start:
public void MediaService_Creating(IMediaService sender, NewEventArgs<IMedia> e)
{
int i = 0;
Type t = e.Entity.GetType();
FieldInfo[] fields = t.GetFields(BindingFlags.NonPublic | BindingFlags.Instance);
FieldInfo field = fields.First(x => x.Name == "_contentType");
MethodInfo findMediaTypeByAlias = ApplicationContext.Current.Services.MediaService
.GetType().GetMethod("FindMediaTypeByAlias", BindingFlags.NonPublic | BindingFlags.Instance);
IMediaType mediaType = (IMediaType)findMediaTypeByAlias.Invoke(
ApplicationContext.Current.Services.MediaService,
new object[] { Constants.Conventions.MediaTypes.Image });
field.SetValue(e.Entity, mediaType);
field = fields.First(x => x.Name == "ContentTypeBase");
field.SetValue(e.Entity, mediaType);
i = e.Entity.ContentTypeId;
}
The basic premise is to change the media type to Image whilst the media type is being created. By changing it in this way any extra properties for the Image media type get added and automatically populated. If a property on the custom media type shares an alias with one of the Image media type properties (such as umbracoFile) then that properties value is automatically populated meaning that it can be used in any Saving/Saved event listeners as required.

Fable/F# - How do I save enums or discriminated unions to the browser?

I can save a string to local browser storage with
Browser.localStorage.setItem(key, str)
but when I try to stringify a discriminated union (e.g. by calling string on it), it comes out as [Object object].
Since the FSharp.Reflection and enum-manipulation functions are not supported in Fable, how can I save and load a DU or enum value (without doing a bunch of extra work for every case)?
Per the Fable docs, you can use the function Fable.Import.JS.JSON.stringify to serialize the DU, and Fable.Import.JS.JSON.parse to deserialize it. This allows it to be saved and loaded from browser localStorage.
There is also a [<StringEnum>] attribute, which I assume makes enums be treated as their string representation, but I did not test it for this use case.

How do you get the value of a data attribute within an event-based rule in Adobe Dynamic Tag Manager (DTM)?

I have an event-based rule configured to fire on click of an element with a specific class. On click, I would like to capture the value of a data attribute that exists. The DTM documentation says you can capture attribute values using this syntax:
%this.data-event%
or
%this.id%
Example HTML:
On click of links with the class "test", I would like to store the value of "event name" within an eVar. When I used the above syntax however, the syntax is converted to a string and in the Adobe server call as:
v25:%this.data-event%
What is the best way to dynamically grab the value of an attribute of an HTML element on click within DTM?
DTM documentation says you can do that, but in practice I too have found that it doesn't seem to work as advertised most of the time, and will instead populate it with a literal (un-eval'd) string like that.
So what I do instead is under Conditions > Rule Conditions I create a Custom condition. In the Custom condition, I add the following:
// example to get id
_satellite.setVar('this_id',this.id);
// example to get href
_satellite.setVar('this_href',this.href);
return true;
Basically I create on-the-fly data elements using javascript, and then return true (so the condition doesn't affect the rule from triggering).
Then I use %this_id%, %this_href%, etc. syntax from the data element I created, in the Adobe Analytics section variable fields.
The easist way to capture the values of a data attribute against an eVar or prop on the element clicked using DTM is to set the input as the following:
%this.getAttribute(data-attributename)%
For example, if there was a data attribute on an element of data-social-share-destination='facebook' simply input %this.getAttribute(data-social-share-destination)%. This will then capture the value of 'facebook'
More detail on data attributes can be found at http://www.digitalbalance.com.au/our-blog/event-based-tracking-using-html5-custom-data-attributes/
I found a solution. The best way to grab the value of an attribute on click is to use this syntax:
%this.getAttribute(data-title)%
The key is to not use quotes around the attribute name AND ensure the attribute has a value.
If the attribute is missing, the expression is not replaced by an empty string as one would normally expect from experience in other platforms, but instead will display the raw un-interpolated code.

Resources