From 362907ccf20263a2738940c6c4c200f2ec692c60 Mon Sep 17 00:00:00 2001 From: Jon Nordby Date: Sat, 4 Mar 2017 19:47:00 +0100 Subject: [PATCH 01/41] README: Mention how to install/run --- README.md | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index d1cb988..c34a092 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,15 @@ # Canadianness -## Example program using noflo + +Basic example of programming with [NoFlo](https://noflojs.org). + +## Prerequisites + +You need to have [Node.js](http://nodejs.org) 4.x or newer installed. + +## Install + + npm install + +## Run tests + + npm test From d6424fdf137d84f940b3075764e26d0915ca2706 Mon Sep 17 00:00:00 2001 From: Jon Nordby Date: Sat, 4 Mar 2017 19:55:02 +0100 Subject: [PATCH 02/41] Update all NoFlo dependencies --- package.json | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index fab15fd..8cc2fb4 100644 --- a/package.json +++ b/package.json @@ -15,11 +15,11 @@ "url": "https://github.com/aretecode/canadianness.git" }, "dependencies": { - "coffee-script": "^1.10.0", + "coffee-script": "^1.12.0", "natural": "^0.4.0", - "noflo": "git+https://github.com/aretecode/noflo-built.git", - "noflo-core": "^0.1.3", - "noflo-math": "git+https://github.com/aretecode/noflo-math.git" + "noflo": "0.x >= 0.8", + "noflo-core": "^0.4.0", + "noflo-math": "^0.1.1" }, "devDependencies": { "chai": "^3.5.0", @@ -30,9 +30,9 @@ "grunt-coffeelint": "^0.0.13", "grunt-mocha-test": "^0.12.2", "mocha": "^2.5.3", - "noflo-nodejs": "^0.7.1", - "noflo-runtime-base": "^0.7.3", - "noflo-tester": "0.0.3" + "noflo-nodejs": "^0.8.1", + "noflo-runtime-base": "^0.8.2", + "noflo-tester": "^0.1.1" }, "scripts": { "start": "./node_modules/.bin/noflo-nodejs --trace --debug", From 78c2968a7ac518671e507ae4f88be0b2496708fc Mon Sep 17 00:00:00 2001 From: Jon Nordby Date: Sat, 4 Mar 2017 19:56:24 +0100 Subject: [PATCH 03/41] Travis: Only test nodejs 6 LTS --- .travis.yml | 4 +--- README.md | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 9996b8c..8062c4d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,5 @@ language: node_js sudo: false node_js: -- '0.12' -- '4.2' -- '6.2' +- '6' script: npm test diff --git a/README.md b/README.md index c34a092..610529e 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ Basic example of programming with [NoFlo](https://noflojs.org). ## Prerequisites -You need to have [Node.js](http://nodejs.org) 4.x or newer installed. +You need to have [Node.js](http://nodejs.org) 6.10 or newer installed. ## Install From a0a5795838d082c0bf7a5635392ce635225f8415 Mon Sep 17 00:00:00 2001 From: Jon Nordby Date: Sat, 4 Mar 2017 20:07:13 +0100 Subject: [PATCH 04/41] index: Split out spelling data to a JSON file --- index.coffee | 2 +- spec/Canadianness.coffee | 3 ++- spellingdata.json | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) create mode 100644 spellingdata.json diff --git a/index.coffee b/index.coffee index c6efec5..0a8c607 100755 --- a/index.coffee +++ b/index.coffee @@ -6,7 +6,7 @@ unless noflo.isBrowser() else baseDir = '/canadianness' -spellingData = [{"Canadian":["calibre"],"British":["calibre"],"American":["caliber"],"Notes":""},{"Canadian":["caliper"],"British":["caliper"],"American":["caliper","calliper"],"Notes":""},{"Canadian":["cancellation"],"British":["cancellation"],"American":["cancelation"],"Notes":""},{"Canadian":["cancelled/cancelling"],"British":["cancelled/cancelling"],"American":["canceled/canceling"],"Notes":""},{"Canadian":["candour","candor"],"British":["candour"],"American":["candor"],"Notes":""},{"Canadian":["capitalize"],"British":["capitalise","capitalize"],"American":["capitalize"],"Notes":""},{"Canadian":["caramelize"],"British":["caramelise","caramelize"],"American":["caramelize"],"Notes":""},{"Canadian":["carburetor"],"British":["carburettor"],"American":["carburetor"],"Notes":""},{"Canadian":["catalogue"],"British":["catalogue"],"American":["catalog","catalogue"],"Notes":""},{"Canadian":["catalyze"],"British":["catalyse"],"American":["catalyze"],"Notes":""},{"Canadian":["categorization"],"British":["categorisation","categorization"],"American":["categorization"],"Notes":""},{"Canadian":["categorize"],"British":["categorise","categorize"],"American":["categorize"],"Notes":""},{"Canadian":["cauldron"],"British":["cauldron"],"American":["cauldron","caldron"],"Notes":""},{"Canadian":["cauterize"],"British":["cauterise","cauterize"],"American":["cauterize"],"Notes":""},{"Canadian":["centimetre"],"British":["centimetre"],"American":["centimeter"],"Notes":""},{"Canadian":["centre"],"British":["centre"],"American":["center"],"Notes":""},{"Canadian":["cesarean","caesarian"],"British":["caesarean"],"American":["cesarean","caesarean"],"Notes":""},{"Canadian":["cesium"],"British":["caesium"],"American":["cesium"],"Notes":""},{"Canadian":["characterize"],"British":["characterise","characterize"],"American":["characterize"],"Notes":""},{"Canadian":["checkered","chequered"],"British":["chequered"],"American":["checkered"],"Notes":""},{"Canadian":["cheque"],"British":["cheque"],"American":["check"],"Notes":"noun, meaning 'form of payment'; otherwise check"},{"Canadian":["chili"],"British":["chilli","chili"],"American":["chili","chile"],"Notes":""},{"Canadian":["cigarette"],"British":["cigarette"],"American":["cigarette","cigaret"],"Notes":""},{"Canadian":["cipher"],"British":["cipher","cypher"],"American":["cipher"],"Notes":""},{"Canadian":["civilization"],"British":["civilisation","civilization"],"American":["civilization"],"Notes":""},{"Canadian":["civilize"],"British":["civilise","civilize"],"American":["civilize"],"Notes":""},{"Canadian":["clamour","clamor"],"British":["clamour"],"American":["clamor"],"Notes":""},{"Canadian":["clangour","clangor"],"British":["clangour"],"American":["clangor"],"Notes":""},{"Canadian":["co-author","coauthor"],"British":["co-author"],"American":["coauthor"],"Notes":""},{"Canadian":["colonize"],"British":["colonise","colonize"],"American":["colonize"],"Notes":""},{"Canadian":["colour"],"British":["colour"],"American":["color"],"Notes":""},{"Canadian":["commercialize"],"British":["commercialise","commercialize"],"American":["commercialize"],"Notes":""},{"Canadian":["computerize"],"British":["computerise","computerize"],"American":["computerize"],"Notes":""},{"Canadian":["connection"],"British":["connection","connexion"],"American":["connection"],"Notes":""},{"Canadian":["conjuror","conjurer"],"British":["conjuror","conjurer"],"American":["conjuror","conjurer"],"Notes":"both spellings equally acceptable"},{"Canadian":["co-opt","coopt"],"British":["co-opt"],"American":["coopt"],"Notes":""},{"Canadian":["councillor","councilor"],"British":["councillor"],"American":["councilor"],"Notes":""},{"Canadian":["counselled/counselling"],"British":["counselled/counselling"],"American":["counseled/counseling"],"Notes":""},{"Canadian":["counsellor"],"British":["counsellor"],"American":["counselor"],"Notes":""},{"Canadian":["counter-attack"],"British":["counter-attack"],"American":["counterattack"],"Notes":""},{"Canadian":["cozy","cosy"],"British":["cosy"],"American":["cozy"],"Notes":""},{"Canadian":["criticize"],"British":["criticise"],"American":["criticize"],"Notes":""},{"Canadian":["crueller/cruellest"],"British":["crueller/cruellest"],"American":["crueler/cruelest"],"Notes":""},{"Canadian":["crystalline"],"British":["crystalline"],"American":["crystaline"],"Notes":""},{"Canadian":["crystallize"],"British":["crystallise","crystallize"],"American":["crystalize","crystallize"],"Notes":""},{"Canadian":["curb"],"British":["curb","kerb"],"American":["curb"],"Notes":"kerb only used for noun meaning 'edge of road' in UK; other meanings curb"},{"Canadian":["customize"],"British":["customise","customize"],"American":["customize"],"Notes":""},{"Canadian":[""],"British":[""],"American":[""],"Notes":""},{"Canadian":["abridgement","abridgment"],"British":["abridgement"],"American":["abridgment"],"Notes":""},{"Canadian":["acknowledgement","acknowledgment"],"British":["acknowledgement"],"American":["acknowledgment","acknowledgement"],"Notes":""},{"Canadian":["advertise"],"British":["advertise"],"American":["advertise","advertize"],"Notes":""},{"Canadian":["aegis","egis"],"British":["aegis"],"American":["egis"],"Notes":""},{"Canadian":["aeon","eon"],"British":["aeon"],"American":["eon"],"Notes":""},{"Canadian":["aesthetic","esthetic"],"British":["aesthetic"],"American":["esthetic","aesthetic"],"Notes":""},{"Canadian":["aging","ageing"],"British":["ageing","aging"],"American":["aging"],"Notes":""},{"Canadian":["airplane"],"British":["aeroplane"],"American":["airplane"],"Notes":""},{"Canadian":["aluminum"],"British":["aluminium"],"American":["aluminum"],"Notes":""},{"Canadian":["amid","amidst"],"British":["amid","amidst"],"American":["amid"],"Notes":""},{"Canadian":["amoeba"],"British":["amoeba"],"American":["ameba"],"Notes":""},{"Canadian":["among","amongst"],"British":["among","amongst"],"American":["among"],"Notes":""},{"Canadian":["amortization"],"British":["amortisation","amortization"],"American":["amortization"],"Notes":""},{"Canadian":["amortize"],"British":["amortise","amortize"],"American":["amortize"],"Notes":""},{"Canadian":["amphitheatre"],"British":["amphitheatre"],"American":["amphitheater"],"Notes":""},{"Canadian":["anaesthesia","anesthesia"],"British":["anaesthesia"],"American":["anesthesia"],"Notes":""},{"Canadian":["analogue","analog"],"British":["analogue"],"American":["analogue","analog"],"Notes":"analog when used as a technical term (i.e. not digital)"},{"Canadian":["analyze","analyse"],"British":["analyse"],"American":["analyze"],"Notes":""},{"Canadian":["anemia","anaemia"],"British":["anaemia"],"American":["anemia"],"Notes":""},{"Canadian":["anemic","anaemic"],"British":["anaemic"],"American":["anemic"],"Notes":""},{"Canadian":["annex"],"British":["annexe","annex"],"American":["annex"],"Notes":"noun meaning 'something added'; verb is always annex"},{"Canadian":["apologize"],"British":["apologise","apologize"],"American":["apologize"],"Notes":""},{"Canadian":["appal","appall"],"British":["appal"],"American":["appall"],"Notes":"appalled/appalling in all countries"},{"Canadian":["appetizer"],"British":["appetiser","appetizer"],"American":["appetizer"],"Notes":""},{"Canadian":["arbour","arbor"],"British":["arbour"],"American":["arbor"],"Notes":""},{"Canadian":["archaeology","archeology"],"British":["archaeology"],"American":["archeology","archaeology"],"Notes":""},{"Canadian":["ardour","ardor"],"British":["ardour"],"American":["ardor"],"Notes":""},{"Canadian":["artifact"],"British":["artefact"],"American":["artifact"],"Notes":""},{"Canadian":["armour","armor"],"British":["armour"],"American":["armor"],"Notes":""},{"Canadian":["authorize"],"British":["authorise","authorize"],"American":["authorize"],"Notes":""},{"Canadian":["axe"],"British":["axe"],"American":["ax"],"Notes":""},{"Canadian":[""],"British":[""],"American":[""],"Notes":""}] +spellingData = require './spellingdata.json' listData = {"eh": 11, "eh!": 11} canadianness = (args, cb) -> diff --git a/spec/Canadianness.coffee b/spec/Canadianness.coffee index ee2e80a..3bfff92 100755 --- a/spec/Canadianness.coffee +++ b/spec/Canadianness.coffee @@ -8,11 +8,12 @@ unless noflo.isBrowser() else baseDir = 'canadianness' +spellingData = require '../spellingdata.json' + # how we test the components first, then the graph as a whole # because then we do not have to # figure out where along the graph the problem is describe 'Canadianness graph', -> - spellingData = [{"Canadian":["calibre"],"British":["calibre"],"American":["caliber"],"Notes":""},{"Canadian":["caliper"],"British":["caliper"],"American":["caliper","calliper"],"Notes":""},{"Canadian":["cancellation"],"British":["cancellation"],"American":["cancelation"],"Notes":""},{"Canadian":["cancelled/cancelling"],"British":["cancelled/cancelling"],"American":["canceled/canceling"],"Notes":""},{"Canadian":["candour","candor"],"British":["candour"],"American":["candor"],"Notes":""},{"Canadian":["capitalize"],"British":["capitalise","capitalize"],"American":["capitalize"],"Notes":""},{"Canadian":["caramelize"],"British":["caramelise","caramelize"],"American":["caramelize"],"Notes":""},{"Canadian":["carburetor"],"British":["carburettor"],"American":["carburetor"],"Notes":""},{"Canadian":["catalogue"],"British":["catalogue"],"American":["catalog","catalogue"],"Notes":""},{"Canadian":["catalyze"],"British":["catalyse"],"American":["catalyze"],"Notes":""},{"Canadian":["categorization"],"British":["categorisation","categorization"],"American":["categorization"],"Notes":""},{"Canadian":["categorize"],"British":["categorise","categorize"],"American":["categorize"],"Notes":""},{"Canadian":["cauldron"],"British":["cauldron"],"American":["cauldron","caldron"],"Notes":""},{"Canadian":["cauterize"],"British":["cauterise","cauterize"],"American":["cauterize"],"Notes":""},{"Canadian":["centimetre"],"British":["centimetre"],"American":["centimeter"],"Notes":""},{"Canadian":["centre"],"British":["centre"],"American":["center"],"Notes":""},{"Canadian":["cesarean","caesarian"],"British":["caesarean"],"American":["cesarean","caesarean"],"Notes":""},{"Canadian":["cesium"],"British":["caesium"],"American":["cesium"],"Notes":""},{"Canadian":["characterize"],"British":["characterise","characterize"],"American":["characterize"],"Notes":""},{"Canadian":["checkered","chequered"],"British":["chequered"],"American":["checkered"],"Notes":""},{"Canadian":["cheque"],"British":["cheque"],"American":["check"],"Notes":"noun, meaning 'form of payment'; otherwise check"},{"Canadian":["chili"],"British":["chilli","chili"],"American":["chili","chile"],"Notes":""},{"Canadian":["cigarette"],"British":["cigarette"],"American":["cigarette","cigaret"],"Notes":""},{"Canadian":["cipher"],"British":["cipher","cypher"],"American":["cipher"],"Notes":""},{"Canadian":["civilization"],"British":["civilisation","civilization"],"American":["civilization"],"Notes":""},{"Canadian":["civilize"],"British":["civilise","civilize"],"American":["civilize"],"Notes":""},{"Canadian":["clamour","clamor"],"British":["clamour"],"American":["clamor"],"Notes":""},{"Canadian":["clangour","clangor"],"British":["clangour"],"American":["clangor"],"Notes":""},{"Canadian":["co-author","coauthor"],"British":["co-author"],"American":["coauthor"],"Notes":""},{"Canadian":["colonize"],"British":["colonise","colonize"],"American":["colonize"],"Notes":""},{"Canadian":["colour"],"British":["colour"],"American":["color"],"Notes":""},{"Canadian":["commercialize"],"British":["commercialise","commercialize"],"American":["commercialize"],"Notes":""},{"Canadian":["computerize"],"British":["computerise","computerize"],"American":["computerize"],"Notes":""},{"Canadian":["connection"],"British":["connection","connexion"],"American":["connection"],"Notes":""},{"Canadian":["conjuror","conjurer"],"British":["conjuror","conjurer"],"American":["conjuror","conjurer"],"Notes":"both spellings equally acceptable"},{"Canadian":["co-opt","coopt"],"British":["co-opt"],"American":["coopt"],"Notes":""},{"Canadian":["councillor","councilor"],"British":["councillor"],"American":["councilor"],"Notes":""},{"Canadian":["counselled/counselling"],"British":["counselled/counselling"],"American":["counseled/counseling"],"Notes":""},{"Canadian":["counsellor"],"British":["counsellor"],"American":["counselor"],"Notes":""},{"Canadian":["counter-attack"],"British":["counter-attack"],"American":["counterattack"],"Notes":""},{"Canadian":["cozy","cosy"],"British":["cosy"],"American":["cozy"],"Notes":""},{"Canadian":["criticize"],"British":["criticise"],"American":["criticize"],"Notes":""},{"Canadian":["crueller/cruellest"],"British":["crueller/cruellest"],"American":["crueler/cruelest"],"Notes":""},{"Canadian":["crystalline"],"British":["crystalline"],"American":["crystaline"],"Notes":""},{"Canadian":["crystallize"],"British":["crystallise","crystallize"],"American":["crystalize","crystallize"],"Notes":""},{"Canadian":["curb"],"British":["curb","kerb"],"American":["curb"],"Notes":"kerb only used for noun meaning 'edge of road' in UK; other meanings curb"},{"Canadian":["customize"],"British":["customise","customize"],"American":["customize"],"Notes":""},{"Canadian":[""],"British":[""],"American":[""],"Notes":""},{"Canadian":["abridgement","abridgment"],"British":["abridgement"],"American":["abridgment"],"Notes":""},{"Canadian":["acknowledgement","acknowledgment"],"British":["acknowledgement"],"American":["acknowledgment","acknowledgement"],"Notes":""},{"Canadian":["advertise"],"British":["advertise"],"American":["advertise","advertize"],"Notes":""},{"Canadian":["aegis","egis"],"British":["aegis"],"American":["egis"],"Notes":""},{"Canadian":["aeon","eon"],"British":["aeon"],"American":["eon"],"Notes":""},{"Canadian":["aesthetic","esthetic"],"British":["aesthetic"],"American":["esthetic","aesthetic"],"Notes":""},{"Canadian":["aging","ageing"],"British":["ageing","aging"],"American":["aging"],"Notes":""},{"Canadian":["airplane"],"British":["aeroplane"],"American":["airplane"],"Notes":""},{"Canadian":["aluminum"],"British":["aluminium"],"American":["aluminum"],"Notes":""},{"Canadian":["amid","amidst"],"British":["amid","amidst"],"American":["amid"],"Notes":""},{"Canadian":["amoeba"],"British":["amoeba"],"American":["ameba"],"Notes":""},{"Canadian":["among","amongst"],"British":["among","amongst"],"American":["among"],"Notes":""},{"Canadian":["amortization"],"British":["amortisation","amortization"],"American":["amortization"],"Notes":""},{"Canadian":["amortize"],"British":["amortise","amortize"],"American":["amortize"],"Notes":""},{"Canadian":["amphitheatre"],"British":["amphitheatre"],"American":["amphitheater"],"Notes":""},{"Canadian":["anaesthesia","anesthesia"],"British":["anaesthesia"],"American":["anesthesia"],"Notes":""},{"Canadian":["analogue","analog"],"British":["analogue"],"American":["analogue","analog"],"Notes":"analog when used as a technical term (i.e. not digital)"},{"Canadian":["analyze","analyse"],"British":["analyse"],"American":["analyze"],"Notes":""},{"Canadian":["anemia","anaemia"],"British":["anaemia"],"American":["anemia"],"Notes":""},{"Canadian":["anemic","anaemic"],"British":["anaemic"],"American":["anemic"],"Notes":""},{"Canadian":["annex"],"British":["annexe","annex"],"American":["annex"],"Notes":"noun meaning 'something added'; verb is always annex"},{"Canadian":["apologize"],"British":["apologise","apologize"],"American":["apologize"],"Notes":""},{"Canadian":["appal","appall"],"British":["appal"],"American":["appall"],"Notes":"appalled/appalling in all countries"},{"Canadian":["appetizer"],"British":["appetiser","appetizer"],"American":["appetizer"],"Notes":""},{"Canadian":["arbour","arbor"],"British":["arbour"],"American":["arbor"],"Notes":""},{"Canadian":["archaeology","archeology"],"British":["archaeology"],"American":["archeology","archaeology"],"Notes":""},{"Canadian":["ardour","ardor"],"British":["ardour"],"American":["ardor"],"Notes":""},{"Canadian":["artifact"],"British":["artefact"],"American":["artifact"],"Notes":""},{"Canadian":["armour","armor"],"British":["armour"],"American":["armor"],"Notes":""},{"Canadian":["authorize"],"British":["authorise","authorize"],"American":["authorize"],"Notes":""},{"Canadian":["axe"],"British":["axe"],"American":["ax"],"Notes":""},{"Canadian":[""],"British":[""],"American":[""],"Notes":""}] listData = {"eh": 11, "eh!": 11} c = null diff --git a/spellingdata.json b/spellingdata.json new file mode 100644 index 0000000..08676f7 --- /dev/null +++ b/spellingdata.json @@ -0,0 +1 @@ +[{"Canadian":["calibre"],"British":["calibre"],"American":["caliber"],"Notes":""},{"Canadian":["caliper"],"British":["caliper"],"American":["caliper","calliper"],"Notes":""},{"Canadian":["cancellation"],"British":["cancellation"],"American":["cancelation"],"Notes":""},{"Canadian":["cancelled/cancelling"],"British":["cancelled/cancelling"],"American":["canceled/canceling"],"Notes":""},{"Canadian":["candour","candor"],"British":["candour"],"American":["candor"],"Notes":""},{"Canadian":["capitalize"],"British":["capitalise","capitalize"],"American":["capitalize"],"Notes":""},{"Canadian":["caramelize"],"British":["caramelise","caramelize"],"American":["caramelize"],"Notes":""},{"Canadian":["carburetor"],"British":["carburettor"],"American":["carburetor"],"Notes":""},{"Canadian":["catalogue"],"British":["catalogue"],"American":["catalog","catalogue"],"Notes":""},{"Canadian":["catalyze"],"British":["catalyse"],"American":["catalyze"],"Notes":""},{"Canadian":["categorization"],"British":["categorisation","categorization"],"American":["categorization"],"Notes":""},{"Canadian":["categorize"],"British":["categorise","categorize"],"American":["categorize"],"Notes":""},{"Canadian":["cauldron"],"British":["cauldron"],"American":["cauldron","caldron"],"Notes":""},{"Canadian":["cauterize"],"British":["cauterise","cauterize"],"American":["cauterize"],"Notes":""},{"Canadian":["centimetre"],"British":["centimetre"],"American":["centimeter"],"Notes":""},{"Canadian":["centre"],"British":["centre"],"American":["center"],"Notes":""},{"Canadian":["cesarean","caesarian"],"British":["caesarean"],"American":["cesarean","caesarean"],"Notes":""},{"Canadian":["cesium"],"British":["caesium"],"American":["cesium"],"Notes":""},{"Canadian":["characterize"],"British":["characterise","characterize"],"American":["characterize"],"Notes":""},{"Canadian":["checkered","chequered"],"British":["chequered"],"American":["checkered"],"Notes":""},{"Canadian":["cheque"],"British":["cheque"],"American":["check"],"Notes":"noun, meaning 'form of payment'; otherwise check"},{"Canadian":["chili"],"British":["chilli","chili"],"American":["chili","chile"],"Notes":""},{"Canadian":["cigarette"],"British":["cigarette"],"American":["cigarette","cigaret"],"Notes":""},{"Canadian":["cipher"],"British":["cipher","cypher"],"American":["cipher"],"Notes":""},{"Canadian":["civilization"],"British":["civilisation","civilization"],"American":["civilization"],"Notes":""},{"Canadian":["civilize"],"British":["civilise","civilize"],"American":["civilize"],"Notes":""},{"Canadian":["clamour","clamor"],"British":["clamour"],"American":["clamor"],"Notes":""},{"Canadian":["clangour","clangor"],"British":["clangour"],"American":["clangor"],"Notes":""},{"Canadian":["co-author","coauthor"],"British":["co-author"],"American":["coauthor"],"Notes":""},{"Canadian":["colonize"],"British":["colonise","colonize"],"American":["colonize"],"Notes":""},{"Canadian":["colour"],"British":["colour"],"American":["color"],"Notes":""},{"Canadian":["commercialize"],"British":["commercialise","commercialize"],"American":["commercialize"],"Notes":""},{"Canadian":["computerize"],"British":["computerise","computerize"],"American":["computerize"],"Notes":""},{"Canadian":["connection"],"British":["connection","connexion"],"American":["connection"],"Notes":""},{"Canadian":["conjuror","conjurer"],"British":["conjuror","conjurer"],"American":["conjuror","conjurer"],"Notes":"both spellings equally acceptable"},{"Canadian":["co-opt","coopt"],"British":["co-opt"],"American":["coopt"],"Notes":""},{"Canadian":["councillor","councilor"],"British":["councillor"],"American":["councilor"],"Notes":""},{"Canadian":["counselled/counselling"],"British":["counselled/counselling"],"American":["counseled/counseling"],"Notes":""},{"Canadian":["counsellor"],"British":["counsellor"],"American":["counselor"],"Notes":""},{"Canadian":["counter-attack"],"British":["counter-attack"],"American":["counterattack"],"Notes":""},{"Canadian":["cozy","cosy"],"British":["cosy"],"American":["cozy"],"Notes":""},{"Canadian":["criticize"],"British":["criticise"],"American":["criticize"],"Notes":""},{"Canadian":["crueller/cruellest"],"British":["crueller/cruellest"],"American":["crueler/cruelest"],"Notes":""},{"Canadian":["crystalline"],"British":["crystalline"],"American":["crystaline"],"Notes":""},{"Canadian":["crystallize"],"British":["crystallise","crystallize"],"American":["crystalize","crystallize"],"Notes":""},{"Canadian":["curb"],"British":["curb","kerb"],"American":["curb"],"Notes":"kerb only used for noun meaning 'edge of road' in UK; other meanings curb"},{"Canadian":["customize"],"British":["customise","customize"],"American":["customize"],"Notes":""},{"Canadian":[""],"British":[""],"American":[""],"Notes":""},{"Canadian":["abridgement","abridgment"],"British":["abridgement"],"American":["abridgment"],"Notes":""},{"Canadian":["acknowledgement","acknowledgment"],"British":["acknowledgement"],"American":["acknowledgment","acknowledgement"],"Notes":""},{"Canadian":["advertise"],"British":["advertise"],"American":["advertise","advertize"],"Notes":""},{"Canadian":["aegis","egis"],"British":["aegis"],"American":["egis"],"Notes":""},{"Canadian":["aeon","eon"],"British":["aeon"],"American":["eon"],"Notes":""},{"Canadian":["aesthetic","esthetic"],"British":["aesthetic"],"American":["esthetic","aesthetic"],"Notes":""},{"Canadian":["aging","ageing"],"British":["ageing","aging"],"American":["aging"],"Notes":""},{"Canadian":["airplane"],"British":["aeroplane"],"American":["airplane"],"Notes":""},{"Canadian":["aluminum"],"British":["aluminium"],"American":["aluminum"],"Notes":""},{"Canadian":["amid","amidst"],"British":["amid","amidst"],"American":["amid"],"Notes":""},{"Canadian":["amoeba"],"British":["amoeba"],"American":["ameba"],"Notes":""},{"Canadian":["among","amongst"],"British":["among","amongst"],"American":["among"],"Notes":""},{"Canadian":["amortization"],"British":["amortisation","amortization"],"American":["amortization"],"Notes":""},{"Canadian":["amortize"],"British":["amortise","amortize"],"American":["amortize"],"Notes":""},{"Canadian":["amphitheatre"],"British":["amphitheatre"],"American":["amphitheater"],"Notes":""},{"Canadian":["anaesthesia","anesthesia"],"British":["anaesthesia"],"American":["anesthesia"],"Notes":""},{"Canadian":["analogue","analog"],"British":["analogue"],"American":["analogue","analog"],"Notes":"analog when used as a technical term (i.e. not digital)"},{"Canadian":["analyze","analyse"],"British":["analyse"],"American":["analyze"],"Notes":""},{"Canadian":["anemia","anaemia"],"British":["anaemia"],"American":["anemia"],"Notes":""},{"Canadian":["anemic","anaemic"],"British":["anaemic"],"American":["anemic"],"Notes":""},{"Canadian":["annex"],"British":["annexe","annex"],"American":["annex"],"Notes":"noun meaning 'something added'; verb is always annex"},{"Canadian":["apologize"],"British":["apologise","apologize"],"American":["apologize"],"Notes":""},{"Canadian":["appal","appall"],"British":["appal"],"American":["appall"],"Notes":"appalled/appalling in all countries"},{"Canadian":["appetizer"],"British":["appetiser","appetizer"],"American":["appetizer"],"Notes":""},{"Canadian":["arbour","arbor"],"British":["arbour"],"American":["arbor"],"Notes":""},{"Canadian":["archaeology","archeology"],"British":["archaeology"],"American":["archeology","archaeology"],"Notes":""},{"Canadian":["ardour","ardor"],"British":["ardour"],"American":["ardor"],"Notes":""},{"Canadian":["artifact"],"British":["artefact"],"American":["artifact"],"Notes":""},{"Canadian":["armour","armor"],"British":["armour"],"American":["armor"],"Notes":""},{"Canadian":["authorize"],"British":["authorise","authorize"],"American":["authorize"],"Notes":""},{"Canadian":["axe"],"British":["axe"],"American":["ax"],"Notes":""},{"Canadian":[""],"British":[""],"American":[""],"Notes":""}] From 9351e3be59ab63bb6b10df996b4663345f5216dc Mon Sep 17 00:00:00 2001 From: Jon Nordby Date: Sat, 4 Mar 2017 21:09:33 +0100 Subject: [PATCH 05/41] fbpspec: Don't catch output from noflo-nodejs Right now fbp-spec relies on this being outputted. References flowbased/fbp-spec#93 --- spec/fbpspec.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/fbpspec.coffee b/spec/fbpspec.coffee index 8c99d82..69979f4 100644 --- a/spec/fbpspec.coffee +++ b/spec/fbpspec.coffee @@ -8,7 +8,7 @@ nodeRuntime = secret: 'notasecret' address: "ws://localhost:3333" id: "7807f4d8-63e0-4a89-a577-2770c14f8106" - command: './node_modules/.bin/noflo-nodejs --verbose --catch-exceptions=false --secret notasecret --port=3333 --host=localhost --register=false --capture-output=true --debug=true' + command: './node_modules/.bin/noflo-nodejs --verbose --catch-exceptions=false --secret notasecret --port=3333 --host=localhost --register=false --debug=true' fbpspec.mocha.run nodeRuntime, './spec', fixturetimeout: 50000 From 8523bf4a2ff6b4ff27f523181f24008d15a15e51 Mon Sep 17 00:00:00 2001 From: Jon Nordby Date: Sat, 4 Mar 2017 21:11:10 +0100 Subject: [PATCH 06/41] package.json: Update repo location --- package.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 8cc2fb4..1914aea 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "license": "MIT", "repository": { "type": "git", - "url": "https://github.com/aretecode/canadianness.git" + "url": "https://github.com/noflo/canadianness.git" }, "dependencies": { "coffee-script": "^1.12.0", @@ -35,7 +35,7 @@ "noflo-tester": "^0.1.1" }, "scripts": { - "start": "./node_modules/.bin/noflo-nodejs --trace --debug", - "test": "./node_modules/.bin/grunt test" + "start": "noflo-nodejs --trace --debug", + "test": "grunt test" } } From 2b20c51cd327bc0d9f1f9c54c90334d5be92347a Mon Sep 17 00:00:00 2001 From: Jon Nordby Date: Sat, 4 Mar 2017 21:39:05 +0100 Subject: [PATCH 07/41] fbp-spec: Update to latest --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1914aea..136b22b 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,7 @@ "devDependencies": { "chai": "^3.5.0", "coffeelint": "^1.13.0", - "fbp-spec": "^0.1.15", + "fbp-spec": "^0.2.0", "grunt": "^0.4.5", "grunt-cli": "^1.2.0", "grunt-coffeelint": "^0.0.13", From cb4d810b7c417b977f35aa4223b691edfb341b5f Mon Sep 17 00:00:00 2001 From: Jon Nordby Date: Sat, 4 Mar 2017 21:39:38 +0100 Subject: [PATCH 08/41] tests: Fix compatibilty with NoFlo 0.8 Fixes exception like Uncaught TypeError: callback is not a function at node_modules/noflo/src/lib/Component.coffee:89:7 at node_modules/noflo/src/components/Graph.coffee:179:10 at node_modules/noflo/src/lib/Network.coffee:636:11 at Network.sendDefaults (node_modules/noflo/src/lib/Network.coffee:600:12) --- spec/Canadianness.coffee | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/spec/Canadianness.coffee b/spec/Canadianness.coffee index 3bfff92..4bf5d37 100755 --- a/spec/Canadianness.coffee +++ b/spec/Canadianness.coffee @@ -47,9 +47,9 @@ describe 'Canadianness graph', -> # because it is a graph, we want to wait until it is ready c.once 'ready', -> - c.start() - # for asyncish - setTimeout done, 1 + c.start () -> + # for asyncish + setTimeout done, 1 # before each test we want to attach all of the outports # (we also attach the inports here as well so the `before` is simpler) From c4524f960d23ca3180afb6de049e092089b0c344 Mon Sep 17 00:00:00 2001 From: Jon Nordby Date: Sat, 4 Mar 2017 22:05:20 +0100 Subject: [PATCH 09/41] tests: Fix noflo-tester setup --- package.json | 2 +- spec/CanadiannessNofloTester.coffee | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 136b22b..19ffabc 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "mocha": "^2.5.3", "noflo-nodejs": "^0.8.1", "noflo-runtime-base": "^0.8.2", - "noflo-tester": "^0.1.1" + "noflo-wrapper": "^0.1.2" }, "scripts": { "start": "noflo-nodejs --trace --debug", diff --git a/spec/CanadiannessNofloTester.coffee b/spec/CanadiannessNofloTester.coffee index be838a6..d58f3b1 100644 --- a/spec/CanadiannessNofloTester.coffee +++ b/spec/CanadiannessNofloTester.coffee @@ -1,8 +1,8 @@ -Tester = require 'noflo-tester' +Tester = require 'noflo-wrapper' chai = require 'chai' describe 'FindWords component', -> - t = new Tester 'canadianness/FindWords' + t = new Tester 'canadianness/FindWords', cache: false before (done) -> t.start (err, instance) -> return throw err if err From 6da39d17ac05470ac4b6663ed6e2fbbd86c91bdd Mon Sep 17 00:00:00 2001 From: Jon Nordby Date: Sat, 4 Mar 2017 22:09:29 +0100 Subject: [PATCH 10/41] TestDetermineEmotion: Remove workarounds for pre-NoFlo-0.8 --- components/TestDetermineEmotion.coffee | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/components/TestDetermineEmotion.coffee b/components/TestDetermineEmotion.coffee index 7ea68d6..ec2720b 100644 --- a/components/TestDetermineEmotion.coffee +++ b/components/TestDetermineEmotion.coffee @@ -15,12 +15,8 @@ exports.getComponent = -> required: true c.process (input, output) -> - # if it is not data, remove it from the buffer - return input.buffer.get().pop() if input.ip.type isnt 'data' - return unless input.has 'in' + return unless input.hasData 'in' - # needs the extra closeBracket - # because of the extra connect in translation layer output.send out: new noflo.IP 'openBracket' datas = input.getData 'in' @@ -29,6 +25,5 @@ exports.getComponent = -> for data in datas output.send out: new noflo.IP 'data', data - output.send out: new noflo.IP 'closeBracket' output.send out: new noflo.IP 'closeBracket' output.done() From 891bb6f871ac3d96a32ed6f9fb4a29a2310dc216 Mon Sep 17 00:00:00 2001 From: Jon Nordby Date: Sat, 4 Mar 2017 22:17:26 +0100 Subject: [PATCH 11/41] Fix more workarounds from pre-NoFlo-0.8 times --- components/FindWords.coffee | 10 +++------- spec/Canadianness.coffee | 3 --- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/components/FindWords.coffee b/components/FindWords.coffee index baa3ace..fc67b8e 100755 --- a/components/FindWords.coffee +++ b/components/FindWords.coffee @@ -50,19 +50,15 @@ exports.getComponent = -> c.forwardBrackets = content: 'matches' c.process (input, output) -> - # if it is not data, remove it from the buffer - return input.buffer.get().pop() if input.ip.type isnt 'data' # make sure we have data in the required inPorts - return unless input.has 'word', 'content', (ip) -> ip.type is 'data' + return unless input.hasData 'word', 'content' + # get the data from our in ports + [ word, content ] = input.getData 'word', 'content' # since we are sending out multiple `data` IPs # we want to wrap them in brackets output.send matches: new noflo.IP 'openBracket', content - # get the data from our in ports - word = input.getData 'word' - content = input.getData 'content' - # do our word processing r = /([.?!]*eh[.?!]*)/gi matches = matchAll content, r diff --git a/spec/Canadianness.coffee b/spec/Canadianness.coffee index 4bf5d37..3c98670 100755 --- a/spec/Canadianness.coffee +++ b/spec/Canadianness.coffee @@ -248,12 +248,9 @@ describe 'DetermineEmotion component', -> chai.expect(data).to.eql 'neutral' done() - # needs the extra closeBracket - # because of the extra connect in translation layer content.send new noflo.IP 'openBracket' content.send new noflo.IP 'data', 'eh' content.send new noflo.IP 'closeBracket' - content.send new noflo.IP 'closeBracket' describe 'with content eh!', -> it 'should be joyful', (done) -> From 3c6dfb362db737c6231ea30481250fd7e48a4e48 Mon Sep 17 00:00:00 2001 From: Jon Nordby Date: Sat, 4 Mar 2017 22:29:33 +0100 Subject: [PATCH 12/41] components: TestDetermineEmotion -> ArrayToStream --- .../{TestDetermineEmotion.coffee => ArrayToStream.coffee} | 2 +- spec/determineemotion.yaml | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) rename components/{TestDetermineEmotion.coffee => ArrayToStream.coffee} (92%) diff --git a/components/TestDetermineEmotion.coffee b/components/ArrayToStream.coffee similarity index 92% rename from components/TestDetermineEmotion.coffee rename to components/ArrayToStream.coffee index ec2720b..ea1d330 100644 --- a/components/TestDetermineEmotion.coffee +++ b/components/ArrayToStream.coffee @@ -2,7 +2,7 @@ noflo = require 'noflo' exports.getComponent = -> c = new noflo.Component - description: 'Test using fbp-spec' + description: 'Convert input array to a NoFlo stream' inPorts: in: datatype: 'array' diff --git a/spec/determineemotion.yaml b/spec/determineemotion.yaml index 13fefaf..c4225e8 100644 --- a/spec/determineemotion.yaml +++ b/spec/determineemotion.yaml @@ -1,12 +1,13 @@ topic: "canadianness/DetermineEmotion" name: "Determine Emotion fbpspec" +timeout: 10000 fixture: type: 'fbp' data: | # @runtime noflo-nodejs - INPORT=TestDetermineEmotion.IN:IN + INPORT=stream.IN:IN OUTPORT=DetermineEmotion.EMOTION:EMOTION - TestDetermineEmotion(canadianness/TestDetermineEmotion) OUT -> CONTENT DetermineEmotion(canadianness/DetermineEmotion) + stream(canadianness/ArrayToStream) OUT -> CONTENT DetermineEmotion(canadianness/DetermineEmotion) cases: - From 8557511eabdf0036ac743ffdbabb26dc77b5200f Mon Sep 17 00:00:00 2001 From: Jon Nordby Date: Sat, 4 Mar 2017 22:46:28 +0100 Subject: [PATCH 13/41] tests: Bump timeout for component loading --- spec/Canadianness.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/Canadianness.coffee b/spec/Canadianness.coffee index 3c98670..5c46472 100755 --- a/spec/Canadianness.coffee +++ b/spec/Canadianness.coffee @@ -36,7 +36,7 @@ describe 'Canadianness graph', -> # we only need to load the graph once, so it is in the before before (done) -> - @timeout 4000 + @timeout 10*1000 loader = new noflo.ComponentLoader baseDir loader.load 'canadianness/Canadianness', (err, instance) -> return done err if err From 0a440cabfaa9a258d3a7be9a46744fc3c7e8f590 Mon Sep 17 00:00:00 2001 From: Jon Nordby Date: Sat, 4 Mar 2017 23:06:30 +0100 Subject: [PATCH 14/41] tests: Don't duplicate spellings everywhere --- package.json | 2 ++ spec/Canadianness.coffee | 2 +- spec/canadianness.yaml | 18 +++++++++++++++--- 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 19ffabc..192fd2b 100644 --- a/package.json +++ b/package.json @@ -30,8 +30,10 @@ "grunt-coffeelint": "^0.0.13", "grunt-mocha-test": "^0.12.2", "mocha": "^2.5.3", + "noflo-filesystem": "^1.1.1", "noflo-nodejs": "^0.8.1", "noflo-runtime-base": "^0.8.2", + "noflo-strings": "^0.3.0", "noflo-wrapper": "^0.1.2" }, "scripts": { diff --git a/spec/Canadianness.coffee b/spec/Canadianness.coffee index 5c46472..bf2d212 100755 --- a/spec/Canadianness.coffee +++ b/spec/Canadianness.coffee @@ -121,7 +121,7 @@ describe 'Canadianness graph', -> content.send 'eh!' describe 'WordScore component', -> - listData = [{"Canadian":["calibre"],"British":["calibre"],"American":["caliber"],"Notes":""},{"Canadian":["caliper"],"British":["caliper"],"American":["caliper","calliper"],"Notes":""},{"Canadian":["cancellation"],"British":["cancellation"],"American":["cancelation"],"Notes":""},{"Canadian":["cancelled/cancelling"],"British":["cancelled/cancelling"],"American":["canceled/canceling"],"Notes":""},{"Canadian":["candour","candor"],"British":["candour"],"American":["candor"],"Notes":""},{"Canadian":["capitalize"],"British":["capitalise","capitalize"],"American":["capitalize"],"Notes":""},{"Canadian":["caramelize"],"British":["caramelise","caramelize"],"American":["caramelize"],"Notes":""},{"Canadian":["carburetor"],"British":["carburettor"],"American":["carburetor"],"Notes":""},{"Canadian":["catalogue"],"British":["catalogue"],"American":["catalog","catalogue"],"Notes":""},{"Canadian":["catalyze"],"British":["catalyse"],"American":["catalyze"],"Notes":""},{"Canadian":["categorization"],"British":["categorisation","categorization"],"American":["categorization"],"Notes":""},{"Canadian":["categorize"],"British":["categorise","categorize"],"American":["categorize"],"Notes":""},{"Canadian":["cauldron"],"British":["cauldron"],"American":["cauldron","caldron"],"Notes":""},{"Canadian":["cauterize"],"British":["cauterise","cauterize"],"American":["cauterize"],"Notes":""},{"Canadian":["centimetre"],"British":["centimetre"],"American":["centimeter"],"Notes":""},{"Canadian":["centre"],"British":["centre"],"American":["center"],"Notes":""},{"Canadian":["cesarean","caesarian"],"British":["caesarean"],"American":["cesarean","caesarean"],"Notes":""},{"Canadian":["cesium"],"British":["caesium"],"American":["cesium"],"Notes":""},{"Canadian":["characterize"],"British":["characterise","characterize"],"American":["characterize"],"Notes":""},{"Canadian":["checkered","chequered"],"British":["chequered"],"American":["checkered"],"Notes":""},{"Canadian":["cheque"],"British":["cheque"],"American":["check"],"Notes":"noun, meaning 'form of payment'; otherwise check"},{"Canadian":["chili"],"British":["chilli","chili"],"American":["chili","chile"],"Notes":""},{"Canadian":["cigarette"],"British":["cigarette"],"American":["cigarette","cigaret"],"Notes":""},{"Canadian":["cipher"],"British":["cipher","cypher"],"American":["cipher"],"Notes":""},{"Canadian":["civilization"],"British":["civilisation","civilization"],"American":["civilization"],"Notes":""},{"Canadian":["civilize"],"British":["civilise","civilize"],"American":["civilize"],"Notes":""},{"Canadian":["clamour","clamor"],"British":["clamour"],"American":["clamor"],"Notes":""},{"Canadian":["clangour","clangor"],"British":["clangour"],"American":["clangor"],"Notes":""},{"Canadian":["co-author","coauthor"],"British":["co-author"],"American":["coauthor"],"Notes":""},{"Canadian":["colonize"],"British":["colonise","colonize"],"American":["colonize"],"Notes":""},{"Canadian":["colour"],"British":["colour"],"American":["color"],"Notes":""},{"Canadian":["commercialize"],"British":["commercialise","commercialize"],"American":["commercialize"],"Notes":""},{"Canadian":["computerize"],"British":["computerise","computerize"],"American":["computerize"],"Notes":""},{"Canadian":["connection"],"British":["connection","connexion"],"American":["connection"],"Notes":""},{"Canadian":["conjuror","conjurer"],"British":["conjuror","conjurer"],"American":["conjuror","conjurer"],"Notes":"both spellings equally acceptable"},{"Canadian":["co-opt","coopt"],"British":["co-opt"],"American":["coopt"],"Notes":""},{"Canadian":["councillor","councilor"],"British":["councillor"],"American":["councilor"],"Notes":""},{"Canadian":["counselled/counselling"],"British":["counselled/counselling"],"American":["counseled/counseling"],"Notes":""},{"Canadian":["counsellor"],"British":["counsellor"],"American":["counselor"],"Notes":""},{"Canadian":["counter-attack"],"British":["counter-attack"],"American":["counterattack"],"Notes":""},{"Canadian":["cozy","cosy"],"British":["cosy"],"American":["cozy"],"Notes":""},{"Canadian":["criticize"],"British":["criticise"],"American":["criticize"],"Notes":""},{"Canadian":["crueller/cruellest"],"British":["crueller/cruellest"],"American":["crueler/cruelest"],"Notes":""},{"Canadian":["crystalline"],"British":["crystalline"],"American":["crystaline"],"Notes":""},{"Canadian":["crystallize"],"British":["crystallise","crystallize"],"American":["crystalize","crystallize"],"Notes":""},{"Canadian":["curb"],"British":["curb","kerb"],"American":["curb"],"Notes":"kerb only used for noun meaning 'edge of road' in UK; other meanings curb"},{"Canadian":["customize"],"British":["customise","customize"],"American":["customize"],"Notes":""},{"Canadian":[""],"British":[""],"American":[""],"Notes":""},{"Canadian":["abridgement","abridgment"],"British":["abridgement"],"American":["abridgment"],"Notes":""},{"Canadian":["acknowledgement","acknowledgment"],"British":["acknowledgement"],"American":["acknowledgment","acknowledgement"],"Notes":""},{"Canadian":["advertise"],"British":["advertise"],"American":["advertise","advertize"],"Notes":""},{"Canadian":["aegis","egis"],"British":["aegis"],"American":["egis"],"Notes":""},{"Canadian":["aeon","eon"],"British":["aeon"],"American":["eon"],"Notes":""},{"Canadian":["aesthetic","esthetic"],"British":["aesthetic"],"American":["esthetic","aesthetic"],"Notes":""},{"Canadian":["aging","ageing"],"British":["ageing","aging"],"American":["aging"],"Notes":""},{"Canadian":["airplane"],"British":["aeroplane"],"American":["airplane"],"Notes":""},{"Canadian":["aluminum"],"British":["aluminium"],"American":["aluminum"],"Notes":""},{"Canadian":["amid","amidst"],"British":["amid","amidst"],"American":["amid"],"Notes":""},{"Canadian":["amoeba"],"British":["amoeba"],"American":["ameba"],"Notes":""},{"Canadian":["among","amongst"],"British":["among","amongst"],"American":["among"],"Notes":""},{"Canadian":["amortization"],"British":["amortisation","amortization"],"American":["amortization"],"Notes":""},{"Canadian":["amortize"],"British":["amortise","amortize"],"American":["amortize"],"Notes":""},{"Canadian":["amphitheatre"],"British":["amphitheatre"],"American":["amphitheater"],"Notes":""},{"Canadian":["anaesthesia","anesthesia"],"British":["anaesthesia"],"American":["anesthesia"],"Notes":""},{"Canadian":["analogue","analog"],"British":["analogue"],"American":["analogue","analog"],"Notes":"analog when used as a technical term (i.e. not digital)"},{"Canadian":["analyze","analyse"],"British":["analyse"],"American":["analyze"],"Notes":""},{"Canadian":["anemia","anaemia"],"British":["anaemia"],"American":["anemia"],"Notes":""},{"Canadian":["anemic","anaemic"],"British":["anaemic"],"American":["anemic"],"Notes":""},{"Canadian":["annex"],"British":["annexe","annex"],"American":["annex"],"Notes":"noun meaning 'something added'; verb is always annex"},{"Canadian":["apologize"],"British":["apologise","apologize"],"American":["apologize"],"Notes":""},{"Canadian":["appal","appall"],"British":["appal"],"American":["appall"],"Notes":"appalled/appalling in all countries"},{"Canadian":["appetizer"],"British":["appetiser","appetizer"],"American":["appetizer"],"Notes":""},{"Canadian":["arbour","arbor"],"British":["arbour"],"American":["arbor"],"Notes":""},{"Canadian":["archaeology","archeology"],"British":["archaeology"],"American":["archeology","archaeology"],"Notes":""},{"Canadian":["ardour","ardor"],"British":["ardour"],"American":["ardor"],"Notes":""},{"Canadian":["artifact"],"British":["artefact"],"American":["artifact"],"Notes":""},{"Canadian":["armour","armor"],"British":["armour"],"American":["armor"],"Notes":""},{"Canadian":["authorize"],"British":["authorise","authorize"],"American":["authorize"],"Notes":""},{"Canadian":["axe"],"British":["axe"],"American":["ax"],"Notes":""},{"Canadian":[""],"British":[""],"American":[""],"Notes":""}] + listData = require '../spellingdata.json' c = null content = null diff --git a/spec/canadianness.yaml b/spec/canadianness.yaml index fe90c7b..beae2fe 100644 --- a/spec/canadianness.yaml +++ b/spec/canadianness.yaml @@ -1,11 +1,25 @@ topic: "canadianness/Canadianness" name: "Canadianness fbpspec" +fixture: + type: 'fbp' + data: | + # @runtime noflo-nodejs + INPORT=graph.WORDS:WORDS + INPORT=graph.CONTENT:CONTENT + OUTPORT=graph.EMOTION:EMOTION + OUTPORT=graph.SCORE:SCORE + OUTPORT=errors.OUT:ERROR + # read the available spelling + './spellingdata.json' -> read(filesystem/ReadFile) -> words(strings/ParseJson) + words -> SPELLING graph(canadianness/Canadianness) + # forward errors + read ERROR -> errors(core/Repeat) + words ERROR -> errors cases: - name: 'content `A bunch of centers had a color cancelation.`' assertion: 'should be neutral and -3' inputs: - spelling: [{"Canadian":["calibre"],"British":["calibre"],"American":["caliber"],"Notes":""},{"Canadian":["caliper"],"British":["caliper"],"American":["caliper","calliper"],"Notes":""},{"Canadian":["cancellation"],"British":["cancellation"],"American":["cancelation"],"Notes":""},{"Canadian":["cancelled/cancelling"],"British":["cancelled/cancelling"],"American":["canceled/canceling"],"Notes":""},{"Canadian":["candour","candor"],"British":["candour"],"American":["candor"],"Notes":""},{"Canadian":["capitalize"],"British":["capitalise","capitalize"],"American":["capitalize"],"Notes":""},{"Canadian":["caramelize"],"British":["caramelise","caramelize"],"American":["caramelize"],"Notes":""},{"Canadian":["carburetor"],"British":["carburettor"],"American":["carburetor"],"Notes":""},{"Canadian":["catalogue"],"British":["catalogue"],"American":["catalog","catalogue"],"Notes":""},{"Canadian":["catalyze"],"British":["catalyse"],"American":["catalyze"],"Notes":""},{"Canadian":["categorization"],"British":["categorisation","categorization"],"American":["categorization"],"Notes":""},{"Canadian":["categorize"],"British":["categorise","categorize"],"American":["categorize"],"Notes":""},{"Canadian":["cauldron"],"British":["cauldron"],"American":["cauldron","caldron"],"Notes":""},{"Canadian":["cauterize"],"British":["cauterise","cauterize"],"American":["cauterize"],"Notes":""},{"Canadian":["centimetre"],"British":["centimetre"],"American":["centimeter"],"Notes":""},{"Canadian":["centre"],"British":["centre"],"American":["center"],"Notes":""},{"Canadian":["cesarean","caesarian"],"British":["caesarean"],"American":["cesarean","caesarean"],"Notes":""},{"Canadian":["cesium"],"British":["caesium"],"American":["cesium"],"Notes":""},{"Canadian":["characterize"],"British":["characterise","characterize"],"American":["characterize"],"Notes":""},{"Canadian":["checkered","chequered"],"British":["chequered"],"American":["checkered"],"Notes":""},{"Canadian":["cheque"],"British":["cheque"],"American":["check"],"Notes":"noun, meaning 'form of payment'; otherwise check"},{"Canadian":["chili"],"British":["chilli","chili"],"American":["chili","chile"],"Notes":""},{"Canadian":["cigarette"],"British":["cigarette"],"American":["cigarette","cigaret"],"Notes":""},{"Canadian":["cipher"],"British":["cipher","cypher"],"American":["cipher"],"Notes":""},{"Canadian":["civilization"],"British":["civilisation","civilization"],"American":["civilization"],"Notes":""},{"Canadian":["civilize"],"British":["civilise","civilize"],"American":["civilize"],"Notes":""},{"Canadian":["clamour","clamor"],"British":["clamour"],"American":["clamor"],"Notes":""},{"Canadian":["clangour","clangor"],"British":["clangour"],"American":["clangor"],"Notes":""},{"Canadian":["co-author","coauthor"],"British":["co-author"],"American":["coauthor"],"Notes":""},{"Canadian":["colonize"],"British":["colonise","colonize"],"American":["colonize"],"Notes":""},{"Canadian":["colour"],"British":["colour"],"American":["color"],"Notes":""},{"Canadian":["commercialize"],"British":["commercialise","commercialize"],"American":["commercialize"],"Notes":""},{"Canadian":["computerize"],"British":["computerise","computerize"],"American":["computerize"],"Notes":""},{"Canadian":["connection"],"British":["connection","connexion"],"American":["connection"],"Notes":""},{"Canadian":["conjuror","conjurer"],"British":["conjuror","conjurer"],"American":["conjuror","conjurer"],"Notes":"both spellings equally acceptable"},{"Canadian":["co-opt","coopt"],"British":["co-opt"],"American":["coopt"],"Notes":""},{"Canadian":["councillor","councilor"],"British":["councillor"],"American":["councilor"],"Notes":""},{"Canadian":["counselled/counselling"],"British":["counselled/counselling"],"American":["counseled/counseling"],"Notes":""},{"Canadian":["counsellor"],"British":["counsellor"],"American":["counselor"],"Notes":""},{"Canadian":["counter-attack"],"British":["counter-attack"],"American":["counterattack"],"Notes":""},{"Canadian":["cozy","cosy"],"British":["cosy"],"American":["cozy"],"Notes":""},{"Canadian":["criticize"],"British":["criticise"],"American":["criticize"],"Notes":""},{"Canadian":["crueller/cruellest"],"British":["crueller/cruellest"],"American":["crueler/cruelest"],"Notes":""},{"Canadian":["crystalline"],"British":["crystalline"],"American":["crystaline"],"Notes":""},{"Canadian":["crystallize"],"British":["crystallise","crystallize"],"American":["crystalize","crystallize"],"Notes":""},{"Canadian":["curb"],"British":["curb","kerb"],"American":["curb"],"Notes":"kerb only used for noun meaning 'edge of road' in UK; other meanings curb"},{"Canadian":["customize"],"British":["customise","customize"],"American":["customize"],"Notes":""},{"Canadian":[""],"British":[""],"American":[""],"Notes":""},{"Canadian":["abridgement","abridgment"],"British":["abridgement"],"American":["abridgment"],"Notes":""},{"Canadian":["acknowledgement","acknowledgment"],"British":["acknowledgement"],"American":["acknowledgment","acknowledgement"],"Notes":""},{"Canadian":["advertise"],"British":["advertise"],"American":["advertise","advertize"],"Notes":""},{"Canadian":["aegis","egis"],"British":["aegis"],"American":["egis"],"Notes":""},{"Canadian":["aeon","eon"],"British":["aeon"],"American":["eon"],"Notes":""},{"Canadian":["aesthetic","esthetic"],"British":["aesthetic"],"American":["esthetic","aesthetic"],"Notes":""},{"Canadian":["aging","ageing"],"British":["ageing","aging"],"American":["aging"],"Notes":""},{"Canadian":["airplane"],"British":["aeroplane"],"American":["airplane"],"Notes":""},{"Canadian":["aluminum"],"British":["aluminium"],"American":["aluminum"],"Notes":""},{"Canadian":["amid","amidst"],"British":["amid","amidst"],"American":["amid"],"Notes":""},{"Canadian":["amoeba"],"British":["amoeba"],"American":["ameba"],"Notes":""},{"Canadian":["among","amongst"],"British":["among","amongst"],"American":["among"],"Notes":""},{"Canadian":["amortization"],"British":["amortisation","amortization"],"American":["amortization"],"Notes":""},{"Canadian":["amortize"],"British":["amortise","amortize"],"American":["amortize"],"Notes":""},{"Canadian":["amphitheatre"],"British":["amphitheatre"],"American":["amphitheater"],"Notes":""},{"Canadian":["anaesthesia","anesthesia"],"British":["anaesthesia"],"American":["anesthesia"],"Notes":""},{"Canadian":["analogue","analog"],"British":["analogue"],"American":["analogue","analog"],"Notes":"analog when used as a technical term (i.e. not digital)"},{"Canadian":["analyze","analyse"],"British":["analyse"],"American":["analyze"],"Notes":""},{"Canadian":["anemia","anaemia"],"British":["anaemia"],"American":["anemia"],"Notes":""},{"Canadian":["anemic","anaemic"],"British":["anaemic"],"American":["anemic"],"Notes":""},{"Canadian":["annex"],"British":["annexe","annex"],"American":["annex"],"Notes":"noun meaning 'something added'; verb is always annex"},{"Canadian":["apologize"],"British":["apologise","apologize"],"American":["apologize"],"Notes":""},{"Canadian":["appal","appall"],"British":["appal"],"American":["appall"],"Notes":"appalled/appalling in all countries"},{"Canadian":["appetizer"],"British":["appetiser","appetizer"],"American":["appetizer"],"Notes":""},{"Canadian":["arbour","arbor"],"British":["arbour"],"American":["arbor"],"Notes":""},{"Canadian":["archaeology","archeology"],"British":["archaeology"],"American":["archeology","archaeology"],"Notes":""},{"Canadian":["ardour","ardor"],"British":["ardour"],"American":["ardor"],"Notes":""},{"Canadian":["artifact"],"British":["artefact"],"American":["artifact"],"Notes":""},{"Canadian":["armour","armor"],"British":["armour"],"American":["armor"],"Notes":""},{"Canadian":["authorize"],"British":["authorise","authorize"],"American":["authorize"],"Notes":""},{"Canadian":["axe"],"British":["axe"],"American":["ax"],"Notes":""},{"Canadian":[""],"British":[""],"American":[""],"Notes":""}] words: {"eh": 11, "eh!": 11} content: 'A bunch of centers had a color cancelation.' expect: @@ -17,7 +31,6 @@ cases: name: 'content `eh`' assertion: 'should be neutral, yet highly Canadian' inputs: - spelling: [{"Canadian":["calibre"],"British":["calibre"],"American":["caliber"],"Notes":""},{"Canadian":["caliper"],"British":["caliper"],"American":["caliper","calliper"],"Notes":""},{"Canadian":["cancellation"],"British":["cancellation"],"American":["cancelation"],"Notes":""},{"Canadian":["cancelled/cancelling"],"British":["cancelled/cancelling"],"American":["canceled/canceling"],"Notes":""},{"Canadian":["candour","candor"],"British":["candour"],"American":["candor"],"Notes":""},{"Canadian":["capitalize"],"British":["capitalise","capitalize"],"American":["capitalize"],"Notes":""},{"Canadian":["caramelize"],"British":["caramelise","caramelize"],"American":["caramelize"],"Notes":""},{"Canadian":["carburetor"],"British":["carburettor"],"American":["carburetor"],"Notes":""},{"Canadian":["catalogue"],"British":["catalogue"],"American":["catalog","catalogue"],"Notes":""},{"Canadian":["catalyze"],"British":["catalyse"],"American":["catalyze"],"Notes":""},{"Canadian":["categorization"],"British":["categorisation","categorization"],"American":["categorization"],"Notes":""},{"Canadian":["categorize"],"British":["categorise","categorize"],"American":["categorize"],"Notes":""},{"Canadian":["cauldron"],"British":["cauldron"],"American":["cauldron","caldron"],"Notes":""},{"Canadian":["cauterize"],"British":["cauterise","cauterize"],"American":["cauterize"],"Notes":""},{"Canadian":["centimetre"],"British":["centimetre"],"American":["centimeter"],"Notes":""},{"Canadian":["centre"],"British":["centre"],"American":["center"],"Notes":""},{"Canadian":["cesarean","caesarian"],"British":["caesarean"],"American":["cesarean","caesarean"],"Notes":""},{"Canadian":["cesium"],"British":["caesium"],"American":["cesium"],"Notes":""},{"Canadian":["characterize"],"British":["characterise","characterize"],"American":["characterize"],"Notes":""},{"Canadian":["checkered","chequered"],"British":["chequered"],"American":["checkered"],"Notes":""},{"Canadian":["cheque"],"British":["cheque"],"American":["check"],"Notes":"noun, meaning 'form of payment'; otherwise check"},{"Canadian":["chili"],"British":["chilli","chili"],"American":["chili","chile"],"Notes":""},{"Canadian":["cigarette"],"British":["cigarette"],"American":["cigarette","cigaret"],"Notes":""},{"Canadian":["cipher"],"British":["cipher","cypher"],"American":["cipher"],"Notes":""},{"Canadian":["civilization"],"British":["civilisation","civilization"],"American":["civilization"],"Notes":""},{"Canadian":["civilize"],"British":["civilise","civilize"],"American":["civilize"],"Notes":""},{"Canadian":["clamour","clamor"],"British":["clamour"],"American":["clamor"],"Notes":""},{"Canadian":["clangour","clangor"],"British":["clangour"],"American":["clangor"],"Notes":""},{"Canadian":["co-author","coauthor"],"British":["co-author"],"American":["coauthor"],"Notes":""},{"Canadian":["colonize"],"British":["colonise","colonize"],"American":["colonize"],"Notes":""},{"Canadian":["colour"],"British":["colour"],"American":["color"],"Notes":""},{"Canadian":["commercialize"],"British":["commercialise","commercialize"],"American":["commercialize"],"Notes":""},{"Canadian":["computerize"],"British":["computerise","computerize"],"American":["computerize"],"Notes":""},{"Canadian":["connection"],"British":["connection","connexion"],"American":["connection"],"Notes":""},{"Canadian":["conjuror","conjurer"],"British":["conjuror","conjurer"],"American":["conjuror","conjurer"],"Notes":"both spellings equally acceptable"},{"Canadian":["co-opt","coopt"],"British":["co-opt"],"American":["coopt"],"Notes":""},{"Canadian":["councillor","councilor"],"British":["councillor"],"American":["councilor"],"Notes":""},{"Canadian":["counselled/counselling"],"British":["counselled/counselling"],"American":["counseled/counseling"],"Notes":""},{"Canadian":["counsellor"],"British":["counsellor"],"American":["counselor"],"Notes":""},{"Canadian":["counter-attack"],"British":["counter-attack"],"American":["counterattack"],"Notes":""},{"Canadian":["cozy","cosy"],"British":["cosy"],"American":["cozy"],"Notes":""},{"Canadian":["criticize"],"British":["criticise"],"American":["criticize"],"Notes":""},{"Canadian":["crueller/cruellest"],"British":["crueller/cruellest"],"American":["crueler/cruelest"],"Notes":""},{"Canadian":["crystalline"],"British":["crystalline"],"American":["crystaline"],"Notes":""},{"Canadian":["crystallize"],"British":["crystallise","crystallize"],"American":["crystalize","crystallize"],"Notes":""},{"Canadian":["curb"],"British":["curb","kerb"],"American":["curb"],"Notes":"kerb only used for noun meaning 'edge of road' in UK; other meanings curb"},{"Canadian":["customize"],"British":["customise","customize"],"American":["customize"],"Notes":""},{"Canadian":[""],"British":[""],"American":[""],"Notes":""},{"Canadian":["abridgement","abridgment"],"British":["abridgement"],"American":["abridgment"],"Notes":""},{"Canadian":["acknowledgement","acknowledgment"],"British":["acknowledgement"],"American":["acknowledgment","acknowledgement"],"Notes":""},{"Canadian":["advertise"],"British":["advertise"],"American":["advertise","advertize"],"Notes":""},{"Canadian":["aegis","egis"],"British":["aegis"],"American":["egis"],"Notes":""},{"Canadian":["aeon","eon"],"British":["aeon"],"American":["eon"],"Notes":""},{"Canadian":["aesthetic","esthetic"],"British":["aesthetic"],"American":["esthetic","aesthetic"],"Notes":""},{"Canadian":["aging","ageing"],"British":["ageing","aging"],"American":["aging"],"Notes":""},{"Canadian":["airplane"],"British":["aeroplane"],"American":["airplane"],"Notes":""},{"Canadian":["aluminum"],"British":["aluminium"],"American":["aluminum"],"Notes":""},{"Canadian":["amid","amidst"],"British":["amid","amidst"],"American":["amid"],"Notes":""},{"Canadian":["amoeba"],"British":["amoeba"],"American":["ameba"],"Notes":""},{"Canadian":["among","amongst"],"British":["among","amongst"],"American":["among"],"Notes":""},{"Canadian":["amortization"],"British":["amortisation","amortization"],"American":["amortization"],"Notes":""},{"Canadian":["amortize"],"British":["amortise","amortize"],"American":["amortize"],"Notes":""},{"Canadian":["amphitheatre"],"British":["amphitheatre"],"American":["amphitheater"],"Notes":""},{"Canadian":["anaesthesia","anesthesia"],"British":["anaesthesia"],"American":["anesthesia"],"Notes":""},{"Canadian":["analogue","analog"],"British":["analogue"],"American":["analogue","analog"],"Notes":"analog when used as a technical term (i.e. not digital)"},{"Canadian":["analyze","analyse"],"British":["analyse"],"American":["analyze"],"Notes":""},{"Canadian":["anemia","anaemia"],"British":["anaemia"],"American":["anemia"],"Notes":""},{"Canadian":["anemic","anaemic"],"British":["anaemic"],"American":["anemic"],"Notes":""},{"Canadian":["annex"],"British":["annexe","annex"],"American":["annex"],"Notes":"noun meaning 'something added'; verb is always annex"},{"Canadian":["apologize"],"British":["apologise","apologize"],"American":["apologize"],"Notes":""},{"Canadian":["appal","appall"],"British":["appal"],"American":["appall"],"Notes":"appalled/appalling in all countries"},{"Canadian":["appetizer"],"British":["appetiser","appetizer"],"American":["appetizer"],"Notes":""},{"Canadian":["arbour","arbor"],"British":["arbour"],"American":["arbor"],"Notes":""},{"Canadian":["archaeology","archeology"],"British":["archaeology"],"American":["archeology","archaeology"],"Notes":""},{"Canadian":["ardour","ardor"],"British":["ardour"],"American":["ardor"],"Notes":""},{"Canadian":["artifact"],"British":["artefact"],"American":["artifact"],"Notes":""},{"Canadian":["armour","armor"],"British":["armour"],"American":["armor"],"Notes":""},{"Canadian":["authorize"],"British":["authorise","authorize"],"American":["authorize"],"Notes":""},{"Canadian":["axe"],"British":["axe"],"American":["ax"],"Notes":""},{"Canadian":[""],"British":[""],"American":[""],"Notes":""}] words: {"eh": 11, "eh!": 11} content: 'eh' expect: @@ -29,7 +42,6 @@ cases: name: 'content `eh!`' assertion: 'should be joyful, and Canadian' inputs: - spelling: [{"Canadian":["calibre"],"British":["calibre"],"American":["caliber"],"Notes":""},{"Canadian":["caliper"],"British":["caliper"],"American":["caliper","calliper"],"Notes":""},{"Canadian":["cancellation"],"British":["cancellation"],"American":["cancelation"],"Notes":""},{"Canadian":["cancelled/cancelling"],"British":["cancelled/cancelling"],"American":["canceled/canceling"],"Notes":""},{"Canadian":["candour","candor"],"British":["candour"],"American":["candor"],"Notes":""},{"Canadian":["capitalize"],"British":["capitalise","capitalize"],"American":["capitalize"],"Notes":""},{"Canadian":["caramelize"],"British":["caramelise","caramelize"],"American":["caramelize"],"Notes":""},{"Canadian":["carburetor"],"British":["carburettor"],"American":["carburetor"],"Notes":""},{"Canadian":["catalogue"],"British":["catalogue"],"American":["catalog","catalogue"],"Notes":""},{"Canadian":["catalyze"],"British":["catalyse"],"American":["catalyze"],"Notes":""},{"Canadian":["categorization"],"British":["categorisation","categorization"],"American":["categorization"],"Notes":""},{"Canadian":["categorize"],"British":["categorise","categorize"],"American":["categorize"],"Notes":""},{"Canadian":["cauldron"],"British":["cauldron"],"American":["cauldron","caldron"],"Notes":""},{"Canadian":["cauterize"],"British":["cauterise","cauterize"],"American":["cauterize"],"Notes":""},{"Canadian":["centimetre"],"British":["centimetre"],"American":["centimeter"],"Notes":""},{"Canadian":["centre"],"British":["centre"],"American":["center"],"Notes":""},{"Canadian":["cesarean","caesarian"],"British":["caesarean"],"American":["cesarean","caesarean"],"Notes":""},{"Canadian":["cesium"],"British":["caesium"],"American":["cesium"],"Notes":""},{"Canadian":["characterize"],"British":["characterise","characterize"],"American":["characterize"],"Notes":""},{"Canadian":["checkered","chequered"],"British":["chequered"],"American":["checkered"],"Notes":""},{"Canadian":["cheque"],"British":["cheque"],"American":["check"],"Notes":"noun, meaning 'form of payment'; otherwise check"},{"Canadian":["chili"],"British":["chilli","chili"],"American":["chili","chile"],"Notes":""},{"Canadian":["cigarette"],"British":["cigarette"],"American":["cigarette","cigaret"],"Notes":""},{"Canadian":["cipher"],"British":["cipher","cypher"],"American":["cipher"],"Notes":""},{"Canadian":["civilization"],"British":["civilisation","civilization"],"American":["civilization"],"Notes":""},{"Canadian":["civilize"],"British":["civilise","civilize"],"American":["civilize"],"Notes":""},{"Canadian":["clamour","clamor"],"British":["clamour"],"American":["clamor"],"Notes":""},{"Canadian":["clangour","clangor"],"British":["clangour"],"American":["clangor"],"Notes":""},{"Canadian":["co-author","coauthor"],"British":["co-author"],"American":["coauthor"],"Notes":""},{"Canadian":["colonize"],"British":["colonise","colonize"],"American":["colonize"],"Notes":""},{"Canadian":["colour"],"British":["colour"],"American":["color"],"Notes":""},{"Canadian":["commercialize"],"British":["commercialise","commercialize"],"American":["commercialize"],"Notes":""},{"Canadian":["computerize"],"British":["computerise","computerize"],"American":["computerize"],"Notes":""},{"Canadian":["connection"],"British":["connection","connexion"],"American":["connection"],"Notes":""},{"Canadian":["conjuror","conjurer"],"British":["conjuror","conjurer"],"American":["conjuror","conjurer"],"Notes":"both spellings equally acceptable"},{"Canadian":["co-opt","coopt"],"British":["co-opt"],"American":["coopt"],"Notes":""},{"Canadian":["councillor","councilor"],"British":["councillor"],"American":["councilor"],"Notes":""},{"Canadian":["counselled/counselling"],"British":["counselled/counselling"],"American":["counseled/counseling"],"Notes":""},{"Canadian":["counsellor"],"British":["counsellor"],"American":["counselor"],"Notes":""},{"Canadian":["counter-attack"],"British":["counter-attack"],"American":["counterattack"],"Notes":""},{"Canadian":["cozy","cosy"],"British":["cosy"],"American":["cozy"],"Notes":""},{"Canadian":["criticize"],"British":["criticise"],"American":["criticize"],"Notes":""},{"Canadian":["crueller/cruellest"],"British":["crueller/cruellest"],"American":["crueler/cruelest"],"Notes":""},{"Canadian":["crystalline"],"British":["crystalline"],"American":["crystaline"],"Notes":""},{"Canadian":["crystallize"],"British":["crystallise","crystallize"],"American":["crystalize","crystallize"],"Notes":""},{"Canadian":["curb"],"British":["curb","kerb"],"American":["curb"],"Notes":"kerb only used for noun meaning 'edge of road' in UK; other meanings curb"},{"Canadian":["customize"],"British":["customise","customize"],"American":["customize"],"Notes":""},{"Canadian":[""],"British":[""],"American":[""],"Notes":""},{"Canadian":["abridgement","abridgment"],"British":["abridgement"],"American":["abridgment"],"Notes":""},{"Canadian":["acknowledgement","acknowledgment"],"British":["acknowledgement"],"American":["acknowledgment","acknowledgement"],"Notes":""},{"Canadian":["advertise"],"British":["advertise"],"American":["advertise","advertize"],"Notes":""},{"Canadian":["aegis","egis"],"British":["aegis"],"American":["egis"],"Notes":""},{"Canadian":["aeon","eon"],"British":["aeon"],"American":["eon"],"Notes":""},{"Canadian":["aesthetic","esthetic"],"British":["aesthetic"],"American":["esthetic","aesthetic"],"Notes":""},{"Canadian":["aging","ageing"],"British":["ageing","aging"],"American":["aging"],"Notes":""},{"Canadian":["airplane"],"British":["aeroplane"],"American":["airplane"],"Notes":""},{"Canadian":["aluminum"],"British":["aluminium"],"American":["aluminum"],"Notes":""},{"Canadian":["amid","amidst"],"British":["amid","amidst"],"American":["amid"],"Notes":""},{"Canadian":["amoeba"],"British":["amoeba"],"American":["ameba"],"Notes":""},{"Canadian":["among","amongst"],"British":["among","amongst"],"American":["among"],"Notes":""},{"Canadian":["amortization"],"British":["amortisation","amortization"],"American":["amortization"],"Notes":""},{"Canadian":["amortize"],"British":["amortise","amortize"],"American":["amortize"],"Notes":""},{"Canadian":["amphitheatre"],"British":["amphitheatre"],"American":["amphitheater"],"Notes":""},{"Canadian":["anaesthesia","anesthesia"],"British":["anaesthesia"],"American":["anesthesia"],"Notes":""},{"Canadian":["analogue","analog"],"British":["analogue"],"American":["analogue","analog"],"Notes":"analog when used as a technical term (i.e. not digital)"},{"Canadian":["analyze","analyse"],"British":["analyse"],"American":["analyze"],"Notes":""},{"Canadian":["anemia","anaemia"],"British":["anaemia"],"American":["anemia"],"Notes":""},{"Canadian":["anemic","anaemic"],"British":["anaemic"],"American":["anemic"],"Notes":""},{"Canadian":["annex"],"British":["annexe","annex"],"American":["annex"],"Notes":"noun meaning 'something added'; verb is always annex"},{"Canadian":["apologize"],"British":["apologise","apologize"],"American":["apologize"],"Notes":""},{"Canadian":["appal","appall"],"British":["appal"],"American":["appall"],"Notes":"appalled/appalling in all countries"},{"Canadian":["appetizer"],"British":["appetiser","appetizer"],"American":["appetizer"],"Notes":""},{"Canadian":["arbour","arbor"],"British":["arbour"],"American":["arbor"],"Notes":""},{"Canadian":["archaeology","archeology"],"British":["archaeology"],"American":["archeology","archaeology"],"Notes":""},{"Canadian":["ardour","ardor"],"British":["ardour"],"American":["ardor"],"Notes":""},{"Canadian":["artifact"],"British":["artefact"],"American":["artifact"],"Notes":""},{"Canadian":["armour","armor"],"British":["armour"],"American":["armor"],"Notes":""},{"Canadian":["authorize"],"British":["authorise","authorize"],"American":["authorize"],"Notes":""},{"Canadian":["axe"],"British":["axe"],"American":["ax"],"Notes":""},{"Canadian":[""],"British":[""],"American":[""],"Notes":""}] words: {"eh": 11, "eh!": 11} content: 'eh!' expect: From c1e7dfde1518237657a06cbba8824d5a6024cf75 Mon Sep 17 00:00:00 2001 From: Jon Nordby Date: Sat, 4 Mar 2017 23:17:59 +0100 Subject: [PATCH 15/41] tests: Bring back fbp-spec timeouts to something more sane --- spec/fbpspec.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/fbpspec.coffee b/spec/fbpspec.coffee index 69979f4..3377f40 100644 --- a/spec/fbpspec.coffee +++ b/spec/fbpspec.coffee @@ -11,5 +11,5 @@ nodeRuntime = command: './node_modules/.bin/noflo-nodejs --verbose --catch-exceptions=false --secret notasecret --port=3333 --host=localhost --register=false --debug=true' fbpspec.mocha.run nodeRuntime, './spec', - fixturetimeout: 50000 - starttimeout: 100000 + fixturetimeout: 10000 + starttimeout: 10000 From 9aac0087b951757406073bb05d0d092dd362f710 Mon Sep 17 00:00:00 2001 From: Jon Nordby Date: Sat, 4 Mar 2017 23:29:49 +0100 Subject: [PATCH 16/41] README: Add Travis CI badge --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 610529e..164470b 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,4 @@ +[![Build Status](https://travis-ci.org/noflo/canadianness.svg?branch=master)](https://travis-ci.org/noflo/canadianness) # Canadianness Basic example of programming with [NoFlo](https://noflojs.org). From e3041e746bae12df937d6fc817830306f112407b Mon Sep 17 00:00:00 2001 From: Jon Nordby Date: Sun, 5 Mar 2017 20:04:16 +0100 Subject: [PATCH 17/41] components: Add Markdown annotations for docs --- components/DetermineEmotion.coffee | 37 ++++++++++++++++++++++-------- components/FindWords.coffee | 36 +++++++++++++++++++---------- components/WordScore.coffee | 11 +++++++-- 3 files changed, 60 insertions(+), 24 deletions(-) diff --git a/components/DetermineEmotion.coffee b/components/DetermineEmotion.coffee index b7b45f9..bcef182 100755 --- a/components/DetermineEmotion.coffee +++ b/components/DetermineEmotion.coffee @@ -1,6 +1,9 @@ +# ## Import libraries noflo = require 'noflo' -# https://en.wikipedia.org/wiki/Mode_(statistics) +# ## Useful functions +# +# Function to calculate most common value (the [mode](https://en.wikipedia.org/wiki/Mode_(statistics)) findMode = (array) -> frequency = {} maxFrequency = 0 @@ -12,7 +15,9 @@ findMode = (array) -> result = array[v] result -# could also pass in full contents here and determine distance from each other +# ## Component declaration +# +# Define the input and output ports, and describe their function exports.getComponent = -> c = new noflo.Component description: 'Find all of the instances of `word` in `content` and send them out in a stream' @@ -29,21 +34,30 @@ exports.getComponent = -> error: datatype: 'object' - # we are using brackets to group the stream, so we do not want to forward them + # ## Processing function + # c.process (input, output) -> + + # ### Receiving input + # + # We expect a [stream](noflojs.org/documentation/process-api/#full-stream) + # Will also accept a single (non-bracketed) input packet, returned as a stream of length 1 return unless input.hasStream 'content' - - # we get the [full stream](noflojs.org/documentation/process-api/#full-stream) contents = input.getStream 'content' - # since it has `openBracket` and `closeBracket` we only want the dat + # The output will be a single packet (not a stream), + # hence we drop the `openBracket` and `closeBracket` contents = contents.filter (ip) -> ip.type is 'data' - # since it is an array of IP objects, - # they contain other properties, we only want the data + # extract the data payload from the IP objects contents = contents.map (ip) -> ip.data - # to hold the emotion matches + # ### Component business logic + # + # First find which emotions are present, then calculate which one is most common. + # This could alternatively be split into two dedicate components. + + # to hold the emotions found matches = [] # the emotions we will use @@ -65,11 +79,14 @@ exports.getComponent = -> if content in data matches.push emotion - # if we didn't get any emotions, it is default neutral + # if we didn't get any emotions, it default to 'neutral' if matches.length is 0 mode = 'neutral' # if we did, we need to find the emotion that was the most common else mode = findMode matches + # ### Send output + # + # Also signals completion by using `sendDone()` output.sendDone emotion: mode diff --git a/components/FindWords.coffee b/components/FindWords.coffee index fc67b8e..7308f06 100755 --- a/components/FindWords.coffee +++ b/components/FindWords.coffee @@ -1,6 +1,11 @@ +# ## Import libraries noflo = require 'noflo' -# a helper to match all on a string +# ## Helper functions +# +# Not NoFlo or even component-logic-specific, so nice to keep them separate + +# Return all RegExp matches on a string matchAll = (string, regexp) -> matches = [] string.replace regexp, -> @@ -12,25 +17,26 @@ matchAll = (string, regexp) -> return if matches.length then matches else [] -# since regexing will give the `index` and the `input`, we only want the match +# Extract the actual data of the match result actualMatches = (matches) -> # because we want to send out an empty array if there are no matches return [[]] if matches.length is 0 matches.map (match) -> match[0] +# ## Component declaration exports.getComponent = -> c = new noflo.Component description: 'Find all of the instances of `word` in `content` and send them out in a stream' inPorts: + content: + datatype: 'string' + description: 'the content which we look for a word in' + required: true word: datatype: 'string' # could be array|string, which would be `all` description: 'the word we are looking for instances of' control: true required: true - content: - datatype: 'string' - description: 'the content which we look for the word in' - required: true surrounding: # could use a regex but this is a specific case datatype: 'boolean' description: 'whether to get surrounding characters, symbols before and after until space' @@ -42,21 +48,25 @@ exports.getComponent = -> description: 'the resulting findings as a stream of data packets' required: true - # we are only using data, - # so we do not need any brackets sent to the inPorts, pass them along + # ## Processing function # - # control ports do not have brackets, - # so we don't need to do anything special with them + # To preserve streams, forward brackets from the primary inport `content` to the output. c.forwardBrackets = content: 'matches' c.process (input, output) -> - # make sure we have data in the required inPorts + + # ### Receiving input data + # + # We need both a `word`, and `content` to start processing + # Since `word` is a control port, the latest value is kept, no need to continiously send return unless input.hasData 'word', 'content' - # get the data from our in ports [ word, content ] = input.getData 'word', 'content' + # ### Component business logic + # # since we are sending out multiple `data` IPs # we want to wrap them in brackets + # TODO: make exception safe output.send matches: new noflo.IP 'openBracket', content # do our word processing @@ -64,6 +74,8 @@ exports.getComponent = -> matches = matchAll content, r matches = actualMatches matches + # ### Sending output + # # for each of our matches, send them out for match in matches # if you just send content, it will automatically put it in a data ip diff --git a/components/WordScore.coffee b/components/WordScore.coffee index 598757c..d47a5ec 100755 --- a/components/WordScore.coffee +++ b/components/WordScore.coffee @@ -1,7 +1,9 @@ +# ## Import libraries noflo = require 'noflo' natural = require 'natural' tokenizer = new natural.WordTokenizer() +# ## Component declaration exports.getComponent = -> c = new noflo.Component description: 'Find how the input words compare against the list of weighted words' @@ -21,13 +23,16 @@ exports.getComponent = -> description: 'the resulting number of comparing the content with the list' required: true - # we are only using data, so we do not need any brackets sent to the inPorts, pass them along + # ## Processing function + # + # To preserve streams, forward brackets from the inports to the output. c.forwardBrackets = list: 'out' content: 'out' c.process (input, output) -> - # our precondition, make sure it has both before trying to get the data + + # ## Receive input return unless input.has 'list', 'content', (ip) -> ip.type is 'data' # get the data @@ -37,6 +42,7 @@ exports.getComponent = -> content = ((input.getStream('content').filter (ip) -> ip.type is 'data').map (ip) -> ip.data)[0] list = input.getStream('list')[0].data + # ## Component business logic # our base score we will send out score = 0 @@ -88,6 +94,7 @@ exports.getComponent = -> score += scoringFunction data + # ## Send output # we could do `output.sendDone score` if we wanted # since there is only one outport it will know which one we mean output.sendDone score: score From c4a86c77d90cb96caa03f138265f1dcf9cf67f3d Mon Sep 17 00:00:00 2001 From: Jon Nordby Date: Mon, 6 Mar 2017 13:49:42 +0100 Subject: [PATCH 18/41] tests: Remove noflo-tester use We do fbp-spec for graphs+components, and will use Mocha for testing the JS API --- spec/CanadiannessNofloTester.coffee | 42 ----------------------------- 1 file changed, 42 deletions(-) delete mode 100644 spec/CanadiannessNofloTester.coffee diff --git a/spec/CanadiannessNofloTester.coffee b/spec/CanadiannessNofloTester.coffee deleted file mode 100644 index d58f3b1..0000000 --- a/spec/CanadiannessNofloTester.coffee +++ /dev/null @@ -1,42 +0,0 @@ -Tester = require 'noflo-wrapper' -chai = require 'chai' - -describe 'FindWords component', -> - t = new Tester 'canadianness/FindWords', cache: false - before (done) -> - t.start (err, instance) -> - return throw err if err - done() - - describe 'with content eh', -> - it 'should be find one `eh`', (done) -> - # will only listen once and trigger after disconnect - t.receive 'matches', (data) -> - chai.expect(data).to.eql 'eh' - done() - - t.ins.word.send 'eh' - t.ins.surrounding.send false - t.ins.content.send 'eh' - - describe 'with content that has no `eh`s', -> - it 'should send an empty array', (done) -> - t.receive 'matches', (data) -> - chai.expect(data).to.eql [] - done() - t.ins.word.send 'eh' - t.ins.surrounding.send false - t.ins.content.send 'A string without it is a sad string.' - - describe 'with content that has multiple `eh`s', -> - it 'should send an array of ehs', (done) -> - expect = ['Eh...', 'eh?', 'EH!'] - t.outs.matches.on 'ip', (ip) -> - if ip.type is 'data' - chai.expect(ip.data).to.eql expect.shift() - if ip.type is 'closeBracket' - done() - - t.ins.word.send 'eh' - t.ins.surrounding.send true - t.ins.content.send 'Eh... eh? EH!' From 1e29a1a1d69aa81e80aabb94110b1c6b39d7868d Mon Sep 17 00:00:00 2001 From: Jon Nordby Date: Mon, 6 Mar 2017 15:55:57 +0100 Subject: [PATCH 19/41] index: Expose API and implement CLI --- index.coffee | 44 +++++++++++++++++++++++++++++++++----------- index.js | 2 ++ package.json | 1 - 3 files changed, 35 insertions(+), 12 deletions(-) create mode 100644 index.js diff --git a/index.coffee b/index.coffee index 0a8c607..e7749e6 100755 --- a/index.coffee +++ b/index.coffee @@ -6,16 +6,16 @@ unless noflo.isBrowser() else baseDir = '/canadianness' -spellingData = require './spellingdata.json' -listData = {"eh": 11, "eh!": 11} +defaultSpellingData = require './spellingdata.json' +defaultWords = {"eh": 11, "eh!": 11} -canadianness = (args, cb) -> - spellingData = args['spelling'] - wordsData = args['words'] +canadianness = (contentData, options, callback) -> + spellingData = options.spelling or defaultSpellingData + wordsData = options.words or defaultWords # debugging [optional] - debug = args['debug'] or false - contentData = args['content'] + debug = options.debug or false + # FIXME: use asCallback from NoFlo 0.8.2+ loader = new noflo.ComponentLoader baseDir # project name / graph or component name loader.load 'canadianness/Canadianness', (err, instance) -> @@ -29,7 +29,7 @@ canadianness = (args, cb) -> if debug tracer.attach instance.network - instance.start() + instance.start () -> # outPorts score = noflo.internalSocket.createSocket() @@ -58,7 +58,10 @@ canadianness = (args, cb) -> # and log where we wrote it to finished = -> return unless scoreData? and emotionData? - cb emotionData, scoreData + data = + score: scoreData + emotion: emotionData + return callback null, data, scoreData if debug tracer.dumpFile null, (err, f) -> @@ -79,5 +82,24 @@ canadianness = (args, cb) -> spelling.send spellingData content.send contentData -canadianness {spelling: spellingData, words: listData, content: 'eh', debug: true}, (score, emotion) -> - console.log score, emotion +# Expose function as public API +module.exports = canadianness + +# ## Command-line program +main = () -> + content = process.argv[2] + + options = + spelling: null + words: null + debug: true + + canadianness content, options, (err, results) -> + if err + console.error err + process.exit 1 + console.log results.score, results.emotion + +# Only run main if we are not imported as a module +if not module.parent + main() diff --git a/index.js b/index.js new file mode 100644 index 0000000..94c8b89 --- /dev/null +++ b/index.js @@ -0,0 +1,2 @@ +require('coffee-script/register'); +module.exports = require('./index.coffee'); diff --git a/package.json b/package.json index 192fd2b..11e4298 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,6 @@ "candian", "canadianness" ], - "main": "./index.coffee", "author": "aretecode ", "license": "MIT", "repository": { From 38c75765334837366392b6dfda4112e77a21345f Mon Sep 17 00:00:00 2001 From: Jon Nordby Date: Mon, 6 Mar 2017 16:05:10 +0100 Subject: [PATCH 20/41] tests: Test the JavaScript API in JS --- spec/API.coffee | 14 ++ spec/Canadianness.coffee | 275 --------------------------------------- 2 files changed, 14 insertions(+), 275 deletions(-) create mode 100755 spec/API.coffee delete mode 100755 spec/Canadianness.coffee diff --git a/spec/API.coffee b/spec/API.coffee new file mode 100755 index 0000000..3257c2c --- /dev/null +++ b/spec/API.coffee @@ -0,0 +1,14 @@ +canadianness = require '../index.js' +chai = require 'chai' + +describe 'Javascript API', -> + + describe 'calling with sad content', -> + content = 'life is hard and then you die, ...eh' + it 'should return emotion=sadness', (done) -> + canadianness content, {}, (err, result) -> + chai.expect(err).to.not.exist + chai.expect(result).to.include.keys ['emotion', 'score'] + chai.expect(result.emotion).to.equal 'sadness' + chai.expect(result.score).to.be.above 5 + return done() diff --git a/spec/Canadianness.coffee b/spec/Canadianness.coffee deleted file mode 100755 index bf2d212..0000000 --- a/spec/Canadianness.coffee +++ /dev/null @@ -1,275 +0,0 @@ -noflo = require 'noflo' - -# if you want to run your tests on the browser builds using phantom -unless noflo.isBrowser() - chai = require 'chai' - path = require 'path' - baseDir = path.resolve __dirname, '../' -else - baseDir = 'canadianness' - -spellingData = require '../spellingdata.json' - -# how we test the components first, then the graph as a whole -# because then we do not have to -# figure out where along the graph the problem is -describe 'Canadianness graph', -> - listData = {"eh": 11, "eh!": 11} - - c = null - content = null - spelling = null - words = null - emotion = null - score = null - - # we are using this because we are waiting for both port event listeners - # to receive data - emotionData = null - scoreData = null - doDone = (done) -> - # if both are set, it is done, so reset test state - if scoreData? and emotionData? - scoreData = null - emotionData = null - done() - - # we only need to load the graph once, so it is in the before - before (done) -> - @timeout 10*1000 - loader = new noflo.ComponentLoader baseDir - loader.load 'canadianness/Canadianness', (err, instance) -> - return done err if err - - # but we need to access the instance elsewhere, - # so it is assigned to the scoped variable - c = instance - - # because it is a graph, we want to wait until it is ready - c.once 'ready', -> - c.start () -> - # for asyncish - setTimeout done, 1 - - # before each test we want to attach all of the outports - # (we also attach the inports here as well so the `before` is simpler) - # and we want to detach the outports after each, - # otherwise the event listeners in the test that ran before - # would get triggered again - beforeEach -> - content = noflo.internalSocket.createSocket() - spelling = noflo.internalSocket.createSocket() - words = noflo.internalSocket.createSocket() - c.inPorts.content.attach content - c.inPorts.spelling.attach spelling - c.inPorts.words.attach words - - emotion = noflo.internalSocket.createSocket() - score = noflo.internalSocket.createSocket() - c.outPorts.emotion.attach emotion - c.outPorts.score.attach score - afterEach -> - c.outPorts.emotion.detach emotion - c.outPorts.score.detach score - - describe 'content "A bunch of centers had a color cancelation."', -> - it 'should be neutral, and uncanadian', (done) -> - score.on 'data', (data) -> - chai.expect(data).to.eql -3 - scoreData = data - doDone done - - emotion.on 'data', (data) -> - chai.expect(data).to.eql 'neutral' - emotionData = data - doDone done - - spelling.send spellingData - words.send listData - content.send 'A bunch of centers had a color cancelation.' - - describe 'content eh', -> - it 'should be neutral, yet highly Canadian', (done) -> - score.on 'data', (data) -> - chai.expect(data).to.eql 11 - scoreData = data - doDone done - - emotion.on 'data', (data) -> - chai.expect(data).to.eql 'neutral' - emotionData = data - doDone done - - spelling.send spellingData - words.send listData - content.send 'eh' - - describe 'content "eh!"', -> - it 'should be joyful, and canadian', (done) -> - score.on 'data', (data) -> - chai.expect(data).to.eql 11 - scoreData = data - doDone done - - emotion.on 'data', (data) -> - chai.expect(data).to.eql 'joy' - emotionData = data - doDone done - - spelling.send spellingData - words.send listData - content.send 'eh!' - -describe 'WordScore component', -> - listData = require '../spellingdata.json' - - c = null - content = null - list = null - score = null - before (done) -> - @timeout 4000 - loader = new noflo.ComponentLoader baseDir - loader.load 'canadianness/WordScore', (err, instance) -> - return done err if err - c = instance - content = noflo.internalSocket.createSocket() - list = noflo.internalSocket.createSocket() - c.inPorts.content.attach content - c.inPorts.list.attach list - done() - beforeEach -> - score = noflo.internalSocket.createSocket() - c.outPorts.score.attach score - afterEach -> - c.outPorts.score.detach score - - describe 'with content `ardour eh`', -> - it 'should be Canadian', (done) -> - score.on 'data', (data) -> - chai.expect(data).to.eql 1 - done() - - list.send listData - content.send 'ardour eh?' - - describe 'with content `ax`', -> - it 'should be not Canadian', (done) -> - score.on 'data', (data) -> - chai.expect(data).to.eql -1 - done() - - list.send listData - content.send 'ax' - -describe 'FindWords component', -> - c = null - word = null - surrounding = null - content = null - matches = null - before (done) -> - @timeout 4000 - loader = new noflo.ComponentLoader baseDir - loader.load 'canadianness/FindWords', (err, instance) -> - return done err if err - c = instance - word = noflo.internalSocket.createSocket() - content = noflo.internalSocket.createSocket() - surrounding = noflo.internalSocket.createSocket() - c.inPorts.word.attach word - c.inPorts.content.attach content - c.inPorts.surrounding.attach surrounding - done() - beforeEach -> - matches = noflo.internalSocket.createSocket() - c.outPorts.matches.attach matches - afterEach -> - c.outPorts.matches.detach matches - - describe 'with content eh', -> - it 'should be find one `eh`', (done) -> - matches.on 'data', (data) -> - chai.expect(data).to.eql 'eh' - done() - - word.send 'eh' - surrounding.send false - content.send 'eh' - - describe 'with content that has no `eh`s', -> - it 'should send an empty array', (done) -> - matches.on 'data', (data) -> - chai.expect(data).to.eql [] - done() - word.send 'eh' - surrounding.send false - content.send 'A string without it is a sad string.' - - describe 'with content that has multiple `eh`s', -> - it 'should send an array of ehs', (done) -> - expect = ['Eh...', 'eh?', 'EH!'] - matches.on 'ip', (ip) -> - if ip.type is 'data' - chai.expect(ip.data).to.eql expect.shift() - if ip.type is 'closeBracket' - done() - - word.send 'eh' - surrounding.send true - content.send 'Eh... eh? EH!' - -describe 'DetermineEmotion component', -> - c = null - emotion = null - content = null - error = null - before (done) -> - @timeout 4000 - loader = new noflo.ComponentLoader baseDir - loader.load 'canadianness/DetermineEmotion', (err, instance) -> - return done err if err - c = instance - content = noflo.internalSocket.createSocket() - c.inPorts.content.attach content - done() - beforeEach -> - emotion = noflo.internalSocket.createSocket() - error = noflo.internalSocket.createSocket() - c.outPorts.emotion.attach emotion - c.outPorts.error.attach error - afterEach -> - c.outPorts.emotion.detach emotion - c.outPorts.error.detach error - - describe 'with content eh', -> - it 'should be neutral', (done) -> - emotion.on 'data', (data) -> - chai.expect(data).to.eql 'neutral' - done() - - content.send new noflo.IP 'openBracket' - content.send new noflo.IP 'data', 'eh' - content.send new noflo.IP 'closeBracket' - - describe 'with content eh!', -> - it 'should be joyful', (done) -> - emotion.on 'data', (data) -> - chai.expect(data).to.eql 'joy' - done() - - content.send new noflo.IP 'openBracket' - content.send new noflo.IP 'data', 'eh!' - content.send new noflo.IP 'closeBracket' - - describe 'with content [eh?, eh!?, Eh?]', -> - it 'should be amusement', (done) -> - emotion.on 'data', (data) -> - chai.expect(data).to.eql 'amusement' - done() - - content.send new noflo.IP 'openBracket' - content.send new noflo.IP 'data', 'eh?' - content.send new noflo.IP 'data', 'eh!?' - content.send new noflo.IP 'data', 'Eh?' - content.send new noflo.IP 'closeBracket' From b63124b25f55e2623f8f860d1bffa1c03395e4a8 Mon Sep 17 00:00:00 2001 From: Jon Nordby Date: Mon, 6 Mar 2017 16:52:23 +0100 Subject: [PATCH 21/41] tests: Prettier names --- spec/canadianness.yaml | 2 +- spec/determineemotion.yaml | 2 +- spec/findwords.yaml | 1 - 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/spec/canadianness.yaml b/spec/canadianness.yaml index beae2fe..2f95f3b 100644 --- a/spec/canadianness.yaml +++ b/spec/canadianness.yaml @@ -1,5 +1,5 @@ topic: "canadianness/Canadianness" -name: "Canadianness fbpspec" +name: "Canadianness graph" fixture: type: 'fbp' data: | diff --git a/spec/determineemotion.yaml b/spec/determineemotion.yaml index c4225e8..b588406 100644 --- a/spec/determineemotion.yaml +++ b/spec/determineemotion.yaml @@ -1,5 +1,5 @@ topic: "canadianness/DetermineEmotion" -name: "Determine Emotion fbpspec" +name: "DetermineEmotion component" timeout: 10000 fixture: type: 'fbp' diff --git a/spec/findwords.yaml b/spec/findwords.yaml index aec97c5..77a132d 100644 --- a/spec/findwords.yaml +++ b/spec/findwords.yaml @@ -1,5 +1,4 @@ topic: "canadianness/FindWords" -name: "Find words fbpspec" cases: - name: 'content eh' From 1686292a0a8dbf78710373c57bc0ea159cfeada8 Mon Sep 17 00:00:00 2001 From: Jon Nordby Date: Mon, 6 Mar 2017 16:35:25 +0100 Subject: [PATCH 22/41] WordScore: Clean up old input handling --- components/WordScore.coffee | 31 +++++++++++++------------------ 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/components/WordScore.coffee b/components/WordScore.coffee index d47a5ec..dc8bd18 100755 --- a/components/WordScore.coffee +++ b/components/WordScore.coffee @@ -25,29 +25,26 @@ exports.getComponent = -> # ## Processing function # - # To preserve streams, forward brackets from the inports to the output. - c.forwardBrackets = - list: 'out' - content: 'out' + # To preserve streams, forward brackets from the primary inport to the output. + c.forwardBrackets = {} c.process (input, output) -> - # ## Receive input - return unless input.has 'list', 'content', (ip) -> ip.type is 'data' + # ### Receive input + return unless input.hasStream 'content' + return unless input.hasData 'list' + content = input.getStream('content').filter((ip) -> ip.type is 'data').map((ip) -> ip.data) + list = input.getData 'list' - # get the data - # content = input.getData 'content' - # list = input.getData 'list' - # @TODO: temporary hack since getData does not behave as one expects, change when fixed - content = ((input.getStream('content').filter (ip) -> ip.type is 'data').map (ip) -> ip.data)[0] - list = input.getStream('list')[0].data + # there can be multiple pieces of content + content = content.join('\n') - # ## Component business logic + # ### Component business logic # our base score we will send out score = 0 # splits content into an array of words - contents = tokenizer.tokenize content + tokens = tokenizer.tokenize content # if the list has the word in it, return the score # otherwise, 0 points @@ -82,7 +79,7 @@ exports.getComponent = -> nounInflector = new natural.NounInflector() # go through each item in contents - for data in contents + for data in tokens plural = nounInflector.pluralize data singular = nounInflector.singularize data @@ -94,7 +91,5 @@ exports.getComponent = -> score += scoringFunction data - # ## Send output - # we could do `output.sendDone score` if we wanted - # since there is only one outport it will know which one we mean + # ### Send output output.sendDone score: score From 1f3481fcdc8423688a7277e3d0e15c245774aea9 Mon Sep 17 00:00:00 2001 From: Jon Nordby Date: Mon, 6 Mar 2017 17:27:36 +0100 Subject: [PATCH 23/41] API: Use noflo.asCallback helper --- index.coffee | 74 ++++++---------------------------------------------- package.json | 6 ++--- 2 files changed, 10 insertions(+), 70 deletions(-) diff --git a/index.coffee b/index.coffee index e7749e6..d021025 100755 --- a/index.coffee +++ b/index.coffee @@ -1,5 +1,4 @@ noflo = require 'noflo' -trace = require('noflo-runtime-base').trace unless noflo.isBrowser() baseDir = __dirname @@ -15,72 +14,15 @@ canadianness = (contentData, options, callback) -> # debugging [optional] debug = options.debug or false - # FIXME: use asCallback from NoFlo 0.8.2+ - loader = new noflo.ComponentLoader baseDir - # project name / graph or component name - loader.load 'canadianness/Canadianness', (err, instance) -> - throw err if err + componentName = 'canadianness/Canadianness' + inputs = + words: wordsData + spelling: spellingData + content: contentData - if debug - # instantiate our Tracer - tracer = new trace.Tracer() - - instance.once 'ready', -> - if debug - tracer.attach instance.network - - instance.start () -> - - # outPorts - score = noflo.internalSocket.createSocket() - emotion = noflo.internalSocket.createSocket() - - # inPorts - spelling = noflo.internalSocket.createSocket() - words = noflo.internalSocket.createSocket() - content = noflo.internalSocket.createSocket() - - # attach them - instance.inPorts.content.attach content - instance.inPorts.spelling.attach spelling - instance.inPorts.words.attach words - instance.outPorts.score.attach score - instance.outPorts.emotion.attach emotion - - # scoped variables since we don't know which data comes in first - scoreData = null - emotionData = null - - # when we listen for data, we can call this - # to check if both have received data - # when they have, call the callback - # and then, if we are debugging, write the trace - # and log where we wrote it to - finished = -> - return unless scoreData? and emotionData? - data = - score: scoreData - emotion: emotionData - return callback null, data, scoreData - - if debug - tracer.dumpFile null, (err, f) -> - throw err if err - console.log 'Wrote flowtrace to', f - - # listen for data - score.on 'data', (data) -> - scoreData = data - finished() - - emotion.on 'data', (data) -> - emotionData = data - finished() - - # send the data - words.send wordsData - spelling.send spellingData - content.send contentData + wrapperFunction = noflo.asCallback componentName + wrapperFunction inputs, (err, results) -> + return callback err, results # Expose function as public API module.exports = canadianness diff --git a/package.json b/package.json index 11e4298..ef7ca81 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "dependencies": { "coffee-script": "^1.12.0", "natural": "^0.4.0", - "noflo": "0.x >= 0.8", + "noflo": "0.x >= 0.8.2", "noflo-core": "^0.4.0", "noflo-math": "^0.1.1" }, @@ -31,9 +31,7 @@ "mocha": "^2.5.3", "noflo-filesystem": "^1.1.1", "noflo-nodejs": "^0.8.1", - "noflo-runtime-base": "^0.8.2", - "noflo-strings": "^0.3.0", - "noflo-wrapper": "^0.1.2" + "noflo-strings": "^0.3.0" }, "scripts": { "start": "noflo-nodejs --trace --debug", From 5f985d65af5996cbd65e6406321e382ceecd4327 Mon Sep 17 00:00:00 2001 From: Henri Bergius Date: Mon, 13 Nov 2017 15:28:46 +0100 Subject: [PATCH 24/41] Remove Grunt and start ES6 port --- .gitignore | 2 -- Gruntfile.coffee | 32 ------------------------------ index.coffee | 47 --------------------------------------------- spec/API.coffee | 14 -------------- spec/API.js | 18 +++++++++++++++++ spec/fbpspec.coffee | 15 --------------- spec/fbpspec.js | 17 ++++++++++++++++ 7 files changed, 35 insertions(+), 110 deletions(-) delete mode 100755 Gruntfile.coffee delete mode 100755 index.coffee delete mode 100755 spec/API.coffee create mode 100644 spec/API.js delete mode 100644 spec/fbpspec.coffee create mode 100644 spec/fbpspec.js diff --git a/.gitignore b/.gitignore index 82372cb..ecafe7b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,4 @@ /node_modules/ -spec/*.js -spec/browser/*.js npm-debug.log .DS_Store .noflo.json diff --git a/Gruntfile.coffee b/Gruntfile.coffee deleted file mode 100755 index 51b47de..0000000 --- a/Gruntfile.coffee +++ /dev/null @@ -1,32 +0,0 @@ -module.exports = -> - # Project configuration - @initConfig - pkg: @file.readJSON 'package.json' - - # load all of the .coffee files inside of our /spec directory - mochaTest: - nodejs: - src: ['spec/*.coffee'] - options: - reporter: 'spec' - timeout: 20000 - require: 'coffee-script/register' - grep: process.env.TESTS - - # Coding standards - coffeelint: - all: - files: - src: ['components/*.coffee', 'spec/*.coffee'] - options: - max_line_length: - value: 80 - level: 'ignore' - - # Grunt plugins used for testing - @loadNpmTasks 'grunt-mocha-test' - @loadNpmTasks 'grunt-coffeelint' - - # Our local tasks - @registerTask 'test', ['coffeelint', 'mochaTest'] - @registerTask 'default', ['test'] diff --git a/index.coffee b/index.coffee deleted file mode 100755 index d021025..0000000 --- a/index.coffee +++ /dev/null @@ -1,47 +0,0 @@ -noflo = require 'noflo' - -unless noflo.isBrowser() - baseDir = __dirname -else - baseDir = '/canadianness' - -defaultSpellingData = require './spellingdata.json' -defaultWords = {"eh": 11, "eh!": 11} - -canadianness = (contentData, options, callback) -> - spellingData = options.spelling or defaultSpellingData - wordsData = options.words or defaultWords - # debugging [optional] - debug = options.debug or false - - componentName = 'canadianness/Canadianness' - inputs = - words: wordsData - spelling: spellingData - content: contentData - - wrapperFunction = noflo.asCallback componentName - wrapperFunction inputs, (err, results) -> - return callback err, results - -# Expose function as public API -module.exports = canadianness - -# ## Command-line program -main = () -> - content = process.argv[2] - - options = - spelling: null - words: null - debug: true - - canadianness content, options, (err, results) -> - if err - console.error err - process.exit 1 - console.log results.score, results.emotion - -# Only run main if we are not imported as a module -if not module.parent - main() diff --git a/spec/API.coffee b/spec/API.coffee deleted file mode 100755 index 3257c2c..0000000 --- a/spec/API.coffee +++ /dev/null @@ -1,14 +0,0 @@ -canadianness = require '../index.js' -chai = require 'chai' - -describe 'Javascript API', -> - - describe 'calling with sad content', -> - content = 'life is hard and then you die, ...eh' - it 'should return emotion=sadness', (done) -> - canadianness content, {}, (err, result) -> - chai.expect(err).to.not.exist - chai.expect(result).to.include.keys ['emotion', 'score'] - chai.expect(result.emotion).to.equal 'sadness' - chai.expect(result.score).to.be.above 5 - return done() diff --git a/spec/API.js b/spec/API.js new file mode 100644 index 0000000..3fce1e0 --- /dev/null +++ b/spec/API.js @@ -0,0 +1,18 @@ +const canadianness = require('../index.js'); +const chai = require('chai'); + +describe('Javascript API', () => + + describe('calling with sad content', () => { + const content = 'life is hard and then you die, ...eh'; + it('should return emotion=sadness', done => + canadianness(content, {}, (err, result) => { + chai.expect(err).to.not.exist; + chai.expect(result).to.include.keys(['emotion', 'score']); + chai.expect(result.emotion).to.equal('sadness'); + chai.expect(result.score).to.be.above(5); + done(); + }) + ); + }) +); diff --git a/spec/fbpspec.coffee b/spec/fbpspec.coffee deleted file mode 100644 index 3377f40..0000000 --- a/spec/fbpspec.coffee +++ /dev/null @@ -1,15 +0,0 @@ -fbpspec = require 'fbp-spec' - -nodeRuntime = - label: "NoFlo node.js" - description: "" - type: "noflo" - protocol: "websocket" - secret: 'notasecret' - address: "ws://localhost:3333" - id: "7807f4d8-63e0-4a89-a577-2770c14f8106" - command: './node_modules/.bin/noflo-nodejs --verbose --catch-exceptions=false --secret notasecret --port=3333 --host=localhost --register=false --debug=true' - -fbpspec.mocha.run nodeRuntime, './spec', - fixturetimeout: 10000 - starttimeout: 10000 diff --git a/spec/fbpspec.js b/spec/fbpspec.js new file mode 100644 index 0000000..d679511 --- /dev/null +++ b/spec/fbpspec.js @@ -0,0 +1,17 @@ +const fbpspec = require('fbp-spec'); + +const nodeRuntime = { + label: "NoFlo node.js", + description: "", + type: "noflo", + protocol: "websocket", + secret: 'notasecret', + address: "ws://localhost:3333", + id: "7807f4d8-63e0-4a89-a577-2770c14f8106", + command: './node_modules/.bin/noflo-nodejs --verbose --catch-exceptions=false --secret notasecret --port=3333 --host=localhost --register=false --debug=true' +}; + +fbpspec.mocha.run(nodeRuntime, './spec', { + fixturetimeout: 10000, + starttimeout: 10000 +}); From 5996d8f3816be860fa4fb7b645e8575442137c98 Mon Sep 17 00:00:00 2001 From: Henri Bergius Date: Mon, 13 Nov 2017 15:38:49 +0100 Subject: [PATCH 25/41] Port components to ES6 --- components/ArrayToStream.coffee | 29 -------- components/ArrayToStream.js | 40 ++++++++++ components/DetermineEmotion.coffee | 92 ----------------------- components/DetermineEmotion.js | 112 ++++++++++++++++++++++++++++ components/FindWords.coffee | 86 --------------------- components/FindWords.js | 101 +++++++++++++++++++++++++ components/WordScore.coffee | 95 ----------------------- components/WordScore.js | 116 +++++++++++++++++++++++++++++ index.js | 55 +++++++++++++- 9 files changed, 422 insertions(+), 304 deletions(-) delete mode 100644 components/ArrayToStream.coffee create mode 100644 components/ArrayToStream.js delete mode 100755 components/DetermineEmotion.coffee create mode 100644 components/DetermineEmotion.js delete mode 100755 components/FindWords.coffee create mode 100644 components/FindWords.js delete mode 100755 components/WordScore.coffee create mode 100644 components/WordScore.js diff --git a/components/ArrayToStream.coffee b/components/ArrayToStream.coffee deleted file mode 100644 index ea1d330..0000000 --- a/components/ArrayToStream.coffee +++ /dev/null @@ -1,29 +0,0 @@ -noflo = require 'noflo' - -exports.getComponent = -> - c = new noflo.Component - description: 'Convert input array to a NoFlo stream' - inPorts: - in: - datatype: 'array' - description: 'data we want to send' - required: true - outPorts: - out: - datatype: 'string' - description: 'the data wrapped in brackets' - required: true - - c.process (input, output) -> - return unless input.hasData 'in' - - output.send out: new noflo.IP 'openBracket' - - datas = input.getData 'in' - unless Array.isArray datas - datas = [datas] - for data in datas - output.send out: new noflo.IP 'data', data - - output.send out: new noflo.IP 'closeBracket' - output.done() diff --git a/components/ArrayToStream.js b/components/ArrayToStream.js new file mode 100644 index 0000000..08b1062 --- /dev/null +++ b/components/ArrayToStream.js @@ -0,0 +1,40 @@ +const noflo = require('noflo'); + +exports.getComponent = function() { + const c = new noflo.Component({ + description: 'Convert input array to a NoFlo stream', + inPorts: { + in: { + datatype: 'array', + description: 'data we want to send', + required: true + } + }, + outPorts: { + out: { + datatype: 'string', + description: 'the data wrapped in brackets', + required: true + } + } + }); + + c.process((input, output) => { + if (!input.hasData('in')) { return; } + + output.send({out: new noflo.IP('openBracket')}); + + let datas = input.getData('in'); + if (!Array.isArray(datas)) { + datas = [datas]; + } + datas.forEach((data) => { + output.send({out: new noflo.IP('data', data)}); + }); + + output.send({out: new noflo.IP('closeBracket')}); + output.done(); + }); + + return c; +}; diff --git a/components/DetermineEmotion.coffee b/components/DetermineEmotion.coffee deleted file mode 100755 index bcef182..0000000 --- a/components/DetermineEmotion.coffee +++ /dev/null @@ -1,92 +0,0 @@ -# ## Import libraries -noflo = require 'noflo' - -# ## Useful functions -# -# Function to calculate most common value (the [mode](https://en.wikipedia.org/wiki/Mode_(statistics)) -findMode = (array) -> - frequency = {} - maxFrequency = 0 - result = undefined - for v of array - frequency[array[v]] = (frequency[array[v]] or 0) + 1 - if frequency[array[v]] > maxFrequency - maxFrequency = frequency[array[v]] - result = array[v] - result - -# ## Component declaration -# -# Define the input and output ports, and describe their function -exports.getComponent = -> - c = new noflo.Component - description: 'Find all of the instances of `word` in `content` and send them out in a stream' - inPorts: - content: - datatype: 'string' - description: 'the content which we look for the word in' - required: true - outPorts: - emotion: - datatype: 'string' - description: 'the emotion based the content in ehs' - required: true - error: - datatype: 'object' - - # ## Processing function - # - c.process (input, output) -> - - # ### Receiving input - # - # We expect a [stream](noflojs.org/documentation/process-api/#full-stream) - # Will also accept a single (non-bracketed) input packet, returned as a stream of length 1 - return unless input.hasStream 'content' - contents = input.getStream 'content' - - # The output will be a single packet (not a stream), - # hence we drop the `openBracket` and `closeBracket` - contents = contents.filter (ip) -> ip.type is 'data' - - # extract the data payload from the IP objects - contents = contents.map (ip) -> ip.data - - # ### Component business logic - # - # First find which emotions are present, then calculate which one is most common. - # This could alternatively be split into two dedicate components. - - # to hold the emotions found - matches = [] - - # the emotions we will use - emotions = - joy: ['eh!'] - neutral: ['eh'] - amusement: ['eh?', 'Eh?', 'Eh??'] - fear: ['eH??', 'eh??'] - surprise: ['eh !?', 'EH!?'] - anticipation: ['eh?!'] - excitment: ['EH!', 'eH!'] - sadness: ['...eh', '...eh...', '..eh', 'eh..', '..eh..'] - anger: ['EH!?', 'EH?'] - - # go through our content and our emotions - # then add them to our `matches` - for content in contents - for emotion, data of emotions - if content in data - matches.push emotion - - # if we didn't get any emotions, it default to 'neutral' - if matches.length is 0 - mode = 'neutral' - # if we did, we need to find the emotion that was the most common - else - mode = findMode matches - - # ### Send output - # - # Also signals completion by using `sendDone()` - output.sendDone emotion: mode diff --git a/components/DetermineEmotion.js b/components/DetermineEmotion.js new file mode 100644 index 0000000..1f05170 --- /dev/null +++ b/components/DetermineEmotion.js @@ -0,0 +1,112 @@ +// ## Import libraries +const noflo = require('noflo'); + +// ## Useful functions +// +// Function to calculate most common value (the [mode](https://en.wikipedia.org/wiki/Mode_(statistics)) +const findMode = function(array) { + const frequency = {}; + let maxFrequency = 0; + let result = undefined; + for (let v in array) { + frequency[array[v]] = (frequency[array[v]] || 0) + 1; + if (frequency[array[v]] > maxFrequency) { + maxFrequency = frequency[array[v]]; + result = array[v]; + } + } + return result; +}; + +// ## Component declaration +// +// Define the input and output ports, and describe their function +exports.getComponent = () => { + const c = new noflo.Component({ + description: 'Find all of the instances of `word` in `content` and send them out in a stream', + inPorts: { + content: { + datatype: 'string', + description: 'the content which we look for the word in', + required: true + } + }, + outPorts: { + emotion: { + datatype: 'string', + description: 'the emotion based the content in ehs', + required: true + }, + error: { + datatype: 'object' + } + } + }); + + // ## Processing function + // + c.process((input, output) => { + + // ### Receiving input + // + // We expect a [stream](noflojs.org/documentation/process-api/#full-stream) + // Will also accept a single (non-bracketed) input packet, returned as a stream of length 1 + let emotion, mode; + if (!input.hasStream('content')) { return; } + let contents = input.getStream('content'); + + // The output will be a single packet (not a stream), + // hence we drop the `openBracket` and `closeBracket` + contents = contents.filter(ip => ip.type === 'data'); + + // extract the data payload from the IP objects + contents = contents.map(ip => ip.data); + + // ### Component business logic + // + // First find which emotions are present, then calculate which one is most common. + // This could alternatively be split into two dedicate components. + + // to hold the emotions found + const matches = []; + + // the emotions we will use + const emotions = { + joy: ['eh!'], + neutral: ['eh'], + amusement: ['eh?', 'Eh?', 'Eh??'], + fear: ['eH??', 'eh??'], + surprise: ['eh !?', 'EH!?'], + anticipation: ['eh?!'], + excitment: ['EH!', 'eH!'], + sadness: ['...eh', '...eh...', '..eh', 'eh..', '..eh..'], + anger: ['EH!?', 'EH?'] + }; + + // go through our content and our emotions + // then add them to our `matches` + contents.forEach((content) => { + emotions.forEach((emotion) => { + const data = emotions[emotion]; + if (content.indexOf(data) !== -1) { + matches.push(emotion); + } + }); + }); + + // if we didn't get any emotions, it default to 'neutral' + if (matches.length === 0) { + mode = 'neutral'; + // if we did, we need to find the emotion that was the most common + } else { + mode = findMode(matches); + } + + // ### Send output + // + // Also signals completion by using `sendDone()` + output.sendDone({emotion: mode}); + }); + + return c; +}; diff --git a/components/FindWords.coffee b/components/FindWords.coffee deleted file mode 100755 index 7308f06..0000000 --- a/components/FindWords.coffee +++ /dev/null @@ -1,86 +0,0 @@ -# ## Import libraries -noflo = require 'noflo' - -# ## Helper functions -# -# Not NoFlo or even component-logic-specific, so nice to keep them separate - -# Return all RegExp matches on a string -matchAll = (string, regexp) -> - matches = [] - string.replace regexp, -> - arr = [].slice.call arguments, 0 - extras = arr.splice -2 - arr.index = extras[0] - arr.input = extras[1] - matches.push arr - return - if matches.length then matches else [] - -# Extract the actual data of the match result -actualMatches = (matches) -> - # because we want to send out an empty array if there are no matches - return [[]] if matches.length is 0 - matches.map (match) -> match[0] - -# ## Component declaration -exports.getComponent = -> - c = new noflo.Component - description: 'Find all of the instances of `word` in `content` and send them out in a stream' - inPorts: - content: - datatype: 'string' - description: 'the content which we look for a word in' - required: true - word: - datatype: 'string' # could be array|string, which would be `all` - description: 'the word we are looking for instances of' - control: true - required: true - surrounding: # could use a regex but this is a specific case - datatype: 'boolean' - description: 'whether to get surrounding characters, symbols before and after until space' - default: false # if nothing is sent to it, this is the default when `get`ting from it - control: true - outPorts: - matches: - datatype: 'string' - description: 'the resulting findings as a stream of data packets' - required: true - - # ## Processing function - # - # To preserve streams, forward brackets from the primary inport `content` to the output. - c.forwardBrackets = - content: 'matches' - c.process (input, output) -> - - # ### Receiving input data - # - # We need both a `word`, and `content` to start processing - # Since `word` is a control port, the latest value is kept, no need to continiously send - return unless input.hasData 'word', 'content' - [ word, content ] = input.getData 'word', 'content' - - # ### Component business logic - # - # since we are sending out multiple `data` IPs - # we want to wrap them in brackets - # TODO: make exception safe - output.send matches: new noflo.IP 'openBracket', content - - # do our word processing - r = /([.?!]*eh[.?!]*)/gi - matches = matchAll content, r - matches = actualMatches matches - - # ### Sending output - # - # for each of our matches, send them out - for match in matches - # if you just send content, it will automatically put it in a data ip - # so this is the same as `output.send matches: new noflo.IP 'data', match` - output.send matches: match - - # this is the same as doing `output.send` and then `output.done` - output.sendDone matches: new noflo.IP 'closeBracket', content diff --git a/components/FindWords.js b/components/FindWords.js new file mode 100644 index 0000000..ff83274 --- /dev/null +++ b/components/FindWords.js @@ -0,0 +1,101 @@ +// ## Import libraries +const noflo = require('noflo'); + +// ## Helper functions +// +// Not NoFlo or even component-logic-specific, so nice to keep them separate + +// Return all RegExp matches on a string +const matchAll = function(string, regexp) { + const matches = []; + string.replace(regexp, function() { + const arr = [].slice.call(arguments, 0); + const extras = arr.splice(-2); + arr.index = extras[0]; + arr.input = extras[1]; + matches.push(arr); + }); + if (matches.length) { return matches; } else { return []; } +}; + +// Extract the actual data of the match result +const actualMatches = function(matches) { + // because we want to send out an empty array if there are no matches + if (matches.length === 0) { return [[]]; } + return matches.map(match => match[0]); +}; + +// ## Component declaration +exports.getComponent = () => { + const c = new noflo.Component({ + description: 'Find all of the instances of `word` in `content` and send them out in a stream', + inPorts: { + content: { + datatype: 'string', + description: 'the content which we look for a word in', + required: true + }, + word: { + datatype: 'string', // could be array|string, which would be `all` + description: 'the word we are looking for instances of', + control: true, + required: true + }, + surrounding: { // could use a regex but this is a specific case + datatype: 'boolean', + description: 'whether to get surrounding characters, symbols before and after until space', + default: false, // if nothing is sent to it, this is the default when `get`ting from it + control: true + } + }, + outPorts: { + matches: { + datatype: 'string', + description: 'the resulting findings as a stream of data packets', + required: true + } + } + }); + + // ## Processing function + // + // To preserve streams, forward brackets from the primary inport `content` to the output. + c.forwardBrackets = { + content: ['matches'], + }; + c.process((input, output) => { + + // ### Receiving input data + // + // We need both a `word`, and `content` to start processing + // Since `word` is a control port, the latest value is kept, no need to continiously send + if (!input.hasData('word', 'content')) { return; } + const [ word, content ] = input.getData('word', 'content'); + + // ### Component business logic + // + // since we are sending out multiple `data` IPs + // we want to wrap them in brackets + // TODO: make exception safe + output.send({matches: new noflo.IP('openBracket', content)}); + + // do our word processing + const r = /([.?!]*eh[.?!]*)/gi; + let matches = matchAll(content, r); + matches = actualMatches(matches); + + // ### Sending output + // + // for each of our matches, send them out + matches.forEach((match) => { + // if you just send content, it will automatically put it in a data ip + // so this is the same as `output.send matches: new noflo.IP 'data', match` + output.send({matches: match}); + }); + + // this is the same as doing `output.send` and then `output.done` + return output.sendDone({matches: new noflo.IP('closeBracket', content)}); + }); + + return c; +}; diff --git a/components/WordScore.coffee b/components/WordScore.coffee deleted file mode 100755 index dc8bd18..0000000 --- a/components/WordScore.coffee +++ /dev/null @@ -1,95 +0,0 @@ -# ## Import libraries -noflo = require 'noflo' -natural = require 'natural' -tokenizer = new natural.WordTokenizer() - -# ## Component declaration -exports.getComponent = -> - c = new noflo.Component - description: 'Find how the input words compare against the list of weighted words' - inPorts: - list: - datatype: 'array' - description: 'list of words we will use with the list of content' - control: true - required: true - content: - datatype: 'string' - description: 'the content which we will determine the score of' - required: true - outPorts: - score: - datatype: 'number' - description: 'the resulting number of comparing the content with the list' - required: true - - # ## Processing function - # - # To preserve streams, forward brackets from the primary inport to the output. - c.forwardBrackets = {} - - c.process (input, output) -> - - # ### Receive input - return unless input.hasStream 'content' - return unless input.hasData 'list' - content = input.getStream('content').filter((ip) -> ip.type is 'data').map((ip) -> ip.data) - list = input.getData 'list' - - # there can be multiple pieces of content - content = content.join('\n') - - # ### Component business logic - # our base score we will send out - score = 0 - - # splits content into an array of words - tokens = tokenizer.tokenize content - - # if the list has the word in it, return the score - # otherwise, 0 points - wordScore = (word) -> - if list[word]? - return list[word] - else - return 0 - - # go through each of the comparisons in the list - # if it is Canadian: 1, American: -1, British: .5, None: 0 - spellingScore = (word) -> - for comparison in list - if word not in comparison["American"] - if word in comparison["Canadian"] - return 1 - else if word in comparison["British"] - return 0.5 - else - return -1 - - return 0 - - # if it has this, it is a spelling list - if list[0]?["Canadian"]? - scoringFunction = spellingScore - # otherwise it is an object list of words with scores - else - scoringFunction = wordScore - - # use this to singularize and pluralize each word - nounInflector = new natural.NounInflector() - - # go through each item in contents - for data in tokens - plural = nounInflector.pluralize data - singular = nounInflector.singularize data - - # if it is already plural or singular do not use it - if plural isnt data - score += scoringFunction plural - if singular isnt data - score += scoringFunction singular - - score += scoringFunction data - - # ### Send output - output.sendDone score: score diff --git a/components/WordScore.js b/components/WordScore.js new file mode 100644 index 0000000..936c71c --- /dev/null +++ b/components/WordScore.js @@ -0,0 +1,116 @@ +// ## Import libraries +const noflo = require('noflo'); +const natural = require('natural'); +const tokenizer = new natural.WordTokenizer(); + +// ## Component declaration +exports.getComponent = function() { + const c = new noflo.Component({ + description: 'Find how the input words compare against the list of weighted words', + inPorts: { + list: { + datatype: 'array', + description: 'list of words we will use with the list of content', + control: true, + required: true + }, + content: { + datatype: 'string', + description: 'the content which we will determine the score of', + required: true + } + }, + outPorts: { + score: { + datatype: 'number', + description: 'the resulting number of comparing the content with the list', + required: true + } + } + }); + + // ## Processing function + // + // To preserve streams, forward brackets from the primary inport to the output. + c.forwardBrackets = {}; + + c.process(function(input, output) { + + // ### Receive input + let scoringFunction; + if (!input.hasStream('content')) { return; } + if (!input.hasData('list')) { return; } + let content = input.getStream('content').filter(ip => ip.type === 'data').map(ip => ip.data); + const list = input.getData('list'); + + // there can be multiple pieces of content + content = content.join('\n'); + + // ### Component business logic + // our base score we will send out + let score = 0; + + // splits content into an array of words + const tokens = tokenizer.tokenize(content); + + // if the list has the word in it, return the score + // otherwise, 0 points + const wordScore = function(word) { + if (list[word] != null) { + return list[word]; + } else { + return 0; + } + }; + + // go through each of the comparisons in the list + // if it is Canadian: 1, American: -1, British: .5, None: 0 + const spellingScore = function(word) { + for (let comparison of Array.from(list)) { + if (!Array.from(comparison["American"]).includes(word)) { + if (Array.from(comparison["Canadian"]).includes(word)) { + return 1; + } else if (Array.from(comparison["British"]).includes(word)) { + return 0.5; + } + } else { + return -1; + } + } + + return 0; + }; + + // if it has this, it is a spelling list + if ((list[0] != null ? list[0]["Canadian"] : undefined) != null) { + scoringFunction = spellingScore; + // otherwise it is an object list of words with scores + } else { + scoringFunction = wordScore; + } + + // use this to singularize and pluralize each word + const nounInflector = new natural.NounInflector(); + + // go through each item in contents + for (let data of Array.from(tokens)) { + const plural = nounInflector.pluralize(data); + const singular = nounInflector.singularize(data); + + // if it is already plural or singular do not use it + if (plural !== data) { + score += scoringFunction(plural); + } + if (singular !== data) { + score += scoringFunction(singular); + } + + score += scoringFunction(data); + } + + // ### Send output + output.sendDone({score}); + }); + + return c; +}; diff --git a/index.js b/index.js index 94c8b89..adbb784 100644 --- a/index.js +++ b/index.js @@ -1,2 +1,53 @@ -require('coffee-script/register'); -module.exports = require('./index.coffee'); +const noflo = require('noflo'); +const defaultSpellingData = require('./spellingdata.json'); + +const defaultWords = { + eh: 11, + "eh!": 11, +}; + +const canadianness = (contentData, options, callback) => { + const spellingData = options.spelling || defaultSpellingData; + const wordsData = options.words || defaultWords; + // debugging [optional] + const debug = options.debug || false; + + const componentName = 'canadianness/Canadianness'; + const inputs = { + words: wordsData, + spelling: spellingData, + content: contentData, + }; + + const wrapperFunction = noflo.asCallback(componentName, { + baseDir: __dirname, + }); + return wrapperFunction(inputs, (err, results) => callback(err, results)); +}; + +// Expose function as public API +module.exports = canadianness; + +// ## Command-line program +const main = function() { + const content = process.argv[2]; + + const options = { + spelling: null, + words: null, + debug: true, + }; + + canadianness(content, options, function(err, results) { + if (err) { + console.error(err); + process.exit(1); + } + console.log(results.score, results.emotion); + }); +}; + +// Only run main if we are not imported as a module +if (!module.parent) { + main(); +} From 1618a04af26c976a47cceaa6d27976f052ed27d3 Mon Sep 17 00:00:00 2001 From: Henri Bergius Date: Mon, 13 Nov 2017 15:39:01 +0100 Subject: [PATCH 26/41] Add eslint --- .eslintrc.json | 3 +++ package.json | 28 +++++++++++++--------------- 2 files changed, 16 insertions(+), 15 deletions(-) create mode 100644 .eslintrc.json diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..7cde01d --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,3 @@ +{ + "extends": "airbnb-base" +} diff --git a/package.json b/package.json index ef7ca81..61b04ba 100644 --- a/package.json +++ b/package.json @@ -14,27 +14,25 @@ "url": "https://github.com/noflo/canadianness.git" }, "dependencies": { - "coffee-script": "^1.12.0", "natural": "^0.4.0", - "noflo": "0.x >= 0.8.2", + "noflo": "^1.0.0", "noflo-core": "^0.4.0", - "noflo-math": "^0.1.1" + "noflo-math": "^0.3.0" }, "devDependencies": { - "chai": "^3.5.0", - "coffeelint": "^1.13.0", - "fbp-spec": "^0.2.0", - "grunt": "^0.4.5", - "grunt-cli": "^1.2.0", - "grunt-coffeelint": "^0.0.13", - "grunt-mocha-test": "^0.12.2", - "mocha": "^2.5.3", - "noflo-filesystem": "^1.1.1", - "noflo-nodejs": "^0.8.1", - "noflo-strings": "^0.3.0" + "chai": "^4.1.2", + "eslint": "^4.11.0", + "eslint-config-airbnb-base": "^12.1.0", + "eslint-plugin-import": "^2.8.0", + "fbp-spec": "^0.4.0", + "mocha": "^4.0.1", + "noflo-filesystem": "^2.0.0", + "noflo-nodejs": "^0.9.0", + "noflo-strings": "^0.4.0" }, "scripts": { "start": "noflo-nodejs --trace --debug", - "test": "grunt test" + "pretest": "eslint *.js components/*.js", + "test": "mocha --require chai -R spec -t 2000 spec/*.js" } } From 1b23c9d1c105e4da68014dd3e1d41fc736d3eca3 Mon Sep 17 00:00:00 2001 From: Henri Bergius Date: Mon, 13 Nov 2017 15:39:14 +0100 Subject: [PATCH 27/41] No need to require chai --- spec/API.js | 1 - 1 file changed, 1 deletion(-) diff --git a/spec/API.js b/spec/API.js index 3fce1e0..88e6028 100644 --- a/spec/API.js +++ b/spec/API.js @@ -1,5 +1,4 @@ const canadianness = require('../index.js'); -const chai = require('chai'); describe('Javascript API', () => From afdef09b3cc6c938dba9d304277c6d394f654aa5 Mon Sep 17 00:00:00 2001 From: Henri Bergius Date: Mon, 13 Nov 2017 16:04:06 +0100 Subject: [PATCH 28/41] Make linter happy --- components/ArrayToStream.js | 27 +++++++++------ components/DetermineEmotion.js | 46 ++++++++++++------------- components/FindWords.js | 51 ++++++++++++++++------------ components/WordScore.js | 61 ++++++++++++++++++---------------- index.js | 12 +++---- 5 files changed, 105 insertions(+), 92 deletions(-) diff --git a/components/ArrayToStream.js b/components/ArrayToStream.js index 08b1062..d5d60a6 100644 --- a/components/ArrayToStream.js +++ b/components/ArrayToStream.js @@ -1,38 +1,45 @@ const noflo = require('noflo'); -exports.getComponent = function() { +exports.getComponent = () => { const c = new noflo.Component({ description: 'Convert input array to a NoFlo stream', inPorts: { in: { datatype: 'array', description: 'data we want to send', - required: true - } + required: true, + }, }, outPorts: { out: { datatype: 'string', description: 'the data wrapped in brackets', - required: true - } - } + required: true, + }, + }, }); c.process((input, output) => { if (!input.hasData('in')) { return; } - output.send({out: new noflo.IP('openBracket')}); - let datas = input.getData('in'); if (!Array.isArray(datas)) { datas = [datas]; } + + output.send({ + out: new noflo.IP('openBracket'), + }); + datas.forEach((data) => { - output.send({out: new noflo.IP('data', data)}); + output.send({ + out: new noflo.IP('data', data), + }); }); - output.send({out: new noflo.IP('closeBracket')}); + output.send({ + out: new noflo.IP('closeBracket'), + }); output.done(); }); diff --git a/components/DetermineEmotion.js b/components/DetermineEmotion.js index 1f05170..cc8521f 100644 --- a/components/DetermineEmotion.js +++ b/components/DetermineEmotion.js @@ -4,19 +4,19 @@ const noflo = require('noflo'); // ## Useful functions // // Function to calculate most common value (the [mode](https://en.wikipedia.org/wiki/Mode_(statistics)) -const findMode = function(array) { +function findMode(array) { const frequency = {}; let maxFrequency = 0; - let result = undefined; - for (let v in array) { - frequency[array[v]] = (frequency[array[v]] || 0) + 1; - if (frequency[array[v]] > maxFrequency) { - maxFrequency = frequency[array[v]]; - result = array[v]; + let result; + array.forEach((v) => { + frequency[v] = (frequency[v] || 0) + 1; + if (frequency[v] > maxFrequency) { + maxFrequency = frequency[v]; + result = v; } - } + }); return result; -}; +} // ## Component declaration // @@ -28,39 +28,34 @@ exports.getComponent = () => { content: { datatype: 'string', description: 'the content which we look for the word in', - required: true - } + required: true, + }, }, outPorts: { emotion: { datatype: 'string', description: 'the emotion based the content in ehs', - required: true + required: true, }, error: { - datatype: 'object' - } - } + datatype: 'object', + }, + }, }); // ## Processing function // c.process((input, output) => { - // ### Receiving input // // We expect a [stream](noflojs.org/documentation/process-api/#full-stream) // Will also accept a single (non-bracketed) input packet, returned as a stream of length 1 - let emotion, mode; if (!input.hasStream('content')) { return; } - let contents = input.getStream('content'); // The output will be a single packet (not a stream), // hence we drop the `openBracket` and `closeBracket` - contents = contents.filter(ip => ip.type === 'data'); - - // extract the data payload from the IP objects - contents = contents.map(ip => ip.data); + // and extract the data payload from the IP objects + const contents = input.getStream('content').filter(ip => ip.type === 'data').map(ip => ip.data); // ### Component business logic // @@ -80,7 +75,7 @@ exports.getComponent = () => { anticipation: ['eh?!'], excitment: ['EH!', 'eH!'], sadness: ['...eh', '...eh...', '..eh', 'eh..', '..eh..'], - anger: ['EH!?', 'EH?'] + anger: ['EH!?', 'EH?'], }; // go through our content and our emotions @@ -95,6 +90,7 @@ exports.getComponent = () => { }); // if we didn't get any emotions, it default to 'neutral' + let mode; if (matches.length === 0) { mode = 'neutral'; // if we did, we need to find the emotion that was the most common @@ -105,7 +101,9 @@ exports.getComponent = () => { // ### Send output // // Also signals completion by using `sendDone()` - output.sendDone({emotion: mode}); + output.sendDone({ + emotion: mode, + }); }); return c; diff --git a/components/FindWords.js b/components/FindWords.js index ff83274..58b7ca1 100644 --- a/components/FindWords.js +++ b/components/FindWords.js @@ -6,24 +6,26 @@ const noflo = require('noflo'); // Not NoFlo or even component-logic-specific, so nice to keep them separate // Return all RegExp matches on a string -const matchAll = function(string, regexp) { +function matchAll(string, regexp) { const matches = []; - string.replace(regexp, function() { - const arr = [].slice.call(arguments, 0); + string.replace(regexp, (...rest) => { + const arr = rest.slice(0); const extras = arr.splice(-2); - arr.index = extras[0]; - arr.input = extras[1]; + [arr.index, arr.input] = extras; matches.push(arr); }); - if (matches.length) { return matches; } else { return []; } -}; + if (matches.length) { + return matches; + } + return []; +} // Extract the actual data of the match result -const actualMatches = function(matches) { +function actualMatches(matches) { // because we want to send out an empty array if there are no matches if (matches.length === 0) { return [[]]; } return matches.map(match => match[0]); -}; +} // ## Component declaration exports.getComponent = () => { @@ -33,28 +35,28 @@ exports.getComponent = () => { content: { datatype: 'string', description: 'the content which we look for a word in', - required: true + required: true, }, word: { datatype: 'string', // could be array|string, which would be `all` description: 'the word we are looking for instances of', control: true, - required: true + required: true, }, surrounding: { // could use a regex but this is a specific case datatype: 'boolean', description: 'whether to get surrounding characters, symbols before and after until space', default: false, // if nothing is sent to it, this is the default when `get`ting from it - control: true - } + control: true, + }, }, outPorts: { matches: { datatype: 'string', description: 'the resulting findings as a stream of data packets', - required: true - } - } + required: true, + }, + }, }); // ## Processing function @@ -63,21 +65,24 @@ exports.getComponent = () => { c.forwardBrackets = { content: ['matches'], }; - c.process((input, output) => { + c.process((input, output) => { // ### Receiving input data // // We need both a `word`, and `content` to start processing // Since `word` is a control port, the latest value is kept, no need to continiously send if (!input.hasData('word', 'content')) { return; } - const [ word, content ] = input.getData('word', 'content'); + // const [word, content] = input.getData('word', 'content'); + const content = input.getData('content'); // ### Component business logic // // since we are sending out multiple `data` IPs // we want to wrap them in brackets // TODO: make exception safe - output.send({matches: new noflo.IP('openBracket', content)}); + output.send({ + matches: new noflo.IP('openBracket', content), + }); // do our word processing const r = /([.?!]*eh[.?!]*)/gi; @@ -90,11 +95,15 @@ exports.getComponent = () => { matches.forEach((match) => { // if you just send content, it will automatically put it in a data ip // so this is the same as `output.send matches: new noflo.IP 'data', match` - output.send({matches: match}); + output.send({ + matches: match, + }); }); // this is the same as doing `output.send` and then `output.done` - return output.sendDone({matches: new noflo.IP('closeBracket', content)}); + output.sendDone({ + matches: new noflo.IP('closeBracket', content), + }); }); return c; diff --git a/components/WordScore.js b/components/WordScore.js index 936c71c..fd67fc9 100644 --- a/components/WordScore.js +++ b/components/WordScore.js @@ -1,10 +1,11 @@ // ## Import libraries const noflo = require('noflo'); const natural = require('natural'); + const tokenizer = new natural.WordTokenizer(); // ## Component declaration -exports.getComponent = function() { +exports.getComponent = () => { const c = new noflo.Component({ description: 'Find how the input words compare against the list of weighted words', inPorts: { @@ -12,21 +13,21 @@ exports.getComponent = function() { datatype: 'array', description: 'list of words we will use with the list of content', control: true, - required: true + required: true, }, content: { datatype: 'string', description: 'the content which we will determine the score of', - required: true - } + required: true, + }, }, outPorts: { score: { datatype: 'number', description: 'the resulting number of comparing the content with the list', - required: true - } - } + required: true, + }, + }, }); // ## Processing function @@ -34,8 +35,7 @@ exports.getComponent = function() { // To preserve streams, forward brackets from the primary inport to the output. c.forwardBrackets = {}; - c.process(function(input, output) { - + c.process((input, output) => { // ### Receive input let scoringFunction; if (!input.hasStream('content')) { return; } @@ -55,34 +55,35 @@ exports.getComponent = function() { // if the list has the word in it, return the score // otherwise, 0 points - const wordScore = function(word) { + const wordScore = (word) => { if (list[word] != null) { return list[word]; - } else { - return 0; } + return 0; }; // go through each of the comparisons in the list // if it is Canadian: 1, American: -1, British: .5, None: 0 - const spellingScore = function(word) { - for (let comparison of Array.from(list)) { - if (!Array.from(comparison["American"]).includes(word)) { - if (Array.from(comparison["Canadian"]).includes(word)) { - return 1; - } else if (Array.from(comparison["British"]).includes(word)) { - return 0.5; - } - } else { - return -1; + const spellingScore = (word) => { + let value = 0; + list.forEach((comparison) => { + if (comparison.American.indexOf(word) !== -1) { + value = -1; + return; } - } - - return 0; + if (comparison.Canadian.indexOf(word) !== -1) { + value = 1; + return; + } + if (comparison.British.indexOf(word) !== -1) { + value = 0.5; + } + }); + return value; }; // if it has this, it is a spelling list - if ((list[0] != null ? list[0]["Canadian"] : undefined) != null) { + if ((list[0] != null ? list[0].Canadian : undefined) != null) { scoringFunction = spellingScore; // otherwise it is an object list of words with scores } else { @@ -93,7 +94,7 @@ exports.getComponent = function() { const nounInflector = new natural.NounInflector(); // go through each item in contents - for (let data of Array.from(tokens)) { + tokens.forEach((data) => { const plural = nounInflector.pluralize(data); const singular = nounInflector.singularize(data); @@ -106,10 +107,12 @@ exports.getComponent = function() { } score += scoringFunction(data); - } + }); // ### Send output - output.sendDone({score}); + output.sendDone({ + score, + }); }); return c; diff --git a/index.js b/index.js index adbb784..3b9ed5f 100644 --- a/index.js +++ b/index.js @@ -3,15 +3,12 @@ const defaultSpellingData = require('./spellingdata.json'); const defaultWords = { eh: 11, - "eh!": 11, + 'eh!': 11, }; const canadianness = (contentData, options, callback) => { const spellingData = options.spelling || defaultSpellingData; const wordsData = options.words || defaultWords; - // debugging [optional] - const debug = options.debug || false; - const componentName = 'canadianness/Canadianness'; const inputs = { words: wordsData, @@ -29,23 +26,22 @@ const canadianness = (contentData, options, callback) => { module.exports = canadianness; // ## Command-line program -const main = function() { +function main() { const content = process.argv[2]; const options = { spelling: null, words: null, - debug: true, }; - canadianness(content, options, function(err, results) { + canadianness(content, options, (err, results) => { if (err) { console.error(err); process.exit(1); } console.log(results.score, results.emotion); }); -}; +} // Only run main if we are not imported as a module if (!module.parent) { From 0fed614758f0df397209d948c18db55ec32f2fe2 Mon Sep 17 00:00:00 2001 From: Henri Bergius Date: Mon, 13 Nov 2017 16:25:45 +0100 Subject: [PATCH 29/41] Fix emotion matching --- components/DetermineEmotion.js | 7 +++++-- spec/API.js | 6 +++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/components/DetermineEmotion.js b/components/DetermineEmotion.js index cc8521f..8948ef4 100644 --- a/components/DetermineEmotion.js +++ b/components/DetermineEmotion.js @@ -43,6 +43,9 @@ exports.getComponent = () => { }, }); + // Since we want to work with a full stream, we disable bracket forwarding + c.forwardBrackets = {}; + // ## Processing function // c.process((input, output) => { @@ -81,9 +84,9 @@ exports.getComponent = () => { // go through our content and our emotions // then add them to our `matches` contents.forEach((content) => { - emotions.forEach((emotion) => { + Object.keys(emotions).forEach((emotion) => { const data = emotions[emotion]; - if (content.indexOf(data) !== -1) { + if (data.indexOf(content) !== -1) { matches.push(emotion); } }); diff --git a/spec/API.js b/spec/API.js index 88e6028..7ccca22 100644 --- a/spec/API.js +++ b/spec/API.js @@ -1,4 +1,5 @@ const canadianness = require('../index.js'); +const chai = require('chai'); describe('Javascript API', () => @@ -6,7 +7,10 @@ describe('Javascript API', () => const content = 'life is hard and then you die, ...eh'; it('should return emotion=sadness', done => canadianness(content, {}, (err, result) => { - chai.expect(err).to.not.exist; + if (err) { + done(err); + return; + } chai.expect(result).to.include.keys(['emotion', 'score']); chai.expect(result.emotion).to.equal('sadness'); chai.expect(result.score).to.be.above(5); From 7508d5bb8b18d55f1589ba93a55bbe8346cd3fef Mon Sep 17 00:00:00 2001 From: Henri Bergius Date: Mon, 13 Nov 2017 16:26:00 +0100 Subject: [PATCH 30/41] Simplify --- index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.js b/index.js index 3b9ed5f..5ff17c4 100644 --- a/index.js +++ b/index.js @@ -19,7 +19,7 @@ const canadianness = (contentData, options, callback) => { const wrapperFunction = noflo.asCallback(componentName, { baseDir: __dirname, }); - return wrapperFunction(inputs, (err, results) => callback(err, results)); + return wrapperFunction(inputs, callback); }; // Expose function as public API From b2aef1e26f187f49de87aee345fae880a0ac2252 Mon Sep 17 00:00:00 2001 From: Henri Bergius Date: Mon, 13 Nov 2017 16:26:22 +0100 Subject: [PATCH 31/41] Update natural lib --- package.json | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 61b04ba..2390f33 100644 --- a/package.json +++ b/package.json @@ -14,9 +14,8 @@ "url": "https://github.com/noflo/canadianness.git" }, "dependencies": { - "natural": "^0.4.0", + "natural": "^0.5.0", "noflo": "^1.0.0", - "noflo-core": "^0.4.0", "noflo-math": "^0.3.0" }, "devDependencies": { @@ -26,13 +25,15 @@ "eslint-plugin-import": "^2.8.0", "fbp-spec": "^0.4.0", "mocha": "^4.0.1", + "noflo-core": "^0.5.0", "noflo-filesystem": "^2.0.0", "noflo-nodejs": "^0.9.0", "noflo-strings": "^0.4.0" }, "scripts": { + "postinstall": "noflo-cache-preheat", "start": "noflo-nodejs --trace --debug", "pretest": "eslint *.js components/*.js", - "test": "mocha --require chai -R spec -t 2000 spec/*.js" + "test": "mocha -R spec -t 2000 spec/*.js" } } From 4aa6c8830f8ee6b04ad637de98fee922619c9247 Mon Sep 17 00:00:00 2001 From: Henri Bergius Date: Mon, 13 Nov 2017 16:28:11 +0100 Subject: [PATCH 32/41] Ensure Mocha quits --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2390f33..0aafa4a 100644 --- a/package.json +++ b/package.json @@ -34,6 +34,6 @@ "postinstall": "noflo-cache-preheat", "start": "noflo-nodejs --trace --debug", "pretest": "eslint *.js components/*.js", - "test": "mocha -R spec -t 2000 spec/*.js" + "test": "mocha -R spec -t 2000 --exit spec/*.js" } } From e1c36127b4d223f01cd0b881e4372f71f1fd6a9e Mon Sep 17 00:00:00 2001 From: Henri Bergius Date: Mon, 13 Nov 2017 16:28:22 +0100 Subject: [PATCH 33/41] Disable debug --- spec/fbpspec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/fbpspec.js b/spec/fbpspec.js index d679511..71b3c9c 100644 --- a/spec/fbpspec.js +++ b/spec/fbpspec.js @@ -8,7 +8,7 @@ const nodeRuntime = { secret: 'notasecret', address: "ws://localhost:3333", id: "7807f4d8-63e0-4a89-a577-2770c14f8106", - command: './node_modules/.bin/noflo-nodejs --verbose --catch-exceptions=false --secret notasecret --port=3333 --host=localhost --register=false --debug=true' + command: './node_modules/.bin/noflo-nodejs --catch-exceptions=false --secret notasecret --port=3333 --host=localhost --register=false --capture-output=true' }; fbpspec.mocha.run(nodeRuntime, './spec', { From ccdb5a132958135b847495acfa5897adf572b5be Mon Sep 17 00:00:00 2001 From: Henri Bergius Date: Mon, 13 Nov 2017 17:26:08 +0100 Subject: [PATCH 34/41] Simplify index --- index.js | 38 +++++++++++--------------------------- 1 file changed, 11 insertions(+), 27 deletions(-) diff --git a/index.js b/index.js index 5ff17c4..3a56df6 100644 --- a/index.js +++ b/index.js @@ -6,44 +6,28 @@ const defaultWords = { 'eh!': 11, }; -const canadianness = (contentData, options, callback) => { +// Produce the JavaScript entry point +function canadianness(contentData, options, callback) { + // Normalize options const spellingData = options.spelling || defaultSpellingData; const wordsData = options.words || defaultWords; - const componentName = 'canadianness/Canadianness'; + + // Convert options and input to a set of NoFlo packets to be sent const inputs = { words: wordsData, spelling: spellingData, content: contentData, }; + // Produce a NoFlo.asCallback wrapped function to execute our graph + const componentName = 'canadianness/Canadianness'; const wrapperFunction = noflo.asCallback(componentName, { baseDir: __dirname, }); - return wrapperFunction(inputs, callback); -}; - -// Expose function as public API -module.exports = canadianness; -// ## Command-line program -function main() { - const content = process.argv[2]; - - const options = { - spelling: null, - words: null, - }; - - canadianness(content, options, (err, results) => { - if (err) { - console.error(err); - process.exit(1); - } - console.log(results.score, results.emotion); - }); + // Run the graph with inputs and call callback + wrapperFunction(inputs, callback); } -// Only run main if we are not imported as a module -if (!module.parent) { - main(); -} +// Expose function as public API +module.exports = canadianness; From 53994bdf44e0507c48047cd7b2ed500aae49d5f3 Mon Sep 17 00:00:00 2001 From: "greenkeeper[bot]" Date: Mon, 27 Nov 2017 15:02:30 +0000 Subject: [PATCH 35/41] chore(package): update dependencies --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0aafa4a..2968def 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ "eslint": "^4.11.0", "eslint-config-airbnb-base": "^12.1.0", "eslint-plugin-import": "^2.8.0", - "fbp-spec": "^0.4.0", + "fbp-spec": "^0.5.0", "mocha": "^4.0.1", "noflo-core": "^0.5.0", "noflo-filesystem": "^2.0.0", From e6006aabb116928f46684683173f453ed0306711 Mon Sep 17 00:00:00 2001 From: "greenkeeper[bot]" Date: Mon, 27 Nov 2017 15:02:36 +0000 Subject: [PATCH 36/41] docs(readme): add Greenkeeper badge --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 164470b..42a3d89 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ [![Build Status](https://travis-ci.org/noflo/canadianness.svg?branch=master)](https://travis-ci.org/noflo/canadianness) # Canadianness +[![Greenkeeper badge](https://badges.greenkeeper.io/noflo/canadianness.svg)](https://greenkeeper.io/) + Basic example of programming with [NoFlo](https://noflojs.org). ## Prerequisites From 32b6623caa05e997fba71216a5cc09fe78dec865 Mon Sep 17 00:00:00 2001 From: Henri Bergius Date: Mon, 27 Nov 2017 16:08:07 +0100 Subject: [PATCH 37/41] Move badges --- README.md | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/README.md b/README.md index 42a3d89..0ee1049 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,4 @@ -[![Build Status](https://travis-ci.org/noflo/canadianness.svg?branch=master)](https://travis-ci.org/noflo/canadianness) -# Canadianness - -[![Greenkeeper badge](https://badges.greenkeeper.io/noflo/canadianness.svg)](https://greenkeeper.io/) +# Canadianness [![Build Status](https://travis-ci.org/noflo/canadianness.svg?branch=master)](https://travis-ci.org/noflo/canadianness) [![Greenkeeper badge](https://badges.greenkeeper.io/noflo/canadianness.svg)](https://greenkeeper.io/) Basic example of programming with [NoFlo](https://noflojs.org). From 72924e50b08d0c919eaa73fe6a4eb92c366795c0 Mon Sep 17 00:00:00 2001 From: Henri Bergius Date: Mon, 27 Nov 2017 16:08:13 +0100 Subject: [PATCH 38/41] Test on latest Node.js --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 8062c4d..1145be5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,5 @@ language: node_js sudo: false node_js: -- '6' +- 'lts/*' script: npm test From 2f113d1c034aeab9e5f6876cd182adc8d4aa16ed Mon Sep 17 00:00:00 2001 From: "greenkeeper[bot]" Date: Thu, 18 Jan 2018 08:43:33 +0000 Subject: [PATCH 39/41] chore(package): update mocha to version 5.0.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2968def..1ac034b 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,7 @@ "eslint-config-airbnb-base": "^12.1.0", "eslint-plugin-import": "^2.8.0", "fbp-spec": "^0.5.0", - "mocha": "^4.0.1", + "mocha": "^5.0.0", "noflo-core": "^0.5.0", "noflo-filesystem": "^2.0.0", "noflo-nodejs": "^0.9.0", From 6fbff57b33b700980b37d97da4e906843e77f507 Mon Sep 17 00:00:00 2001 From: "greenkeeper[bot]" Date: Thu, 22 Mar 2018 16:41:12 +0000 Subject: [PATCH 40/41] chore(package): update noflo-nodejs to version 0.10.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1ac034b..dbc21b7 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ "mocha": "^5.0.0", "noflo-core": "^0.5.0", "noflo-filesystem": "^2.0.0", - "noflo-nodejs": "^0.9.0", + "noflo-nodejs": "^0.10.0", "noflo-strings": "^0.4.0" }, "scripts": { From af37801503609b82a3c090e586d54db7cafaf168 Mon Sep 17 00:00:00 2001 From: "greenkeeper[bot]" Date: Sat, 31 Mar 2018 00:13:36 +0000 Subject: [PATCH 41/41] chore(package): update fbp-spec to version 0.6.2 Closes #9 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index dbc21b7..ac3a6a9 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ "eslint": "^4.11.0", "eslint-config-airbnb-base": "^12.1.0", "eslint-plugin-import": "^2.8.0", - "fbp-spec": "^0.5.0", + "fbp-spec": "^0.6.2", "mocha": "^5.0.0", "noflo-core": "^0.5.0", "noflo-filesystem": "^2.0.0",