fastr 0.0.3 → 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.
- data/README.rdoc +182 -6
- data/bin/fastr +46 -10
- data/lib/fastr.rb +5 -0
- data/lib/fastr/application.rb +59 -152
- data/lib/fastr/async.rb +11 -0
- data/lib/fastr/controller.rb +67 -24
- data/lib/fastr/cookie.rb +37 -0
- data/lib/fastr/deferrable.rb +9 -9
- data/lib/fastr/dispatch.rb +151 -0
- data/lib/fastr/extensions/string.rb +8 -0
- data/lib/fastr/filter.rb +118 -11
- data/lib/fastr/http.rb +58 -0
- data/lib/fastr/plugin.rb +8 -8
- data/lib/fastr/router.rb +56 -7
- data/lib/fastr/settings.rb +9 -5
- data/lib/fastr/template.rb +83 -24
- data/lib/fastr/template/erubis.rb +23 -0
- data/lib/fastr/template/haml.rb +23 -0
- data/lib/fastr/test.rb +9 -0
- data/lib/fastr/test/application.rb +25 -0
- data/lib/fastr/test/controller.rb +78 -0
- data/lib/fastr/test/logger.rb +5 -0
- data/lib/fastr/test/tasks.rb +3 -0
- data/lib/fastr/test/tasks/test.rake +10 -0
- data/test/fastr_app/app/config/settings.rb +1 -0
- data/test/fastr_app/app/controllers/dispatch.rb +31 -0
- data/test/helper.rb +6 -4
- data/test/test_application.rb +13 -9
- data/test/test_cookie.rb +65 -0
- data/test/test_deferrable.rb +7 -7
- data/test/test_deferrable_response.rb +8 -8
- data/test/test_dispatch.rb +125 -0
- metadata +62 -11
- data/lib/fastr/session.rb +0 -5
- data/lib/fastr/session/cookie.rb +0 -0
data/lib/fastr/http.rb
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
module Fastr
|
2
|
+
module HTTP
|
3
|
+
|
4
|
+
# Parses the query string.
|
5
|
+
#
|
6
|
+
# @param qs [String]
|
7
|
+
# @return [Hash]
|
8
|
+
def self.parse_query_string(qs)
|
9
|
+
params = {}
|
10
|
+
return params if not qs
|
11
|
+
CGI::parse(qs).each do |k,v|
|
12
|
+
if v.length == 1
|
13
|
+
params[k] = v[0]
|
14
|
+
else
|
15
|
+
params[k] = v
|
16
|
+
end
|
17
|
+
end
|
18
|
+
return params
|
19
|
+
end
|
20
|
+
|
21
|
+
# Builds a query string of parameters.
|
22
|
+
#
|
23
|
+
# @param params [Hash] The parameters to put in the query string.
|
24
|
+
# @return [String] Query string with proper URL encoding for values.
|
25
|
+
def self.build_query_string(params)
|
26
|
+
qs = []
|
27
|
+
params.each do |k,v|
|
28
|
+
qs << "#{k}=#{CGI::escape(v)}"
|
29
|
+
end
|
30
|
+
qs.join('&')
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.method?(env, method)
|
34
|
+
return false if not env['REQUEST_METHOD']
|
35
|
+
return env['REQUEST_METHOD'].downcase.to_sym == method
|
36
|
+
end
|
37
|
+
|
38
|
+
# Parses the HTTP cookie.
|
39
|
+
#
|
40
|
+
# @param env [Hash]
|
41
|
+
# @return [Hash]
|
42
|
+
def self.parse_cookies(env)
|
43
|
+
if env.has_key? "HTTP_COOKIE"
|
44
|
+
cookies = env['HTTP_COOKIE'].split(';')
|
45
|
+
c = {}
|
46
|
+
cookies.each do |cookie|
|
47
|
+
info = cookie.strip.split("=")
|
48
|
+
if info.length == 2
|
49
|
+
c[info[0].strip] = info[1].strip
|
50
|
+
end
|
51
|
+
end
|
52
|
+
c
|
53
|
+
else
|
54
|
+
{}
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
data/lib/fastr/plugin.rb
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
module Fastr
|
2
2
|
module Plugin
|
3
3
|
include Fastr::Log
|
4
|
-
|
4
|
+
|
5
5
|
PLUGIN_PATH = "custom/plugins"
|
6
|
-
|
6
|
+
|
7
7
|
def self.load(app)
|
8
8
|
logger.debug "Loading plugins..."
|
9
9
|
|
@@ -11,7 +11,7 @@ module Fastr
|
|
11
11
|
load_plugins_dir(app)
|
12
12
|
end
|
13
13
|
end
|
14
|
-
|
14
|
+
|
15
15
|
def self.load_plugins_dir(app)
|
16
16
|
Dir.foreach("#{app.app_path}/#{PLUGIN_PATH}") do |filename|
|
17
17
|
if filename != '.' and filename != '..'
|
@@ -19,23 +19,23 @@ module Fastr
|
|
19
19
|
end
|
20
20
|
end
|
21
21
|
end
|
22
|
-
|
22
|
+
|
23
23
|
def self.load_plugin(app, name, dir)
|
24
24
|
plugin_name = "#{name.camelcase}Plugin"
|
25
25
|
logger.debug "Loading plugin #{plugin_name}..."
|
26
|
-
|
26
|
+
|
27
27
|
begin
|
28
28
|
require("#{dir}/plugin.rb")
|
29
29
|
m = Module.const_get(plugin_name)
|
30
|
-
|
30
|
+
|
31
31
|
if File.directory? "#{dir}/lib"
|
32
32
|
Dir.glob(File.join("#{dir}/lib/**", "*.rb")).each { |f| require("#{f}") }
|
33
33
|
end
|
34
|
-
|
34
|
+
|
35
35
|
app.plugins << m
|
36
36
|
rescue => e
|
37
37
|
logger.error "Unable to load plugin: #{e}"
|
38
38
|
end
|
39
39
|
end
|
40
40
|
end
|
41
|
-
end
|
41
|
+
end
|
data/lib/fastr/router.rb
CHANGED
@@ -1,8 +1,27 @@
|
|
1
1
|
module Fastr
|
2
|
+
# The router manages the routes for an application.
|
3
|
+
#
|
4
|
+
# Routes are configured in the <b>app/config/routes.rb</b> file.
|
5
|
+
#
|
6
|
+
# = Example
|
7
|
+
#
|
8
|
+
# router.draw do |route|
|
9
|
+
# route.for '/:controller/:action'
|
10
|
+
# route.for '/home/:action', :action => '[A-Za-z]+'
|
11
|
+
# route.for '/test', :to => 'home#index'
|
12
|
+
# end
|
13
|
+
#
|
14
|
+
# @author Chris Moos
|
2
15
|
class Router
|
3
16
|
include Fastr::Log
|
4
17
|
|
5
|
-
|
18
|
+
# The routes for this router.
|
19
|
+
# @return [Array]
|
20
|
+
attr_accessor :routes
|
21
|
+
|
22
|
+
# The full path to the routes file.
|
23
|
+
# @return [String]
|
24
|
+
attr_accessor :route_file
|
6
25
|
|
7
26
|
def initialize(app)
|
8
27
|
@app = app
|
@@ -11,8 +30,32 @@ module Fastr
|
|
11
30
|
setup_watcher
|
12
31
|
end
|
13
32
|
|
33
|
+
# Searches the routes for a match given a Rack env.
|
34
|
+
#
|
35
|
+
# {#match} looks in the {#routes} to find a match.
|
36
|
+
#
|
37
|
+
# This method looks at PATH_INFO in +env+ to get the current request's path.
|
38
|
+
#
|
39
|
+
# == Return
|
40
|
+
#
|
41
|
+
# No Match:
|
42
|
+
#
|
43
|
+
# {:error => :not_found}
|
44
|
+
#
|
45
|
+
# Match:
|
46
|
+
#
|
47
|
+
# {:ok => {:controller => 'controller', :action => 'action', :var => 'value'}}
|
48
|
+
#
|
49
|
+
# @param env [Hash]
|
50
|
+
# @return [Hash]
|
14
51
|
def match(env)
|
15
52
|
self.routes.each do |info|
|
53
|
+
|
54
|
+
# If the route didn't specify method(s) to limit by, then all HTTP methods are valid.
|
55
|
+
# If the route specified method(s), we check the request's HTTP method and validate
|
56
|
+
# that it exists in that list.
|
57
|
+
next unless info[:methods].nil? or info[:methods].include?(env["REQUEST_METHOD"].downcase.to_sym)
|
58
|
+
|
16
59
|
match = env['PATH_INFO'].match(info[:regex])
|
17
60
|
|
18
61
|
# See if a route matches
|
@@ -33,6 +76,7 @@ module Fastr
|
|
33
76
|
{:error => :not_found}
|
34
77
|
end
|
35
78
|
|
79
|
+
# Loads the routes from {#route_file} and evaluates it within the context of {Fastr::Router}.
|
36
80
|
def load
|
37
81
|
log.debug "Loading routes from: #{self.route_file}"
|
38
82
|
self.routes = []
|
@@ -41,24 +85,29 @@ module Fastr
|
|
41
85
|
@app.instance_eval(file.read)
|
42
86
|
end
|
43
87
|
|
88
|
+
# Adds a route for a path and arguments.
|
89
|
+
#
|
90
|
+
# @param path [String]
|
91
|
+
# @param args [Array]
|
44
92
|
def for(path, *args)
|
45
93
|
arg = args[0]
|
46
94
|
log.debug "Adding route, path: #{path}, args: #{args.inspect}"
|
47
95
|
|
48
96
|
match = get_regex_for_route(path, arg)
|
49
97
|
hash = get_to_hash(arg)
|
98
|
+
route_info = {:regex => match[:regex], :args => arg, :vars => match[:vars], :hash => hash}
|
50
99
|
|
51
|
-
|
100
|
+
# Add the HTTP methods for this route if they exist in options
|
101
|
+
route_info[:methods] = arg[:methods] if not arg.nil? and arg.has_key? :methods
|
102
|
+
|
103
|
+
self.routes.push(route_info)
|
52
104
|
end
|
53
105
|
|
106
|
+
# Evaluates the block in the context of the router.
|
54
107
|
def draw(&block)
|
55
108
|
block.call(self)
|
56
109
|
end
|
57
110
|
|
58
|
-
def file_modified
|
59
|
-
puts "changed!"
|
60
|
-
end
|
61
|
-
|
62
111
|
private
|
63
112
|
|
64
113
|
def get_to_hash(args)
|
@@ -84,7 +133,7 @@ module Fastr
|
|
84
133
|
if args.has_key? varName.to_sym
|
85
134
|
match = args[varName.to_sym]
|
86
135
|
end
|
87
|
-
regexRoute.gsub!(":#{
|
136
|
+
regexRoute.gsub!(":#{varName}", "(#{match.to_s})")
|
88
137
|
vars.push(varName.to_sym)
|
89
138
|
end
|
90
139
|
{:regex => "^#{regexRoute}$", :vars => vars}
|
data/lib/fastr/settings.rb
CHANGED
@@ -1,16 +1,20 @@
|
|
1
|
-
module Fastr
|
1
|
+
module Fastr
|
2
2
|
class Settings
|
3
3
|
include Fastr::Log
|
4
|
-
|
4
|
+
|
5
5
|
attr_accessor :cache_templates
|
6
|
-
|
6
|
+
|
7
7
|
def initialize(app)
|
8
8
|
@app = app
|
9
9
|
@cache_templates = true
|
10
10
|
end
|
11
|
-
|
11
|
+
|
12
12
|
def log_level=(level)
|
13
13
|
Fastr::Log.level = level
|
14
14
|
end
|
15
|
+
|
16
|
+
def plugins
|
17
|
+
@app.plugins
|
18
|
+
end
|
15
19
|
end
|
16
|
-
end
|
20
|
+
end
|
data/lib/fastr/template.rb
CHANGED
@@ -1,10 +1,9 @@
|
|
1
|
-
require 'haml'
|
2
1
|
require 'json'
|
3
2
|
|
4
3
|
module Fastr
|
5
4
|
module Template
|
6
|
-
|
7
|
-
|
5
|
+
EXTENSIONS = {} unless defined?(EXTENSIONS)
|
6
|
+
TEMPLATE_CACHE = {} unless defined?(TEMPLATE_CACHE)
|
8
7
|
|
9
8
|
def self.included(kls)
|
10
9
|
kls.extend(ClassMethods)
|
@@ -14,37 +13,97 @@ module Fastr
|
|
14
13
|
|
15
14
|
end
|
16
15
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
16
|
+
# Finds the engine for a particular path.
|
17
|
+
#
|
18
|
+
# ==== Parameters
|
19
|
+
# path<String>:: The path of the file to find an engine for.
|
20
|
+
#
|
21
|
+
# ==== Returns
|
22
|
+
# Class:: The engine.
|
23
|
+
def engine_for(path)
|
24
|
+
path = File.expand_path(path)
|
25
|
+
EXTENSIONS[path.match(/\.([^\.]*)$/)[1]]
|
24
26
|
end
|
25
27
|
|
26
|
-
|
27
|
-
|
28
|
+
# Get all known template extensions
|
29
|
+
#
|
30
|
+
# ==== Returns
|
31
|
+
# Array:: Extension strings.
|
32
|
+
def template_extensions
|
33
|
+
EXTENSIONS.keys
|
28
34
|
end
|
29
35
|
|
30
|
-
|
31
|
-
|
36
|
+
# Registers the extensions that will trigger a particular templating
|
37
|
+
# engine.
|
38
|
+
#
|
39
|
+
# ==== Parameters
|
40
|
+
# engine<Class>:: The class of the engine that is being registered
|
41
|
+
# extensions<Array[String]>::
|
42
|
+
# The list of extensions that will be registered with this templating
|
43
|
+
# language
|
44
|
+
#
|
45
|
+
# ==== Raises
|
46
|
+
# ArgumentError:: engine does not have a compile_template method.
|
47
|
+
#
|
48
|
+
# ==== Returns
|
49
|
+
# nil
|
50
|
+
#
|
51
|
+
# ==== Example
|
52
|
+
# Fastr::Template.register_extensions(Fastr::Template::Erubis, ["erb"])
|
53
|
+
def self.register_extensions(engine, extensions)
|
54
|
+
raise ArgumentError, "The class you are registering does not have a result method" unless
|
55
|
+
engine.respond_to?(:result)
|
56
|
+
extensions.each{|ext| EXTENSIONS[ext] = engine }
|
57
|
+
Fastr::Controller.class_eval <<-HERE
|
58
|
+
include #{engine}::Mixin
|
59
|
+
HERE
|
32
60
|
end
|
33
61
|
|
34
|
-
def
|
35
|
-
|
62
|
+
def render(kind, tpl, opts={})
|
63
|
+
# Read the cache template settings for this application, unless it is passed in
|
64
|
+
opts[:cache_template] = self.app.settings.cache_templates unless opts[:cache_template]
|
36
65
|
|
37
|
-
|
38
|
-
|
66
|
+
case kind.to_sym
|
67
|
+
when :template then
|
68
|
+
render_template(tpl, opts)
|
69
|
+
when :partial then
|
70
|
+
render_template_to_string(tpl, opts)
|
71
|
+
when :text then
|
72
|
+
render_text(tpl, opts)
|
73
|
+
when :json then
|
74
|
+
render_json(tpl, opts)
|
39
75
|
else
|
40
|
-
|
41
|
-
|
42
|
-
|
76
|
+
raise ArgumentError, "Unknown render type: #{kind.inspect}"
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def render_template(tpl_path, opts={})
|
81
|
+
self.headers['Content-Type'] = 'text/html'
|
82
|
+
@response_code = opts[:response_code] || 200
|
83
|
+
|
84
|
+
[ @response_code, @headers, [render_template_to_string(tpl_path, opts)] ]
|
85
|
+
end
|
86
|
+
|
87
|
+
def render_template_to_string(tpl_path, opts={})
|
88
|
+
unless engine = engine_for(tpl_path)
|
89
|
+
raise ArgumentError, "No template engine registered for #{tpl_path}"
|
43
90
|
end
|
44
|
-
|
45
|
-
resp = haml_engine.render(self)
|
46
91
|
|
47
|
-
[
|
92
|
+
@vars = opts[:vars] || {}
|
93
|
+
engine.result(tpl_path, binding(), opts[:cache_template])
|
94
|
+
end
|
95
|
+
|
96
|
+
def render_text(text, opts={})
|
97
|
+
self.headers['Content-Type'] = 'text/plain'
|
98
|
+
@response_code = opts[:response_code] || 200
|
99
|
+
[ @response_code, @headers, [text] ]
|
48
100
|
end
|
101
|
+
|
102
|
+
def render_json(obj, opts={})
|
103
|
+
self.headers['Content-Type'] = 'application/json'
|
104
|
+
@response_code = opts[:response_code] || 200
|
105
|
+
[ @response_code, @headers, [obj.to_json.to_s] ]
|
106
|
+
end
|
107
|
+
|
49
108
|
end
|
50
109
|
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'erubis'
|
2
|
+
|
3
|
+
module Fastr
|
4
|
+
module Template
|
5
|
+
class Erubis
|
6
|
+
|
7
|
+
def self.result(tpl_path, _binding, cache_template)
|
8
|
+
eruby = Fastr::Template::TEMPLATE_CACHE[tpl_path]
|
9
|
+
unless eruby and cache_template
|
10
|
+
eruby = ::Erubis::Eruby.new(File.read("app/views/#{tpl_path}"))
|
11
|
+
Fastr::Template::TEMPLATE_CACHE[tpl_path] = eruby
|
12
|
+
end
|
13
|
+
eruby.result(_binding)
|
14
|
+
end
|
15
|
+
|
16
|
+
module Mixin
|
17
|
+
end
|
18
|
+
|
19
|
+
Fastr::Template.register_extensions(self, %w[erb])
|
20
|
+
|
21
|
+
end # Erubis
|
22
|
+
end # Template
|
23
|
+
end # Fastr
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'haml'
|
2
|
+
|
3
|
+
module Fastr
|
4
|
+
module Template
|
5
|
+
class Haml
|
6
|
+
|
7
|
+
def self.result(tpl_path, _binding)
|
8
|
+
engine = Fastr::Template::TEMPLATE_CACHE[tpl_path]
|
9
|
+
unless engine and cache_template
|
10
|
+
engine = ::Haml::Engine.new(File.read("app/views/#{tpl_path}"))
|
11
|
+
Fastr::Template::TEMPLATE_CACHE[tpl_path] = engine
|
12
|
+
end
|
13
|
+
engine.render(_binding)
|
14
|
+
end
|
15
|
+
|
16
|
+
module Mixin
|
17
|
+
end
|
18
|
+
|
19
|
+
Fastr::Template.register_extensions(self, %w[haml])
|
20
|
+
|
21
|
+
end # Haml
|
22
|
+
end # Template
|
23
|
+
end # Fastr
|
data/lib/fastr/test.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
module Fastr
|
2
|
+
module Test
|
3
|
+
class Application < Fastr::Application
|
4
|
+
include Fastr::Log
|
5
|
+
|
6
|
+
attr_accessor :route
|
7
|
+
|
8
|
+
def boot
|
9
|
+
load_settings
|
10
|
+
Fastr::Plugin.load(self)
|
11
|
+
load_app_classes
|
12
|
+
setup_router
|
13
|
+
|
14
|
+
@booting = false
|
15
|
+
|
16
|
+
plugin_after_boot
|
17
|
+
app_init
|
18
|
+
end
|
19
|
+
|
20
|
+
def dispatch_controller(route, env)
|
21
|
+
super(self.route, env)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|