fastr 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Chris Moos
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,17 @@
1
+ = fastr
2
+
3
+ Description goes here.
4
+
5
+ == Note on Patches/Pull Requests
6
+
7
+ * Fork the project.
8
+ * Make your feature addition or bug fix.
9
+ * Add tests for it. This is important so I don't break it in a
10
+ future version unintentionally.
11
+ * Commit, do not mess with rakefile, version, or history.
12
+ (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
13
+ * Send me a pull request. Bonus points for topic branches.
14
+
15
+ == Copyright
16
+
17
+ Copyright (c) 2010 Chris Moos. See LICENSE for details.
data/bin/fastr ADDED
@@ -0,0 +1,96 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'fileutils'
4
+
5
+ if ARGV.size == 0
6
+ Fastr.usage
7
+ exit(0)
8
+ end
9
+
10
+ module Fastr
11
+ def self.init_app(app_name)
12
+ if File.directory? app_name
13
+ puts "directory already exists"
14
+ exit(0)
15
+ end
16
+
17
+ # Directory Structre
18
+
19
+ dirs = ['app/config', 'app/controllers', 'app/views', 'app/models', 'lib', 'test']
20
+ dirs.each do |dir|
21
+ FileUtils.mkdir_p("#{app_name}/#{dir}")
22
+ end
23
+
24
+ # Default Routes
25
+ File.open("#{app_name}/app/config/routes.rb", "w") do |f|
26
+ f.write("router.draw do |route|\n")
27
+ f.write("\troute.for '/:controller/:action'\n")
28
+ f.write("\t#route.for '/home/:action', :action => '[A-Za-z]+'\n")
29
+ f.write("\t#route.for '/test', :to => 'home#index'\n")
30
+ f.write("end")
31
+ f.close
32
+ end
33
+
34
+ # Rack file
35
+ File.open("#{app_name}/config.ru", "w") do |f|
36
+ f.puts("require 'fastr'")
37
+ f.puts("EM.kqueue = true # OS X")
38
+ f.puts("fastrApp = Fastr::Application.new(File.expand_path(File.dirname(__FILE__)))")
39
+ f.puts("app = lambda { |env|")
40
+ f.puts("\tfastrApp.dispatch(env)")
41
+ f.puts("}")
42
+ f.puts("run app")
43
+ f.close
44
+ end
45
+
46
+ # Gemfile
47
+ File.open("#{app_name}/Gemfile", 'a') do |f|
48
+ f.puts "source :gemcutter"
49
+
50
+ f.puts "gem 'jeweler'"
51
+ f.puts "gem 'eventmachine'"
52
+ f.puts "gem 'haml'"
53
+ f.puts "\ngem 'fastr'"
54
+ f.close
55
+ end
56
+
57
+ puts "#{app_name} initialized!"
58
+ end
59
+
60
+ def self.usage
61
+ puts "Initialize a fastr application."
62
+ puts "Usage: fastr [init name] [generate controller name]"
63
+ end
64
+ end
65
+
66
+ command = ARGV[0]
67
+
68
+ if command == 'init' and ARGV.length == 2
69
+ Fastr.init_app(ARGV[1])
70
+ elsif command == 'generate' and ARGV.length > 2
71
+ what = ARGV[1]
72
+ if what == 'controller' and ARGV.length == 3
73
+ name = ARGV[2]
74
+ path = "app/controllers/#{name}_controller.rb"
75
+ if File.exists? path
76
+ puts "Controller already exists."
77
+ exit(0)
78
+ end
79
+
80
+ puts "Creating controller: #{path}"
81
+ File.open(path, "w") do |f|
82
+ f.puts("class #{name.capitalize}Controller < Fastr::Controller")
83
+ f.puts("end")
84
+ f.close
85
+ end
86
+ else
87
+ puts "unknown generator: #{what}"
88
+ Fastr usage
89
+ end
90
+ else
91
+ puts "Unknown command: #{command}"
92
+ Fastr.usage
93
+ end
94
+
95
+
96
+
@@ -0,0 +1,112 @@
1
+ require 'logger'
2
+
3
+ module Fastr
4
+ class Application
5
+ include Fastr::Log
6
+
7
+ attr_accessor :router, :app_path
8
+
9
+ def initialize(path)
10
+ self.app_path = path
11
+
12
+ @booting = true
13
+ boot
14
+ end
15
+
16
+ def dispatch(env)
17
+ return [500, {}, "Server Not Ready"] if @booting
18
+
19
+ begin
20
+ do_dispatch(env)
21
+ rescue Exception => e
22
+ bt = e.backtrace.join("\n")
23
+ [500, {}, "Exception: #{e}\n\n#{bt}"]
24
+ end
25
+ end
26
+
27
+ def do_dispatch(env)
28
+ path = env['PATH_INFO']
29
+
30
+ log.debug "Checking for routes that match: #{path}"
31
+ route = router.match(env)
32
+
33
+ if route.has_key? :ok
34
+ vars = route[:ok]
35
+ controller = vars[:controller]
36
+ action = vars[:action]
37
+
38
+ raise Fastr::Error.new("Controller and action not present in route") if controller.nil? or action.nil?
39
+
40
+
41
+ klass = "#{controller.capitalize}Controller"
42
+
43
+ log.info "Routing to controller: #{klass}, action: #{action}"
44
+
45
+ obj = Module.const_get(klass).new
46
+
47
+ ret = obj.send(action)
48
+
49
+ #[200, {}, "ok"]
50
+ ret
51
+ else
52
+ [404, {"Content-Type" => "text/plain"}, "404 Not Found: #{path}"]
53
+ end
54
+ end
55
+
56
+ private
57
+
58
+ #
59
+ # This is used to initialize the application.
60
+ # It runs in a thread because startup depends on EventMachine running
61
+ #
62
+ def boot
63
+ Thread.new do
64
+ sleep 1 until EM.reactor_running?
65
+
66
+ begin
67
+ load_app_classes
68
+ setup_router
69
+ setup_watcher
70
+
71
+ @booting = false
72
+ rescue Exception => e
73
+ log.error "#{e}"
74
+ puts e.backtrace
75
+ log.fatal "Exiting due to previous errors..."
76
+ exit(1)
77
+ end
78
+ end
79
+ end
80
+
81
+ def setup_router
82
+ self.router = Fastr::Router.new(self)
83
+ self.router.load
84
+ end
85
+
86
+ def load_app_classes
87
+ log.debug "Loading application classes..."
88
+ Dir["#{self.app_path}/app/controllers/*.rb"].each do |f|
89
+ log.debug "Loading: #{f}"
90
+ load(f)
91
+ end
92
+ end
93
+
94
+ def setup_watcher
95
+ this = self
96
+ Handler.send(:define_method, :app) do
97
+ this
98
+ end
99
+
100
+ Dir["#{self.app_path}/app/controllers/*.rb"].each do |f|
101
+ EM.watch_file(f, Handler)
102
+ end
103
+ end
104
+
105
+ module Handler
106
+ def file_modified
107
+ app.log.info "Reloading file: #{path}"
108
+ load(path)
109
+ end
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,6 @@
1
+ module Fastr
2
+ class Controller
3
+ include Fastr::Template
4
+
5
+ end
6
+ end
@@ -0,0 +1,3 @@
1
+ module Fastr
2
+ class Error < Exception; end
3
+ end
@@ -0,0 +1,27 @@
1
+ require 'logger'
2
+
3
+ module Fastr
4
+ module Log
5
+ def self.included(kls)
6
+ logger = Logger.new(STDOUT)
7
+ logger.level = Logger::DEBUG
8
+ logger.formatter = Fastr::Log::Formatter.new(kls)
9
+ define_method :log do
10
+ logger
11
+ end
12
+ end
13
+
14
+ class Formatter < Logger::Formatter
15
+ attr_accessor :progname
16
+
17
+ def initialize(name)
18
+ self.progname = name
19
+ end
20
+
21
+
22
+ def call(severity, time, progname, msg)
23
+ puts "[#{severity}] [#{self.progname}]: #{msg}"
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,109 @@
1
+ module Fastr
2
+ class Router
3
+ include Fastr::Log
4
+
5
+ attr_accessor :routes, :route_file
6
+
7
+ def initialize(app)
8
+ @app = app
9
+ self.routes = []
10
+ self.route_file = "#{@app.app_path}/app/config/routes.rb"
11
+ setup_watcher
12
+ end
13
+
14
+ def match(env)
15
+ self.routes.each do |info|
16
+ match = env['PATH_INFO'].match(info[:regex])
17
+
18
+ # See if a route matches
19
+ if not match.nil?
20
+
21
+ # Map any parameters in our matched string
22
+ vars = {}
23
+
24
+ info[:vars].each_index do |i|
25
+ var = info[:vars][i]
26
+ vars[var] = match[i+1]
27
+ end
28
+
29
+ return {:ok => vars.merge!(info[:hash]) }
30
+ end
31
+ end
32
+
33
+ {:error => :not_found}
34
+ end
35
+
36
+ def load
37
+ log.debug "Loading routes from: #{self.route_file}"
38
+ self.routes = []
39
+
40
+ file = File.open(self.route_file)
41
+ @app.instance_eval(file.read)
42
+ end
43
+
44
+ def for(path, *args)
45
+ arg = args[0]
46
+ log.debug "Adding route, path: #{path}, args: #{args.inspect}"
47
+
48
+ match = get_regex_for_route(path, arg)
49
+ hash = get_to_hash(arg)
50
+
51
+ self.routes.push({:regex => match[:regex], :args => arg, :vars => match[:vars], :hash => hash})
52
+ end
53
+
54
+ def draw(&block)
55
+ block.call(self)
56
+ end
57
+
58
+ def file_modified
59
+ puts "changed!"
60
+ end
61
+
62
+ private
63
+
64
+ def get_to_hash(args)
65
+ hash = {}
66
+ return hash if args.nil?
67
+ if args.has_key? :to
68
+ match = args[:to].match(/(\w+)#(\w+)/)
69
+ hash.merge!(:controller => match[1], :action => match[2]) if not match.nil?
70
+ end
71
+ hash
72
+ end
73
+
74
+ def get_regex_for_route(path, args)
75
+ vars = []
76
+ regexRoute = path
77
+
78
+ args = {} if args.nil?
79
+
80
+ path.scan(/:(\w+)/).each do |var|
81
+ match = '\w+'
82
+ varName = var[0]
83
+
84
+ if args.has_key? varName.to_sym
85
+ match = args[varName.to_sym]
86
+ end
87
+ regexRoute.gsub!(":#{var}", "(#{match.to_s})")
88
+ vars.push(varName.to_sym)
89
+ end
90
+ {:regex => "^#{regexRoute}$", :vars => vars}
91
+ end
92
+
93
+ def setup_watcher
94
+ this = self
95
+ Handler.send(:define_method, :router) do
96
+ this
97
+ end
98
+
99
+ EM.watch_file(self.route_file, Handler)
100
+ end
101
+
102
+ module Handler
103
+ def file_modified
104
+ router.log.info "Routes changed, reloading."
105
+ router.load
106
+ end
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,46 @@
1
+ require 'haml'
2
+
3
+ module Fastr
4
+ module Template
5
+ @@tpl_cache = {}
6
+
7
+
8
+ def self.included(kls)
9
+ kls.extend(ClassMethods)
10
+ end
11
+
12
+ module ClassMethods
13
+
14
+ end
15
+
16
+ def render(type, *args)
17
+ method = "render_#{type}".to_sym
18
+ if self.respond_to? method
19
+ self.send(method, args)
20
+ else
21
+ raise Exception.new("No render found for: #{type}")
22
+ end
23
+ end
24
+
25
+ def render_text(txt)
26
+ [200, {"Content-Type" => 'text/plain'}, txt]
27
+ end
28
+
29
+ def render_haml(args)
30
+ tpl = args[0][:template]
31
+
32
+ if @@tpl_cache.has_key? tpl
33
+ haml_engine = @@tpl_cache[tpl]
34
+ else
35
+ tpl_data = File.read("app/views/#{tpl}.haml")
36
+ haml_engine = Haml::Engine.new(tpl_data)
37
+ @@tpl_cache[tpl] = haml_engine
38
+ end
39
+
40
+
41
+ resp = haml_engine.render
42
+
43
+ [200, {"Content-Type" => "text/html"}, resp]
44
+ end
45
+ end
46
+ end
data/lib/fastr.rb ADDED
@@ -0,0 +1,10 @@
1
+ module Fastr
2
+ ROOT = File.expand_path(File.dirname(__FILE__))
3
+
4
+ autoload :Application, "#{ROOT}/fastr/application"
5
+ autoload :Log, "#{ROOT}/fastr/logger"
6
+ autoload :Router, "#{ROOT}/fastr/router"
7
+ autoload :Error, "#{ROOT}/fastr/exception"
8
+ autoload :Controller, "#{ROOT}/fastr/controller"
9
+ autoload :Template, "#{ROOT}/fastr/template"
10
+ end
data/test/helper.rb ADDED
@@ -0,0 +1,10 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+ require 'shoulda'
4
+
5
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
6
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
7
+ require 'fastr'
8
+
9
+ class Test::Unit::TestCase
10
+ end
@@ -0,0 +1,7 @@
1
+ require 'helper'
2
+
3
+ class TestFastr < Test::Unit::TestCase
4
+ should "probably rename this file and start testing for real" do
5
+ flunk "hey buddy, you should probably rename this file and start testing for real"
6
+ end
7
+ end
metadata ADDED
@@ -0,0 +1,72 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fastr
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 0
8
+ - 1
9
+ version: 0.0.1
10
+ platform: ruby
11
+ authors:
12
+ - Chris Moos
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-05-19 00:00:00 -07:00
18
+ default_executable: fastr
19
+ dependencies: []
20
+
21
+ description: A fast, micro-framework for Ruby that should be run under EventMachine servers (thin)
22
+ email: chris@tech9computers.com
23
+ executables:
24
+ - fastr
25
+ extensions: []
26
+
27
+ extra_rdoc_files:
28
+ - LICENSE
29
+ - README.rdoc
30
+ files:
31
+ - lib/fastr.rb
32
+ - lib/fastr/application.rb
33
+ - lib/fastr/controller.rb
34
+ - lib/fastr/exception.rb
35
+ - lib/fastr/logger.rb
36
+ - lib/fastr/router.rb
37
+ - lib/fastr/template.rb
38
+ - LICENSE
39
+ - README.rdoc
40
+ has_rdoc: true
41
+ homepage: http://github.com/chrismoos/fastr
42
+ licenses: []
43
+
44
+ post_install_message:
45
+ rdoc_options:
46
+ - --charset=UTF-8
47
+ require_paths:
48
+ - lib
49
+ required_ruby_version: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ segments:
54
+ - 0
55
+ version: "0"
56
+ required_rubygems_version: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ segments:
61
+ - 0
62
+ version: "0"
63
+ requirements: []
64
+
65
+ rubyforge_project:
66
+ rubygems_version: 1.3.6
67
+ signing_key:
68
+ specification_version: 3
69
+ summary: Another rack web framework for Ruby.
70
+ test_files:
71
+ - test/helper.rb
72
+ - test/test_fastr.rb