Enginery

Stuff Builder for Espresso Framework

Install

$ gem install enginery

+ $ rbenv rehash if you are using rbenv

Quick start

Create a new application in ./App/ folder:

$ enginery g App

Create a new application in current folder:

$ enginery g

Generate Controllers:

$ enginery g:c Foo
# generate multiple controllers at once ...
$ enginery g:c Foo Bar Baz

Generate Routes for Foo controller:

$ enginery g:r Foo a
# generate multiple routes at once ...
$ enginery g:r Foo a b c

Generate Models:

$ enginery g:m Foo
# generate multiple models at once ...
$ enginery g:m Foo Bar Baz

Generate Specs:

$ enginery g:s SomeController some_action

Generate Migrations:

$ enginery m migrationName model:ModelName column:some_column

List Migrations:

$ enginery m:l

Run Migrations:

$ enginery m:up migrationID
$ enginery m:down migrationID

Application structure

- base/
  | - models/
  | - views/
  | - controllers/
    ` - rear-controllers/
  | - helpers/
  | - specs/
  | - migrations/
  | - boot.rb
  | - config.rb
  ` - database.rb

- config/
  | - config.yml
  ` - database.yml

- public/
  | - assets/
      | - app.css
      ` - app.js

- tmp/

- var/
  | - db/
  | - log/
  ` - pid/

- Rakefile
- Gemfile
- app.rb
- config.ru

Tutorial

Projects | Controllers | Routes | Specs | Views | Models | Migrations | Admin Interface

Projects

To generate a project simply type:

$ enginery g App

This will create ./App folder with a ready-to-use application inside.

To generate a new application in current folder simply omit application name:

$ enginery g

Engine

Generated application will use ERB engine by default.

To generate a project that will use a custom engine, use engine option followed by a semicolon and the full, case sensitive, name of desired engine:

$ enginery g engine:Slim

This will update your Gemfile by adding slim gem and will also update config.yml by adding engine: :Slim.

Option name can be shortened down to first letter:

$ enginery g e:Slim

ORM

If your project will use any ORM, use orm option followed by a semicolon and the name of desired ORM:

$ enginery g orm:ActiveRecord

Worth to note - ORM name are case insensitive and can be shortened to first letter(s):

project using ActiveRecord:

$ enginery g orm:ar
# or just
$ enginery g o:ar

project using DataMapper:

$ enginery g orm:dm
# or just
$ enginery g o:dm

project using Sequel:

$ enginery g orm:sequel
# or just
$ enginery g o:sq

Database

It is also possible to set database connection info. Accepted options:

  • db_type (or dbtype)
  • db_host (or dbhost)
  • db_port (or dbport)
  • db_name (or dbname)
  • db_user (or dbuser)
  • db_pass (or dbpass)

project using MySQL:

$ enginery g dbtype:MySQL
# or
$ enginery g dbtype:mysql
# or just
$ enginery g dbtype:m

project using PostgreSQL:

$ enginery g dbtype:postgres
# or just
$ enginery g dbtype:p

project using Sqlite:

$ enginery g dbtype:sqlite
# or just
$ enginery g dbtype:s

Server/Port/Host

Applications generated by Enginery will use Thin web server by default.

To use another server set server option.

Server name should be provided in full and is case sensitive:

enginery g server:Puma
# or just
enginery g s:Puma

Generated application will listen on 5252 port by default.

To use another port, set port option:

enginery g server:Unicorn port:2000
# or just
enginery g s:Unicorn p:2000

To make application to listen on another host than "localhost", use host option:

enginery g server:Unicorn port:2000 host:192.168.2.5
# or just
enginery g s:Unicorn p:2000 h:192.168.2.5

Format

Enginery also allow to specify format to be used by all controllers / actions.

Ex: to make all actions to serve URLs ending in .html, use format:html:

$ enginery g format:html

And of course as per other options, format can be shortened to first letter too:

$ enginery g f:html

And of course you can pass multiple options:

$ enginery g o:ar e:Slim f:html

[ contents ↑ ]

Controllers

As simple as:

$ enginery g:c Foo

This will create "base/controllers/foo/" folder and "base/controllers/foo_controller.rb" file.

The file will contain controller's setups and the folder will contain controller's actions.

Map

By default the controller will be mapped to its underscored name, that's it:

Foo      to /foo
FooBar   to /foo_bar
Foo::Bar to /foo/bar
etc.

To generate a controller mapped to a custom location, use the route option:

$ enginery g:c Foo route:bar
# or just
$ enginery g:c Foo r:bar

Setups

When generating a controller without any setups, it will use project-wide ones(passed at project generation), if any.

To generate a controller with custom setups, pass them as options:

$ enginery g:c Foo e:Haml

This will create a controller that will use Haml engine.

Another option is format:

$ enginery g:c Foo f:html

Multiple

When you need to generate multiple controllers at once just pass their names separated by a space:

$ enginery g:c A B C

This will generate 3 controllers without any setups.

Any passed setups will apply to all generated controllers:

$ enginery g:c A B C e:Haml

Namespaces

When you need a namespaced controller, pass its name as is:

$ enginery g:c Foo::Bar

This will generate Foo module with Bar controller inside:

module Foo
  class Bar < E
    # ...
  end
end

Worth to note that Bar controller will be mapped to "/foo/bar" URL.
To map it to another location, use route option as shown above.

Including modules

If your controller needs extra modules included, use include: option:

$ enginery g:c Foo include:Bar
# or just
$ enginery g:c Foo i:Bar

This will generate Foo controller with Bar included:

module Foo < E
  include Bar
  # ...
end

Deleting Controllers

As easy as:

$ enginery delete:c ControllerName

This will remove all controller routes, views, specs and helpers, so use with care.

[ contents ↑ ]

Routes

As simple as:

$ enginery g:route Foo bar
# or just
$ enginery g:r Foo bar

where Foo is the controller name and bar is the route.

This will create "base/controllers/foo/bar.rb" and "base/views/foo/bar.erb" files.

Mapping

You can provide the URL rather than the action name - it will be automatically converted into action name according to effective path rules:

$ enginery g:r Forum posts/latest

This will create "base/controllers/forum/posts_latest.rb" file with `postslatest` action inside and the "base/views/forum/posts_latest.erb" template file.

See more details on actions mapping.

Setups

Setups provided at route generation will be effective only on generated route:

# generate Foo controller
$ enginery g:c Foo e:Haml

# generate Foo#bar route
$ enginery g:r Foo bar

# generate Foo#baz route
$ enginery g:r Foo baz e:Slim

Foo#bar action will use Haml engine, as per controller setup.
Foo#baz action will use Slim engine instead, as per route setup.

Multiple

To generate multiple routes at once just pass their names separated by spaces:

$ enginery g:r Foo a b c

this will create 3 routes and 3 views.

Worth to note that any provided setups will apply on all and only generated actions.

Deleting Routes

As easy as:

$ enginery delete:r ControllerName route_name

This will remove all route files, views and specs, so use with care.

[ contents ↑ ]

Specs

Specs are generated simultaneously with routes.

It makes sense to generate a spec manually only if it was accidentally lost/damaged.

Note - Enginery uses Specular to build/run specs. Feel free to contribute by adding support for other testing frameworks.

To generate a spec use spec(or just s) notation followed by controller name and the route to be tested:

$ enginery g:s Foo bar
# where Foo is the controller and bar is the route.

This will create base/specs/foo/ with bar_spec.rb file inside.

To generate multiple specs pass route names separated by a space:

$ enginery g:s Foo a b c

This will generate specs/foo/a_spec.rb, specs/foo/b_spec.rb and specs/foo/c_spec.rb files.

To run a spec use $ rake test:Foo#bar, where Foo is the controller name and bar is the tested route.

To run all specs for Foo controller use $ rake test:Foo

To run all specs for all controllers use $ rake test or just $ rake

If the controller is under some namespace, pass the full name, do not worry about ::, rake will take care:

$ rake test:Forum::Posts
$ rake test:Forum::Posts#read

To see all available specs use $ rake -D

[ contents ↑ ]

Views

View generator are triggered every time you generate a route, so it make sense to use it only to create a template that was accidentally damaged/lost.

Invocation:

$ enginery g:v Foo bar

where Foo is the controller name and bar is the action to generate view for.

This will create "base/views/foo/bar.[ext]" template, if it does not exists.

[ext] depending on effective template engine.

If template already exists, the generator will simply touch it, without modifying the name/content in any way.

[ contents ↑ ]

Models

Supported ORMs: ActiveRecord, DataMapper, Sequel

$ enginery g:model Foo
# or just 
$ enginery g:m Foo

this will create "base/models/foo.rb" file.

File content will depend on setups passed at project generation:

If we generate a project like this:

$ enginery g orm:ActiveRecord

the:

$ enginery g:m Foo

will result in:

class Foo < ActiveRecord::Base

end

And if the project are generated like this:

$ enginery g orm:DataMapper

the:

$ enginery g:m Foo

will result in:

class Foo
  include DataMapper::Resource

  property :id, Serial
end

To generate a model on a project without default ORM, use orm option at model generation:

$ enginery g:m Foo orm:ActiveRecord
# or just
$ enginery g:m Foo orm:ar
# or even
$ enginery g:m Foo o:ar

will result in:

class Foo < ActiveRecord::Base

end

and will update your Gemfile by adding corresponding gems, unless they are already there.

Associations

With Enginery you can specify a list of associations at model generation.

Supported associations:

  • belongs_to
  • has_one
  • has_many
  • has_and_belongs_to_many

Though associations are passed in ActiveRecord way, they will be automatically adjusted if another ORM used.

enginery g:m State has_many:cities
enginery g:m City belongs_to:state

If you need a through association simply use :through option:

enginery g:m Photo has_many:tags:through:tagging
enginery g:m Tag has_many:photos:through:tagging

Multiple

Generating multiple models at once:

$ enginery g:m A B C
# or just for readability
$ enginery g:models A B C

Including modules

If your model needs extra modules included, use include: option:

$ enginery g:m Foo include:Bar
# or just
$ enginery g:m Foo i:Bar

This will generate Foo model with Bar included:

module Foo < ActiveRecord::Base
  include Bar
  # ...
end

Deleting Models

As easy as:

$ enginery delete:m ModelName

[ contents ↑ ]

Migrations

Supported ORMs: ActiveRecord, DataMapper, Sequel

Initial migration for any model are auto-generated alongside with model:

$ enginery g:m Page

this will generate Page model as well a migration that will create model's table when performed up and drop it when performed down.

Migrations will reside in base/migrations/ folder. The file for Page model created above will be named 1.[timestamp].initializing-Page-model.rb

Now you can edit it by adding columns you need created alongside with table. You should add them inside up method or block, depending on used ORM.

If you do not want to edit the file manually, you can automatize this step as well by providing columns at model generation:

$ enginery g:m Page column:name column:about:text

now the "up" section will contain instructions to create the table and 2 columns.
Note: if type omitted, String will be used.

When your migration are ready, run it using its serial number.

Serial number usually are printed when migration are generated.

You can also find it by listing available migrations:

$ enginery m:list
# or just
$ enginery m:l

this will display something like:

                    ---=---
                     1 : initializing-Page-model
            created at : [timestamp]
        last performed : [none|timestamp]
                    ---=---

where "1" is the serial number and "initializing-Page-model" is the name.

Run migration up:

enginery m:up 1

Run migration down:

enginery m:down 1

Adding columns

To add some column to an existing model simply add new migration that will do this.

To generate a migration use the m notation followed by migration name, model and column(s):

$ enginery m add-email model:Person column:email

this will output something like:

--- Person model - generating "add-email" migration ---

  Serial Number: 2

Run migration up:

enginery m:up 2

this will alter table by adding "email" column of "string" type.

Run migration down:

enginery m:down 2

this will drop "email" column.

Updating Columns

To modify some column type use update_column option followed by column name and new type:

enginery m update-email model:Person update_column:email:text

this will output something like:

--- Person model - generating "update-email" migration ---

  Serial Number: 3

Run migration up:

enginery m:up 3

this will alter table by setting "email" type to "text".

Run migration down:

enginery m:down 3

this will alter table by reverting "email" type to "string".

Renaming Columns

To rename some column type use rename_column option followed by current column name and new name:

enginery m rename-name model:Person rename_column:name:first_name

this will output something like:

--- Person model - generating "update-name" migration ---

  Serial Number: 4

Running migration up will rename "name" column to "first_name":

enginery m:up 4

Running migration down will rename "first_name" back to "name":

enginery m:down 4

Running Migrations

With Enginery you are free to choose what migration(s) to run in multiple ways.

Most obvious one is to provide the serial number of a single migration:

$ enginery m:[up|down] 1

When you need to run multiple migrations pass serial numbers separated by spaces:

$ enginery m:[up|down] 1 4 6

this will run 1st, 4th and 6th migrations.

When you need to run N to M migrations, use N-M notation:

$ enginery m:[up|down] 2-6

this will run 2nd to 6th migrations inclusive.

Important Note: Enginery will automatically set the running order depending on performed direction - ascending on "up" and descending on "down".

$ enginery m:up 4 2 6

performing order: 2 4 6

$ enginery m:down 4 2 6

performing order: 6 4 2

$ enginery m:up 1-4

performing order: 1 2 3 4

$ enginery m:down 1-4

performing order: 4 3 2 1

To run all outstanding migrations just do not pass any steps.

Perform UP all outstanding migrations:

$ enginery m:up

Perform DOWN all outstanding migrations:

$ enginery m:down

To list available migrations use $ enginery m:list or just $ enginery m:l

Force Running

Enginery will keep track of migrations already performed and wont run same migration twice.

However, sometimes you may need to run it anyway due to manual schema modification etc.

In such non-standard cases you can use force option:

$ enginery m:up:force 1

DataMapper Notes

With DataMapper ORM you have extra rake tasks "for free", like dm:auto_migrate, dm:auto_upgrade, dm:auto_migrate:ModelName, dm:auto_upgrade:ModelName

Use $ rake -D to list all tasks.

Note on renaming columns: as of 'dm-migrations' 1.2.0 renaming columns are broken for MySQL adapter. Master branch have it fixed but not yet released.

[ contents ↑ ]

Admin Interface

Enginery is using Rear to build a admin interface for generated models.

Admin interface will be automatically mounted at /admin.

To mount it elsewhere, edit config/config.yml by updating :admin_url setting.

To disable admin interface simply remove :admin_url setting from config/config.yml.

[ contents ↑ ]

Contributing

  • Fork Enginery repository
  • optionally create a new branch
  • make your changes
  • submit a pull request


Issues/Bugs: github.com/espresso/enginery/issues

Mailing List: groups.google.com/.../espresso-framework

IRC channel: #espressorb on irc.freenode.net

Author - Walter Smith. License - MIT.