1 | |
package org.jbehave.core.parsers; |
2 | |
|
3 | |
import java.util.ArrayList; |
4 | |
import java.util.List; |
5 | |
import java.util.regex.Matcher; |
6 | |
import java.util.regex.Pattern; |
7 | |
|
8 | |
import org.apache.commons.lang.builder.ToStringBuilder; |
9 | |
import org.apache.commons.lang.builder.ToStringStyle; |
10 | |
import org.jbehave.core.steps.StepType; |
11 | |
|
12 | |
|
13 | |
|
14 | |
|
15 | |
|
16 | |
|
17 | |
|
18 | |
|
19 | |
|
20 | |
|
21 | |
|
22 | |
|
23 | |
|
24 | |
|
25 | |
|
26 | 89 | public class RegexPrefixCapturingPatternParser implements StepPatternParser { |
27 | |
|
28 | |
|
29 | |
|
30 | |
|
31 | |
private static final String DEFAULT_PREFIX = "$"; |
32 | |
|
33 | |
|
34 | |
|
35 | |
private static final String DEFAULT_CHARACTER_CLASS = "[\\p{L}\\p{N}\\p{Pc}]"; |
36 | |
|
37 | |
private final String prefix; |
38 | |
private final String characterClass; |
39 | |
|
40 | |
|
41 | |
|
42 | |
|
43 | |
|
44 | |
public RegexPrefixCapturingPatternParser() { |
45 | 582 | this(DEFAULT_PREFIX); |
46 | 582 | } |
47 | |
|
48 | |
|
49 | |
|
50 | |
|
51 | |
|
52 | |
|
53 | |
|
54 | |
|
55 | |
public RegexPrefixCapturingPatternParser(String prefix) { |
56 | 583 | this(prefix, DEFAULT_CHARACTER_CLASS); |
57 | 583 | } |
58 | |
|
59 | |
|
60 | |
|
61 | |
|
62 | |
|
63 | |
|
64 | |
|
65 | |
|
66 | |
|
67 | |
|
68 | |
public RegexPrefixCapturingPatternParser(String prefix, |
69 | 584 | String characterClass) { |
70 | 584 | this.prefix = prefix; |
71 | 584 | this.characterClass = characterClass; |
72 | 584 | } |
73 | |
|
74 | |
public String getPrefix() { |
75 | 1 | return prefix; |
76 | |
} |
77 | |
|
78 | |
public StepMatcher parseStep(StepType stepType, String stepPattern) { |
79 | 140 | String escapingPunctuation = escapingPunctuation(stepPattern); |
80 | 140 | List<Parameter> parameters = findParameters(escapingPunctuation); |
81 | 140 | Pattern regexPattern = buildPattern(escapingPunctuation, parameters); |
82 | 140 | return new RegexStepMatcher(stepType, escapingPunctuation, regexPattern, |
83 | |
parameterNames(parameters)); |
84 | |
} |
85 | |
|
86 | |
private Pattern buildPattern(String stepPattern, List<Parameter> parameters) { |
87 | 140 | return Pattern.compile( |
88 | |
parameterCapturingRegex(stepPattern, parameters), |
89 | |
Pattern.DOTALL); |
90 | |
} |
91 | |
|
92 | |
private String[] parameterNames(List<Parameter> parameters) { |
93 | 140 | List<String> names = new ArrayList<String>(); |
94 | 140 | for (Parameter parameter : parameters) { |
95 | 89 | names.add(parameter.name); |
96 | 89 | } |
97 | 140 | return names.toArray(new String[names.size()]); |
98 | |
} |
99 | |
|
100 | |
private List<Parameter> findParameters(String pattern) { |
101 | 140 | List<Parameter> parameters = new ArrayList<Parameter>(); |
102 | 140 | Matcher findingAllParameterNames = findingAllParameterNames().matcher( |
103 | |
pattern); |
104 | 229 | while (findingAllParameterNames.find()) { |
105 | 89 | parameters.add(new Parameter(pattern, findingAllParameterNames |
106 | |
.start(), findingAllParameterNames.end(), |
107 | |
findingAllParameterNames.group(2))); |
108 | |
} |
109 | 140 | return parameters; |
110 | |
} |
111 | |
|
112 | |
private Pattern findingAllParameterNames() { |
113 | 140 | return Pattern.compile("(\\" + prefix + characterClass + "*)(\\W|\\Z)", |
114 | |
Pattern.DOTALL); |
115 | |
} |
116 | |
|
117 | |
private String escapingPunctuation(String pattern) { |
118 | 140 | return pattern.replaceAll("([\\[\\]\\{\\}\\?\\^\\.\\*\\(\\)\\+\\\\])", |
119 | |
"\\\\$1"); |
120 | |
} |
121 | |
|
122 | |
private String ignoringWhitespace(String pattern) { |
123 | 140 | return pattern.replaceAll("\\s+", "\\\\s+"); |
124 | |
} |
125 | |
|
126 | |
private String parameterCapturingRegex(String stepPattern, |
127 | |
List<Parameter> parameters) { |
128 | 140 | String regex = stepPattern; |
129 | 140 | String capture = "(.*)"; |
130 | 229 | for (int i = parameters.size(); i > 0; i--) { |
131 | 89 | Parameter parameter = parameters.get(i - 1); |
132 | 89 | String start = regex.substring(0, parameter.start); |
133 | 89 | String end = regex.substring(parameter.end); |
134 | 89 | String whitespaceIfAny = parameter.whitespaceIfAny; |
135 | 89 | regex = start + capture + whitespaceIfAny + end; |
136 | |
} |
137 | 140 | return ignoringWhitespace(regex); |
138 | |
} |
139 | |
|
140 | 356 | private class Parameter { |
141 | |
private final int start; |
142 | |
private final int end; |
143 | |
private final String whitespaceIfAny; |
144 | |
private final String name; |
145 | |
|
146 | |
public Parameter(String pattern, int start, int end, |
147 | 89 | String whitespaceIfAny) { |
148 | 89 | this.start = start; |
149 | 89 | this.end = end; |
150 | 89 | this.whitespaceIfAny = whitespaceIfAny; |
151 | 89 | this.name = pattern.substring(start + prefix.length(), |
152 | |
end - whitespaceIfAny.length()).trim(); |
153 | 89 | } |
154 | |
|
155 | |
@Override |
156 | |
public String toString() { |
157 | 0 | return name; |
158 | |
} |
159 | |
} |
160 | |
|
161 | |
@Override |
162 | |
public String toString() { |
163 | 1 | return ToStringBuilder.reflectionToString(this, |
164 | |
ToStringStyle.SHORT_PREFIX_STYLE); |
165 | |
} |
166 | |
} |