diff options
author | Cedric Beust <cedric@beust.com> | 2012-08-01 10:45:27 -0700 |
---|---|---|
committer | Cedric Beust <cedric@beust.com> | 2012-08-01 10:45:27 -0700 |
commit | dbccffb3047aa721e3c09ecda4e6b12a00152dd1 (patch) | |
tree | 32eb15ff497c92e696a9bf4201b12989f50b3f28 | |
parent | 18acf239feebe9f079a4d31e1852556b7cd2fd4c (diff) | |
download | jcommander-dbccffb3047aa721e3c09ecda4e6b12a00152dd1.tar.gz |
Refactoring: introducing FuzzyMap and IKey.
-rw-r--r-- | src/main/java/com/beust/jcommander/FuzzyMap.java | 61 | ||||
-rw-r--r-- | src/main/java/com/beust/jcommander/JCommander.java | 94 | ||||
-rw-r--r-- | src/main/java/com/beust/jcommander/StringKey.java | 48 | ||||
-rw-r--r-- | src/test/java/com/beust/jcommander/JCommanderTest.java | 2 | ||||
-rw-r--r-- | src/test/resources/testng-single.xml | 8 |
5 files changed, 146 insertions, 67 deletions
diff --git a/src/main/java/com/beust/jcommander/FuzzyMap.java b/src/main/java/com/beust/jcommander/FuzzyMap.java new file mode 100644 index 0000000..5f3939b --- /dev/null +++ b/src/main/java/com/beust/jcommander/FuzzyMap.java @@ -0,0 +1,61 @@ +package com.beust.jcommander; + +import com.beust.jcommander.internal.Maps; + +import java.util.Map; + +/** + * Helper class to perform fuzzy key look ups: looking up case insensitive or + * abbreviated keys. + */ +public class FuzzyMap { + interface IKey { + String getName(); + } + + public static <V> V findInMap(Map<? extends IKey, V> map, IKey name, + boolean caseSensitive, boolean allowAbbreviations) { + if (allowAbbreviations) { + return findAbbreviatedValue(map, name, caseSensitive); + } else { + if (caseSensitive) { + return map.get(name); + } else { + for (IKey c : map.keySet()) { + if (c.getName().equalsIgnoreCase(name.getName())) { + return map.get(c); + } + } + } + } + return null; + } + + private static <V> V findAbbreviatedValue(Map<? extends IKey, V> map, IKey name, + boolean caseSensitive) { + String string = name.getName(); + Map<String, V> results = Maps.newHashMap(); + for (IKey c : map.keySet()) { + String n = c.getName(); + boolean match = (caseSensitive && n.startsWith(string)) + || ((! caseSensitive) && n.toLowerCase().startsWith(string.toLowerCase())); + if (match) { + results.put(n, map.get(c)); + } + } + + V result; + if (results.size() > 1) { + throw new ParameterException("Ambiguous option: " + name + + " matches " + results.keySet()); + } else if (results.size() == 1) { + result = results.values().iterator().next(); + } else { + result = null; + } + + return result; + } + + +} diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index fccbb9e..bfda67f 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -18,6 +18,7 @@ package com.beust.jcommander; +import com.beust.jcommander.FuzzyMap.IKey; import com.beust.jcommander.converters.IParameterSplitter; import com.beust.jcommander.converters.NoConverter; import com.beust.jcommander.converters.StringConverter; @@ -67,7 +68,7 @@ public class JCommander { /** * A map to look up parameter description per option name. */ - private Map<String, ParameterDescription> m_descriptions; + private Map<IKey, ParameterDescription> m_descriptions; /** * The objects that contain fields annotated with @Parameter. @@ -122,7 +123,7 @@ public class JCommander { /** * Alias database for reverse lookup */ - private Map<String, ProgramName> aliasMap = Maps.newLinkedHashMap(); + private Map<IKey, ProgramName> aliasMap = Maps.newLinkedHashMap(); /** * The name of the command after the parsing has run. @@ -399,8 +400,8 @@ public class JCommander { } private ParameterDescription getPrefixDescriptionFor(String arg) { - for (Map.Entry<String, ParameterDescription> es : m_descriptions.entrySet()) { - if (arg.startsWith(es.getKey())) return es.getValue(); + for (Map.Entry<IKey, ParameterDescription> es : m_descriptions.entrySet()) { + if (arg.startsWith(es.getKey().getName())) return es.getValue(); } return null; @@ -539,14 +540,14 @@ public class JCommander { new ParameterDescription(object, p, parameterized, m_bundle, this); } else { for (String name : p.names()) { - if (m_descriptions.containsKey(name)) { + if (m_descriptions.containsKey(new StringKey(name))) { throw new ParameterException("Found the option " + name + " multiple times"); } p("Adding description for " + name); ParameterDescription pd = new ParameterDescription(object, p, parameterized, m_bundle, this); m_fields.put(parameterized, pd); - m_descriptions.put(name, pd); + m_descriptions.put(new StringKey(name), pd); if (p.required()) m_requiredFields.put(parameterized, pd); } @@ -574,7 +575,7 @@ public class JCommander { ParameterDescription pd = new ParameterDescription(object, dp, parameterized, m_bundle, this); m_fields.put(parameterized, pd); - m_descriptions.put(name, pd); + m_descriptions.put(new StringKey(name), pd); if (dp.required()) m_requiredFields.put(parameterized, pd); } @@ -1356,8 +1357,9 @@ public class JCommander { //Note: Name clash check is intentionally omitted to resemble the // original behaviour of clashing commands. // Aliases are, however, are strictly checked for name clashes. - aliasMap.put(name, progName); - for (String alias : aliases) { + aliasMap.put(new StringKey(name), progName); + for (String a : aliases) { + IKey alias = new StringKey(a); //omit pointless aliases to avoid name clash exception if (!alias.equals(name)) { ProgramName mappedName = aliasMap.get(alias); @@ -1415,68 +1417,29 @@ public class JCommander { return m_objects; } - private <V> V findAbbreviatedOption(Map<String, V> map, String name, boolean caseSensitive) { - Map<String, V> results = Maps.newHashMap(); - for (String c : map.keySet()) { - boolean match = (caseSensitive && c.startsWith(name)) - || ((! caseSensitive) && c.toLowerCase().startsWith(name.toLowerCase())); - if (match) { - results.put(c, map.get(c)); - } - } - V result; - if (results.size() > 1) { - throw new ParameterException("Ambiguous option: " + name - + " matches " + results.keySet()); - } else if (results.size() == 1) { - result = results.values().iterator().next(); - } else { - result = null; - } - - return result; - } - - private <V> V findCaseSensitiveMap(Map<String, V> map, String name) { - if (m_caseSensitiveOptions) { - if (m_allowAbbreviatedOptions) { - return findAbbreviatedOption(map, name, m_caseSensitiveOptions); - } else { - return map.get(name); - } - } else { - if (m_allowAbbreviatedOptions) { - return findAbbreviatedOption(map, name, m_caseSensitiveOptions); - } else { - for (String c : map.keySet()) { - if (c.equalsIgnoreCase(name)) { - return map.get(c); - } - } - } - } - return null; - } - private ParameterDescription findParameterDescription(String arg) { - return findCaseSensitiveMap(m_descriptions, arg); + return FuzzyMap.findInMap(m_descriptions, new StringKey(arg), m_caseSensitiveOptions, + m_allowAbbreviatedOptions); } private JCommander findCommand(ProgramName name) { - if (! m_caseSensitiveOptions) { - return m_commands.get(name); - } else { - for (ProgramName c : m_commands.keySet()) { - if (c.getName().equalsIgnoreCase(name.getName())) { - return m_commands.get(c); - } - } - } - return null; + return FuzzyMap.findInMap(m_commands, name, + m_caseSensitiveOptions, m_allowAbbreviatedOptions); +// if (! m_caseSensitiveOptions) { +// return m_commands.get(name); +// } else { +// for (ProgramName c : m_commands.keySet()) { +// if (c.getName().equalsIgnoreCase(name.getName())) { +// return m_commands.get(c); +// } +// } +// } +// return null; } private ProgramName findProgramName(String name) { - return findCaseSensitiveMap(aliasMap, name); + return FuzzyMap.findInMap(aliasMap, new StringKey(name), + m_caseSensitiveOptions, m_allowAbbreviatedOptions); } /* @@ -1499,7 +1462,7 @@ public class JCommander { /** * Encapsulation of either a main application or an individual command. */ - private static final class ProgramName { + private static final class ProgramName implements IKey { private final String m_name; private final List<String> m_aliases; @@ -1508,6 +1471,7 @@ public class JCommander { m_aliases = aliases; } + @Override public String getName() { return m_name; } diff --git a/src/main/java/com/beust/jcommander/StringKey.java b/src/main/java/com/beust/jcommander/StringKey.java new file mode 100644 index 0000000..09d1149 --- /dev/null +++ b/src/main/java/com/beust/jcommander/StringKey.java @@ -0,0 +1,48 @@ +package com.beust.jcommander; + +import com.beust.jcommander.FuzzyMap.IKey; + +public class StringKey implements IKey { + + private String m_name; + + public StringKey(String name) { + m_name = name; + } + + @Override + public String getName() { + return m_name; + } + + @Override + public String toString() { + return m_name; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((m_name == null) ? 0 : m_name.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + StringKey other = (StringKey) obj; + if (m_name == null) { + if (other.m_name != null) + return false; + } else if (!m_name.equals(other.m_name)) + return false; + return true; + } + +} diff --git a/src/test/java/com/beust/jcommander/JCommanderTest.java b/src/test/java/com/beust/jcommander/JCommanderTest.java index 741f16a..2f2d88d 100644 --- a/src/test/java/com/beust/jcommander/JCommanderTest.java +++ b/src/test/java/com/beust/jcommander/JCommanderTest.java @@ -861,7 +861,7 @@ public class JCommanderTest { @Test(enabled = false) public static void main(String[] args) throws Exception { -// new JCommanderTest().ambiguousAbbreviatedOptionsCaseInsensitive(); + new JCommanderTest().multiObjectsWithDuplicatesFail(); // class A { // @Parameter(names = "-short", required = true) // List<String> parameters; diff --git a/src/test/resources/testng-single.xml b/src/test/resources/testng-single.xml index c3cdd46..d981d70 100644 --- a/src/test/resources/testng-single.xml +++ b/src/test/resources/testng-single.xml @@ -4,7 +4,13 @@ <test name="JCommander tests"> <classes> - <class name="com.beust.jcommander.FinderTest"> +<!-- + <class name="com.beust.jcommander.FinderTest" /> +--> + <class name="com.beust.jcommander.command.CommandAliasTest"> + <methods> + <include name="clashingAliasesAreNotAllowed" /> + </methods> </class> </classes> </test> |