├── generators └── app │ ├── templates │ ├── app │ │ ├── router.js │ │ ├── methods │ │ │ └── .keep │ │ ├── packages │ │ │ └── .keep │ │ ├── private │ │ │ └── .keep │ │ ├── public │ │ │ └── .keep │ │ ├── client │ │ │ ├── lib │ │ │ │ └── .keep │ │ │ ├── routes │ │ │ │ ├── .keep │ │ │ │ └── login │ │ │ │ │ ├── login.html │ │ │ │ │ └── login.js │ │ │ ├── autoruns │ │ │ │ └── .keep │ │ │ ├── components │ │ │ │ ├── .keep │ │ │ │ ├── layout-login │ │ │ │ │ ├── layout-login.html │ │ │ │ │ └── layout-login.js │ │ │ │ └── layout-main │ │ │ │ │ ├── layout-main.html │ │ │ │ │ └── layout-main.js │ │ │ ├── stylesheets │ │ │ │ ├── base.scss │ │ │ │ ├── layout.scss │ │ │ │ ├── variables.scss │ │ │ │ └── components │ │ │ │ │ └── .keep │ │ │ ├── template-helpers │ │ │ │ └── .keep │ │ │ ├── router.js │ │ │ ├── subscriptions.js │ │ │ ├── index.html │ │ │ └── config-iron-router.js │ │ ├── server │ │ │ ├── lib │ │ │ │ ├── .keep │ │ │ │ └── constants.js │ │ │ ├── methods │ │ │ │ └── .keep │ │ │ ├── authorizations │ │ │ │ └── .keep │ │ │ ├── publications │ │ │ │ └── .keep │ │ │ ├── factories │ │ │ │ └── user.js │ │ │ └── seed.js │ │ ├── collection-hooks │ │ │ └── .keep │ │ ├── before │ │ │ └── lib │ │ │ │ ├── before │ │ │ │ ├── lodash.js │ │ │ │ └── constant.js │ │ │ │ └── schemas │ │ │ │ ├── 0-schema.js │ │ │ │ └── users.js │ │ ├── scss.json │ │ ├── collection-helpers │ │ │ └── users.js │ │ ├── index.scss │ │ └── .meteor │ │ │ └── packages │ ├── autorun │ │ └── autorun.js │ ├── collection-helper │ │ └── collection-helper.js │ ├── component │ │ ├── template.html │ │ └── template.js │ ├── method │ │ └── method.js │ ├── collection-hook │ │ └── collection-hook.js │ ├── factory │ │ └── factory.js │ ├── template-helper │ │ └── template-helper.js │ ├── publication │ │ └── publication.js │ ├── schema │ │ └── schema.js │ └── authorization │ │ └── authorization.js │ └── index.js ├── .gitignore ├── package.json └── README.md /generators/app/templates/app/router.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /generators/app/templates/app/methods/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /generators/app/templates/app/packages/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /generators/app/templates/app/private/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /generators/app/templates/app/public/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | npm-debug.log 3 | -------------------------------------------------------------------------------- /generators/app/templates/app/client/lib/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /generators/app/templates/app/client/routes/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /generators/app/templates/app/server/lib/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /generators/app/templates/app/client/autoruns/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /generators/app/templates/app/client/components/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /generators/app/templates/app/collection-hooks/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /generators/app/templates/app/server/methods/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /generators/app/templates/app/client/stylesheets/base.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /generators/app/templates/app/client/template-helpers/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /generators/app/templates/app/server/authorizations/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /generators/app/templates/app/server/publications/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /generators/app/templates/app/client/stylesheets/layout.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /generators/app/templates/app/client/stylesheets/variables.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /generators/app/templates/app/client/stylesheets/components/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /generators/app/templates/app/before/lib/before/lodash.js: -------------------------------------------------------------------------------- 1 | _ = lodash 2 | -------------------------------------------------------------------------------- /generators/app/templates/app/before/lib/before/constant.js: -------------------------------------------------------------------------------- 1 | Constant = {} 2 | -------------------------------------------------------------------------------- /generators/app/templates/app/before/lib/schemas/0-schema.js: -------------------------------------------------------------------------------- 1 | Schema = {} 2 | -------------------------------------------------------------------------------- /generators/app/templates/app/scss.json: -------------------------------------------------------------------------------- 1 | { 2 | "useIndex" : true 3 | } 4 | -------------------------------------------------------------------------------- /generators/app/templates/app/client/router.js: -------------------------------------------------------------------------------- 1 | Router.route('/', function () { 2 | }) 3 | -------------------------------------------------------------------------------- /generators/app/templates/app/client/subscriptions.js: -------------------------------------------------------------------------------- 1 | // Meteor.subscribe('users'); 2 | -------------------------------------------------------------------------------- /generators/app/templates/autorun/autorun.js: -------------------------------------------------------------------------------- 1 | Tracker.autorun(function () { 2 | 3 | }) 4 | -------------------------------------------------------------------------------- /generators/app/templates/app/collection-helpers/users.js: -------------------------------------------------------------------------------- 1 | Meteor.users.helpers({ 2 | 3 | }) 4 | -------------------------------------------------------------------------------- /generators/app/templates/app/server/lib/constants.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Server side only constants 3 | */ 4 | -------------------------------------------------------------------------------- /generators/app/templates/app/server/factories/user.js: -------------------------------------------------------------------------------- 1 | Factory.define('user', Meteor.users, { 2 | 3 | }) 4 | -------------------------------------------------------------------------------- /generators/app/templates/collection-helper/collection-helper.js: -------------------------------------------------------------------------------- 1 | <%= collectionName %>.helpers({ 2 | 3 | }) 4 | -------------------------------------------------------------------------------- /generators/app/templates/app/client/routes/login/login.html: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /generators/app/templates/component/template.html: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /generators/app/templates/method/method.js: -------------------------------------------------------------------------------- 1 | Meteor.methods({ 2 | <%= collectionNameCamel %>: function () { 3 | 4 | } 5 | }) 6 | -------------------------------------------------------------------------------- /generators/app/templates/collection-hook/collection-hook.js: -------------------------------------------------------------------------------- 1 | <%= collectionName %>.before.insert(function (userId, doc) { 2 | 3 | }) 4 | -------------------------------------------------------------------------------- /generators/app/templates/factory/factory.js: -------------------------------------------------------------------------------- 1 | Factory.define('<%= collectionNameCamelSingle %>', <%= collectionName %>, { 2 | 3 | }) 4 | -------------------------------------------------------------------------------- /generators/app/templates/app/client/index.html: -------------------------------------------------------------------------------- 1 | 2 | METEOR POETIC GENERATOR 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /generators/app/templates/template-helper/template-helper.js: -------------------------------------------------------------------------------- 1 | Template.registerHelper('<%= collectionNameCamel %>', function () { 2 | 3 | }) 4 | -------------------------------------------------------------------------------- /generators/app/templates/app/server/seed.js: -------------------------------------------------------------------------------- 1 | Meteor.startup(function(){ 2 | var preserveDb = false; 3 | if (preserveDb) { 4 | return 5 | } 6 | }) 7 | -------------------------------------------------------------------------------- /generators/app/templates/app/client/components/layout-login/layout-login.html: -------------------------------------------------------------------------------- 1 | 5 | -------------------------------------------------------------------------------- /generators/app/templates/app/client/components/layout-main/layout-main.html: -------------------------------------------------------------------------------- 1 | 5 | -------------------------------------------------------------------------------- /generators/app/templates/publication/publication.js: -------------------------------------------------------------------------------- 1 | Meteor.publish('<%= collectionNameCamel %>', function() { 2 | return <%= collectionName %>.find() 3 | }) 4 | -------------------------------------------------------------------------------- /generators/app/templates/app/index.scss: -------------------------------------------------------------------------------- 1 | @import "client/stylesheets/variables.scss"; 2 | @import "client/stylesheets/base.scss"; 3 | @import "client/stylesheets/layout.scss"; 4 | -------------------------------------------------------------------------------- /generators/app/templates/app/client/routes/login/login.js: -------------------------------------------------------------------------------- 1 | Template.Login.onRendered(function(){ 2 | 3 | }); 4 | 5 | Template.Login.helpers({ 6 | 7 | }); 8 | 9 | Template.Login.events({ 10 | 11 | }); 12 | -------------------------------------------------------------------------------- /generators/app/templates/component/template.js: -------------------------------------------------------------------------------- 1 | Template.<%= tplName %>.onRendered(function(){ 2 | 3 | }) 4 | 5 | Template.<%= tplName %>.helpers({ 6 | 7 | }) 8 | 9 | Template.<%= tplName %>.events({ 10 | 11 | }) 12 | -------------------------------------------------------------------------------- /generators/app/templates/app/client/components/layout-main/layout-main.js: -------------------------------------------------------------------------------- 1 | Template.LayoutMain.onRendered(function(){ 2 | 3 | }); 4 | 5 | Template.LayoutMain.helpers({ 6 | 7 | }); 8 | 9 | Template.LayoutMain.events({ 10 | 11 | }); 12 | -------------------------------------------------------------------------------- /generators/app/templates/app/client/components/layout-login/layout-login.js: -------------------------------------------------------------------------------- 1 | Template.LayoutLogin.onRendered(function(){ 2 | 3 | }); 4 | 5 | Template.LayoutLogin.helpers({ 6 | 7 | }); 8 | 9 | Template.LayoutLogin.events({ 10 | 11 | }); 12 | -------------------------------------------------------------------------------- /generators/app/templates/schema/schema.js: -------------------------------------------------------------------------------- 1 | var <%= collectionNameSingle %>Schema = new SimpleSchema({ 2 | }) 3 | 4 | <%= collectionName %> = new Mongo.Collection('<%= collectionNameCamel %>') 5 | <%= collectionName %>.attachSchema(<%= collectionNameSingle %>Schema) 6 | -------------------------------------------------------------------------------- /generators/app/templates/authorization/authorization.js: -------------------------------------------------------------------------------- 1 | <%= collectionName %>.allow({ 2 | insert: function (userId, doc) { 3 | return true 4 | }, 5 | update: function (userId, doc, fieldNames, modifier) { 6 | return true 7 | }, 8 | remove: function (userId, doc) { 9 | return true 10 | }, 11 | }) 12 | -------------------------------------------------------------------------------- /generators/app/templates/app/.meteor/packages: -------------------------------------------------------------------------------- 1 | meteor-platform 2 | erasaur:meteor-lodash 3 | iron:router 4 | fourseven:scss 5 | aldeed:simple-schema 6 | aldeed:collection2 7 | aldeed:autoform 8 | digilord:faker 9 | useraccounts:semantic-ui 10 | accounts-password 11 | dburles:factory 12 | dburles:collection-helpers 13 | matb33:collection-hooks 14 | -------------------------------------------------------------------------------- /generators/app/templates/app/client/config-iron-router.js: -------------------------------------------------------------------------------- 1 | var publicRoutes = [] 2 | 3 | Router.onBeforeAction(function () { 4 | // Public Routes 5 | var currentRoute = Router.current().route.getName() 6 | if(_.includes(publicRoutes, currentRoute)) { 7 | this.next() 8 | return 9 | } 10 | 11 | // Login If Not Logged In 12 | if(!Meteor.user()) { 13 | this.layout('LayoutLogin') 14 | this.render('Login') 15 | return 16 | } 17 | 18 | this.next() 19 | }) 20 | 21 | Router.configure({ 22 | layoutTemplate: 'LayoutMain' 23 | }) 24 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "generator-meteor-poetic", 3 | "version": "1.0.4", 4 | "description": "An opinionaed Yeoman generator for meteor", 5 | "main": "generators/index.js", 6 | "dependencies": { 7 | "inflection": "^1.7.1", 8 | "lodash": "^3.8.0", 9 | "yeoman-generator": "^0.20.1" 10 | }, 11 | "devDependencies": {}, 12 | "scripts": { 13 | "test": "echo \"Error: no test specified\" && exit 1" 14 | }, 15 | "keywords": [ 16 | "yeoman-generator", 17 | "generator", 18 | "meteor" 19 | ], 20 | "files": [ 21 | "templates", 22 | "generators" 23 | ], 24 | "author": "Chun Yang", 25 | "license": "ISC", 26 | "repository": "https://github.com/poetic/generator-meteor-poetic" 27 | } 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Install 2 | ``` 3 | npm install generator-meteor-poetic 4 | ``` 5 | 6 | # [File structure and the reason behind it](http://chun-yang.github.io/meteor/2015/08/08/how-to-structure-meteor-app.html) 7 | 8 | # Usage 9 | Read generators/index.js to have a full list of generators. 10 | ``` 11 | # You can create an alias 12 | # alias mg='yo meteor-poetic' 13 | 14 | yo meteor-poetic 15 | # generate a new meteor project 16 | 17 | yo meteor-poetic route admin/show 18 | # ./client/routes/admin/show/show.html 19 | # ./client/routes/admin/show/show.js 20 | 21 | yo meteor-poetic component admin/show 22 | # ./client/components/admin/show/show.html 23 | # ./client/components/admin/show/show.js 24 | 25 | yo meteor-poetic template-helper image-src 26 | # ./client/template-helpers/image-src.js 27 | 28 | yo meteor-poetic schema campaigns 29 | # ./schema/campaigns.js 30 | 31 | yo meteor-poetic publication campaigns 32 | # ./server/publications/campaigns.js 33 | 34 | yo meteor-poetic factory campaigns 35 | # ./server/factorys/campaigns.js 36 | 37 | yo meteor-poetic collection-helpers campaigns 38 | # ./collection-helpers/campaigns.js 39 | 40 | yo meteor-poetic collection-helpers campaigns --server 41 | # ./server/collection-helpers/campaigns.js 42 | ``` 43 | -------------------------------------------------------------------------------- /generators/app/templates/app/before/lib/schemas/users.js: -------------------------------------------------------------------------------- 1 | var UserProfile = new SimpleSchema({ 2 | 3 | }) 4 | 5 | var UserSchema = new SimpleSchema({ 6 | username: { 7 | type: String, 8 | regEx: /^[a-z0-9A-Z_]{3,15}$/ 9 | }, 10 | emails: { 11 | type: [Object], 12 | optional: true 13 | }, 14 | "emails.$.address": { 15 | type: String, 16 | regEx: SimpleSchema.RegEx.Email 17 | }, 18 | "emails.$.verified": { 19 | type: Boolean 20 | }, 21 | createdAt: { 22 | type: Date 23 | }, 24 | profile: { 25 | type: UserProfile, 26 | optional: true 27 | }, 28 | services: { 29 | type: Object, 30 | optional: true, 31 | blackbox: true 32 | }, 33 | 34 | // # Add `roles` to your schema if you use the meteor-roles package. 35 | 36 | // ## Option 1: Object type 37 | // If you specify that type as Object, you must also specify the 38 | // `Roles.GLOBAL_GROUP` group whenever you add a user to a role. 39 | // Example: 40 | // Roles.addUsersToRoles(userId, ["admin"], Roles.GLOBAL_GROUP); 41 | // You can't mix and match adding with and without a group since 42 | // you will fail validation in some cases. 43 | 44 | // roles: { 45 | // type: Object, 46 | // optional: true, 47 | // blackbox: true 48 | // }, 49 | 50 | // ## Option 2: [String] type 51 | // If you are sure you will never need to use role groups, then 52 | // you can specify [String] as the type 53 | 54 | // roles: { 55 | // type: [String], 56 | // optional: true 57 | // } 58 | }) 59 | 60 | Meteor.users.attachSchema(UserSchema) 61 | -------------------------------------------------------------------------------- /generators/app/index.js: -------------------------------------------------------------------------------- 1 | var generators = require('yeoman-generator') 2 | var _ = require('lodash') 3 | var inflection = require('inflection') 4 | var sides = ['before', 'everywhere', 'client', 'server'] 5 | 6 | module.exports = generators.Base.extend({ 7 | constructor: function () { 8 | generators.Base.apply(this, arguments) 9 | 10 | this.option('client', { 11 | desc: 'Generate files in the client folder', 12 | type: Boolean 13 | }) 14 | this.option('server', { 15 | desc: 'Generate files in the server folder', 16 | type: Boolean 17 | }) 18 | this.option('everywhere', { 19 | desc: 'Generate files in the root folder', 20 | type: Boolean 21 | }) 22 | }, 23 | 24 | prompting: { 25 | // prefix is client by default 26 | addPrefixToOptions: function () { 27 | this.options.prefix = this.options.server ? 'server' : 'client' 28 | }, 29 | 30 | init: function (type) { 31 | if(!(typeof type === 'undefined')) { 32 | return 33 | } 34 | 35 | var done = this.async() 36 | 37 | this.prompt({ 38 | type: 'confirm', 39 | name: 'confirm', 40 | message: 'Create a new meteor project?' 41 | }, function (answer) { 42 | if(answer.confirm) { 43 | done() 44 | } else { 45 | process.exit(0) 46 | } 47 | }) 48 | }, 49 | }, 50 | 51 | writing: { 52 | init: function (type) { 53 | if(!(typeof type === 'undefined')) { 54 | return 55 | } 56 | 57 | this.directory('app', './') 58 | }, 59 | component: function (type, name) { 60 | if(!(type === 'component')) { 61 | return 62 | } 63 | 64 | if(this.options.server) { 65 | this.log.error('You can not create a component on the server side.') 66 | process.exit(1) 67 | } 68 | generateFilesForRoute(type, name, this) 69 | }, 70 | route: function (type, name) { 71 | if(!(type === 'route')) { 72 | return 73 | } 74 | 75 | generateFilesForRoute(type, name, this) 76 | // TODO: do not create new one if one route already exist 77 | addRouteToTheEndOfRouter(type, name, this) 78 | }, 79 | templateHelper: function (type, name) { 80 | if(!(type === 'template-helper')) { 81 | return 82 | } 83 | 84 | generateJsFile(type, name, 'client', this) 85 | }, 86 | schema: function (type, name) { 87 | if(!(type === 'schema')) { 88 | return 89 | } 90 | 91 | generateJsFile(type, name, 'before', this) 92 | }, 93 | factory: function (type, name) { 94 | if(!(type === 'factory')) { 95 | return 96 | } 97 | 98 | generateJsFile(type, name, 'server', this) 99 | }, 100 | publication: function (type, name) { 101 | if(!(type === 'publication')) { 102 | return 103 | } 104 | 105 | generateJsFile(type, name, 'server', this) 106 | }, 107 | authorization: function (type, name) { 108 | if(!(type === 'authorization')) { 109 | return 110 | } 111 | 112 | generateJsFile(type, name, 'server', this) 113 | }, 114 | autorun: function (type, name) { 115 | if(!(type === 'autorun')) { 116 | return 117 | } 118 | 119 | generateJsFile(type, name, 'client', this) 120 | }, 121 | method: function (type, name) { 122 | if(!(type === 'method')) { 123 | return 124 | } 125 | 126 | generateJsFile(type, name, 'everywhere', this) 127 | }, 128 | collectionHelper: function (type, name) { 129 | if(!(type === 'collection-helper')) { 130 | return 131 | } 132 | 133 | generateJsFile(type, name, 'everywhere', this) 134 | }, 135 | collectionHook: function (type, name) { 136 | if(!(type === 'collection-hook')) { 137 | return 138 | } 139 | 140 | generateJsFile(type, name, 'everywhere', this) 141 | }, 142 | }, 143 | 144 | // Helpers 145 | _getSide: function (defalutSide) { 146 | var generator = this 147 | 148 | var selectedSide = _.find(sides, function (side) { 149 | return generator.options[side] 150 | }) 151 | 152 | return selectedSide || defalutSide 153 | }, 154 | }); 155 | 156 | /* 157 | * generate file for route or component 158 | */ 159 | function generateFilesForRoute (type, name, generator) { 160 | if(!name) { 161 | generator.log.error('You need a ' + type + ' name.') 162 | process.exit(1) 163 | } 164 | 165 | var routeInfo = parseRouteName(name, generator) 166 | var filePath = [generator.options.prefix, inflection.pluralize(type) , routeInfo.filePath].join('/') 167 | var tplName = routeInfo.tplName 168 | 169 | generator.fs.copyTpl( 170 | generator.templatePath('component/template.html'), 171 | generator.destinationPath(filePath + '.html'), 172 | {tplName: tplName} 173 | ) 174 | generator.fs.copyTpl( 175 | generator.templatePath('component/template.js'), 176 | generator.destinationPath(filePath + '.js'), 177 | {tplName: tplName} 178 | ) 179 | } 180 | 181 | function addRouteToTheEndOfRouter (type, name, generator) { 182 | var path = "client/router.js" 183 | var file = generator.readFileAsString(path) 184 | file += [ 185 | "", 186 | "Router.route('/" + name + "', function () {", 187 | " this.render('" + capitalize(name)+ "')", 188 | "})" 189 | ].join("\n") 190 | 191 | /* make modifications to the file string here */ 192 | 193 | generator.writeFileFromString(file, path); 194 | } 195 | 196 | /* 197 | * @return 198 | * { 199 | * filePath: {String}, 200 | * tplName: {String} 201 | * } 202 | */ 203 | function parseRouteName (name, generator) { 204 | var filePath = name 205 | var fileName = extractFileName(name) 206 | var tplName = capitalize(name) 207 | 208 | // make sure name is not camelcase 209 | if(name !== name.toLowerCase()) { 210 | generator.log.error('Your name (' + name + ') ' + 'should not be camelcase, use "-" instead') 211 | process.exit(1) 212 | } 213 | 214 | return { 215 | filePath: name + '/' + fileName, 216 | tplName: tplName 217 | } 218 | } 219 | 220 | /* 221 | * @param defaultSide {'client'|'server'|'everywhere'} 222 | */ 223 | function generateJsFile (type, name, defaultSide, generator) { 224 | var side = generator._getSide(defaultSide) 225 | var prefix 226 | if(side === 'before') { 227 | prefix = 'before/lib' 228 | } else if (side === 'everywhere') { 229 | prefix = '' 230 | } else { 231 | prefix = side 232 | } 233 | 234 | var collectionName = capitalize(name) 235 | var collectionNameSingle = inflection.singularize(collectionName) 236 | var collectionNameCamel = camelize(collectionName) 237 | var collectionNameCamelSingle = inflection.singularize(collectionNameCamel) 238 | 239 | var templatePath = concatAsPath(type, type) + '.js' 240 | var destinationPath = concatAsPath(prefix, inflection.pluralize(type), name) + '.js' 241 | 242 | generator.fs.copyTpl( 243 | generator.templatePath(templatePath), 244 | generator.destinationPath(destinationPath), 245 | { 246 | collectionName: collectionName, 247 | collectionNameSingle: collectionNameSingle, 248 | collectionNameCamel: collectionNameCamel, 249 | collectionNameCamelSingle: collectionNameCamelSingle 250 | } 251 | ) 252 | } 253 | 254 | function capitalize (str) { 255 | var segments = str.split('/').filter(Boolean) 256 | var capitalizedName = segments.map(function(segment){ 257 | return segment.split(/[-_]/).map(_.capitalize).join(''); 258 | }).join(''); 259 | return capitalizedName 260 | } 261 | 262 | function camelize (str) { 263 | return deCapitalizeFirst(capitalize(str)) 264 | } 265 | 266 | function deCapitalizeFirst (str) { 267 | return str[0].toLowerCase() + str.substr(1) 268 | } 269 | 270 | function extractFileName (path) { 271 | return _.last(path.split('/')) 272 | } 273 | 274 | function concatAsPath () { 275 | var segments = Array.prototype.slice.call(arguments).filter(Boolean) 276 | return _.flatten(segments).join('/') 277 | } 278 | --------------------------------------------------------------------------------