From 7e541d398a99876ef2a4c49b4c147a692f75babf Mon Sep 17 00:00:00 2001 From: Adam Davis Date: Wed, 3 Jul 2019 10:50:28 -0400 Subject: [PATCH] 1.0-M3: Made it so metaClasses are not modified by default but are for the gradle plugin; also added processors to GroocssExtension and added tests --- groocss-gradle-plugin/build.gradle | 5 ++ .../org/groocss/GroocssExtension.groovy | 9 ++- .../groovy/org/groocss/GroocssPlugin.groovy | 2 +- .../groovy/org/groocss/GroocssTask.groovy | 6 +- .../org/groocss/GroocssExtensionSpec.groovy | 30 +++++++ .../org/groocss/GroocssPluginSpec.groovy | 35 +++++++++ .../groovy/org/groocss/GroocssTaskSpec.groovy | 78 +++++++++++++++++++ src/main/groovy/org/groocss/GrooCSS.groovy | 24 ++++-- 8 files changed, 179 insertions(+), 10 deletions(-) create mode 100644 groocss-gradle-plugin/src/test/groovy/org/groocss/GroocssExtensionSpec.groovy create mode 100644 groocss-gradle-plugin/src/test/groovy/org/groocss/GroocssPluginSpec.groovy create mode 100644 groocss-gradle-plugin/src/test/groovy/org/groocss/GroocssTaskSpec.groovy diff --git a/groocss-gradle-plugin/build.gradle b/groocss-gradle-plugin/build.gradle index a45749f..bd9b77d 100644 --- a/groocss-gradle-plugin/build.gradle +++ b/groocss-gradle-plugin/build.gradle @@ -42,6 +42,11 @@ dependencies { compile project(':'), { exclude module: "groovy-all", group: "org.codehaus.groovy" } + testCompile 'org.spockframework:spock-core:1.1-groovy-2.4', { + exclude module: "groovy-all", group: "org.codehaus.groovy" + } + testRuntime "net.bytebuddy:byte-buddy:1.9.13" + testRuntime "org.objenesis:objenesis:3.0.1" } group = 'org.groocss' diff --git a/groocss-gradle-plugin/src/main/groovy/org/groocss/GroocssExtension.groovy b/groocss-gradle-plugin/src/main/groovy/org/groocss/GroocssExtension.groovy index 9dfca1f..bb37845 100644 --- a/groocss-gradle-plugin/src/main/groovy/org/groocss/GroocssExtension.groovy +++ b/groocss-gradle-plugin/src/main/groovy/org/groocss/GroocssExtension.groovy @@ -1,5 +1,7 @@ package org.groocss +import org.groocss.proc.Processor + /** Extension to Gradle for configuring GrooCSS. */ class GroocssExtension { @@ -18,5 +20,10 @@ class GroocssExtension { /** Whether or not convert under-scores in CSS classes into dashes (main_content becomes main-content). * Default is false. */ boolean convertUnderline = false - + + /** Custom processors/validators to use. + * @see org.groocss.proc.Processor + * @see org.groocss.valid.DefaultValidator + */ + Set processors = [] } diff --git a/groocss-gradle-plugin/src/main/groovy/org/groocss/GroocssPlugin.groovy b/groocss-gradle-plugin/src/main/groovy/org/groocss/GroocssPlugin.groovy index 82f4563..10b0838 100644 --- a/groocss-gradle-plugin/src/main/groovy/org/groocss/GroocssPlugin.groovy +++ b/groocss-gradle-plugin/src/main/groovy/org/groocss/GroocssPlugin.groovy @@ -38,7 +38,7 @@ class GroocssPlugin implements Plugin { def convertFile = {File inFile, File out -> Config config = new Config(extension.properties) - GrooCSS.convert(config, inFile, out) + GrooCSS.convert(config, inFile, out, extension.charset ?: 'UTF-8', true) } def convertCss = project.task("convertCss") diff --git a/groocss-gradle-plugin/src/main/groovy/org/groocss/GroocssTask.groovy b/groocss-gradle-plugin/src/main/groovy/org/groocss/GroocssTask.groovy index 9e261f6..77c7f92 100644 --- a/groocss-gradle-plugin/src/main/groovy/org/groocss/GroocssTask.groovy +++ b/groocss-gradle-plugin/src/main/groovy/org/groocss/GroocssTask.groovy @@ -17,6 +17,7 @@ import org.gradle.internal.file.PathToFileResolver class GroocssTask extends Copy { Config conf + String charset = 'UTF-8' @Override protected CopyAction createCopyAction() { @@ -30,6 +31,7 @@ class GroocssTask extends Copy { throw new InvalidUserDataException("No copy destination directory has been specified, use 'into' to specify a target directory."); } def action = new GroocssFileAction(fileLookup.getFileResolver(destinationDir), conf, rootSpec) + action.charset = charset stream.process(action) return WorkResults.didWork(action.didWork) } @@ -41,6 +43,7 @@ class GroocssTask extends Copy { private final PathToFileResolver fileResolver Config config + String charset = 'UTF-8' CopySpec copySpec boolean didWork @@ -61,7 +64,8 @@ class GroocssTask extends Copy { if (copied) { File newTarget = new File(target.parentFile, GroocssPlugin.toCssName(target.name)) - GrooCSS.convert config, target, newTarget + + GrooCSS.convert config, target, newTarget, charset, true target.delete() didWork = true } diff --git a/groocss-gradle-plugin/src/test/groovy/org/groocss/GroocssExtensionSpec.groovy b/groocss-gradle-plugin/src/test/groovy/org/groocss/GroocssExtensionSpec.groovy new file mode 100644 index 0000000..adf01f4 --- /dev/null +++ b/groocss-gradle-plugin/src/test/groovy/org/groocss/GroocssExtensionSpec.groovy @@ -0,0 +1,30 @@ +package org.groocss + +import spock.lang.Specification + +class GroocssExtensionSpec extends Specification { + + def "should have basic properties" () { + expect: + def ext = new GroocssExtension(compress: true, prettyPrint: true) + ext.compress + ext.prettyPrint + ext.addMoz + ext.addMs + ext.addOpera + ext.addWebkit + } + + def "should have charset default of null" () { + expect: + def ext = new GroocssExtension() + ext.charset == null + } + + def "should have processors which is empty list by default" () { + expect: + def ext = new GroocssExtension() + ext.processors.empty + ext.processors instanceof Set + } +} diff --git a/groocss-gradle-plugin/src/test/groovy/org/groocss/GroocssPluginSpec.groovy b/groocss-gradle-plugin/src/test/groovy/org/groocss/GroocssPluginSpec.groovy new file mode 100644 index 0000000..cf367fb --- /dev/null +++ b/groocss-gradle-plugin/src/test/groovy/org/groocss/GroocssPluginSpec.groovy @@ -0,0 +1,35 @@ +package org.groocss + +import org.gradle.api.NamedDomainObjectContainer +import org.gradle.api.Project +import org.gradle.api.Task +import org.gradle.api.plugins.ExtensionContainer +import org.gradle.api.tasks.TaskContainer +import spock.lang.Specification + +class GroocssPluginSpec extends Specification { + + + def "GroocssPlugin should work as a plugin" () { + given: + def project = Mock(Project.class) + def extensions = Mock(ExtensionContainer) + def files = Mock(NamedDomainObjectContainer) + def tasks = Mock(TaskContainer) + def convertCss = Mock(Task) + when: + def p = new GroocssPlugin() + + p.apply(project) + then: + project.getExtensions() >> { extensions } + 1 * extensions.create("groocss", GroocssExtension) + project.container(GrooCssFile) >> files + project.getTasks() >> { tasks } + 1* tasks.findByName("build") + 1* tasks.findByName("processResources") + project.task("convertCss") >> { convertCss } + 1* convertCss.doFirst(_) + } + +} diff --git a/groocss-gradle-plugin/src/test/groovy/org/groocss/GroocssTaskSpec.groovy b/groocss-gradle-plugin/src/test/groovy/org/groocss/GroocssTaskSpec.groovy new file mode 100644 index 0000000..1f23330 --- /dev/null +++ b/groocss-gradle-plugin/src/test/groovy/org/groocss/GroocssTaskSpec.groovy @@ -0,0 +1,78 @@ +package org.groocss + +import org.gradle.api.file.CopySpec +import org.gradle.api.file.RelativePath +import org.gradle.api.internal.file.copy.FileCopyDetailsInternal +import org.gradle.internal.file.PathToFileResolver +import spock.lang.Specification +import spock.lang.Unroll + +class GroocssTaskSpec extends Specification { + + @Unroll + def "should convert regular groocss file #i"() { + given: + def resolver = Mock(PathToFileResolver) + def copySpec = Mock(CopySpec) + def details = Mock(FileCopyDetailsInternal) + def path = Mock(RelativePath) + def config = new Config().noExts().compress() + def target = File.createTempFile("test", ".css.groovy") + File newTarget = new File(target.parentFile, GroocssPlugin.toCssName(target.name)) + def testFile = File.createTempFile("input", ".css.groovy") + when: + testFile.text = groocss + new GroocssTask.GroocssFileAction(resolver, config, copySpec).processFile(details) + then: + details.getRelativePath() >> { path } + resolver.resolve(_) >> { target } + details.copyTo(_) >> { target.text = testFile.text } + + assert newTarget.isFile() + println(newTarget.text) + assert newTarget.text == css + where: + i || groocss || css + 1 | '''import org.groocss.Config + 'test'.groocss(new Config().noExts().compress()) { + + body { fontSize 2.em color 0.color } + + article { padding 2.em } + + 'thing'.id { fontSize 200.percent } + + keyframes('test') { + from { color black } to { color red } + } + + } + ''' | "body{font-size: 2em;color: #000000;}article{padding: 2em;}#thing{font-size: 200%;}"+ + "@keyframes test {from{color: Black;}to{color: Red;}}" + 2 | ''' + body { fontSize 2.em color 0.color } + + article { padding 2.em } + + 'thing'.id { fontSize 200.percent } + + 'test'.kf { + from { color black } to { color red } + } + ''' | "body{font-size: 2em;color: #000000;}article{padding: 2em;}#thing{font-size: 200%;}"+ + "@keyframes test {from{color: Black;}to{color: Red;}}" + 3 | 'assert 1.initMetaClassesCalled()' | '' + } + + def "should have default charset"() { + given: + def resolver = Mock(PathToFileResolver) + def copySpec = Mock(CopySpec) + def config = new Config() + expect: + def action = new GroocssTask.GroocssFileAction(resolver, config, copySpec) + action.charset == 'UTF-8' + } + + +} diff --git a/src/main/groovy/org/groocss/GrooCSS.groovy b/src/main/groovy/org/groocss/GrooCSS.groovy index 6f356a9..6acf49c 100644 --- a/src/main/groovy/org/groocss/GrooCSS.groovy +++ b/src/main/groovy/org/groocss/GrooCSS.groovy @@ -54,9 +54,12 @@ class GrooCSS extends Script implements CurrentKeyFrameHolder { * @param conf Optional Config object for configuration. * @param inf Input file with GrooCSS code. * @param out Output file of resulting CSS. + * @param charset Charset of file to read (UTF-8 by default). + * @param addMeta Tells GrooCSS to augment String and Integer classes using metaClass (false by default). */ - static void convert(Config conf = new Config(), File inf, File out) { - convert(conf, inf.newInputStream(), out.newOutputStream()) + static void convert(Config conf = new Config(), File inf, File out, + String charset = "UTF-8", boolean addMeta = false) { + convert(conf, inf.newInputStream(), out.newOutputStream(), charset, addMeta) } /** @@ -90,18 +93,20 @@ class GrooCSS extends Script implements CurrentKeyFrameHolder { /** Processes a given InputStream and outputs to given OutputStream. */ @TypeChecked - static void convert(Config conf = new Config(), InputStream inf, OutputStream out, String charset1 = "UTF-8") { + static void convert(Config conf = new Config(), InputStream inf, OutputStream out, String charset1 = "UTF-8", + boolean addMeta = false) { out.withPrintWriter { pw -> - convert conf, new InputStreamReader(inf, charset1), pw + convert conf, new InputStreamReader(inf, charset1), pw, addMeta } } /** Processes a given Reader and outputs to given PrintWriter. */ @TypeChecked - static void convert(Config conf = new Config(), Reader reader, PrintWriter writer) { + static void convert(Config conf = new Config(), Reader reader, PrintWriter writer, boolean addMeta = false) { reader.withCloseable { input -> def shell = makeShell() def script = shell.parse(input) + if (addMeta) script.invokeMethod('initMetaClasses', true) script.invokeMethod('setConfig', conf) def result = script.run() MediaCSS css = (MediaCSS) script.getProperty('css') @@ -218,11 +223,16 @@ class GrooCSS extends Script implements CurrentKeyFrameHolder { GrooCSS() { - addNumberMetaStuff() - addStringMetaStuff() threadLocalInstance.set(this) // set this instance for the current Thread } + /** Called when addMeta is true (parameter to "convert") which is used by Gradle plugin. */ + void initMetaClasses(boolean addNumberMeta = true, boolean addStringMeta = true) { + if (addNumberMeta) addNumberMetaStuff() + if (addStringMeta) addStringMetaStuff() + Integer.metaClass.initMetaClassesCalled = {return true} + } + private void addStringMetaStuff() { String.metaClass.groocss = { Config config, Closure closure -> println "processing $delegate"; GrooCSS.process(config, closure)