lotusrb 0.0.0 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/{LICENSE.txt → LICENSE.md} +0 -0
- data/README.md +436 -8
- data/lib/lotus.rb +10 -0
- data/lib/lotus/application.rb +121 -0
- data/lib/lotus/config/assets.rb +29 -0
- data/lib/lotus/config/load_paths.rb +27 -0
- data/lib/lotus/config/mapper.rb +36 -0
- data/lib/lotus/config/mapping.rb +12 -0
- data/lib/lotus/config/routes.rb +16 -0
- data/lib/lotus/configuration.rb +961 -0
- data/lib/lotus/frameworks.rb +40 -0
- data/lib/lotus/loader.rb +92 -0
- data/lib/lotus/middleware.rb +42 -0
- data/lib/lotus/rendering_policy.rb +69 -0
- data/lib/lotus/routes.rb +95 -0
- data/lib/lotus/routing/default.rb +25 -0
- data/lib/lotus/templates/default.html.erb +9 -0
- data/lib/lotus/version.rb +6 -0
- data/lib/lotus/views/default.rb +20 -0
- data/lib/lotus/views/null_view.rb +17 -0
- data/lib/lotusrb.rb +1 -5
- data/lotusrb.gemspec +21 -14
- metadata +126 -21
- data/.gitignore +0 -17
- data/Gemfile +0 -4
- data/Rakefile +0 -1
- data/lib/lotusrb/version.rb +0 -3
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'lotus/router'
|
2
|
+
require 'lotus/controller'
|
3
|
+
require 'lotus/view'
|
4
|
+
|
5
|
+
# FIXME Ideally, this should be done like this:
|
6
|
+
#
|
7
|
+
# module Lotus
|
8
|
+
# module Frameworks
|
9
|
+
# module Action
|
10
|
+
# module Rack
|
11
|
+
# protected
|
12
|
+
# def response
|
13
|
+
# [super, self].flatten
|
14
|
+
# end
|
15
|
+
# end
|
16
|
+
# end
|
17
|
+
# end
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# Lotus::Action::Rack.class_eval do
|
21
|
+
# include Lotus::Frameworks::Action::Rack
|
22
|
+
# end
|
23
|
+
#
|
24
|
+
# ..but it doesn't work and I want to ship it!
|
25
|
+
|
26
|
+
Lotus::Action::Rack.class_eval do
|
27
|
+
DEFAULT_RESPONSE_CODE = 200
|
28
|
+
DEFAULT_RESPONSE_BODY = []
|
29
|
+
|
30
|
+
protected
|
31
|
+
def response
|
32
|
+
[ @_status || DEFAULT_RESPONSE_CODE, headers, @_body || DEFAULT_RESPONSE_BODY.dup, self ]
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
Lotus::Action.class_eval do
|
37
|
+
def to_rendering
|
38
|
+
exposures.merge(format: format)
|
39
|
+
end
|
40
|
+
end
|
data/lib/lotus/loader.rb
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
require 'lotus/utils/class'
|
2
|
+
require 'lotus/utils/kernel'
|
3
|
+
require 'lotus/utils/string'
|
4
|
+
require 'lotus/routes'
|
5
|
+
require 'lotus/routing/default'
|
6
|
+
|
7
|
+
module Lotus
|
8
|
+
# Load an application
|
9
|
+
#
|
10
|
+
# @since 0.1.0
|
11
|
+
# @api private
|
12
|
+
class Loader
|
13
|
+
def initialize(application)
|
14
|
+
@application = application
|
15
|
+
@configuration = @application.configuration
|
16
|
+
|
17
|
+
@mutex = Mutex.new
|
18
|
+
end
|
19
|
+
|
20
|
+
def load!
|
21
|
+
@mutex.synchronize do
|
22
|
+
load_configuration!
|
23
|
+
load_frameworks!
|
24
|
+
load_application!
|
25
|
+
finalize!
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
attr_reader :application, :configuration
|
31
|
+
|
32
|
+
def load_configuration!
|
33
|
+
configuration.load!(application_module)
|
34
|
+
end
|
35
|
+
|
36
|
+
def load_frameworks!
|
37
|
+
config = configuration
|
38
|
+
|
39
|
+
unless application_module.const_defined?('Controller')
|
40
|
+
controller = Lotus::Controller.duplicate(application_module) do
|
41
|
+
default_format config.default_format
|
42
|
+
end
|
43
|
+
|
44
|
+
application_module.const_set('Controller', controller)
|
45
|
+
end
|
46
|
+
|
47
|
+
unless application_module.const_defined?('View')
|
48
|
+
view = Lotus::View.duplicate(application_module) do
|
49
|
+
root config.templates
|
50
|
+
layout config.layout
|
51
|
+
end
|
52
|
+
|
53
|
+
application_module.const_set('View', view)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def load_application!
|
58
|
+
configuration.load_paths.load!(configuration.root)
|
59
|
+
namespace = configuration.namespace || application_module
|
60
|
+
|
61
|
+
resolver = Lotus::Routing::EndpointResolver.new(pattern: configuration.controller_pattern, namespace: namespace)
|
62
|
+
default_app = Lotus::Routing::Default.new
|
63
|
+
application.routes = Lotus::Router.new(
|
64
|
+
resolver: resolver,
|
65
|
+
default_app: default_app,
|
66
|
+
scheme: configuration.scheme,
|
67
|
+
host: configuration.host,
|
68
|
+
port: configuration.port,
|
69
|
+
&configuration.routes
|
70
|
+
)
|
71
|
+
|
72
|
+
application.middleware # preload
|
73
|
+
end
|
74
|
+
|
75
|
+
def finalize!
|
76
|
+
unless application_module.const_defined?('Routes')
|
77
|
+
routes = Lotus::Routes.new(application.routes)
|
78
|
+
application_module.const_set('Routes', routes)
|
79
|
+
end
|
80
|
+
|
81
|
+
application_module.module_eval %{
|
82
|
+
#{ application_module }::View.load!
|
83
|
+
}
|
84
|
+
end
|
85
|
+
|
86
|
+
def application_module
|
87
|
+
@application_module ||= Utils::Class.load!(
|
88
|
+
Utils::String.new(application.class).namespace
|
89
|
+
)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Lotus
|
2
|
+
# Rack middleware stack for an application
|
3
|
+
#
|
4
|
+
# @since 0.1.0
|
5
|
+
# @api private
|
6
|
+
class Middleware
|
7
|
+
# Instantiate a middleware stack
|
8
|
+
#
|
9
|
+
# @param application [Lotus::Application] the application
|
10
|
+
#
|
11
|
+
# @return [Lotus::Middleware] the new stack
|
12
|
+
#
|
13
|
+
# @since 0.1.0
|
14
|
+
# @api private
|
15
|
+
#
|
16
|
+
# @see Lotus::Configuration
|
17
|
+
# @see http://rdoc.info/gems/rack/Rack/Builder
|
18
|
+
def initialize(application)
|
19
|
+
configuration = application.configuration
|
20
|
+
routes = application.routes
|
21
|
+
|
22
|
+
@builder = ::Rack::Builder.new
|
23
|
+
@builder.use Rack::Static,
|
24
|
+
urls: configuration.assets.entries,
|
25
|
+
root: configuration.assets
|
26
|
+
@builder.run routes
|
27
|
+
end
|
28
|
+
|
29
|
+
# Process a request.
|
30
|
+
# This method makes the middleware stack compatible with the Rack protocol.
|
31
|
+
#
|
32
|
+
# @param env [Hash] a Rack env
|
33
|
+
#
|
34
|
+
# @return [Array] a serialized Rack response
|
35
|
+
#
|
36
|
+
# @since 0.1.0
|
37
|
+
# @api private
|
38
|
+
def call(env)
|
39
|
+
@builder.call(env)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'lotus/utils/class'
|
2
|
+
require 'lotus/views/default'
|
3
|
+
require 'lotus/views/null_view'
|
4
|
+
|
5
|
+
module Lotus
|
6
|
+
# Rendering policy
|
7
|
+
#
|
8
|
+
# @since 0.1.0
|
9
|
+
# @api private
|
10
|
+
class RenderingPolicy
|
11
|
+
STATUS = 0
|
12
|
+
HEADERS = 1
|
13
|
+
BODY = 2
|
14
|
+
|
15
|
+
RACK_RESPONSE_SIZE = 3
|
16
|
+
|
17
|
+
SUCCESSFUL_STATUSES = (200..201).freeze
|
18
|
+
STATUSES_WITHOUT_BODY = Set.new((100..199).to_a << 204 << 205 << 301 << 302 << 304).freeze
|
19
|
+
RENDERABLE_FORMATS = [:all, :html].freeze
|
20
|
+
CONTENT_TYPE = 'Content-Type'.freeze
|
21
|
+
|
22
|
+
def initialize(configuration)
|
23
|
+
@controller_pattern = %r{#{ configuration.controller_pattern.gsub(/\%\{(controller|action)\}/) { "(?<#{ $1 }>(.*))" } }}
|
24
|
+
@view_pattern = configuration.view_pattern
|
25
|
+
@namespace = configuration.namespace
|
26
|
+
end
|
27
|
+
|
28
|
+
def render(response)
|
29
|
+
if renderable?(response)
|
30
|
+
action = response.pop
|
31
|
+
|
32
|
+
body = if successful?(response)
|
33
|
+
view_for(response, action).render(
|
34
|
+
action.to_rendering
|
35
|
+
)
|
36
|
+
else
|
37
|
+
if render_status_page?(response, action)
|
38
|
+
Lotus::Views::Default.render(response: response, format: :html)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
response[BODY] = Array(body) if body
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
def renderable?(response)
|
48
|
+
response.size > RACK_RESPONSE_SIZE
|
49
|
+
end
|
50
|
+
|
51
|
+
def successful?(response)
|
52
|
+
SUCCESSFUL_STATUSES.include?(response[STATUS])
|
53
|
+
end
|
54
|
+
|
55
|
+
def render_status_page?(response, action)
|
56
|
+
RENDERABLE_FORMATS.include?(action.format) &&
|
57
|
+
!STATUSES_WITHOUT_BODY.include?(response[STATUS])
|
58
|
+
end
|
59
|
+
|
60
|
+
def view_for(response, action)
|
61
|
+
if response[BODY].empty?
|
62
|
+
captures = @controller_pattern.match(action.class.name)
|
63
|
+
Utils::Class.load!(@view_pattern % { controller: captures[:controller], action: captures[:action] }, @namespace)
|
64
|
+
else
|
65
|
+
Views::NullView.new(response[BODY])
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
data/lib/lotus/routes.rb
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
module Lotus
|
2
|
+
# Routes factory
|
3
|
+
#
|
4
|
+
# A Lotus application has this factory instantiated by default and associated
|
5
|
+
# to the `Routes` constant, under the application namespace.
|
6
|
+
#
|
7
|
+
# @since 0.1.0
|
8
|
+
class Routes
|
9
|
+
# Initialize the factory
|
10
|
+
#
|
11
|
+
# @param routes [Lotus::Router] a routes set
|
12
|
+
#
|
13
|
+
# @return [Lotus::Routes] the factory
|
14
|
+
#
|
15
|
+
# @since 0.1.0
|
16
|
+
def initialize(routes)
|
17
|
+
@routes = routes
|
18
|
+
end
|
19
|
+
|
20
|
+
# Return a relative path for the given route name
|
21
|
+
#
|
22
|
+
# @param name [Symbol] the route name
|
23
|
+
# @param args [Array,nil] an optional set of arguments that is passed down
|
24
|
+
# to the wrapped route set.
|
25
|
+
#
|
26
|
+
# @return [String] the corresponding relative URL
|
27
|
+
#
|
28
|
+
# @raise Lotus::Routing::InvalidRouteException
|
29
|
+
#
|
30
|
+
# @since 0.1.0
|
31
|
+
#
|
32
|
+
# @see http://rdoc.info/gems/lotus-router/Lotus/Router#path-instance_method
|
33
|
+
#
|
34
|
+
# @example
|
35
|
+
# require 'lotus'
|
36
|
+
#
|
37
|
+
# module Bookshelf
|
38
|
+
# class Application < Lotus::Application
|
39
|
+
# configure do
|
40
|
+
# routes do
|
41
|
+
# get '/login', to: 'sessions#new', as: :login
|
42
|
+
# end
|
43
|
+
# end
|
44
|
+
# end
|
45
|
+
# end
|
46
|
+
#
|
47
|
+
# Bookshelf::Routes.path(:login)
|
48
|
+
# # => '/login'
|
49
|
+
#
|
50
|
+
# Bookshelf::Routes.path(:login, return_to: '/dashboard')
|
51
|
+
# # => '/login?return_to=%2Fdashboard'
|
52
|
+
def path(name, *args)
|
53
|
+
@routes.path(name, *args)
|
54
|
+
end
|
55
|
+
|
56
|
+
# Return an absolute path for the given route name
|
57
|
+
#
|
58
|
+
# @param name [Symbol] the route name
|
59
|
+
# @param args [Array,nil] an optional set of arguments that is passed down
|
60
|
+
# to the wrapped route set.
|
61
|
+
#
|
62
|
+
# @return [String] the corresponding absolute URL
|
63
|
+
#
|
64
|
+
# @raise Lotus::Routing::InvalidRouteException
|
65
|
+
#
|
66
|
+
# @since 0.1.0
|
67
|
+
#
|
68
|
+
# @see http://rdoc.info/gems/lotus-router/Lotus/Router#url-instance_method
|
69
|
+
#
|
70
|
+
# @example
|
71
|
+
# require 'lotus'
|
72
|
+
#
|
73
|
+
# module Bookshelf
|
74
|
+
# class Application < Lotus::Application
|
75
|
+
# configure do
|
76
|
+
# routes do
|
77
|
+
# scheme 'https'
|
78
|
+
# host 'bookshelf.org'
|
79
|
+
#
|
80
|
+
# get '/login', to: 'sessions#new', as: :login
|
81
|
+
# end
|
82
|
+
# end
|
83
|
+
# end
|
84
|
+
# end
|
85
|
+
#
|
86
|
+
# Bookshelf::Routes.url(:login)
|
87
|
+
# # => 'https://bookshelf.org/login'
|
88
|
+
#
|
89
|
+
# Bookshelf::Routes.url(:login, return_to: '/dashboard')
|
90
|
+
# # => 'https://bookshelf.org/login?return_to=%2Fdashboard'
|
91
|
+
def url(name, *args)
|
92
|
+
@routes.url(name, *args)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Lotus
|
2
|
+
module Routing
|
3
|
+
# The default Rack application that responds when a resource cannot be found.
|
4
|
+
#
|
5
|
+
# @since 0.1.0
|
6
|
+
# @api private
|
7
|
+
class Default
|
8
|
+
DEFAULT_CODE = 404
|
9
|
+
DEFAULT_BODY = ['Not Found'].freeze
|
10
|
+
CONTENT_TYPE = 'Content-Type'.freeze
|
11
|
+
|
12
|
+
class NullAction
|
13
|
+
include Lotus::Action
|
14
|
+
|
15
|
+
def call(env)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def call(env)
|
20
|
+
action = NullAction.new.tap {|a| a.call(env) }
|
21
|
+
[ DEFAULT_CODE, {CONTENT_TYPE => action.content_type}, DEFAULT_BODY, action ]
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Lotus
|
2
|
+
module Views
|
3
|
+
# The default view that is rendered for non successful responses (200 and 201)
|
4
|
+
#
|
5
|
+
# @since 0.1.0
|
6
|
+
# @api private
|
7
|
+
class Default
|
8
|
+
include Lotus::View
|
9
|
+
configuration.reset!
|
10
|
+
|
11
|
+
layout nil
|
12
|
+
root Pathname.new(File.dirname(__FILE__)).join('../templates').realpath
|
13
|
+
template 'default'
|
14
|
+
|
15
|
+
def title
|
16
|
+
response[2].first
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
data/lib/lotusrb.rb
CHANGED
data/lotusrb.gemspec
CHANGED
@@ -1,23 +1,30 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
lib = File.expand_path('../lib', __FILE__)
|
3
3
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
-
require '
|
4
|
+
require 'lotus/version'
|
5
5
|
|
6
6
|
Gem::Specification.new do |spec|
|
7
|
-
spec.name =
|
8
|
-
spec.version =
|
9
|
-
spec.authors = [
|
10
|
-
spec.email = [
|
11
|
-
spec.summary = %q{
|
12
|
-
spec.description = %q{
|
13
|
-
spec.homepage =
|
14
|
-
spec.license =
|
7
|
+
spec.name = 'lotusrb'
|
8
|
+
spec.version = Lotus::VERSION
|
9
|
+
spec.authors = ['Luca Guidi']
|
10
|
+
spec.email = ['me@lucaguidi.com']
|
11
|
+
spec.summary = %q{A complete web framework for Ruby}
|
12
|
+
spec.description = %q{A complete web framework for Ruby}
|
13
|
+
spec.homepage = 'http://lotusrb.org'
|
14
|
+
spec.license = 'MIT'
|
15
15
|
|
16
|
-
spec.files = `git ls-files`.split(
|
16
|
+
spec.files = `git ls-files -z -- lib/* LICENSE.md README.md lotusrb.gemspec`.split("\x0")
|
17
17
|
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
-
spec.test_files = spec.files.grep(%r{^(test
|
19
|
-
spec.require_paths = [
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test)/})
|
19
|
+
spec.require_paths = ['lib']
|
20
20
|
|
21
|
-
spec.
|
22
|
-
spec.
|
21
|
+
spec.add_dependency 'lotus-utils', '~> 0.2'
|
22
|
+
spec.add_dependency 'lotus-router', '~> 0.1', '>= 0.1.1'
|
23
|
+
spec.add_dependency 'lotus-controller', '~> 0.2'
|
24
|
+
spec.add_dependency 'lotus-view', '~> 0.2'
|
25
|
+
|
26
|
+
spec.add_development_dependency 'bundler', '~> 1.6'
|
27
|
+
spec.add_development_dependency 'rake', '~> 10'
|
28
|
+
spec.add_development_dependency 'minitest', '~> 5'
|
29
|
+
spec.add_development_dependency 'rack-test', '~> 0.6'
|
23
30
|
end
|