fastr 0.0.1

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/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