UNPKG

33.1 kBMarkdownView Raw
1# generator-ng-poly
2[![NPM version](https://badge.fury.io/js/generator-ng-poly.svg)](http://badge.fury.io/js/generator-ng-poly) [![Build Status](https://travis-ci.org/dustinspecker/generator-ng-poly.svg?branch=master)](https://travis-ci.org/dustinspecker/generator-ng-poly) [![Coverage Status](https://img.shields.io/coveralls/dustinspecker/generator-ng-poly.svg)](https://coveralls.io/r/dustinspecker/generator-ng-poly?branch=master)
3
4[![Code Climate](https://codeclimate.com/github/dustinspecker/generator-ng-poly/badges/gpa.svg)](https://codeclimate.com/github/dustinspecker/generator-ng-poly) [![Dependencies](https://david-dm.org/dustinspecker/generator-ng-poly.svg)](https://david-dm.org/dustinspecker/generator-ng-poly/#info=dependencies&view=table) [![DevDependencies](https://david-dm.org/dustinspecker/generator-ng-poly/dev-status.svg)](https://david-dm.org/dustinspecker/generator-ng-poly/#info=devDependencies&view=table)
5
6> [Yeoman](http://yeoman.io) generator for modular AngularJS apps with Gulp and optional Polymer support
7
8*Inspired by [John Papa](https://github.com/johnpapa)'s [Angular Style Guide](https://github.com/johnpapa/angular-styleguide) and [Todd Motto](https://github.com/toddmotto)'s [AngularJS styleguide](https://github.com/toddmotto/angularjs-styleguide).*
9
10## Purpose
11
12This generator focuses on organizing Angular components by feature (home, about, video player, etc.) instead of by type (controller, service, directive, etc.) to encourage the development of self-contained, reusable components.
13
14A typical workflow with this generator consists of creating an Angular module ([ng-poly:module](#module)) and then generating controllers, directives, etc. for this module to create a new feature.
15
16**Polymer is just an added feature, but it isn't required to utilize this generator.**
17
18## Usage
19
20Install `generator-ng-poly`:
21
22```
23npm install -g bower gulp yo generator-ng-poly
24```
25
26If TypeScript is going to be used, `tsd` will need to be installed:
27
28```
29npm install -g tsd
30```
31
32Run `yo ng-poly`
33Yeoman will then ask for an app name and language preferences.
34
35**If using Node 0.12, there is a bug in Yeoman or Node causing yeoman generators to hang. With ng-poly, if after it outputs the generated home module files it hangs, then it is safe to enter `Ctrl+C`, etc. The project is good to go and everything else should work normally.**
36
37Run `gulp` to build and start the development environment. [More detail on Gulp tasks](#gulp-tasks-in-detail)
38
39## User Groups
40
41Please feel free to ask any questions on our [GitHub Issues](https://github.com/dustinspecker/generator-ng-poly/issues) or [Google Group](https://groups.google.com/forum/#!forum/generator-ng-poly).
42
43## Generators
44
45Available generators:
46* AngularJS
47 - [ng-poly](#app) (a.k.a. [ng-poly:app](#app))
48 - [ng-poly:constant](#constant)
49 - [ng-poly:controller](#controller)
50 - [ng-poly:decorator](#decorator)
51 - [ng-poly:directive](#directive)
52 - [ng-poly:factory](#factory)
53 - [ng-poly:filter](#filter)
54 - [ng-poly:module](#module)
55 - [ng-poly:provider](#provider)
56 - [ng-poly:route](#route)
57 - [ng-poly:service](#service)
58 - [ng-poly:value](#value)
59 - [ng-poly:view](#view)
60* Polymer
61 - [ng-poly:element](#element)
62
63Languages and Features supported:
64 * Angular Versions
65 - 1.2.\*, 1.3.\*, 1.4.\*
66 * Markup
67 - HAML, HTML, Jade
68 * Application scripting languages
69 - CoffeeScript, EcmaScript2015 (ES6) with Babel, JavaScript (ES5), TypeScript
70 * Testing scripting languages
71 - CoffeeScript, EcmaScript2015 (ES6) with Babel, JavaScript (ES5), TypeScript†
72 * Style languages
73 - CSS, LESS, SCSS, Stylus
74 * Routers
75 - Angular Route, UI Router
76 * Unit testing
77 - Jasmine (Karma as the test runner) for AngularJS
78 - Mocha with Chai (Karma as the test runner) for AngularJS
79 * e2e testing
80 - Jasmine (ran with Protractor) for AngularJS
81 - Mocha, Chai, and Chai as Promised (ran with Protractor) for AngularJS
82 * Frameworks (scaffolds simple navbar)
83 - Angular Material (1.3.* or higher only)
84 - Doesn't scaffold navbar, yet
85 - Bootstrap with AngularStrap
86 - Bootstrap with UI Bootstrap (1.2.* only)
87 - Foundation with Angular Foundation
88 * Polymer
89 - Core, Paper
90 * Task runners
91 - Gulp
92 * Other supported Bower packages:
93 - Angular Animate
94 - Angular Cookies
95 - Angular Messages
96 - Angular Resource
97 - Angular Sanitize
98 - Angular Touch
99 - Font Awesome
100 - Lo-Dash
101 - Restangular
102
103[Configurations](#configurations):
104 * Syntax
105 - [Controller As](#controller-as-syntax)
106
107† e2e tests are not supported in TypeScript. JavaScript will instead be used for e2e tests.
108
109### Gulp Tasks Briefing
110`gulp` will start a localhost and open in the default browser
111
112Using `--stage prod` will concat and minify HTML, CSS, and Angular modules.
113
114`gulp build` will compile the assets
115
116`gulp dev` will call the build task and setup the development environment
117
118`gulp unitTest` will run unit tests via Karma and create code coverage reports
119
120`gulp webdriverUpdate` will download the Selenium server standalone and Chrome driver for e2e testing
121
122`gulp e2eTest` will run e2e tests via Protractor (must start a localhost before running `gulp e2eTest`)
123
124[Gulp Tasks in Detail](#gulp-tasks-in-detail)
125
126* * *
127**All generators ask for a module name except app and element. All generators except app take a name as an argument. A name can be written with CamelCase or hyphens.**
128
129Generators requiring a module can take a module option to bypass the prompt:
130```
131yo ng-poly:view newView --module=home/kitchen
132```
133**A module value of `app` will add the new components to the module defined in app.js or app.coffee.**
134* * *
135
136**Examples are shown with HTML, LESS, JavaScript, Jasmine, and UI Router as the app configuration.**
137
138### App
139Asks for application name and language preferences to scaffold out an application with a home module. It will also ask if tests should be placed in the `app/` or `tests/` directory. It'll ask for some additional Bower dependencies and then install npm and Bower dependencies.
140
141Example:
142
143Run `yo ng-poly` to get started. ng-poly will then asks you some questions:
144
145```
146[?] What is the app's name?
147[?] Which version of Angular should be used?
148[?] Which structure should be used?
149[?] Which is the preferred markup language?
150[?] Which is the preferred application scripting language?
151[?] Want to use Controller As syntax?
152[?] By default, should the route generator create controllers?
153[?] Which is the preferred test scripting language?
154[?] Which is the preferred unit testing framework?
155[?] Which is the preferred e2e testing framework?
156[?] Which is the preferred style language?
157[?] Should Polymer support be enabled?
158[?] Should a framework be setup?
159[?] Should ngRoute be used instead of UI Router?
160[?] Which additional Bower components should be installed?
161```
162
163ng-poly makes some assumptions, but these can be overridden.
164
165| Option | Default Value| Info |
166| -------| ------------ | ---- |
167| host | localhost | BrowserSync and Protractor will use this host. |
168| port | 3000 | BrowserSync and Protractor will use this port. |
169| app-dir | app | Source code will be generated here. |
170| unit-test-dir | app | Unit tests will be generated here. |
171| skip-controller | false | Should the route generator *skip* creating a controller? |
172| skip-install | false | Should ng-poly skip installing Bower and npm dependencies? |
173
174Example: `yo ng-poly --port=8080 --app-dir=src` to override the default port and app directory.
175
176A **module-only** structure produces:
177```
178root/
179├── app/
180│ ├── fonts/ (empty)
181│ ├── home/
182│ │ ├── home-module.{coffee,es6,js,ts}
183│ │ ├── home-routes.{coffee,es6,js,ts}
184│ │ ├── home.{css,less,scss,styl}
185│ │ ├── home.tpl.{haml,html,jade}
186│ │ ├── home-controller.{coffee,es6,js,ts}
187│ │ └── home-controller_test.{coffee,es6,js,ts}
188│ ├── images/ (empty)
189│ ├── app-module.{coffee,es6,js,ts}
190│ ├── app-routes.{coffee,es6,js,ts}
191│ └── index.{haml,html,jade}
192├── bower_components/
193├── e2e/
194│ └── home/
195│ ├── home.po.{coffee,es6,js}
196│ └── home_test.{coffee,es6,js}
197├── gulp/
198│ ├── analyze.js
199│ ├── build.js
200│ ├── test.js
201│ └── watch.js
202├── node_modules/
203├── typings/*
204├── .bowerrc
205├── .editorconfig
206├── .eslintrc
207├── .gitignore
208├── .jscsrc
209├── .jshintrc
210├── .yo-rc.json
211├── bower.json
212├── build.config.js
213├── Gulpfile.js
214├── karma.config.js
215├── package.json
216├── protractor.config.js
217├── README.md
218└── tsd.json*
219```
220
221A **module-type** structure produces:
222```
223root/
224├── app/
225│ ├── fonts/ (empty)
226│ ├── home/
227│ │ ├── controllers/
228│ │ │ ├── home-controller.{coffee,es6,js,ts}
229│ │ │ └── home-controller_test.{coffee,es6,js,ts}
230│ │ ├── views/
231│ │ │ ├── home.{css,less,scss,styl}
232│ │ │ └── home.tpl.{haml,html,jade}
233│ │ ├── home-module.{coffee,es6,js,ts}
234│ │ └── home-routes.{coffee,es6,js,ts}
235│ ├── images/ (empty)
236│ ├── app-module.{coffee,es6,js,ts}
237│ ├── app-routes.{coffee,es6,js,ts}
238│ └── index.{haml,html,jade}
239├── bower_components/
240├── e2e/
241│ └── home/
242│ ├── home.po.{coffee,es6,js}
243│ └── home_test.{coffee,es6,js}
244├── gulp/
245│ ├── analyze.js
246│ ├── build.js
247│ ├── test.js
248│ └── watch.js
249├── node_modules/
250├── typings/*
251├── .bowerrc
252├── .editorconfig
253├── .eslintrc
254├── .gitignore
255├── .jscsrc
256├── .jshintrc
257├── .yo-rc.json
258├── bower.json
259├── build.config.js
260├── Gulpfile.js
261├── karma.config.js
262├── package.json
263├── protractor.config.js
264├── README.md
265└── tsd.json*
266```
267\* Only TypeScript projects will have this.
268### Constant
269Generates a constant and its test.
270
271Example:
272```
273yo ng-poly:constant theHero
274[?] Which module is this for?
275```
276
277Produces `app/module/the-hero-constant.js`:
278```javascript
279(function () {
280 'use strict';
281
282 /**
283 * @ngdoc service
284 * @name module.constant:theHero
285 *
286 * @description
287 *
288 */
289 angular
290 .module('module')
291 .constant('theHero', 0);
292}());
293
294```
295
296Produces `app/module/the-hero-constant_test.js`:
297```javascript
298/*global describe, beforeEach, it, expect, inject, module*/
299'use strict';
300
301describe('theHero', function () {
302 var constant;
303
304 beforeEach(module('module'));
305
306 beforeEach(inject(function (theHero) {
307 constant = theHero;
308 }));
309
310 it('should equal 0', function () {
311 expect(constant).toBe(0);
312 });
313});
314
315```
316
317### Controller
318Genrates a controller and its test.
319
320Example:
321```
322yo ng-poly:controller micro
323[?] Which module is this for?
324```
325
326Produces `app/module/micro-controller.js`:
327```javascript
328(function () {
329 'use strict';
330
331 /**
332 * @ngdoc object
333 * @name module.controller:MicroCtrl
334 * @requires $scope
335 *
336 * @description
337 *
338 */
339 angular
340 .module('module')
341 .controller('MicroCtrl', MicroCtrl);
342
343 function MicroCtrl($scope) {
344 $scope.micro = {};
345 $scope.micro.ctrlName = 'MicroCtrl';
346 }
347}());
348
349```
350
351Produces `app/module/micro-controller_test.js`:
352```javascript
353/*global describe, beforeEach, it, expect, inject, module*/
354'use strict';
355
356describe('MicroCtrl', function () {
357 var scope;
358
359 beforeEach(module('module'));
360
361 beforeEach(inject(function ($rootScope, $controller) {
362 scope = $rootScope.$new();
363 $controller('MicroCtrl', {$scope: scope});
364 }));
365
366 it('should have ctrlName as MicroCtrl', function () {
367 expect(scope.micro.ctrlName).toEqual('MicroCtrl');
368 });
369});
370
371```
372
373### Decorator
374Generates a decorator and its test.
375
376Example:
377```
378yo ng-poly:decorator awesomeService
379[?] Which module is this for?
380```
381
382**Note: If decorating a service starting with a `$` you must escape it like:**
383
384`yo ng-poly:decorator \$state`
385
386Produces `app/module/awesome-service-decorator.js`:
387```javascript
388(function () {
389 'use strict';
390
391 /**
392 * @ngdoc decorator
393 * @name home.decorator:awesomeService
394 * @restrict EA
395 * @element
396 *
397 * @description
398 *
399 */
400 angular
401 .module('module')
402 .config(decorator);
403
404 function decorator($provide) {
405 $provide.decorator('awesomeService', function ($delegate) {
406 $delegate.simpleFunction = function () {
407 return 'awesomeService';
408 };
409 return $delegate;
410 });
411 }
412}());
413
414```
415
416Produces: `app/module/awesome-service-decorator_test.js`:
417```javascript
418/*global describe, beforeEach, it, expect, inject, module*/
419'use strict';
420
421describe('awesomeService', function () {
422 var decorator;
423
424 beforeEach(module('module'));
425
426 beforeEach(inject(function (awesomeService) {
427 decorator = awesomeService;
428 }));
429
430 it('should have simpleFunction return awesomeService', function () {
431 expect(decorator.simpleFunction()).toEqual('awesomeService');
432 });
433});
434
435```
436
437### Directive
438Generates a directive, its template, and its test.
439
440Example:
441```
442yo ng-poly:directive fancy-button
443[?] Which module is this for?
444```
445
446Produces `app/module/fancy-button-directive.js`:
447```javascript
448(function () {
449 'use strict';
450
451 /**
452 * @ngdoc directive
453 * @name module.directive:fancyButton
454 * @restrict EA
455 * @element
456 *
457 * @description
458 *
459 * @example
460 <example module="module">
461 <file name="index.html">
462 <fancy-button></fancy-button>
463 </file>
464 </example>
465 *
466 */
467 angular
468 .module('module')
469 .directive('fancyButton', fancyButton);
470
471 function fancyButton() {
472 return {
473 restrict: 'EA',
474 scope: {},
475 templateUrl: 'module/fancy-button-directive.tpl.html',
476 replace: false,
477 controller: function (scope) {
478 scope.fancyButton = {};
479 scope.fancyButton.name = 'fancyButton';
480 },
481 link: function (scope, element, attrs) {
482 /*jshint unused:false */
483 /*eslint "no-unused-vars": [2, {"args": "none"}]*/
484 }
485 };
486 }
487}());
488
489```
490
491Produces `app/module/fancy-button-directive.tpl.html`:
492```html
493<div>{{fancyButton.name}}</div>
494```
495
496Produces `app/module/fancy-button-directive_test.js`:
497```javascript
498/*global describe, beforeEach, it, expect, inject, module*/
499'use strict';
500
501describe('fancyButton', function () {
502 var scope;
503 var element;
504
505 beforeEach(module('module', 'module/fancy-button-directive.tpl.html'));
506
507 beforeEach(inject(function ($compile, $rootScope) {
508 scope = $rootScope.$new();
509 element = $compile(angular.element('<fancy-button></fancy-button>'))(scope);
510 }));
511
512 it('should have correct text', function () {
513 scope.$apply();
514 expect(element.isolateScope().fancyButton.name).toEqual('fancyButton');
515 });
516});
517
518```
519**The directive's template (HAML, HTML, or Jade) is converted to a temporary module automatically for testing.**
520
521### Factory
522Generates a factory and its test.
523
524Example:
525```
526yo ng-poly:factory cake
527[?] Which module is this for?
528```
529
530Produces `app/module/cake-factory.js`:
531```javascript
532(function () {
533 'use strict';
534
535 /**
536 * @ngdoc service
537 * @name module.factory:Cake
538 *
539 * @description
540 *
541 */
542 angular
543 .module('module')
544 .factory('Cake', Cake);
545
546 function Cake() {
547 var CakeBase = {};
548 CakeBase.someValue = 'Cake';
549 CakeBase.someMethod = function () {
550 return 'Cake';
551 };
552 return CakeBase;
553 }
554}());
555
556```
557
558Produces `app/module/Cake-factory_test.js`:
559```javascript
560/*global describe, beforeEach, it, expect, inject, module*/
561'use strict';
562
563describe('Cake', function () {
564 var factory;
565
566 beforeEach(module('module'));
567
568 beforeEach(inject(function (Cake) {
569 factory = Cake;
570 }));
571
572 it('should have someValue be Cake', function () {
573 expect(factory.someValue).toEqual('Cake');
574 });
575
576 it('should have someMethod return Cake', function () {
577 expect(factory.someMethod()).toEqual('Cake');
578 });
579});
580
581```
582
583### Filter
584Generates a filter and its test.
585
586Example:
587```
588yo ng-poly:filter coffee
589[?] Which module is this for?
590```
591
592Produces `app/module/coffee-filter.js`:
593```javascript
594(function () {
595 'use strict';
596
597 /**
598 * @ngdoc filter
599 * @name module.filter:coffee
600 *
601 * @description
602 *
603 * @param {Array} input The array to filter
604 * @returns {Array} The filtered array
605 *
606 */
607 angular
608 .module('module')
609 .filter('coffee', coffee);
610
611 function coffee() {
612 return function (input) {
613 var temp = [];
614 angular.forEach(input, function (item) {
615 if(item > 3) {
616 temp.push(item);
617 }
618 });
619 return temp;
620 };
621 }
622}());
623
624```
625
626Produces `app/module/coffee-filter_test.js`:
627```javascript
628/*global describe, beforeEach, it, expect, inject, module*/
629'use strict';
630
631describe('coffee', function () {
632 beforeEach(module('module'));
633
634 it('should filter our numbers not greater than 3', inject(function ($filter) {
635 expect($filter('coffee')([1,2,3,4])).toEqual([4]);
636 }));
637});
638
639```
640
641### Module
642Generates a new module and create a new route. Updates parent module's dependencies.
643
644**Top Level Example:**
645```
646yo ng-poly:module top
647```
648
649Produces `app/top/top-module.js`:
650```javascript
651(function () {
652 'use strict';
653
654 /* @ngdoc object
655 * @name top
656 * @description
657 *
658 */
659 angular
660 .module('top', [
661 'ui.router'
662 ]);
663}());
664
665```
666
667Produces `pp/top/top-routes.js`:
668```javascript
669(function () {
670 'use strict';
671
672 angular
673 .module('top')
674 .config(config);
675
676 function config($stateProvider) {
677 $stateProvider
678 .state('top', {
679 url: '/top',
680 templateUrl: 'top/top.tpl.html',
681 controller: 'TopCtrl'
682 });
683 }
684}());
685
686```
687
688Produces `app/top/top-controller.js`, `app/top/top-controller_test.js`, `app/top/top.tpl.html`, `app/top/top.less`, `e2e/top/top.po.js`, `e2e/top/top_test.js`
689
690Updates `app/app-module.js`:
691```javascript
692(function () {
693 'use strict';
694
695 /* @ngdoc object
696 * @name module
697 * @requires $urlRouterProvider
698 * @description
699 *
700 */
701 angular
702 .module('module', [
703 'ui.router',
704 'home',
705 'top'
706 ]);
707}());
708
709```
710
711* * *
712
713**Deep Level Example:**
714```
715yo ng-poly:module top/bottom
716```
717
718Produces `app/top/bottom/bottom-module.js`, `app/top/boottom/bottom-routes.js`, `app/top/bottom/bottom-controller.js`, `app/top/bottom/bottom-controller_test.js`, `app/top/bottom/bottom.tpl.html`, `app/top/bottom/bottom.less`, `e2e/bottom/bottom.po.js`, `e2e/bottom/bottom_test.js`
719
720Updates `app/top/top-module.js`:
721```javascript
722(function () {
723 'use strict';
724
725 /* @ngdoc object
726 * @name top
727 * @requires $stateProvider
728 *
729 * @description
730 *
731 */
732 angular
733 .module('top', [
734 'ui.router',
735 'top.bottom'
736 ]);
737}());
738
739```
740
741**Notice the module in `app/top/bottom/` is called 'top.bottom'. All tests in this directory use this nomenclature, as well.**
742
743* * *
744**Deeper Level Example:**
745```
746yo ng-poly:module top/bottom/bottomest
747```
748
749Produces 'bottom.bottomest' module and routes, a controller, controller test, style, and a view in `app/top/bottom/bottomest/`
750
751Updates 'top.bottom' module with the new 'bottom.bottemest' module as a dependency.
752
753* * *
754**Deeperestier Level Example:**
755
756It just keeps going...
757
758* * *
759**Empty modules**
760
761By running `ng-poly:module newHome --empty` a module's routes file will **not** be created.
762
763The module file will omit the router dependency:
764```javascript
765(function () {
766 'use strict';
767
768 /* @ngdoc object
769 * @name newHome
770 *
771 * @description
772 *
773 */
774 angular
775 .module('newHome', [
776 ]);
777}());
778
779```
780
781### Provider
782Generates a provider and its test.
783
784Example:
785```
786yo ng-poly:provider bacon
787[?] Which module is this for?
788```
789
790Produces `app/module/bacon-provider.js`:
791```javascript
792(function () {
793 'use strict';
794
795 /**
796 * @ngdoc service
797 * @name module.provider:Bacon
798 *
799 * @description
800 *
801 */
802 angular
803 .module('module')
804 .provider('Bacon', Bacon);
805
806 function Bacon() {
807 return {
808 $get: function () {
809 return 'Bacon';
810 }
811 };
812 }
813}());
814
815```
816
817Produces `app/module/Bacon-provider_test.js`:
818```javascript
819/*global describe, beforeEach, it, expect, inject, module*/
820'use strict';
821
822describe('Bacon', function () {
823 var provider;
824
825 beforeEach(module('module'));
826
827 beforeEach(inject(function (Bacon) {
828 provider = Bacon;
829 }));
830
831 it('should equal Bacon', function () {
832 expect(provider).toEqual('Bacon');
833 });
834});
835
836```
837
838### Route
839Adds a new route and generates a controller and view. The name provided is used as state name for UI Router and as the route URL for ngRoute. Yeoman will then ask for the module to add the route to, the URL for the route (UI Router only), and the templateUrl. It will also generate an e2e test and a Page Object model for the new route.
840
841Example:
842```
843yo ng-poly:route your-place
844[?] Which module is this for?
845[?] What's the URL for this route? (UI Router only)
846[?] What's the templateURL for this route?
847```
848
849Updates `app/module/module-module.js`:
850```javascript
851(function () {
852 'use strict';
853
854 /* @ngdoc object
855 * @name module
856 * @requires $stateProvider
857 *
858 * @description
859 *
860 */
861 angular
862 .module('module', [
863 'ui.router'
864 ]);
865
866 angular
867 .module('module')
868 .config(config);
869
870 function config($stateProvider) {
871 $stateProvider
872 .state('module', {
873 url: '/module',
874 templateUrl: 'module/module.tpl.html',
875 controller: 'ModuleCtrl'
876 })
877 .state('yourPlace', {
878 url: '/yourPlace',
879 templateUrl: 'module/your-place.tpl.html',
880 controller: 'YourPlaceCtrl'
881 });
882 }
883}());
884
885```
886
887Produces `e2e/your-place/your-place.po.js`:
888```javascript
889/*global element, by*/
890'use strict';
891
892var YourPlacePage = function () {
893 this.text = element(by.tagName('p'));
894 this.heading = element(by.tagName('h2'));
895};
896
897module.exports = YourPlacePage;
898```
899
900Produces `e2e/your-place/your-place_test.js`:
901```javascript
902/*global describe, beforeEach, it, browser, expect */
903'use strict';
904
905var buildConfigFile = require('findup-sync')('build.config.js')
906 , buildConfig = require(buildConfigFile)
907 , YourPlacePagePo = require('./your-place.po');
908
909describe('Your place page', function () {
910 var yourPlacePage;
911
912 beforeEach(function () {
913 yourPlacePage = new YourPlacePagePo();
914 browser.driver.get(buildConfig.host + ':' + buildConfig.port + '/#/yourPlace');
915 });
916
917 it('should say YourPlaceCtrl', function () {
918 expect(yourPlacePage.heading.getText()).toEqual('yourPlace');
919 expect(yourPlacePage.text.getText()).toEqual('YourPlaceCtrl');
920 });
921});
922
923```
924
925Produces `app/module/your-place-controller.js`, `app/module/your-place-controller_test.js`, `app/module/your-place.tpl.html`, and `app/module/your-place.less`
926
927**Currently, the module must have an existing state for another to be added.**
928
929* * *
930The route generator can take URL and templateUrl options, as well.
931```
932yo ng-poly:route yourPlace --url=yourPlace --template-url=your-place
933```
934The URL will automatically be prepended with `/` and and the templateUrl will be appended with `.tpl.html`.
935* * *
936
937### Service
938Generates a service and its test.
939
940Example:
941```
942yo ng-poly:service cheap-or-good
943[?] Which module is this for?
944```
945
946Produces `app/module/cheap-or-good-service.js`:
947```javascript
948(function () {
949 'use strict';
950
951 /**
952 * @ngdoc service
953 * @name home.service:CheapOrGood
954 *
955 * @description
956 *
957 */
958 angular
959 .module('module')
960 .service('CheapOrGood', CheapOrGood);
961
962 function CheapOrGood() {
963 var self = this;
964
965 self.get = function get() {
966 return 'CheapOrGood';
967 };
968 }
969}());
970
971```
972
973Produces `app/module/cheap-or-good-service_test.js`:
974```javascript
975/*global describe, beforeEach, it, expect, inject, module*/
976'use strict';
977
978describe('CheapOrGood', function () {
979 var service;
980
981 beforeEach(module('module'));
982
983 beforeEach(inject(function (CheapOrGood) {
984 service = CheapOrGood;
985 }));
986
987 it('should equal CheapOrGood', function () {
988 expect(service.get()).toEqual('CheapOrGood');
989 });
990});
991
992```
993
994### Value
995Generates a value and its test.
996
997Example:
998```
999yo ng-poly:value morals
1000[?] Which module is this for?
1001```
1002
1003Produces `app/module/morals-value.js`:
1004```javascript
1005(function () {
1006 'use strict';
1007
1008 /**
1009 * @ngdoc service
1010 * @name module.constant:morals
1011 *
1012 * @description
1013 *
1014 */
1015 angular
1016 .module('module')
1017 .value('morals', 0);
1018}());
1019
1020```
1021
1022Produces `app/module/morals-value_test.js`:
1023```javascript
1024/*global describe, beforeEach, it, expect, inject, module*/
1025'use strict';
1026
1027describe('morals', function () {
1028 var value;
1029
1030 beforeEach(module('module'));
1031
1032 beforeEach(inject(function (morals) {
1033 value = morals;
1034 }));
1035
1036 it('should equal 0', function () {
1037 expect(value).toBe(0);
1038 });
1039});
1040
1041```
1042
1043### View
1044Generates a view and its style.
1045
1046Example:
1047```
1048yo ng-poly:view nice
1049[?] Which module is this for?
1050```
1051
1052Produces `app/module/nice-view.tpl.html`:
1053```html
1054<h2>nice</h2>
1055<p>{{nice.ctrlName}}</p>
1056```
1057
1058Produces an empty file `app/module/nice-view.less`
1059
1060* * *
1061
1062### Element
1063Generates a Polymer element.
1064
1065Example:
1066```
1067yo ng-poly:element gold-silver
1068```
1069
1070Produces `app/components/gold-silver/gold-silver.less`:
1071```css
1072:host {
1073 height: 100px;
1074 width: 100px;
1075 display: inline-block;
1076}
1077```
1078
1079Produces `app/components/gold-silver/gold-silver.html`:
1080```html
1081<link rel='import' href='../polymer/polymer.html'>
1082
1083<polymer-element name='gold-silver'>
1084 <template>
1085 <link rel='stylesheet' href='gold-silver.css'>
1086 <div>{{name}}</div>
1087 </template>
1088
1089 <script src='gold-silver.js'></script>
1090</polymer-element>
1091```
1092
1093Produces `app/components/gold-silver/gold-silver.js`:
1094```javascript
1095/*global Polymer*/
1096(function () {
1097 'use strict';
1098
1099 var element = new Polymer({
1100 is: 'gold-silver',
1101 ready: function () {
1102 console.log('gold-silver');
1103 }
1104 });
1105
1106 return element;
1107}());
1108```
1109
1110* * *
1111
1112## Configurations
1113
1114It is possible to override the configurations initially specified when `yo ng-poly` was ran.
1115
1116Each generator is able to take the following arguments. For example, `yo ng-poly:module test --controller-as=true` will override the configuration settings for everything generated by this command.
1117
1118| Option | Possible Values|
1119| ------ | -------------- |
1120| controller-as | true, false |
1121| skip-controller | true, false |
1122| ng-route | true, false|
1123
1124**It's not recommended to mix ngRoute and UI Router, but it's possible.**
1125
1126### Controller As Syntax
1127
1128This generator has support for the Controller As syntax. Yeoman will ask if this should be enabled when `ng-poly:app` is ran.
1129
1130This will generate controllers like:
1131
1132```javascript
1133(function () {
1134 'use strict';
1135
1136 /**
1137 * @ngdoc object
1138 * @name home.controller:HomeCtrl
1139 *
1140 * @description
1141 *
1142 */
1143 angular
1144 .module('home')
1145 .controller('HomeCtrl', HomeCtrl);
1146
1147 function () {
1148 var vm = this;
1149 vm.ctrlName = 'HomeCtrl';
1150 }
1151}());
1152```
1153
1154...and their tests like:
1155
1156```javascript
1157/*global describe, beforeEach, it, expect, inject, module*/
1158'use strict';
1159
1160describe('HomeCtrl', function () {
1161 var ctrl;
1162
1163 beforeEach(module('home'));
1164
1165 beforeEach(inject(function ($rootScope, $controller) {
1166 ctrl = $controller('HomeCtrl');
1167 }));
1168
1169 it('should have ctrlName as HomeCtrl', function () {
1170 expect(ctrl.ctrlName).toEqual('HomeCtrl');
1171 });
1172});
1173
1174```
1175
1176It'll also modify the state's controller like:
1177
1178```javascript
1179(function () {
1180 'use strict';
1181
1182 /* @ngdoc object
1183 * @name home
1184 * @requires $stateProvider
1185 *
1186 * @description
1187 *
1188 */
1189 angular
1190 .module('home', [
1191 'ui.router'
1192 ]);
1193
1194 angular
1195 .module('home')
1196 .config(config);
1197
1198 function config($stateProvider) {
1199 $stateProvider
1200 .state('home', {
1201 url: '/home',
1202 templateUrl: 'home/home.tpl.html',
1203 controller: 'HomeCtrl as home'
1204 });
1205 }
1206}());
1207
1208```
1209
1210Directives will be generated like:
1211
1212```javascript
1213(function () {
1214 'use strict';
1215
1216 /**
1217 * @ngdoc directive
1218 * @name home.directive:fancyButton
1219 * @restrict EA
1220 * @element
1221 *
1222 * @description
1223 *
1224 * @example
1225 <example module="home">
1226 <file name="index.html">
1227 <fancy-button></fancy-button>
1228 </file>
1229 </example>
1230 *
1231 */
1232 angular
1233 .module('home')
1234 .directive('fancyButton', fancyButton);
1235
1236 function fancyButton() {
1237 return {
1238 restrict: 'EA',
1239 scope: {},
1240 templateUrl: 'home/fancy-button-directive.tpl.html',
1241 replace: false,
1242 controllerAs: 'fancyButton',
1243 controller: function () {
1244 var vm = this;
1245 vm.name = 'fancyButton';
1246 },
1247 link: function (scope, element, attrs) {
1248 /*jshint unused:false */
1249 /*eslint "no-unused-vars": [2, {"args": "none"}]*/
1250 }
1251 };
1252 }
1253}());
1254
1255```
1256
1257Lastly, views will be generated like:
1258
1259```html
1260<h2>home</h2>
1261<p>{{home.ctrlName}}</p>
1262```
1263
1264* * *
1265
1266## Gulp Tasks in Detail
1267
1268*Items in italics are only ran in --stage=prod*
1269
1270Available tasks:
1271- `gulp` or `gulp default`
1272 - Runs `gulp dev`
1273- `gulp dev`
1274 - Runs `gulp build` and starts BrowserSync and Gulp's watch
1275- `gulp build`
1276 - Runs `gulp analyze`
1277 - Runs `gulp clean` to delete build directory
1278 - Runs `gulp markup` to compile Haml and Jade to HTML
1279 - Runs `gulp styles` to compile Less, SCSS, and Stylus (with Nib), add vendor prefixes, *modify images and font URLs*, *concat*, *minify*, and *rev*
1280 - Runs `gulp scripts` to compile ES2015, CoffeeScript, and TypeScript, *injects HTML templates in $templateCache*, *sorts Angular files*, *annotates*, *minifies*, and *rev*
1281 - Runs `gulp inject` to inject sorted JS and CSS source files into build/index.html
1282 - Runs `gulp bowerCopy` to *modify image and font URLs in vendor CSS files*, *concat vendor CSS*, *minify vendor CSS*, *rev vendor CSS*, copy vendor CSS to build, *concat vendor JS*, *minify vendor JS and leave licenses intact*, copy vendor JS to build
1283 - Runs `gulp bowerInject` to inject vendor CSS and JS into build/index.html
1284 - Runs `gulp bowerAssets` to copy over any vendor image and fonts to build/
1285 - Runs `gulp fonts` to copy app fonts to build/
1286 - Runs `gulp images` to copy app images to build/
1287 - Runs `gulp copyTemplates` to copy compiled templates to a separate test directory used for unit testing
1288 - Runs `gulp deleteTemplates` to *delete templates in build*
1289- `gulp unitTest`
1290 - Runs `gulp lint`
1291 - Runs `gulp clean:test` to delete previous compiled unit tests
1292 - Runs `gulp buildTests` to compile CoffeeScript, ES2015, and TypeScript unit tests
1293 - Runs `gulp build`
1294 - Runs `gulp karmaFiles` to automatically configure Bower dependencies, directive templates, sorted build JS files, and unit tests for Karma
1295 - Run unit tests with Karma
1296- `gulp e2eTest`
1297 - Runs `gulp lint`
1298 - Runs `gulp build`
1299 - Runs `gulp build:e2eTest` to compile CoffeeScript, ES2015, and TypeScript tests
1300 - Runs Protractor to perform e2eTest (**app needs to be running via `gulp default`**)
1301- `gulp webdriverUpdate` downloads Selenium and webdrivers for e2e testing
1302- `gulp analyze`
1303 - Analyzes source and test code with CoffeeLint, ESLint, JSHint, and JSCS
1304 - Uses Plato to inspect source and test for complexity and maintainability
1305
1306* * *
1307
1308## How to Add Polymer elements
1309
1310Currently, this process isn't as simple as desired. **Pull requests are greatly appreciated to help this process in any way.**
1311
1312For this, we're going to install and setup `paper-toolbar`.
1313
13141. Run `bower install --save polymerelements/paper-toolbar` to download `paper-toolbar` and its dependencies.
13151. Digging through `bower_components/paper-toolbar/`, we can determine it needs to have `paper-toolbar/paper-toolbar.html`, `paper-styles/paper-styles.html`, and `polymer/polymer`. We then dig through `bower_components/paper-styles/` to find it needs `paper-styles/paper-styles.html`, `paper-styles/color.html`, `paper-styles/default-theme.html`, `paper-styles/shadow.html`, `paper-styles/typography.html`, `iron-flex-layout/iron-flex-layout.html`, and `iron-flex-layout/classes/iron-flex-layout.html`. Then we dig through `iron-flex-layout/iron-flex-layout` to find out we just need to additionally include `iron-flex-layout/iron-flex-layout/classes/iron-shadow-flex-layout.html`.
13161. Edit the `components` task in `gulp/build.js` to include polymerBowerAssetsToCopy like:
1317
1318 ```javascript
1319 polymerBowerAssetsToCopy = [
1320 'polymer/polymer*.html',
1321 'iron-flex-layout/iron-flex-layout.html',
1322 'iron-flex-layout/classes/*.html',
1323 'paper-styles/{color,default-theme,paper-styles,shadow.html,typography.html}',
1324 'paper-toolbar/paper-toolbar.html'
1325 ].map(function (file) {
1326 return bowerDir + file;
1327 });
1328 ```
1329
13301. Edit the `componentsInject` task in `gulp/build.js` to include
1331
1332 ```javascript
1333 var polymerAssetsToInject = [
1334 'polymer/polymer.html',
1335 'paper-styles/paper-styles.html'
1336 ].map(function (file) {
1337 return config.buildComponents + file;
1338 });
1339 ```
1340
13411. Now, we can use the `<paper-toolbar>` element in our code.
1342
1343**Note: for custom components, we just need to include them in `polymerAssetsToInject`. They are all automically copied.**
1344* * *
1345
1346### License
1347
1348MIT
1349
\No newline at end of file