Wrong number of arguments (given 1, expected 0)

I have (foolishly??) upgraded from Jekyll 3.x and Ruby 2.x to Jekyll 4 and Ruby 3 (latest)

This is the line in question from one of my includes

<input type="text" id="commentID" name="nid" value="{{ 'now' | date: '%s' | dec2hex }}" />

dec2hex is a one line filter that functioned with j3r2.

This works:
sprintf("%x", input) #=> 62fff587

With a require “base64”, this functions but is clearly not a successful base64 conversion:
sprintf("%s.", Base64.urlsafe_encode64(input, padding: false)) #=> MTY2MDkzOTk2Nw

ruby -e 'puts 1660941703.to_s(36);' #=> rgvqtj

This throws the error:
sprintf("%s", input.to_s(36))
I believe (poor version control, sorry) that p input.to_s(36) was working with j3r2 but I’ve attempted printf, puts, and a variety of other things. Of course, if I could get the Base64 working I wouldn’t be bothering but base36 is better than base 16, so…

This sent me down a bit of a rabbit hole, so please bare with me. I searched for the dec2hex filter in the official Jekyll docs and in the Shopify Liquid docs and came up with nothing. A few Google searches also came up with nothing. This leads me to believe that while that filter may have worked, it is undocumented or unsupported.

You could create a plugin that performs this function, or you could roll your own code to do something similar.

From what I can tell there is no out-of-box way to convert decimal to hexadecimal, so I looked up how to do it using this article.

From there, I re-created the code for you to re-use.

Before you read the rest of this:

  1. This is sample code I tested for just a little bit
  2. You could remove all the extra stuff here and turn it into an include file, passing it a parameter of the value you want

In this case, I created a markdown file at the root of my Jekyll folder

test.md

---
layout: page
---
{% assign decimal = "now" | date: '%s' | round %}
decimal: {{decimal}}

{% assign quotient = decimal %}
{% assign remainder = quotient %}
{% assign hex = null %}

{% for i in (1..100) %}
    {% assign remainder = quotient | modulo: 16 %}
    remainder: {{remainder}}
    {% assign quotient = quotient | divided_by: 16 %}
    quotient: {{quotient}}
    {% case remainder %}
        {% when 0 %}
            {% assign hex = hex | prepend: "0" %}
        {% when 1 %}
            {% assign hex = hex | prepend: "1" %}
        {% when 2 %}
            {% assign hex = hex | prepend: "2" %}
        {% when 3 %}
            {% assign hex = hex | prepend: "3" %}
        {% when 4 %}
            {% assign hex = hex | prepend: "4" %}
        {% when 5 %}
            {% assign hex = hex | prepend: "5" %}
        {% when 6 %}
            {% assign hex = hex | prepend: "6" %}
        {% when 7 %}
            {% assign hex = hex | prepend: "7" %}
        {% when 8 %}
            {% assign hex = hex | prepend: "8" %}
        {% when 9 %}
            {% assign hex = hex | prepend: "9" %}
        {% when 10 %}
            {% assign hex = hex | prepend: "a" %}
        {% when 11 %}
            {% assign hex = hex | prepend: "b" %}
        {% when 12 %}
            {% assign hex = hex | prepend: "c" %}
        {% when 13 %}
            {% assign hex = hex | prepend: "d" %}
        {% when 14 %}
            {% assign hex = hex | prepend: "e" %}
        {% when 15 %}
            {% assign hex = hex | prepend: "f" %}
        {% else %}            
    {% endcase %}
    hex: {{hex}}
    {% if quotient <= 0 %}
        {% break %}
    {% endif %}
{% endfor %}

Final hex: {{hex}}

:1234: Define the decimal value

First, this code gets the number of seconds since 1970-01-01 00:00:00 UTC using Liquid’s special word now with the date operator. I assume this based on Ruby’s Time.Parse method. Also, just in case, I round off the number since this code assumes you are working with a whole number decimal.

:checkered_flag: Initialize variables

There are a few variables to initialize so we can use them outside iterators:

quotient is the result as we slowly widdle down the number, dividing by 16
remainder represents each digit for the hexadecimal output
hex is the final dec2hex number you are looking for

:repeat: Loop until divide by 16 is <= 0

Unfortunately, Liquid – and therefore Jekyll – does not have a do until loop, so we have to use the for iterator so I just said “go from 1-100”. You could make the number bigger or smaller. I don’t think your particular number will go more than a few loops.

Note that once the quotient is <= 0 the loop breaks.

:abacus: Divide the decimal down to get the hex equivalent

The trick here is to use the modulo filter to get the remainder and the divide_by filter to get the quotient. As a reminder, the quotient is divided by 16 until we get to zero and the remainder represents the hex number.

:wrench: Construct the hex number

As noted earlier, each remainder value in the loop becomes a digit in your hex value. We need to keep building the hex variable until the quotient hits zero.

If I were to keep appending the hex value, you might have something that looks like this:
2f53

But really, the number is in reverse, so that is why I prepend, so the number looks like this:
35f2

Here is the table I used to create the case tag:

Decimal Hexidecimal
0 0
1 1
2 2
3 3
4 4
5 5
6 6
7 7
8 8
9 9
10 a
11 b
12 c
13 d
14 e
15 f

:checkered_flag: Finish!

With the quotient down to zero, the hex value is yours to use!

Remember, you could put this code in an include file and pass whatever variable you want with a few changes.

Hope this helps!

[edit] pressed save too soon so finished the post :slight_smile:

Apologies, I thought it was clear from what I was saying (eg. this is a one line filter), that dec2hex was a filter that I was writing, currently:

require "base64"

module Jekyll
  module HexFilter
    def dec2hex(input)
#      sprintf("%s", input.to_s(36))
      sprintf("%x", input)
#      sprintf("%s.", Base64.urlsafe_encode64(input, padding: false))
    end
  end
end

Liquid::Template.register_filter(Jekyll::HexFilter)

the hexadecimal-ness of it all is just the first step of getting something that works (which it does, hex works just fine). The final intended state is to filter into a base64 number. Base 36 worked before I upgraded Jekyll and Ruby but doesn’t anymore and crashes the build. Base 64 doesn’t stop the site build from finishing, but does not work properly.

I have realized the error of my ways:
the input is a string. The fact that sprintf("%x", input) worked without issue was misleading to the problem that to_s wants a number, so sprintf("%s", input.to_i.to_s(36)) works and does not crash the site build. Also, Base64 encode is not the same thing as a base 64 conversion. Duh. 8-(

This is actually my desired outcome modified from an answer on stackoverflow

module Jekyll
  module HexFilter
    def dec2base62(input)
      chars = [*'A'..'Z', *'a'..'z', *'0'..'9']
      digits = input.to_i.digits(62).reverse
      sprintf("%s", digits.map { |i| chars[i] }.join)
    end
  end
end

Liquid::Template.register_filter(Jekyll::HexFilter)

Glad you sorted it out and thank you for sharing the code!