Code Monkey home page Code Monkey logo

hanami's Introduction

Hanami ๐ŸŒธ

The web, with simplicity.

Version

This branch contains the code for hanami 2.0.x.

Frameworks

Hanami is a full-stack Ruby web framework. It's made up of smaller, single-purpose libraries.

This repository is for the full-stack framework, which provides the glue that ties all the parts together:

These components are designed to be used independently or together in a Hanami application.

Status

Gem Version CI Depfu

Installation

Hanami supports Ruby (MRI) 3.0+

gem install hanami

Usage

hanami new bookshelf
cd bookshelf && bundle
bundle exec hanami server # visit http://localhost:2300

Please follow along with the Getting Started guide.

Donations

You can give back to Open Source, by supporting Hanami development via GitHub Sponsors.

Supporters

Contact

Community

We strive for an inclusive and helpful community. We have a Code of Conduct to handle controversial cases. In general, we expect you to be nice with other people. Our hope is for a great software and a great Community.

Contributing Open Source Helpers

  1. Fork it ( https://github.com/hanami/hanami/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

In addition to contributing code, you can help to triage issues. This can include reproducing bug reports, or asking for vital information such as version numbers or reproduction instructions. If you would like to start triaging issues, one easy way to get started is to subscribe to hanami on CodeTriage.

Tests

To run all test suite:

$ bundle exec rake

To run all the unit tests:

$ bundle exec rspec spec/unit

To run all the integration tests:

$ bundle exec rspec spec/integration

To run a single test:

$ bundle exec rspec path/to/spec.rb

Development Requirements

  • Ruby >= 3.0
  • Bundler
  • Node.js (MacOS)

Versioning

Hanami uses Semantic Versioning 2.0.0

Copyright

Copyright ยฉ 2014 Hanami Team โ€“ Released under MIT License.

hanami's People

Contributors

aderyabin avatar alfonsouceda avatar artofhuman avatar brennovich avatar cllns avatar davydovanton avatar duykhoa avatar erol avatar gotjosh avatar hieuk09 avatar jasoncharnes avatar jeremyf avatar jodosha avatar lengarvey avatar linuus avatar lucasallan avatar mengqing avatar nguyenngoc2505 avatar oreoshake avatar parndt avatar rosafaria avatar solnic avatar stevehook avatar t4deu avatar thecrab avatar timriley avatar titeiko avatar tomkadwill avatar vyper avatar waiting-for-dev avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

hanami's Issues

Allow to configure cookies

Provide a configuration for cookies.

Proposal

module Bookshelf
  class Application < Lotus::Application
    configure do
      cookies true
    end
  end
end

This should inject Lotus::Action::Cookies into Bookshelf::Action, using Lotus::Controller::Configuration#modules during the load time.

Secure by default?

What is the policy for Lotus regarding security? Should Lotus be (reasonably) secure by default or should this be a responsibility of the developer? (I'm thinking about rack-protection for example, I' not so sure about a mechanism similar to SafeBuffer)

Make JSON body available in params

Rack implementation doesn't parse JSON requests by default.

Example

# config.ru
require 'rubygems'
require 'bundler/setup'
require 'lotus'

module Bookshelf
  class Application < Lotus::Application
    configure do
      routes do
        put '/api/apps/:id', to: 'apps#update'
      end
    end

    load!
  end

  module Controllers
    module Apps
      include Bookshelf::Controller

      action 'Update' do
        def call(params)
          self.body = params.inspect
        end
      end
    end
  end
end

run Bookshelf::Application.new
curl http://localhost:9292/api/apps/1 -H "Content-Type: application/json" -H "Accept: application/json" -d '{"id":"1", "published":false}' -X PUT

Returns { :id => "1" } and omits published from request body.

Custom error pages

Allow developers to customize their error pages.

As now, when a request that accepts text/html and causes a non successful response, the framework shows a simple page like the following:

<!DOCTYPE html>
<html>
  <head>
    <title>Internal Server Error</title>
  </head>
  <body>
    <h1>Internal Server Error</h1>
  </body>
</html>

This use case is handled by Lotus::Views::Default which renders lotus/templates/default.html.erb.

Method load! problems

Hi Guys, I try the OneFile example, but when run rackup I get this error:

<class:Application>': undefined methodload!' for OneFile::Application:Class (NoMethodError)

When I removed the load! method and replace the module OneFile:: per global Lotus::, the code run without problems

Modular structure

Love the approach you are taking. Thank you for your work.
Is it possible to suport a modular structure where each module/feature is self contained as shown below

test/fixtures/information_tech
โ”œโ”€โ”€ modules
โ”‚   โ”œโ”€โ”€ Foo
โ”‚   โ”‚   โ”œโ”€โ”€ controllers
โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ foo_controller.rb            FooController::Index
โ”‚   โ”‚   โ”œโ”€โ”€ templates
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ foo.html.erb
โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ foo
โ”‚   โ”‚   โ”‚       โ””โ”€โ”€ index.html.erb
โ”‚   โ”‚   โ”œโ”€โ”€ views
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ foo_sub_layout.rb            ModuleLayout
โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ foo
โ”‚   โ”‚   โ”‚       โ””โ”€โ”€ index.rb                 foo::Index
โ”‚   โ”‚   โ”œโ”€โ”€ config
โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ routes
โ”‚   โ”‚   โ”œโ”€โ”€ javascripts
โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ application.js
โ”‚   โ”‚   โ””โ”€โ”€ stylesheets
โ”‚   โ”‚       โ””โ”€โ”€ application.css
โ”‚   โ”œโ”€โ”€ Bar
โ”‚   โ”‚   โ”œโ”€โ”€ controllers
โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ bar_controller.rb            HardwareController::Index
โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ zeebar_controller.rb         HardwareController::Index
โ”‚   โ”‚   โ”œโ”€โ”€ templates
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ bar.html.erb
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ bar
โ”‚   โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ index.html.erb
โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ zeebar
โ”‚   โ”‚   โ”‚       โ””โ”€โ”€ index.html.erb
โ”‚   โ”‚   โ”œโ”€โ”€ views
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ bar_sub_layout.rb            ModuleLayout
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ bar
โ”‚   โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ index.rb                 Bar::Index
โ”‚   โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ edit.rb                  Bar::Edit
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ zeebar
โ”‚   โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ index.rb                 ZeeBar::Index
โ”‚   โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ edit.rb                  ZeeBar::Edit
โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ shared
โ”‚   โ”‚   โ”‚       โ””โ”€โ”€ bar_sub_layout.rb        Hardware::Index
โ”‚   โ”‚   โ”œโ”€โ”€ config
โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ routes
โ”‚   โ”‚   โ”œโ”€โ”€ javascripts
โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ application.js
โ”‚   โ”‚   โ””โ”€โ”€ stylesheets
โ”‚   โ”‚       โ””โ”€โ”€ application.css
โ”‚   โ”‚
โ”‚   โ”œโ”€โ”€ controllers
โ”‚   โ”‚   โ””โ”€โ”€ hardware_controller.rb           HardwareController::Index
โ”‚   โ”œโ”€โ”€ templates
โ”‚   โ”‚   โ”œโ”€โ”€ app.html.erb
โ”‚   โ”‚   โ””โ”€โ”€ hardware
โ”‚   โ”‚       โ””โ”€โ”€ index.html.erb
โ”‚   โ””โ”€โ”€ views
โ”‚       โ”œโ”€โ”€ app_layout.rb                    AppLayout
โ”‚       โ””โ”€โ”€ hardware
โ”‚           โ””โ”€โ”€ index.rb                     Hardware::Index
โ”œโ”€โ”€ application.rb                           InformationTech::Application
โ”œโ”€โ”€ config
โ”‚   โ””โ”€โ”€ routes.rb
โ””โ”€โ”€ public
    โ”œโ”€โ”€ favicon.ico
    โ”œโ”€โ”€ fonts
    โ”‚   โ””โ”€โ”€ cabin-medium.woff
    โ”œโ”€โ”€ images
    โ”‚   โ””โ”€โ”€ application.jpg
    โ”œโ”€โ”€ javascripts
    โ”‚   โ””โ”€โ”€ application.js
    โ””โ”€โ”€ stylesheets
        โ””โ”€โ”€ application.css


rake routes or lotus routes

Hi:

It would be a good a idea print routes like rails does it 'rake routes'.

Do you think is better idea with rake or lotus?

Logging utilities

Add logging utilities for each Lotus application. An idea on how to implement is to generate a Bookshelf::Logger class for a Bookshelf::Application.

Lotus failed to serve assets

The code is at: github.com/joneslee85/lotus-blog

When I run: bundle exec lotus server and browser localhost:2300/posts

I got error:

Unexpected error while processing request: Content-Length header was 18943, but should be 0
    /Users/trung_le/src/lotus-blog/.bundle/ruby/2.1.0/gems/rack-1.5.2/lib/rack/lint.rb:20:in `assert'
    /Users/trung_le/src/lotus-blog/.bundle/ruby/2.1.0/gems/rack-1.5.2/lib/rack/lint.rb:631:in `verify_content_length'
    /Users/trung_le/src/lotus-blog/.bundle/ruby/2.1.0/gems/rack-1.5.2/lib/rack/lint.rb:655:in `each'
    /Users/trung_le/src/lotus-blog/.bundle/ruby/2.1.0/gems/rack-1.5.2/lib/rack/body_proxy.rb:31:in `each'
    /Users/trung_le/src/lotus-blog/.bundle/ruby/2.1.0/gems/thin-1.6.3/lib/thin/response.rb:96:in `each'
    /Users/trung_le/src/lotus-blog/.bundle/ruby/2.1.0/gems/thin-1.6.3/lib/thin/connection.rb:114:in `post_process'
    /Users/trung_le/src/lotus-blog/.bundle/ruby/2.1.0/gems/thin-1.6.3/lib/thin/connection.rb:53:in `process'
    /Users/trung_le/src/lotus-blog/.bundle/ruby/2.1.0/gems/thin-1.6.3/lib/thin/connection.rb:39:in `receive_data'
    /Users/trung_le/src/lotus-blog/.bundle/ruby/2.1.0/gems/eventmachine-1.0.3/lib/eventmachine.rb:187:in `run_machine'
    /Users/trung_le/src/lotus-blog/.bundle/ruby/2.1.0/gems/eventmachine-1.0.3/lib/eventmachine.rb:187:in `run'
    /Users/trung_le/src/lotus-blog/.bundle/ruby/2.1.0/gems/thin-1.6.3/lib/thin/backends/base.rb:73:in `start'
    /Users/trung_le/src/lotus-blog/.bundle/ruby/2.1.0/gems/thin-1.6.3/lib/thin/server.rb:162:in `start'
    /Users/trung_le/src/lotus-blog/.bundle/ruby/2.1.0/gems/rack-1.5.2/lib/rack/handler/thin.rb:16:in `run'
    /Users/trung_le/src/lotus-blog/.bundle/ruby/2.1.0/gems/rack-1.5.2/lib/rack/server.rb:264:in `start'
    /Users/trung_le/src/lotus-blog/.bundle/ruby/2.1.0/bundler/gems/lotus-224fc6019ddd/lib/lotus/cli.rb:24:in `server'
    /Users/trung_le/src/lotus-blog/.bundle/ruby/2.1.0/gems/thor-0.19.1/lib/thor/command.rb:27:in `run'
    /Users/trung_le/src/lotus-blog/.bundle/ruby/2.1.0/gems/thor-0.19.1/lib/thor/invocation.rb:126:in `invoke_command'
    /Users/trung_le/src/lotus-blog/.bundle/ruby/2.1.0/gems/thor-0.19.1/lib/thor.rb:359:in `dispatch'
    /Users/trung_le/src/lotus-blog/.bundle/ruby/2.1.0/gems/thor-0.19.1/lib/thor/base.rb:440:in `start'
    /Users/trung_le/src/lotus-blog/.bundle/ruby/2.1.0/bundler/gems/lotus-224fc6019ddd/bin/lotus:4:in `<top (required)>'
    /Users/trung_le/src/lotus-blog/.bundle/ruby/2.1.0/bin/lotus:23:in `load'
    /Users/trung_le/src/lotus-blog/.bundle/ruby/2.1.0/bin/lotus:23:in `<main>'

I could reproduce this bug easily. Any thought?

`lotus new` should initialize a git repository

While I dislike being git-centric, I think this is important behaviour. A plurality of developers are going to be using git, and failing to support that as the default also means that users who quickly add a repository will often miss files that shouldn't be committed, such as config/.env et al. which are files that are exceedingly easy to miss.

I realized that I myself contributed my app's session secret earlier as a result. Granted it was the development secret, but if there had been a generated production secret, it would now be in my repository's history.

Allow to configure sessions

A Lotus application should provide an API to enable sessions and to allow developers to set options for it. This should take advantage of the middleware configuration (#40).

Proposal:

module Bookshelf
  class Application < ::Lotus::Application
    configure do
      sessions true

      middleware.use Rack::Session::Redis,
        domain: 'foo.com',
        expire_after: 2592000
    end
  end
end

Please note that sessions true should enable sessions, by including Lotus::Action::Sessions into Bookshelf::Action taking advantage of Lotus::Controller::Configuration#modules.

The ideal place where this should happen is at the load time.

Alternative proposal:

module Bookshelf
  class Application < ::Lotus::Application
    configure do
      sessions :redis,
        domain: 'foo.com',
        expire_after: 2592000
    end
  end
end

This should:

  1. Enable sessions with the same mechanisms above
  2. Lookup for a Rack::Session::Redis middleware and add it with middleware.use

This is alternative is nicer, because it hides the internal requirements of the framework (see sessions true above). On the other hand, we're introducing a convention: :redis => Rack::Session::Redis. I'd make #sessions to accept also a class (name). Example sessions MySessionStore and/or sessions 'MySessionStore'.

Access to SQL console

Status: In Progress

Provide a convenient way to access the SQL console. The feature should resemble the Rails's rake db:console

The interface for the CLI would be: bundle exec lotus dbconsole. The command should look into the configuration of adapter which is set in lib/<app_name>.rb.

Please be noted that the command only works if adapter is SQL, it should raise error or warning that if it uses non-SQL adapter.

Autogeneration of MyApp::Controller and MyApp::View is magic

I would like that autogeneration of MyApp::Controller is removed. This feature suprised me when I found out about it. What happened in my development was that I wanted to make a MyApp::Controller, and then I got warnings of already initialized constant, and some really weird errors (because I tried to make MyApp::Controller a class). There is

unless application_module.const_defined?('Controller')
  # generate MyApp::Controller
end

But it didn't work for me, because I didn't require "my_app/controller" before the app loading (I did it in individual controllers).

Another downside of this approach is that now controllers (and views) which "inherit" from MyApp::Controller (MyApp::View) can't be tested in isolation, because they require MyApp::Application to be loaded (so that it generates the "application" controller). I really liked Lotus' idea of isolated unit-testing, that I can just require the components I need.

I know there is the problem of "inheriting" some configuration from Lotus::Application#configuration, like #handle_exceptions, #format etc. But in my opinion these should have stayed only in Lotus::Controller, for me it's such a perfect idea to configure individual components (I original thought Lotus encouraged that), and not the global Application class itself.

What do you think about this?

Allow asset path configuration

It would be great if Lotus would provide a way to allow developers to configure asset paths (especially for multi-app scenarios).

Example structure:

โ”œโ”€โ”€ apps
โ”‚ย ย  โ”œโ”€โ”€ backend 
โ”‚ย ย  โ”‚ย ย  โ”œโ”€โ”€ controllers
โ”‚ย ย  โ”‚ย ย  โ”œโ”€โ”€ ...
โ”‚ย ย  โ”‚ย ย  โ”œโ”€โ”€ public
โ”‚ย ย  โ”‚ย ย  โ”‚ย ย  โ”œโ”€โ”€ css
โ”‚ย ย  โ”‚ย ย  โ”‚ย ย  โ”œโ”€โ”€ images
โ”‚ย ย  โ”‚ย ย  โ”‚ย ย  โ””โ”€โ”€ js
โ”‚ย ย  โ”‚ย ย  โ””โ”€โ”€ application.rb
โ”‚ย ย  โ”œโ”€โ”€ frontend
โ”‚ย ย  โ”‚ย ย  โ”œโ”€โ”€ controllers
โ”‚ย ย  โ”‚ย ย  โ”œโ”€โ”€ ...
โ”‚ย ย  โ”‚ย ย  โ”œโ”€โ”€ public
โ”‚ย ย  โ”‚ย ย  โ”‚ย ย  โ”œโ”€โ”€ css
โ”‚ย ย  โ”‚ย ย  โ”‚ย ย  โ”œโ”€โ”€ images
โ”‚ย ย  โ”‚ย ย  โ”‚ย ย  โ””โ”€โ”€ js
โ”‚ย ย  โ”œโ”€โ”€ public
โ”‚ย ย  โ”‚ย ย  โ”œโ”€โ”€ vendor
โ”‚ย ย  โ”‚ย ย  โ”œโ”€โ”€ fonts
โ”‚ย ย  โ”‚ย ย  โ”œโ”€โ”€ images

@jodosha suggested the following API similar to the existing load_paths API

Customers::Application < Lotus::Application
  configure do
    assets << [
      'public',
      'path/to/vendored/assets'
    ]
  end
end

Gem doesn't install any executables

The README suggests the gem provides command line utilities such as lotus server and lotus console. However a fresh install doesn't include any executables:

alex:~$ ruby -v
ruby 2.1.2p95 (2014-05-08 revision 45877) [x86_64-darwin13.0]
alex:~$ gem install lotusrb
Successfully installed lotusrb-0.1.0
Parsing documentation for lotusrb-0.1.0
Done installing documentation for lotusrb after 0 seconds
1 gem installed
alex:~$ gem which lotus
.../lotusrb-0.1.0/lib/lotus.rb
alex:~$ lotus server
-bash: lotus: command not found

The same happens when installed from a Gemfile inside a lotus project. Am I missing something?

Get response from middleware

I used this construction:

action 'SignIn' do
  use Auth::SignIn

  def call(params)
  end
end

Auth::SignIn returns Rack::Response, but action SignIn doesn't know about this response. How can I return this response or get params from middleware to call method?

Support .env files

Support .env files in order to load configurations into ENV variables.
This is a well known and large used best practice.

This is a proposal to support multiple environments and put those files under config/. We should have a general file .env that is the master of all the configurations. Then we should have per environment settings.

# ...
config/
  .env             # general
  .env.development # environment specifics overloads
  .env.test

The idea is to use a dotenv gem for this.

Example

# config/.env.development
DATABASE_URL="postgres://localhost/bookshelf_development"
# config/.env.test
DATABASE_URL="postgres://localhost/bookshelf_test"
module Bookshelf
  class Application < Lotus::Application
    configure do
      adapter type: :sql, uri: ENV['DATABASE_URL']
    end
  end
end

Code generators

In order to streamline the getting started process with Lotus, we want to provide an application generator. The implementation can take advantage of the code that Lotus CLI offers (see #23 ).

One pending question is about the default code structure that we want to support. After a lot of experiments with Lotus apps, I vote for microservices.

That architecture encourages developers to keep all the code under the application module and to not pollute Ruby global namespace. This makes easier to build/run multiple applications in the same repository / process and to eventually extract them, as the code base grows.

Application freeze

The Lotus philosophy for application boot is: load all the code at the beginning, then freeze the parts that may suffer of accidental changes and lead to software defects.

This MUST include:

  • The configuration of an application (see Lotus::Application.configuration)
  • All the configurations of the single duplicated frameworks

Lotus console doesn't load files in load_path

Given this example application:

require 'lotus'
require 'lotus/model'

module Timetracker
  class Application < Lotus::Application
    configure do
      root File.dirname(__FILE__)
      load_paths << [
        'controllers',
        'entities',
        'repositories'
      ]

      routes 'config/routes'
      mapping 'config/mapping'
    end
  end
end

And this entity:

module Timetracker
  module Entities
    class User
      include Lotus::Entity

      self.attributes = :name, :lastname, :email, :password, :activated
    end
  end
end

puts "hi"

When starting the application the user entity gets required via the load_path configuration.

timetracker-ruby โžค be lotus server -p 3000                                                                                        git:master mri-2.1.5
hi
[2014-11-16 11:37:10] INFO  WEBrick 1.3.1
[2014-11-16 11:37:10] INFO  ruby 2.1.5 (2014-11-13) [x86_64-linux]
[2014-11-16 11:37:10] INFO  WEBrick::HTTPServer#start: pid=30579 port=3000

When starting the lotus console the entity isn't required:

timetracker-ruby โžค be lotus console --applications=app/application.rb                                                             git:master mri-2.1.5
irb(main):001:0> 

The whole application can be found under: https://github.com/bennyklotz/timetracker-ruby

Introduce Lotus::Container

Lotus::Container allows to define multiple Rack and Lotus applications in a single place.

Architecture

This is needed as public API reference in a context of a Lotus microservices architecture.

# config/environment.rb

Lotus::Container.configure do
  mount Backend::Application, at: '/backend'
  mount Web::Application,     at: '/'
end
# config.ru

run Lotus::Container.new
# use with Capybara
Capybara.app = Lotus::Container.new

Testing applications in isolation

The other requirement is to allow developers to test components in isolation.
When we mount applications directly in Lotus::Router, it immediately instantiate them.

my_router = Lotus::Router.new {
  mount Web::Application, at: '/'
}

# at this point Web::Application in instantiated and stored by `my_router`.

When we instantiate a Lotus::Application, it self configures and load all the production code. In other words, all the controllers, views, entities are loaded by doing Web::Application.new.

If we want to test things in isolation, we need to defer the time when those things are loaded. There are two scenarios when we want the full application loaded: when it's started (with lotus server or puma) and when we're running features with Capybara.

Lotus::Container instantiate the registered applications only when we instantiate it.

Allow redirects with symbols

As now we have two ways to specify an URL for a redirect in an action:

By hardcoding the path:

redirect_to '/'

By using the helper:

redirect_to MyApp::Routes.url(:root)

I would like to introduce a third way:

redirect_to :root

Load order

My structure is:

app/
   controllers/
      mixins/
         some_mixin.rb
      first_controller.rb
      second_controller.rb

FirstController and SecondController are using SomeMixin.
The problem is that those controllers are loaded first when SomeMixin is undefined.

Any ideas how to deal with it?

Session test fail intermittently

I took few runs till I bumped into this intermittent failure

Trungs-MacBook-Pro:lotus trung_le$ rake test
Run options: --seed 32658

# Running:

.............F....................WARN: tilt autoloading 'tilt/erb' in a non thread-safe way; explicit require 'tilt/erb' suggested.
.................................................................................................................................................................................................................S.......................................S...SS..........................

Finished in 1.277457s, 246.5836 runs/s, 600.4116 assertions/s.

  1) Failure:
Lotus::Middleware::when it's configured with sessions#test_0001_includes sessions middleware [/Users/trung_le/src/lotusrb/lotus/test/middleware_test.rb:51]:
Expected [["Rack::Session::Cookie", [{:domain=>"0.0.0.0", :secure=>false}], nil], [Lotus::Welcome, [], nil], [Rack::MethodOverride, [], nil]] to include ["Rack::Session::Cookie", [{}], nil].

315 runs, 767 assertions, 1 failures, 0 errors, 4 skips

You have skipped tests. Run with --verbose for details.
rake aborted!
Command failed with status (1): [ruby -I"lib:test" -I"/opt/boxen/rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/rake-10.4.2/lib" "/opt/boxen/rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/rake-10.4.2/lib/rake/rake_test_loader.rb" "test/**/*_test.rb" ]

Per framework configuration

Framework configurations are a fast moving target.
With the current approach, if we introduce a new setting in a minor release of Model/View/Controller gems, we're forced to add it to Lotus::Configuration as well.

There are some configurations that makes sense to expose at the top level (Lotus::Configuration) like we do right now. Settings like adapter and mapping are stable in both Lotus and Lotus::Model.

There are also some minor things that we can add from time to time.

For instance, in the next version of Lotus::Controller there is Action#request_id. It's implemented like this: SecureRandom.hex(DEFAULT_REQUEST_ID_LENGTH). That constant is equal to 16.

Now, if some reason we want to add way to change the algorithm or the length, via Lotus::Controller::Configuration, we can't think to add the corresponding API in lotusrb. Again, the reason is the maintenance in the long term: it's hard to keep in sync Lotus with the other frameworks.

My proposal is to add per framework configuration.

module Bookshelf
  class Application < Lotus::Application
    configure do
      controller.handle_exceptions false

      view.prepare do
        include RoutingHelpers
      end
    end
  end
end

The idea is to forward those method calls to the underlying frameworks configurations.

Getting back to the example above, if we ship a minor release of lotus-controller with that setting. Once the developers do a bundle update they're able to use it, without the need of a new lotusrb release.

Failed to render page with Safari

I clone your furnitures app then try to run it with rackup. When I view /catalog page under Safari, I got error from Safari that the server has dropped connection and return an Safari error page. I checked the output of WEBrick, and the request seems fine "GET HTTP/1.1" 200 - 0.0123.

FYI, the page renders normally under Chrome.

The test app is at github.com/joneslee85/lotus-blog, please run start.sh to start the app

Not Found response when mounting a Rack app into Lotus container

Given a container configuration:

Lotus::Container.configure do
  mount Web::Application, at: '/'
  mount ->(env) {[200, {}, ['Rack Four']]},  at: '/rack'
end

After starting server, perform a curl request:

curl -H Accept:application/json -H Content-Type:application/json http://localhost:2300/rack

Results in a Not Found.

Environment information follows.

ruby -v
ruby 2.1.5p273 (2014-11-13 revision 48405) [x86_64-darwin14.0]
bundle show
  ...
  * lotus-controller (0.3.0)
  * lotus-model (0.2.0)
  * lotus-router (0.2.0)
  * lotus-utils (0.3.2)
  * lotus-validations (0.2.1)
  * lotus-view (0.3.0)
  * lotusrb (0.2.0)
  ...
  * rack (1.6.0)
  * rack-accept (0.4.5)
  * rack-mount (0.8.3)
  * rack-test (0.6.2)

Application.configure to accept a path

Actual

We can override configurations per env basis.

module Bookshelf
  class Application < Lotus::Application
    configure do
      handle_exceptions true # this is the default value
      default_format :json
    end

    configure :development do
      handle_exceptions false
    end
  end
end

Configurations are inherited from the general one (the first), and according to the current env, the second block is evaluated.

In the example above the default format will always be JSON, because it was configured in the general one and not overwritten by the child.

The behavior changes when we talk about exceptions: in development mode they won't he handled, but they will be in all the other environments.

Proposed API

In order to declutter application.rb we should allow developers to specify a path where to find the settings for a specific env.

# application.rb

module Bookshelf
  class Application < Lotus::Application
    configure do
      handle_exceptions true # this is the default value
      default_format :json
    end

    configure :development, 'config/development'
  end
end
# config/development.rb

handle_exceptions false

We have a similar code for Configuration#routes and #mapping.

Dotenv error when application name includes a dash

When I create an application with a dash in its name, running bundle exec lotus server fails even when I've not changed anything.

I can reproduce this on both the latest gem version and when generated using --lotus-head.

I suspect we need to do some sanitization of app names to prevent invalid characters from being used in ENV variables.

Here's an example stack trace:

/home/rob/Sites/r/rob-dyn/vendor/gems/ruby/2.1.0/gems/dotenv-1.0.2/lib/dotenv/parser.rb:59:in `block in call': Line "ROB-DYN_DATABASE_URL=\"file:///db/rob-dyn_development\"" doesn't match format (Dotenv::FormatError)
    from /home/rob/Sites/r/rob-dyn/vendor/gems/ruby/2.1.0/gems/dotenv-1.0.2/lib/dotenv/parser.rb:37:in `each'
    from /home/rob/Sites/r/rob-dyn/vendor/gems/ruby/2.1.0/gems/dotenv-1.0.2/lib/dotenv/parser.rb:37:in `inject'
    from /home/rob/Sites/r/rob-dyn/vendor/gems/ruby/2.1.0/gems/dotenv-1.0.2/lib/dotenv/parser.rb:37:in `call'
    from /home/rob/Sites/r/rob-dyn/vendor/gems/ruby/2.1.0/gems/dotenv-1.0.2/lib/dotenv/parser.rb:29:in `call'
    from /home/rob/Sites/r/rob-dyn/vendor/gems/ruby/2.1.0/gems/dotenv-1.0.2/lib/dotenv/environment.rb:10:in `load'
    from /home/rob/Sites/r/rob-dyn/vendor/gems/ruby/2.1.0/gems/dotenv-1.0.2/lib/dotenv/environment.rb:6:in `initialize'
    from /home/rob/Sites/r/rob-dyn/vendor/gems/ruby/2.1.0/gems/dotenv-1.0.2/lib/dotenv.rb:16:in `new'
    from /home/rob/Sites/r/rob-dyn/vendor/gems/ruby/2.1.0/gems/dotenv-1.0.2/lib/dotenv.rb:16:in `block in overload'
    from /home/rob/Sites/r/rob-dyn/vendor/gems/ruby/2.1.0/gems/dotenv-1.0.2/lib/dotenv.rb:27:in `call'
    from /home/rob/Sites/r/rob-dyn/vendor/gems/ruby/2.1.0/gems/dotenv-1.0.2/lib/dotenv.rb:27:in `block (2 levels) in with'
    from /home/rob/Sites/r/rob-dyn/vendor/gems/ruby/2.1.0/gems/dotenv-1.0.2/lib/dotenv.rb:26:in `each'
    from /home/rob/Sites/r/rob-dyn/vendor/gems/ruby/2.1.0/gems/dotenv-1.0.2/lib/dotenv.rb:26:in `block in with'
    from /home/rob/Sites/r/rob-dyn/vendor/gems/ruby/2.1.0/gems/dotenv-1.0.2/lib/dotenv.rb:25:in `tap'
    from /home/rob/Sites/r/rob-dyn/vendor/gems/ruby/2.1.0/gems/dotenv-1.0.2/lib/dotenv.rb:25:in `with'
    from /home/rob/Sites/r/rob-dyn/vendor/gems/ruby/2.1.0/gems/dotenv-1.0.2/lib/dotenv.rb:16:in `overload'
    from /home/rob/Sites/r/rob-dyn/vendor/gems/ruby/2.1.0/bundler/gems/lotus-9e7ec45d7765/lib/lotus/environment.rb:368:in `set_application_env_vars!'
    from /home/rob/Sites/r/rob-dyn/vendor/gems/ruby/2.1.0/bundler/gems/lotus-9e7ec45d7765/lib/lotus/environment.rb:353:in `set_env_vars!'
    from /home/rob/Sites/r/rob-dyn/vendor/gems/ruby/2.1.0/bundler/gems/lotus-9e7ec45d7765/lib/lotus/environment.rb:160:in `block in initialize'
    from /home/rob/Sites/r/rob-dyn/vendor/gems/ruby/2.1.0/bundler/gems/lotus-9e7ec45d7765/lib/lotus/environment.rb:160:in `synchronize'
    from /home/rob/Sites/r/rob-dyn/vendor/gems/ruby/2.1.0/bundler/gems/lotus-9e7ec45d7765/lib/lotus/environment.rb:160:in `initialize'
    from /home/rob/Sites/r/rob-dyn/vendor/gems/ruby/2.1.0/bundler/gems/lotus-9e7ec45d7765/lib/lotus/cli.rb:82:in `new'
    from /home/rob/Sites/r/rob-dyn/vendor/gems/ruby/2.1.0/bundler/gems/lotus-9e7ec45d7765/lib/lotus/cli.rb:82:in `environment'
    from /home/rob/Sites/r/rob-dyn/vendor/gems/ruby/2.1.0/bundler/gems/lotus-9e7ec45d7765/lib/lotus/cli.rb:32:in `server'
    from /home/rob/Sites/r/rob-dyn/vendor/gems/ruby/2.1.0/gems/thor-0.19.1/lib/thor/command.rb:27:in `run'
    from /home/rob/Sites/r/rob-dyn/vendor/gems/ruby/2.1.0/gems/thor-0.19.1/lib/thor/invocation.rb:126:in `invoke_command'
    from /home/rob/Sites/r/rob-dyn/vendor/gems/ruby/2.1.0/gems/thor-0.19.1/lib/thor.rb:359:in `dispatch'
    from /home/rob/Sites/r/rob-dyn/vendor/gems/ruby/2.1.0/gems/thor-0.19.1/lib/thor/base.rb:440:in `start'
    from /home/rob/Sites/r/rob-dyn/vendor/gems/ruby/2.1.0/bundler/gems/lotus-9e7ec45d7765/bin/lotus:4:in `<top (required)>'
    from /home/rob/Sites/r/rob-dyn/vendor/gems/ruby/2.1.0/bin/lotus:23:in `load'
    from /home/rob/Sites/r/rob-dyn/vendor/gems/ruby/2.1.0/bin/lotus:23:in `<main>'

can't disable assets

Hello! I want NGINX to serve files from the public directory so I decided to disable assets in lotus so it won't handle that requests and let NGINX do its business.

 class Application < Lotus::Application
    configure do
      layout :application
      load_paths << 'app'
      routes 'config/routes'
      assets :disabled
    end

    def self.root
      Pathname.new(File.expand_path(__dir__, '../..')).dirname.realpath
    end
  end

but there an wild error appeared

/Users/lessless/.rubies/ruby-2.1.5/lib/ruby/2.1.0/pathname.rb:392:in `initialize': no implicit conversion of Symbol into String (TypeError)
    from /Users/lessless/.rubies/ruby-2.1.5/lib/ruby/2.1.0/pathname.rb:392:in `new'
    from /Users/lessless/.rubies/ruby-2.1.5/lib/ruby/2.1.0/pathname.rb:392:in `join'
    from /Users/lessless/.gem/ruby/2.1.5/gems/lotusrb-0.1.0/lib/lotus/config/assets.rb:11:in `initialize'
    from /Users/lessless/.gem/ruby/2.1.5/gems/lotusrb-0.1.0/lib/lotus/configuration.rb:353:in `new'
    from /Users/lessless/.gem/ruby/2.1.5/gems/lotusrb-0.1.0/lib/lotus/configuration.rb:353:in `assets'
    from /Users/lessless/.gem/ruby/2.1.5/gems/lotusrb-0.1.0/lib/lotus/middleware.rb:24:in `initialize'
    from /Users/lessless/.gem/ruby/2.1.5/gems/lotusrb-0.1.0/lib/lotus/application.rb:118:in `new'
    from /Users/lessless/.gem/ruby/2.1.5/gems/lotusrb-0.1.0/lib/lotus/application.rb:118:in `middleware'
    from /Users/lessless/.gem/ruby/2.1.5/gems/lotusrb-0.1.0/lib/lotus/loader.rb:72:in `load_application!'
    from /Users/lessless/.gem/ruby/2.1.5/gems/lotusrb-0.1.0/lib/lotus/loader.rb:24:in `block in load!'
    from /Users/lessless/.gem/ruby/2.1.5/gems/lotusrb-0.1.0/lib/lotus/loader.rb:21:in `synchronize'
    from /Users/lessless/.gem/ruby/2.1.5/gems/lotusrb-0.1.0/lib/lotus/loader.rb:21:in `load!'
    from /Users/lessless/.gem/ruby/2.1.5/gems/lotusrb-0.1.0/lib/lotus/application.rb:77:in `initialize'
    from /Users/lessless/Code/ruby/users/config.ru:18:in `new'
    from /Users/lessless/Code/ruby/users/config.ru:18:in `block in <main>'
    from /Users/lessless/.gem/ruby/2.1.5/gems/rack-1.5.2/lib/rack/builder.rb:55:in `instance_eval'
    from /Users/lessless/.gem/ruby/2.1.5/gems/rack-1.5.2/lib/rack/builder.rb:55:in `initialize'
    from /Users/lessless/Code/ruby/users/config.ru:in `new'
    from /Users/lessless/Code/ruby/users/config.ru:in `<main>'
    from /Users/lessless/.gem/ruby/2.1.5/gems/rack-1.5.2/lib/rack/builder.rb:49:in `eval'
    from /Users/lessless/.gem/ruby/2.1.5/gems/rack-1.5.2/lib/rack/builder.rb:49:in `new_from_string'
    from /Users/lessless/.gem/ruby/2.1.5/gems/rack-1.5.2/lib/rack/builder.rb:40:in `parse_file'
    from /Users/lessless/.gem/ruby/2.1.5/gems/rack-1.5.2/lib/rack/server.rb:277:in `build_app_and_options_from_config'
    from /Users/lessless/.gem/ruby/2.1.5/gems/rack-1.5.2/lib/rack/server.rb:199:in `app'
    from /Users/lessless/.gem/ruby/2.1.5/gems/rack-1.5.2/lib/rack/server.rb:314:in `wrapped_app'
    from /Users/lessless/.gem/ruby/2.1.5/gems/rack-1.5.2/lib/rack/server.rb:250:in `start'
    from /Users/lessless/.gem/ruby/2.1.5/gems/rack-1.5.2/lib/rack/server.rb:141:in `start'
    from /Users/lessless/.gem/ruby/2.1.5/gems/rack-1.5.2/bin/rackup:4:in `<top (required)>'
    from /Users/lessless/.gem/ruby/2.1.5/bin/rackup:23:in `load'
    from /Users/lessless/.gem/ruby/2.1.5/bin/rackup:23:in `<main>'

Access router from views/templates

Just wondering if there is a recommended way of accessing the router (for path helpers) from views/templates.

@robyurkowski pointed out a way to access it through the application constant:

MyApplication::Routes.path(:sign_in)

Should something be exposed at the view level?

Testing utilities

Add utilities to ease the testing process.
The goal is to support BDD via feature and unit tests. For feature tests we mean, full stack, browser simulation (like Cucumber does).

This should be part of this PR. We should support the same feature with MiniTest & RSpec

The expected structure is:

spec
โ”œโ”€โ”€ chirp
โ”‚ย ย  โ”œโ”€โ”€ entities
โ”‚ย ย  โ”œโ”€โ”€ repositories
โ”œโ”€โ”€ support
โ”œโ”€โ”€ features_helper.rb
โ”œโ”€โ”€ spec_helper.rb
โ””โ”€โ”€ web
    โ”œโ”€โ”€ controllers
    โ”œโ”€โ”€ features
    โ””โ”€โ”€ views
  • Support MiniTest
  • Support RSpec
  • Support for feature tests with Capybara
  • Code generator must create a directory to for tests (see #29)

There is a simple setup to use with RSpec to have feature tests. The code is borrowed from rspec-rails.

Per env default Rack middleware inside application

We want to setup common per env Rack utilities. For instance Rack::Lint or Rack::ShowExceptions in development or Rack::CommonLogger in production.

The reason is to allow developers to configure their Rack stack per application basis.

JRuby support

JRuby support is currently missing from lotus.

Asking @jodosha it seems to be because Module.prepend is missing in the current JRuby release.

FYI Module.prepend seems to be mostly implemented on JRuby master jruby/jruby#751 which is the next major release (JRuby 9k) - unfortunately I dunno when it's gonna land (hoping for start of next year personally).

If I get a lot of time I might look into the code to figure out if prepend could be reasonably replaced.

Cheers!

Lotus console

Add a development console as part of the Lotus CLI (see #23).
It should load the applications and the code, and let developers to quickly test code.

Bonus, start a PRY console instead of IRB, only if PRY is available.

unable to start a single file application

When I try to run this with rackup

# config.ru
require 'lotus'

module OneFile
  class Application < Lotus::Application
    configure do
      routes do
        get '/', to: 'home#index'
      end
    end
  end

  module Controllers::Home
    include OneFile::Controller

    action 'Index' do
      def call(params)
      end
    end
  end

  module Views::Home
    class Index
      include OneFile::View

      def render
        'Hello'
      end
    end
  end
end

run OneFile::Application.new
# Gemfile
source "https://rubygems.org"
gem "lotusrb"

it throws this error:

/home/hrvoje/code/hack/lotus-fun/config.ru:13:in `<module:OneFile>': uninitialized constant OneFile::Controllers (NameError)
        from /home/hrvoje/code/hack/lotus-fun/config.ru:4:in `block in <main>'
        from /home/hrvoje/.gem/ruby/2.1.2/gems/rack-1.5.2/lib/rack/builder.rb:55:in `instance_eval'
        from /home/hrvoje/.gem/ruby/2.1.2/gems/rack-1.5.2/lib/rack/builder.rb:55:in `initialize'
        from /home/hrvoje/code/hack/lotus-fun/config.ru:in `new'
        from /home/hrvoje/code/hack/lotus-fun/config.ru:in `<main>'
        from /home/hrvoje/.gem/ruby/2.1.2/gems/rack-1.5.2/lib/rack/builder.rb:49:in `eval'
        from /home/hrvoje/.gem/ruby/2.1.2/gems/rack-1.5.2/lib/rack/builder.rb:49:in `new_from_string'
        from /home/hrvoje/.gem/ruby/2.1.2/gems/rack-1.5.2/lib/rack/builder.rb:40:in `parse_file'
        from /home/hrvoje/.gem/ruby/2.1.2/gems/rack-1.5.2/lib/rack/server.rb:277:in `build_app_and_options_from_config'
        from /home/hrvoje/.gem/ruby/2.1.2/gems/rack-1.5.2/lib/rack/server.rb:199:in `app'
        from /home/hrvoje/.gem/ruby/2.1.2/gems/rack-1.5.2/lib/rack/server.rb:314:in `wrapped_app'
        from /home/hrvoje/.gem/ruby/2.1.2/gems/rack-1.5.2/lib/rack/server.rb:250:in `start'
        from /home/hrvoje/.gem/ruby/2.1.2/gems/rack-1.5.2/lib/rack/server.rb:141:in `start'
        from /home/hrvoje/.gem/ruby/2.1.2/gems/rack-1.5.2/bin/rackup:4:in `<top (required)>'
        from /home/hrvoje/.gem/ruby/2.1.2/bin/rackup:23:in `load'
        from /home/hrvoje/.gem/ruby/2.1.2/bin/rackup:23:in `<main>'

How do I start a single file Lotus app?

Question: Are there good references on Ruby modules and Lotus' theory of how to use them?

In playing with this framework a small amount I've certainly noticed that almost everything is a module which is to be included as a mixin. I understand it is part of the philosophy of lotus and is a conscious design decision. Are there any good reference materials, books, papers, blogs, explanations, or anything else you could point me toward to help me understand the theory behind that philosophy.

Much of lotus source code reads so cleanly and is broken up very modularly because of it. In other cases however, when you get into mixins having initialize methods, or even in some cases I've seen the use of protected visibility on method_missing calls which then have an if/elsif logic gate that eventually might call super that leads to another mixin with a similar method_missing method, it gets kind of intractable to my small human brain.

Lotus doesn't work on ruby 1.9.3

Throws an error when attempting to require 'lotusrb'

SyntaxError: /home/james/.rvm/gems/ruby-1.9.3-p448/gems/lotus-controller-0.2.0/lib/lotus/action/redirect.rb:33: syntax error, unexpected tLABEL
def redirect_to(url, status: 302)
^
/home/james/.rvm/gems/ruby-1.9.3-p448/gems/lotus-controller-0.2.0/lib/lotus/action/redirect.rb:39: syntax error, unexpected keyword_end, expecting $end
from /home/james/.rvm/rubies/ruby-1.9.3-p448/lib/ruby/site_ruby/1.9.1/rubygems/custom_require.rb:36:in `require'

I assume that lotus only supports ruby 2.0 or greater? If so it should say in the documentation.

Register Lotus applications

The microservices architecture uses an anonymous Lotus::Router instance. Mounted applications aren't aware of the prefix that we assign in config.ru, this leads to wrong URL generation.

Example:

# config.ru
run Lotus::Router.new {
  mount Backend::Application, at: '/backend'
}

# code
Backend::Routes.path(:home) # => "/dashboard", but it should return "/backend/dashboard".

This double routing dispatch is inefficient: a request goes thru two instances of Router, one from config.ru, one from the application.

We can do introduce a new object like this:

# config.ru
run Lotus::Builder.new {
  mount Backend::Application, at: '/backend'
  mount Frontend::Application, at: '/'
}

It should:

  1. Pass to the single applications the :at prefix, so they are aware of the prefix configuration.
  2. Read all the routes from all the applications and try to compose a one-tier routing system (if possible).

Imagine the following scenario, where we have two applications with the following routes and controllers:

# apps/backend/application.rb
module Backend
  class Application < Lotus::Application
    configure do
      get '/dashboard', to: 'dashboard#index', as: :home # routes to Backend::Controllers::Dashboard::Index
    end
  end
end

# apps/frontend/application.rb
module Frontend
  class Application < Lotus::Application
    configure do
      get '/dashboard', to: 'dashboard#index', as: :home # routes to Frontend::Controllers::Dashboard::Index
    end
  end
end

With anoymous Lotus::Router:

                                                              /dashboard       +-------------------------------------------+
                                                                               |                                           |
                                                         +-------------------> |  Backend::Controllers::Dashboard::Index   |
                                    +-------------------++                     |                                           |
                                    |                   ||                     +-------------------------------------------+
                      /backend      |  Backend routes   ++                                                                  
+----------------+                  |                   |                                                                   
|                +----------------> +-------------------+                                                                   
|  Anonymous     |                                                                                                          
|  Router        |                                                                                                          
|                +----------------> +-------------------+                                                                   
+----------------+                  |                   |                                                                   
                      /             |  Frontend routes  ++                                                                  
                                    |                   ||                     +-------------------------------------------+
                                    +-------------------++                     |                                           |
                                                         +-------------------> |  Frontend::Controllers::Dashboard::Index  |
                                                                               |                                           |
                                                              /dashboard       +-------------------------------------------+

With registered applications (flatten routes)

                                            +-------------------------------------------+
                      /backend/dashboard    |                                           |
+----------------+                          |  Backend::Controllers::Dashboard::Index   |
|                +------------------------> |                                           |
|  Registered    |                          +-------------------------------------------+
|  Applications  |                                                                       
|                +------------------------> +-------------------------------------------+
+----------------+                          |                                           |
                      /dashboard            |  Frontend::Controllers::Dashboard::Index  |
                                            |                                           |
                                            +-------------------------------------------+

Support multiple environments

Let a Lotus application to change its behavior according to the current environment where it's running.

For instance, we can avoid to freeze the configuration (see #26) if we are running the application on a development machine. This ease to process of make it reloadable (see #24).

Another example, is the Rack middleware stack (see #27), to serve static files and use Rack::Lint isn't useful in production mode.

At the boot time we should look for a RACK_ENV or LOTUS_ENV env variable or default to "development".
We can add an optional argument to Lotus::Configuration#configure: env so that we can do.

# application.rb
module Bookshelf
  class Application < Lotus::Application
    configure do
      # ...
    end

    configure :development do
      # ...
    end

     configure 'config/environments/development' # see below
  end
end

# config/environments/development.rb
configure :development do # the environment here is mandatory
  # ...
end

Default templates path does not work well on Heroku

I think this issue can be marked as "wontfix", but it might be worth sharing.

The thing is that Heroku uses following paths to bootstrap the app:

  • /app โ€“ this is where the git repository is checked out
  • /app/vendor โ€“ this is where gems are installed

Default Lotus root path is /app, so when Lotus::View performs template search it also does that on a bunch of files located in /app/vendor which might contain test fixtures so wrong views are picked.

Important notes to reproduce are:

  • Lotus should be installed from source, since gem release does not contain any fixtures
  • App views should have the same names as fixtures have, e.g. home or something

However, possible solutions are, but I don't really satisfied with any of them:

  • Setting path app/templates if exists
  • Blacklisting some paths such as vendor
  • Encouraging people to set templates path manually

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.