<commit_before>### WIP (Work In Progress)

[![Build Status](https://travis-ci.org/drujensen/kemalyst.svg?branch=master)](https://travis-ci.org/drujensen/kemalyst)

[![docrystal.org](http://docrystal.org/badge.svg)](http://docrystal.org/github.com/drujensen/kemalyst)

# Kemalyst

Kemalyst is a yarlf (yet another rails like framework) that is based on on
super fast [kemal](https://github.com/sdogruyol/kemal). The framework
leverages the http handlers which are similar to Rack middleware.

The router and controllers are an extension of the same middleware so you can
chain any compatible HTTP::Handler before or after the routing handler so you
can limit a particular handler to a sub-tree of your routes.

The model is a simple ORM mapping and supports MySQL, PG and SQLite.

The views are handled using [kilt](https://github.com/jeromegn/kilt) and several macros to simplify
development.

## Installation

1. Install Crystal

You can find instructions on how to install Crystal from [Crystal's
Website](http://crystal-lang.org).  I recommend using
[crenv](https://github.com/pine613/crenv) to manage your crystal versions.

2. Create a Crystal App

```
crystal init app [your_app]
cd [your_app]
```
3. Add kemalyst dependency to your shard.yml
```
dependencies:
  kemalyst:
    github: drujensen/kemalyst

  # optional

  # postgres driver is still in development
  pg:
    github: asterite/crystal-pg
    branch: feature/db

  # when it is released
  pg:
    github: crystal-lang/crystal-pg

  mysql:
    github: crystal-lang/crystal-mysql

  sqlite3:
    github: crystal-lang/crystal-sqlite3
```
and run `shards update`.

### Post Install

To keep a similar structure to yarlf, several directories and files will be
installed.  This structure should look familiar to you if your coming from a
Rails background.

 - config - Each handler may have its own config.  The database.yml and
   routes.cr are also here.
 - db - holds the migrate.cr script and any other db related artifacts.
 - libs - shards are installed here.
 - public - Default location for html/css/js files.  The static handler points
   to this directory.
 - spec - all the crystal specs go here.
 - src - all the source code goes here.  In rails, this would be your apps
   folder.

The post install will only run if it doesn't find a `src/app.cr` file.

You may want to remove the remnants of `crystal init`:
```
rm -r src/[your_app]
rm spec/[your_app_spec].cr
rm spec/spec_helper.cr_old
```

## Usage

### Run Locally
To test the demo app locally:

1. create a postgres database called `[your_app]`
2. run `export DATABASE_URL=postgres://[username]:[password]@localhost:5432/[your_app]`
3. migrate the database: `crystal db/migrate.cr`
4. run the specs: `crystal spec`

To build the demo app locally:

1. build the app `crystal build --release src/app.cr`
2. run with `./app`
3. visit `http://0.0.0.0:3000/`


### Run with docker compose
To run the demo app, we are including a Dockerfile and docker-compose.yml. If
you have docker setup, you should be able to run:
```
docker-compose build
docker-compose run web crystal db/migrate.cr
docker-compose up web
```
This will download an ubuntu/cedar image compatible with heroku and has all the
dependencies installed including crystal.

Now you should be able to hit the site:
```
open "http://localhost"
```

### Cookie Session
You will need to set a secret for the session.  Run the following
command:
```
crystal eval "require \"secure_random\"; puts SecureRandom.hex(64)"
```
copy the secret and set this in `config/session.cr`.

### Sample Applications

Several sample applications are provided:

 - [Blog Kemalyst](https://github.com/drujensen/blog-kemalyst)
 - [Chat Kemalyst](https://github.com/drujensen/chat-kemalyst)
 - [ToDo Backend Kemalyst](https://github.com/drujensen/todo-backend-kemalyst)

### Configure App

All config settings are in the `/config` folder.  Each handler has its own
settings.  You will find the `database.yml` and `routes.cr` here. Checkout
the samples that demonstrates a traditional blog site and a websocket chat
app.

### Middleware HTTP::Handlers

There are 6 handlers that are pre-configured for Kemalyst:
 - Logger.instance(@logger) - Logs all requests/responses to the `@logger` provided
 - Error.instance - Handles any Exceptions and renders a response.
 - Static.instance - Delivers any static assets from the `./public` folder.
 - Session.instance - Provides a Cookie Session that can be accessed from the `context.session`
 - Params.instance - Unifies the parameters into `context.params`
 - Router.instance - Routes requests to other handlers\controllers based on the HTTP method and path.

Other handlers available for Kemalyst:
 - BasicAuth.instance(username, password) - Provides Basic Authentication.
 - CORS.instance - Handles Cross Origin Resource Sharing.
 - CSRF.instance - Helps prevent Cross Site Request Forgery.

You may want to add, replace or remove handlers based on your situation.  You can do that in the
Application configuration `config/application.cr`:

```
Kemalyst::Application.config do |config|
  # handlers will be chained in the order provided
  config.handlers = [
    Kemalyst::Handler::Logger.instance(config.logger),
    Kemalyst::Handler::Error.instance,
    Kemalyst::Handler::Params.instance,
    Kemalyst::Handler::CORS.instance, # Enable CORS
    Kemalyst::Handler::Router.instance
  ]
end
```

### Router

The router will perform a lookup based on the method and path and return the
chain of handlers you specify in the routes.cr file.

An example of a route would be:
```
get "/",   DemoController::Index.instance
```

You may chain multiple handlers in a route using an array:
```
get "/", [ BasicAuth.instance("username", "password"),
           DemoController::Index.instance ]<commit_msg>update logger param<commit_after>### WIP (Work In Progress)

[![Build Status](https://travis-ci.org/drujensen/kemalyst.svg?branch=master)](https://travis-ci.org/drujensen/kemalyst)

[![docrystal.org](http://docrystal.org/badge.svg)](http://docrystal.org/github.com/drujensen/kemalyst)

# Kemalyst

Kemalyst is a yarlf (yet another rails like framework) that is based on on
super fast [kemal](https://github.com/sdogruyol/kemal). The framework
leverages the http handlers which are similar to Rack middleware.

The router and controllers are an extension of the same middleware so you can
chain any compatible HTTP::Handler before or after the routing handler so you
can limit a particular handler to a sub-tree of your routes.

The model is a simple ORM mapping and supports MySQL, PG and SQLite.

The views are handled using [kilt](https://github.com/jeromegn/kilt) and several macros to simplify
development.

## Installation

1. Install Crystal

You can find instructions on how to install Crystal from [Crystal's
Website](http://crystal-lang.org).  I recommend using
[crenv](https://github.com/pine613/crenv) to manage your crystal versions.

2. Create a Crystal App

```
crystal init app [your_app]
cd [your_app]
```
3. Add kemalyst dependency to your shard.yml
```
dependencies:
  kemalyst:
    github: drujensen/kemalyst

  # optional

  # postgres driver is still in development
  pg:
    github: asterite/crystal-pg
    branch: feature/db

  # when it is released
  pg:
    github: crystal-lang/crystal-pg

  mysql:
    github: crystal-lang/crystal-mysql

  sqlite3:
    github: crystal-lang/crystal-sqlite3
```
and run `shards update`.

### Post Install

To keep a similar structure to yarlf, several directories and files will be
installed.  This structure should look familiar to you if your coming from a
Rails background.

 - config - Each handler may have its own config.  The database.yml and
   routes.cr are also here.
 - db - holds the migrate.cr script and any other db related artifacts.
 - libs - shards are installed here.
 - public - Default location for html/css/js files.  The static handler points
   to this directory.
 - spec - all the crystal specs go here.
 - src - all the source code goes here.  In rails, this would be your apps
   folder.

The post install will only run if it doesn't find a `src/app.cr` file.

You may want to remove the remnants of `crystal init`:
```
rm -r src/[your_app]
rm spec/[your_app_spec].cr
rm spec/spec_helper.cr_old
```

## Usage

### Run Locally
To test the demo app locally:

1. create a postgres database called `[your_app]`
2. run `export DATABASE_URL=postgres://[username]:[password]@localhost:5432/[your_app]`
3. migrate the database: `crystal db/migrate.cr`
4. run the specs: `crystal spec`

To build the demo app locally:

1. build the app `crystal build --release src/app.cr`
2. run with `./app`
3. visit `http://0.0.0.0:3000/`


### Run with docker compose
To run the demo app, we are including a Dockerfile and docker-compose.yml. If
you have docker setup, you should be able to run:
```
docker-compose build
docker-compose run web crystal db/migrate.cr
docker-compose up web
```
This will download an ubuntu/cedar image compatible with heroku and has all the
dependencies installed including crystal.

Now you should be able to hit the site:
```
open "http://localhost"
```

### Cookie Session
You will need to set a secret for the session.  Run the following
command:
```
crystal eval "require \"secure_random\"; puts SecureRandom.hex(64)"
```
copy the secret and set this in `config/session.cr`.

### Sample Applications

Several sample applications are provided:

 - [Blog Kemalyst](https://github.com/drujensen/blog-kemalyst)
 - [Chat Kemalyst](https://github.com/drujensen/chat-kemalyst)
 - [ToDo Backend Kemalyst](https://github.com/drujensen/todo-backend-kemalyst)

### Configure App

All config settings are in the `/config` folder.  Each handler has its own
settings.  You will find the `database.yml` and `routes.cr` here. Checkout
the samples that demonstrates a traditional blog site and a websocket chat
app.

### Middleware HTTP::Handlers

There are 6 handlers that are pre-configured for Kemalyst:
 - Logger.instance - Logs all requests/responses to the logger configured.
 - Error.instance - Handles any Exceptions and renders a response.
 - Static.instance - Delivers any static assets from the `./public` folder.
 - Session.instance - Provides a Cookie Session that can be accessed from the `context.session`
 - Params.instance - Unifies the parameters into `context.params`
 - Router.instance - Routes requests to other handlers\controllers based on the HTTP method and path.

Other handlers available for Kemalyst:
 - BasicAuth.instance(username, password) - Provides Basic Authentication.
 - CORS.instance - Handles Cross Origin Resource Sharing.
 - CSRF.instance - Helps prevent Cross Site Request Forgery.

You may want to add, replace or remove handlers based on your situation.  You can do that in the
Application configuration `config/application.cr`:

```
Kemalyst::Application.config do |config|
  # handlers will be chained in the order provided
  config.handlers = [
    Kemalyst::Handler::Logger.instance,
    Kemalyst::Handler::Error.instance,
    Kemalyst::Handler::Params.instance,
    Kemalyst::Handler::CORS.instance, # Enable CORS
    Kemalyst::Handler::Router.instance
  ]
end
```

### Router

The router will perform a lookup based on the method and path and return the
chain of handlers you specify in the routes.cr file.

An example of a route would be:
```
get "/",   DemoController::Index.instance
```

You may chain multiple handlers in a route using an array:
```
get "/", [ BasicAuth.instance("username", "password"),
           DemoController::Index.instance ]
{'fraction_non_alphanumeric': 0.09615052649749697, 'fraction_numerical': 0.005178663904712584, 'mean_word_length': 4.018189692507579, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 16, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 2, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '273494', 'n_tokens_mistral': 3638, 'n_tokens_neox': 3417, 'n_words': 1368}