Add reverse-scaffold-all/reverse-model-all command

Powerful reverse engineering commands.

## reverse-model-all

### DDL

```sql
create table company (
  id bigserial not null primary key,
  name varchar(100) not null,
  url varchar(512),
  created_at timestamp not null default current_timestamp
);

create table member (
  id bigserial not null primary key,
  name varchar(512) not null,
  nickname varchar(32),
  company_id bigint references company(id),
  joined_at timestamp not null,
  leave_at timestamp
);
```

### Output

```
 *** Skinny Reverse Engineering Task ***

  Table     : company
  ID        : id:Long

  Columns:
   - name:String:varchar(100)
   - url:Option[String]:varchar(512)
   - createdAt:DateTime
   - members:Seq[Member]

 *** Skinny Generator Task ***

  "tmp/ReverseModelAllGeneratorSpec/src/main/scala/model/Company.scala" created.
  "tmp/ReverseModelAllGeneratorSpec/src/test/scala/model/CompanySpec.scala" created.


 *** Skinny Reverse Engineering Task ***

  Table     : member
  ID        : id:Long

  Columns:
   - name:String:varchar(512)
   - nickname:Option[String]:varchar(32)
   - companyId:Option[Long]
   - joinedAt:DateTime
   - leaveAt:Option[DateTime]
   - company:Option[Company]

 *** Skinny Generator Task ***

  "tmp/ReverseModelAllGeneratorSpec/src/main/scala/model/Member.scala" created.
  "tmp/ReverseModelAllGeneratorSpec/src/test/scala/model/MemberSpec.scala" created.
```

### Generated Files

```scala
package model

import skinny.orm._, feature._
import scalikejdbc._
import org.joda.time._

// If your model has +23 fields, switch this to normal class and mixin scalikejdbc.EntityEquality.
case class Company(
  id: Long,
  name: String,
  url: Option[String] = None,
  createdAt: DateTime,
  members: Seq[Member] = Nil
)

object Company extends SkinnyCRUDMapper[Company] {
  override lazy val tableName = "company"
  override lazy val defaultAlias = createAlias("c")

  lazy val membersRef = hasMany[Member](
    many = Member -> Member.defaultAlias,
    on = (c, m) => sqls.eq(c.id, m.companyId),
    merge = (c, ms) => c.copy(members = ms)
  )

  override def extract(rs: WrappedResultSet, rn: ResultName[Company]): Company = {
    autoConstruct(rs, rn, "members")
  }
}
```

```scala
package model

import skinny.orm._, feature._
import scalikejdbc._
import org.joda.time._

// If your model has +23 fields, switch this to normal class and mixin scalikejdbc.EntityEquality.
case class Member(
  id: Long,
  name: String,
  nickname: Option[String] = None,
  companyId: Option[Long] = None,
  joinedAt: DateTime,
  leaveAt: Option[DateTime] = None,
  company: Option[Company] = None
)

object Member extends SkinnyCRUDMapper[Member] {
  override lazy val tableName = "member"
  override lazy val defaultAlias = createAlias("m")

  lazy val companyRef = belongsTo[Company](Company, (m, c) => m.copy(company = c))

  override def extract(rs: WrappedResultSet, rn: ResultName[Member]): Member = {
    autoConstruct(rs, rn, "company")
  }
}
```

## reverse-scaffold-all

### DDL

```sql
create table user_group (
  id bigserial not null primary key,
  name varchar(100) not null,
  url varchar(512)
);
create table organization (
  id bigserial not null primary key,
  name varchar(100) not null,
  url varchar(512) not null
);
create table developer (
  id bigserial not null primary key,
  name varchar(512) not null,
  nickname varchar(32),
  user_group_id bigint references user_group(id)
);
create table organization_developer (
  organization_id bigint not null references organization(id),
  developer_id bigint not null references developer(id)
);
```

### Output

```
 *** Skinny Reverse Engineering Task ***

  Table     : developer
  ID        : id:Long
  Resources : developers
  Resource  : developer

  Columns:
   - name:String:varchar(512)
   - nickname:Option[String]:varchar(32)
   - userGroupId:Option[Long]
   - userGroup:Option[UserGroup]
   - organizationDevelopers:Seq[OrganizationDeveloper]

 *** Skinny Generator Task ***

  "tmp/ReverseScaffoldAllGeneratorSpec/src/main/scala/controller/ApplicationController.scala" skipped.
  "tmp/ReverseScaffoldAllGeneratorSpec/src/main/scala/controller/DevelopersController.scala" created.
  "tmp/ReverseScaffoldAllGeneratorSpec/src/main/scala/controller/Controllers.scala" modified.
  "tmp/ReverseScaffoldAllGeneratorSpec/src/test/scala/controller/DevelopersControllerSpec.scala" created.
  "tmp/ReverseScaffoldAllGeneratorSpec/src/test/scala/integrationtest/DevelopersController_IntegrationTestSpec.scala" created.
  "tmp/ReverseScaffoldAllGeneratorSpec/src/test/resources/factories.conf" modified.
  "tmp/ReverseScaffoldAllGeneratorSpec/src/main/scala/model/Developer.scala" created.
  "tmp/ReverseScaffoldAllGeneratorSpec/src/test/scala/model/DeveloperSpec.scala" created.
  "tmp/ReverseScaffoldAllGeneratorSpec/src/main/webapp/WEB-INF/views/developers/_form.html.ssp" created.
  "tmp/ReverseScaffoldAllGeneratorSpec/src/main/webapp/WEB-INF/views/developers/new.html.ssp" created.
  "tmp/ReverseScaffoldAllGeneratorSpec/src/main/webapp/WEB-INF/views/developers/edit.html.ssp" created.
  "tmp/ReverseScaffoldAllGeneratorSpec/src/main/webapp/WEB-INF/views/developers/index.html.ssp" created.
  "tmp/ReverseScaffoldAllGeneratorSpec/src/main/webapp/WEB-INF/views/developers/show.html.ssp" created.
  "tmp/ReverseScaffoldAllGeneratorSpec/src/main/resources/messages.conf" modified.
  "tmp/ReverseScaffoldAllGeneratorSpec/src/main/resources/db/migration/V20141207024947__Create_developers_table.sql" created.


 *** Skinny Reverse Engineering Task ***

  Table     : organization
  ID        : id:Long
  Resources : organizations
  Resource  : organization

  Columns:
   - name:String:varchar(100)
   - url:String:varchar(512)
   - organizationDevelopers:Seq[OrganizationDeveloper]

 *** Skinny Generator Task ***

  "tmp/ReverseScaffoldAllGeneratorSpec/src/main/scala/controller/ApplicationController.scala" skipped.
  "tmp/ReverseScaffoldAllGeneratorSpec/src/main/scala/controller/OrganizationsController.scala" created.
  "tmp/ReverseScaffoldAllGeneratorSpec/src/main/scala/controller/Controllers.scala" modified.
  "tmp/ReverseScaffoldAllGeneratorSpec/src/test/scala/controller/OrganizationsControllerSpec.scala" created.
  "tmp/ReverseScaffoldAllGeneratorSpec/src/test/scala/integrationtest/OrganizationsController_IntegrationTestSpec.scala" created.
  "tmp/ReverseScaffoldAllGeneratorSpec/src/test/resources/factories.conf" modified.
  "tmp/ReverseScaffoldAllGeneratorSpec/src/main/scala/model/Organization.scala" created.
  "tmp/ReverseScaffoldAllGeneratorSpec/src/test/scala/model/OrganizationSpec.scala" created.
  "tmp/ReverseScaffoldAllGeneratorSpec/src/main/webapp/WEB-INF/views/organizations/_form.html.ssp" created.
  "tmp/ReverseScaffoldAllGeneratorSpec/src/main/webapp/WEB-INF/views/organizations/new.html.ssp" created.
  "tmp/ReverseScaffoldAllGeneratorSpec/src/main/webapp/WEB-INF/views/organizations/edit.html.ssp" created.
  "tmp/ReverseScaffoldAllGeneratorSpec/src/main/webapp/WEB-INF/views/organizations/index.html.ssp" created.
  "tmp/ReverseScaffoldAllGeneratorSpec/src/main/webapp/WEB-INF/views/organizations/show.html.ssp" created.
  "tmp/ReverseScaffoldAllGeneratorSpec/src/main/resources/messages.conf" modified.
  "tmp/ReverseScaffoldAllGeneratorSpec/src/main/resources/db/migration/V20141207024947__Create_organizations_table.sql" created.


Since this table (organization_developer) has no primary key, generator created only NoIdCRUDMapper file and skipped creating controller and view files.

 *** Skinny Reverse Engineering Task ***

  Table  : organization_developer

  Columns:
   - organizationId:Long
   - developerId:Long
   - developer:Option[Developer]
   - organization:Option[Organization]

 *** Skinny Generator Task ***

  "tmp/ReverseScaffoldAllGeneratorSpec/src/main/scala/model/OrganizationDeveloper.scala" created.
  "tmp/ReverseScaffoldAllGeneratorSpec/src/test/scala/model/OrganizationDeveloperSpec.scala" created.
  "tmp/ReverseScaffoldAllGeneratorSpec/src/main/resources/db/migration/V20141207024947__Create_organizationDevelopers_table.sql" created.


 *** Skinny Reverse Engineering Task ***

  Table     : user_group
  ID        : id:Long
  Resources : userGroups
  Resource  : userGroup

  Columns:
   - name:String:varchar(100)
   - url:Option[String]:varchar(512)
   - developers:Seq[Developer]

 *** Skinny Generator Task ***

  "tmp/ReverseScaffoldAllGeneratorSpec/src/main/scala/controller/ApplicationController.scala" skipped.
  "tmp/ReverseScaffoldAllGeneratorSpec/src/main/scala/controller/UserGroupsController.scala" created.
  "tmp/ReverseScaffoldAllGeneratorSpec/src/main/scala/controller/Controllers.scala" modified.
  "tmp/ReverseScaffoldAllGeneratorSpec/src/test/scala/controller/UserGroupsControllerSpec.scala" created.
  "tmp/ReverseScaffoldAllGeneratorSpec/src/test/scala/integrationtest/UserGroupsController_IntegrationTestSpec.scala" created.
  "tmp/ReverseScaffoldAllGeneratorSpec/src/test/resources/factories.conf" modified.
  "tmp/ReverseScaffoldAllGeneratorSpec/src/main/scala/model/UserGroup.scala" created.
  "tmp/ReverseScaffoldAllGeneratorSpec/src/test/scala/model/UserGroupSpec.scala" created.
  "tmp/ReverseScaffoldAllGeneratorSpec/src/main/webapp/WEB-INF/views/userGroups/_form.html.ssp" created.
  "tmp/ReverseScaffoldAllGeneratorSpec/src/main/webapp/WEB-INF/views/userGroups/new.html.ssp" created.
  "tmp/ReverseScaffoldAllGeneratorSpec/src/main/webapp/WEB-INF/views/userGroups/edit.html.ssp" created.
  "tmp/ReverseScaffoldAllGeneratorSpec/src/main/webapp/WEB-INF/views/userGroups/index.html.ssp" created.
  "tmp/ReverseScaffoldAllGeneratorSpec/src/main/webapp/WEB-INF/views/userGroups/show.html.ssp" created.
  "tmp/ReverseScaffoldAllGeneratorSpec/src/main/resources/messages.conf" modified.
  "tmp/ReverseScaffoldAllGeneratorSpec/src/main/resources/db/migration/V20141207024947__Create_userGroups_table.sql" created.
```

### Generated Files

```scala
package model

import skinny.orm._, feature._
import scalikejdbc._
import org.joda.time._

// If your model has +23 fields, switch this to normal class and mixin scalikejdbc.EntityEquality.
case class Developer(
  id: Long,
  name: String,
  nickname: Option[String] = None,
  userGroupId: Option[Long] = None,
  userGroup: Option[UserGroup] = None,
  organizations: Seq[Organization] = Nil
)

object Developer extends SkinnyCRUDMapper[Developer] {
  override lazy val tableName = "developer"
  override lazy val defaultAlias = createAlias("d")

  lazy val userGroupRef = belongsTo[UserGroup](UserGroup, (d, ug) => d.copy(userGroup = ug))

  lazy val organizationsRef = hasManyThrough[Organization](
    through = OrganizationDeveloper,
    many = Organization,
    merge = (d, os) => d.copy(organizations = os)
  )

  override def extract(rs: WrappedResultSet, rn: ResultName[Developer]): Developer = {
    autoConstruct(rs, rn, "userGroup", "organizations")
  }
}
```

```scala
package controller

import skinny._
import skinny.validator._
import _root_.controller._
import model.Developer

class DevelopersController extends SkinnyResource with ApplicationController {
  protectFromForgery()

  override def model = Developer
  override def resourcesName = "developers"
  override def resourceName = "developer"

  override def resourcesBasePath = s"/${toSnakeCase(resourcesName)}"
  override def useSnakeCasedParamKeys = true

  override def viewsDirectoryPath = s"/${resourcesName}"

  override def createParams = Params(params)
  override def createForm = validation(createParams,
    paramKey("name") is required & maxLength(512),
    paramKey("nickname") is maxLength(32),
    paramKey("user_group_id") is numeric & longValue
  )
  override def createFormStrongParameters = Seq(
    "name" -> ParamType.String,
    "nickname" -> ParamType.String,
    "user_group_id" -> ParamType.Long
  )

  override def updateParams = Params(params)
  override def updateForm = validation(updateParams,
    paramKey("name") is required & maxLength(512),
    paramKey("nickname") is maxLength(32),
    paramKey("user_group_id") is numeric & longValue
  )
  override def updateFormStrongParameters = Seq(
    "name" -> ParamType.String,
    "nickname" -> ParamType.String,
    "user_group_id" -> ParamType.Long
  )

}
```