How can I run only a single function in a generator (and end the generator) if a flag is set? What is the preferred way to achieve this?
var MyGenerator = yeoman.generators.Base.extend({
constructor: function () {
yeoman.generators.Base.apply(this, arguments);
this.option('flag', {
desc: 'Do something',
type: String,
required: false,
defaults: null
});
},
runOnlyThisIfFlagIsSet: function() {
if(this.options.flag) {
// do stuff and end the generator so that it does all the things defined here
}
},
doNotRunThis: function() {
// I don't want this to run if the flag is set
},
iCouldDoThisButItIsTooRepetitive: function() {
if(!this.options.flag) {
// do stuff
}
}
});
module.exports = MyGenerator;
yo myGeneratorName --flag
Maybe you're over thinking this? Based on http://yeoman.io/authoring/running-context.html, I would recommend only having maybe one function in your generator anyway (default?). Read the section called "Helper and private methods" if you want to break your generator into additional methods.
var MyGenerator = yeoman.generators.Base.extend({
constructor: function () {
yeoman.generators.Base.apply(this, arguments);
this.option('flag', {
desc: 'Do something',
type: String,
required: false,
defaults: null
});
},
default: function() {
if(this.options.flag) {
// do stuff and end the generator so that it does all the things defined here. Use the documentation link above to figure out how to create private methods you can call from here.
}
}
});
module.exports = MyGenerator;
If the flag is not set, the generator will just exit.
Related
what exactly I want to do is, I have a file say permissions.js with contents:
Permissions.js
module..exports = {
Student: {
Read: true,
Service: "StudentService",
Teach: false
},
Teacher: {
Read: false,
Service: "TeacherService",
Teach: true
}
}
and another file functions.js:
functions.js
// functions.js
module.exports = {
StudentService: {
someFunc1: function() {...},
someFunc2: function() {...},
someFunc3: function() {...}
},
TeacherService: {
someFunc1: function() {...},
someFunc2: function() {...},
someFunc3: function() {...}
}
}
and importing both the files in school.js:
school.js
// school.js
import functions from "./path-to/functions.js";
import { Student, Teacher } from "./path-to/permissions.js";
// Making it very simple
let service = Student.Service; // service = "StudentService"
service.someFunc1() // returns someFunc1 is not a function
So what I want to do is use the service variable as a reference for the StudentService in functions.js. Cannot use require.
This doesn't isn't specific to react-native at all, just modern JS modules. This will work:
import * as functions from "./path-to/functions.js"
import { Student } from "./path-to/permissions.js"
let service = Student.Service;
functions[service].someFunc1
A better approach though would be this:
perissions.js
import { StudentService, TeacherService } from "./path-to/functions.js";
module.exports = {
Student: {
Read: true,
Service: StudentService,
Teach: false
},
Teacher: {
Read: false,
Service: TeacherService,
Teach: true
}
}
And then you never have to mess about referencing things with strings.
Following the Intern user guide, I wrote a simple page object:
define(function(require) {
function ListPage(remote) {
this.remote = remote;
}
ListPage.prototype = {
constructor: ListPage,
doSomething: function(value) {
return this.remote
.get(require.toUrl('http://localhost:5000/index.html'))
.findByCssSelector("[data-tag-test-id='element-of-interest']")
.click().end();
}
};
return ListPage;
});
In the test, I want to call doSomething twice in a row, like this:
define(function(require) {
var registerSuite = require('intern!object');
var ListPage = require('../support/pages/ListPage');
registerSuite(function() {
var listPage;
return {
name: 'test suite name',
setup: function() {
listPage = new ListPage(this.remote);
},
beforeEach: function() {
return listPage
.doSomething('Value 1')
.doSomething('Value 2');
},
'test function': function() {
// ...
}
};
});
});
However, when I run the test, I get this error:
TypeError: listPage.doSomething(...).doSomething is not a function
I tried some approaches described in this question, to no avail.
A better way to implement page objects with Intern is as helper functions rather than Command wrappers. Groups of related helper functions can then be used to create Page Object modules.
// A helper function can take config parameters and returns a function
// that will be used as a Command chain `then` callback.
function doSomething(value) {
return function () {
return this.parent
.findByCssSelector('whatever')
.click()
}
}
// ...
registerSuite(function () {
name: 'test suite',
'test function': function () {
return this.remote.get('page')
// In a Command chain, a call to the helper is the argument
// to a `then`
.then(doSomething('value 1'))
.then(doSomething('value 2'));
}
}
So starting my adventure into all things Node. One of the tools I am trying to learn is Sequelize. So I will start off what I was trying to do:
'use strict';
var crypto = require('crypto');
module.exports = function(sequelize, DataTypes) {
var User = sequelize.define('User', {
username: DataTypes.STRING,
first_name: DataTypes.STRING,
last_name: DataTypes.STRING,
salt: DataTypes.STRING,
hashed_pwd: DataTypes.STRING
}, {
classMethods: {
},
instanceMethods: {
createSalt: function() {
return crypto.randomBytes(128).toString('base64');
},
hashPassword: function(salt, pwd) {
var hmac = crypto.createHmac('sha1', salt);
return hmac.update(pwd).digest('hex');
},
authenticate: function(passwordToMatch) {
return this.hashPassword(this.salt, passwordToMatch) === this.hashed_pwd;
}
}
});
return User;
};
I am confused on when to use classMethods vs instanceMethods. To me when I think about createSalt() and hashPassword() should be class methods. They are general and for the most part dont really have anything to do with the specific instance they are just used in general. But when I have createSalt() and hashPassword() in classMethods I cannot call them from instanceMethods.
I have tried variations of the following:
this.createSalt();
this.classMethods.createSalt();
createSalt();
Something like below wont work and I am probably just not understanding something simple.
authenticate: function(passwordToMatch) {
console.log(this.createSalt());
return this.hashPassword(this.salt, passwordToMatch) === this.hashed_pwd;
}
Any hints/tips/direction would be very much so appreciated!
All the method who don't modify or check any type of instance should be classMethod and the rest instanceMethod
ex:
// Should be a classMethods
function getMyFriends() {
return this.find({where{...}})
}
// Should be a instanceMethods
function checkMyName() {
return this.name === "george";
}
Although the basics are that instance methods should be used when you want to modify your instance ( ergo row ). I would rather not pollute the classMethods with methods that don't use the class ( ergo the table ) itself.
In your example I would put hashPassword function outside your class and leave it as a helper function somewhere in my utilities module ( or why not the same module but as a normal defined function ) ... like
var hashPassword = function(...) { ... }
...
...
instanceMethods: {
authenticate: function( ... ) { hashPassword( ... ) }
}
I found this worked for me as of sequelize 3.14
var myModel = sequelize.define('model', {
}, {
classMethods: {
someClassMethod: function() {
return true;
}
}, {
instanceMethods: {
callClassMethod: function() {
myModel.someClassMethod();
}
}
});
The question:
As I understand in sails.js during initialization process Services are initialized before Models.
Is there any possibility to change this behavior? To make Models load before Services.
If it's not, then how can I load particular settings from the database to use them to build instance of my class described in some Service during this Service initialization?
A little bit code for solidity:
api/models/Model.js
console.log("Model Identified");
module.exports = {
attributes: {
name: { type: 'string', required: true, size: 15 },
//Some extra secret fields
}
};
...
api/services/MyCoolService.js
console.log('service inits');
function MyCoolService(options){
//some extraordinary constructor logic may be ommited
}
MyCoolService.prototype.setOptions = function(options){
//Set values for MyCoolService fields.
}
//Some other methods
var myCoolServiceWithSettingsFromDb = new MyCoolService();
//That's the place
model.findOne(sails.config.myApplication.settingsId).exec(function(err,result){
if(!err)
myCoolServiceWithSettingsFromDb.setOptions(result);
});
module.exports = myCoolServiceWithSettingsFromDb;
It's because you instantiate object in service with constructor that needs sails that not exist. Try use this at MyCoolService;
module.exports = {
someOption: null,
method: function () {
var that = this;
sails.models.model.findOne(sails.config.myApplication.settingsId)
.exec(function (err, result) {
if (!err)
that.someOption = result;
});
}
};
that method can be called by sails.services.mycoolservice.method() or simply MyCoolService.method() to give your service some option from DB.
If you want to initiate them at Sails start, call that method at config/bootstrap.js
Thanks to Andi Nugroho Dirgantara,
I ended up with this solution (I still don't like it much, but it works):
api/services/MyCoolService.js
console.log('service inits');
function MyCoolService(options){
//some extraordinary constructor logic may be ommited
}
//All the same as in question
//The instance
var instance;
module.exports = module.exports = {
init: function(options) {
instance = new MyCoolService(options);
},
get: function() {
return instance;
},
constructor: MyCoolService
};
config/bootstrap.js
...
Model.findOrCreate({ id: 1 }, sails.config.someDefaultSettings).exec(function(err, result) {
if (err)
return sails.log.error(err);
result = result || sails.config.someDefaultSettings;
MyCoolService.init(result);
return sails.log.verbose("MyCoolService Created: ", TbcPaymentProcessorService.get());
});
...
tests/unit/service/MyCoolService.test.js
...
describe('MyCoolService', function() {
it('check MyCoolService', function(done) {
assert.notDeepEqual(MyCoolService.get(), sails.config.someDefaultSettings);
done();
});
});
...
It works: the service is instantiated once while bootstraping and it's instance is avaliable everywhere.
But to me this solution still weird... I still don't understand how to globally instantiate instance of my service (for use in a lot of controllers) and make it the best way.
I have set up a simple model with 2 instance methods. How can I call those methods in lifecycle callbacks?
module.exports = {
attributes: {
name: {
type: 'string',
required: true
}
// Instance methods
doSomething: function(cb) {
console.log('Lets try ' + this.doAnotherThing('this'));
cb();
},
doAnotherThing: function(input) {
console.log(input);
}
},
beforeUpdate: function(values, cb) {
// This doesn't seem to work...
this.doSomething(function() {
cb();
})
}
};
It looks like custom defined instance methods were not designed to be called in lifecycle but after querying a model.
SomeModel.findOne(1).done(function(err, someModel){
someModel.doSomething('dance')
});
Link to example in documentation - https://github.com/balderdashy/sails-docs/blob/0.9/models.md#custom-defined-instance-methods
Try defining the functions in regular javascript, this way they can be called from the entire model file like this:
// Instance methods
function doSomething(cb) {
console.log('Lets try ' + this.doAnotherThing('this'));
cb();
},
function doAnotherThing(input) {
console.log(input);
}
module.exports = {
attributes: {
name: {
type: 'string',
required: true
}
},
beforeUpdate: function(values, cb) {
// accessing the function defined above the module.exports
doSomething(function() {
cb();
})
}
};
doSomething and doAnotherThing aren't attributes, are methods and must be at Lifecycle callbacks level. Try something like this:
module.exports = {
attributes: {
name: {
type: 'string',
required: true
}
},
doSomething: function(cb) {
console.log('Lets try ' + "this.doAnotherThing('this')");
this.doAnotherThing('this')
cb();
},
doAnotherThing: function(input) {
console.log(input);
},
beforeCreate: function(values, cb) {
this.doSomething(function() {
cb();
})
}
};
On Second place, you're trying send to console this.doAnotherThing('this') but it is an instance of model so you can't pass it like parameter on the "Lets try" string. Instead of it try to exec this function apart and will work