Search code examples
handlebars.jsassemble

Correct way to import custom handlebar helpers to assemble


Have the following assemble file, and everything is loading as expected. The file compiles if I use the handlebars-helpers, but its missing the helpers I need. So I had to use a custom helper file/module

var gulp = require('gulp');
var rename = require('gulp-rename');
var assemble = require('assemble');
//var helpers = require('handlebars-helpers');
var app = assemble();
var prettify = require('gulp-prettify');
var config = require('../config');

gulp.task('init', function(cb) {
  app.helpers(config.paths.path_src + 'partials/_helpers/is-helper.js');
  //app.helper('compare', helpers.comparison());
  app.partials(config.paths.path_src + 'templates/includes/**/*.hbs');
  app.layouts(config.paths.path_src + 'templates/layouts/**/*.hbs');
  app.pages(config.paths.path_src + 'templates/content/**/*.hbs');
  cb();
});

gulp.task('assemble', ['init'], function() {
  return app.toStream('pages')
    .pipe(app.renderFile())
    .pipe(prettify({
        indent_inner_html: false,
        preserve_newlines: true,
        end_with_newline: true,
        extra_liners: ['head', 'body']
    }))
    .pipe(rename({
        extname: '.html'
    }))
    .pipe(rename({dirname: ''}))
    .pipe(app.dest('site'));
});

gulp.task('test', ['assemble']);

Now I already tried handlebars-helper but it does not have the helper file I am after so I had to use the one below:

/*
    Custom handlebars helpers which allows to make

    {{#is a '===' b}}}

    {{/is}}
*/

module.exports.register = function (handlebars) {

    var isArray = function(value) {
        return Object.prototype.toString.call(value) === '[object Array]';
    }

    var ExpressionRegistry = function() {
        this.expressions = [];
    };

    ExpressionRegistry.prototype.add = function (operator, method) {
        this.expressions[operator] = method;
    };

    ExpressionRegistry.prototype.call = function (operator, left, right) {
        if ( ! this.expressions.hasOwnProperty(operator)) {
            throw new Error('Unknown operator "'+operator+'"');
        }

        return this.expressions[operator](left, right);
    };

    var eR = new ExpressionRegistry;
    eR.add('not', function(left, right) {
        return left != right;
    });
    eR.add('>', function(left, right) {
        return left > right;
    });
    eR.add('<', function(left, right) {
        return left < right;
    });
    eR.add('>=', function(left, right) {
        return left >= right;
    });
    eR.add('<=', function(left, right) {
        return left <= right;
    });

    eR.add('==', function(left, right) {
        return left == right;
    });

    eR.add('===', function(left, right) {
        return left === right;
    });
    eR.add('!==', function(left, right) {
        return left !== right;
    });
    eR.add('in', function(left, right) {
        if ( ! isArray(right)) {
            right = right.split(',');
        }
        return right.indexOf(left) !== -1;
    });

    var isHelper = function() {
        var args = arguments
        ,   left = args[0]
        ,   operator = args[1]
        ,   right = args[2]
        ,   options = args[3]
        ;


        // console.log(args);

        if (args.length == 2) {
            options = args[1];
            if (left) return options.fn(this);
            return options.inverse(this);
        }

        if (args.length == 3) {
            right = args[1];
            options = args[2];
            if (left == right) return options.fn(this);
            return options.inverse(this);
        }

        if (eR.call(operator, left, right)) {
            return options.fn(this);
        }
        return options.inverse(this);
    };

    handlebars.registerHelper('is', isHelper);

    return eR;
};

I keep getting the following error missing helper "is". Looks like its not registering! Please help!!!


Solution

  • In reference to this github issue:

    The is helper documentation is here.

    Also is there a way to import custom helpers?

    This is described here. Instead of using a path, you use require:

    // single helper (required module returns the helper function)
    app.helper('is', require('./helpers/is'));
    
    // multiple helpers (required module returns an object of helper functions... e.g. key/value pairs)
    app.helpers(require('./helpers'));
    

    The above custom helper code is using the grunt-assemble syntax for registering helpers. In this case, I would change your helper to look like this:

    /*
        Custom handlebars helpers which allows to make
    
        {{#is a '===' b}}}
    
        {{/is}}
    */
    
    module.exports = function () {
    
        var isArray = function(value) {
            return Object.prototype.toString.call(value) === '[object Array]';
        }
    
        var ExpressionRegistry = function() {
            this.expressions = [];
        };
    
        ExpressionRegistry.prototype.add = function (operator, method) {
            this.expressions[operator] = method;
        };
    
        ExpressionRegistry.prototype.call = function (operator, left, right) {
            if ( ! this.expressions.hasOwnProperty(operator)) {
                throw new Error('Unknown operator "'+operator+'"');
            }
    
            return this.expressions[operator](left, right);
        };
    
        var eR = new ExpressionRegistry;
        eR.add('not', function(left, right) {
            return left != right;
        });
        eR.add('>', function(left, right) {
            return left > right;
        });
        eR.add('<', function(left, right) {
            return left < right;
        });
        eR.add('>=', function(left, right) {
            return left >= right;
        });
        eR.add('<=', function(left, right) {
            return left <= right;
        });
    
        eR.add('==', function(left, right) {
            return left == right;
        });
    
        eR.add('===', function(left, right) {
            return left === right;
        });
        eR.add('!==', function(left, right) {
            return left !== right;
        });
        eR.add('in', function(left, right) {
            if ( ! isArray(right)) {
                right = right.split(',');
            }
            return right.indexOf(left) !== -1;
        });
    
        var isHelper = function() {
            var args = arguments
            ,   left = args[0]
            ,   operator = args[1]
            ,   right = args[2]
            ,   options = args[3]
            ;
    
    
            // console.log(args);
    
            if (args.length == 2) {
                options = args[1];
                if (left) return options.fn(this);
                return options.inverse(this);
            }
    
            if (args.length == 3) {
                right = args[1];
                options = args[2];
                if (left == right) return options.fn(this);
                return options.inverse(this);
            }
    
            if (eR.call(operator, left, right)) {
                return options.fn(this);
            }
            return options.inverse(this);
        };
    
        return isHelper;
    };
    

    The in assemble you can load the helper by doing:

    var isHelper = require(config.paths.path_src + 'partials/_helpers/is-helper'));
    app.helper('is', isHelper());
    

    Notice that the returned function from the is-helper is called before passing it to app.helper. This allows you to pass custom options to your helper (e.g. custom expressions that you're using in your helper), but that's up to you.

    Hope this helps.