Title: [1213] trunk/core/jbehave-core/src/java/org/jbehave/scenario/steps: JBEHAVE-173: Paired with Paul to implement usage of named parameters for step methods.

Diff

Modified: trunk/core/examples/trader/src/main/java/org/jbehave/examples/trader/scenarios/TraderSteps.java (1212 => 1213)

--- trunk/core/examples/trader/src/main/java/org/jbehave/examples/trader/scenarios/TraderSteps.java	2009-08-27 16:46:48 UTC (rev 1212)
+++ trunk/core/examples/trader/src/main/java/org/jbehave/examples/trader/scenarios/TraderSteps.java	2009-08-28 14:57:15 UTC (rev 1213)
@@ -13,6 +13,7 @@
 import org.jbehave.scenario.annotations.Alias;
 import org.jbehave.scenario.annotations.Aliases;
 import org.jbehave.scenario.annotations.Given;
+import org.jbehave.scenario.annotations.Named;
 import org.jbehave.scenario.annotations.Then;
 import org.jbehave.scenario.annotations.When;
 import org.jbehave.scenario.parser.PrefixCapturingPatternBuilder;
@@ -44,7 +45,8 @@
     }
 
     @Given("a stock of prices %prices and a threshold of %threshold")
-    public void aStockOfPrice(List<Double> prices, double threshold) {
+    // Parameters are in reverse order to prove one of the features of @Named annotation 
+    public void aStockOfPrice(@Named("threshold") double threshold, @Named("prices") List<Double> prices) {
         stock = new Stock(prices, threshold);
     }
 

Modified: trunk/core/jbehave-core/src/behaviour/org/jbehave/scenario/parser/PrefixCapturingPatternBuilderBehaviour.java (1212 => 1213)

--- trunk/core/jbehave-core/src/behaviour/org/jbehave/scenario/parser/PrefixCapturingPatternBuilderBehaviour.java	2009-08-27 16:46:48 UTC (rev 1212)
+++ trunk/core/jbehave-core/src/behaviour/org/jbehave/scenario/parser/PrefixCapturingPatternBuilderBehaviour.java	2009-08-28 14:57:15 UTC (rev 1213)
@@ -68,8 +68,16 @@
                 "The grid looks like  .");
         ensureThat(matched.matches());
         ensureThat(matched.group(1), equalTo(
-                "."));
-        
+                "."));        
     }
+    
+    @Test
+    public void shouldExtractParameterNamesFromStepPattern(){
+    	StepPatternBuilder builder = new PrefixCapturingPatternBuilder();
+        String[] names  = builder.extractParameterNames("The grid $name looks like $grid");
+        ensureThat(names.length, equalTo(2));
+        ensureThat(names[0], equalTo("name"));
+        ensureThat(names[1], equalTo("grid"));
+    }
 
 }

Modified: trunk/core/jbehave-core/src/behaviour/org/jbehave/scenario/steps/CandidateStepBehaviour.java (1212 => 1213)

--- trunk/core/jbehave-core/src/behaviour/org/jbehave/scenario/steps/CandidateStepBehaviour.java	2009-08-27 16:46:48 UTC (rev 1212)
+++ trunk/core/jbehave-core/src/behaviour/org/jbehave/scenario/steps/CandidateStepBehaviour.java	2009-08-28 14:57:15 UTC (rev 1213)
@@ -7,8 +7,14 @@
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 
+import java.beans.BeanInfo;
+import java.beans.IntrospectionException;
+import java.beans.Introspector;
+import java.beans.MethodDescriptor;
+import java.lang.reflect.Method;
 import java.util.List;
 
+import org.jbehave.scenario.annotations.Named;
 import org.jbehave.scenario.parser.PrefixCapturingPatternBuilder;
 import org.jbehave.scenario.parser.StepPatternBuilder;
 import org.jbehave.scenario.reporters.ScenarioReporter;
@@ -136,4 +142,45 @@
         candidateStep.createFrom("When windows on the 1,2,3 floors").perform();
         ensureThat(((List<?>) someSteps.args).toString(), equalTo(asList("1", "2", "3").toString()));
     }
+    
+    @Test
+    public void shouldMatchMethodParametersByAnnotatedNames() throws Exception {
+    	NamedParameterSteps steps = new NamedParameterSteps();
+        CandidateStep candidateStep = new CandidateStep("I live on the $ith floor but some call it the $nth",
+        		NamedParameterSteps.methodFor("methodWithNamedParametersInOrder"), steps, PATTERN_BUILDER, MONITOR, new ParameterConverters(), "Given", "When", "Then");
+        candidateStep.createFrom("When I live on the first floor but some call it the ground").perform();
+        ensureThat(steps.ith, equalTo("first"));
+        ensureThat(steps.nth, equalTo("ground"));
+        candidateStep = new CandidateStep("I live on the $ith floor but some call it the $nth",
+        		NamedParameterSteps.methodFor("methodWithNamedParametersInInverseOrder"), steps, PATTERN_BUILDER, MONITOR, new ParameterConverters(), "Given", "When", "Then");
+        candidateStep.createFrom("When I live on the first floor but some call it the ground").perform();
+        ensureThat(steps.ith, equalTo("first"));
+        ensureThat(steps.nth, equalTo("ground"));
+    }
+    
+    public static class NamedParameterSteps extends Steps {
+    	String ith;
+        String nth;
+
+        public void methodWithNamedParametersInOrder(@Named("ith") String ithName, @Named("nth") String nthName){
+    		this.ith = ithName;    	
+    		this.nth = nthName;
+        }
+        
+        public void methodWithNamedParametersInInverseOrder(@Named("nth") String nthName, @Named("ith") String ithName){
+    		this.ith = ithName;    	
+    		this.nth = nthName;
+        }
+
+        public static Method methodFor(String methodName) throws IntrospectionException {
+            BeanInfo beanInfo = Introspector.getBeanInfo(NamedParameterSteps.class);
+            for (MethodDescriptor md : beanInfo.getMethodDescriptors()) {
+                if (md.getMethod().getName().equals(methodName)) {
+                    return md.getMethod();
+                }
+            }
+            return null;
+        }
+    }
+    
 }

Added: trunk/core/jbehave-core/src/java/org/jbehave/scenario/annotations/Named.java (0 => 1213)

--- trunk/core/jbehave-core/src/java/org/jbehave/scenario/annotations/Named.java	                        (rev 0)
+++ trunk/core/jbehave-core/src/java/org/jbehave/scenario/annotations/Named.java	2009-08-28 14:57:15 UTC (rev 1213)
@@ -0,0 +1,14 @@
+package org.jbehave.scenario.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+...@retention(RetentionPolicy.RUNTIME)
+...@target(ElementType.PARAMETER)
+public @interface Named {
+
+    String value();
+
+}
\ No newline at end of file

Modified: trunk/core/jbehave-core/src/java/org/jbehave/scenario/parser/PrefixCapturingPatternBuilder.java (1212 => 1213)

--- trunk/core/jbehave-core/src/java/org/jbehave/scenario/parser/PrefixCapturingPatternBuilder.java	2009-08-27 16:46:48 UTC (rev 1212)
+++ trunk/core/jbehave-core/src/java/org/jbehave/scenario/parser/PrefixCapturingPatternBuilder.java	2009-08-28 14:57:15 UTC (rev 1213)
@@ -14,6 +14,7 @@
  */
 public class PrefixCapturingPatternBuilder implements StepPatternBuilder {
 
+	private final String prefix;
     private final String anyWordBeginningWithThePrefix;
 
     /**
@@ -29,7 +30,8 @@
      * prefix in a matching step.
      */
     public PrefixCapturingPatternBuilder(String prefix) {
-        anyWordBeginningWithThePrefix = "(\\" + prefix + "\\w*)(\\W|\\Z)";
+        this.prefix = prefix;
+		this.anyWordBeginningWithThePrefix = "(\\" + prefix + "\\w*)(\\W|\\Z)";
     }
 
     public Pattern buildPattern(String matchThis) {
@@ -49,7 +51,7 @@
         Matcher findingAllTheDollarWords = Pattern.compile(anyWordBeginningWithThePrefix, Pattern.DOTALL).matcher(matchThisButLeaveBrackets);
         List<Replacement> replacements = new ArrayList<Replacement>();
         while(findingAllTheDollarWords.find()) {
-            replacements.add(new Replacement(findingAllTheDollarWords.start(), findingAllTheDollarWords.end(), findingAllTheDollarWords.group(2)));
+            replacements.add(new Replacement(matchThisButLeaveBrackets, findingAllTheDollarWords.start(), findingAllTheDollarWords.end(), findingAllTheDollarWords.group(2)));
         }
         return replacements;
     }
@@ -71,16 +73,27 @@
         return escapedMatch;
     }
 
-    private static class Replacement {
+    private class Replacement {
         private final int start;
         private final int end;
         private final String whitespaceIfAny;
+		private final String name;
 
-        public Replacement(int start, int end, String whitespaceIfAny) {
+        public Replacement(String pattern, int start, int end, String whitespaceIfAny) {
             this.start = start;
             this.end = end;
             this.whitespaceIfAny = whitespaceIfAny;
+            this.name = pattern.substring(start + prefix.length(), end).trim();
         }
+        
     }
 
+	public String[] extractParameterNames(String pattern) {
+		List<String> names = new ArrayList<String>();
+		for (Replacement replacement : findArgumentsToReplace(pattern)) {
+			names.add(replacement.name);
+		}
+		return names.toArray(new String[names.size()]);
+	}
+
 }

Modified: trunk/core/jbehave-core/src/java/org/jbehave/scenario/parser/StepPatternBuilder.java (1212 => 1213)

--- trunk/core/jbehave-core/src/java/org/jbehave/scenario/parser/StepPatternBuilder.java	2009-08-27 16:46:48 UTC (rev 1212)
+++ trunk/core/jbehave-core/src/java/org/jbehave/scenario/parser/StepPatternBuilder.java	2009-08-28 14:57:15 UTC (rev 1213)
@@ -23,4 +23,11 @@
      */
     Pattern buildPattern(String matchThis);
 
+    /**
+     * Extract the parameter names from a template step
+     * @param step the template step
+     * @return an array of parameter names
+     */
+	String[] extractParameterNames(String string);
+
 }

Modified: trunk/core/jbehave-core/src/java/org/jbehave/scenario/steps/CandidateStep.java (1212 => 1213)

--- trunk/core/jbehave-core/src/java/org/jbehave/scenario/steps/CandidateStep.java	2009-08-27 16:46:48 UTC (rev 1212)
+++ trunk/core/jbehave-core/src/java/org/jbehave/scenario/steps/CandidateStep.java	2009-08-28 14:57:15 UTC (rev 1213)
@@ -1,11 +1,13 @@
 package org.jbehave.scenario.steps;
 
+import java.lang.annotation.Annotation;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.lang.reflect.Type;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
+import org.jbehave.scenario.annotations.Named;
 import org.jbehave.scenario.errors.PendingError;
 import org.jbehave.scenario.parser.StepPatternBuilder;
 
@@ -24,6 +26,7 @@
     private final String[] startingWords;
     private final Pattern pattern;
     private StepMonitor stepMonitor = new SilentStepMonitor();
+	private String[] parameterNames;
 
     public CandidateStep(String stepAsString, Method method, CandidateSteps steps, StepPatternBuilder patterBuilder,
             StepMonitor stepMonitor, ParameterConverters parameterConverters, String... startingWords) {
@@ -31,14 +34,15 @@
         useStepMonitor(stepMonitor);
     }
 
-    public CandidateStep(String stepAsString, Method method, CandidateSteps steps, StepPatternBuilder patterBuilder,
+    public CandidateStep(String stepAsString, Method method, CandidateSteps steps, StepPatternBuilder patternBuilder,
             ParameterConverters parameterConverters, String... startingWords) {
         this.stepAsString = stepAsString;
         this.method = method;
         this.steps = steps;
         this.parameterConverters = parameterConverters;
         this.startingWords = startingWords;
-        this.pattern = patterBuilder.buildPattern(stepAsString);
+        this.pattern = patternBuilder.buildPattern(stepAsString);
+        this.parameterNames = patternBuilder.extractParameterNames(stepAsString);
     }
 
     public void useStepMonitor(StepMonitor stepMonitor) {
@@ -66,16 +70,53 @@
         Matcher matcher = pattern.matcher(trimStartingWord(startingWord, stepAsString));
         matcher.find();
         Type[] types = method.getGenericParameterTypes();
-        final Object[] args = new Object[matcher.groupCount()];
+        String[] annotatedParameterNames = annotatedParameterNames();
+        int groupCount = matcher.groupCount();
+		final Object[] args = new Object[groupCount];
         for (int group = 0; group < args.length; group++) {
-            String arg = matcher.group(group + 1);
+            int parameterIndex = parameterIndex(annotatedParameterNames, group);
+            int groupIndex = group + 1; // default in case parameter index is not found
+            if ( parameterIndex != -1 ){            	
+            	groupIndex = parameterIndex + 1;
+            }
+            String arg = matcher.group(groupIndex);
             Object converted = parameterConverters.convert(arg, types[group]);
             args[group] = converted;
         }
         return createStep(stepAsString, args);
     }
 
-    private String findStartingWord(final String stepAsString) {
+    private int parameterIndex(String[] annotatedNames, int group) {
+    	String name = parameterNames[group];    	
+    	for ( int index = 0; index < annotatedNames.length; index++ ){
+    		if ( name.equals(annotatedNames[index]) ){
+    			return index;
+    		}
+    	}
+    	return -1;
+	}
+
+	/**
+     * Extract annotated parameter names from the @Named parameter annotations
+     * @return An array of annotated parameter names, which <b>may</b> include <code>null</code> values
+     * for parameters that are not annotated
+     */
+    private String[] annotatedParameterNames() {
+		Annotation[][] parameterAnnotations = method.getParameterAnnotations();
+    	String[] names = new String[parameterAnnotations.length];
+        for (int x = 0; x < parameterAnnotations.length; x ++) {
+        	Annotation[] annotations = parameterAnnotations[x];        	
+        	for (int y = 0; y < annotations.length; y ++) {
+        		Annotation annotation = annotations[y];
+    			if (annotation.annotationType().isAssignableFrom(Named.class) ){
+    				names[x] = ((Named)annotation).value();
+        		}
+        	}
+        }
+		return names;
+	}
+
+	private String findStartingWord(final String stepAsString) {
         for (String word : startingWords) {
             if (stepAsString.startsWith(word)) {
                 return word;


To unsubscribe from this list please visit:

http://xircles.codehaus.org/manage_email

Reply via email to