ng-classify v4.1.1
ng-classify
Convert CoffeeScript classes to AngularJS modules
Write less JavaScript. Write less CoffeeScript. Write less Angular.Watch the screencast
Demo
Install
Install with npm
$ npm install ng-classify
Usage
CoffeeScript
ngClassify = require 'ng-classify'
content = '''
class Home extends Controller
constructor: ($log) ->
$log.info 'homeController instantiated'
'''
angularModule = ngClassify content
JavaScript
var ngClassify = require('ng-classify');
var content = '\
class Home extends Controller\n\
constructor: ($log) ->\n\
$log.info \'homeController instantiated\'\
';
var angularModule = ngClassify(content);
Gulp
$ npm install gulp-ng-classify
Grunt
$ npm install grunt-ng-classify
Ruby Gem
ng_classify - maintained by pencilcheck
$ gem install ng_classify
Brunch
ng-classify-brunch - maintained by andrejd
$ npm install ng-classify-brunch
Table of Contents
- Install
- Usage - CoffeeScript - JavaScript - Gulp - Grunt
- Overview - Why? - How? - CoffeeScript classes - Benefits - Considerations - Controller As Syntax
- Module Types - App - Animation - Config - Constant - Controller - Directive - Factory - Filter - Provider - Run - Service - Value
- Multiple Apps
- API
- Contributing
- Changelog
- License
Overview
AngularJS is well suited to take advantage of the CoffeeScript class syntax. However there's still a bit of boilerplate code we have to work through. ng-classify addresses this. Note: all examples are valid CoffeeScript.
Here's how you write a controller using ng-classify
class Admin extends Controller
constructor: ($scope, someService) ->
$scope.coolMethod = someService.coolMethod()
which is equivalent to
angular.module('app').controller('adminController', ['$scope', 'someService', function ($scope, someService) {
$scope.coolMethod = someService.coolMethod();
}]);
Why?
Take the following typical AngularJS controller declaration (same as above)
angular.module('app').controller('adminController', ['$scope', 'someService', function ($scope, someService) {
$scope.coolMethod = someService.coolMethod();
}]);
So what's wrong with this?
- App name,
angular.module('app').controller
, is required within the declaration - some avoid this by the use of a global variable,app.controller
, which is not good JavaScript hygiene - Parameter names are duplicated, one for the getters,
'$scope', 'someService'
, and one for the function parameters,function ($scope, someService)
- this duplication is required to make the module minifiable - some avoid this by the use of ngmin - Depending upon the desired naming format, module type (
controller
) and module name (adminController
) have duplication, due to the suffixedcontroller
in this example - The function is anonymous (unnamed), making it more difficult to debug
- Generally verbose
How?
Write AngularJS modules using the following syntaxes.
NOTE: {{}}
denotes placeholders
class {{appName}} extends {{Animation|Config|Controller|Directive|Factory|Filter|Provider|Run|Service}}
constructor: ({{params}}) ->
# module body here
or
class {{name}} extends {{App|Constant|Value}}
constructor: ->
return {{value}}
CoffeeScript Classes
The typical way to use CoffeeScript classes with AngularJS is as follows.
# 203 characters
class AdminController
constructor: ($scope, someService) ->
$scope.coolMethod = someService.coolMethod()
angular.module('app').controller 'adminController', ['$scope', 'someService', AdminController]
which is equivalent to
// 177 characters
angular.module('app').controller('adminController', ['$scope', 'someService', function AdminController ($scope, someService) {
$scope.coolMethod = someService.coolMethod();
}]);
with ng-classify, this is all you need
# 116 characters
class Admin extends Controller
constructor: ($scope, someService) ->
$scope.coolMethod = someService.coolMethod()
Benefits
- Removes unnecessary ceremonial code (
angular.module('app')
) - App name is not required when writing a module. It is now configurable.
- Parameters are needed only once via the
constructor
function. No need for the array syntax to make your code minifiable. - No need to suffix the module name with the module type, e.g. myController, myCtrl, etc.
- The function is named, making debugging more convenient
- The syntax is arguably concise. Bring your code to the forefront with the elimination of cruft.
Considerations
- To avoid the use of global variables, it is advised to use the
bare: false
CoffeeScript compilation option. see CoffeeScript Usage
Controller As Syntax
AngularJS provides two styles for writing and consuming controllers
$scope
this
withController as
$scope
example
class Admin extends Controller
constructor: ($scope, someService) ->
$scope.coolMethod = someService.coolMethod()
view for $scope
example
<div ng-controller="adminController">
<button ng-click="coolMethod()">Cool It Down!</button>
</div>
this
example
class Admin extends Controller
constructor: (someService) ->
@coolMethod = someService.coolMethod()
view for this
example
<div ng-controller="adminController as controller">
<button ng-click="controller.coolMethod()">Cool It Down!</button>
</div>
Module Types
App
Although there is no AngularJS App module type, it is included for consistency.
class App extends App
constructor: ->
return [
'ngAnimate'
'ngRoute'
]
equivalent to
angular.module('app', [
'ngAnimate',
'ngRoute'
]);
You may wish to use the then
CoffeeScript syntax to highlight your code even more by eliminating the need for extra lines of code and indentation, as follows. Note: this can be leveraged for any CoffeeScript class.
class App extends App then constructor: -> return [
'ngAnimate'
'ngRoute'
]
Note: the app name is configured via the appName option, not the class name
Animation
class MyCrazyFader extends Animation
constructor: ->
return {
enter: (element, done) ->
# run the animation here and call done when the animation is complete
cancellation = (element) ->
# this (optional) function will be called when the animation
# completes or when the animation is cancelled (the cancelled
# flag will be set to true if cancelled).
}
equivalent to
angular.module('app').animation('.my-crazy-fader', [function MyCrazyFader () {
return {
enter: function (element, done) {
// run the animation here and call done when the animation is complete
var cancellation = function (element) {
// this (optional) function will be called when the animation
// completes or when the animation is cancelled (the cancelled
// flag will be set to true if cancelled).
};
return cancellation;
}
};
}]);
Config
class Routes extends Config
constructor: ($routeProvider) ->
$routeProvider
.when '/home',
controller: 'homeController'
templateUrl: 'home.html'
.when '/about',
controller: 'aboutController'
templateUrl: 'about.html'
.otherwise
redirectTo: '/home'
equivalent to
angular.module('app').config(['$routeProvider', function Routes ($routeProvider) {
$routeProvider
.when('/home', {
controller: 'homeController',
templateUrl: 'home.html'
})
.when('/about', {
controller: 'aboutController',
templateUrl: 'about.html'
})
.otherwise({
redirectTo: '/home'
});
}]);
Constant
class HttpStatusCodes extends Constant
constructor: ->
return {
'401': 'Unauthorized'
'403': 'Forbidden'
'404': 'Not Found'
}
equivalent to
angular.module('app').constant('HTTP_STATUS_CODES', {
'401': 'Unauthorized',
'403': 'Forbidden',
'404': 'Not Found'
});
Controller
The example below uses the this syntax
class Home extends Controller
constructor: (userService) ->
@save = (username) ->
userService.addUser username
equivalent to
angular.module('app').controller('homeController', ['userService', function Home (userService) {
this.save = function (username) {
return userService.addUser(username);
};
}]);
Directive
class Dialog extends Directive
constructor: ->
return {
restrict: 'E'
transclude: true
templateUrl: 'dialog.html'
}
equivalent to
angular.module('app').directive('dialog', [function Dialog () {
return {
restrict: 'E',
transclude: true,
templateUrl: 'dialog.html'
};
}]);
Factory
class Greeting extends Factory
constructor: ($log) ->
return {
sayHello: (name) ->
$log.info name
}
equivalent to
angular.module('app').factory('Greeting', ['$log', function Greeting ($log) {
return {
sayHello: function (name) {
$log.info(name);
}
};
}]);
Another nice feature is the ability to return classes
class User extends Factory
constructor: ($log) ->
return class UserInstance
constructor: (firstName, lastName) ->
@getFullName = ->
"#{firstName} #{lastName}"
usage
user = new User 'Cary', 'Landholt'
fullName = user.getFullName() # Cary Landholt
Filter
class Twitterfy extends Filter
constructor: ->
return (username) ->
"@#{username}"
equivalent to
angular.module('app').filter('twitterfy', [function Twitterfy () {
return function (username) {
return '@' + username;
};
}]);
Provider
class Greetings extends Provider
constructor: ($log) ->
@name = 'default'
@$get = ->
name = @name
sayHello: ->
$log.info name
@setName = (name) ->
@name = name
equivalent to
angular.module('app').provider('greetingsProvider', ['$log', function Greetings ($log) {
this.name = 'default';
this.$get = function () {
var name = this.name;
return {
sayHello: function () {
return $log.info(name);
}
};
};
this.setName = function (name) {
return this.name = name;
};
}]);
Run
class ViewsBackend extends Run
constructor: ($httpBackend) ->
$httpBackend.whenGET(/^.*\.(html|htm)$/).passThrough()
equivalent to
angular.module('app').run(['$httpBackend', function ViewsBackend ($httpBackend) {
$httpBackend.whenGET(/^.*\.(html|htm)$/).passThrough();
}]);
Service
class Greeting extends Service
constructor: ($log) ->
@sayHello = (name) ->
$log.info name
equivalent to
angular.module('app').service('greetingService', ['$log', function Greeting ($log) {
this.sayHello = function (name) {
return $log.info(name);
};
}]);
Value
class People extends Value
constructor: ->
return [
{
name: 'Luke Skywalker'
age: 26
}
{
name: 'Han Solo'
age: 35
}
]
equivalent to
angular.module('app').value('people',
[
{
name: 'Luke Skywalker',
age: 26
}, {
name: 'Han Solo',
age: 35
}
]
);
Multiple Apps
Although using multiple apps in an AngularJS application is unnecessary, some may still wish to do so.
Simply provide the app name as a parameter to the module type.
In the example below, a Controller is created within the 'common' app.
class Home extends Controller('common')
constructor: ($log) ->
$log.info 'homeController instantiated'
equivalent to
angular.module('common').controller('homeController', ['$log', function ($log) {
$log.info('homeController instantiated');
})];
API
ngClassify(content, options)
content
Required
Type: String
Default: undefined
The content that may contain CoffeeScript classes to convert to AngularJS modules
options
Type: Object
Default: undefined
options.appName
Type: String
Default: 'app'
The name of the AngularJS app
// for example
angular.module('app')
options.prefix
Type: String
Default: ''
To avoid potential collisions, the moduleType prefix may be set (ex: options.prefix = 'Ng'
)
class Home extends Ng.Controller
constructor: ($log) ->
$log.info 'homeController instantiated'
options.animation
Type: Object
Default: {format: 'spinalCase', prefix: '.'}
options.constant
Type: Object
Default: {format: 'screamingSnakeCase'}
options.controller
Type: Object
Default: {format: 'camelCase', suffix: 'Controller'}
options.directive
Type: Object
Default: {format: 'camelCase'}
options.factory
Type: Object
Default: {format: 'upperCamelCase'}
options.filter
Type: Object
Default: {format: 'camelCase'}
options.provider
Type: Object
Default: {format: 'camelCase', suffix: 'Provider'}
options.service
Type: Object
Default: {format: 'camelCase', suffix: 'Service'}
options.value
Type: Object
Default: {format: 'camelCase'}
Supported Formats
Format | Example |
---|---|
* | no change |
camelCase | camelCase |
lowerCamelCase | lowerCamelCase |
lowerCase | lowercase |
screamingSnakeCase | SCREAMING_SNAKE_CASE |
snakeCase | snake_case |
spinalCase | spinal-case |
trainCase | Train-Case |
upperCamelCase | UpperCamelCase |
upperCase | UPPERCASE |
Contributing
See CONTRIBUTING.md
Changelog
See CHANGELOG.md
License
See LICENSE
9 years ago
9 years ago
9 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago