hanami / hanami Goto Github PK
View Code? Open in Web Editor NEWThe web, with simplicity.
Home Page: http://hanamirb.org
License: MIT License
The web, with simplicity.
Home Page: http://hanamirb.org
License: MIT License
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?
Hi Guys, I try the OneFile example, but when run rackup I get this error:
<class:Application>': undefined method
load!' for OneFile::Application:Class (NoMethodError)
When I removed the load! method and replace the module OneFile:: per global Lotus::, the code run without problems
Just made one for archlinux:
https://aur.archlinux.org/packages/ruby-lotusrb/
I made for other lotus frameworks too.
including:
ps: not sure if this is a right place to announce.
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 installedDefault 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:
home
or somethingHowever, possible solutions are, but I don't really satisfied with any of them:
vendor
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?
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>'
According to this announcement, Ruby 1.9.3 will reach EOL.
Lotus::Container
allows to define multiple Rack and Lotus applications in a single place.
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
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.
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
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:
Lotus::Application.configuration
)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" ]
Problem hanami/controller#64
This appears to be a problem that affects full stack applications and how they configure sessions. Thanks to @AlfonsoUceda for finding the root cause.
I know this isn't in the readme, but I think this should have a similar behaviour to rails new .
perhaps a default app_name should be used when app_name is '.'
Use shotgun
to achieve code reloading.
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
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.
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
.
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:
:at
prefix, so they are aware of the prefix configuration.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 |
| |
+-------------------------------------------+
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
.
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
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.
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?
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.
# 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
Since we allow a database mapping block to be yielded to the Configuration#mapping
method, this should be documented in the README.
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>'
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.
Rack implementation doesn't parse JSON requests by default.
# 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.
Provide a configuration for cookies.
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.
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
This should be part of Lotus::Configuration
.
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?
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?
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.
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
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
There is a simple setup to use with RSpec to have feature tests. The code is borrowed from rspec-rails
.
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)
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
)
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.
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?
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).
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.
module Bookshelf
class Application < ::Lotus::Application
configure do
sessions :redis,
domain: 'foo.com',
expire_after: 2592000
end
end
end
This should:
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'
.
When following the instructions in http://rdoc.info/gems/lotusrb for a single file app
On copying and pasting into the file I get:
ruby config.ru
config.ru:13:in <module:OneFile>': uninitialized constant OneFile::Controllers (NameError) from config.ru:4:in
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.
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?
Add logging utilities for each Lotus application. An idea on how to implement is to generate a Bookshelf::Logger
class for a Bookshelf::Application
.
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.
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?
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
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!
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.
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.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.