lotusrb 0.0.0 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
@@ -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
@@ -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,9 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title><%= title %></title>
5
+ </head>
6
+ <body>
7
+ <h1><%= title %></h1>
8
+ </body>
9
+ </html>
@@ -0,0 +1,6 @@
1
+ module Lotus
2
+ # Defines the version
3
+ #
4
+ # @since 0.1.0
5
+ VERSION = '0.1.0'.freeze
6
+ 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
@@ -0,0 +1,17 @@
1
+ module Lotus
2
+ module Views
3
+ # Null Object pattern for views
4
+ #
5
+ # @since 0.1.0
6
+ # @api private
7
+ class NullView
8
+ def initialize(body)
9
+ @body = body
10
+ end
11
+
12
+ def render(context)
13
+ @body
14
+ end
15
+ end
16
+ end
17
+ end
data/lib/lotusrb.rb CHANGED
@@ -1,5 +1 @@
1
- require "lotusrb/version"
2
-
3
- module Lotusrb
4
- # Your code goes here...
5
- end
1
+ require_relative 'lotus'
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 'lotusrb/version'
4
+ require 'lotus/version'
5
5
 
6
6
  Gem::Specification.new do |spec|
7
- spec.name = "lotusrb"
8
- spec.version = Lotusrb::VERSION
9
- spec.authors = ["Luca Guidi"]
10
- spec.email = ["me@lucaguidi.com"]
11
- spec.summary = %q{Full stack web framework for Ruby}
12
- spec.description = %q{Full stack web framework for Ruby}
13
- spec.homepage = ""
14
- spec.license = "MIT"
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|spec|features)/})
19
- spec.require_paths = ["lib"]
18
+ spec.test_files = spec.files.grep(%r{^(test)/})
19
+ spec.require_paths = ['lib']
20
20
 
21
- spec.add_development_dependency "bundler", "~> 1.5"
22
- spec.add_development_dependency "rake"
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