From c37bcc4a44be262c9009233611f7c52185297266 Mon Sep 17 00:00:00 2001 From: LUO Yihao Date: Fri, 26 Feb 2016 17:59:35 +0800 Subject: [PATCH] Add one more option "--css-class-splitter" when we use closure-stylesheets. By this developers can assign any single character as splitter for closure-stylesheets to use. --- .../common/css/SplittingSubstitutionMap.java | 50 +++++++++++++--- .../ClosureCommandLineCompiler.java | 57 +++++++++++++++++++ .../compiler/commandline/RenamingType.java | 5 +- .../ClosureCommandLineCompilerTest.java | 16 ++++++ 4 files changed, 118 insertions(+), 10 deletions(-) diff --git a/src/com/google/common/css/SplittingSubstitutionMap.java b/src/com/google/common/css/SplittingSubstitutionMap.java index 77bfb868..062f4f42 100644 --- a/src/com/google/common/css/SplittingSubstitutionMap.java +++ b/src/com/google/common/css/SplittingSubstitutionMap.java @@ -16,6 +16,7 @@ package com.google.common.css; +import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Preconditions; import com.google.common.base.Splitter; import com.google.common.collect.ImmutableMap; @@ -24,19 +25,52 @@ import java.util.Map; /** - * The CSS class substitution map which splits CSS class names on the "-" (dash) - * character and processes them separately using a delegate substitution map. + *

The CSS class substitution map which splits CSS class names on the "-" (dash) + * character and processes them separately using a delegate substitution map.

* + *

At the same time, if customized splitter character is assigned, the CSS class + * substitution map will splits CSS class names on the specific character;

+ * * @author dgajda@google.com (Damian Gajda) */ public class SplittingSubstitutionMap implements MultipleMappingSubstitutionMap { - private static final Splitter DASH = Splitter.on('-'); + public static final char DEFAULT_CSS_CLASS_SPLITTER_CHAR = '-'; + private static final Splitter DEFAULT_CSS_CLASS_SPLITTER = Splitter. + on(DEFAULT_CSS_CLASS_SPLITTER_CHAR); private final SubstitutionMap delegate; - + + /** + * Make splitter become configurable. The value can be decided by the option + * user input. Default value is dash character '-'. + */ + private char splitterChar = DEFAULT_CSS_CLASS_SPLITTER_CHAR; + private Splitter splitter = DEFAULT_CSS_CLASS_SPLITTER; + public SplittingSubstitutionMap(SubstitutionMap substitutionMap) { this.delegate = substitutionMap; } + + /** + * Please NOTE: this method is used as internal method when developers want to + * introduce customized css class splitter. So do not call it manually. + * + * @param splitterChar The customized splitter you need. + */ + public void registerSplitter(char splitterChar) { + this.splitterChar = splitterChar; + this.splitter = Splitter.on(splitterChar); + } + + /** + * Please NOTE: this method is used as testing method. So do not call it manually. + * + * @return splitterChar + */ + @VisibleForTesting + public char getSplitterChar() { + return splitterChar; + } @Override public String get(String key) { @@ -48,8 +82,8 @@ public ValueWithMappings getValueWithMappings(String key) { Preconditions.checkNotNull(key, "CSS key cannot be null"); Preconditions.checkArgument(!key.isEmpty(), "CSS key cannot be empty"); - // Efficiently handle the common case with no dashes. - if (key.indexOf('-') == -1) { + // Efficiently handle the common case with no specific splitter character. + if (key.indexOf(this.splitterChar) == -1) { String value = delegate.get(key); return ValueWithMappings.createForSingleMapping(key, value); } @@ -58,9 +92,9 @@ public ValueWithMappings getValueWithMappings(String key) { // Cannot use an ImmutableMap.Builder because the same key/value pair may be // inserted more than once in this loop. Map mappings = Maps.newHashMap(); - for (String part : DASH.split(key)) { + for (String part : splitter.split(key)) { if (buffer.length() != 0) { - buffer.append('-'); + buffer.append(this.splitterChar); } String value = delegate.get(part); diff --git a/src/com/google/common/css/compiler/commandline/ClosureCommandLineCompiler.java b/src/com/google/common/css/compiler/commandline/ClosureCommandLineCompiler.java index 51b7d751..0b4585e8 100644 --- a/src/com/google/common/css/compiler/commandline/ClosureCommandLineCompiler.java +++ b/src/com/google/common/css/compiler/commandline/ClosureCommandLineCompiler.java @@ -33,6 +33,8 @@ import com.google.common.css.JobDescriptionBuilder; import com.google.common.css.OutputRenamingMapFormat; import com.google.common.css.SourceCode; +import com.google.common.css.SplittingSubstitutionMap; +import com.google.common.css.SubstitutionMap; import com.google.common.css.Vendor; import com.google.common.css.compiler.ast.ErrorManager; import com.google.common.css.compiler.gssfunctions.DefaultGssFunctionMapProvider; @@ -62,6 +64,9 @@ */ public class ClosureCommandLineCompiler extends DefaultCommandLineCompiler { + private static final String DEFAULT_CSS_CLASS_SLIPPTER_SINGLE_CHARACTER_STRING = + String.valueOf(SplittingSubstitutionMap.DEFAULT_CSS_CLASS_SPLITTER_CHAR); + protected ClosureCommandLineCompiler(JobDescription job, ExitCodeHandler exitCodeHandler, ErrorManager errorManager) { super(job, exitCodeHandler, errorManager); @@ -202,6 +207,12 @@ static class Flags { usage = "Specify integer constants to be used in for loops. Invoke for each const, e.g.: " + "--const=VAR1=VALUE1 --const=VAR2=VALUE2") private Map compileConstants = new HashMap<>(); + + @Option(name = "--css-class-splitter", + usage = "Define your single-character customized splitter when process " + + "css class names. Default value is '-'. If you want to enable this feature, " + + "please choose 'DEBUG' or 'CLOSURE' for '--rename'") + private String splitter = DEFAULT_CSS_CLASS_SLIPPTER_SINGLE_CHARACTER_STRING; /** * All remaining arguments are considered input CSS files. @@ -283,6 +294,43 @@ private Map parseCompileConstants( } return parsedConstants; } + + /** + * Only following requirements are satisfied, the customized splitter will + * be used: + *
    + *
  • + * Option css-class-splitter is NOT Null or empty; + *
  • + *
  • + * Option css-class-splitter only contains ONE character; + *
  • + *
  • + * Option css-class-splitter doesn't equal to default value '-'; + *
  • + *
  • + * Option renamingType is RenamingType.CLOSURE or + * RenamingType.DEBUG; + *
  • + *
+ */ + @VisibleForTesting + void registerSplitterIfExist() { + if (!Strings.isNullOrEmpty(splitter) + && !splitter.equals(DEFAULT_CSS_CLASS_SLIPPTER_SINGLE_CHARACTER_STRING) + && (renamingType.equals(RenamingType.CLOSURE) + || renamingType.equals(RenamingType.DEBUG))) { + SubstitutionMap map = renamingType.getCssSubstitutionMapProvider().get(); + if (map instanceof SplittingSubstitutionMap) { + ((SplittingSubstitutionMap)map).registerSplitter(splitter.charAt(0)); + } + } + } + + @VisibleForTesting + RenamingType getRenamingType() { + return renamingType; + } } /** @@ -386,8 +434,16 @@ public void printUsage(OutputStream out) { return null; } + boolean errorHappen = false; + if (!Strings.isNullOrEmpty(flags.splitter) && flags.splitter.length() > 1) { + System.err.println("\nERROR: Only single character is supported for --css-class-splitter.\n"); + errorHappen = true; + } if (flags.arguments.isEmpty()) { System.err.println("\nERROR: No input files specified.\n"); + errorHappen = true; + } + if (errorHappen) { argsParser.printUsage(System.err); exitCodeHandler.processExitCode( AbstractCommandLineCompiler.ERROR_MESSAGE_EXIT_CODE); @@ -404,6 +460,7 @@ public static void main(String[] args) { return; } + flags.registerSplitterIfExist(); JobDescription job = flags.createJobDescription(); OutputInfo info = flags.createOutputInfo(); executeJob(job, exitCodeHandler, info); diff --git a/src/com/google/common/css/compiler/commandline/RenamingType.java b/src/com/google/common/css/compiler/commandline/RenamingType.java index bb594184..ddc88119 100644 --- a/src/com/google/common/css/compiler/commandline/RenamingType.java +++ b/src/com/google/common/css/compiler/commandline/RenamingType.java @@ -52,8 +52,9 @@ public SubstitutionMap get() { /** - * Each chunk of a CSS class as delimited by '-' is renamed using the - * shortest available name. + * Each chunk of a CSS class as delimited by specific splitter is + * renamed using the shortest available name. Default specific + * splitter is '-'. */ CLOSURE(new SubstitutionMapProvider() { @Override diff --git a/tests/com/google/common/css/compiler/commandline/ClosureCommandLineCompilerTest.java b/tests/com/google/common/css/compiler/commandline/ClosureCommandLineCompilerTest.java index 176712dd..934b8a4f 100644 --- a/tests/com/google/common/css/compiler/commandline/ClosureCommandLineCompilerTest.java +++ b/tests/com/google/common/css/compiler/commandline/ClosureCommandLineCompilerTest.java @@ -19,6 +19,7 @@ import com.google.common.css.JobDescription; import com.google.common.css.JobDescriptionBuilder; import com.google.common.css.SourceCode; +import com.google.common.css.SplittingSubstitutionMap; import com.google.common.css.compiler.ast.ErrorManager; import com.google.common.css.compiler.ast.testing.NewFunctionalTestBase; @@ -26,6 +27,8 @@ public class ClosureCommandLineCompilerTest extends TestCase { + private static final String TEST_SPLITTER = "-"; + static final ExitCodeHandler EXIT_CODE_HANDLER = new ExitCodeHandler() { @Override @@ -64,4 +67,17 @@ public void testAllowDefPropagationDefaultsToTrue() throws Exception { JobDescription jobDescription = flags.createJobDescription(); assertTrue(jobDescription.allowDefPropagation); } + + public void testAssignCustomizedSplitter() throws Exception { + ClosureCommandLineCompiler.Flags flags = + ClosureCommandLineCompiler.parseArgs(new String[] {"--allow-unrecognized-functions", + "--allow-unrecognized-properties", "--rename", "CLOSURE", + "--css-class-splitter", TEST_SPLITTER, "/dev/null"}, EXIT_CODE_HANDLER); + flags.registerSplitterIfExist(); + assertEquals("Type of RenamingType should be CLOSURE", + flags.getRenamingType().name(), "CLOSURE"); + assertEquals("The passed splitter should be the same as it in test case.", + TEST_SPLITTER.charAt(0), + ((SplittingSubstitutionMap)(flags.getRenamingType().getCssSubstitutionMapProvider().get())).getSplitterChar()); + } }