lotusrb 0.0.0 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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