Skip to content

Commit

Permalink
steps toward Jython i18n support, still one hard-coded piece to remov…
Browse files Browse the repository at this point in the history
…e, and some work around languages having unicode issues
  • Loading branch information
sabrams committed Jan 30, 2012
1 parent d98bf81 commit da476b4
Show file tree
Hide file tree
Showing 4 changed files with 34 additions and 26 deletions.
26 changes: 15 additions & 11 deletions jython/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -124,11 +124,13 @@ def engine = new SimpleTemplateEngine()
def templateSource = new File(project.baseDir, "src${File.separator}main${File.separator}code_generator${File.separator}I18n.jython.txt").getText()
I18n.all.each { i18n ->
def binding = ["i18n":i18n]
template = engine.createTemplate(templateSource).make(binding)
def file = new File(project.baseDir, "target${File.separator}generated-sources${File.separator}i18n${File.separator}java${File.separator}cucumber${File.separator}runtime${File.separator}jython${File.separator}${i18n.underscoredIsoCode.toUpperCase()}.py")
file.parentFile.mkdirs()
file.write(template.toString(), "UTF-8")
if (!["ar", "bg", "he", "is", "ja", "ko", "pl", "ru", "sr_cyrl", "uk", "uz", "zh_cn", "zh_tw"].contains(i18n.underscoredIsoCode)) {
def binding = ["i18n":i18n]
template = engine.createTemplate(templateSource).make(binding)
file = new File(project.baseDir, "target${File.separator}generated-sources${File.separator}i18n${File.separator}java${File.separator}cucumber${File.separator}runtime${File.separator}jython${File.separator}i18n${File.separator}${i18n.underscoredIsoCode.toUpperCase()}.py")
file.parentFile.mkdirs()
file.write(template.toString(), "UTF-8")
}
}
]]></groovy>

Expand All @@ -143,15 +145,17 @@ I18n.all.each { i18n ->
<version>1.7</version>
<executions>
<execution>
<id>add-source</id>
<phase>generate-sources</phase>
<id>add-resource</id>
<phase>generate-resources</phase>
<goals>
<goal>add-source</goal>
<goal>add-resource</goal>
</goals>
<configuration>
<sources>
<source>${basedir}/target/generated-sources/i18n/java</source>
</sources>
<resources>
<resource>
<directory>${basedir}/target/generated-sources/i18n/java</directory>
</resource>
</resources>
</configuration>
</execution>
</executions>
Expand Down
11 changes: 1 addition & 10 deletions jython/src/main/code_generator/I18n.jython.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,4 @@ def keywords = i18n.codeKeywords.collect { kw ->
Normalizer.normalize(kw, Normalizer.Form.NFD).replaceAll("\\p{InCombiningDiacriticalMarks}+", "")
}.unique()
%>
class ${keywords[0]}(object):
def __init__(self, regexp):
self.regexp = regexp

def __call__(self, func):
arity = func.func_code.co_argcount - 1
backend.registerStepdef(StepDefinition(self.regexp, func), arity)
return func

${keywords.reverse().join(" = ")}
${keywords.join(" = ")} = I18NKeywordTemplate
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,15 @@
import org.python.core.PyString;
import org.python.util.PythonInterpreter;

import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.List;

public class JythonBackend implements Backend {
private static final String DSL = "/cucumber/runtime/jython/dsl.py";
private static final String EN = "/cucumber/runtime/jython/i18n/EN.py"; // temporary
private final SnippetGenerator snippetGenerator = new SnippetGenerator(new JythonSnippet());
private final ResourceLoader resourceLoader;
private final PythonInterpreter jython;
Expand All @@ -29,6 +33,7 @@ public JythonBackend(ResourceLoader resourceLoader, PythonInterpreter jython) {
this.jython = jython;
jython.set("backend", this);
jython.execfile(getClass().getResourceAsStream(DSL), DSL);
jython.execfile(getClass().getResourceAsStream(EN), EN);
}

public JythonBackend(ResourceLoader resourceLoader) {
Expand Down
18 changes: 13 additions & 5 deletions jython/src/main/resources/cucumber/runtime/jython/dsl.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,19 @@
import re
from gherkin.formatter import Argument

class I18NKeywordTemplate(object):
def __init__(self, regexp):
self.regexp = regexp

def __call__(self, func):
arity = func.func_code.co_argcount - 1
backend.registerStepdef(StepDefinition(self.regexp, func), arity)
return func

class StepDefinition:
def __init__(self, regexp, func):
self.regexp = regexp
self.func = func

self.regexp = regexp
self.func = func
def matched_arguments(self, step_name):
match = re.match(self.regexp, step_name)
if(match):
Expand All @@ -26,6 +34,6 @@ def execute(self, *args):
def pattern(self):
return self.regexp


class World:
"""The World"""

4 comments on commit da476b4

@aslakhellesoy
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems like a decent workaround. Latin-to-ASCII able Locales get translated. Others don't because it's a limitation of Python/Jython.

Am I right?

@sabrams
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is correct. To support the annotation format we're given by the Jython interpreter for these unicode, non-ascii-able languages, there will at least need to be some pre-processing phase on the file. One possibility for a future update: we could use a character replacement mechanism on both the I18N file generator and this pre-processing phase, creating classes whose names were ascii-able. For example, if in English we suddenly started spelling Given with the Yen sign (Gi¥en), and someone wrote the step def:

@gi¥en('I have (\d+) "(.+)" in my belly')
def something_in_the_belly(self, n, what):
self.n = int(n)
self.what = what

we could use a preprocess phase that parses this file, and feeds this to the Jython parser:

@GiU_00A5en('I have (\d+) "(.+)" in my belly')
def something_in_the_belly(self, n, what):
self.n = int(n)
self.what = what

This would run, grabbing the class name from the annotation, where the class def was already loaded in the EN.py I18N file:

And = But = GiU_00A5en = Then = When = I18NKeywordTemplate

(U+00A5 is Unicode char point for Yen sym)

Anyway, support for most of the languages is almost there - just need a way to load them and make them usable from any context (maven, cli, ide)

@aslakhellesoy
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This sounds like it would allow people to write invalid python code. (non-ASCII annotations are invalid python as it seems).

Allowing people to write invalid python doesn't sound like a good idea to me. I think people working in non-ASCII languages should be forced to use ASCII.

@sabrams
Copy link
Owner Author

@sabrams sabrams commented on da476b4 Feb 7, 2012

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm in agreement about keeping the Python code valid.

Please sign in to comment.