0

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?

Mo Abdul-Hameed
  • 6,030
  • 2
  • 23
  • 36
  • Are you familiar with the CaseIterable protocol? If you can make all of your enums conform to that all you have to do is call YourEnum.allCases.randomElement() – Rob C Jun 22 '20 at 09:35
  • Is it a requirement that you have to do this via sourcery? If not you can opt for `CaseIterable`, and use `YourEnum.allCases.randomElement()` – Sander Saelmans Jun 22 '20 at 09:42
  • @RobertCrabtree Thank you for the idea, Robert! – Mo Abdul-Hameed Jun 22 '20 at 16:29

2 Answers2

1

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.

Mo Abdul-Hameed
  • 6,030
  • 2
  • 23
  • 36
0

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".

Sander Saelmans
  • 831
  • 4
  • 13