gherkin 1.0.2-i386-mingw32 → 1.0.3-i386-mingw32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. data/.gitattributes +1 -0
  2. data/History.txt +18 -0
  3. data/README.rdoc +12 -1
  4. data/Rakefile +4 -2
  5. data/VERSION.yml +1 -1
  6. data/bin/gherkin +1 -1
  7. data/dotnet/.gitignore +13 -0
  8. data/features/feature_parser.feature +22 -2
  9. data/features/native_lexer.feature +1 -1
  10. data/features/parser_with_native_lexer.feature +1 -1
  11. data/features/step_definitions/gherkin_steps.rb +2 -6
  12. data/features/step_definitions/pretty_printer_steps.rb +2 -3
  13. data/features/steps_parser.feature +1 -1
  14. data/gherkin.gemspec +46 -18
  15. data/java/Gherkin.iml +2 -4
  16. data/java/build.xml +3 -0
  17. data/java/src/gherkin/FixJava.java +6 -3
  18. data/java/src/gherkin/I18nLexer.java +48 -0
  19. data/java/src/gherkin/Listener.java +3 -1
  20. data/java/src/gherkin/Main.java +17 -0
  21. data/java/src/gherkin/Parser.java +9 -3
  22. data/java/src/gherkin/formatter/Argument.java +39 -0
  23. data/java/src/gherkin/formatter/ArgumentFormat.java +17 -0
  24. data/java/src/gherkin/formatter/Colors.java +7 -0
  25. data/java/src/gherkin/formatter/Formatter.java +15 -0
  26. data/java/src/gherkin/formatter/PrettyFormatter.java +219 -0
  27. data/java/src/gherkin/parser/StateMachineReader.java +8 -3
  28. data/java/test/gherkin/formatter/ArgumentTest.java +17 -0
  29. data/lib/gherkin/csharp_lexer.rb +15 -0
  30. data/lib/gherkin/format/argument.rb +35 -0
  31. data/lib/gherkin/format/monochrome_format.rb +9 -0
  32. data/lib/gherkin/i18n.rb +22 -0
  33. data/lib/gherkin/i18n.yml +34 -20
  34. data/lib/gherkin/i18n_lexer.rb +57 -13
  35. data/lib/gherkin/lexer.rb +9 -18
  36. data/lib/gherkin/parser.rb +3 -3
  37. data/lib/gherkin/parser/meta.txt +5 -4
  38. data/lib/gherkin/parser/root.txt +11 -9
  39. data/lib/gherkin/parser/steps.txt +4 -3
  40. data/lib/gherkin/rb_parser.rb +13 -5
  41. data/lib/gherkin/tools/colors.rb +119 -0
  42. data/lib/gherkin/tools/files.rb +6 -1
  43. data/lib/gherkin/tools/pretty_listener.rb +115 -23
  44. data/ragel/lexer.c.rl.erb +67 -51
  45. data/ragel/lexer.csharp.rl.erb +240 -0
  46. data/ragel/lexer.java.rl.erb +27 -18
  47. data/ragel/lexer.rb.rl.erb +17 -17
  48. data/ragel/lexer_common.rl.erb +8 -8
  49. data/spec/gherkin/c_lexer_spec.rb +4 -4
  50. data/spec/gherkin/csharp_lexer_spec.rb +20 -0
  51. data/spec/gherkin/fixtures/comments_in_table.feature +9 -0
  52. data/spec/gherkin/fixtures/complex.feature +2 -0
  53. data/spec/gherkin/fixtures/dos_line_endings.feature +45 -0
  54. data/spec/gherkin/fixtures/i18n_fr.feature +1 -0
  55. data/spec/gherkin/fixtures/i18n_no.feature +1 -0
  56. data/spec/gherkin/fixtures/i18n_zh-CN.feature +1 -0
  57. data/spec/gherkin/format/argument_spec.rb +28 -0
  58. data/spec/gherkin/i18n_lexer_spec.rb +4 -4
  59. data/spec/gherkin/i18n_spec.rb +31 -23
  60. data/spec/gherkin/java_lexer_spec.rb +4 -3
  61. data/spec/gherkin/parser_spec.rb +5 -0
  62. data/spec/gherkin/rb_lexer_spec.rb +4 -2
  63. data/spec/gherkin/sexp_recorder.rb +1 -1
  64. data/spec/gherkin/shared/lexer_spec.rb +169 -60
  65. data/spec/gherkin/shared/py_string_spec.rb +6 -0
  66. data/spec/gherkin/shared/row_spec.rb +107 -0
  67. data/spec/gherkin/shared/tags_spec.rb +1 -1
  68. data/spec/gherkin/tools/colors_spec.rb +19 -0
  69. data/spec/gherkin/tools/pretty_listener_spec.rb +147 -0
  70. data/spec/spec_helper.rb +31 -7
  71. data/tasks/compile.rake +81 -7
  72. data/tasks/ragel_task.rb +6 -4
  73. data/tasks/rspec.rake +2 -2
  74. metadata +92 -31
  75. data/lib/gherkin/java_lexer.rb +0 -10
  76. data/spec/gherkin/shared/table_spec.rb +0 -97
@@ -0,0 +1,48 @@
1
+ package gherkin;
2
+
3
+ import java.util.regex.Matcher;
4
+ import java.util.regex.Pattern;
5
+
6
+ public class I18nLexer implements Lexer {
7
+ private static final Pattern LANGUAGE_PATTERN = Pattern.compile("language\\s*:\\s*(.*)");
8
+ private final Listener listener;
9
+ private String i18nLanguage;
10
+
11
+ public I18nLexer(Listener listener) {
12
+ this.listener = listener;
13
+ }
14
+
15
+ /**
16
+ * @return the i18n language code from the previous scanned source.
17
+ */
18
+ public String getI18nLanguage() {
19
+ return i18nLanguage;
20
+ }
21
+
22
+ public void scan(CharSequence source) {
23
+ createDelegate(source).scan(source);
24
+ }
25
+
26
+ private Lexer createDelegate(CharSequence source) {
27
+ i18nLanguage = lang(source);
28
+ String i18nLanguage = this.i18nLanguage.replaceAll("[\\s-]", "").toLowerCase();
29
+ String i18nLexerClassName = i18nLanguage.substring(0,1).toUpperCase() + i18nLanguage.substring(1);
30
+ String qualifiedI18nLexerClassName = "gherkin.lexer." + i18nLexerClassName;
31
+ try {
32
+ Class<?> delegateClass = Class.forName(qualifiedI18nLexerClassName);
33
+ return (Lexer) delegateClass.getConstructor(Listener.class).newInstance(listener);
34
+ } catch (Exception e) {
35
+ throw new RuntimeException("Couldn't load lexer class: " + qualifiedI18nLexerClassName, e);
36
+ }
37
+ }
38
+
39
+ private String lang(CharSequence source) {
40
+ String lineOne = source.toString().split("\\n")[0];
41
+ Matcher matcher = LANGUAGE_PATTERN.matcher(lineOne);
42
+ if(matcher.find()) {
43
+ return matcher.group(1);
44
+ } else {
45
+ return "en";
46
+ }
47
+ }
48
+ }
@@ -19,9 +19,11 @@ public interface Listener {
19
19
 
20
20
  void step(String keyword, String name, int line);
21
21
 
22
- void table(List<List<String>> rows, int line);
22
+ void row(List<String> row, int line);
23
23
 
24
24
  void py_string(String string, int line);
25
25
 
26
+ void eof();
27
+
26
28
  void syntax_error(String state, String event, List<String> legalEvents, int line);
27
29
  }
@@ -0,0 +1,17 @@
1
+ package gherkin;
2
+
3
+ import gherkin.formatter.PrettyFormatter;
4
+
5
+ import java.io.FileReader;
6
+ import java.io.IOException;
7
+
8
+ public class Main {
9
+ public static void main(String[] args) throws IOException {
10
+ Parser p = new Parser(new PrettyFormatter(System.out, true));
11
+ Lexer l = new I18nLexer(p);
12
+
13
+ CharSequence input = FixJava.readReader(new FileReader(args[0]));
14
+ l.scan(input);
15
+ }
16
+
17
+ }
@@ -79,11 +79,16 @@ public class Parser implements Listener {
79
79
  listener.comment(content, line);
80
80
  }
81
81
 
82
- public void table(List<List<String>> rows, int line) {
83
- if (event("table", line))
84
- listener.table(rows, line);
82
+ public void row(List<String> row, int line) {
83
+ if (event("row", line))
84
+ listener.row(row, line);
85
85
  }
86
86
 
87
+ public void eof() {
88
+ if (event("eof", 1))
89
+ listener.eof();
90
+ }
91
+
87
92
  public void syntax_error(String name, String event, List<String> strings, int line) {
88
93
  }
89
94
 
@@ -154,6 +159,7 @@ public class Parser implements Listener {
154
159
  }
155
160
  }
156
161
  Collections.sort(result);
162
+ result.remove("eof");
157
163
  return result;
158
164
  }
159
165
 
@@ -0,0 +1,39 @@
1
+ package gherkin.formatter;
2
+
3
+ import java.io.UnsupportedEncodingException;
4
+ import java.util.List;
5
+
6
+ public class Argument {
7
+ private final int byteOffset;
8
+ private final byte[] val;
9
+
10
+ public Argument(int byteOffset, String val) throws UnsupportedEncodingException {
11
+ this.byteOffset = byteOffset;
12
+ this.val = val.getBytes("UTF-8");
13
+ }
14
+
15
+ public static String format(String string, ArgumentFormat format, List<Argument> arguments) throws UnsupportedEncodingException {
16
+ return format(string, format, (Argument[]) arguments.toArray(new Argument[arguments.size()]));
17
+ }
18
+
19
+ public static String format(String string, ArgumentFormat format, Argument... arguments) throws UnsupportedEncodingException {
20
+ byte[] result = string.getBytes("UTF-8");
21
+ int offset = 0, pastOffset = 0;
22
+ for (Argument argument : arguments) {
23
+ if (argument.byteOffset != -1 && argument.byteOffset >= pastOffset) {
24
+ byte[] replacement = format.formatArgument(argument.val);
25
+ int delta = replacement.length - argument.val.length;
26
+ byte[] newResult = new byte[result.length + delta];
27
+
28
+ System.arraycopy(result, 0, newResult, 0, argument.byteOffset+offset);
29
+ System.arraycopy(replacement, 0, newResult, argument.byteOffset+offset, replacement.length);
30
+ int n = argument.byteOffset + argument.val.length + offset;
31
+ System.arraycopy(result, n, newResult, argument.byteOffset + replacement.length, result.length - n);
32
+
33
+ offset += delta;
34
+ result = newResult;
35
+ }
36
+ }
37
+ return new String(result, "UTF-8");
38
+ }
39
+ }
@@ -0,0 +1,17 @@
1
+ package gherkin.formatter;
2
+
3
+ import java.io.UnsupportedEncodingException;
4
+
5
+ public class ArgumentFormat {
6
+ private final String prefix;
7
+ private final String suffix;
8
+
9
+ public ArgumentFormat(String prefix, String suffix) {
10
+ this.prefix = prefix;
11
+ this.suffix = suffix;
12
+ }
13
+
14
+ public byte[] formatArgument(byte[] argument) throws UnsupportedEncodingException {
15
+ return (prefix + new String(argument, "UTF-8") + suffix).getBytes("UTF-8");
16
+ }
17
+ }
@@ -0,0 +1,7 @@
1
+ package gherkin.formatter;
2
+
3
+ public class Colors {
4
+ public static String comments(String s, boolean monochrome) {
5
+ return s;
6
+ }
7
+ }
@@ -0,0 +1,15 @@
1
+ package gherkin.formatter;
2
+
3
+ import gherkin.Listener;
4
+
5
+ import java.util.List;
6
+
7
+ /**
8
+ * This interface extends the Listener interface with extra methods for formatting
9
+ * Gherkin features during execution.
10
+ */
11
+ public interface Formatter extends Listener {
12
+ void scenario(String keyword, String name, int line, String location);
13
+ void step(String keyword, String name, int line, String status, List<Argument> arguments, String location);
14
+ void flushTable();
15
+ }
@@ -0,0 +1,219 @@
1
+ package gherkin.formatter;
2
+
3
+ import java.io.OutputStream;
4
+ import java.io.PrintWriter;
5
+ import java.util.ArrayList;
6
+ import java.util.Collections;
7
+ import java.util.List;
8
+ import java.util.regex.Pattern;
9
+
10
+ import static gherkin.FixJava.join;
11
+ import static gherkin.formatter.Colors.*;
12
+
13
+ public class PrettyFormatter implements Formatter {
14
+ private final PrintWriter out;
15
+ private final boolean monochrome;
16
+ private int maxStepLength = 0;
17
+ private int[] stepLengths;
18
+ private int stepIndex;
19
+ private List<List<String>> rows;
20
+ private List<String> comments;
21
+ private List<String> tags;
22
+
23
+ public PrettyFormatter(OutputStream out, boolean monochrome) {
24
+ this.out = new PrintWriter(out);
25
+ this.monochrome = monochrome;
26
+ }
27
+
28
+ public void tag(String name, int line) {
29
+ if (tags == null) tags = new ArrayList<String>();
30
+ tags.add('@' + name);
31
+ }
32
+
33
+ public void comment(String content, int line) {
34
+ if (comments == null) comments = new ArrayList<String>();
35
+ comments.add(content);
36
+ }
37
+
38
+ public void feature(String keyword, String name, int line) {
39
+ printCommentsAndTags("");
40
+ out.println(keyword + ": " + indent(name, " "));
41
+ out.flush();
42
+ }
43
+
44
+ public void background(String keyword, String name, int line) {
45
+ out.println();
46
+ printCommentsAndTags(" ");
47
+ out.println(" " + keyword + ": " + name);
48
+ }
49
+
50
+ public void scenario(String keyword, String name, int line) {
51
+ scenario(keyword, name, line, null);
52
+ }
53
+
54
+ public void scenario(String keyword, String name, int line, String location) {
55
+ flushTable();
56
+ out.println();
57
+ printCommentsAndTags(" ");
58
+ out.println(" " + keyword + ": " + indent(name, " ") + indentedScenarioLocation(keyword, name, location));
59
+ out.flush();
60
+ }
61
+
62
+ public void scenario_outline(String keyword, String name, int line) {
63
+ flushTable();
64
+ out.println();
65
+ printCommentsAndTags(" ");
66
+ out.println(" " + keyword + ": " + name);
67
+ }
68
+
69
+ public void examples(String keyword, String name, int line) {
70
+ flushTable();
71
+ out.println();
72
+ printCommentsAndTags(" ");
73
+ out.println(" " + keyword + ": " + name);
74
+ }
75
+
76
+ public void step(String keyword, String name, int line, String status, List<Argument> arguments, String location) {
77
+ flushTable();
78
+ out.println(" " + keyword + indent(name, " ") + indentedStepLocation(location));
79
+ out.flush();
80
+ }
81
+
82
+ public void flushTable() {
83
+ if (rows == null) return;
84
+ int columnCount = rows.get(0).size();
85
+ int[][] cellLengths = new int[rows.size()][columnCount];
86
+ int[] maxLengths = new int[columnCount];
87
+ for (int i = 0; i < rows.size(); i++) {
88
+ for (int j = 0; j < columnCount; j++) {
89
+ int length = rows.get(i).get(j).length();
90
+ cellLengths[i][j] = length;
91
+ maxLengths[j] = Math.max(maxLengths[j], length);
92
+ }
93
+ }
94
+
95
+ for (int i = 0; i < rows.size(); i++) {
96
+ out.write(" | ");
97
+ for (int j = 0; j < columnCount; j++) {
98
+ out.write(rows.get(i).get(j));
99
+ padSpace(maxLengths[j] - cellLengths[i][j]);
100
+ if (j < columnCount - 1) {
101
+ out.write(" | ");
102
+ } else {
103
+ out.write(" |");
104
+ }
105
+ }
106
+ out.println();
107
+ }
108
+ out.flush();
109
+ rows = null;
110
+ }
111
+
112
+ public void step(String keyword, String name, int line) {
113
+ step(keyword, name, line, null, Collections.<Argument>emptyList(), null);
114
+ }
115
+
116
+ public void row(List<String> row, int line) {
117
+ if (rows == null) rows = new ArrayList<List<String>>();
118
+ rows.add(row);
119
+ }
120
+
121
+ public void py_string(String string, int line) {
122
+ out.println(" \"\"\"");
123
+ out.print(Pattern.compile("^", Pattern.MULTILINE).matcher(string).replaceAll(" "));
124
+ out.println("\n \"\"\"");
125
+ }
126
+
127
+ public void eof() {
128
+ flushTable();
129
+ out.flush();
130
+ }
131
+
132
+ public void syntax_error(String state, String event, List<String> legalEvents, int line) {
133
+ out.println("Syntax error:" + state + ' ' + event);
134
+ }
135
+
136
+ public void steps(List<List<String>> steps) {
137
+ stepLengths = new int[steps.size()];
138
+ int i = 0;
139
+ for (List<String> step : steps) {
140
+ int stepLength = step.get(0).length() + step.get(1).length();
141
+ stepLengths[i++] = stepLength;
142
+ maxStepLength = Math.max(maxStepLength, stepLength);
143
+ }
144
+ stepIndex = -1;
145
+ }
146
+
147
+ private void padSpace(int indent, StringBuffer buffer) {
148
+ for (int i = 0; i < indent; i++) {
149
+ buffer.append(" ");
150
+ }
151
+ }
152
+
153
+ private void padSpace(int indent) {
154
+ for (int i = 0; i < indent; i++) {
155
+ out.write(" ");
156
+ }
157
+ }
158
+
159
+ private void printCommentsAndTags(String indent) {
160
+ printComments(indent);
161
+ printTags(indent);
162
+ }
163
+
164
+ private boolean printComments(String indent) {
165
+ if (comments == null) return false;
166
+ for (String comment : comments) {
167
+ out.print(indent);
168
+ out.println(comment);
169
+ }
170
+ out.flush();
171
+ comments = null;
172
+ return true;
173
+ }
174
+
175
+ private boolean printTags(String indent) {
176
+ if (tags == null) return false;
177
+ out.print(indent);
178
+ out.println(join(tags, " "));
179
+ out.flush();
180
+ tags = null;
181
+ return true;
182
+ }
183
+
184
+ private String indent(String name, String indentation) {
185
+ String indent = "";
186
+ StringBuilder sb = new StringBuilder();
187
+ String[] lines = name.split("\\n");
188
+ for (int i = 0; i < lines.length; i++) {
189
+ sb.append(indent).append(lines[i]);
190
+ if (i < lines.length - 1) {
191
+ sb.append("\n");
192
+ }
193
+ indent = indentation;
194
+ }
195
+ return sb.toString();
196
+ }
197
+
198
+ private String indentedScenarioLocation(String keyword, String name, String location) {
199
+ if (location == null || "".equals(location)) return "";
200
+ int l = keyword.length() + name.length();
201
+ maxStepLength = Math.max(maxStepLength, l);
202
+ int indent = maxStepLength - l;
203
+
204
+ StringBuffer buffer = new StringBuffer();
205
+ padSpace(indent, buffer);
206
+ buffer.append(" ").append(comments("# " + location, monochrome));
207
+ return buffer.toString();
208
+ }
209
+
210
+ private String indentedStepLocation(String location) {
211
+ if (location == null || "".equals(location)) return "";
212
+ int indent = maxStepLength - stepLengths[stepIndex += 1];
213
+
214
+ StringBuffer buffer = new StringBuffer();
215
+ padSpace(indent, buffer);
216
+ buffer.append(" ").append(comments("# " + location, monochrome));
217
+ return buffer.toString();
218
+ }
219
+ }
@@ -7,6 +7,7 @@ import gherkin.lexer.En;
7
7
 
8
8
  import java.io.IOException;
9
9
  import java.util.List;
10
+ import java.util.ArrayList;
10
11
 
11
12
  public class StateMachineReader implements Listener {
12
13
  private final String machinePath;
@@ -17,9 +18,10 @@ public class StateMachineReader implements Listener {
17
18
  }
18
19
 
19
20
  public List<List<String>> transitionTable() {
21
+ transitionTable = new ArrayList<List<String>>();
20
22
  Lexer lexer = new En(this);
21
23
  try {
22
- lexer.scan(FixJava.readResourceAsString(machinePath));
24
+ lexer.scan(FixJava.readResource(machinePath));
23
25
  } catch (IOException e) {
24
26
  throw new RuntimeException("Fatal error. Couldn't read " + machinePath);
25
27
  }
@@ -53,10 +55,13 @@ public class StateMachineReader implements Listener {
53
55
  public void py_string(String string, int line) {
54
56
  }
55
57
 
58
+ public void eof() {
59
+ }
60
+
56
61
  public void syntax_error(String name, String event, List<String> strings, int line) {
57
62
  }
58
63
 
59
- public void table(List<List<String>> rows, int line) {
60
- transitionTable = rows;
64
+ public void row(List<String> row, int line) {
65
+ transitionTable.add(row);
61
66
  }
62
67
  }