diff options
author | David Heinemeier Hansson <david@loudthinking.com> | 2004-11-24 01:04:44 +0000 |
---|---|---|
committer | David Heinemeier Hansson <david@loudthinking.com> | 2004-11-24 01:04:44 +0000 |
commit | db045dbbf60b53dbe013ef25554fd013baf88134 (patch) | |
tree | 257830e3c76458c8ff3d1329de83f32b23926028 /railties/lib | |
download | rails-db045dbbf60b53dbe013ef25554fd013baf88134.tar.gz rails-db045dbbf60b53dbe013ef25554fd013baf88134.tar.bz2 rails-db045dbbf60b53dbe013ef25554fd013baf88134.zip |
Initial
git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@4 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
Diffstat (limited to 'railties/lib')
-rw-r--r-- | railties/lib/code_statistics.rb | 71 | ||||
-rw-r--r-- | railties/lib/dispatcher.rb | 55 | ||||
-rw-r--r-- | railties/lib/generator.rb | 112 | ||||
-rw-r--r-- | railties/lib/webrick_server.rb | 159 |
4 files changed, 397 insertions, 0 deletions
diff --git a/railties/lib/code_statistics.rb b/railties/lib/code_statistics.rb new file mode 100644 index 0000000000..53e7feb1c0 --- /dev/null +++ b/railties/lib/code_statistics.rb @@ -0,0 +1,71 @@ +class CodeStatistics + def initialize(*pairs) + @pairs = pairs + @statistics = calculate_statistics + @total = calculate_total if pairs.length > 1 + end + + def to_s + print_header + @statistics.each{ |k, v| print_line(k, v) } + print_splitter + + if @total + print_line("Total", @total) + print_splitter + end + end + + private + def calculate_statistics + @pairs.inject({}) { |stats, pair| stats[pair.first] = calculate_directory_statistics(pair.last); stats } + end + + def calculate_directory_statistics(directory, pattern = /.*rb/) + stats = { "lines" => 0, "codelines" => 0, "classes" => 0, "methods" => 0 } + + Dir.foreach(directory) do |file_name| + next unless file_name =~ pattern + + f = File.open(directory + "/" + file_name) + + while line = f.gets + stats["lines"] += 1 + stats["classes"] += 1 if line =~ /class [A-Z]/ + stats["methods"] += 1 if line =~ /def [a-z]/ + stats["codelines"] += 1 unless line =~ /^\s*$/ || line =~ /^\s*#/ + end + end + + stats + end + + def calculate_total + total = { "lines" => 0, "codelines" => 0, "classes" => 0, "methods" => 0 } + @statistics.each_value { |pair| pair.each { |k, v| total[k] += v } } + total + end + + def print_header + print_splitter + puts "| Name | Lines | LOC | Classes | Methods | M/C | LOC/M |" + print_splitter + end + + def print_splitter + puts "+----------------------+-------+-------+---------+---------+-----+-------+" + end + + def print_line(name, statistics) + m_over_c = (statistics["methods"] / statistics["classes"]) rescue m_over_c = 0 + loc_over_m = (statistics["codelines"] / statistics["methods"]) - 2 rescue loc_over_m = 0 + + puts "| #{name.ljust(20)} " + + "| #{statistics["lines"].to_s.rjust(5)} " + + "| #{statistics["codelines"].to_s.rjust(5)} " + + "| #{statistics["classes"].to_s.rjust(7)} " + + "| #{statistics["methods"].to_s.rjust(7)} " + + "| #{m_over_c.to_s.rjust(3)} " + + "| #{loc_over_m.to_s.rjust(5)} |" + end +end
\ No newline at end of file diff --git a/railties/lib/dispatcher.rb b/railties/lib/dispatcher.rb new file mode 100644 index 0000000000..aa7ae98edd --- /dev/null +++ b/railties/lib/dispatcher.rb @@ -0,0 +1,55 @@ +#-- +# Copyright (c) 2004 David Heinemeier Hansson +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +#++ + +class Dispatcher + DEFAULT_SESSION_OPTIONS = { "database_manager" => CGI::Session::PStore, "prefix" => "ruby_sess.", "session_path" => "/" } + + def self.dispatch(cgi = CGI.new, session_options = DEFAULT_SESSION_OPTIONS, error_page = nil) + begin + request = ActionController::CgiRequest.new(cgi, session_options) + response = ActionController::CgiResponse.new(cgi) + + controller_name = request.parameters["controller"].gsub(/[^_a-zA-Z0-9]/, "").untaint + + if module_name = request.parameters["module"] + Module.new do + ActionController::Base.require_or_load "#{module_name}/#{Inflector.underscore(controller_name)}_controller" + Object.const_get("#{Inflector.camelize(controller_name)}Controller").process(request, response).out + end + else + ActionController::Base.require_or_load "#{Inflector.underscore(controller_name)}_controller" + Object.const_get("#{Inflector.camelize(controller_name)}Controller").process(request, response).out + end + rescue Exception => e + begin + ActionController::Base.logger.info "\n\nException throw during dispatch: #{e.message}\n#{e.backtrace.join("\n")}" + rescue Exception + # Couldn't log error + end + + if error_page then cgi.out{ IO.readlines(error_page) } else raise e end + ensure + ActiveRecord::Base.reset_associations_loaded + end + end +end diff --git a/railties/lib/generator.rb b/railties/lib/generator.rb new file mode 100644 index 0000000000..28b41c60f0 --- /dev/null +++ b/railties/lib/generator.rb @@ -0,0 +1,112 @@ +require 'fileutils' +require 'active_record/support/inflector' + +module Generator + class GeneratorError < StandardError; end + + class Base + @@template_root = File.dirname(__FILE__) + '/../generators/templates' + cattr_accessor :template_root + + attr_reader :rails_root, :class_name, :file_name, :table_name, + :actions, :options + + def initialize(rails_root, object_name, actions = [], options = {}) + @rails_root = rails_root + @class_name = Inflector.camelize(object_name) + @file_name = Inflector.underscore(@class_name) + @table_name = Inflector.pluralize(@file_name) + @actions = actions + @options = options + + # Use local templates if rails_root/generators directory exists. + local_template_root = File.join(@rails_root, 'generators') + if File.directory?(local_template_root) + self.class.template_root = local_template_root + end + end + + protected + + # Generate a file in a fresh Rails app from an ERB template. + # Takes a template path relative to +template_root+, a + # destination path relative to +rails_root+, evaluates the template, + # and writes the result to the destination. + def generate_file(template_file_path, rails_file_path, eval_binding = nil) + # Determine full paths for source and destination files. + template_path = File.join(template_root, template_file_path) + rails_path = File.join(rails_root, rails_file_path) + + # Create destination directories. + FileUtils.mkdir_p(File.dirname(rails_path)) + + # Render template and write result. + eval_binding ||= binding + contents = ERB.new(File.read(template_path), nil, '-').result(eval_binding) + File.open(rails_path, 'w') { |file| file.write(contents) } + end + end + + # Generate controller, helper, functional test, and views. + class Controller < Base + def generate + options[:scaffold] = file_name if options[:scaffold] + + # Controller class. + generate_file "controller.erb", "app/controllers/#{file_name}_controller.rb" + + # Helper class. + generate_file "helper.erb", "app/helpers/#{file_name}_helper.rb" + + # Function test. + generate_file "controller_test.erb", "test/functional/#{file_name}_controller_test.rb" + + # View template for each action. + @actions.each do |action| + generate_file "controller_view.rhtml", + "app/views/#{file_name}/#{action}.rhtml", + binding + end + end + end + + # Generate model, unit test, and fixtures. + class Model < Base + def generate + + # Model class. + generate_file "model.erb", "app/models/#{file_name}.rb" + + # Model unit test. + generate_file "model_test.erb", "test/unit/#{file_name}_test.rb" + + # Test fixtures directory. + FileUtils.mkdir_p("test/fixtures/#{table_name}") + end + end + + # Generate mailer, helper, functional test, and views. + class Mailer < Base + def generate + + # Mailer class. + generate_file "mailer.erb", "app/models/#{file_name}.rb" + + # Mailer unit test. + generate_file "mailer_test.erb", "test/unit/#{file_name}_test.rb" + + # Test fixtures directory. + FileUtils.mkdir_p("test/fixtures/#{table_name}") + + # View template and fixture for each action. + @actions.each do |action| + generate_file "mailer_action.rhtml", + "app/views/#{file_name}/#{action}.rhtml", + binding + generate_file "mailer_fixture.rhtml", + "test/fixtures/#{table_name}/#{action}", + binding + end + end + end +end diff --git a/railties/lib/webrick_server.rb b/railties/lib/webrick_server.rb new file mode 100644 index 0000000000..66c78fbd5f --- /dev/null +++ b/railties/lib/webrick_server.rb @@ -0,0 +1,159 @@ +# Donated by Florian Gross + +require 'webrick' +require 'cgi' +require 'stringio' + +begin + require 'dev-utils/debug' + require 'irb/completion' + + module DevUtils::Debug + alias_method :breakpoint_without_io, :breakpoint unless method_defined?(:breakpoint_without_io) + + def breakpoint(name = nil, context = nil, &block) + $new_stdin, $new_stdout = $stdin, $stdout + $stdin, $stdout = $old_stdin, $old_stdout + breakpoint_without_io(name, context, &block) + $stdin, $stdout = $new_stdin, $new_stdout + end + end +rescue LoadError + # dev utils not available +end + +include WEBrick + +class DispatchServlet < WEBrick::HTTPServlet::AbstractServlet + REQUEST_MUTEX = Mutex.new + + def self.dispatch(options = {}) + Socket.do_not_reverse_lookup = true # patch for OS X + + server = WEBrick::HTTPServer.new(:Port => options[:port].to_i, :ServerType => options[:server_type], :BindAddress => options[:ip]) + server.mount('/', DispatchServlet, options) + + trap("INT") { server.shutdown } + server.start + end + + def initialize(server, options) + @server_options = options + @file_handler = WEBrick::HTTPServlet::FileHandler.new(server, options[:server_root], {:FancyIndexing => true }) + super + end + + def do_GET(req, res) + begin + REQUEST_MUTEX.lock + + unless handle_index(req, res) + unless handle_dispatch(req, res) + unless handle_file(req, res) + unless handle_mapped(req, res) + raise WEBrick::HTTPStatus::NotFound, "`#{req.path}' not found." + end + end + end + end + ensure + REQUEST_MUTEX.unlock + end + end + + alias :do_POST :do_GET + + def handle_index(req, res) + if req.request_uri.path == "/" + if @server_options[:index_controller] + res.set_redirect WEBrick::HTTPStatus::MovedPermanently, "/#{@server_options[:index_controller]}/" + else + res.set_redirect WEBrick::HTTPStatus::MovedPermanently, "/_doc/index.html" + end + + return true + else + return false + end + end + + def handle_file(req, res) + begin + @file_handler.send(:do_GET, req, res) + return true + rescue HTTPStatus::PartialContent, HTTPStatus::NotModified => err + res.set_error(err) + return true + rescue => err + p err + return false + end + end + + def handle_mapped(req, res) + parsed_ok, controller, action, id = DispatchServlet.parse_uri(req.request_uri.path) + if parsed_ok + query = "controller=#{controller}&action=#{action}&id=#{id}" + query << "&#{req.request_uri.query}" if req.request_uri.query + origin = req.request_uri.path + "?" + query + req.request_uri.path = "/dispatch.rb" + req.request_uri.query = query + handle_dispatch(req, res, origin) + else + return false + end + end + + def handle_dispatch(req, res, origin = nil) + return false unless /^\/dispatch\.(?:cgi|rb|fcgi)$/.match(req.request_uri.path) + + env = req.meta_vars.clone + env["QUERY_STRING"] = req.request_uri.query + env["REQUEST_URI"] = origin if origin + + data = nil + $old_stdin, $old_stdout = $stdin, $stdout + $stdin, $stdout = StringIO.new(req.body || ""), StringIO.new + + begin + require 'cgi' + CGI.send(:define_method, :env_table) { env } + + load File.join(@server_options[:server_root], "dispatch.rb") + + $stdout.rewind + data = $stdout.read + ensure + $stdin, $stdout = $old_stdin, $old_stdout + end + + raw_header, body = *data.split(/^[\xd\xa]+/on, 2) + header = WEBrick::HTTPUtils::parse_header(raw_header) + if /^(\d+)/ =~ header['status'][0] + res.status = $1.to_i + header.delete('status') + end + header.each { |key, val| res[key] = val.join(", ") } + + res.body = body + return true + rescue => err + p err, err.backtrace + return false + end + + def self.parse_uri(path) + component = /([-_a-zA-Z0-9]+)/ + + case path.sub(%r{^/(?:fcgi|mruby|cgi)/}, "/") + when %r{^/#{component}/?$} then + [true, $1, "index", nil] + when %r{^/#{component}/#{component}/?$} then + [true, $1, $2, nil] + when %r{^/#{component}/#{component}/#{component}/?$} then + [true, $1, $2, $3] + else + [false, nil, nil, nil] + end + end +end |