From 9ace84144147816a9ea3c8e7e80b4164e1e38dc5 Mon Sep 17 00:00:00 2001 From: Lukas Degener Date: Wed, 5 Mar 2014 16:15:11 +0100 Subject: [PATCH] Add i18n support (close #156) Also closes #34, closes #109 and closes #116. Squashed commit of the following: commit 8a6b2cfc6fbc32780dc94b17cb62285ee442bc8b Author: Julien Biezemans Date: Wed Mar 5 16:11:41 2014 +0100 Bump TCK commit 1a3c684d2d737d9dfff4cf6d95b923911f520ad0 Merge: 0beabd4 98a2725 Author: Julien Biezemans Date: Wed Mar 5 16:05:11 2014 +0100 Merge branch 'master' into i18n commit 0beabd409eb35c257d1eef24b5c49bfb7d071dde Author: Lukas Degener Date: Tue Sep 10 21:41:34 2013 +0200 more flexible regexp for detecting language commit b10728638c93ba7ef86f0d02b4a43a6ad52fc0db Author: Brian Clozel Date: Wed Mar 20 18:26:40 2013 +0100 update specs for i18n support commit 6fa8f93466da4535937ebbcd56a2d0a9e84874a9 Author: Brian Clozel Date: Wed Mar 20 18:25:04 2013 +0100 used a modified patch made by @vslinko - see #109 --- features/cucumber-tck | 2 +- lib/cucumber/parser.js | 16 +++++++++---- spec/cucumber/parser_spec.js | 45 +++++++++++++++++++++++++++--------- 3 files changed, 47 insertions(+), 16 deletions(-) diff --git a/features/cucumber-tck b/features/cucumber-tck index 7ea91477e..05b4fbced 160000 --- a/features/cucumber-tck +++ b/features/cucumber-tck @@ -1 +1 @@ -Subproject commit 7ea91477edd14180ded92f7699d09689227644cd +Subproject commit 05b4fbced93245f30393a21a21dd7b23472816f1 diff --git a/lib/cucumber/parser.js b/lib/cucumber/parser.js index 5edf99877..c748539a1 100644 --- a/lib/cucumber/parser.js +++ b/lib/cucumber/parser.js @@ -1,6 +1,5 @@ var Parser = function(featureSources, astFilter) { var Gherkin = require('gherkin'); - var GherkinLexer = require('gherkin/lib/gherkin/lexer/en'); var Cucumber = require('../cucumber'); var features = Cucumber.Ast.Features(); @@ -9,13 +8,22 @@ var Parser = function(featureSources, astFilter) { var self = { parse: function parse() { - var eventHandler = self.getEventHandlers(); - var lexer = new GherkinLexer(self.getEventHandlers()); + var lexers = {}; + var lexer = function (lang) { + if (!(lang in lexers)) { + lexers[lang] = new (Gherkin.Lexer(lang))(self.getEventHandlers()); + } + + return lexers[lang]; + }; + for (i in featureSources) { var currentSourceUri = featureSources[i][Parser.FEATURE_NAME_SOURCE_PAIR_URI_INDEX]; var featureSource = featureSources[i][Parser.FEATURE_NAME_SOURCE_PAIR_SOURCE_INDEX]; self.setCurrentSourceUri(currentSourceUri); - lexer.scan(featureSource); + var languageMatch = /^\s*#\s*language:\s*([a-z_]*)/.exec(featureSource.toString()); + var language = languageMatch == null ? 'en' : languageMatch[1]; + lexer(language).scan(featureSource); } return features; }, diff --git a/spec/cucumber/parser_spec.js b/spec/cucumber/parser_spec.js index 655287e62..e5fa88a45 100644 --- a/spec/cucumber/parser_spec.js +++ b/spec/cucumber/parser_spec.js @@ -2,17 +2,15 @@ require('../support/spec_helper'); describe("Cucumber.Parser", function () { var Cucumber = requireLib('cucumber'); - var gherkinLexerConstructor; var parser, featureSources; var features, astFilter, astAssembler; beforeEach(function () { - gherkinLexerConstructor = spyOnModule("gherkin/lib/gherkin/lexer/en"); features = createSpy("Root 'features' AST element"); astFilter = createSpy("AST filter"); featureSources = [ - ["(feature:1)", createSpy('first feature source')], - ["(feature:2)", createSpy('second feature source')] + ["(feature:1)", createSpyWithStubs('first feature source', {toString:"first feature source"})], + ["(feature:2)", createSpyWithStubs('second feature source', {toString:"# language: fr\nsecond feature source"})] ]; astAssembler = createSpy("AST assembler"); spyOn(Cucumber.Ast, 'Features').andReturn(features); @@ -32,12 +30,25 @@ describe("Cucumber.Parser", function () { describe("parse()", function () { var Gherkin = require('gherkin'); - var gherkinLexer; + var gherkinENLexerConstructor, gherkinFRLexerConstructor, gherkinENLexer, gherkinFRLexer; var eventHandlers; beforeEach(function () { - gherkinLexer = createSpyWithStubs("English gherkin lexer instance", {scan: null}); - gherkinLexerConstructor.andReturn(gherkinLexer); + gherkinENLexer = createSpyWithStubs("English gherkin lexer instance", {scan: null}); + gherkinFRLexer = createSpyWithStubs("French gherkin lexer instance", {scan: null}); + gherkinENLexerConstructor = createSpy("English gherkin lexer constructor").andReturn(gherkinENLexer); + gherkinFRLexerConstructor = createSpy("French gherkin lexer constructor").andReturn(gherkinFRLexer); + spyOn(Gherkin, 'Lexer').andCallFake( + function(language){ + if(language == 'en') { + return gherkinENLexerConstructor; + } else if(language == 'fr') { + return gherkinFRLexerConstructor; + } else { + throw "Could not instantiate a parser for this language" + } + } + ); eventHandlers = createSpy("Parser event handlers"); spyOn(parser, 'getEventHandlers').andReturn(eventHandlers); spyOn(parser, 'setCurrentSourceUri'); @@ -50,7 +61,15 @@ describe("Cucumber.Parser", function () { it("creates a gherkin lexer for the English language", function () { parser.parse(); - expect(gherkinLexerConstructor).toHaveBeenCalledWith(eventHandlers); + expect(Gherkin.Lexer).toHaveBeenCalledWith('en'); + expect(gherkinENLexerConstructor).toHaveBeenCalledWith(eventHandlers); + }); + + + it("creates a gherkin lexer for the French language", function () { + parser.parse(); + expect(Gherkin.Lexer).toHaveBeenCalledWith('fr'); + expect(gherkinFRLexerConstructor).toHaveBeenCalledWith(eventHandlers); }); it("sets the uri of each feature source", function () { @@ -59,12 +78,16 @@ describe("Cucumber.Parser", function () { expect(parser.setCurrentSourceUri).toHaveBeenCalledWith(featureSources[1][0]); }); - it("asks the lexer to scan each feature source", function () { + it("asks the English lexer to scan the first feature source", function () { parser.parse(); - expect(gherkinLexer.scan).toHaveBeenCalledWith(featureSources[0][1]); - expect(gherkinLexer.scan).toHaveBeenCalledWith(featureSources[1][1]); + expect(gherkinENLexer.scan).toHaveBeenCalledWith(featureSources[0][1]); }); + it("asks the French lexer to scan the second feature source", function () { + parser.parse(); + expect(gherkinFRLexer.scan).toHaveBeenCalledWith(featureSources[1][1]); + }); + it("returns the features root element", function () { expect(parser.parse()).toBe(features); });