diff --git a/src/main/java/io/klerch/alexa/tellask/model/wrapper/AlexaSpeechletResponse.java b/src/main/java/io/klerch/alexa/tellask/model/wrapper/AlexaSpeechletResponse.java
index b9bf238..a09e712 100644
--- a/src/main/java/io/klerch/alexa/tellask/model/wrapper/AlexaSpeechletResponse.java
+++ b/src/main/java/io/klerch/alexa/tellask/model/wrapper/AlexaSpeechletResponse.java
@@ -18,15 +18,10 @@
import io.klerch.alexa.tellask.model.AlexaOutputSlot;
import io.klerch.alexa.tellask.schema.UtteranceReader;
import io.klerch.alexa.tellask.util.resource.YamlReader;
-import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.apache.log4j.Logger;
import java.io.IOException;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Optional;
-import java.util.Random;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -145,11 +140,11 @@ public Reprompt getReprompt() {
private String resolveSlotsInUtterance(final String utterance) {
final StringBuffer buffer = new StringBuffer();
// extract all the placeholders found in the utterance
- final Matcher slots = Pattern.compile("\\{(.*?)\\}").matcher(utterance);
+ final Matcher slotsInUtterance = Pattern.compile("\\{(.*?)\\}").matcher(utterance);
// for any of the placeholders ...
- while (slots.find()) {
+ while (slotsInUtterance.find()) {
// ... placeholder-name is the slotName to look after in two places of the output
- final String slotName = slots.group(1);
+ final String slotName = slotsInUtterance.group(1);
final AlexaOutputSlot outputSlot = output
// prefer directly set output slots
.getSlots().stream()
@@ -157,18 +152,24 @@ private String resolveSlotsInUtterance(final String utterance) {
.filter(slot -> slot.getName().equals(slotName))
.findFirst()
// if not directly applied look in provided models for AlexaSlotSave fields
- .orElse(output.getModels()
- .stream()
- // for those having that AlexaSlotSave field
- .filter(model -> model.hasOutputSlot(slotName))
- // create a AlexaOutputSlot from attributes in annotation + the field value itself
- .map(model -> model.getOutputSlot(slotName).orElse(null))
- .findFirst().orElse(null));
+ .orElse(getSavedSlot(slotName));
Validate.notNull(outputSlot, "Could not replace placeholder with name {" + slotName + "} because no corresponding slot was set in the output.");
- slots.appendReplacement(buffer, outputSlot.getSsml());
+ // RJH - FEB 2017 - Matcher.quoteReplacement on slot input to fix bug
+ // ~ https://github.com/KayLerch/alexa-skills-kit-tellask-java/issues/1
+ slotsInUtterance.appendReplacement(buffer, Matcher.quoteReplacement(outputSlot.getSsml()));
}
- slots.appendTail(buffer);
+ slotsInUtterance.appendTail(buffer);
return "" + buffer.toString() + "";
}
+
+ private AlexaOutputSlot getSavedSlot(String slotName) {
+ return output.getModels()
+ .stream()
+ // for those having that AlexaSlotSave field
+ .filter(model -> model.hasOutputSlot(slotName))
+ // create a AlexaOutputSlot from attributes in annotation + the field value itself
+ .map(model -> model.getOutputSlot(slotName).orElse(null))
+ .findFirst().orElse(null);
+ }
}
diff --git a/src/test/java/io/klerch/alexa/tellask/model/wrapper/AlexaSpeechletResponseTest.java b/src/test/java/io/klerch/alexa/tellask/model/wrapper/AlexaSpeechletResponseTest.java
index f8942af..db6835d 100644
--- a/src/test/java/io/klerch/alexa/tellask/model/wrapper/AlexaSpeechletResponseTest.java
+++ b/src/test/java/io/klerch/alexa/tellask/model/wrapper/AlexaSpeechletResponseTest.java
@@ -64,6 +64,24 @@ public void getResponseWithSlots() throws Exception {
((SsmlOutputSpeech)response.getOutputSpeech()).getSsml());
Assert.assertNull(response.getReprompt());
}
+ // RJH FEB 2017 - added test for issue:
+ // ~ https://github.com/KayLerch/alexa-skills-kit-tellask-java/issues/1
+ @Test
+ public void getResponseWithSlotsMatcherQuoteReplacement() throws Exception {
+ final AlexaStateModelSample model = new AlexaStateModelSample();
+ model.setName("Paul");
+
+ final AlexaOutput output = AlexaOutput
+ .ask("IntentWithOneSlotReplacement")
+ .putSlot("theSlot", "$5.00")
+ .putState(model).build();
+
+ final AlexaSpeechletResponse response = new AlexaSpeechletResponse(output, new ResourceUtteranceReader(), "en-US");
+ Assert.assertEquals(output, response.getOutput());
+ Assert.assertEquals("This is a single slot replacement: $5.00",
+ ((SsmlOutputSpeech)response.getOutputSpeech()).getSsml());
+ Assert.assertNull(response.getReprompt());
+ }
@Test
public void getResponseWithReprompt() throws Exception {
diff --git a/src/test/resources/en-US/utterances.yml b/src/test/resources/en-US/utterances.yml
index 1c9543f..54b92e0 100644
--- a/src/test/resources/en-US/utterances.yml
+++ b/src/test/resources/en-US/utterances.yml
@@ -43,6 +43,10 @@ IntentWithOneUtteranceAndOneReprompt:
Reprompts:
- "This is a reprompt {name} with your score of {credits}"
+IntentWithOneSlotReplacement:
+ Utterances:
+ - "This is a single slot replacement: {theSlot}"
+
IntentWithInstantUtterance:
- "Hello there {name}. Your current score is {credits} This is awesome"
- "Welcome {name}. You got a score of {credits} You are awesome"