Access random array element using Sourcery and Stencil

417 views Asked by At

I'm doing some code generation stuff using Sourcery and Stencil.

I'm trying to add an extension to all my enums that has a method that returns a random case of the enum. So, in my case, I need a way to access a random array element.

I know that we can do array lookup using one of the following ways: (first, last or by index), but I can't find a way to access a random element.

Here is an example of what I'm trying to achieve:

{% for type in types.enums %}
extension {{ type.name }} {
    static func random() -> {{ type.name }} {
         let index = Int.random(in: 0..<{{ type.cases.count }})
         return .{{ type.cases.index.name }}
    }
}
{% endfor %}

The previous code snippet doesn't work, obviously. I just added it as a way to make my intention clear.

Does anyone have an idea about this?

2

There are 2 answers

1
Mo Abdul-Hameed On BEST ANSWER

So, after the ideas posted by others here (thanks to them). I implemented it like the following as I also need to randomize the associated values of the cases that have associated values:

{% for type in types.enums %}
extension {{ type.name }} {
    static func random() -> {{ type.name }} {
        let cases: [{{ type.name }}] = [
        {% for case in type.cases %}
        {% if case.associatedValues.count > 0 %}
        {% map case.associatedValues into values using value %}.random(){% endmap %}
            .{{ case.name }}({{ values|join:", " }}),
        {% else %}
            .{{ case.name }},
        {% endif %}
        {% endfor %}
        ]
        return cases.randomElement()!
    }
}
{% endfor %}

The above code snippet iterates over the cases of the enum and creates an array that contains all the cases. If a case has associated values, it will create a random element for each associated value using the random() method.

1
Sander Saelmans On

If you need to use sourcery however:

{% for type in types.enums %}
extension {{ type.name }} {
    static func random() -> {{ type.name }} {
        [{% for case in type.cases %}.{{ case.name }},{% endfor %}].randomElement()!
    }
}
{% endfor %}

The problem with the example you provided is that you expect index to be an actual number. The problem is that in its current state, it's actually trying to access a property called "index".