Skip to content

Instantly share code, notes, and snippets.

@ninmonkey
Last active August 29, 2023 22:40
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ninmonkey/536ec85d5ddc0b47310e867880203395 to your computer and use it in GitHub Desktop.
Save ninmonkey/536ec85d5ddc0b47310e867880203395 to your computer and use it in GitHub Desktop.
Some html formatting is used by Power Query's doc strings

Here's a random example to demonstrate html

Tips : Multiline strings

It can be messy writing a bunch of newlines in a multiline string. It's easier to use a list of strings that combine.

For Html newlines

= Text.Combine({ "Line1", "", "Line3" }, "<br>")

For regular Newline and Carriage Returns

= Text.Combine({ "Line1", "", "Line3" }, "#(cr,lf)")

or write a macro

= Text.JoinBR = (source as list) as text => Text.Combine( source, "<br/>" ),
= Text.JoinNL = (source as list) as text => Text.Combine( source, "#(cr,lf)" ),
Text.Combine({
  "Transforms text that contains a Date and Time range into a date and time data-types",
  "",
  "Supports ranges like: ""13/11/2022 10:00 AM - 6:00 PM""",
  "<b>## This function was written to demonstratates a few concepts:</b>",
  "",
  " Using custom <b>format string</b>s for Date.FromText and Time.FromText",
  "• Parsing text is simpler if you break it into two steps. Then you can use really simple delimiters that you split around.",
  "• Using a custom <b>Culture</b> which controls the rules for converting to and from text",
  "• Adding documentation to your functions",
  "• Using HTML in your documentation",
  "• Long texts are easier to read if you use <code>Text.Combine()</code> with &lt;br&gt; in HTML and newlines for text",
  "• Totally <b>optional</b> parameter",
  "• How to <b>shadow</b> variables in the local scope, overriding the outer scope",
  "• Using a Record for Default Values",
  "• Combining the default Record allowing you to overwrite some of the defaults, basically opt-in to changing some without losing all the defaults",
  "",
  "<b>## Docs, References, or Tutorials:</b>",
  "",
  "- UI on splitting: <https://learn.microsoft.com/en-us/power-query/split-columns-delimiter>",
  "- Splitter functions: <https://learn.microsoft.com/en-us/powerquery-m/splitter-functions>",
  "- See sections on extraction and transformation: <https://learn.microsoft.com/en-us/powerquery-m/text-functions#extraction>",
  "- <https://github.com/ninmonkey/ninMonkQuery-examples> has more examples.",
  "- If you want easy to generate metrics on your git repos, I started <https://gitlogger.com>. It'd be cool if you check it out."

  }, "<br>")
        ```

### Full Query

```ts
let
    /*
    post todo: 2023-05-14 ; There's a simplified version of this function, that removes all the fancy-pants-fluff
        named: <2023-05-04 - Dates with Times as Ranges.Simplified.pq>
    */
    Source = #table(
        type table[DateText = text],
        {
            { "13/11/2022 10:00 AM - 6:00 PM" },
            { "9/11/2022 9:00 AM - 12:00 PM" }
        }),

    DateTimeRange.FromText = Value.ReplaceType( DateTimeRange.FromText.Func, DateTimeRange.FromText.Type ),
    DateTimeRange.FromText.Type = type function(
        source as text,
        optional options as nullable record
    ) as record meta [
        Documentation.Name = "DateTimeRange.FromText",
        Documentation.Author = "Jake Bolton <jake.bolton.314@gmail.com>",
        Documentation.Author.Github = "https://github.com/ninmonkey",
        Documentation.Author.Blog = "https://ninmonkeys.com/blog/",
        Documentation.Author.SourceUrl = "https://github.com/ninmonkey/ninMonkQuery-examples",
        Documentation.LongDescription = Text.Combine({
            "Transforms text that contains a Date and Time range into a date and time data-types",
            "",
            "Supports ranges like: ""13/11/2022 10:00 AM - 6:00 PM""",
            "<b>## This function was written to demonstratates a few concepts:</b>",
            "",
            " Using custom <b>format string</b>s for Date.FromText and Time.FromText",
            "• Parsing text is simpler if you break it into two steps. Then you can use really simple delimiters that you split around.",
            "• Using a custom <b>Culture</b> which controls the rules for converting to and from text",
            "• Adding documentation to your functions",
            "• Using HTML in your documentation",
            "• Long texts are easier to read if you use <code>Text.Combine()</code> with &lt;br&gt; in HTML and newlines for text",
            "• Totally <b>optional</b> parameter",
            "• How to <b>shadow</b> variables in the local scope, overriding the outer scope",
            "• Using a Record for Default Values",
            "• Combining the default Record allowing you to overwrite some of the defaults, basically opt-in to changing some without losing all the defaults",
            "",
            "<b>## Docs, References, or Tutorials:</b>",
            "",
            "- UI on splitting: <https://learn.microsoft.com/en-us/power-query/split-columns-delimiter>",
            "- Splitter functions: <https://learn.microsoft.com/en-us/powerquery-m/splitter-functions>",
            "- See sections on extraction and transformation: <https://learn.microsoft.com/en-us/powerquery-m/text-functions#extraction>",
            "- <https://github.com/ninmonkey/ninMonkQuery-examples> has more examples.",
            "- If you want easy to generate metrics on your git repos, I started <https://gitlogger.com>. It'd be cool if you check it out."

        }, "<br>"),
            Documentation.Examples = {
                // [Description = "Inspecting strings", Code = "Text.Inspect(""SomeString"")", Result = "..."],
                [
                    Description = "Inspecting table columns",
                    Code = Text.Combine({
                        "let",
                        "   sample = DateTimeRange.FromText( ""13/11/2022 10:00 AM - 6:00 PM"" ) ",
                        "in",
                        "   sample"
                    }, "#(cr,lf)"),
                    Result = "[
                        Date        = #(#)date(2022, 11, 9),
                        StartTime   = Time.FromText(""9:00 AM"",  [Culture = ""en-us""] ),
                        EndTime     = Time.FromText(""12:00 PM"", [Culture = ""en-us""] )
                    ]"
                ]
            }

    ],
    DateTimeRange.FromText.Func =
        (source as text, optional config as nullable record)
            as record => let
                // default values, optionally overrided by user, key-by-key
                config = Record.Combine({
                    [
                        Format = "d/MM/yyyy",
                        Culture = Culture.Current // or maybe "en-us", "de-de", "es-us"
                    ],
                    config ?? []
                }),
                date_str  = Text.BeforeDelimiter( source, " ", Occurrence.First ),
                times_str = Text.AfterDelimiter(  source, " ", Occurrence.First ),
                pair_str  = Text.Split( times_str, " - " ),
                start     = Time.FromText( pair_str{0}, [ Culture = config[Culture] ] ),
                end       = Time.FromText( pair_str{1}, [ Culture = config[Culture] ] ),
                Date      = Date.FromText( date_str, [ Format = config[Format], Culture = config[Culture] ] ),
                return    = [
                    Date  = Date,
                    StartTime = start,
                    EndTime = end
                ]
            in return,

    Summary = [
        FancyDocs = DateTimeRange.FromText,
        Source = Source,
        target = Source{1}[DateText],
        test = DateTimeRange.FromText( target ),
        expected = [
            Date        = #date(2022, 11, 9),
            StartTime   = Time.FromText("9:00 AM",  [ Culture = "en-us" ] ),
            EndTime     = Time.FromText("12:00 PM", [ Culture = "en-us" ] )
        ],
        DateTimeRange.FromText = DateTimeRange.FromText,
        #"Conversion Is Correct?" = expected = test,
        #"Inspect Custom Function Metadata" = Value.Metadata( Value.Type( DateTimeRange.FromText ) )
    ][FancyDocs]
in
    Summary
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment