Skip to content
This repository has been archived by the owner on Dec 15, 2022. It is now read-only.

Initial support for v2 API #6

Merged
merged 10 commits into from
Feb 12, 2015
10 changes: 10 additions & 0 deletions binding.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,16 @@
'src/spellchecker_hunspell.cc',
],
}],
['OS=="win"', {
'sources': [
'src/spellchecker_win.cc'
],
}],
['OS=="linux"', {
'sources': [
'src/spellchecker_linux.cc'
],
}],
['OS=="mac" and spellchecker_use_hunspell=="false"', {
'sources': [
'src/spellchecker_mac.mm',
Expand Down
29 changes: 26 additions & 3 deletions lib/spellchecker.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,30 @@
var path = require('path');
var bindings = require('../build/Release/spellchecker.node');
bindings.init(__dirname);

Spellchecker = bindings.Spellchecker;

var defaultSpellcheck = null;
var ensureDefaultSpellCheck = function() {
if (defaultSpellcheck) return;

defaultSpellcheck = new Spellchecker();
defaultSpellcheck.setDictionary('en_US', path.join(__dirname, '..', 'vendor', 'hunspell_dictionaries'));
};

var isMisspelled = function() {
ensureDefaultSpellCheck();

return defaultSpellcheck.isMisspelled.apply(defaultSpellcheck, arguments);
};

var getCorrectionsForMisspelling = function() {
ensureDefaultSpellCheck();

return defaultSpellcheck.getCorrectionsForMisspelling.apply(defaultSpellcheck, arguments);
};

module.exports = {
isMisspelled: bindings.isMisspelled,
getCorrectionsForMisspelling: bindings.getCorrectionsForMisspelling
isMisspelled: isMisspelled,
getCorrectionsForMisspelling: getCorrectionsForMisspelling,
Spellchecker: Spellchecker
};
116 changes: 84 additions & 32 deletions src/main.cc
Original file line number Diff line number Diff line change
@@ -1,49 +1,101 @@
#include "nan.h"
#include "spellchecker.h"

#include "nan.h"
using node::ObjectWrap;
using namespace spellchecker;
using namespace v8;

namespace {

NAN_METHOD(PlatformInit) {
NanScope();
spellchecker::Init(*String::Utf8Value(args[0]));
NanReturnUndefined();
}
class Spellchecker : public ObjectWrap {
SpellcheckerImplementation* impl;

NAN_METHOD(IsMisspelled) {
NanScope();
if (args.Length() < 1)
return NanThrowError("Bad argument");
static NAN_METHOD(New) {
NanScope();
Spellchecker* that = new Spellchecker();
that->Wrap(args.This());

std::string word = *String::Utf8Value(args[0]);
NanReturnValue(NanNew<Boolean>(spellchecker::IsMisspelled(word)));
}
NanReturnValue(args.This());
}

static NAN_METHOD(SetDictionary) {
NanScope();

if (args.Length() < 1) {
return NanThrowError("Bad argument");
}

NAN_METHOD(GetCorrectionsForMisspelling) {
NanScope();
if (args.Length() < 1)
return NanThrowError("Bad argument");
Spellchecker* that = ObjectWrap::Unwrap<Spellchecker>(args.Holder());

std::string word = *String::Utf8Value(args[0]);
std::vector<std::string> corrections =
spellchecker::GetCorrectionsForMisspelling(word);
std::string language = *String::Utf8Value(args[0]);
std::string directory = ".";
if (args.Length() > 1) {
directory = *String::Utf8Value(args[1]);
}

Local<Array> result = NanNew<Array>(corrections.size());
for (size_t i = 0; i < corrections.size(); ++i) {
const std::string& word = corrections[i];
result->Set(i, NanNew<String>(word.data(), word.size()));
that->impl->SetDictionary(language, directory);
NanReturnUndefined();
}

NanReturnValue(result);
}
static NAN_METHOD(IsMisspelled) {
NanScope();
if (args.Length() < 1) {
return NanThrowError("Bad argument");
}

Spellchecker* that = ObjectWrap::Unwrap<Spellchecker>(args.Holder());
std::string word = *String::Utf8Value(args[0]);

NanReturnValue(NanNew<Boolean>(that->impl->IsMisspelled(word)));
}

static NAN_METHOD(GetCorrectionsForMisspelling) {
NanScope();
if (args.Length() < 1) {
return NanThrowError("Bad argument");
}

Spellchecker* that = ObjectWrap::Unwrap<Spellchecker>(args.Holder());

std::string word = *String::Utf8Value(args[0]);
std::vector<std::string> corrections =
that->impl->GetCorrectionsForMisspelling(word);

Local<Array> result = NanNew<Array>(corrections.size());
for (size_t i = 0; i < corrections.size(); ++i) {
const std::string& word = corrections[i];
result->Set(i, NanNew<String>(word.data(), word.size()));
}

NanReturnValue(result);
}

Spellchecker() {
impl = SpellcheckerFactory::CreateSpellchecker();
}

// actual destructor
virtual ~Spellchecker() {
delete impl;
}

public:
static void Init(Handle<Object> exports) {
Local<FunctionTemplate> tpl = NanNew<FunctionTemplate>(Spellchecker::New);

tpl->SetClassName(NanSymbol("Spellchecker"));
tpl->InstanceTemplate()->SetInternalFieldCount(1);

NODE_SET_METHOD(tpl->InstanceTemplate(), "setDictionary", Spellchecker::SetDictionary);
NODE_SET_METHOD(tpl->InstanceTemplate(), "getCorrectionsForMisspelling", Spellchecker::GetCorrectionsForMisspelling);
NODE_SET_METHOD(tpl->InstanceTemplate(), "isMisspelled", Spellchecker::IsMisspelled);

exports->Set(NanNew("Spellchecker"), tpl->GetFunction());
}
};

void Init(Handle<Object> exports) {
NODE_SET_METHOD(exports, "init", PlatformInit);
NODE_SET_METHOD(exports, "isMisspelled", IsMisspelled);
NODE_SET_METHOD(exports,
"getCorrectionsForMisspelling",
GetCorrectionsForMisspelling);
void Init(Handle<Object> exports, Handle<Object> module) {
Spellchecker::Init(exports);
}

} // namespace
Expand Down
21 changes: 15 additions & 6 deletions src/spellchecker.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,23 @@

namespace spellchecker {

// Initializes everything.
void Init(const std::string& dirname);
class SpellcheckerImplementation {
public:
virtual void SetDictionary(const std::string& language, const std::string& path) = 0;

// Returns true if the word is misspelled.
bool IsMisspelled(const std::string& word);
// Returns an array containing possible corrections for the word.
virtual std::vector<std::string> GetCorrectionsForMisspelling(const std::string& word) = 0;

// Returns an array containing possible corrections for the word.
std::vector<std::string> GetCorrectionsForMisspelling(const std::string& word);
// Returns true if the word is misspelled.
virtual bool IsMisspelled(const std::string& word) = 0;

virtual ~SpellcheckerImplementation() {}
};

class SpellcheckerFactory {
public:
static SpellcheckerImplementation* CreateSpellchecker();
};

} // namespace spellchecker

Expand Down
40 changes: 23 additions & 17 deletions src/spellchecker_hunspell.cc
Original file line number Diff line number Diff line change
@@ -1,38 +1,44 @@
#include "spellchecker.h"

#include "../vendor/hunspell/src/hunspell/hunspell.hxx"

#include "spellchecker_hunspell.h"

namespace spellchecker {

namespace {
HunspellSpellchecker::HunspellSpellchecker() {
this->hunspell = NULL;
}

Hunspell* g_hunspell = NULL;
HunspellSpellchecker::~HunspellSpellchecker() {
if (!this->hunspell) return;

} // namespace
delete this->hunspell;
}

void Init(const std::string& dirname) {
if (g_hunspell != NULL)
return;
void HunspellSpellchecker::SetDictionary(const std::string& language, const std::string& dirname) {
if (hunspell != NULL) {
delete this->hunspell;
}

std::string affixpath = dirname + "/../vendor/hunspell_dictionaries/en_US.aff";
std::string dpath = dirname + "/../vendor/hunspell_dictionaries/en_US.dic";
g_hunspell = new Hunspell(affixpath.c_str(), dpath.c_str());
std::string affixpath = dirname + "/" + language + ".aff";
std::string dpath = dirname + "/" + language + ".dic";
this->hunspell = new Hunspell(affixpath.c_str(), dpath.c_str());
}

bool IsMisspelled(const std::string& word) {
return g_hunspell->spell(word.c_str()) == 0;
bool HunspellSpellchecker::IsMisspelled(const std::string& word) {
return this->hunspell->spell(word.c_str()) == 0;
}

std::vector<std::string> GetCorrectionsForMisspelling(const std::string& word) {
std::vector<std::string> HunspellSpellchecker::GetCorrectionsForMisspelling(const std::string& word) {
std::vector<std::string> corrections;
char** slist;
int size = g_hunspell->suggest(&slist, word.c_str());
int size = hunspell->suggest(&slist, word.c_str());

corrections.reserve(size);
for (int i = 0; i < size; ++i)
for (int i = 0; i < size; ++i) {
corrections.push_back(slist[i]);
}

g_hunspell->free_list(&slist, size);
this->hunspell->free_list(&slist, size);
return corrections;
}

Expand Down
25 changes: 25 additions & 0 deletions src/spellchecker_hunspell.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#ifndef SRC_SPELLCHECKER_HUNSPELL_H_
#define SRC_SPELLCHECKER_HUNSPELL_H_

#include "spellchecker.h"

class Hunspell;

namespace spellchecker {

class HunspellSpellchecker : public SpellcheckerImplementation {
public:
HunspellSpellchecker();
~HunspellSpellchecker();

void SetDictionary(const std::string& language, const std::string& path);
std::vector<std::string> GetCorrectionsForMisspelling(const std::string& word);
bool IsMisspelled(const std::string& word);

private:
Hunspell* hunspell;
};

} // namespace spellchecker

#endif // SRC_SPELLCHECKER_MAC_H_
10 changes: 10 additions & 0 deletions src/spellchecker_linux.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#include "spellchecker.h"
#include "spellchecker_hunspell.h"

namespace spellchecker {

SpellcheckerImplementation* SpellcheckerFactory::CreateSpellchecker() {
return new HunspellSpellchecker();
}

} // namespace spellchecker
17 changes: 17 additions & 0 deletions src/spellchecker_mac.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#ifndef SRC_SPELLCHECKER_MAC_H_
#define SRC_SPELLCHECKER_MAC_H_

#include "spellchecker.h"

namespace spellchecker {

class MacSpellchecker : public SpellcheckerImplementation {
public:
void SetDictionary(const std::string& language, const std::string& path);
std::vector<std::string> GetCorrectionsForMisspelling(const std::string& word);
bool IsMisspelled(const std::string& word);
};

} // namespace spellchecker

#endif // SRC_SPELLCHECKER_MAC_H_
12 changes: 8 additions & 4 deletions src/spellchecker_mac.mm
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
#include "spellchecker.h"
#include "spellchecker_mac.h"

#import <Cocoa/Cocoa.h>
#import <dispatch/dispatch.h>

namespace spellchecker {

void Init(const std::string& dirname) {
void MacSpellchecker::SetDictionary(const std::string& language, const std::string& path) {
}

bool IsMisspelled(const std::string& word) {
bool MacSpellchecker::IsMisspelled(const std::string& word) {
bool result;

@autoreleasepool {
Expand All @@ -23,7 +23,7 @@ bool IsMisspelled(const std::string& word) {
return result;
}

std::vector<std::string> GetCorrectionsForMisspelling(const std::string& word) {
std::vector<std::string> MacSpellchecker::GetCorrectionsForMisspelling(const std::string& word) {
std::vector<std::string> corrections;

@autoreleasepool {
Expand All @@ -47,4 +47,8 @@ bool IsMisspelled(const std::string& word) {
return corrections;
}

SpellcheckerImplementation* SpellcheckerFactory::CreateSpellchecker() {
return new MacSpellchecker();
}

} // namespace spellchecker
10 changes: 10 additions & 0 deletions src/spellchecker_win.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#include "spellchecker.h"
#include "spellchecker_hunspell.h"

namespace spellchecker {

SpellcheckerImplementation* SpellcheckerFactory::CreateSpellchecker() {
return new HunspellSpellchecker();
}

} // namespace spellchecker