Skip to content
This repository has been archived by the owner on Jun 15, 2023. It is now read-only.

Commit

Permalink
Add new generators implementation.
Browse files Browse the repository at this point in the history
  • Loading branch information
paulmillr committed Jul 3, 2012
1 parent 3db09a1 commit 125b69d
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 200 deletions.
19 changes: 19 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,22 @@
# Brunch 1.4.0 (unreleased)
* Added new phenomenally simplified scaffolding:
1. Create `generators/` directory in your brunch application.
2. Place generator there in a way that mirrors generated file path.
For example, if you want `brunch generate <generator-name>`
to create new file in `app/views/styles`, you'll need to create
`generators/app/views/styles/<generator-name>.<extension>`.
`brunch generate --path PARENT-DIR` is still supported for custom paths.
3. Generator relations (e.g. create `model-test` for every `model`) are
now customizable & supported via `config.generatorsRelations`.
Example: `generatorsRelations: {model: ['model-test']}`.
* Because of new scaffolding API, a lot of things is now not needed:
* Removed support for `config.files[lang].defaultExtension`.
Brunch will automatically detect extension from your generator file name.
* Removed support for `config.framework`. It's not needed because
all generators are local to your application.
* Removed support for `config.generators`.
* All these deprecations will now alert a warning.

# Brunch 1.3.3 (June 29, 2012)
* Added node.js 0.8 and 0.9 support.
* `jsdom`, required for `brunch test` can now be installed once
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
"async": "0.1.x",
"mkdirp": "0.3.x",
"ncp": "0.2.x",
"walk": "2.2.x",
"rimraf": "2.0.x",
"growl": "1.5.x",
"express": "2.5.x",
Expand Down
266 changes: 66 additions & 200 deletions src/commands/scaffold.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ fs = require 'fs'
inflection = require 'inflection'
mkdirp = require 'mkdirp'
sysPath = require 'path'
walk = require 'walk'
helpers = require '../helpers'
logger = require '../logger'
fs_utils = require '../fs_utils'
Expand All @@ -14,201 +15,59 @@ flatten = (array) ->
acc.concat(if Array.isArray(elem) then flatten(elem) else [elem])
, []

categories =
backbone:
'model-test': 'javascripts'
model: 'javascripts'
'collection-test': 'javascripts'
collection: 'javascripts'
template: 'templates'
style: 'stylesheets'
'view-test': 'javascripts'
view: 'javascripts'
scaffold: 'javascripts'

chaplin:
'controller-test': 'javascripts'
controller: 'javascripts'
'model-test': 'javascripts'
model: 'javascripts'
'collection-test': 'javascripts'
collection: 'javascripts'
template: 'templates'
style: 'stylesheets'
'view-test': 'javascripts'
view: 'javascripts'
'collection-view-test': 'javascripts'
'collection-view': 'javascripts'
'page-view-test': 'javascripts'
'page-view': 'javascripts'
scaffold: 'javascripts'

frameworkChocies = ->
Object.keys(categories).join(', ')

generatorChoices = (framework) ->
Object.keys(categories[framework] or {}).join(', ')

generators = (config, generator) ->
backbone:
'model-test': (name, pluralName) ->
[sysPath.join(config.paths.test, 'models', "#{name}_test")]

model: (name, pluralName) ->
[sysPath.join(config.paths.app, 'models', "#{name}")].concat(
generator('model-test', name, pluralName)
)

'collection-test': (name, pluralName) ->
[sysPath.join(config.paths.test, 'models', "#{pluralName}_test")]

collection: (name, pluralName) ->
[sysPath.join(config.paths.app, 'models', "#{pluralName}")].concat(
generator('collection-test', name, pluralName)
)

template: (name) ->
[sysPath.join(config.paths.app, 'views', 'templates', "#{name}")]

style: (name) ->
[sysPath.join(config.paths.app, 'views', 'styles', "#{name}")]

'view-test': (name, pluralName) ->
[sysPath.join(config.paths.test, 'views', "#{name}_view_test")]

view: (name, pluralName) ->
[sysPath.join(config.paths.app, 'views', "#{name}_view")].concat(
generator('view-test', name, pluralName),
generator('template', name),
generator('style', name)
)

scaffold: (name, pluralName) ->
generator('model', name, pluralName).concat(
generator('view', name, pluralName),
)

chaplin:
'controller-test': (name, pluralName) ->
[sysPath.join(
config.paths.test, 'controllers', "#{pluralName}_controller_test"
)]

controller: (name, pluralName) ->
[sysPath.join(
config.paths.app, 'controllers', "#{pluralName}_controller"
)].concat(generator('controller-test', name, pluralName))

'model-test': (name, pluralName) ->
[sysPath.join(config.paths.test, 'models', "#{name}_test")]

model: (name, pluralName) ->
[sysPath.join(config.paths.app, 'models', "#{name}")].concat(
generator('model-test', name, pluralName)
)

'collection-test': (name, pluralName) ->
[sysPath.join(config.paths.test, 'models', "#{pluralName}_test")]

collection: (name, pluralName) ->
[sysPath.join(config.paths.app, 'models', "#{pluralName}")].concat(
generator('collection-test', name, pluralName)
)

template: (name) ->
[sysPath.join(config.paths.app, 'views', 'templates', "#{name}")]

style: (name) ->
[sysPath.join(config.paths.app, 'views', 'styles', "#{name}")]

'view-test': (name, pluralName) ->
[sysPath.join(config.paths.test, 'views', "#{name}_view_test")]

view: (name, pluralName) ->
[sysPath.join(config.paths.app, 'views', "#{name}_view")].concat(
generator('view-test', name, pluralName),
generator('template', name)
)

'collection-view-test': (name, pluralName) ->
[sysPath.join(config.paths.test, 'views', "#{pluralName}_view_test")]

'collection-view': (name, pluralName) ->
[sysPath.join(config.paths.app, 'views', "#{pluralName}_view")].concat(
generator('collection-view-test', name, pluralName)
)

'page-view-test': (name, pluralName) ->
[sysPath.join(config.paths.test, 'views', "#{name}_page_view_test")]

'page-view': (name, pluralName) ->
[sysPath.join(config.paths.app, 'views', "#{name}_page_view")].concat(
generator('page-view-test', name, pluralName),
generator('template', "#{name}_page"),
generator('style', "#{name}_page"),
)

scaffold: (name, pluralName) ->
generator('controller', name, pluralName).concat(
generator('model', name, pluralName),
generator('view', name, pluralName),
generator('collection-view', name, pluralName)
)

getGenerator = (config, plugins) ->
framework = config.framework or 'backbone'

unless categories[framework]?
return logger.error "Framework #{framework} isn't supported. Use one of:
#{frameworkChocies()}"

getExtension = (type) ->
category = categories[framework]?[type]
if category?
config.files[category]?.defaultExtension ? ''
else
logger.error "Generator #{type} isn't supported. Use one of:
#{generatorChoices(framework)}."
''

generatorMap = null
getGeneratorMap = ->
generatorMap ?= generators config, generator

generator = (type, name, pluralName) ->
configGenerator = config.generators?[type]
getData = (item) ->
if typeof item is 'function'
item name, pluralName
else
item

extension = getExtension type
plugin = plugins.filter((plugin) -> plugin.extension is extension)[0]
dataGenerator = plugin?.generators?[framework]?[type]

data = if configGenerator?
getData configGenerator
else if dataGenerator?
getData dataGenerator
else
''

getPaths = getGeneratorMap()[framework]?[type]
paths = (getPaths? name, pluralName) or []
nonStrings = paths.filter (path) -> typeof path isnt 'string'
strings = paths
.filter (path) ->
typeof path is 'string'
.map (path) ->
path + ".#{extension}"
.map (path) ->
file = {type, extension, path, data}
logger.debug 'info', "Scaffolding", file
file
strings.concat(nonStrings)

generator
formatTemplate = (template) ->
template

#
#
# generatorsPath - String,
# callback - Function,
#
# Example:
#
# getAllGenerators './generators', ->
# # => {
# controller: {parent: 'app/controllers', template: '', extension: ''}
# }
#
# Returns an Object of Object-s.
getAllGenerators = (generatorsPath, callback) ->
err = null
generators = Object.create(null)
walker = walk.walk generatorsPath
walker.on 'file', (root, stats, next) ->
path = sysPath.join root, stats.name
return next() if fs_utils.ignored path
type = sysPath.basename(path).replace(/\.\w*$/, '')
generators[type] = generator = Object.create(null)
generator.type = type
generator.parent = sysPath.relative generatorsPath, root
generator.extension = sysPath.extname path
fs.readFile path, (error, data) ->
if error?
err = error
return next()
generator.template = data.toString()
next()
walker.on 'end', ->
callback err, generators

getGenerator = (generators, name, pluralName) -> (type, parent) ->
generator = generators[type]
unless generator?
throw new Error "Generator #{type} isn't supported. Use one of:
#{Object.keys(generators).join(', ')}"
generator.parent = parent if parent?
generator.name = name
generator.pluralName = pluralName
Object.freeze generator

getFilesFromGenerators = (generators) ->
console.log generators
generators.map (generator) ->
path = sysPath.join(generator.parent, generator.name) + generator.extension
data = formatTemplate generator.template
{path, data}

generateFile = (path, data, callback) ->
parentDir = sysPath.dirname path
Expand Down Expand Up @@ -250,10 +109,17 @@ module.exports = scaffold = (rollback, options, callback = (->)) ->
return logger.error error if error?
config = helpers.loadConfig configPath
return callback() unless config?
plugins = helpers.getPlugins packages, config

relatedTypes = config.generatorsRelations?[type] ? []

generator = getGenerator config, plugins
files = generator type, name, pluralName
async.forEach files, generateOrDestroyFile, (error) ->
getAllGenerators config.paths.generators, (error, allGenerators) ->
return logger.error error if error?
callback null, files
getGen = getGenerator allGenerators, name, pluralName
generators = if parentDir?
[getGen type, parent]
else
([type].concat relatedTypes).map (type) -> getGen type
files = getFilesFromGenerators generators
async.forEach files, generateOrDestroyFile, (error) ->
return logger.error error if error?
callback null, files
2 changes: 2 additions & 0 deletions src/helpers.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,8 @@ exports.setConfigDefaults = setConfigDefaults = (config, configPath) ->
paths.test ?= apps[1]
paths.vendor ?= [apps[2], join('test', 'vendor')]

paths.generators ?= joinRoot 'generators'

paths.assets ?= [join('app', 'assets'), join('test', 'assets')]
paths.ignored ?= (path) -> startsWith sysPath.basename(path), '_'

Expand Down

0 comments on commit 125b69d

Please sign in to comment.