From f35060fa22b8a0bb2b812f3772ff4657b9033014 Mon Sep 17 00:00:00 2001 From: Philippe Mioulet Date: Mon, 21 Oct 2019 18:05:46 +0200 Subject: [PATCH] Add Python support Python support was added using jython. JNR version was forced to the jruby version to avoid this issue: https://github.com/jruby/jruby/issues/5334 --- build.gradle | 3 + .../java/com/rivescript/ObjectIT.java | 6 +- .../java/com/rivescript/PythonObjectIT.java | 83 +++++++++++++++++++ .../rivescript/lang/python/PythonHandler.java | 20 +++++ .../rivescript/lang/python/package-info.java | 26 ++++++ .../java/com/rivescript/parser/Parser.java | 6 +- 6 files changed, 139 insertions(+), 5 deletions(-) create mode 100644 rivescript-core/src/integration-test/java/com/rivescript/PythonObjectIT.java create mode 100644 rivescript-core/src/main/java/com/rivescript/lang/python/PythonHandler.java create mode 100644 rivescript-core/src/main/java/com/rivescript/lang/python/package-info.java diff --git a/build.gradle b/build.gradle index da324a0..946d16f 100644 --- a/build.gradle +++ b/build.gradle @@ -11,6 +11,7 @@ ext { hamcrestVersion = "1.3" junitVersion = "4.12" jrubyVersion = "9.2.7.0" + jythonVersion = "2.7.1b3" jsonVersion = "20160810" mockitoVersion = "2.28.2" slf4jVersion = "1.7.26" @@ -194,7 +195,9 @@ project("rivescript-core") { dependencies { compileOnly "org.json:json:${jsonVersion}" + integrationTestRuntime "com.github.jnr:jnr-constants:0.9.12" integrationTestRuntime "org.codehaus.groovy:groovy-all:${groovyVersion}" + integrationTestRuntime "org.python:jython:${jythonVersion}" integrationTestRuntime "org.jruby:jruby:${jrubyVersion}" } } diff --git a/rivescript-core/src/integration-test/java/com/rivescript/ObjectIT.java b/rivescript-core/src/integration-test/java/com/rivescript/ObjectIT.java index f80dcb8..ff849d7 100644 --- a/rivescript-core/src/integration-test/java/com/rivescript/ObjectIT.java +++ b/rivescript-core/src/integration-test/java/com/rivescript/ObjectIT.java @@ -20,15 +20,17 @@ * SOFTWARE. */ + + import com.rivescript.macro.ObjectHandler; import com.rivescript.util.StringUtils; import org.junit.Test; - import java.util.HashMap; import java.util.Map; import static com.rivescript.RiveScript.DEFAULT_OBJECT_NOT_FOUND_MESSAGE; + /** * @author Noah Petherbridge * @author Marcel Overdijk @@ -54,7 +56,7 @@ public void testMacroParsing() { "+ goodbye", "- goodbye" }); - assertReply("Hello", "Hello world!"); + assertReply("Hello", " Hello world!"); assertReply("goodbye", DEFAULT_OBJECT_NOT_FOUND_MESSAGE); } diff --git a/rivescript-core/src/integration-test/java/com/rivescript/PythonObjectIT.java b/rivescript-core/src/integration-test/java/com/rivescript/PythonObjectIT.java new file mode 100644 index 0000000..524950c --- /dev/null +++ b/rivescript-core/src/integration-test/java/com/rivescript/PythonObjectIT.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2016-2017 the original author or authors. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.rivescript; + +import static com.rivescript.RiveScript.DEFAULT_OBJECT_NOT_FOUND_MESSAGE; + +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +import com.rivescript.lang.python.PythonHandler; + +/** + * Integration tests for {@link PythonHandler}. + * + * @author Marcel Overdijk + */ +public class PythonObjectIT extends BaseIT { + + @BeforeClass + public static void setup() throws Exception { + System.setProperty("python.cachedir.skip", "true"); + System.setProperty("python.import.site", "false"); + } + @Before + public void setUp() { + rs = new RiveScript(); + rs.setHandler("python", new PythonHandler()); + setUp(new String[] { + "> object reverse python", + " msg = ' '.join(args)", + " return msg[::-1]", + "< object", + "> object setname python", + " username = rs.currentUser()", + " rs.setUservar(username, 'name', args[0])", + "< object", + "+ reverse *", + "- reverse ", + "+ my name is *", + "- I will remember that.setname \"\"", + "+ what is my name", + "- You are ." + }); + } + + @Test + public void testReverse() { + assertReply("reverse hello world", "dlrow olleh"); + } + + @Test + public void testSetName() { + assertReply("my name is john doe", "I will remember that."); + assertReply("what is my name", "You are John Doe."); + } + + @Test + public void testNoRubyHandler() { + rs.removeHandler("python"); + assertReply("reverse hello world", DEFAULT_OBJECT_NOT_FOUND_MESSAGE); + } +} diff --git a/rivescript-core/src/main/java/com/rivescript/lang/python/PythonHandler.java b/rivescript-core/src/main/java/com/rivescript/lang/python/PythonHandler.java new file mode 100644 index 0000000..4fbc88b --- /dev/null +++ b/rivescript-core/src/main/java/com/rivescript/lang/python/PythonHandler.java @@ -0,0 +1,20 @@ +package com.rivescript.lang.python; + +import com.rivescript.lang.jsr223.Jsr223ScriptingHandler; +import com.rivescript.macro.ObjectHandler; + +public class PythonHandler extends Jsr223ScriptingHandler { + + /** + * Constructs a Python {@link ObjectHandler}. + */ + public PythonHandler() { + super("python", "" + + "def %s(rs, args):\n" + + "%s\n" + + ""); + System.setProperty("python.cachedir.skip", "true"); + System.setProperty("python.import.site", "false"); + } + +} diff --git a/rivescript-core/src/main/java/com/rivescript/lang/python/package-info.java b/rivescript-core/src/main/java/com/rivescript/lang/python/package-info.java new file mode 100644 index 0000000..cb2f63c --- /dev/null +++ b/rivescript-core/src/main/java/com/rivescript/lang/python/package-info.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2016-2017 the original author or authors. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/** + * Provides Python programming language support classes. + */ +package com.rivescript.lang.python; diff --git a/rivescript-core/src/main/java/com/rivescript/parser/Parser.java b/rivescript-core/src/main/java/com/rivescript/parser/Parser.java index 37c49f5..8954414 100644 --- a/rivescript-core/src/main/java/com/rivescript/parser/Parser.java +++ b/rivescript-core/src/main/java/com/rivescript/parser/Parser.java @@ -125,10 +125,10 @@ public Root parse(String filename, String[] code) throws ParserException { lineno = lp + 1; // Strip the line. - String line = code[lp].trim(); - if (line.length() == 0) { + if (code[lp].trim().length() == 0) { continue; // Skip blank lines! } + String line = code[lp]; // Are we inside an `> object`? if (inObject) { @@ -150,7 +150,7 @@ public Root parse(String filename, String[] code) throws ParserException { } continue; } - + line = line.trim(); // Look for comments. if (line.startsWith("//")) { continue; // Single line comment.