Changeset 83
- Timestamp:
- 11/13/06 13:49:01 (2 years ago)
- Files:
-
- Rakefile (modified) (3 diffs)
- TODO (modified) (1 diff)
- bin/merb (modified) (6 diffs)
- examples/sample_app/dist/app/controllers/files.rb (added)
- examples/sample_app/dist/app/controllers/upload.rb (deleted)
- examples/sample_app/dist/app/views/files (added)
- examples/sample_app/dist/app/views/files/progress.merbjs (added)
- examples/sample_app/dist/app/views/files/start.rhtml (added)
- examples/sample_app/dist/app/views/files/upload.rhtml (added)
- examples/sample_app/dist/app/views/upload (deleted)
- examples/sample_app/dist/conf/merb.yml (added)
- examples/sample_app/dist/conf/merb_init.rb (modified) (1 diff)
- examples/sample_app/dist/conf/mup.conf (added)
- examples/sample_app/dist/public/javascripts/mup.js (added)
- ext (added)
- ext/optimized_locking (added)
- ext/optimized_locking/Makefile (added)
- ext/optimized_locking/extconf.rb (added)
- ext/optimized_locking/optimized_locking.bundle (added)
- ext/optimized_locking/optimized_locking.c (added)
- lib/merb.rb (modified) (2 diffs)
- lib/merb/merb_class_extensions.rb (modified) (3 diffs)
- lib/merb/merb_controller.rb (modified) (5 diffs)
- lib/merb/merb_handler.rb (modified) (3 diffs)
- lib/merb/merb_utils.rb (modified) (2 diffs)
- lib/merb/mixins/controller_mixin.rb (modified) (7 diffs)
- lib/merb/mixins/render_mixin.rb (modified) (2 diffs)
- lib/mutex_hotfix.rb (added)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
Rakefile
r73 r83 7 7 require 'code_statistics' 8 8 require 'fileutils' 9 require File.dirname(__FILE__)+'/tools/rakehelp' 9 10 include FileUtils 10 11 11 12 NAME = "merb" 12 VERS = "0.0. 6"13 VERS = "0.0.7" 13 14 CLEAN.include ['**/.*.sw?', '*.gem', '.config'] 14 15 RDOC_OPTS = ['--quiet', '--title', "Merb Documentation", … … 18 19 "--inline-source"] 19 20 21 setup_clean ["ext/optimized_locking/*.{bundle,so,obj,pdb,lib,def,exp}", 22 "ext/optimized_locking/Makefile" "pkg", "lib/*.bundle", "*.gem", 23 "doc/rdoc/**/*", ".config"] 24 25 20 26 desc "Packages up Merb." 21 27 task :default => [:package] 22 task :package => [:clean ]28 task :package => [:clean,:compile, :rdoc] 23 29 24 30 task :doc => [:rdoc] 31 32 desc "Compiles all extensions" 33 task :compile => [:optimized_locking] do 34 if Dir.glob(File.join("lib","optimized_locking.*")).length == 0 35 STDERR.puts "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" 36 STDERR.puts "Gem actually failed to build. Your system is" 37 STDERR.puts "NOT configured properly to build OptimizedMutex." 38 STDERR.puts "Merb will fall back to hot patched ruby mutex" 39 STDERR.puts "You still have a fully functional Merb install" 40 STDERR.puts "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" 41 exit(1) 42 end 43 end 44 45 setup_extension("optimized_locking", "optimized_locking") 25 46 26 47 Rake::RDocTask.new do |rdoc| … … 51 72 s.required_ruby_version = '>= 1.8.4' 52 73 53 s.files = %w(LICENSE README Rakefile TODO) + Dir.glob("{app,bin,doc, test,lib,examples}/**/*")74 s.files = %w(LICENSE README Rakefile TODO) + Dir.glob("{app,bin,doc,ext,test,lib,examples}/**/*") 54 75 55 76 s.require_path = "lib" TODO
r72 r83 5 5 * config file **DONE** 6 6 * session 7 ** AR 7 ** AR ** DONE ** 8 8 ** DRb 9 9 * Rails integration 10 * Mongoose ?11 10 * Text backend? 12 11 * plugins support(rails plugins too?) 13 12 * Layouts **DONE** 14 13 * auto template_dir **DONE** 15 * before/after filters 14 * before/after filters **DONE** 16 15 * merbjs **DONE** 17 16 * testing bin/merb
r73 r83 5 5 require 'fileutils' 6 6 require 'yaml' 7 require 'erubis' 8 7 9 module Merb 8 10 end … … 16 18 :merb_root => Dir.pwd 17 19 } 18 19 20 begin 20 options = defaults.merge(YAML.load(E RB.new(IO.read("#{defaults[:merb_root]}/dist/conf/merb.yml")).result))21 options = defaults.merge(YAML.load(Erubis::Eruby.new(IO.read("#{defaults[:merb_root]}/dist/conf/merb.yml")).result)) 21 22 rescue 22 23 options = defaults … … 80 81 end 81 82 83 def self.initialize_merb 84 require 'merb' 85 require @@merb_opts[:merb_root]+'/dist/conf/router.rb' 86 require @@merb_opts[:merb_root]+'/dist/conf/merb_init.rb' 87 end 88 82 89 def self.run 83 90 @@merb_raw_opts = ARGV … … 85 92 86 93 @@merb_opts[:dist_root] = @@merb_opts[:merb_root]+'/dist' 94 $LOAD_PATH.unshift( File.join(@@merb_opts[:dist_root] , '/app/controllers') ) 95 $LOAD_PATH.unshift( File.join(@@merb_opts[:dist_root] , '/app/models') ) 96 $LOAD_PATH.unshift( File.join(@@merb_opts[:dist_root] , '/lib') ) 87 97 88 $LOAD_PATH.unshift( File.join(@@merb_opts[:merb_root] , '/dist/app/controllers') )89 $LOAD_PATH.unshift( File.join(@@merb_opts[:merb_root] , '/dist/lib') )90 require 'merb'91 require @@merb_opts[:merb_root]+'/dist/conf/router.rb'92 require @@merb_opts[:merb_root]+'/dist/conf/merb_init.rb'93 94 98 if @@merb_opts[:console] 99 initialize_merb 95 100 ARGV.clear # Avoid passing args to IRB 96 101 require 'irb' … … 116 121 start(@@merb_opts[:port]) 117 122 else 123 initialize_merb 118 124 trap('INT') {exit} 119 125 mongrel_start(@@merb_opts[:port]) … … 153 159 154 160 def self.mongrel_start(port) 155 h = Mongrel::HttpServer.new((@@merb_opts[:host]||"0.0.0.0"), (port ||4000), (@@merb_opts[:numprocs]||100)) 156 h.register("/", MerbHandler.new(@@merb_opts[:dist_root]+'/public')) 157 h.register("/favicon.ico", Mongrel::Error404Handler.new("")) 158 h.run.join 161 initialize_merb 162 163 config = Mongrel::Configurator.new :host => (@@merb_opts[:host]||"0.0.0.0"), :port => (port ||4000) do 164 load_plugins :includes => ["mongrel"], :excludes => ["rails"] 165 listener do 166 run_config(@@merb_opts[:config]) if @@merb_opts[:config] 167 uri "/", :handler => MerbHandler.new(@@merb_opts[:dist_root]+'/public') 168 uri "/favicon.ico", :handler => Mongrel::Error404Handler.new("") 169 end 170 171 trap("INT") { stop } 172 run 173 end 174 config.join 159 175 end 160 176 examples/sample_app/dist/conf/merb_init.rb
r81 r83 10 10 :adapter => 'mysql', 11 11 :username => 'root', 12 :password => ' xxxxx',12 :password => 'reversal', 13 13 :database => 'merb' 14 14 ) lib/merb.rb
r78 r83 6 6 7 7 module Merb 8 VERSION='0.0. 6' unless defined?VERSION8 VERSION='0.0.7' unless defined?VERSION 9 9 class Server 10 10 def self.config … … 17 17 18 18 MERB_FRAMEWORK_ROOT = File.dirname(__FILE__) 19 20 begin 21 old_verbose = $VERBOSE 22 $VERBOSE = nil 23 require 'optimized_locking' 24 Mutex = OptimizedMutex 25 puts 'Using OptimizedMutex' 26 rescue LoadError 27 Mutex = nil 28 require 'mutex_hotfix' 29 ensure 30 $VERBOSE = old_verbose 31 end 19 32 MERB_ROOT = Merb::Server.config[:merb_root] || Dir.pwd 20 33 DIST_ROOT = Merb::Server.config[:dist_root] || Dir.pwd+'/dist' lib/merb/merb_class_extensions.rb
r78 r83 1 1 class Class # :nodoc: 2 def inheritable_reader(*syms)2 def meta_reader(*syms) 3 3 syms.each do |sym| 4 4 class_eval <<-EOS 5 5 def self.#{sym} 6 read_ inheritable_attribute(:#{sym})6 read_meta_attribute(:#{sym}) 7 7 end 8 8 … … 14 14 end 15 15 16 def inheritable_writer(*syms)16 def meta_writer(*syms) 17 17 syms.each do |sym| 18 18 class_eval <<-EOS 19 19 def self.#{sym}=(obj) 20 write_ inheritable_attribute(:#{sym}, obj)20 write_meta_attribute(:#{sym}, obj) 21 21 end 22 22 … … 28 28 end 29 29 30 31 def inheritable_accessor(*syms) 32 inheritable_reader(*syms) 33 inheritable_writer(*syms) 30 def meta_accessor(*syms) 31 meta_reader(*syms) 32 meta_writer(*syms) 34 33 end 35 34 36 def inheritable_attributes37 @ inheritable_attributes ||= {}35 def meta_attributes 36 @meta_attributes ||= {} 38 37 end 39 38 40 def write_ inheritable_attribute(key, value)41 inheritable_attributes[key] = value39 def write_meta_attribute(key, value) 40 meta_attributes[key] = value 42 41 end 43 42 44 def read_ inheritable_attribute(key)45 inheritable_attributes[key]43 def read_meta_attribute(key) 44 meta_attributes[key] 46 45 end 47 46 48 def reset_ inheritable_attributes49 inheritable_attributes.clear47 def reset_meta_attributes 48 meta_attributes.clear 50 49 end 51 50 52 51 private 53 def inherited_with_ inheritable_attributes(child)54 inherited_without_ inheritable_attributes(child) if respond_to?(:inherited_without_inheritable_attributes)52 def inherited_with_meta_attributes(child) 53 inherited_without_meta_attributes(child) if respond_to?(:inherited_without_meta_attributes) 55 54 56 new_ inheritable_attributes = inheritable_attributes.inject({}) do |memo, (key, value)|55 new_meta_attributes = meta_attributes.inject({}) do |memo, (key, value)| 57 56 memo.update(key => (value.dup rescue value)) 58 57 end 59 58 60 child.instance_variable_set('@ inheritable_attributes', new_inheritable_attributes)59 child.instance_variable_set('@meta_attributes', new_meta_attributes) 61 60 end 62 61 63 alias inherited_without_ inheritable_attributes inherited64 alias inherited inherited_with_ inheritable_attributes62 alias inherited_without_meta_attributes inherited 63 alias inherited inherited_with_meta_attributes 65 64 end lib/merb/merb_controller.rb
r79 r83 26 26 # file uploads by writing a tempfile and passing a reference 27 27 # in params. 28 def initialize(req, env, args, method=(env[ 'REQUEST_METHOD']||"GET")) #:nodoc:28 def initialize(req, env, args, method=(env[Mongrel::Const::REQUEST_METHOD]||Mongrel::Const::GET)) 29 29 env = MerbHash[env.to_hash] 30 @layout = 'application'31 @status, @method, @env, @headers, @root = 200, method.downcase , env,32 { 'Content-Type'=>'text/html'}, env['SCRIPT_NAME'].sub(/\/$/,'')30 @layout = :application 31 @status, @method, @env, @headers, @root = 200, method.downcase.to_sym, env, 32 {Mongrel::Const::CONTENT_TYPE =>'text/html'}, env[Mongrel::Const::SCRIPT_NAME].sub(/\/$/,'') 33 33 @k = query_parse(env['HTTP_COOKIE'], ';,') 34 34 qs = query_parse(env['QUERY_STRING']) 35 35 @in = req 36 if %r|\Amultipart/form-data.*boundary=\"?([^\";,]+)|n .match(env['CONTENT_TYPE'])36 if %r|\Amultipart/form-data.*boundary=\"?([^\";,]+)|n =~ (env[Mongrel::Const::CONTENT_TYPE]) 37 37 b = /(?:\r?\n|\A)#{Regexp::quote("--#$1")}(?:--)?\r$/ 38 38 until @in.eof? … … 66 66 fh[:tempfile].rewind if fh.is_a?MerbHash 67 67 end 68 elsif @method == "post"68 elsif @method == :post 69 69 qs.merge!(query_parse(@in.read)) 70 70 end … … 74 74 75 75 def dispatch(action=nil) 76 puts self.class.name.to_s + "#{action}" 76 77 setup_session if respond_to?:setup_session 77 78 call_filters(before_filters) … … 99 100 end 100 101 101 inheritable_accessor :before_filters 102 # meta_accessor sets up a class instance variable that can 103 # be unique for each class but also inherits the meta attrs 104 # from its superclasses. Since @@class variables are almost 105 # global vars within an inheritance tree 106 meta_accessor :before_filters 102 107 103 108 def call_filters(filter_set) 104 109 (filter_set || []).each do |filter| 105 110 case filter 106 when Symbol 111 when Symbol, String 107 112 send(filter) 108 113 when Proc 109 114 filter.call(self) 110 else111 raise(112 MerbControllerError,113 'filters needs to be either a Symbol or a Proc'114 )115 115 end 116 116 end … … 118 118 119 119 def self.before(filter) 120 (self.before_filters ||= []) << filter 120 case filter 121 when Symbol, String, Proc 122 (self.before_filters ||= []) << filter 123 else 124 raise( 125 MerbControllerError, 126 'filters need to be either a Symbol, String or a Proc' 127 ) 128 end 121 129 end 122 130 lib/merb/merb_handler.rb
r74 r83 42 42 # File exists as-is so serve it up 43 43 MERB_LOGGER.info("Serving static file: #{path_info}") 44 45 44 @files.process(request,response) 46 45 elsif get_or_head and @files.can_serve(page_cached) 47 46 # Possible cached page, serve it up 48 MERB_LOGGER.info("Serving static file: #{pa th_info}")47 MERB_LOGGER.info("Serving static file: #{page_cached}") 49 48 request.params[Mongrel::Const::PATH_INFO] = page_cached 50 49 @files.process(request,response) … … 89 88 90 89 controller = nil 91 92 90 if sendfile 93 91 MERB_LOGGER.info("X-SENDFILE: #{sendfile}") 94 # send X-SENDFILE header to mongrel 95 response.send_status(File.size(sendfile)) 96 response.send_header 97 response.send_file(sendfile) 92 request.params[Mongrel::Const::PATH_INFO] = sendfile 93 @files.process(request, response) 98 94 else 99 95 MERB_LOGGER.info("Response status: #{response.status}\n\n") 100 96 # render response from successful controller 101 response.send_status((output|| '').length)97 response.send_status((output||='').length) 102 98 response.send_header 103 99 response.write(output) … … 115 111 path = path[0..-2] if (path[-1] == ?/) 116 112 route = Merb::RouteMatcher.new.route_request(path) 117 if route 118 MERB_LOGGER.info("No Matching Route!") if route[:controller] == 'Noroutefound' 119 [ instantiate_controller(route[:controller], request.body, request.params, route), 120 route[:action] ] 121 else 122 MERB_LOGGER.info("No Matching Route!") 123 ["<html><body>Error: no route matches!</body></html>", nil] 124 end 113 MERB_LOGGER.info("No Matching Route!") if route[:controller] == 'Noroutefound' 114 [ instantiate_controller(route[:controller], request.body, request.params, route), 115 route[:action] ] 125 116 end 126 117 lib/merb/merb_utils.rb
r78 r83 67 67 alias_method :regular_writer, :[]= unless method_defined?(:regular_writer) 68 68 alias_method :regular_update, :update unless method_defined?(:regular_update) 69 alias_method :u, :regular_update 69 70 70 71 def []=(key, value) … … 120 121 end 121 122 122 require 'thread'123 124 # monkey patch Mutex so it does not leak memory.125 class Mutex126 127 def lock128 while (Thread.critical = true; @locked)129 @waiting.unshift Thread.current130 Thread.stop131 end132 @locked = true133 Thread.critical = false134 self135 end136 137 def unlock138 return unless @locked139 Thread.critical = true140 @locked = false141 begin142 t = @waiting.pop143 t.wakeup if t144 rescue ThreadError145 retry146 end147 Thread.critical = false148 begin149 t.run if t150 rescue ThreadError151 end152 self153 end154 155 endlib/merb/mixins/controller_mixin.rb
r78 r83 7 7 MERB_LOGGER.info("Redirecting to: #{url}") 8 8 @status = 302 9 @headers.merge!({'Location'=> url})9 headers.merge!({'Location'=> url}) 10 10 return '' 11 11 end … … 33 33 # {:bar => 'nik', :post => {:title => 'heya', :body => 'whatever}} 34 34 def query_parse(qs, d = '&;') 35 m = proc {|_,o,n|o.update(n,&m)rescue([*o]<<n)} 35 puts qs 36 m = proc {|_,o,n|o.u(n,&m)rescue([*o]<<n)} 36 37 (qs||'').split(/[#{d}] */n).inject(MerbHash[]) { |h,p| 37 38 k, v=unescape(p).split('=',2) 38 h.u pdate(k.split(/[\]\[]+/).reverse.39 h.u(k.split(/[\]\[]+/).reverse. 39 40 inject(v) { |x,i| MerbHash[i,x] },&m) 40 41 } 41 42 end 43 44 def make_token 45 require 'digest/md5' 46 Digest::MD5.hexdigest("#{inspect}#{Time.now}#{rand}") 47 end 42 48 43 49 # does url escaping … … 57 63 alias js :escape_js 58 64 65 # returns true if the request is an ajax request. 59 66 def xml_http_request? 60 67 not /XMLHttpRequest/i.match(@headers['HTTP_X_REQUESTED_WITH']).nil? … … 63 70 alias ajax? :xml_http_request? 64 71 72 # returns the remote IP address if it can find it. 65 73 def remote_ip 66 74 return @headers['HTTP_CLIENT_IP'] if @headers.include?('HTTP_CLIENT_IP') 67 75 68 if @headers.include?( 'HTTP_X_FORWARDED_FOR') then69 remote_ips = @headers[ 'HTTP_X_FORWARDED_FOR'].split(',').reject do |ip|76 if @headers.include?(Mongrel::Const::HTTP_X_FORWARDED_FOR) then 77 remote_ips = @headers[Mongrel::Const::HTTP_X_FORWARDED_FOR].split(',').reject do |ip| 70 78 ip =~ /^unknown$|^(127|10|172\.16|192\.168)\./i 71 79 end … … 74 82 end 75 83 76 return @headers[ 'REMOTE_ADDR']84 return @headers[Mongrel::Const::REMOTE_ADDR] 77 85 end 78 86 87 # returns either 'https://' or 'http://' depending on 88 # the HTTPS header 79 89 def protocol 80 90 @headers['HTTPS'] == 'on' ? 'https://' : 'http://' 81 91 end 82 92 93 # returns true if the request is an SSL request 83 94 def ssl? 84 95 @headers['HTTPS'] == 'on' … … 86 97 87 98 # The request uri. 88 89 99 def uri 90 @headers[ 'REQUEST_URI']100 @headers[Mongrel::Const::REQUEST_URI] 91 101 end 92 102 93 103 # The path is the uri without the query string. 94 95 104 def path 96 105 uri ? uri.split('?').first : '' 97 106 end 98 107 99 108 def path_info 100 @headers[ 'PATH_INFO']109 @headers[Mongrel::Const::PATH_INFO] 101 110 end 102 111 … … 119 128 120 129 def method 121 @ headers['REQUEST_METHOD'].downcase.to_sym130 @method ||= @headers[Mongrel::Const::REQUEST_METHOD].downcase.to_sym 122 131 end 123 132 lib/merb/mixins/render_mixin.rb
r72 r83 14 14 15 15 # does a render with no layout. Also sets the 16 # content type header to text/javascript and 17 # escapes the template for javascript eval on 18 # the client 16 # content type header to text/javascript 19 17 def render_js(template=current_method_name(1), b=binding) 20 18 headers['Content-Type'] = "text/javascript" … … 69 67 MERB_LOGGER.info("With Layout: #{template_dir('layout')}/#{layout}.rhtml") 70 68 @layout_content = layout_content 71 layout_tmpl = Erubis::Eruby.new( IO.read( template_dir('layout') + "/#{layout}.rhtml" ) )69 layout_tmpl = Erubis::Eruby.new( IO.read( "#{template_dir('layout')}/#{layout}.rhtml" ) ) 72 70 layout_tmpl.result(b) 73 71 end
