amethyst

Rails inspired web-framework middleware
0.0.2 released

Amethyst Build Status

Amethyst is a web framework written in Crystal language. The goals of Amethyst are to be fast and user-friendly as Rails. Note, Amethyst is in very early stage, so a lot of base features are missing yet. However, it works :). For now, next things are implemented:

  • class-based controllers with actions
  • middleware support
  • simple routing For details, see docs below.

Would be glad for any help with contributing.

Installation

Suggested that you installed Crystal 0.7.1 or higher.

git clone https://github.com/Codcore/Amethyst.git

Or add it to Projectfile of your Crystal project

deps do
  github "Codcore/amethyst"
end

You can play with example of simple web-application written with Amethyst at examples directory:

crystal examples/simple_application.cr

Usage

If you want to load Amethyst in global namespace to be able not to prepend classes with name of modules they are in (for example, Core::BaseController),you can load all modules into global namespace next way:

require "amethyst/all"

From that moment, you can type Application.new instead of Core::Application.new, BaseController instead Core::BaseController, etc.)

Controllers

Amethyst controllers are classes, the name of controller must be NameController, and it needs to be inherited from BaseController. Here is an example of simple controller:

require "../src/amethyst"

class IndexController < Core::BaseController

  def hello
    html "<p>Hello, you're asked a #{request.method} #{request.path}</p> \n
          <a href='/bye'>Visit <b>bye</b> action</a>"
  end

  def bye
    html "<p>Bye!We hope you will come back</p>"
  end

  def actions
    add :hello
    add :bye
  end
end

Controllers describe actions as a methods. Actions have direct access to request and response objects, and other helpers, such as a html . Controller method actions is special method that must be provided by each controller of your application.It lets app to know which methods of your contoller are actions, and which aren't. The synopsys is add :action_name.

Middleware

Middleware are implemented as classes. Middleware class inherits from Core::Middleware::BaseMiddleware (or, just type BaseMiddleware`` if you prefer require amethyst/all), and should have the call``` method. Actually, there are two call methods with different signatures:

def call(request)
end

def call(request, response)
end

The first one will be called when app gets request from server. It accepts Amethyst::Http::Request as an argument. Last one will be invoked when controller returned response(this happens automatically). It gets Amethyst::Http::Request and Amethyst::Http::Response as arguments. Here is an example of middleware that calculates time elapsed between request and response.

class TimeMiddleware < Core::Middleware::BaseMiddleware

  # All instance variables have to be initialized here to use them in call methods
  def initialize
    @t_req = Time.new 
    @t_res = Time.new
  end

  def call(request)
    @t_req = Time.now
  end

  # This one will be called when response returned from controller. It accepts both
  # Http::Request and Http::Response
  def call(request, response)
    @t_res = Time.now
    response.body += "<hr> Time elapsed: #{(@t_res-@t_req)} seconds"
  end
end

Application creating

app = Core::Application.new

# Middleware registering
app.use(TimeMiddleware.new)

You can set a port and app name (defaul port is 8080, default name is name of file application is in):

app.port = 8080
app.name = "example"

#Routing

Amethyst has Rails-like approach to describe routes. For now, only get() supported. It consists of path and string controller_name#action_name

app.routes.draw do |routes|
  # map GET "/" to "hello" action of IndexController
  get "/",    "index#hello"
  map GET "/bye" to "bye" action of IndexController
  get "/bye", "index#bye"
end

Note, /bye and /bye/ work slightly different. First matches /bye, /bye/, /bye_something, second is "strict", and matches only /bye and /bye/. Both not matches /bye/something.

You can specify params to be captured:

get "/users/:id", "users#show" #(params not works yet)

After you defined a controller, you have to register it in app with app.routes.register(NameController) where NameController(CamelCase) is the classname of your controller:

app.routes.register(IndexController)

#Running application

app.serve

Development

Feel free to fork project and make pull-requests. Stick to standart project structure and name conventions:

src/
  amethyst/
    module1/       #module1 files
      class1.cr
      ...
      module1.cr   #loads all module1 files into namespace Amethyst::Module1
    module2/
      class1.cr    #describe class Class1 (module, struct, i.e)
      ...
      module2.cr   #loads all module2 files into namespace Amethyst::Module2
    file_module.cr #module that consists of one file
  amethyst.cr      #requires module1.cr, module2.cr, file_module.cr

spec/
  module1/
    class1_spec.cr #specs for Module1::Class
  module2/
    class2_spec.cr
  spec_helper      #loads amethyst.cr

examples/          #examples to play with
                   #don't forget to require "..src/amethyst"

Contributing

  1. Fork it ( https://github.com/Codcore/amethyst/fork )
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create a new Pull Request

Contributors

  • Codcore codcore - creator, maintainer
amethyst:
  github: amethyst-framework/amethyst
  version: ~> 0.0.2
Crystal none

Dependencies 0

Development Dependencies 0

Dependents 0

Last synced .
search fire star recently