Introduce slugs in arenas and classes.

Whitespace and punctuation in identifiers is a fairly big source of
issues in areas like permissions and commands where whitespace isn't
directly supported (or at least makes things needlessly difficult).

This commit introduces the concept of a "slug" in arenas and classes,
giving them a _consistent_ `kebab-case` name for use in such places, but
it does not implement their use anywhere. Slugs are expected to be the
solution to problems like the one posed in issue #647.

At the time of writing, we're only concerned with simple stuff like
removing periods, commas, parentheses and replacing underscores and
spaces with dashes. If it turns out that people have unanticipatedly
problematic arena and class names, we may have to expand the slug
definition rules or allow for custom slugs.
This commit is contained in:
Andreas Troelsen
2020-11-01 14:28:33 +01:00
parent 5ebdf45f6a
commit aed57f5cb6
5 changed files with 84 additions and 0 deletions
@@ -3,6 +3,7 @@ package com.garbagemule.MobArena;
import com.garbagemule.MobArena.framework.Arena; import com.garbagemule.MobArena.framework.Arena;
import com.garbagemule.MobArena.framework.ArenaMaster; import com.garbagemule.MobArena.framework.ArenaMaster;
import com.garbagemule.MobArena.things.Thing; import com.garbagemule.MobArena.things.Thing;
import com.garbagemule.MobArena.util.Slugs;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
@@ -16,6 +17,7 @@ import java.util.stream.IntStream;
public class ArenaClass public class ArenaClass
{ {
private String configName, lowercaseName; private String configName, lowercaseName;
private String slug;
private Thing helmet, chestplate, leggings, boots, offhand; private Thing helmet, chestplate, leggings, boots, offhand;
private List<Thing> armor; private List<Thing> armor;
private List<Thing> items; private List<Thing> items;
@@ -32,6 +34,7 @@ public class ArenaClass
*/ */
public ArenaClass(String name, Thing price, boolean unbreakableWeapons, boolean unbreakableArmor) { public ArenaClass(String name, Thing price, boolean unbreakableWeapons, boolean unbreakableArmor) {
this.configName = name; this.configName = name;
this.slug = Slugs.create(name);
this.lowercaseName = name.toLowerCase().replace(" ", ""); this.lowercaseName = name.toLowerCase().replace(" ", "");
this.items = new ArrayList<>(); this.items = new ArrayList<>();
@@ -54,6 +57,14 @@ public class ArenaClass
return configName; return configName;
} }
/**
* Get the slug version of the arena class name.
* @return the slugified class name
*/
public String getSlug() {
return slug;
}
/** /**
* Get the lowercase class name. * Get the lowercase class name.
* @return the lowercase class name * @return the lowercase class name
@@ -26,6 +26,7 @@ import com.garbagemule.MobArena.things.InvalidThingInputString;
import com.garbagemule.MobArena.things.Thing; import com.garbagemule.MobArena.things.Thing;
import com.garbagemule.MobArena.things.ThingPicker; import com.garbagemule.MobArena.things.ThingPicker;
import com.garbagemule.MobArena.util.ClassChests; import com.garbagemule.MobArena.util.ClassChests;
import com.garbagemule.MobArena.util.Slugs;
import com.garbagemule.MobArena.util.inventory.InventoryManager; import com.garbagemule.MobArena.util.inventory.InventoryManager;
import com.garbagemule.MobArena.util.timer.AutoStartTimer; import com.garbagemule.MobArena.util.timer.AutoStartTimer;
import com.garbagemule.MobArena.util.timer.StartDelayTimer; import com.garbagemule.MobArena.util.timer.StartDelayTimer;
@@ -77,6 +78,7 @@ public class ArenaImpl implements Arena
// General stuff // General stuff
private MobArena plugin; private MobArena plugin;
private String name; private String name;
private String slug;
private World world; private World world;
private Messenger messenger; private Messenger messenger;
private Announcer announcer; private Announcer announcer;
@@ -155,6 +157,7 @@ public class ArenaImpl implements Arena
throw new NullPointerException("[MobArena] ERROR! World for arena '" + name + "' does not exist!"); throw new NullPointerException("[MobArena] ERROR! World for arena '" + name + "' does not exist!");
this.name = name; this.name = name;
this.slug = Slugs.create(name);
this.world = world; this.world = world;
this.plugin = plugin; this.plugin = plugin;
this.settings = makeSection(section, "settings"); this.settings = makeSection(section, "settings");
@@ -1448,6 +1451,11 @@ public class ArenaImpl implements Arena
return MAUtils.nameConfigToArena(name); return MAUtils.nameConfigToArena(name);
} }
@Override
public String getSlug() {
return slug;
}
@Override @Override
public MobArena getPlugin() public MobArena getPlugin()
{ {
@@ -223,6 +223,8 @@ public interface Arena
String arenaName(); String arenaName();
String getSlug();
MobArena getPlugin(); MobArena getPlugin();
Map<String,ArenaClass> getClasses(); Map<String,ArenaClass> getClasses();
@@ -0,0 +1,18 @@
package com.garbagemule.MobArena.util;
public final class Slugs {
/**
* Create a slug version
* @param input
* @return
*/
public static String create(String input) {
return input
.toLowerCase()
.replaceAll("[.,:;'\"]", "")
.replaceAll("[<>(){}\\[\\]]", "")
.replaceAll("[ _']", "-");
}
}
@@ -0,0 +1,45 @@
package com.garbagemule.MobArena.util;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameter;
import org.junit.runners.Parameterized.Parameters;
import java.util.Arrays;
import java.util.Collection;
import static org.junit.Assert.assertEquals;
@RunWith(Parameterized.class)
public class SlugsTest {
@Parameters
public static Collection<Object[]> data() {
return Arrays.asList(new Object[][] {
{"castle", "castle"},
{"Castle", "castle"},
{"CaStLe", "castle"},
{"Castle of Kebab", "castle-of-kebab"},
{"Area 52", "area-52"},
{"Project: Nuclear", "project-nuclear"},
{"Mr. Kebal Bab's Mansion", "mr-kebal-babs-mansion"},
{"Unnamed Arena (3)", "unnamed-arena-3"},
{"The Wolf Master", "the-wolf-master"},
{"already-a-slug", "already-a-slug"},
});
}
@Parameter
public String input;
@Parameter(1)
public String expected;
@Test
public void test() {
String actual = Slugs.create(input);
assertEquals("Wrong slug for '" + input + "'", expected, actual);
}
}