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 | |
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')
45 files changed, 1837 insertions, 0 deletions
diff --git a/railties/CHANGELOG b/railties/CHANGELOG new file mode 100644 index 0000000000..60eb1c3e2a --- /dev/null +++ b/railties/CHANGELOG @@ -0,0 +1,265 @@ +*CVS* + +* Added breakpoint support by default to the WEBrick dispatcher. This means that you can break out of execution at any point in + the code, investigate and change the model, AND then resume execution! Example: + + class WeblogController < ActionController::Base + def index + @posts = Post.find_all + breakpoint "Breaking out from the list" + end + end + + So the controller will accept the action, run the first line, then present you with a IRB prompt in the WEBrick window (you shouldn't + run as daemon when you want to use this). Here you can do things like: + + Executing breakpoint "Breaking out from the list" at .../webrick_server.rb:16 in 'breakpoint' + + >> @posts.inspect + => "[#<Post:0x14a6be8 @attributes={\"title\"=>nil, \"body\"=>nil, \"id\"=>\"1\"}>, + #<Post:0x14a6620 @attributes={\"title\"=>\"Rails you know!\", \"body\"=>\"Only ten..\", \"id\"=>\"2\"}>]" + >> @posts.first.title = "hello from a breakpoint" + => "hello from a breakpoint" + + ...and even better is that you can examine how your runtime objects actually work: + + >> f = @posts.first + => #<Post:0x13630c4 @attributes={"title"=>nil, "body"=>nil, "id"=>"1"}> + >> f. + Display all 152 possibilities? (y or n) + + Finally, when you're ready to resume execution, you press CTRL-D + +* Changed environments to be configurable through an environment variable. By default, the environment is "development", but you + can change that and set your own by configuring the Apache vhost with a string like (mod_env must be available on the server): + + SetEnv RAILS_ENV production + + ...if you're using WEBrick, you can pick the environment to use with the command-line parameters -e/--environment, like this: + + ruby public/dispatcher.servlet -e production + +* Added a new default environment called "development", which leaves the production environment to be tuned exclusively for that. + +* Added a start_server in the root of the Rails application to make it even easier to get started + +* Fixed public/.htaccess to use RewriteBase and share the same rewrite rules for all the dispatch methods + +* Fixed webrick_server to handle requests in a serialized manner (the Rails reloading infrastructure is not thread-safe) + +* Added support for controllers in directories. So you can have: + + app/controllers/account_controller.rb # URL: /account/ + app/controllers/admin/account_controller.rb # URL: /admin/account/ + + NOTE: You need to update your public/.htaccess with the new rules to pick it up + +* Added reloading for associations and dependencies under cached environments like FastCGI and mod_ruby. This makes it possible to use + those environments for development. This is turned on by default, but can be turned off with + ActiveRecord::Base.reload_associations = false and ActionController::Base.reload_dependencies = false in production environments. + +* Added support for sub-directories in app/models. So now you can have something like Basecamp with: + + app/models/accounting + app/models/project + app/models/participants + app/models/settings + + It's poor man's namespacing, but only for file-system organization. You still require files just like before. + Nothing changes inside the files themselves. + + +* Fixed a few references in the tests generated by new_mailer [bitsweat] + +* Added support for mocks in testing with test/mocks + +* Cleaned up the environments a bit and added global constant RAILS_ROOT + + +*0.8.5* (9) + +* Made dev-util available to all tests, so you can insert breakpoints in any test case to get an IRB prompt at that point [bitsweat]: + + def test_complex_stuff + @david.projects << @new_project + breakpoint "Let's have a closer look at @david" + end + + You need to install dev-utils yourself for this to work ("gem install dev-util"). + +* Added shared generator behavior so future upgrades should be possible without manually copying over files [bitsweat] + +* Added the new helper style to both controller and helper templates [bitsweat] + +* Added new_crud generator for creating a model and controller at the same time with explicit scaffolding [bitsweat] + +* Added configuration of Test::Unit::TestCase.fixture_path to test_helper to concide with the new AR fixtures style + +* Fixed that new_model was generating singular table/fixture names + +* Upgraded to Action Mailer 0.4.0 + +* Upgraded to Action Pack 0.9.5 + +* Upgraded to Active Record 1.1.0 + + +*0.8.0 (15)* + +* Removed custom_table_name option for new_model now that the Inflector is as powerful as it is + +* Changed the default rake action to just do testing and separate API generation and coding statistics into a "doc" task. + +* Fixed WEBrick dispatcher to handle missing slashes in the URLs gracefully [alexey] + +* Added user option for all postgresql tool calls in the rakefile [elvstone] + +* Fixed problem with running "ruby public/dispatch.servlet" instead of "cd public; ruby dispatch.servlet" [alexey] + +* Fixed WEBrick server so that it no longer hardcodes the ruby interpreter used to "ruby" but will get the one used based + on the Ruby runtime configuration. [Marcel Molina Jr.] + +* Fixed Dispatcher so it'll route requests to magic_beans to MagicBeansController/magic_beans_controller.rb [Caio Chassot] + +* "new_controller MagicBeans" and "new_model SubscriptionPayments" will now both behave properly as they use the new Inflector. + +* Fixed problem with MySQL foreign key constraint checks in Rake :clone_production_structure_to_test target [Andreas Schwarz] + +* Changed WEBrick server to by default be auto-reloading, which is slower but makes source changes instant. + Class compilation cache can be turned on with "-c" or "--cache-classes". + +* Added "-b/--binding" option to WEBrick dispatcher to bind the server to a specific IP address (default: 127.0.0.1) [Kevin Temp] + +* dispatch.fcgi now DOESN'T set FCGI_PURE_RUBY as it was slowing things down for now reason [Andreas Schwarz] + +* Added new_mailer generator to work with Action Mailer + +* Included new framework: Action Mailer 0.3 + +* Upgraded to Action Pack 0.9.0 + +* Upgraded to Active Record 1.0.0 + + +*0.7.0* + +* Added an optional second argument to the new_model script that allows the programmer to specify the table name, + which will used to generate a custom table_name method in the model and will also be used in the creation of fixtures. + [Kevin Radloff] + +* script/new_model now turns AccountHolder into account_holder instead of accountholder [Kevin Radloff] + +* Fixed the faulty handleing of static files with WEBrick [Andreas Schwarz] + +* Unified function_test_helper and unit_test_helper into test_helper + +* Fixed bug with the automated production => test database dropping on PostgreSQL [dhawkins] + +* create_fixtures in both the functional and unit test helper now turns off the log during fixture generation + and can generate more than one fixture at a time. Which makes it possible for assignments like: + + @people, @projects, @project_access, @companies, @accounts = + create_fixtures "people", "projects", "project_access", "companies", "accounts" + +* Upgraded to Action Pack 0.8.5 (locally-scoped variables, partials, advanced send_file) + +* Upgraded to Active Record 0.9.5 (better table_name guessing, cloning, find_all_in_collection) + + +*0.6.5* + +* No longer specifies a template for rdoc, so it'll use whatever is default (you can change it in the rakefile) + +* The new_model generator will now use the same rules for plural wordings as Active Record + (so Category will give categories, not categorys) [Kevin Radloff] + +* dispatch.fcgi now sets FCGI_PURE_RUBY to true to ensure that it's the Ruby version that's loaded [danp] + +* Made the GEM work with Windows + +* Fixed bug where mod_ruby would "forget" the load paths added when switching between controllers + +* PostgreSQL are now supported for the automated production => test database dropping [Kevin Radloff] + +* Errors thrown by the dispatcher are now properly handled in FCGI. + +* Upgraded to Action Pack 0.8.0 (lots and lots and lots of fixes) + +* Upgraded to Active Record 0.9.4 (a bunch of fixes) + + +*0.6.0* + +* Added AbstractionApplicationController as a superclass for all controllers generated. This class can be used + to carry filters and methods that are to be shared by all. It has an accompanying ApplicationHelper that all + controllers will also automatically have available. + +* Added environments that can be included from any script to get the full Active Record and Action Controller + context running. This can be used by maintenance scripts or to interact with the model through IRB. Example: + + require 'config/environments/production' + + for account in Account.find_all + account.recalculate_interests + end + + A short migration script for an account model that had it's interest calculation strategy changed. + +* Accessing the index of a controller with "/weblog" will now redirect to "/weblog/" (only on Apache, not WEBrick) + +* Simplified the default Apache config so even remote requests are served off CGI as a default. + You'll now have to do something specific to activate mod_ruby and FCGI (like using the force urls). + This should make it easier for new comers that start on an external server. + +* Added more of the necessary Apache options to .htaccess to make it easier to setup + +* Upgraded to Action Pack 0.7.9 (lots of fixes) + +* Upgraded to Active Record 0.9.3 (lots of fixes) + + +*0.5.7* + +* Fixed bug in the WEBrick dispatcher that prevented it from getting parameters from the URL + (through GET requests or otherwise) + +* Added lib in root as a place to store app specific libraries + +* Added lib and vendor to load_path, so anything store within can be loaded directly. + Hence lib/redcloth.rb can be loaded with require "redcloth" + +* Upgraded to Action Pack 0.7.8 (lots of fixes) + +* Upgraded to Active Record 0.9.2 (minor upgrade) + + +*0.5.6* + +* Upgraded to Action Pack 0.7.7 (multipart form fix) + +* Updated the generated template stubs to valid XHTML files + +* Ensure that controllers generated are capitalized, so "new_controller TodoLists" + gives the same as "new_controller Todolists" and "new_controller todolists". + + +*0.5.5* + +* Works on Windows out of the box! (Dropped symlinks) + +* Added webrick dispatcher: Try "ruby public/dispatch.servlet --help" [Florian Gross] + +* Report errors about initialization to browser (instead of attempting to use uninitialized logger) + +* Upgraded to Action Pack 0.7.6 + +* Upgraded to Active Record 0.9.1 + +* Added distinct 500.html instead of reusing 404.html + +* Added MIT license + + +*0.5.0* + +* First public release diff --git a/railties/MIT-LICENSE b/railties/MIT-LICENSE new file mode 100644 index 0000000000..5919c288e4 --- /dev/null +++ b/railties/MIT-LICENSE @@ -0,0 +1,20 @@ +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.
\ No newline at end of file diff --git a/railties/README b/railties/README new file mode 100644 index 0000000000..4702f8a6c8 --- /dev/null +++ b/railties/README @@ -0,0 +1,121 @@ +== Welcome to Rails + +Rails is a web-application and persistance framework that includes everything +needed to create database-backed web-applications according to the +Model-View-Control pattern of separation. This pattern splits the view (also +called the presentation) into "dumb" templates that are primarily responsible +for inserting pre-build data in between HTML tags. The model contains the +"smart" domain objects (such as Account, Product, Person, Post) that holds all +the business logic and knows how to persist themselves to a database. The +controller handles the incoming requests (such as Save New Account, Update +Product, Show Post) by manipulating the model and directing data to the view. + +In Rails, the model is handled by what's called a object-relational mapping +layer entitled Active Record. This layer allows you to present the data from +database rows as objects and embellish these data objects with business logic +methods. You can read more about Active Record in +link:files/vendor/activerecord/README.html. + +The controller and view is handled by the Action Pack, which handles both +layers by its two parts: Action View and Action Controller. These two layers +are bundled in a single package due to their heavy interdependence. This is +unlike the relationship between the Active Record and Action Pack that is much +more separate. Each of these packages can be used independently outside of +Rails. You can read more about Action Pack in +link:files/vendor/actionpack/README.html. + + +== Requirements + +* Database and driver (MySQL, PostgreSQL, or SQLite) +* Rake[http://rake.rubyforge.org] for running tests and the generating documentation + +== Optionals + +* Apache 1.3.x or 2.x (or any FastCGI-capable webserver with a + mod_rewrite-like module) +* FastCGI (or mod_ruby) for production performance (CGI is used for + development) + +== Getting started + +1a. Setup Apache for the Rails application (see "Example for Apache conf") +1b. Run the WEBrick servlet: <tt>ruby public/dispatch.servlet --help</tt> +2. Go to http://rails/ (or whatever is your ServerName) and check + that you get the "Congratulations, you're on Rails!" screen +3. Follow the guidelines on the "Congratulations, you're on Rails!" screen + + +== Example for Apache conf + + <VirtualHost *:80> + ServerName rails + DocumentRoot /path/tapplication/public/ + ErrorLog /path/application/log/apache.log + + <Directory /path/application/public/> + Options ExecCGI FollowSymLinks + AllowOverride all + Allow from all + Order allow,deny + </Directory> + </VirtualHost> + +NOTE: Be sure that CGIs can be executed in that directory as well. So ExecCGI +should be on and ".cgi" should respond. All requests from 127.0.0.1 goes +through CGI, so no Apache restart is necessary for changes. All other requests +goes through FCGI (or mod_ruby) that requires restart to show changes. + + +== Debugging Rails + +Have "tail -f" commands running on both the apache.log, production.log, and +test.log files. Rails will automatically display debugging and runtime +information to these files. Debugging info will also be shown in the browser +on requests from 127.0.0.1. + + +== Description of contents + +app + Holds all the code that's specific to this particular application. + +app/controllers + Holds controllers that should be named like weblog_controller.rb for + automated URL mapping. All controllers should descend from + ActionController::Base. + +app/models + Holds models that should be named like post.rb. + Most models will descent from ActiveRecord::Base. + +app/views + Holds the template files for the view that should be named like + weblog/index.rhtml for the WeblogController#index action. All views uses eRuby + syntax. This directory can also be used to keep stylesheets, images, and so on + that can be symlinked to public. + +app/helpers + Holds view helpers that should be named like weblog_helper.rb. + +config + Configuration files for Apache, database, and other dependencies. + +lib + Application specific libraries. Basically, any kind of custom code that doesn't + belong controllers, models, or helpers. This directory is in the load path. + +public + The directory available for Apache, which includes symbolic links to other + parts of the structure that are to be made available. Refrain from placing + actual files in here if you're using CVS and don't want to check in this + directory. + +script + Helper scripts for automation and generation. + +test + Unit and functional tests along with fixtures. + +vendor + External libraries that the application depend on. This directory is in the load path. diff --git a/railties/Rakefile b/railties/Rakefile new file mode 100644 index 0000000000..aef5a4e884 --- /dev/null +++ b/railties/Rakefile @@ -0,0 +1,279 @@ +require 'rake' +require 'rake/testtask' +require 'rake/rdoctask' +require 'rake/gempackagetask' +require 'rake/contrib/rubyforgepublisher' + +require 'date' + + +PKG_BUILD = ENV['PKG_BUILD'] ? '.' + ENV['PKG_BUILD'] : '' +PKG_NAME = 'rails' +PKG_VERSION = '0.8.5' + PKG_BUILD +PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}" +PKG_DESTINATION = ENV["RAILS_PKG_DESTINATION"] || "../#{PKG_NAME}" + +desc "Default Task" +task :default => [ :fresh_rails ] + +desc "Generates a fresh Rails package with documentation" +task :fresh_rails => [ :make_dir_structure, :initialize_file_stubs, :copy_vendor_libraries, :copy_ties_content, :generate_documentation ] + +desc "Generates a fresh Rails package using GEMs with documentation" +task :fresh_gem_rails => [ :make_dir_structure, :initialize_file_stubs, :copy_ties_content, :copy_gem_environment ] + +desc "Generates a fresh Rails package without documentation (faster)" +task :fresh_rails_without_docs => [ :make_dir_structure, :initialize_file_stubs, :copy_vendor_libraries, :copy_ties_content ] + +desc "Packages the fresh Rails package with documentation" +task :package => [ :clean, :fresh_rails ] do + system %{cd ..; tar -czvf #{PKG_NAME}-#{PKG_VERSION}.tgz #{PKG_NAME}} + system %{cd ..; zip -r #{PKG_NAME}-#{PKG_VERSION}.zip #{PKG_NAME}} +end + +task :clean do + File.rm_rf "#{PKG_DESTINATION}" +end + + +# Make directory structure ---------------------------------------------------------------- + +desc "Make the directory structure for the new Rails application" +task :make_dir_structure => [ :make_base_dirs, :make_app_dirs, :make_public_dirs, :make_test_dirs ] do +end + +task :make_base_dirs do + File.rm_rf PKG_DESTINATION + File.mkdir "#{PKG_DESTINATION}" + File.mkdir "#{PKG_DESTINATION}/app" + File.mkdir "#{PKG_DESTINATION}/config" + File.mkdir "#{PKG_DESTINATION}/config/environments" + File.mkdir "#{PKG_DESTINATION}/db" + File.mkdir "#{PKG_DESTINATION}/doc" + File.mkdir "#{PKG_DESTINATION}/log" + File.mkdir "#{PKG_DESTINATION}/lib" + File.mkdir "#{PKG_DESTINATION}/public" + File.mkdir "#{PKG_DESTINATION}/script" + File.mkdir "#{PKG_DESTINATION}/test" + File.mkdir "#{PKG_DESTINATION}/vendor" +end + +task :make_app_dirs do + File.mkdir "#{PKG_DESTINATION}/app/models" + File.mkdir "#{PKG_DESTINATION}/app/controllers" + File.mkdir "#{PKG_DESTINATION}/app/helpers" + File.mkdir "#{PKG_DESTINATION}/app/views" + File.mkdir "#{PKG_DESTINATION}/app/views/layouts" +end + +task :make_public_dirs do + File.mkdir "#{PKG_DESTINATION}/public/images" + File.mkdir "#{PKG_DESTINATION}/public/javascripts" + File.mkdir "#{PKG_DESTINATION}/public/stylesheets" + File.mkdir "#{PKG_DESTINATION}/public/_doc" +end + +task :make_test_dirs do + File.mkdir "#{PKG_DESTINATION}/test/fixtures" + File.mkdir "#{PKG_DESTINATION}/test/unit" + File.mkdir "#{PKG_DESTINATION}/test/functional" + File.mkdir "#{PKG_DESTINATION}/test/mocks/development" + File.mkdir "#{PKG_DESTINATION}/test/mocks/testing" +end + + +# Initialize file stubs ------------------------------------------------------------------- + +desc "Initialize empty file stubs (such as for logging)" +task :initialize_file_stubs => [ :initialize_log_files ] do +end + +task :initialize_log_files do + chmod 0777, "#{PKG_DESTINATION}/log" + + File.touch "#{PKG_DESTINATION}/log/apache.log" + File.touch "#{PKG_DESTINATION}/log/production.log" + + chmod 0777, "#{PKG_DESTINATION}/log/apache.log" + chmod 0777, "#{PKG_DESTINATION}/log/production.log" +end + + +# Copy Vendors ---------------------------------------------------------------------------- + +desc "Copy in all the Rails packages to vendor" +task :copy_vendor_libraries => [ :copy_action_pack, :copy_active_record, :copy_ties, :copy_action_mailer ] + +task :copy_action_pack do + File.cp_r "../actionpack", "#{PKG_DESTINATION}/vendor/actionpack" +end + +task :copy_active_record do + File.cp_r "../activerecord", "#{PKG_DESTINATION}/vendor/activerecord" +end + +task :copy_action_mailer do + File.cp_r "../actionmailer", "#{PKG_DESTINATION}/vendor/actionmailer" +end + +task :copy_ties do + File.cp_r "../railties", "#{PKG_DESTINATION}/vendor/railties" +end + + +# Copy Ties Content ----------------------------------------------------------------------- + +# :link_apache_config +desc "Make copies of all the default content of ties" +task :copy_ties_content => [ + :copy_rootfiles, :copy_dispatches, :copy_html_files, :copy_abstract_application, + :copy_configs, :copy_generators, :copy_test_helpers, :copy_docs_in_public, + :copy_app_doc_readme ] do +end + +task :copy_dispatches do + File.cp "dispatches/dispatch.rb", "#{PKG_DESTINATION}/public/dispatch.rb" + chmod 0755, "#{PKG_DESTINATION}/public/dispatch.rb" + + File.cp "dispatches/dispatch.rb", "#{PKG_DESTINATION}/public/dispatch.cgi" + chmod 0755, "#{PKG_DESTINATION}/public/dispatch.cgi" + + File.cp "dispatches/dispatch.fcgi", "#{PKG_DESTINATION}/public/dispatch.fcgi" + chmod 0755, "#{PKG_DESTINATION}/public/dispatch.fcgi" + + File.cp "dispatches/dispatch.servlet", "#{PKG_DESTINATION}/public/dispatch.servlet" + + File.cp "dispatches/start_server", "#{PKG_DESTINATION}/start_server" + chmod 0755, "#{PKG_DESTINATION}/start_server" +end + +task :copy_html_files do + File.cp "html/404.html", "#{PKG_DESTINATION}/public/404.html" + File.cp "html/500.html", "#{PKG_DESTINATION}/public/500.html" + File.cp "html/index.html", "#{PKG_DESTINATION}/public/index.html" +end + +task :copy_abstract_application do + File.cp "helpers/abstract_application.rb", "#{PKG_DESTINATION}/app/controllers/abstract_application.rb" + File.cp "helpers/application_helper.rb", "#{PKG_DESTINATION}/app/helpers/application_helper.rb" +end + +task :copy_configs do + File.cp "configs/database.yml", "#{PKG_DESTINATION}/config/database.yml" + + File.cp "configs/apache.conf", "#{PKG_DESTINATION}/public/.htaccess" + + File.cp "environments/shared.rb", "#{PKG_DESTINATION}/config/environment.rb" + File.cp "environments/production.rb", "#{PKG_DESTINATION}/config/environments/production.rb" + File.cp "environments/development.rb", "#{PKG_DESTINATION}/config/environments/development.rb" + File.cp "environments/test.rb", "#{PKG_DESTINATION}/config/environments/test.rb" +end + +task :copy_generators do + File.cp "generators/new_controller.rb", "#{PKG_DESTINATION}/script/new_controller" + File.cp "generators/new_model.rb", "#{PKG_DESTINATION}/script/new_model" + File.cp "generators/new_mailer.rb", "#{PKG_DESTINATION}/script/new_mailer" + File.cp "generators/new_crud.rb", "#{PKG_DESTINATION}/script/new_crud" + chmod 0755, "#{PKG_DESTINATION}/script/new_controller" + chmod 0755, "#{PKG_DESTINATION}/script/new_model" + chmod 0755, "#{PKG_DESTINATION}/script/new_mailer" + chmod 0755, "#{PKG_DESTINATION}/script/new_crud" +end + +task :copy_rootfiles do + File.cp "fresh_rakefile", "#{PKG_DESTINATION}/Rakefile" + File.cp "README", "#{PKG_DESTINATION}/README" +end + +task :copy_test_helpers do + File.cp "helpers/test_helper.rb", "#{PKG_DESTINATION}/test/test_helper.rb" +end + +task :copy_docs_in_public do + File.cp "doc/index.html", "#{PKG_DESTINATION}/public/_doc/index.html" +end + +task :copy_app_doc_readme do + File.cp "doc/README_FOR_APP", "#{PKG_DESTINATION}/doc/README_FOR_APP" +end + +task :link_apache_config do + cd "#{PKG_DESTINATION}/config/" + ln_s "../public/.htaccess", "apache.conf" + cd "../../railties" +end + + +# Generate documentation ------------------------------------------------------------------ + +desc "Generate documentation for the framework and for the empty application" +task :generate_documentation => [ :generate_app_doc, :generate_rails_framework_doc ] do +end + +task :generate_rails_framework_doc do + system %{cd #{PKG_DESTINATION}; rake apidoc} +end + +task :generate_app_doc do + File.cp "doc/README_FOR_APP", "#{PKG_DESTINATION}/doc/README_FOR_APP" + system %{cd #{PKG_DESTINATION}; rake appdoc} +end + + +# Generate GEM ---------------------------------------------------------------------------- + +task :copy_gem_environment do + File.cp "environments/shared_for_gem.rb", "#{PKG_DESTINATION}/config/environment.rb" +end + + +PKG_FILES = FileList[ + '[a-zA-Z]*', + 'bin/**/*', + 'configs/**/*', + 'doc/**/*', + 'dispatches/**/*', + 'environments/**/*', + 'generators/**/*', + 'helpers/**/*', + 'html/**/*', + 'lib/**/*' +] + +spec = Gem::Specification.new do |s| + s.name = 'rails' + s.version = PKG_VERSION + s.summary = "Web-application framework with template engine, control-flow layer, and ORM." + s.description = <<-EOF + Rails is a framework for building web-application using CGI, FCGI, mod_ruby, or WEBrick + on top of either MySQL, PostgreSQL, or SQLite with eRuby-based templates. + EOF + + s.add_dependency('rake', '>= 0.4.11') + s.add_dependency('activerecord', '>= 1.1.0') + s.add_dependency('actionpack', '>= 0.9.5') + s.add_dependency('actionmailer', '>= 0.4.0') + s.add_dependency('dev-utils', '>= 1.0.1') + + s.files = PKG_FILES.to_a + s.require_path = 'lib' + + s.bindir = "bin" # Use these for applications. + s.executables = ["rails"] + s.default_executable = "rails" + + s.author = "David Heinemeier Hansson" + s.email = "david@loudthinking.com" + s.homepage = "http://www.rubyonrails.org" + s.rubyforge_project = "rails" +end + +Rake::GemPackageTask.new(spec) do |pkg| +end + +# Publish beta gem +desc "Publish the API documentation" +task :pgem => [:gem] do + Rake::SshFilePublisher.new("davidhh@one.textdrive.com", "domains/rubyonrails.org/gems/gems", "pkg", "#{PKG_FILE_NAME}.gem").upload + `ssh davidhh@one.textdrive.com './gemupdate.sh'` +end
\ No newline at end of file diff --git a/railties/bin/rails b/railties/bin/rails new file mode 100755 index 0000000000..846f02ac69 --- /dev/null +++ b/railties/bin/rails @@ -0,0 +1,28 @@ +if ARGV[0] + ENV["RAILS_PKG_DESTINATION"] = File.expand_path(ARGV[0]) + if RUBY_PLATFORM =~ /mswin32/ + Dir.chdir File.dirname(__FILE__) + system %{rake.cmd fresh_gem_rails} + else + system %{ cd #{File.dirname(__FILE__)}; rake fresh_gem_rails } + end +else + puts <<-HELP + +NAME + rails - creates a new Rails installation + +SYNOPSIS + rails [full path] + +DESCRIPTION + This generator will create a suggested directory structure, lots of minor helper + files, and a default configuration for creating a new Rails application. Once the + generator is done, you're adviced to look at the README in the root of the folder. + +EXAMPLE + rails ~/Code/Ruby/weblog + + This will generate a new Rails installation in the ~/Code/Ruby/weblog folder. +HELP +end
\ No newline at end of file diff --git a/railties/configs/apache.conf b/railties/configs/apache.conf new file mode 100755 index 0000000000..feb2e32c4e --- /dev/null +++ b/railties/configs/apache.conf @@ -0,0 +1,31 @@ +# General Apache options +AddHandler fastcgi-script .fcgi +AddHandler cgi-script .cgi +Options +FollowSymLinks +ExecCGI + +# Make sure that mod_ruby.c has been added and loaded as a module with Apache +RewriteEngine On + +# Change extension from .cgi to .fcgi to switch to FCGI and to .rb to switch to mod_ruby +RewriteBase /dispatch.cgi + +RewriteRule ^dispatch.servlet$ / [R] + +# Enable this rewrite rule to point to the controller/action that should serve root. +# RewriteRule ^$ /controller/action + +# Add missing slash +RewriteRule ^([-_a-zA-Z0-9]+)$ /$1/ [R] + +# Default rewriting rules. +RewriteRule ^([-_a-zA-Z0-9]+)/([-_a-zA-Z0-9]+)/([0-9]+)$ ?controller=$1&action=$2&id=$3 [QSA,L] +RewriteRule ^([-_a-zA-Z0-9]+)/([-_a-zA-Z0-9]+)$ ?controller=$1&action=$2 [QSA,L] +RewriteRule ^([-_a-zA-Z0-9]+)/$ ?controller=$1&action=index [QSA,L] + +RewriteRule ^([-_a-zA-Z0-9]+)/([-_a-zA-Z0-9]+)/([-_a-zA-Z0-9]+)/([0-9]+)$ ?module=$1&controller=$2&action=$3&id=$4 [QSA,L] +RewriteRule ^([-_a-zA-Z0-9]+)/([-_a-zA-Z0-9]+)/([-_a-zA-Z0-9]+)$ ?module=$1&controller=$2&action=$3 [QSA,L] +RewriteRule ^([-_a-zA-Z0-9]+)/([-_a-zA-Z0-9]+)/$ ?module=$1&controller=$2&action=index [QSA,L] + +# You can also point these error messages to a controller/action +ErrorDocument 500 /500.html +ErrorDocument 404 /404.html
\ No newline at end of file diff --git a/railties/configs/database.yml b/railties/configs/database.yml new file mode 100644 index 0000000000..0f9a7eb20e --- /dev/null +++ b/railties/configs/database.yml @@ -0,0 +1,20 @@ +development: + adapter: mysql + database: rails_development + host: localhost + username: root + password: + +test: + adapter: mysql + database: rails_test + host: localhost + username: root + password: + +production: + adapter: mysql + database: rails_production + host: localhost + username: root + password: diff --git a/railties/dispatches/dispatch.fcgi b/railties/dispatches/dispatch.fcgi new file mode 100755 index 0000000000..dc43f03b19 --- /dev/null +++ b/railties/dispatches/dispatch.fcgi @@ -0,0 +1,7 @@ +#!/usr/local/bin/ruby + +require File.dirname(__FILE__) + "/../config/environment" +require 'dispatcher' +require 'fcgi' + +FCGI.each_cgi { |cgi| Dispatcher.dispatch(cgi, Dispatcher::DEFAULT_SESSION_OPTIONS, File.dirname(__FILE__) + "/500.html") }
\ No newline at end of file diff --git a/railties/dispatches/dispatch.rb b/railties/dispatches/dispatch.rb new file mode 100755 index 0000000000..eb2c95e813 --- /dev/null +++ b/railties/dispatches/dispatch.rb @@ -0,0 +1,10 @@ +#!/usr/local/bin/ruby + +require File.dirname(__FILE__) + "/../config/environment" + +# If you're using RubyGems and mod_ruby, this require should be changed to an absolute path one, like: +# "/usr/local/lib/ruby/gems/1.8/gems/rails-0.8.0/lib/dispatcher" -- otherwise performance is severely impaired +require "dispatcher" + +ADDITIONAL_LOAD_PATHS.flatten.each { |dir| $:.unshift "#{RAILS_ROOT}/#{dir}" } +Dispatcher.dispatch
\ No newline at end of file diff --git a/railties/dispatches/dispatch.servlet b/railties/dispatches/dispatch.servlet new file mode 100644 index 0000000000..a1fa403a67 --- /dev/null +++ b/railties/dispatches/dispatch.servlet @@ -0,0 +1,49 @@ +#!/usr/local/bin/ruby + +require 'webrick' +require 'optparse' + +OPTIONS = { + :port => 3000, + :ip => "127.0.0.1", + :environment => "development", + :server_root => File.expand_path(File.dirname(__FILE__)), + :server_type => WEBrick::SimpleServer +} + +ARGV.options do |opts| + script_name = File.basename($0) + opts.banner = "Usage: ruby #{script_name} [options]" + + opts.separator "" + + opts.on("-p", "--port=port", Integer, + "Runs Rails on the specified port.", + "Default: 3000") { |OPTIONS[:port]| } + opts.on("-b", "--binding=ip", String, + "Binds Rails to the specified ip.", + "Default: 127.0.0.1") { |OPTIONS[:ip]| } + opts.on("-i", "--index=controller", String, + "Specifies an index controller that requests for root will go to (instead of congratulations screen)." + ) { |OPTIONS[:index_controller]| } + opts.on("-e", "--environment=name", String, + "Specifies the environment to run this server under (test/development/production).", + "Default: development") { |OPTIONS[:environment]| } + opts.on("-d", "--daemon", + "Make Rails run as a Daemon (only works if fork is available -- meaning on *nix)." + ) { OPTIONS[:server_type] = WEBrick::Daemon } + + opts.separator "" + + opts.on("-h", "--help", + "Show this help message.") { puts opts; exit } + + opts.parse! +end + +ENV["RAILS_ENV"] = OPTIONS[:environment] +require File.dirname(__FILE__) + "/../config/environment" +require 'webrick_server' + +puts "=> Rails application started on http://#{OPTIONS[:ip]}:#{OPTIONS[:port]}" +DispatchServlet.dispatch(OPTIONS)
\ No newline at end of file diff --git a/railties/dispatches/start_server b/railties/dispatches/start_server new file mode 100644 index 0000000000..c6ecb4e4fe --- /dev/null +++ b/railties/dispatches/start_server @@ -0,0 +1 @@ +ruby public/dispatch.servlet
\ No newline at end of file diff --git a/railties/doc/README_FOR_APP b/railties/doc/README_FOR_APP new file mode 100644 index 0000000000..ac6c149122 --- /dev/null +++ b/railties/doc/README_FOR_APP @@ -0,0 +1,2 @@ +Use this README file to introduce your application and point to useful places in the API for learning more. +Run "rake appdoc" to generate API documentation for your models and controllers.
\ No newline at end of file diff --git a/railties/doc/apache_protection b/railties/doc/apache_protection new file mode 100644 index 0000000000..37676c2c63 --- /dev/null +++ b/railties/doc/apache_protection @@ -0,0 +1,3 @@ +Order Deny,Allow +Deny from all +Allow from 127.0.0.1
\ No newline at end of file diff --git a/railties/doc/index.html b/railties/doc/index.html new file mode 100644 index 0000000000..57e25b75fa --- /dev/null +++ b/railties/doc/index.html @@ -0,0 +1,94 @@ +<html> +<head> + <title>Rails: Welcome on board</title> + <style> + body { background-color: #fff; color: #333; } + + body, p, ol, ul, td { + font-family: verdana, arial, helvetica, sans-serif; + font-size: 12px; + line-height: 18px; + } + + li { + margin-bottom: 7px; + } + + pre { + background-color: #eee; + padding: 10px; + font-size: 11px; + } + + a { color: #000; } + a:visited { color: #666; } + a:hover { color: #fff; background-color:#000; } + </style> +</head> +<body> + +<h1>Congratulations, you're on Rails!</h1> + +<p> + <i>You've succesfully configured your web server to point at this Rails application.</i> +</p> + +<p>Before you move on, verify that the following conditions have been met:</p> + +<ol> + <li>The log directory and the empty log files must be writable to the web server (<code>chmod -R 777 log</code>). + <li> + The shebang line in the public/dispatch* files must reference your Ruby installation. <br/> + You might need to change it to <code>#!/usr/bin/env ruby</code> or point directly at the installation. + </li> + <li> + Rails on Apache needs to have the cgi handler and mod_rewrite enabled. <br/> + Somewhere in your httpd.conf, you should have:<br/> + <code>AddHandler cgi-script .cgi</code><br/> + <code>LoadModule rewrite_module libexec/httpd/mod_rewrite.so</code><br/> + <code>AddModule mod_rewrite.c</code> + </li> +</ol> + +<p>Take the following steps to get started:</p> + +<ol> + <li>Create empty production and test databases for your application.<br/> + <small>Warning: Don't point your test database at your production database, it'll destroy the latter on test runs!</small> + <li>Edit config/database.yml with your database settings. + <li>Create a new controller using the <code>script/new_controller</code> generator <br/> + <small>Help: Run with no arguments for documentation</small> + <li>Create a new model using the <code>script/new_model</code> generator <br/> + <small>Help: Run with no arguments for documentation</small> + <li>See all the tests run and fail by running <code>rake</code>. + <li>Develop your Rails application! + <li>Setup FastCGI or mod_ruby to get production-level performance +</ol> + +<p> + Having problems getting up and running? First try debugging it yourself by looking at the log files. <br/> Then try the friendly Rails + community on IRC (<a href="http://www.rubyonrails.org/show/IRC">howto IRC</a>). It's on FreeNET in channel #rubyonrails. +</p> + +<div style="float: left; margin-right: 20px"> + <h2>Rails Online</h2> + + <ul> + <li><a href="http://www.rubyonrails.org">Ruby on Rails</a></li> + <li><a href="http://activerecord.rubyonrails.org">Active Record</a></li> + <li><a href="http://actionpack.rubyonrails.org">Action Pack</a></li> + </ul> +</div> + +<div style="float: left"> + <h2>Beyond CGI</h2> + + <ul> + <li><a href="http://www.fastcgi.com">FastCGI</a></li> + <li><a href="http://raa.ruby-lang.org/list.rhtml?name=fcgi">FastCGI bindings for Ruby</a></li> + <li><a href="http://modruby.net/en/">mod_ruby</a></li> + </ul> +</div> + +</body> +</html>
\ No newline at end of file diff --git a/railties/environments/development.rb b/railties/environments/development.rb new file mode 100644 index 0000000000..81d5a73403 --- /dev/null +++ b/railties/environments/development.rb @@ -0,0 +1,2 @@ +ActiveRecord::Base.logger = ActionController::Base.logger = ActionMailer::Base.logger = Logger.new("#{RAILS_ROOT}/log/development.log") +ActiveRecord::Base.establish_connection(:development)
\ No newline at end of file diff --git a/railties/environments/production.rb b/railties/environments/production.rb new file mode 100644 index 0000000000..1ecda598de --- /dev/null +++ b/railties/environments/production.rb @@ -0,0 +1,6 @@ +ActiveRecord::Base.logger = ActionController::Base.logger = ActionMailer::Base.logger = Logger.new("#{RAILS_ROOT}/log/production.log") +ActiveRecord::Base.establish_connection(:production) + +ActionController::Base.consider_all_requests_local = false +ActionController::Base.reload_dependencies = false +ActiveRecord::Base.reload_associations = false
\ No newline at end of file diff --git a/railties/environments/shared.rb b/railties/environments/shared.rb new file mode 100644 index 0000000000..f5d4771db6 --- /dev/null +++ b/railties/environments/shared.rb @@ -0,0 +1,35 @@ +RAILS_ROOT = File.expand_path(File.dirname(__FILE__) + "/../") +RAILS_ENV = ENV['RAILS_ENV'] || 'development' + +ADDITIONAL_LOAD_PATHS = [ + "app/models", + "app/controllers", + "app/helpers", + "app", + "config", + "lib", + "vendor", + "vendor/railties", + "vendor/railties/lib", + "vendor/activerecord/lib", + "vendor/actionpack/lib", + "vendor/actionmailer/lib", +] + +ADDITIONAL_LOAD_PATHS.unshift(Dir["#{RAILS_ROOT}/app/models/[a-z]*"].collect{ |dir| "app/models/#{File.basename(dir)}" }) +ADDITIONAL_LOAD_PATHS.unshift("test/mocks/#{RAILS_ENV}") + +ADDITIONAL_LOAD_PATHS.flatten.each { |dir| $: << "#{RAILS_ROOT}/#{dir}" } + + +require 'active_record' +require 'action_controller' +require 'action_mailer' + +require 'yaml' + +ActionController::Base.template_root = ActionMailer::Base.template_root = "#{RAILS_ROOT}/app/views/" +ActiveRecord::Base.configurations = YAML::load(File.open("#{RAILS_ROOT}/config/database.yml")) + +ActionController::Base.require_or_load 'abstract_application' +ActionController::Base.require_or_load "environments/#{RAILS_ENV}"
\ No newline at end of file diff --git a/railties/environments/shared_for_gem.rb b/railties/environments/shared_for_gem.rb new file mode 100644 index 0000000000..1ae6746122 --- /dev/null +++ b/railties/environments/shared_for_gem.rb @@ -0,0 +1,23 @@ +RAILS_ROOT = File.expand_path(File.dirname(__FILE__) + "/../") +RAILS_ENV = ENV['RAILS_ENV'] || 'development' + +ADDITIONAL_LOAD_PATHS = [ "app/models", "app/controllers", "app/helpers", "config", "lib", "vendor" ] +ADDITIONAL_LOAD_PATHS.unshift(Dir["#{RAILS_ROOT}/app/models/[a-z]*"].collect{ |dir| "app/models/#{File.basename(dir)}" }) +ADDITIONAL_LOAD_PATHS.unshift("test/mocks/#{RAILS_ENV}") + +ADDITIONAL_LOAD_PATHS.flatten.each { |dir| $:.unshift "#{RAILS_ROOT}/#{dir}" } + +require 'rubygems' + +require_gem 'activerecord' +require_gem 'actionpack' +require_gem 'actionmailer' +require_gem 'rails' + +require 'yaml' + +ActionController::Base.template_root = ActionMailer::Base.template_root = "#{RAILS_ROOT}/app/views/" +ActiveRecord::Base.configurations = YAML::load(File.open("#{RAILS_ROOT}/config/database.yml")) + +ActionController::Base.require_or_load 'abstract_application' +ActionController::Base.require_or_load "environments/#{RAILS_ENV}" diff --git a/railties/environments/test.rb b/railties/environments/test.rb new file mode 100644 index 0000000000..6ab6a1f50a --- /dev/null +++ b/railties/environments/test.rb @@ -0,0 +1,2 @@ +ActiveRecord::Base.logger = ActionController::Base.logger = ActionMailer::Base.logger = Logger.new("#{RAILS_ROOT}/log/test.log") +ActiveRecord::Base.establish_connection(:test) diff --git a/railties/fresh_rakefile b/railties/fresh_rakefile new file mode 100755 index 0000000000..3b746a49a5 --- /dev/null +++ b/railties/fresh_rakefile @@ -0,0 +1,104 @@ +require 'rake' +require 'rake/testtask' +require 'rake/rdoctask' + +$VERBOSE = nil + +require File.dirname(__FILE__) + '/config/environment' +require 'code_statistics' + +desc "Run all the tests on a fresh test database" +task :default => [ :clone_development_structure_to_test, :test_units, :test_functional ] + +desc "Generate API documentatio, show coding stats" +task :doc => [ :appdoc, :stats ] + + +desc "Run the unit tests in test/unit" +Rake::TestTask.new("test_units") { |t| + t.libs << "test" + t.pattern = 'test/unit/*_test.rb' + t.verbose = true +} + +desc "Run the functional tests in test/functional" +Rake::TestTask.new("test_functional") { |t| + t.libs << "test" + t.pattern = 'test/functional/*_test.rb' + t.verbose = true +} + +desc "Generate documentation for the application" +Rake::RDocTask.new("appdoc") { |rdoc| + rdoc.rdoc_dir = 'doc/app' + rdoc.title = "Rails Application Documentation" + rdoc.options << '--line-numbers --inline-source' + rdoc.rdoc_files.include('doc/README_FOR_APP') + rdoc.rdoc_files.include('app/**/*.rb') +} + +desc "Generate documentation for the Rails framework" +Rake::RDocTask.new("apidoc") { |rdoc| + rdoc.rdoc_dir = 'doc/api' + rdoc.title = "Rails Framework Documentation" + rdoc.options << '--line-numbers --inline-source' + rdoc.rdoc_files.include('README') + rdoc.rdoc_files.include('vendor/railties/CHANGELOG') + rdoc.rdoc_files.include('vendor/railties/MIT-LICENSE') + rdoc.rdoc_files.include('vendor/activerecord/README') + rdoc.rdoc_files.include('vendor/activerecord/CHANGELOG') + rdoc.rdoc_files.include('vendor/activerecord/lib/active_record/**/*.rb') + rdoc.rdoc_files.exclude('vendor/activerecord/lib/active_record/vendor/*') + rdoc.rdoc_files.include('vendor/actionpack/README') + rdoc.rdoc_files.include('vendor/actionpack/CHANGELOG') + rdoc.rdoc_files.include('vendor/actionpack/lib/action_controller/**/*.rb') + rdoc.rdoc_files.include('vendor/actionpack/lib/action_view/**/*.rb') + rdoc.rdoc_files.include('vendor/actionmailer/README') + rdoc.rdoc_files.include('vendor/actionmailer/CHANGELOG') + rdoc.rdoc_files.include('vendor/actionmailer/lib/action_mailer/base.rb') +} + +desc "Report code statistics (KLOCs, etc) from the application" +task :stats do + CodeStatistics.new( + ["Controllers", "app/controllers"], + ["Helpers", "app/helpers"], + ["Models", "app/models"], + ["Units", "test/unit"], + ["Functionals", "test/functional"] + ).to_s +end + +desc "Recreate the test databases from the development structure" +task :clone_development_structure_to_test => [ :db_structure_dump, :purge_test_database ] do + if ActiveRecord::Base.configurations["test"]["adapter"] == "mysql" + ActiveRecord::Base.establish_connection(:test) + ActiveRecord::Base.connection.execute('SET foreign_key_checks = 0') + IO.readlines("db/development_structure.sql").join.split("\n\n").each do |table| + ActiveRecord::Base.connection.execute(table) + end + elsif ActiveRecord::Base.configurations["test"]["adapter"] == "postgresql" + `psql -U #{ActiveRecord::Base.configurations["test"]["username"]} -f db/development_structure.sql #{ActiveRecord::Base.configurations["test"]["database"]}` + end +end + +desc "Dump the database structure to a SQL file" +task :db_structure_dump do + if ActiveRecord::Base.configurations["test"]["adapter"] == "mysql" + ActiveRecord::Base.establish_connection(ActiveRecord::Base.configurations["test"]) + File.open("db/development_structure.sql", "w+") { |f| f << ActiveRecord::Base.connection.structure_dump } + elsif ActiveRecord::Base.configurations["test"]["adapter"] == "postgresql" + `pg_dump -U #{ActiveRecord::Base.configurations["test"]["username"]} -s -f db/development_structure.sql #{ActiveRecord::Base.configurations["test"]["database"]}` + end +end + +desc "Drop the test database and bring it back again" +task :purge_test_database do + if ActiveRecord::Base.configurations["test"]["adapter"] == "mysql" + ActiveRecord::Base.establish_connection(ActiveRecord::Base.configurations["development"]) + ActiveRecord::Base.connection.recreate_database(ActiveRecord::Base.configurations["test"]["database"]) + elsif ActiveRecord::Base.configurations["test"]["adapter"] == "postgresql" + `dropdb -U #{ActiveRecord::Base.configurations["test"]["username"]} #{ActiveRecord::Base.configurations["test"]["database"]}` + `createdb -U #{ActiveRecord::Base.configurations["test"]["username"]} #{ActiveRecord::Base.configurations["test"]["database"]}` + end +end diff --git a/railties/generators/new_controller.rb b/railties/generators/new_controller.rb new file mode 100755 index 0000000000..3060c06382 --- /dev/null +++ b/railties/generators/new_controller.rb @@ -0,0 +1,43 @@ +#!/usr/local/bin/ruby +require File.dirname(__FILE__) + '/../config/environment' +require 'generator' + +unless ARGV.empty? + rails_root = File.dirname(__FILE__) + '/..' + name = ARGV.shift + actions = ARGV + Generator::Controller.new(rails_root, name, actions).generate +else + puts <<-END_HELP + +NAME + new_controller - create controller and view stub files + +SYNOPSIS + new_controller ControllerName action [action ...] + +DESCRIPTION + The new_controller generator takes the name of the new controller as the + first argument and a variable number of view names as subsequent arguments. + The controller name should be supplied without a "Controller" suffix. The + generator will add that itself. + + From the passed arguments, new_controller generates a controller file in + app/controllers with a render action for each of the view names passed. + It then creates a controller test suite in test/functional with one failing + test case. Finally, it creates an HTML stub for each of the view names in + app/views under a directory with the same name as the controller. + +EXAMPLE + new_controller Blog list display new edit + + This will generate a BlogController class in + app/controllers/blog_controller.rb, a BlogHelper class in + app/helpers/blog_helper.rb and a BlogControllerTest in + test/functional/blog_controller_test.rb. It will also create list.rhtml, + display.rhtml, new.rhtml, and edit.rhtml in app/views/blog. + + The BlogController class will have the following methods: list, display, new, edit. + Each will default to render the associated template file. +END_HELP +end diff --git a/railties/generators/new_crud.rb b/railties/generators/new_crud.rb new file mode 100755 index 0000000000..4eaa1cb1f3 --- /dev/null +++ b/railties/generators/new_crud.rb @@ -0,0 +1,34 @@ +#!/usr/local/bin/ruby +require File.dirname(__FILE__) + '/../config/environment' +require 'generator' + +unless ARGV.empty? + rails_root = File.dirname(__FILE__) + '/..' + name = ARGV.shift + actions = ARGV + Generator::Model.new(rails_root, name).generate + Generator::Controller.new(rails_root, name, actions, :scaffold => true).generate +else + puts <<-END_HELP + +NAME + new_crud - create a model and a controller scaffold + +SYNOPSIS + new_crud ModelName [action ...] + +DESCRIPTION + The new_crud generator takes the name of the new model as the + first argument and an optional list of controller actions as the + subsequent arguments. All actions may be omitted since the controller + will have scaffolding automatically set up for this model. + +EXAMPLE + new_crud Account + + This will generate an Account model and controller with scaffolding. + Now create the accounts table in your database and browse to + http://localhost/account/ -- voila, you're on Rails! + +END_HELP +end diff --git a/railties/generators/new_mailer.rb b/railties/generators/new_mailer.rb new file mode 100644 index 0000000000..05d0c9ae82 --- /dev/null +++ b/railties/generators/new_mailer.rb @@ -0,0 +1,43 @@ +#!/usr/local/bin/ruby +require File.dirname(__FILE__) + '/../config/environment' +require 'generator' + +unless ARGV.empty? + rails_root = File.dirname(__FILE__) + '/..' + name = ARGV.shift + actions = ARGV + Generator::Mailer.new(rails_root, name, actions).generate +else + puts <<-END_HELP + +NAME + new_mailer - create mailer and view stub files + +SYNOPSIS + new_mailer MailerName action [action ...] + +DESCRIPTION + The new_mailer generator takes the name of the new mailer class as the + first argument and a variable number of mail action names as subsequent + arguments. + + From the passed arguments, new_mailer generates a class file in + app/models with a mail action for each of the mail action names passed. + It then creates a mail test suite in test/unit with one stub test case + and one stub fixture per mail action. Finally, it creates a template stub + for each of the mail action names in app/views under a directory with the + same name as the class. + +EXAMPLE + new_mailer Notifications signup forgot_password invoice + + This will generate a Notifications class in + app/models/notifications.rb, a NotificationsTest in + test/unit/notifications_test.rb, and signup, forgot_password, and invoice + in test/fixture/notification. It will also create signup.rhtml, + forgot_password.rhtml, and invoice.rhtml in app/views/notifications. + + The Notifications class will have the following methods: signup, + forgot_password, and invoice. +END_HELP +end diff --git a/railties/generators/new_model.rb b/railties/generators/new_model.rb new file mode 100755 index 0000000000..f6fbf5f002 --- /dev/null +++ b/railties/generators/new_model.rb @@ -0,0 +1,31 @@ +#!/usr/local/bin/ruby +require File.dirname(__FILE__) + '/../config/environment' +require 'generator' + +if ARGV.size == 1 + rails_root = File.dirname(__FILE__) + '/..' + name = ARGV.shift + Generator::Model.new(rails_root, name).generate +else + puts <<-HELP + +NAME + new_model - create model stub files + +SYNOPSIS + new_model ModelName + +DESCRIPTION + The new_model generator takes a model name (in CamelCase) and generates + a new, empty model in app/models, a test suite in test/unit with one + failing test case, and a fixtures directory in test/fixtures. + +EXAMPLE + new_model Account + + This will generate an Account class in app/models/account.rb, an + AccountTest in test/unit/account_test.rb, and the directory + test/fixtures/account. + +HELP +end diff --git a/railties/generators/templates/controller.erb b/railties/generators/templates/controller.erb new file mode 100644 index 0000000000..600f5d2c59 --- /dev/null +++ b/railties/generators/templates/controller.erb @@ -0,0 +1,19 @@ +class <%= class_name %>Controller < AbstractApplicationController + helper :<%= file_name %> +<% if options[:scaffold] -%> + model :<%= file_name %> + scaffold :<%= options[:scaffold] %> + + <%- for action in actions -%> + #def <%= action %> + #end + + <%- end -%> +<% else -%> + <%- for action in actions -%> + def <%= action %> + end + + <%- end -%> +<% end -%> +end diff --git a/railties/generators/templates/controller_test.erb b/railties/generators/templates/controller_test.erb new file mode 100644 index 0000000000..5577379c62 --- /dev/null +++ b/railties/generators/templates/controller_test.erb @@ -0,0 +1,17 @@ +require File.dirname(__FILE__) + '/../test_helper' +require '<%= file_name %>_controller' + +# Re-raise errors caught by the controller. +class <%= class_name %>Controller; def rescue_action(e) raise e end; end + +class <%= class_name %>ControllerTest < Test::Unit::TestCase + def setup + @controller = <%= class_name %>Controller.new + @request, @response = ActionController::TestRequest.new, ActionController::TestResponse.new + end + + # Replace this with your real tests + def test_truth + assert true + end +end diff --git a/railties/generators/templates/controller_view.rhtml b/railties/generators/templates/controller_view.rhtml new file mode 100644 index 0000000000..d8a310df50 --- /dev/null +++ b/railties/generators/templates/controller_view.rhtml @@ -0,0 +1,10 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> +<head> + <title><%= class_name %>#<%= action %></title> +</head> +<body> +<h1><%= class_name %>#<%= action %></h1> +<p>Find me in app/views/<%= file_name %>/<%= action %>.rhtml</p> +</body> +</html> diff --git a/railties/generators/templates/helper.erb b/railties/generators/templates/helper.erb new file mode 100644 index 0000000000..3fe2ecdc74 --- /dev/null +++ b/railties/generators/templates/helper.erb @@ -0,0 +1,2 @@ +module <%= class_name %>Helper +end diff --git a/railties/generators/templates/mailer.erb b/railties/generators/templates/mailer.erb new file mode 100644 index 0000000000..5afc254923 --- /dev/null +++ b/railties/generators/templates/mailer.erb @@ -0,0 +1,15 @@ +require 'action_mailer' + +class <%= class_name %> < ActionMailer::Base + +<% for action in actions -%> + def <%= action %>(sent_on = Time.now) + @recipients = '' + @from = '' + @subject = '' + @body = {} + @sent_on = sent_on + end + +<% end -%> +end diff --git a/railties/generators/templates/mailer_action.rhtml b/railties/generators/templates/mailer_action.rhtml new file mode 100644 index 0000000000..b481906829 --- /dev/null +++ b/railties/generators/templates/mailer_action.rhtml @@ -0,0 +1,3 @@ +<%= class_name %>#<%= action %> + +Find me in app/views/<%= file_name %>/<%= action %>.rhtml diff --git a/railties/generators/templates/mailer_fixture.rhtml b/railties/generators/templates/mailer_fixture.rhtml new file mode 100644 index 0000000000..f315d430ed --- /dev/null +++ b/railties/generators/templates/mailer_fixture.rhtml @@ -0,0 +1,4 @@ +<%= class_name %>#<%= action %> + +Find me in test/fixtures/<%= file_name %>/<%= action %>. +I'm tested against the view in app/views/<%= file_name %>/<%= action %>. diff --git a/railties/generators/templates/mailer_test.erb b/railties/generators/templates/mailer_test.erb new file mode 100644 index 0000000000..f17d614195 --- /dev/null +++ b/railties/generators/templates/mailer_test.erb @@ -0,0 +1,37 @@ +require File.dirname(__FILE__) + '/../test_helper' +require '<%= file_name %>' + +class <%= class_name %>Test < Test::Unit::TestCase + FIXTURES_PATH = File.dirname(__FILE__) + '/../fixtures' + + def setup + ActionMailer::Base.delivery_method = :test + ActionMailer::Base.perform_deliveries = true + ActionMailer::Base.deliveries = [] + + @expected = TMail::Mail.new + @expected.to = 'test@localhost' + @expected.from = 'test@localhost' + @expected.subject = '<%= class_name %> test mail' + end + +<% for action in actions -%> + def test_<%= action %> + @expected.body = read_fixture('<%= action %>') + @expected.date = Time.now + + created = nil + assert_nothing_raised { created = <%= class_name %>.create_<%= action %>(@expected.date) } + assert_not_nil created + assert_equal @expected.encoded, created.encoded + + assert_nothing_raised { <%= class_name %>.deliver_<%= action %>(@expected.date) } + assert_equal @expected.encoded, ActionMailer::Base.deliveries.first.encoded + end + +<% end -%> + private + def read_fixture(action) + IO.readlines("#{FIXTURES_PATH}/<%= file_name %>/#{action}") + end +end diff --git a/railties/generators/templates/model.erb b/railties/generators/templates/model.erb new file mode 100644 index 0000000000..8d4c89e912 --- /dev/null +++ b/railties/generators/templates/model.erb @@ -0,0 +1,2 @@ +class <%= class_name %> < ActiveRecord::Base +end diff --git a/railties/generators/templates/model_test.erb b/railties/generators/templates/model_test.erb new file mode 100644 index 0000000000..a3ad2b72fb --- /dev/null +++ b/railties/generators/templates/model_test.erb @@ -0,0 +1,11 @@ +require File.dirname(__FILE__) + '/../test_helper' +require '<%= file_name %>' + +class <%= class_name %>Test < Test::Unit::TestCase + fixtures :<%= table_name %> + + # Replace this with your real tests + def test_truth + assert true + end +end
\ No newline at end of file diff --git a/railties/helpers/abstract_application.rb b/railties/helpers/abstract_application.rb new file mode 100644 index 0000000000..fa26cd0399 --- /dev/null +++ b/railties/helpers/abstract_application.rb @@ -0,0 +1,5 @@ +# The filters added to this controller will be run for all controllers in the application. +# Likewise will all the methods added be available for all controllers. +class AbstractApplicationController < ActionController::Base + helper :application +end
\ No newline at end of file diff --git a/railties/helpers/application_helper.rb b/railties/helpers/application_helper.rb new file mode 100644 index 0000000000..0392b53b46 --- /dev/null +++ b/railties/helpers/application_helper.rb @@ -0,0 +1,3 @@ +# The methods added to this helper will be available to all templates in the application. +module ApplicationHelper +end diff --git a/railties/helpers/test_helper.rb b/railties/helpers/test_helper.rb new file mode 100644 index 0000000000..d348f26517 --- /dev/null +++ b/railties/helpers/test_helper.rb @@ -0,0 +1,16 @@ +ENV["RAILS_ENV"] ||= "test" +require File.dirname(__FILE__) + "/../config/environment" + +require 'test/unit' +require 'active_record/fixtures' +require 'action_controller/test_process' + +# Make rubygems available for testing if possible +begin require('rubygems'); rescue LoadError; end +begin require('dev-utils/debug'); rescue LoadError; end + +def create_fixtures(*table_names) + Fixtures.create_fixtures(File.dirname(__FILE__) + "/fixtures", table_names) +end + +Test::Unit::TestCase.fixture_path = File.dirname(__FILE__) + "/fixtures/"
\ No newline at end of file diff --git a/railties/html/404.html b/railties/html/404.html new file mode 100644 index 0000000000..edbc89bf99 --- /dev/null +++ b/railties/html/404.html @@ -0,0 +1,6 @@ +<html> +<body> + <h1>File not found</h1> + <p>Change this error message for pages not found in public/404.html</p> +</body> +</html>
\ No newline at end of file diff --git a/railties/html/500.html b/railties/html/500.html new file mode 100644 index 0000000000..ee0c919c4a --- /dev/null +++ b/railties/html/500.html @@ -0,0 +1,6 @@ +<html> +<body> + <h1>Application error (Apache)</h1> + <p>Change this error message for exceptions thrown outside of an action (like in Dispatcher setups or broken Ruby code) in public/500.html</p> +</body> +</html>
\ No newline at end of file diff --git a/railties/html/index.html b/railties/html/index.html new file mode 100644 index 0000000000..4949c64a5a --- /dev/null +++ b/railties/html/index.html @@ -0,0 +1 @@ +<html><head><META HTTP-EQUIV="Refresh" CONTENT="0;URL=_doc/index.html"></head></html>
\ No newline at end of file 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 diff --git a/railties/test/webrick_dispatcher_test.rb b/railties/test/webrick_dispatcher_test.rb new file mode 100644 index 0000000000..2c6b51ae62 --- /dev/null +++ b/railties/test/webrick_dispatcher_test.rb @@ -0,0 +1,30 @@ +#!/bin/env ruby + +$:.unshift(File.dirname(__FILE__) + "/../lib") + +require 'test/unit' +require 'webrick_server' + +class ParseUriTest < Test::Unit::TestCase + + def test_parse_uri_old_behavior + assert_equal [true, 'forum', 'index', '1'], DispatchServlet.parse_uri('/forum/index/1') + assert_equal [true, 'forum', 'index', nil], DispatchServlet.parse_uri('/forum/index') + assert_equal [true, 'forum', 'index', nil], DispatchServlet.parse_uri('/forum/') + end + + def test_parse_uri_new_behavior + assert_equal [true, 'forum', 'index', '1'], DispatchServlet.parse_uri('/forum/index/1/') + assert_equal [true, 'forum', 'index', nil], DispatchServlet.parse_uri('/forum/index/') + assert_equal [true, 'forum', 'index', nil], DispatchServlet.parse_uri('/forum') + end + + def test_parse_uri_failures + assert_equal [false, nil, nil, nil], DispatchServlet.parse_uri('/') + assert_equal [false, nil, nil, nil], DispatchServlet.parse_uri('a') + assert_equal [false, nil, nil, nil], DispatchServlet.parse_uri('/forum//') + assert_equal [false, nil, nil, nil], DispatchServlet.parse_uri('/+forum/') + assert_equal [false, nil, nil, nil], DispatchServlet.parse_uri('forum/') + end + +end |