Search code examples
regexrubyjekyll

How can I use regex to construct an API call in my Jekyll plugin?


I'm trying to write my own Jekyll plugin to construct an api query from a custom tag. I've gotten as far as creating the basic plugin and tag, but I've run into the limits of my programming skills so looking to you for help.

Here's my custom tag for reference:

{% card "Arbor Elf | M13" %}

Here's the progress on my plugin:

module Jekyll
    class Scryfall < Liquid::Tag

        def initialize(tag_name, text, tokens)
            super
            @text = text
        end 

        def render(context)
            # Store the name of the card, ie "Arbor Elf"
            @card_name = 

            # Store the name of the set, ie "M13"
            @card_set = 

            # Build the query
            @query = "https://api.scryfall.com/cards/named?exact=#{@card_name}&set=#{@card_set}"

            # Store a specific JSON property
            @card_art = 

            # Finally we render out the result
            "<img src='#{@card_art}' title='#{@card_name}' />"
        end

    end
end

Liquid::Template.register_tag('cards', Jekyll::Scryfall)

For reference, here's an example query using the above details (paste it into your browser to see the response you get back)

https://api.scryfall.com/cards/named?exact=arbor+elf&set=m13

My initial attempts after Googling around was to use regex to split the @text at the |, like so:

@card_name = "#{@text}".split(/| */)

This didn't quite work, instead it output this:

[“A”, “r”, “b”, “o”, “r”, “ “, “E”, “l”, “f”, “ “, “|”, “ “, “M”, “1”, “3”, “ “]

I'm also then not sure how to access and store specific properties within the JSON response. Ideally, I can do something like this:

@card_art = JSONRESPONSE.image_uri.large

I'm well aware I'm asking a lot here, but I'd love to try and get this working and learn from it.

Thanks for reading.


Solution

  • Actually, your split should work – you just need to give it the correct regex (and you can call that on @text directly). You also need to escape the pipe character in the regex, because pipes can have special meaning. You can use rubular.com to experiment with regexes.

    parts = @text.split(/\|/)
    # => => ["Arbor Elf ", " M13"]
    

    Note that they also contain some extra whitespace, which you can remove with strip.

    @card_name = parts.first.strip
    @card_set  = parts.last.strip
    

    This might also be a good time to answer questions like: what happens if the user inserts multiple pipes? What if they insert none? Will your code give them a helpful error message for this?

    You'll also need to escape these values in your URL. What if one of your users adds a card containing a & character? Your URL will break:

    https://api.scryfall.com/cards/named?exact=Sword of Dungeons & Dragons&set=und
    

    That looks like a URL with three parameters, exact, set and Dragons. You need to encode the user input to be included in a URL:

    require 'cgi'
    query = "https://api.scryfall.com/cards/named?exact=#{CGI.escape(@card_name)}&set=#{CGI.escape(@card_set)}"
    # => "https://api.scryfall.com/cards/named?exact=Sword+of+Dungeons+%26+Dragons&set=und"
    

    What comes after that is a little less clear, because you haven't written the code yet. Try making the call with the Net::HTTP module and then parsing the response with the JSON module. If you have trouble, come back here and ask a new question.