UNPKG

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