pax_global_header00006660000000000000000000000064117525030020014505gustar00rootroot0000000000000052 comment=73f520a9395d95a678956d77000976aca6f0acbb ruby-merb-core_1.1.3.orig/000077500000000000000000000000001175250300200153625ustar00rootroot00000000000000ruby-merb-core_1.1.3.orig/CHANGELOG000066400000000000000000002027351175250300200166050ustar00rootroot00000000000000== 1.1.0 "Black Hole" 2010-03-22 * Ruby 1.9 support. The big one. Merb now runs on ruby 1.9.1. This mandated some small changes to the internals as well as some changes to the specs. However, it shouldn't require any changes in your app level code, or at least the merb specific parts of your app level code. * Unicorns! Merb is now better behaved as a rack app and works with a config.ru file[2]. This change should make working with whatever is the latest and greatest ruby webserver a lot easier. * Bugfixes. So many bug fixes. As part of the release process we've done our best to clear out many of the bugs which have been gathering dust over the past year. Some do still remain, but those generally require a more complex solution which needs some thought. * !!!BC!!! Dependency handling using Bundler In this version we dropped old way of loading dependencies using the Kernel extensions and started to use Bundler for dependency management. This allows us to move the whole dependency handling and gem management outside the Merb. Therefore we can simplify some internals and remove some of the Kernel monkeypatching: The old Kernel.dependency and Kernel.dependencies will only 'require gem_name' or 'require require_as' when you call this methods. These methods will also emit the DEPRECATED warnings when you will use them. If you see the warning you should move your dependency to the Gemfile or Rakefile. If you used dependencies to load exact version of the Gem and you have installed multiple versions of the same gem you now get one more DEPRECATED warning. This is because we don't use 'gem' command from RubyGems which was used deep inside to load exact gem version. ALSO THE LATEST VERSION OF THE GEM WILL BE LOADED BECAUSE WE DO SIMPLE 'require'. Also methods: use_orm, use_test, use_testing_framework and use_template_engine DON'T require any gems now, you must require it in Gemfile. Merb generators was changed to generate you Gemfile for your application and settings instead of the dependencies.rb. So what still works? Almost everything except it doesn't defer to the Merb start and doesn't load exact version of gem if more versions are installed: dependency "json" => works dependency "rspec", :require_as => 'spec' => works try to require 'spec' dependency "json", '1.1.6' => works unless you have >= 1.1.6 installed dependency "json" { } => works but doesn't yield For more information how to migrate to Bundler see: http://wiki.github.com/merb/merb/howto-using-the-bundler === Bugs fixed * [merb-core] #1040 Allow using <%== %> escaped version of <%= %> * [merb-core] #1068 Correctly handle HEAD requests (This requires manual alteration of rack.rb) * [merb-core] #1174 Merb::Config[:use_mutex] issue 'sel' to string before comparing to string * [merb-core] #1258 Sessions could be overwritten under certain (rare) situations. * [merb-core] #1288 Fix for run_later in clusters * [merb-core] #1298 Fix potential timing attack on cookie sessions. * [merb-core] #1304 Multipart input parsing produces wrong checkbox input * [merb-core] #1310 Prevent mongrel bloat when streaming files * [merb-core] #1317 Merb now returns correct cookie headers * [merb-core] Improvements to handling of conditional validators == 0.9.8 "Time Machine" 2008-06-10 * Pre-release contributors file update. * Nillify Merb.logger first. * Legacy Merb apps log again. And Merb tells you where it logs on boot unless you are testing. * Fixes up RSpec matcher for request helper * remove vestigal @_template_stack variable. * remove rogure require no longer needed * compile templates with preambles to assign locals, support recompiling partial templates if previously unseen locals are provided * Add a note on Dictionary and inflection code to public changelog. * Nuke files that are already part of Extlib. * Update public changelog. * Fixed Merb::BootLoader::Router issue * -core now depends on most recent Extlib * Revert "Added MinimalPrivilege to merb.thor. Thanks namelessjon." * Fixed stats.rake to check if directory exists * Move inflection code and Dictionary to extlib. * Rakefiles should be empty by default (so RSpec is not pushed down test unit users' throat). * Added MinimalPrivilege to merb.thor. Thanks namelessjon. * Added Merb::BootLoader::Router * Improve public specs for logger. Use Mash for log levels. * Untabify logger.rb. * Allow Merb.disable(:signals) to keep Merb from installing any signal handlers. * Added the ability to specify resource actions in the block * Fixed bug where subgems (of meta-gems) weren't reinstalled each time * Added process title reporting as per: LH #517 * Making the :key a synonym to :keys for Behavior#resource * Fixing the rspec error when running rake tasks * Cleaned up the specs. Removed any stray pending specs. * Added stacking and redirecting deferred routing blocks. * Removed private/dispatch/route_params_spec.rb * New spec helpers ported over. Old #request helper becomes #mock_request, which uses some mocking and stubbing to set up the request. The new #request API uses no mocking, and has the following API changes: * Removed spec/private/config * Added dependency 'foo', :immediate => true for loading dependencies immediately * call to_s in the csrf middlewre * make StreamWrapper more duck typed to the old body string. * If --log-level or --log is explicitly given, never log to STDOUT, alsways to file * If Merb.env?(:test) we don't need ugly = true spread all over the place * use Proc === @body instead * Bring the console adapter's #url back into action * update specs for new rack stream_wrapper * Updating streaming methods to work on *all* rack adapters. * Make Merb::Config[]= work without calling setup 1st * Default to = 'UTF8' - you can just set this in init.rb if needed * Colorful GemManagement * Removed unused directory under spec. * Reorganized URL generation methods across Controller classes * Added a :singular option to resource route building * merb -k works right * Fixes stupid issue in spec loader * Route matching handles slashes according to the RFC * Added the #resource controller helper for URL generation. * Fixes #503; raise InternalServerError works now. * We shouldn't use minigems explicitly in our code (yet) * Add missing pieces of forking awesomeness. * Executable wrappers use /usr/bin/env again - run them with /path/to/ruby -S if you need a specific Ruby version * Merge in forking branch. * Use trenary operator here. * capture returns return value of passed in block if it is not a template block * Updated PUBLIC_CHANGELOG regarding Merb::RakeHelper * reverts URI generation on requests * Updates full_uri for the changes to the Request#protocol * Reorganized merb-core/tasks/merb to require merb-core/tasks/merb_rake_helper (see merb-gen too) * Cleanup of tasks/merb_rake_helper.rb * Added :gemspec task to Rakefile * Fixed executable wrapper code (for loading local gems) * Added Merb::RakeHelper.install_package method to install packages directly * Merb::RakeHelper now handles local ./bin and GEM_DIR installs correctly * Rakefile now uses Merb::RakeHelper.install * Added GemManagement module - working towards new install/uninstall rake tasks * Removed Merb::BootLoader::ReloadTemplates; Merb::Config[:reload_templates] needs to be set explicitly * Marked Kernel#track_dependency as @api private - updated specs to reflect this * Added warning when specs are run without memcached being available * Refactored Kernel#dependency and #load_dependency to work with Gem::Dependency * Include request uri in routing exception raised by request helpers. * Added require 'thread' explicitly for Mutex to be available * Revert "Initial support for fast redeploys and code reloading via forks." * Revert "Split out the code transaction into a method and do some experimentation with cluster forking." * Revert "Better exit message" * Revert "Initial experiments are a success. TODO: Move the logic out of mongrel and make a proper clustering instead of hardcoding to 4" * Fixes issue people were having * Initial experiments are a success. TODO: Move the logic out of mongrel and make a proper clustering instead of hardcoding to 4 * Split out the code transaction into a method and do some experimentation with cluster forking. * Better exit message * Initial support for fast redeploys and code reloading via forks. * Fixed that YAML plugin configuratator wasn't requiring YAML. * Reindent core_ext/kernel.rb. * Register dependencies even after the BootLoader has finished * Fixes Merb::Request#protocol to remove the ://. May Break things in apps if you're checking protocol directly. * Moves actual url generation methods onto the request object from the controller. Also updates the Merb::Request#redirect method to be usable just like the controller version. * Throw the correct error when generating a non existent route. * Modify throw_content to not append. Add append_content for that purpose. * Significant router refactoring and feature development * Run specs in groups * Added more discriptive message when a class fails to load * Optimized Merb::Request.query_parse - fixed silly spec * Update Rack application spec to reflect current affairs. * Document template_for. * Make merb fast again. Also make rake install work from any Ruby via -S * ControllerMixin#html_escape => #escape_html (bring it in line with #escape_xml). * Protected makes no sense for class methods. * Remove dead code from responder. * Adds abstract! and abstract? for controller classes for your inheritance pleasure * Server#add_irb_trap should play nice with ruby-debugger. * Reworked the Server#add_irb_trap to suppress the warnings. * added flag for an IRB trap * Add links to nginx_send_file examples: gist and app at GitHub. * Untabify fixture controller for streaming. * Make Merb::Controller#nginx_send_file more user friendly. * More fine-grained check to see if a local ./bin executable should have been used * Ignore products RDoc generates. * Include RDoc in the gem. * Ignore RDoc template cache. * Remove RDoc template cache from version control. * Session cookies now expire at the end of a browser session again (instead of 2 weeks) * Second attempt: fixed load_dependency (hopefully) * Fixed failing spec regarding 'dependency' change * Make flat! more useful * This rescue is obsolete and is obscuring useful failing information, as well as loading from the system even when you require a specific version that isn't available in the bundled gems. * Clean before installation. Remove *.so and *.log under spec. * Make gem 3 times lighter. * Merb::Release is gone. * Bump up version * Set @_content_type before running transform blocks * sneaky merge failure piece that shouldn't be here * Revert "Add specs for action-level only_provides" * Revert "add specs for does_not_provide" * add specs for does_not_provide * Add specs for action-level only_provides * Make controller.route work == 0.9.7 "Universe In A Bundle" 2008-13-09 * Made the post body available to the routing when testing a request. * Better local gems dir detection and end-user feedback * Updated PUBLIC_CHANGELOG regarding gem management and merb.thor * Fixed compatibility with the *new* bundle logic * Made request('/path', {}, {:post_body => 'some XML'}) not setting the post body to nil. * Added two specs for setting request.raw_post. Passes for #dispatch_to, fails for #request. * You can now use request_to with a post body: * It's official: Thor is now a dependency * Removed MerbScriptHelper - simplified loading bundled gems - see merb.thor * Bug Fix: Cookie headers not being formatted correctly * Added request.session.clear! method to clear and destroy the session (including the _session_id cookie itself) * Both memcache-client and memcached gems are supported by the session store * Added better query param parsing (naive but adequate) for nested params * Added specs to make sure blank cookie options aren't used for Set-Cookie * Fixed cookie issues in WebKit/Safari browsers * Log ControllerExceptions with error level and only ServerErrors with info. * Modified absolute_url to handle an object as well as a Hash * Touches to new sessions: doc and minor code improvements. * More meaningful exception message when no session container is configured. * Make it clear how session mixin makes it's way into controller. * Leave a note where new sessions doc needs to be improved. * Fix smart formatting. * Give smart people proper credit when you use their work. * Loosen extlib dependency a bit. * Meaningful message when Memcached session store can't be loaded because of load error. * Remove libxml-ruby and memcache-client dev dependencies. * Require memcached gem where memcached session store is defined (it's lazy loaded). * Meaninful message when have_xpath matcher is used but libxml-ruby fails to load. * Don't blow up when there are no system paths. == 0.9.6 "Therapy session" 2008-08-09 * Merge in simple conditional get support at controller level. * Merged in new bundling (aka freezer) branch * Merged in new-sessions branch * Simplify one more clever line. * Trenary operator is always hard to read. * Added PUBLIC_CHANGELOG note on Language::English::Inflector => English::Inflect * Filters with procs created via class methods have identical signatures regardless if they handle content differently or not. So modified add_filter to just append procs to the filter list. * Consolidating raw Rakefile commands to merb-core/tasks/merb_rake_helper.rb * Update contributors list. * Ticket #461 - This simply adds output for what host and port the adapter has started on. * More Language::English::Inflect to English::Inflect changes - getting ready for Extlib move soon * Language::English::Inflect => English::Inflect name changes * Use frozen strings where possible. * First pass at adding in CSRF protection in to Rack middleware. * Query string of the format "foo=bar&foo=baz" should return params {"foo" => "baz"} * Fixed multiple select not honored in params bug * Public specs for 'fragment' changes in url. * AbstractController now uniformly uses instance_eval for Procs where previously * Renamed anchor to fragment along with some minor tweeks to follow rfc2396 better. * Add support for :anchor when generating url's. Ex. url(:root, :anchor => :lower_half). * Revert "Make Merb::Request#protocol return valid protocol names (http, not http://)." * Adds specs for previous commit * Fixes display @object, :template => "path/to/foo" * Clean up Rakefile. * Remove a line of extra code * Set cookie expires to nil when session_expiry is set to 0. * ConditionalGet refactoring. * Fix: ConditionalGet should not return the message body when the status code is 304. * Rescue Exception subclasses, not only StandardError subclasses. * Make Merb::Request#protocol return valid protocol names (http, not http://). * Add :protocol and :host options to absolute_url * extends basic authentication a bit to allow usage outside of before filters == 0.9.5 "Knife and Spoons" 2008-26-08 * Add Hpricot to dependencies: provided RSpec matchers depend on it. * Documentation fixes * Make Rack application set Date header as required by RFC2616. * Port Django's conditional GET middleware to Rack. * Fix passenger issue * Make Autotest consume less CPU by adding excludes. * Add extract! experimentally * Adds dev deps on rake install * Add necessary dev dependencies * Make route_to(...).with matcher work properly with empty hashes * Make Merb::Request#query_parse a bit faster. * Speed up dispatcher specs by using libxml * throw :halt, nil spec * More rigid specs * merb-core really cannot use >= with extlib 0.9.3 at this point, so update gemspec * Use Logger from Extlib * Fix issue with Safari having weird ordering by fixing the issue in general. * Fixes up a bunch of specs * Add ContentLength middleware. * Rename Rack middleware spec file * Add Tracer middleware. * Improve the documentation of AbstractController. * Move Merb::Rack::Middleware#deferred\? to Merb::Rack::Application. * No longer use Pathname for Merb.root and friends. * fixed merb_erb bug * readded _generator_scope methods with deprecation warnings * added use_template_engine method and removed generator_scope code that is no longer needed * Add clear_content to renderer == 0.9.4 "Leave No Broken Windows" 2008-12-08 * Update required Ruby version to 1.8.6. * Make dispatch_to set params[:controller] and params[:action]. * Update RedirectTo matcher documentation. * redirect_to matcher now has :message option * Adds some detail to the public changelog * Fix rakefile * Make history Rake tasks work again. * Add contributors file. * Add Rake tasks that list and update contributors file. * A bit more readable spec example titles. Follow one assertion per test rule. * Make Merb::Controller#send_file set header with respect to Rack specification. * Removed TODO in Dispatcher#handle. * More updates to Merb::Request methods documentation. * Document Router#route_for(request). * Document some new Request methods. * Doc correction: Request#params returns instance of Mash. * Doc correction: Request#body_and_query_params returns instance of Mash. * ! for methods that change the receiver * Remove old code * Moves session fixation into request * re-add permanent redirects * Don't need this spec anymore. * More work on the dispatcher. * Documentation improvement + improvement in division of responsibilities. * Before moving stuff into the Rack adapter. * Additional refactor of the default Exceptions to use an actual Merb controller. Almost ready for a merge. Yeehaw! * Even more awesome dispatcher improvements. * Fixes an issue with status symbols * Class extensions spec moved to Extlib. * Move all accessors in AbstractController to the top so one can see them easily. * We don't need this anymore * Continues dispatch refactor. Exceptions now maintain a stack that is reported in the case of exceptions that, themselves, throw exceptions. * Document :with option of filters. * Fixed a typo in AbstractController documentation. * Extra specs and love to Merb::Controller._session_* * Added fixture config/init.rb * Resolved conflict after cherry-pick of 9d1a11ff. * Fixtures and pending specs for controller/cookie store integration. * Re-set session cookie expiry and friends once init file/configuration is loaded. * Two more specs for class_inheritable_accessor. * Make spec for #342 do correct assertions. * Fixed a bug where changes to inherited controller filters would bleed acrosss siblings * the dispatcher specs * Add more edge-case specs to Dispatcher and make sure they pass. * Make Cookie#set_cookie handle more options. Improve spec coverage. * Refactor Dispatcher.handle to reduce complexity * Fix some ruby warnings * Added flog tasks to rake * add in stats task * Forgotten changes to Rakefile. * resource urls with additional params * Remove double-start in Thin adapter. * Merb::SimpleSet => Extlib::SimpleSet * merb-extlib => extlib * add spec for empty raw_post on xml content type * make sure to resuce JSON parse errors and return {} * Use Pathname in some more places, fix breakages. * Added more documentation for some of the extra options available to #partial * Temp commit. * Relative :template paths can be extensionless again. * Oops - forgot some files... * Fixed nasty bugs in controller/mixins/responder and its specs. * Reworded the documentation for #partial a little bit * Added some documentation for the new partial collection counter * Slight refactoring of the partial method * Adding views for the new partial collection counter specs * Adding the current index and collection size for partials rendered with a collection * Use gem release task that's in Extlib now. * If someone can figure out why this is already defined, please let me know * Yeah... not a good idea * ADd push_paths to the load path. * another tiny tweak * Fixes open IO issue * Switch to merged extlib. * Use Pathname in some more places, fix breakages. * Move to merb-extlib is almost there. * Output a warning about merb-extlib if it can't be loaded. * Applying patch to allow use of thin_turbo adapter. Thanks dkubb! * Did I really commit that? * Use :info as default log level for now: people wonder "where the output is gone". * Make sure default config has log level of error so template inlining bootloader won't dump everything to the tty. * Do not reference to old merb.yml in doc. * whoops... dup * Add support for argument capture and fix $DEBUG bootloader stuff [#390 state:resolved] * Ignore temp Emacs files. * Generate tags only for lib. * Adds Rake tasks to generate Emacs tags. * Touch RDoc of LoadClasses bootloder. * LoadClasses#remove_file => LoadClasses#remove_classes_in_file. * Output extra information on boot when verbose config option is given from * Make Logger bootloader print meaningful warning when RubyGems is outdated. * capture_erb correctly passes arguments to the block again * Let world know what this delete vs. destroy thing is all about. * Add support for OPTIONS * display doesn't throw an error if a layout is not found, even if one is specified (because of class-wide layout options) * throw_content now concatenates, not replaces, content * Added view for throw_content spec * Clean up resource regexps after ; separator is gone. * @@parent_resources, not @@parent_resource * Semicolon as action separator for resources is no longer supported: breaks basic http auth in Safari. * Small doc update. Thanx jackdempsey * Adds message support (like flash in Rails but with somewhat different semantics) * Add .tmproj to the list of ignores * Fix bug with :status * Spec for :status in display * display handles :status and :location * Improved RDoc of Merb#load_dependencies. * script/frozen-merb => merb-freezer in RDoc * Adjusted logging message for thin sockets vs ports. * Added socket option to thin.rb and to the command line options. * send_file opens files in 'rb' binary mode so windows doesn't shit itself * added add_generators, which allows plugins to load their own generator in the same way as rakefiles * fix nginx_send_file * Spec for previously applied patch to Behavior#defer_to. * use Route#register in defer_to so that deferred routes get an index * Make Autotest ignore doc/ as well. * Ensure Autotest ignores changes in log directory. * Add helpers directory to load path * Modules don't get duped right. * Redo Merb's inheritable_accessors so that they have correct semantics, then redo everything that uses inheritable_accessors so they don't have to hack around the bad semantics. * Added spec for the route matcher testing regexp routes. [#386] * Add Merb.started? alias for Merb.started reader. * Add reader for @started flag which shows when Merb environment is started. * Update memory session storage documentation. * Use warn logger level instead of debug, if session persisting fails. * FileUtils#touch only added mtime option in ruby 1.8.6. let's use File#utime instead * better log message * rescue excpetions in Worker thread, log them and then restart the work queue * Router now can do r.match("/this/old/url").redirect("/where/this/resides/now"). * Refactor Merb::Test::RequestHelper and introduce build_request helper. * spoke too soon. * we actually don't need to log this at all as its logged latert in the _benchmarks * Update link to wiki page on Rack in exception. * Add link to Rack page at wiki to Controller not found exception. This confuses people a lot. * Log namespaced controller name when it's class is not found. * I will test first next time, I promise. * Tell what's actually started when Dispatcher begins to handle request. * Fixed typo in yet another exception message. * Log an info message when route fixation actually happens. Those heavily using Flash will find it helpful. * Log a warning if controller class cannot be found. * A bit more verbose exception message when route does not specify a controller. * Documentation: add deprecation warning to AbstractController. Manually applied patch from dstar. * Increase header level on sub-headers of Filters in AbstractController * Fixes request helper bug [#378: resolved] * Fixes case of :format being ignored. * If the spec.opts file exists, use it. * use Thread.pass to avoid running newly queued item before the action's thread finishes * Added Merb::Worker. You can now add a block to be run in a separate thread * Let's try again, this time with <% end =%> * Try #concat to resolve some issues. * One more time. * Should handle denormalized multiline blocks now. * wycats needs to learn to escape pipes. * Make Merb::Plugins.config[:foo] default to {} * Long lines make wycats' eyes' bleed. Plus, why do all those .joins twice? * jackdempsey's inflector improvements (backported from wycats' patch to Rails) * Fixes typo. * <%= now takes a block in Erubis. Erubis buffer now an ivar (@_erb_buf) so eval is no longer required for capture. Helpers that take a block should now return a string. * Fixes the after filters * Reorganize experimental stuff. * Additional slight efficiency and readability improvement. * Improve speed of content-type=. 5% speed on hello world requests. * Improve the speed of _perform_content_negotiation (and got 10% better speed on requests) * Old stuff that should be committed. * Speed up synonym lookup by order of magnitude :( * add Merb::Rack::Profiler middleware. to use add the following to your config/rack.rb file: * update license * Missing require * require 'stringio' * Add support for non-standard template reloading. Plugin authors need to override load_template_io to handle special reloading logic. * Add support for IO templates instead of just paths. See PLUGIN_API_CHANGELOG for details. * add swiftiplied mongrel rack adapter. * Swapped the order of helper and controller in the default_framework * Why should capture be private? * Merb::Config[:framework] now needs absolute paths to work (breaks BC) * Merb::Config[:framework] paths now pickup files using glob **/*.rb unless specified otherwise * Don't automatically use Facebook signature * Fixes failing spec. * make the default rake task 'specs' so running rake in merb-core just runs the specs * Rename @status to @_status * Avoid adding nil values in place of missing keys for Hash#only * Fix issue with null segments * Fixed session cookie expires value [#366 state:resolved] * Made HTTP method override proc-based and pluggable. [#364] * siiiiiigh. * Revert partial counter and yielding. * Remove some duplication * For crying out loud. * Refactor display. WARNING: This commit might not be stable. I need to add a bunch more specs for display before I feel confident. * Make the TemplateNotFound error read better. Slight refactor of _get_layout. * Fix _template_for so it's actually readable * uhhhhhhhh... * Added Merb::Router.reset! and Merb::Router.capture * Speedup Route URL generation * Start work on fixing contaminated cousins bug. * Changed controller inheritance of _template_root * Added the ability to use full/absolute template paths for render, display and partial views * This cannot be tested this way. It needs to be tested as a public spec (testing it privately here was a cop-out and fails when I fixed up the way dependency works). * Allows passage of query string via env["QUERY_STRING"] in tests. [#358 state:resolved] * Handles use of dependency after BootLoading. [#360 state:resolved] * properly set the session_id_key * added 2 specs for multipart formdata: (1) for checking request with IO, (2) for testing GET with content_type not erroring on multipart/form-data absence; fixed error with multipart/form-data absence. * Made Class a lot more sane. * Fix README for merb-gen app foo * Do not duplicate work Merb::Template.template_extensions does in Templates bootloader. * Make exception message when Merb cannot find template explain what it was * Fixed 2 problems with multipart form upload after application is deployed to Tomcat via warble: (1) The @body object in this environment is an IO object, not a StringIO, so doesn't have a size method, and (2) 'tempfile' needs to be explicitly required. * made only and except uglier and faster * Preserve order parse query, respect query string override in test request * Added partial counter and yielding for collections * Remove occasionly committed *.rbc files. * Ignore *.rbc created by Rubinius compiler. * Send the route into the controller * Add Merb::Request.browser_method_workarounds * Revert ca92bdfc89afda04cbb4fd3d3e5848648cc0b326 * Refactored Merb::BootLoader::LoadClasses.reload into an additional remove_file method for other usage * Fixed some failing specs * Added rake :audit namespace to list routes, controllers and actions * Remove occasionly committed *.rbc files. * Ignore *.rbc created by Rubinius compiler. * Make obj.full_const_get more robust * forgot to comment out the text * added DHH copyright notice to conre_ext/class.rb * Better usage of merb_rake_helper.rb * Added tasks/merb_rake_helper.rb - removed it from merb-more * Refactored Merb::Controller.callable_actions * Fixing bug in the rspec route matcher. * More useful error for display errors * Make load_paths a dictionary so models load first. * Added Merb::Template.template_extensions as a semi-public method for getting known template extensions * Prevent anonymous controller classes from making a Helper module * We've Been Dup'd! - fixed nasty bug concerning class inheritable attrs * Added Object.full_const_set * Add helper for full_uri * Adds a timestamp to a requests output * Fixed documentation examples for dispatch spec helpers * Added public method Merb::BootLoader::LoadClasses.load_classes(*paths) * Only do the rubygems hack if it's needed and deal with cases where people are using the Gem cache library without using the commands. * Updated docs on Merb#merge_env * Merb Personalized Environments; Completed Merb#merge_env method, now accepts boolean parameter to optionally use the merged environments database connection * fix typo in spec * Check to see if the session responds to :data * make nice for windows - remove app level loading (is handled in rakefile in merb-more now * Typos * YARD conversion of set.rb and time.rb * YARD conversion of rubygems.rb * YARD conversion of object_space.rb * YARD conversion of object.rb * YARD conversion of mash.rb * YARD conversion of kernel.rb * YARD conversion for hash.rb * Convert class.rb over to YARD. * Convert string.rb over to YARD format. * Patch for missing inner_content method bug in HasTag * Correct lable and line number in Router#compile * Make merb.show_routes show named routes a bit more verbose. * Make merb.show_routes a bit more verbose. * Use single symbol instead of Array for ORM/test framework generator scopes. * Add links to source at GitHub to boot diagram * Merb core boot diagram is done and prettified * Add support for a :session_cookie_domain config option to allow for setting the session cookie's domain. * Add more advanced nested routes examples to Merb::Router::Behavior#match documentation. * Add a bunch of pretty advanced spec examples for nested matches in routes. * Code clean-up behavior.rb * Created Documentation for new #match functionality * Changes to behavior.rb to allow for :controller, :actions and :params options to be passed in * Implemented Merb::Router::Behavior#match! that is a shortcut for match(...).to({}). * Improve Merb boot diagram. * Make each subsequent call to use_orm just replace effect of previos. * Remove WIP spec for Merb::Router::Behavior#redirect. * fix typo in request_spec.rb * Needs to raise here since if the generator scope has more than one ORM the geneartors will not work. * Log instead of raising when dependencies mechanism this ORM required twice. * Get rid of Kernel#registered_orm?, it is no longer in use. * Make Kernel#registred_orm? use simple include lookup. * Fix spec and Kernel#registred_orm? conditions bug. * Fix a typo. * Fixed erronous documentation in Merb::Router::Behavior * Working on Behaviour#redirect feature: stashing changes. * update callable_actions to exclude any methods beggining with an _underscope * Adds template-checking code to branch where :with option is specified in partials. * Add two notes on layout method versus :layout option of render method. * Forget to add template for added spec example. * Add spec example for render :layout => false that overrides layout. * More sweet empty lines management in controller fixtures. * Clean up empty lines in fixture controller. * Fix _template_for documentation: content type does not default to nil. * Update render method documentation, we support :layout => false. * JSON objects that do not inflate to hashes should populate params[:inflated_object] (Ticket #316) * update new rack middleware machinery to be more merb style in the bootloader * Changed MerbDispatch to MerbApplication. Fixed error in deferred? call chain. * More flexible composition of merb application * Start implementing Merb::Router::Behavior#redirect. * A note on condition block and deferred routes. * Note on thread safety of routes compilation. * Explain what Merb::Router does and what routes compilation is. * Explain how "form used by Merb::Router" is often referred. * Be explicit on what Merb::Router::Route#if_condition actually does and how it is used. * Add a note that Merb::Router::Route#generate uses #to_param on parameters. * Be explicit on what Merb::Router::Route#generate actually does. * Add a note to Merb::Router::Route#name documentation. * Add note on string representation of routes. * More explicit documentation for Merb::Router::Router#register. * Add section on fixation of routes. * Another take on better Merb::Router::Route documentation. * New Merb::Router::Route documentation probably got a bit better. * Something that looks like detailed Merb::Router::Route but needs a lot of work. * Add first naive spec examples for Merb::Router::Route#compile. * Use .prepare when we do not really need .prepend * Made sure default format response_header can set explicit Content-Type header * Default format response_headers cannot overwrite runtime-set (controller) headers * Mirror plural spec from singular. Fix a couple of revealed failures. * Actually implemented Merb.add_mime_type's new_response_headers * Add cases that were failing in pluralization specs to singularization spec. * Fix failures in pluralization specs. Add more cases. * spec/private/vendor/inflector => spec/private/vendor/facets * Pluralization spec examples. * Move singularization specs to separate file. * More spec examples for inflector. * Improve spec coverage of inflector. * Improve inflector spec coverage: separate cases into groups. * Fix a typo exposed by spec suite. * Initial set of spec examples for inflector. * Changed vague :request_headers term into :accepts (meaning HTTP Accept header) * Sweet empty lines management in spec helper. * Increase sleep time reloader spec. * Unwanted change to autotest slipped in, must get better at git * More reliable reloader test with fewer sleeps * remove :nodoc: from merb-core DO NOT USE :nodoc: EVAR!! * More lower-level spec examples for Merb::Router::Route. * More lower-level specs for Merb::Routing::Route. * Initial set of lower-level specs for Merb::Router::Route methods. * Rename file with extra unit specs for Merb::Router * Removed extra comment. * Finished Merb::Router unit-ish spec. * Initial lower-level specs for router. * Fix for users with spaces in gem path * Add missing specs for route fixation. * Add matched_route_for spec helper to get raw Route instance. * Exclude unwanted files from rcov analysis. * Make Rakefile respect GEM_HOME. Thanks Corey Jewett. * Add extra output lines to Merb::Server methods if verbose mode is on. * Add -V/--verbose options. * Improve documentation of session persist/finalize exception callbacks. * Initial specs for Merb::SessionMixin * Tiny documentation touchups * Require RubyGems first before spec to satisfy Autotest. * Exception handler callbacks for finalize_session and persist * Update Merb core boot diagram a bit. * Documentation for Merb::BootLoader::DropPid bootloader. * add in string so that @element.contains? will work when @element is a string and not just Hpricot::Elem * remove hpricot as a merb-core dependency since it is never loaded at runtime. * Merb::BootLoader::Templates now uses _template_roots not just _template_root * add in support for core tasks, and first core task -- routes * Fix Webrick support by preferring REQUEST_PATH over REQUEST_URI * Changed Merb::BootLoader::BeforeAppRuns into Merb::BootLoader::BeforeAppLoads which matches Merb::BootLoader::AfterAppLoads * Added option to Controller#redirect(url, permanent) so 301 responses can be returned as well * Bump version in core to 0.9.4. * Pump version to 0.9.4. * throw argument error when filter receives an invalid option * spec for ticket 307 * Update GitHub gemspec. * fixed description of daemonize spec in Merb::Config * Trick Git: change SHA1 of tree to push recent binary files changes. * Add PNG version of call stack diagram * Add call stack diagram source file, in Mind Manager format. * Add expanded call stack diagram: probably Git does not work perfectly with binary diffs. * Temporarily wipe out call stack diagram * Expand all nodes on call stack diagram. * Add Merb core call stack (yet to be finished). * Fixed cruddy doc comments. * Remove nil items from params when generating routes * Fixed typo in resource rdoc * cleaned up a bit. removed dependency on to_params value in controller test. * added ability to set the Location header with display and render * remove useless complexity from the logger. * 0.9.3 changelog * Remove special case for dm-core in use_orm * removing __app_file_trace__ since it doesn't work. * Add Emacs TAGS to ignore * Explain Merb application layouts in documentation. * Benchmarks * Allow http status to be a symbol - refactored String snake_case method * Explain how to set up /lib autoload in documentation. * Make change_priveledge actually work * bump merb-core version to 0.9.3 in prep for release. * Add new -R/--rackup option to the full(-ish) list of options. * Provide opts for alternate rackup config path. This is consistent with --rackup option for thin and gives a little more freedom to specify the rackup config (instead of being forced to rack.rb). * Testing Merb::Test::RequestHelper#request method to properly handle namespaced routes * test request helpers support namespaced routes * Added parentheses to be_kind_of to get rid of warnings when running application_spec.rb * Fixing pidfiles glob on cluster and pidfile argument * replaced nested 'if' with an 'elseif' * params array serialization * Added handling of INT signal for Merb server in foreground mode * Remove redundant unescape for cookie string * Ensure that Merb::Logger doesn't try to close terminal streams. * Ensure that Merb::Logger doesn't try to close terminal streams. * Added support for multiple keys to designate a resource. For use with Datamapper composite keys support http://www.datamapper.org/articles/spotlight_on_cpk.html * Make Provide controller matcher doc conform to Merb standards. * Whoops. Had target and expected backwards. * Added Provide matcher class, so you can do "controller.should provide( :xml )" in your specs. * completed spec to Merb::Logger#new * Adding missing info about ebb adapter. * Show merb usage if first argument is not a switch * Fix a spelling error and properly RDoc'ify a method name * Fix bug in --very-flat (allow direct inheritance from Merb::Controller) * Changed copyright date in footer of HTML pages from 2007 to 2008 * Append the content_type to the given :template option for render() * Replaced remaining ::STATUS constant references to .status method calls * Refactored Exception status handling/inheritance (it actually works now!) * Make Inflector#plural and Inflector#singular conform to Merb doc standard. * Update inflector documentation. * Tiny docs update to Merb::Server. * Example (from merb_sequel) and corrections to the way Merb finds out plugins Rakefiles. * Docs updates for lib/merb-core.rb. * Reasonable doc examples for Merb.push_path and Merb.remove_paths. * Fix for kill so that cli options are read and handled before kill is actually called. Need this to handle kill under custom pid file scenario. * Updating pidfile cluster fix to handle any extension. * Adding support for pidfile setting with cluster nodes setting. Moving pid file path lookup to separate method. * Correction to Merb::GlobalHelper.log_path docs. * Use Notes instead of Note in docs. * Use Notes instead of Note everywhere in docs. * Add reference to Merb configuration options list to #config method docs. * Wording (Merb::GlobalHelpers.testing? docs). * Better docs for configuration parameters. * Document Merb configuration options in one place. * Another note on framework freezing in docs. * Add explaination of freezing to the documentation * Add a note on supported session types. * Insert line for viewing convenience. * Make Merb::GlobalHelpers.deferrable_actions conform to Merb documentation standard. * Missing documentation for Merb::GlobarHelpers.deferred_actions * Update Kernel#__profile__ documentation. * make in? splat args * Add Object#in? for checking array inclusion * Removed dependency on memcache-client 'memcache_util.rb' which was dependent on ActiveRecord::Base for logging exceptions. * Update documentation to reflect changes in the way #display handles custom options. * Make #display method pass all 'unknown' options to serialization method. * Adds the github gemspec file * Adds Code for generating a gemspec for github * Adds a question method to determine environment. eg Merb.env?(:production) * Give useful information when no template is found for a partial * Really resolve merge conflicts. * Provide hook for param filtering * hopefully the last fix for session fixation, woot woot * Be clear about what is the default init file Merb uses in RDoc. * A bit clearer --init-file option description. * Fix header shown in help: Merb is not longer 'Mongrel + Erb, a lightweight replacement for ActionPack' but a framework on it's own. * Correct doc in Merb::Controller: it uses SimpleSet for callable actions at the moment. * Document Merb::SimpleSet * Remove InvalidPathConversion exception: it is used nowhere in the core. * Update homepage in gem specification. * Clean up String extensions spec. * Remove it, hopefully no one seen it. * Add a note on drawbacks of usage of ObjectSpace. * Use a constant for reload spec instead of hardcoding time in 5 places or so. * Revert "Refactor ToHashParser#from_xml a bit to be able to use parser faster than REXML. It is planned to support Hpricot and fall back to REXML." * Use @ in publicity markers in RDoc. * Use a constant for sleep time in reloading specs * Refactor ToHashParser#from_xml a bit to be able to use parser faster than REXML. It is planned to support Hpricot and fall back to REXML. * Empty lines management, how cool is that? * Missing specs and improved documentation for Hash#to_mash. * Tiny improvement to Object extensions documentation. More empty line management. * One more example for Object#full_const_get; new spec group for Object#make_module. * Missing specs for Object#full_const_path. * Sweet empty lines management, what a wonderful way to apply yourself to. * Kick off Class extensions spec-ing. * Document inheritable attributes Class extension the Merb way, not ActiveSupport way with :nodoc: * Remove Emacs-generated cruft from specs directory. * Add missing specs for Class#reset_inheritable_attributes. * Split Kernel#use_test into smaller methos. Document them. Add specs for them beforehand. * Empty lines management, wonderful way to waste priceless time. * Kernel#already_registred_orm? is a sucky name. Make it Kernel#registred_orm?. Yay. * Split Kernel#use_orm guts into a bunch of smaller methods. Document those. * Add missing specs for Kernel#dependencies and Kernel#load_dependencies. * Pretty naive spec examples for Kernel#load_dependency. * Add missing specs for Kernel#dependency * Split 'misc' examples group in Kernel extensions spec: each method should have a separate group, ever. * Clean up empty lines in Kernel extensions. * Documentation for String#relative_path_from * Add missing specs for String extensions. * Remove helper that duplicated String#camel_case functionality, update the rest of spec suite. * Fix a nasty String#camel_case bug revealed but new shiny spec for String extensions. * Better formatting of spec suite run benchmark with good old sprintf. * Use RSPEC_OPTS environment variable to override default spec run options. * Report total spec suite run time. * Add spec command run options to run_specs. Add tasks for profiled spec run. * Unify &block documentation across Merb::Test::RequestHelper * Fix example in Merb::Test::RequestHelper#request documentation. * If deferred_actions are empty? we want a regex that will never match. * More polish for deferred_actions support. Thin, Ebb and EMongrel adapters * deferred?(env) now works with thin and ebb. * Fixed some its vs. it's issues. (Learning git :) * added delete action to docs * Added error message for when a content_type is requested but not provided * Syncronized code with rails branch. Delete call is required, because user cookie must be cleaned when TamperedWithCookie is raised. * Specs using a method that called must_support_streaming! weren't recognizing the custom NotImplemented error. This change fixes this issue by specifying the entire object chain for its usage within the method. * Fix number of examples in HTTP authentication spec. * first step to adding deferred?(env) support for ebb and thin * Use a dictionary instead of a Hash. * Changed the display method to handle options properly, so that passing :layout => :false works. Added specs. * Added \- to String.unescape_regexp * added HasContent matcher * Standardises the call to set_cookie to use the set_cookie method in cookies.rb by default * Fix cookie sessions bug where you could not properly delete a cookie * should not delete the key * pass arguments to filters * Added thrown_content? predicate method for use in templates. * Added ability to specify :format in url() for named routes * modified specs to test a route restriction based on the type of request (POST, GET, UPDATE, DELETE) * Added 'use_orm :dm_core' option to use datamapper 0.9.0 with the dm-merb gem from dm-more * fixed example for dispatch_with_basic_authentication_to * Fixed typo * reverted mistakenly introduced change in abstract controller * added documentation * slight fix to basic auth spec * added support and specs for http basic authorization * added dispatch helper for http basic authentication * HTTP Basic authentication based on Rack * Fixed lurking infinite loop with not so common formats and ExceptionController * Refactored Merb::AbstractController.layout class method * _dispatch returns @body * really truly(?) fix stream_file ? * really make sure stream_file works * redo stream_file to (hopefully) work * Added Time#to_json to Core Extensions, making the default JSON formatted output for Time objects ISO 8601 compatible. * Added + unescape to String#unescape_regexp * Added String#unescape_regexp for usage in Router::Route#generate * BootLoader::LoadClasses now logs the actual exceptions * add mutex around compiled statement generation in the router so reloading doesn't step * Revert ExampleGroup changes as they were causing failing specs * Added render(template_path) feature to view specs. * RSpec ExampleGroups for Merb controllers, views, helpers, models and routes. * Prep 0.9.2 * Resolves #209 * * removed Merb.logger calls due to the fact the bootloader did not ran by now and it is not initialized. * use __send__ rather than send * Fixed exception setting route when route_index is nil * memoize the raw_post body after its called once * fix Request#raw_post to respect bodies with no rewind method * remove Kernel#requires it wasn't being used. * Move fixation to post initialize * typo * add specs for does_not_provide * Add specs for action-level only_provides * Make controller.route work * Update Ebb adapter to work with latest Ebb 0.1.0 [Ry Dahl] * fix PATH_INFO bug for fcgi * Rename url_with_host to absolute_url * Add url_with_host() and allow params to be pushed into FCGI adapter * More correct to_json of dictionary. * Modify dispatcher to be sane to XHRs; add to_json to dictionaries. * Added html_escape around the exception.message in the show details section. * Fixed bug not allowing have_tag to be called without a attribute hash, even when one is not desired * fix typo * refactor and clean up Merb::BootLoader::Dependencies [James Herdman] * ticket 202 * This keeps erroring out, i hope it didnt commit multiple times: * Merb::BootLoader::LoadClasses should keep unique list of classes * Logger now works as expected, fixed ReloadClasses bootloader * Fixes cookie sessions when the session is blanked out. * catch_content should default to :for_layout * Added --sandbox (-S) option for IRB console * Fixes the dispatch_to request helper to conver the action name to a string. * Added Merb.testing? method * Fixed critical bug in LoadClasses BootLoader concerning reloading * Important changes to the BootLoader process * Added Kernel.load_dependencies method; better docs/comments. * Bugfixes concerning BootLoader and load order in general * fully qualify fcgi rack handler * Set mongrel as default adapter unless other alternative options are specified * Fix configuring session_id_key so that it works * url(:foo, 3) should notice 3 is a Fixnum, and use it instead of 3.id == 0.9.3 "We Sold Our Soul for Rock 'n' Roll" 2008-05-03 * Added render(template_path) feature to view specs. * add mutex around compiled statement generation in the router so reloading doesn't step * BootLoader::LoadClasses now logs the actual exceptions * Added String#unescape_regexp for usage in Router::Route#generate * Added Time#to_json to Core Extensions so JSON formatted output for Time is ISO 8601 compatible * redo stream_file to (hopefully) work * _dispatch returns @body * Refactored Merb::AbstractController.layout class method * Fixed lurking infinite loop with not so common formats and ExceptionController * HTTP Basic authentication based on Rack * added dispatch helper for http basic authentication * added support and specs for http basic authorization * modified specs to test a route restriction based on the request method * Added ability to specify :format in url() for named routes * Added thrown_content? predicate method for use in templates. * pass arguments to filters * Fix cookie sessions bug where you could not properly delete a cookie * Standardises the call to set_cookie to use the set_cookie method in cookies.rb by default * added HasContent matcher * Added \- to String.unescape_regexp * Changed the display method to handle options properly, so that passing :layout => :false works. * Added error message for when a content_type is requested but not provided * added delete action to docs * deferred?(env) now works with thin and ebb. * If deferred_actions are empty? we want a regex that will never match. * Fix example in Merb::Test::RequestHelper#request documentation. * Unify &block documentation across Merb::Test::RequestHelper * Add spec command run options to run_specs. Add tasks for profiled spec run. * Report total spec suite run time. * Use RSPEC_OPTS environment variable to override default spec run options. * Better formatting of spec suite run benchmark with good old sprintf. * Fix a nasty String#camel_case bug revealed but new shiny spec for String extensions. * Remove helper that duplicated String#camel_case functionality, update the rest of spec suite. * Split 'misc' examples group in Kernel extensions spec: each method should have a separate group * Split Kernel#use_orm guts into a bunch of smaller methods. Document those. * Kernel#already_registred_orm? is a sucky name. Make it Kernel#registred_orm?. Yay. * Split Kernel#use_test into smaller methos. Document them. Add specs for them beforehand. * Use a constant for sleep time in reloading specs * Use @ in publicity markers in RDoc. * Remove InvalidPathConversion exception: it is used nowhere in the core. * A bit clearer --init-file option description. * Be clear about what is the default init file Merb uses in RDoc. * hopefully the last fix for session fixation, woot woot * Provide hook for param filtering * Give useful information when no template is found for a partial * Adds a question method to determine environment. eg Merb.env?(:production) * Make #display method pass all 'unknown' options to serialization method. * Add Object#in? for checking array inclusion * Update Kernel#__profile__ documentation. * Adding support for pidfile setting with cluster nodes setting. * Updating pidfile cluster fix to handle any extension. * Fix for kill so that cli options are read and handled before kill is actually called. * Refactored Exception status handling/inheritance (it actually works now!) * Replaced remaining ::STATUS constant references to .status method calls * Append the content_type to the given :template option for render() * Fix bug in --very-flat (allow direct inheritance from Merb::Controller) * Show merb usage if first argument is not a switch * Adding missing info about ebb adapter. * completed spec to Merb::Logger#new * Added Provide matcher class, so you can do "controller.should provide( :xml )" in your specs. * Added support for multiple keys to designate a resource. For use with Datamapper composite keys * Ensure that Merb::Logger doesn't try to close terminal streams. * Remove redundant unescape for cookie string * Added handling of INT signal for Merb server in foreground mode * params array serialization * Fixing pidfiles glob on cluster and pidfile argument * test request helpers support namespaced routes * Testing Merb::Test::RequestHelper#request method to properly handle namespaced routes * Provide opts for alternate rackup config path. * Add new -R/--rackup option to the full(-ish) list of options. * Make change_priveledge actually work * Allow http status to be a symbol - refactored String snake_case method * removing __app_file_trace__ since it doesn't work. == 0.9.2 "appropriate response to reality" 2008-03-24 * removed Merb.logger calls due to the fact the bootloader did not ran by now and it is not initialized. * use __send__ rather than send * Fixed exception setting route when route_index is nil * memoize the raw_post body after it's called once * fix Request#raw_post to respect bodies with no rewind method * remove Kernel#requires it wasn't being used. * Move fixation to post initialize * add specs for does_not_provide * Add specs for action-level only_provides * Make controller.route work * Update Ebb adapter to work with latest Ebb 0.1.0 [Ry Dahl] * fix PATH_INFO bug for fcgi * Rename url_with_host to absolute_url * Add url_with_host() and allow params to be pushed into FCGI adapter * More correct to_json of dictionary. * Modify dispatcher to be sane to XHRs; add to_json to dictionaries. * Added html_escape around the exception.message in the show details section. * Fixed bug not allowing have_tag to be called without a attribute hash, even when one is not desired * refactor and clean up Merb::BootLoader::Dependencies [James Herdman] * Merb::BootLoader::LoadClasses should keep unique list of classes * Logger now works as expected, fixed ReloadClasses bootloader * Fixes cookie sessions when the session is blanked out. * catch_content should default to :for_layout * Added --sandbox (-S) option for IRB console * Added Merb.testing? method * Fixes the dispatch_to request helper to conver the action name to a string. * Added Merb.testing? method * Fixed critical bug in LoadClasses BootLoader concerning reloading * Important changes to the BootLoader process * Added Kernel.load_dependencies method; better docs/comments. * Bugfixes concerning BootLoader and load order in general * fully qualify fcgi rack handler * Set mongrel as default adapter unless other alternative options are specified * Fix configuring session_id_key so that it works * url(:foo, 3) should notice 3 is a Fixnum, and use it instead of 3.id * make load order of core_ext explicit * Modifies before/after in BootLoader to actually work. * ix not-available vs. not-provided bug in content negotiation * Fixed display bug which caused default error exception pages to improperly display drop-down twirly if the path name exceeded the line length. * remove symbolize_keys! as we don't use it anywhere. by now.. * Rework bootloader to make more sense for flat apps (specifically framework load) * More fixes to the flat autoloader * remove custom_* resource route, use :member or :collection instead * fix logger specs * Fixes bug with framework not being defined. * make sure logger bang! methods do not flush unless the proper log level is used. * Updates the request spec to account for the new from_xml behaviour * Adds specs and changes for compatibility with ActiveSupport. There is one caveat. It will not change YAML generated Hash keys to strings if they are defined as symbols as is currently the behaviour of ActiveSupport. * update the logger. no longer accept an optional block to call. * remove some vestigal config defaults * Add rack adapter for Ebb, damn it's fast! * coerce the port to an integer when starting mongrel (jruby compat) * remove specs for dependency as they were broittle and not testing the right thing. * Fixes #155 (_perform_content_negotiation doesn't find */* if it comes last in the accept header order, and nothing else matches) * Changes use_test to wrap only the call to dependencies in the check for Merb.environment == "test" == 0.9.1 "Some are half-wild, and some are just outlaws." 2008-02-29 * Put spec tasks into namespaces and method for specifying pnly a certain model/controller/view to run against * As a last resort, look for */* in the formats before throwing NotAcceptable (TODO: Clean this up) * Fix perform_content_negotiation to correctly handle :format in params. Fix render_* to correctly return the correct content_type. * remove hooks.rb, they were premature and only used in one place * fix evented mongrel to not go crazy * Calling /foo.pdf should throw a 406 if :pdf is not a registered mime. * touch up dispatcher a bit, remove some un-needed code from the hot path * fix dispatcher to not parse the params twice, still supports request_params * fix Exception in exception.html.erb * moved rspec rake tasks into core. Added Merb.rakefiles, which is now used by Merb::Plugins.rakefiles. Changed Kernel#use_test to only load dependency arguments when Merb.env is nil or test. * do not load test framework unless Merb.env == 'test' * Use new Object.make_module to create the module instead of old hackish solution. * Don't clear our mimes previously defined. * Fixed clean task deleting everything in the lib folder * Kernel#dependency requires gems/files in a before_app_loads block. * Move dependency loading after framework and look for framework.rb * Creates helper stub modules for controllers. * fix blank path error. * Cooler errors * add named routes to error page * updates to nested resources * get autotest working for merb-core * Symbolize params in route generation, to accomodate Mashes * Fixes :status not working on strings. * update thin adapter to newest way of silencing the log * :format => :html possible in partials * print request URI when "No routes match the request" error thrown * fix merb -i * Make Merb.start default to the runner adapter * It's now possible to send binary data using the send_data method and to specify the disposition, filename and type of the data being sent. * Fix memcached session writes * allow the setting of a custom session key * Changed TemplateNotFound to stop so much confusion about incorrect template locations because it doesn't include .* * fix dropping of pid files in cluster and daemon mode * Nested partials don't blow away locals. * Better loading of classes * Support concat and test capture/concat * Added single key assignment to Merb.config * Move url method from ControllerMixin to AbstractController for use in Mailers and Parts etc. * Merb.config now returns Merb::Config instead of the current configuration hash. * Added Merb.reload which reloads the framework classes. * Adding Merb.env shorthand for Merb.environment * Added a quaint Merb Configurator * With bootloader order changes, environment was not getting loaded * Fix cookie parsing from localhost, add spec * Add support for multiple template roots * Allow override of router.rb file in config * Modify behavior of 'namespace' in the router * Fix content negotiation for IE and its stupid accept header. * Only serve static files when the HTTP method is GET or HEAD. Other requests should still be handled by Merb. * Add path_prefix support. * Changes dispatch_to spec helper to yield the controller * redo of load_dependency, after_app_loads callback, and Kernel changes * Added Merb.logger.auto_flush * Fix nested resource routing * Do not drop PID file is not running as daemon or cluster * Fixed problem with resources inside a namespace block * Added support for dynamic layouts. * adding conditional behaviour to filters :if and :unless * Use the escape_xml from Erubis rather than rolling our own * Add a merb.reload! command to the merb -i console. * Get rid of StringScanner dependency. * Fix render_then_call to support new streaming tech. * Fix filter specs to respect append order of filters. * check for empty string before calling to_sym on the format parameter * fake requests are incorrectly loading controller classes with namespaces * Fix the RubyGems monkeypatch by testing for Merb.root instead of looking in $" * fix core spec dependency on merb_rspec * Replace calls to puts with Merb.logger * Fix problem with static files, use Proc === body * Added file and line information for evals in router.rb. == 0.9.0 "All you need, none you don't" 2008-02-13 * Developer Only Release * Split merb into merb-core and merb-more == 0.5.3 "Inexperienced With Girls" 2008-01-28 * Improved handling of models/controllers with dependencies * Improved cluster starting/stopping * Frozen script/merb should really work now * Merb::Cookies is used for cookie jar purposes * test_helper no longer assumes rspec mocking framework * asset bundler handles strings and symbols * render() now has an option for explicitly rendering an object * Fixed annoying bug in exception rendering for 500 internal_server_error * testing request helper accepts an option hash == 0.5.2 "Great White North" 2008-01-14 * Make Merb.load_paths accessible for modification * Fix issues with running frozen apps == 0.5.1 "Electic Boogaloo" 2008-01-10 * Fix 0.5.0 == 0.5.0 "Thanks Zed" 2008-01-09 * Added asset bundling for Javascript and stylesheet files == 0.4.2 "Surf's up." 2007-12-14 * Super-huge speed boost for rendering Erubis templates with partials * Windows-specific fixes to Merb's Rakefile * Blocking write is called when in development, test, Windows and jRuby environments and platforms. * merb_helpers: form field labels are now explicit, huge documentation update, added select, fieldset, more helpers * Fixed merb.show_routes within merb -i * Fixed image_tag, css_include_tag, and js_include_tag to work with path_prefix * Adds spec helper methods with_route and dispatch_to * fix rakefile cfor cygwin * add count with collection to partial() * Form control mixin is deprecated Use merb_helpers plugin. * add redirect matcher to rspec test helpers * allow r.resource(:foo, :myparam => 42) resource routes pass on params to underlying match() call * spit out error and help message if you call merb with no args * get rid of dependency on mongrel for escape and unescape * make sure not to use write_nonblock when logging to STDOUT * Fixed image_tag, css_include_tag, and js_include_tag to work with path_prefix * fix set_status to actually work, add docs, * config/merb.yml is now correctly loaded from Rake and test environment - using Merb::Server.load_config * added config option to disable loading of the JSON gem - still enabled by default * don't raise if names local on a partial is nil * Use svn export instead of checkout upon merb:freeze_from_svn * Extracted url and other general methods out of ControllerMixin into GeneralControllerMixin * fix caching of @_buffer in render, form_for * Seperates spec helpers into the Merb::Test namespace to prevent spec methods leaking into specs * Changes the spec url helper method to the same used in the controller * Made Request#parse_multipart return an empty hash instead of nil if the request is not multipart * Changes throw_content so that it can be called without a block * Added :namespace option to routes. == 0.4.1 "Faster Partials or Partially Faster?" 2007-11-12 * Fixed pluralization issues with generators * Resource generators are much improved * url() helper now supports nested resources * url(:post, @post) observers @post.new_record? and adjusts accordingly * Fixed bug with empty Accept headers * Added config/boot.rb to load framework from gems or framework/ dir * New partial() is much faster (and less buggy) * render :partial no longer supported * Add a buffered logger * Fixes bug with parameterized actions on some platforms * partial can now be called on collections: * partial("widget", :with => @new_widgets, :as => "widget") * SMTP mailer now supports non-AUTH setups * set_status() can take symbolic codes like :not_found * JRuby compat fixes * Speed boost, esp. with rendering * Fix spec_helper running against development database * Fix major bug with sessions not working == 0.4.0 "This ain't yo mommas merb" 2007-11-06 == 0.3.7 "Out of the basement" 2007-08-05 == 0.3.4 "Route fixer" 2007-05-31 == 0.3.3 "Hey buddy can you spare a route generator?" 2007-05-31 == 0.3.1 "The Fixed and the Furious" 2007-04-30 == 0.3.0 "The Fast and the Furious" 2007-04-28 == 0.2.0 "Accept your fate and respond_to change" 2007-03-18 == 0.1.0 "Generation Herb" 2007-01-18 == 0.0.9 "merb is the new black" 2007-01-14 == 0.0.8 "Merbivore" 2006-12-17 == 0.0.7 "Lean and mean merbing machine" 2006-11-29 == 0.0.6 "The Black Belt Release" 2006-11-09 == 0.0.5 "The getting real release" 2006-11-01 == 0.0.4 "The toddler phase" 2006-10-26 == 0.0.3 "the switchblade suicide release" 2006-10-17 == 0.0.2 "the quicksliver release" 2006-10-16 == 0.0.1 "The pocket rocket release" 2006-10-15 ruby-merb-core_1.1.3.orig/CONTRIBUTORS000066400000000000000000000034621175250300200172470ustar00rootroot00000000000000Use merb? Say thanks the following people: Aaron Wheeler Abhay Kumar Adam Jacob Andy C Andy Delcambre Antti Tarvainen Ben Burkert Ben Chiu Ben Griffiths Bradly Feeley Brandon Dimcheff Brandon Mitchell Brian Mitchell Bryan Ray Carl Lerche Carlos Villela Charles Jolley Cheah Chu Yeow Chris Van Pelt Coda Hale Cory ODaniel Cristi Balan Damian Terentiev Daniel Neighman Daniel Schierbeck Daniel Siemssen David James Debian User Diego Scataglini Dirkjan Bussink Dr Nic Drew Colthorp Duane Johnson Dudley Flanders Eric D. White Ezra Zygmuntowicz Fabien Franzen Flea Foy Savas Gabe Geoffrey Grosenbach Gert Goet Glenn Rempe Goh Toh Chye Grant Hollingworth Guillaume Maury Hampton Catlin Ho-Sheng Hsiao Jack Dempsey Jakub Šťastný aka Botanicus James Herdman James Whiteman Janne Asmala Jarkko Laine Jaroslaw Zabiello Jed Hurt Jonas Nicklas Jonathan Stott Jonathan Younger Josh Nichols Justin Pease Justin S. Leitgeb Kyle Drake Lachie Cox Lance Carlson Loren Segal Lori Holden Maciej Piechotka Martin Grund Mason Browne Matt Aimonetti Matt Todd Matthew Ford Matthew Windwer Matthijs Langenberg Max Aller Max Lapshin Michael D'Auria Michael D. Ivey Michael Holub Michael Klishin Michael Latta Michael S. Klishin Michael Sheakoski Mirko Froehlich Nathan Weizenbaum Nick Dufresne Nicos Gollan Nikos Dimitrakopoulos Oliver Jakubiec Paul Barry Paul Boone Paul Carey Ray Morgan Rich Cavanaugh Richard Grundy Rob Ares Rob Kaufman Ross Lawley Sergey Molodtsoff Seth Thomas Rasmussen Shalon Wood Shay Arnett Simon Jefford Simon Rozet Sindre Aarsaether StarTrader Steve Tooke Thomas Reynolds Tim Kofol Tyler Hunt Tymon (teamon) Tobolski Wayne E. Seguin Wayne Larsen Wesley Beary Will Prater William Smith Wilson Bilkovich Yehuda Katz Zach Holt atmos booss brainopia gert@pacificstarfish.net jonas jonuts macournoyer mde michael.s.klishin@gmail.com rick wvlruby-merb-core_1.1.3.orig/LICENSE000066400000000000000000000020431175250300200163660ustar00rootroot00000000000000Copyright (c) 2008 Engine Yard Inc. 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.ruby-merb-core_1.1.3.orig/PUBLIC_CHANGELOG000066400000000000000000000151521175250300200176360ustar00rootroot0000000000000010/06/2008: * Use -L option or :log_file or :log_stream in init.rb or env init file to point logger where you want. 10/05/2008: * Merb does not add spec tasks to Rakefiles list by default. Add require "merb-core/test/tasks/spectasks" in your existing Rakefiles explicitly. This is done so that test unit users do not get spec tasks they do not need down their throat in any merb application, even running on just -core. * Dictionary and inflection code are now parts of Extlib library and shared with other frameworks that use it (DataMapper, Halcyon, Mack, etc). 9/26/2008: * For Merb developers, Rakefile features a new implementation of the :install and :uninstall tasks. These will work with Gems directly, without running the intermediate commands on the shell. This means 'sudo' is now explicitly needed when installing gems system-wide; implicit sudo (prompt) is considered harmful. The new code will write appropriate executable wrappers that feature local gem loading and minigems usage. All gems in -more and -core now use this new (un)install procedure. 9/25/2008: * Merb::Config[:reload_templates] needs to be set explicitly in config/environments/development.rb - which is true for newly generated apps. Previously Merb.env?(:development) meant that reload_templates was enabled. Since we don't want to depend on Merb.env like that, we're using Merb::Config. 9/24/2008: * Kernel#dependency and Kernel#load_dependency will now register the requested dependency on Merb::BootLoader::Dependencies.dependencies. Doing so creates a Gem::Dependency instance, which will be returned from these methods. Before, an Array of [name, ver] was returned. Working with Gem::Dependency makes the dependency information more uniform, regardless of the original version requirements. 9/13/2008: * Merb apps will always give priority to gems that are available locally in Merb.root / gems. Because of the specific load order, you will need to use bin/merb to load merb-core from local gems, as detailed below. This is also the case for bin/merb-gen, bin/rake and bin/spec for example. The added advantage is that your app will be completely independent from system gems. * Thor tasks 'merb.thor' have been added for newly generated apps; regenerate your app to get them; alternatively these are available on merbivore.com: http://merbivore.com/merb.thor * Release 0.9.6 introduced 'merb-gen scripts' which added script/merb and script/merb-gen. However, now that merb.thor provides tasks to manage bundled gems, we can directly extract the correct executables. To follow the standard convention, these will be installed in ./bin instead of ./script. With merb.thor installed, run the following to get started: $ thor merb:tasks:setup # adds bin/thor, bin/rake etc. As soon as you install other gems using merb.thor you'll have the required bin executables available; these are setup so that running them will load merb-core from the local gems dir, not from the system-wide rubygems. To get bin/merb and bin/merb-gen for a fresh application, you can use: $ thor merb:stable -a mongrel # install a full merb stack from stable rubygems Alternatively, you can install from the bleeding edge: $ thor merb:edge --install # install a full merb stack from github $ thor merb:gems:install mongrel # or ebb, thin... 9/5/2008: * Language::English::Inflector is now English::Inflect - be sure to change your custom inflections in config/init.rb. Additionally, the merb-gen template config/init.rb has been changed to document the features accordingly. 9/2/2008: * AbstractController now uniformly uses instance_eval for Procs where previously the controller instance (self) was passed as an argument: - Procs thrown during dispatch - Procs used as before/after filters - Procs used as conditions to before/after filters This means that code like this: proc { |c| c.a_controller_method } Becomes the following for the cases mentioned: proc { a_controller_method } 8/29/2008: * The directory Merb.root / 'framework' is now gone - framework gems are expected to be installed as local gems in Merb.root / 'gems': sudo gem install merb -i ./gems * The notion of a frozen application setup (using bundled gems) is now known as a bundled setup; Merb.frozen? => Merb.bundled? By default an app uses bundled gems (the -B or --bundle options to merb), to disable this use the option --no-bundle. 8/27/2008: * Merb::Request#protocol now returns valid protocol names: http, not http://. 8/22/2008: * controller.cookies['foo'] = { ... } (Hash with options) is now deprecated; use controller.cookies['foo'] = 'bar' for simple cookies without options, or use controller.cookies.set_cookie('foo', 'bar', options) for more control. 8/21/2008: * Memcached sessions are now configured by assignment to Merb::MemcachedSession.store (previously the CACHE constant was used) * Added Merb::Config[:ignore_tampered_cookies] option to skip cookie warnings during development. This defaults to 'on' in the development environment. * Merb::Config[:session_store] or Merb::Config[:session_stores] now accept an Array (or String); when an Array is given, multiple session stores will be available to the application. * If you have custom session stores (that inherit from Merb::SessionContainer) be sure to require them in your init.rb 8/20/2008: * Merb::Config[:session_cookie_domain] is now Merb::Config[:default_cookie_domain] * Merb.registered_session_types is now Merb::Request.registered_session_types * When running in :development env, cookie-based sessions won't bother you by raising TamperedWithCookie anymore. 8/14/2008: * Merb.orm_generator_scope and friends are renamed. ** Merb.orm_generator_scope => Merb.orm ** Merb.test_framework_generator_scope => Merb.test_framework ** Added Merb.template_engine Merb-gen is updated accordingly. This let us add --haml and similar options to merb-gen and plugin generators. 8/10/2008: * Modified the way Exceptions are handled in the Dispatcher ** To rescue all exceptions, supply Exceptions#exception ** To rescue all Merb-generated exceptions, supply Exceptions#base ** Exceptions#internal_server_error is no longer a catch-all and should not be used as such. 6/22/2008: Erubis modified: * <%= %> now can take a block, so <%= helper do %>Hello<% end %> now works * Erubis buffer is now an ivar (@_erb_buf), which eliminates the need for eval in capture helpers. CONSEQUENCE: Helpers that take a block should simply return a string, and should not use concat. Example: def my_helper(&blk) "My helper says #{capture(&blk)}." endruby-merb-core_1.1.3.orig/README000066400000000000000000000032531175250300200162450ustar00rootroot00000000000000merb-core A new branch of Merb (sometimes referred to as merb-next) which aims to provide a stable, stripped down API for the Merb 1.0 release. This branch was based off the 0.5 release series with *significant* rewrites. Goals of this release: * Stabilize the @public interface methods to provide for a more consistent application development experience. * Remove features until nothing except a central application API is left * Improve comments on methods using a standard documentation methodology as described in DOCUMENTATION_STANDARDS * Separate the tests into two sections... "private" and "public" * Public methods are methods tagged with @public that will be part of the standard, stable Merb API * Private methods are implementation methods that might * Implement a new render API * Build more extensions to regain selected features when needed To familiarize yourself with how a merb-core application might look, use merb-gen (from merb-more) to generate a few apps: $ merb-gen app myapp # merb stack app, assuming you are using DM and RSpec The only option you can use with stack is --template_engine=(erb|haml). Default is erb. $ merb-gen core myapp # a "regular" app without any predefined dependencies Options available: --orm=datamapper --orm=sequel --orm=activerecord Default is no ORM. --testing_framework=rspec --testing_framework=test_unit Default is rspec. --template_enging=erb --template_enging=haml Default is erb. $ merb-gen flat myapp # a flattened app: one file and directory for views Options are same as for "regular" app. $ merb-gen very_flat myapp # a single-file app Options are same as for "regular" app.ruby-merb-core_1.1.3.orig/Rakefile000066400000000000000000000157261175250300200170420ustar00rootroot00000000000000require 'rubygems' require 'rake' require "rake/rdoctask" require "rake/testtask" require "spec/rake/spectask" require "fileutils" # Load code annotation support library require File.expand_path("../tools/annotation_extract", __FILE__) include FileUtils desc "Run the specs." task :default => :specs task :merb => [:clean, :rdoc, :package] ############################################################################## # Documentation ############################################################################## task :doc => [:rdoc] namespace :doc do Rake::RDocTask.new do |rdoc| files = ["README", "LICENSE", "CHANGELOG", "lib/**/*.rb"] rdoc.rdoc_files.add(files) rdoc.main = "README" rdoc.title = "Merb Docs" rdoc.rdoc_dir = "doc/rdoc" rdoc.options << "--line-numbers" end desc "run webgen" task :webgen do sh %{cd doc/site; webgen} end end ############################################################################## # rSpec & rcov ############################################################################## desc "Run :specs, :rcov" task :aok => [:specs, :rcov] def setup_specs(name, spec_cmd='spec', run_opts = "-c") except = [] except += Dir["spec/**/memcache*_spec.rb"] if ENV['MEMCACHED'] == 'no' public_globs = Dir["#{Dir.pwd}/spec/public/**/*_spec.rb"].reject{|file| file.include?('/gems/')} public_globs_10 = Dir["#{Dir.pwd}/spec10/public/**/*_spec.rb"].reject{|file| file.include?('/gems/')} private_globs = Dir["#{Dir.pwd}/spec/private/**/*_spec.rb"] desc "Run all specs (#{name})" task "specs:#{name}" do require "lib/merb-core/test/run_specs" globs = public_globs + private_globs run_specs(globs, spec_cmd, ENV['RSPEC_OPTS'] || run_opts, except) end desc "Run 1.0 frozen specs" task "specs:oneoh" do require "lib/merb-core/test/run_specs" globs = public_globs_10 run_specs(globs, spec_cmd, ENV['RSPEC_OPTS'] || run_opts, except) end desc "Run private specs (#{name})" task "specs:#{name}:private" do require "lib/merb-core/test/run_specs" run_specs(private_globs, spec_cmd, ENV['RSPEC_OPTS'] || run_opts) end desc "Run public specs (#{name})" task "specs:#{name}:public" do require "lib/merb-core/test/run_specs" run_specs(public_globs, spec_cmd, ENV['RSPEC_OPTS'] || run_opts) end # With profiling formatter desc "Run all specs (#{name}) with profiling formatter" task "specs:#{name}_profiled" do require "lib/merb-core/test/run_specs" run_specs("spec/**/*_spec.rb", spec_cmd, "-c -f o") end desc "Run private specs (#{name}) with profiling formatter" task "specs:#{name}_profiled:private" do require "lib/merb-core/test/run_specs" run_specs("spec/private/**/*_spec.rb", spec_cmd, "-c -f o") end desc "Run public specs (#{name}) with profiling formatter" task "specs:#{name}_profiled:public" do require "lib/merb-core/test/run_specs" run_specs("spec/public/**/*_spec.rb", spec_cmd, "-c -f o") end end setup_specs("mri", "spec") setup_specs("jruby", "jruby -S spec") task "specs:core_ext" do require "lib/merb-core/test/run_specs" run_specs("spec/public/core_ext/*_spec.rb", "spec", "-c -f o") end task "spec" => ["specs:mri"] task "specs" => ["specs:mri"] task "specs:private" => ["specs:mri:private"] task "specs:public" => ["specs:mri:public"] desc "Run coverage suite" task :rcov do require 'fileutils' FileUtils.rm_rf("coverage") if File.directory?("coverage") FileUtils.mkdir("coverage") path = File.expand_path(Dir.pwd) files = Dir["spec/**/*_spec.rb"] files.each do |spec| puts "Getting coverage for #{File.expand_path(spec)}" command = %{rcov #{File.expand_path(spec)} --aggregate #{path}/coverage/data.data --exclude ".*" --include-file "lib/merb-core(?!\/vendor)"} command += " --no-html" unless spec == files.last `#{command} 2>&1` end end desc "Run a specific spec with TASK=xxxx" Spec::Rake::SpecTask.new("spec") do |t| t.spec_opts = ["--colour"] t.libs = ["lib", "server/lib" ] t.spec_files = (ENV["TASK"] || '').split(',').map do |task| "spec/**/#{task}_spec.rb" end end desc "Run all specs output html" Spec::Rake::SpecTask.new("specs_html") do |t| t.spec_opts = ["--format", "html"] t.libs = ["lib", "server/lib" ] t.spec_files = Dir["spec/**/*_spec.rb"].sort end ############################################################################## # CODE STATISTICS ############################################################################## STATS_DIRECTORIES = [ ['Code', 'lib/'], ['Unit tests', 'spec'] ].collect { |name, dir| [ name, "./#{dir}" ] }. select { |name, dir| File.directory?(dir) } desc "Report code statistics (KLOCs, etc) from the application" task :stats do require File.expand_path("../tools/code_statistics", __FILE__) # require "extra/stats" verbose = true CodeStatistics.new(*STATS_DIRECTORIES).to_s end ############################################################################## # SYNTAX CHECKING ############################################################################## task :check_syntax do `find . -name "*.rb" |xargs -n1 ruby -c |grep -v "Syntax OK"` puts "* Done" end # Run specific tests or test files. Searches nested spec directories as well. # # Based on a technique popularized by Geoffrey Grosenbach rule "" do |t| spec_cmd = (RUBY_PLATFORM =~ /java/) ? "jruby -S spec" : "spec" # spec:spec_file:spec_name if /spec:(.*)$/.match(t.name) arguments = t.name.split(':') file_name = arguments[1] spec_name = arguments[2..-1] spec_filename = "#{file_name}_spec.rb" specs = Dir["spec/**/#{spec_filename}"] if path = specs.detect { |f| spec_filename == File.basename(f) } run_file_name = path else puts "No specs found for #{t.name.inspect}" exit end example = " -e '#{spec_name}'" unless spec_name.empty? sh "#{spec_cmd} #{run_file_name} --colour #{example}" end end ############################################################################## # Flog ############################################################################## namespace :flog do task :worst_methods do require "flog" flogger = Flog.new flogger.flog_files Dir["lib/**/*.rb"] totals = flogger.totals.sort_by {|k,v| v}.reverse[0..10] totals.each do |meth, total| puts "%50s: %s" % [meth, total] end end task :total do require "flog" flogger = Flog.new flogger.flog_files Dir["lib/**/*.rb"] puts "Total: #{flogger.total}" end task :per_method do require "flog" flogger = Flog.new flogger.flog_files Dir["lib/**/*.rb"] methods = flogger.totals.reject { |k,v| k =~ /\#none$/ }.sort_by { |k,v| v } puts "Total Flog: #{flogger.total}" puts "Total Methods: #{flogger.totals.size}" puts "Flog / Method: #{flogger.total / methods.size}" end end namespace :tools do namespace :tags do desc "Generates Emacs tags using Exuberant Ctags." task :emacs do sh "ctags -e --Ruby-kinds=-f -o TAGS -R lib" end end end ruby-merb-core_1.1.3.orig/TODO000066400000000000000000000000001175250300200160400ustar00rootroot00000000000000ruby-merb-core_1.1.3.orig/bin/000077500000000000000000000000001175250300200161325ustar00rootroot00000000000000ruby-merb-core_1.1.3.orig/bin/merb000077500000000000000000000007251175250300200170110ustar00rootroot00000000000000#!/usr/bin/env ruby begin # Just in case the bundle was locked # This shouldn't happen in a dev environment but lets be safe require File.expand_path('.bundle/environment', __FILE__) rescue LoadError require 'rubygems' require 'bundler' Bundler.setup end require 'merb-core' ARGV.push '-H' if ARGV[0] && ARGV[0] =~ /^[^-]/ unless %w[-a --adapter -i --irb-console -r --script-runner].any? { |o| ARGV.index(o) } ARGV.push *%w[-a mongrel] end Merb.start ruby-merb-core_1.1.3.orig/bin/merb-specs000077500000000000000000000001711175250300200201170ustar00rootroot00000000000000#!/usr/bin/env ruby require File.join(File.dirname(__FILE__),"..","lib","merb-core","test","run_specs") run_specs ARGV ruby-merb-core_1.1.3.orig/lib/000077500000000000000000000000001175250300200161305ustar00rootroot00000000000000ruby-merb-core_1.1.3.orig/lib/merb-core.rb000066400000000000000000000573011175250300200203360ustar00rootroot00000000000000# require 'merb' must happen after Merb::Config is instantiated # Add the local gems dir if found within the app root; any dependencies loaded # hereafter will try to load from the local gems before loading system gems. root_key = %w[-m --merb-root].detect { |o| ARGV.index(o) } root = ARGV[ARGV.index(root_key) + 1] if root_key root = root.to_a.empty? ? Dir.getwd : root require "bundler" require "thread" require "set" require "fileutils" require "socket" require "pathname" require "extlib" require "extlib/dictionary" Thread.abort_on_exception = true __DIR__ = File.dirname(__FILE__) $LOAD_PATH.unshift __DIR__ unless $LOAD_PATH.include?(__DIR__) || $LOAD_PATH.include?(File.expand_path(__DIR__)) # Some dependencies tend to require&rescue for optionally required files; # doing so will load the full rubygems, even though it was just optional. $MINIGEMS_SKIPPABLE = ['encoding/character/utf-8'] module Merb # Create stub module for global controller helpers. module GlobalHelpers; end class ReservedError < StandardError; end class << self attr_reader :exiting # The list of procs that have been registered with Merb to run when # Merb exits gracefully. # # ==== Returns # Array:: The current list of procs # # :api: private def at_exit_procs @at_exit_procs ||= [] end # Set the current exiting state of Merb. Setting this state to true # also alerts Extlib to exit and clean up its state. # # ==== Returns # Boolean:: The current exiting state of Merb # # :api: private def exiting=(bool) Extlib.exiting = bool @exiting = bool if bool if Extlib.const_defined?("Pooling") && Extlib::Pooling.scavenger Extlib::Pooling.scavenger.wakeup end while prc = self.at_exit_procs.pop prc.call end unless Merb::Config[:reap_workers_quickly] end @exiting end # Register a proc to run when Merb is exiting gracefully. It will *not* # be run when Merb exits quickly. # # ==== Returns # Array:: The current list of procs to run when Merb exits gracefully # # :api: plugin def at_exit(&blk) self.at_exit_procs << blk end # Merge environment settings # # This can allow you to have a "localdev" environment that runs like your "development". # OR # A "staging" environment that runs identical to your "production" environment. # # ==== Examples # From any environment config file (ie, development.rb, custom.rb, localdev.rb, etc). # staging.rb: # Merb.merge_env "production" # We want to use all the settings production uses # Merb::Config.use do |c| # c[:log_level] = "debug" # except we want debug log level # c[:log_stream] = @some_io # and log to this IO handle # c[:exception_details] = true # and we want to see exception details # end # # ==== Parameters # env<~String>:: Environment to run like # use_db<~Boolean>:: Should Merb use the merged environments DB connection # Defaults to +false+ # # :api: public def merge_env(env,use_db=false) if Merb.environment_info.nil? Merb.environment_info = { :real_env => Merb.environment, :merged_envs => [], :db_env => Merb.environment } end #Only load if it hasn't been loaded unless Merb.environment_info[:merged_envs].member? env Merb.environment_info[:merged_envs] << env env_file = Merb.dir_for(:config) / "environments" / ("#{env}.rb") if File.exists?(env_file) load(env_file) else Merb.logger.warn! "Environment file does not exist! #{env_file}" end end # Mark specific environment to load when ORM loads, # if multiple environments are loaded, the last one # with use_db as TRUE will be loaded if use_db Merb.environment_info[:db_env] = env end end # Start Merb by setting up the Config and then starting the server. # Set the Merb application environment and the root path. # # ==== Parameters # argv:: # The config arguments to start Merb with. Defaults to +ARGV+. # # :api: public def start(argv = ARGV) Merb::Config[:original_log_stream] = Merb::Config[:log_stream] Merb::Config[:log_stream] ||= STDOUT if Hash === argv Merb::Config.setup(argv) elsif !argv.nil? Merb::Config.parse_args(argv) end # Keep information that we run inside IRB to guard it against overriding in init.rb @running_irb = Merb::Config[:adapter] == 'irb' Merb::Config[:log_stream] = STDOUT Merb.environment = Merb::Config[:environment] Merb.root = Merb::Config[:merb_root] case Merb::Config[:action] when :kill Merb::Server.kill(Merb::Config[:port], 2) when :kill_9 Merb::Server.kill(Merb::Config[:port], 9) when :fast_deploy Merb::Server.kill("main", "HUP") else Merb::Server.start(Merb::Config[:port], Merb::Config[:cluster]) @started = true end end # Start the Merb environment, but only if it hasn't been loaded yet. # # ==== Parameters # argv:: # The config arguments to start Merb with. Defaults to +ARGV+. # # :api: public def start_environment(argv=ARGV) start(argv) unless (@started ||= false) end # Restart the Merb environment explicitly. # # ==== Parameters # argv:: # The config arguments to restart Merb with. Defaults to +Merb::Config+. # # :api: public def restart_environment(argv={}) @started = false start_environment(Merb::Config.to_hash.merge(argv)) end # :api: public attr_accessor :environment, :adapter # :api: private attr_accessor :load_paths, :environment_info, :started # :api: public alias :env :environment # :api: public alias :started? :started Merb.load_paths = Dictionary.new { [Merb.root] } unless Merb.load_paths.is_a?(Dictionary) # This is the mechanism for setting up your application layout. # There are three application layouts in Merb: # # 1. Regular app/:type layout of Ruby on Rails fame: # # app/models for models # app/mailers for mailers (special type of controllers) # app/parts for parts, Merb components # app/views for templates # app/controllers for controller # lib for libraries # # 2. Flat application layout: # # application.rb for models, controllers, mailers, etc # config/init.rb for initialization and router configuration # config/framework.rb for framework and dependencies configuration # views for views # # 3. Camping-style "very flat" application layout, where the whole Merb # application and configs are contained within a single file. # # ==== Notes # Autoloading for lib uses an empty glob by default. If you # want to have your libraries under lib use autoload, add # the following to Merb init file: # # Merb.push_path(:lib, Merb.root / "lib", "**/*.rb") # glob set explicity. # # Then lib/magicwand/lib/magicwand.rb with MagicWand module will # be autoloaded when you first access that constant. # # ==== Examples # This method gives you a way to build up your own application # structure, for instance, to reflect the structure Rails # uses to simplify transition of legacy application, you can # set it up like this: # # Merb.push_path(:model, Merb.root / "app" / "models", "**/*.rb") # Merb.push_path(:mailer, Merb.root / "app" / "models", "**/*.rb") # Merb.push_path(:controller, Merb.root / "app" / "controllers", "**/*.rb") # Merb.push_path(:view, Merb.root / "app" / "views", "**/*.rb") # # ==== Parameters # type:: The type of path being registered (i.e. :view) # path:: The full path # file_glob:: # A glob that will be used to autoload files under the path. Defaults to # "**/*.rb". # # :api: public def push_path(type, path, file_glob = "**/*.rb") enforce!(type => Symbol) load_paths[type] = [path, file_glob] end # Removes given types of application components # from load path Merb uses for autoloading. # # ==== Parameters # *args:: # component(s) names, for instance, :views, :models # # ==== Examples # Using this combined with Merb::GlobalHelpers.push_path you can make # your Merb application use legacy Rails application components. # # Merb.root = "path/to/legacy/app/root" # Merb.remove_paths(:mailer) # Merb.push_path(:mailer, Merb.root / "app" / "models", "**/*.rb") # # Will make Merb use app/models for mailers just like Ruby on Rails does. # # :api: public def remove_paths(*args) args.each {|arg| load_paths.delete(arg)} end # ==== Parameters # type:: The type of path to retrieve directory for, e.g. :view. # # ==== Returns # String:: The directory for the requested type. # # :api: public def dir_for(type) Merb.load_paths[type].first end # ==== Parameters # type:: The type of path to retrieve glob for, e.g. :view. # # ===== Returns # String:: The pattern with which to match files within the type directory. # # :api: public def glob_for(type) Merb.load_paths[type][1] end # ==== Returns # String:: The Merb root path. # # :api: public def root @root || Merb::Config[:merb_root] || File.expand_path(Dir.pwd) end # ==== Parameters # value:: Path to the root directory. # # :api: public def root=(value) @root = value end # ==== Parameters # *path:: # The relative path (or list of path components) to a directory under the # root of the application. # # ==== Returns # String:: The full path including the root. # # ==== Examples # Merb.root = "/home/merb/app" # Merb.path("images") # => "/home/merb/app/images" # Merb.path("views", "admin") # => "/home/merb/app/views/admin" # # @public def root_path(*path) File.join(root, *path) end # Return the Merb Logger object for the current thread. # Set it up if it does not exist. # # :api: public def logger Thread.current[:merb_logger] ||= Merb::Logger.new end # Removes the logger for the current thread (nil). # # :api: public def reset_logger! Thread.current[:merb_logger] = nil end # ==== Returns # String:: # The path to the log file. # If this Merb instance is running as a daemon this will return +STDOUT+. # # ==== Notes # When Merb.testing? the port is modified to become :test - this keeps this # special environment situation from ending up in the memoized @streams # just once, thereby never taking changes into account again. Now, it will # be memoized as :test - and just logging to merb_test.log. # # :api: public def log_stream(port = "main") port = :test if Merb.testing? @streams ||= {} @streams[port] ||= begin log = if Merb.testing? log_path / "merb_test.log" elsif !Merb::Config[:daemonize] && !Merb::Config[:force_logging] STDOUT else log_path / "merb.#{port}.log" end if log.is_a?(IO) stream = log elsif File.exist?(log) stream = File.open(log, (File::WRONLY | File::APPEND)) else FileUtils.mkdir_p(File.dirname(log)) stream = File.open(log, (File::WRONLY | File::APPEND | File::CREAT)) stream.write("#{Time.now.httpdate} #{Merb::Config[:log_delimiter]} " \ "info #{Merb::Config[:log_delimiter]} Logfile created\n") end stream.sync = true stream end end # ==== Returns # String:: Path to the log directory which contains the log file. # # :api: public def log_path case Merb::Config[:log_file] when String then File.dirname(Merb::Config[:log_file]) else Merb.root_path("log") end end # ==== Returns # String:: The path of root directory of the Merb framework. # # :api: public def framework_root @framework_root ||= File.dirname(__FILE__) end # ==== Returns # RegExp:: # Regular expression against which deferred actions # are matched by Rack application handler. # # ==== Notes # Concatenates :deferred_actions configuration option values. # # :api: public def deferred_actions @deferred ||= begin if Merb::Config[:deferred_actions].empty? /^\0$/ else /#{Merb::Config[:deferred_actions].join("|")}/ end end end # Perform a hard Exit. # Print a backtrace to the merb logger before exiting if verbose is enabled. # # :api: private def fatal!(str, e = nil) Merb::Config[:log_stream] = STDOUT if STDOUT.tty? Merb.reset_logger! Merb.logger.fatal! Merb.logger.fatal!("\e[1;31;47mFATAL: #{str}\e[0m") Merb.logger.fatal! print_colorized_backtrace(e) if e && Merb::Config[:verbose] if Merb::Config[:show_ugly_backtraces] raise e else exit(1) end end # Print a colorized backtrace to the merb logger. # # :api: private def print_colorized_backtrace(e) e.backtrace.map! do |line| line.gsub(/^#{Merb.framework_root}/, "\e[34mFRAMEWORK_ROOT\e[31m") end Merb.logger.fatal! "\e[34mFRAMEWORK_ROOT\e[0m = #{Merb.framework_root}" Merb.logger.fatal! Merb.logger.fatal! "\e[31m#{e.class}: \e[1;31;47m#{e.message}\e[0m" e.backtrace.each do |line| Merb.logger.fatal! "\e[31m#{line}\e[0m" end end # Set up default variables under Merb attr_accessor :klass_hashes, :orm, :test_framework, :template_engine # Returns the default ORM for this application. For instance, :datamapper. # # ==== Returns # :: default ORM. # # :api: public def orm @orm ||= :none end # @deprecated def orm_generator_scope Merb.logger.warn!("WARNING: Merb.orm_generator_scope is deprecated!") return :merb_default if Merb.orm == :none Merb.orm end # Returns the default test framework for this application. For instance :rspec. # # ==== Returns # :: default test framework. # # :api: public def test_framework @test_framework ||= :rspec end # @deprecated def test_framework_generator_scope Merb.logger.warn!("WARNING: Merb.test_framework_generator_scope is deprecated") Merb.test_framework end # Returns the default template engine for this application. For instance :haml. # # ==== Returns # :: default template engine. # # :api: public def template_engine @template_engine ||= :erb end Merb.klass_hashes = [] # ==== Returns # Boolean:: True if Merb is running as an application with bundled gems. # # ==== Notes # Bundling required gems makes your application independent from the # environment it runs in. It is a good practice to freeze application # framework and gems and is very useful when application is run in # some sort of sandbox, for instance, shared hosting with preconfigured gems. # # :api: public def bundled? $BUNDLE || ENV.key?("BUNDLE") end # ==== Returns # Boolean:: True if Merb is running in debug or verbose mode # # :api: public def verbose_logging? (ENV['DEBUG'] || $DEBUG || Merb::Config[:verbose]) && Merb.logger end # Load configuration and assign the logger. # # ==== Parameters # options:: Options to pass on to the Merb config. # # ==== Options # :host:: host to bind to, # default is 0.0.0.0. # # :port:: port to run Merb application on, # default is 4000. # # :adapter:: name of Rack adapter to use, # default is "runner" # # :rackup:: name of Rack init file to use, # default is "rack.rb" # # :reload_classes:: whether Merb should reload # classes on each request, # default is true # # :environment:: name of environment to use, # default is development # # :merb_root:: Merb application root, # default is Dir.pwd # # :use_mutex:: turns action dispatch synchronization # on or off, default is on (true) # # :log_delimiter:: what Merb logger uses as delimiter # between message sections, default is " ~ " # # :log_auto_flush:: whether the log should automatically # flush after new messages are # added, defaults to true. # # :log_stream:: IO handle for logger. Defaults to STDOUT. # # :log_file:: File path for logger. Overrides :log_stream. # # :log_level:: logger level, default is :info # # :disabled_components:: # array of disabled component names, # for instance, to disable json gem, # specify :json. Default is empty array. # # :deferred_actions:: # names of actions that should be deferred # no matter what controller they belong to. # Default is empty array. # # Some of these options come from command line on Merb # application start, some of them are set in Merb init file # or environment-specific. # # :api: public def load_config(options = {}) Merb::Config.setup(Merb::Config.defaults.merge(options)) Merb::BootLoader::Logger.run end # Load all basic dependencies (selected BootLoaders only). # This sets up Merb framework component paths # (directories for models, controllers, etc) using # framework.rb or default layout, loads init file # and dependencies specified in it and runs before_app_loads hooks. # # ==== Parameters # options:: Options to pass on to the Merb config. # # :api: public def load_dependencies(options = {}) load_config(options) Merb::BootLoader::BuildFramework.run Merb::BootLoader::Dependencies.run Merb::BootLoader::BeforeAppLoads.run end # Reload application and framework classes. # See Merb::BootLoader::ReloadClasses for details. # # :api: public def reload Merb::BootLoader::ReloadClasses.reload end # ==== Returns # Boolean:: True if Merb environment is testing for instance, # Merb is running with RSpec, Test::Unit of other testing facility. # # :api: public def testing? $TESTING ||= env?(:test) || Merb::Config[:testing] end # Ask the question about which environment you're in. # ==== Parameters # env:: Name of the environment to query # # ==== Examples # Merb.env #=> production # Merb.env?(:production) #=> true # Merb.env?(:development) #=> false # # :api: public def env?(env) Merb.env == env.to_s end # If block was given configures using the block. # # ==== Parameters # &block:: Configuration parameter block, see example below. # # ==== Returns # Hash:: The current configuration. # # ==== Notes # See Merb::GlobalHelpers.load_config for configuration # options list. # # ==== Examples # Merb.config do # beer "good" # hashish :foo => "bar" # environment "development" # log_level "debug" # use_mutex false # exception_details true # reload_classes true # reload_time 0.5 # end # # :api: public def config(&block) Merb::Config.configure(&block) if block_given? Config end # Disables the given core components, like a Gem for example. # # ==== Parameters # *args:: One or more symbols of Merb internal components. # # :api: public def disable(*components) disabled_components.push(*components) end # ==== Parameters # Array:: All components that should be disabled. # # :api: public def disabled_components=(components) disabled_components.replace components end # ==== Returns # Array:: All components that have been disabled. # # :api: public def disabled_components Merb::Config[:disabled_components] ||= [] end # ==== Returns # Boolean:: True if all components (or just one) are disabled. # # :api: public def disabled?(*components) components.all? { |c| disabled_components.include?(c) } end # ==== Returns # Array(String):: Paths Rakefiles are loaded from. # # ==== Notes # Recommended way to find out what paths Rakefiles # are loaded from. # # :api: public def rakefiles @rakefiles ||= [] end # === Returns # Array(String):: Paths generators are loaded from # # === Notes # Recommended way to find out what paths generators are loaded from. # # :api: public def generators @generators ||= [] end # ==== Parameters # *rakefiles:: Rakefile paths to add to the list of Rakefiles. # # ==== Notes # Recommended way to add Rakefiles load path for plugins authors. # # :api: public def add_rakefiles(*rakefiles) @rakefiles ||= [] @rakefiles += rakefiles end # ==== Parameters # *generators:: Generator paths to add to the list of generators. # # ==== Notes # Recommended way to add Generator load paths for plugin authors. # # :api: public def add_generators(*generators) @generators ||= [] @generators += generators end # Install a signal handler for a given signal unless signals have # been disabled with Merb.disable(:signals) # ==== Parameters # signal:: The name of the signal to install a handler for. # &block:: The block to be run when the given signal is received. # # :api: public def trap(signal, &block) if Signal.list.include?(signal) Kernel.trap(signal, &block) unless Merb.disabled?(:signals) end end # :api: plugin def forking_environment? !on_windows? && !on_jruby? end # :api: plugin def on_jruby? RUBY_PLATFORM =~ Merb::Const::JAVA_PLATFORM_REGEXP end # :api: plugin def on_windows? RUBY_PLATFORM =~ Merb::Const::WIN_PLATFORM_REGEXP end def run_later(&blk) Merb::Dispatcher.work_queue << blk end # :api: private def running_irb? @running_irb end end end require "merb-core/autoload" require "merb-core/server" require "merb-core/gem_ext/erubis" require "merb-core/logger" require "merb-core/version" require "merb-core/controller/mime" # Set the environment if it hasn't already been set. Merb.environment ||= ENV["MERB_ENV"] || Merb::Config[:environment] || (Merb.testing? ? "test" : "development") ruby-merb-core_1.1.3.orig/lib/merb-core/000077500000000000000000000000001175250300200200035ustar00rootroot00000000000000ruby-merb-core_1.1.3.orig/lib/merb-core/autoload.rb000066400000000000000000000017431175250300200221450ustar00rootroot00000000000000require 'merb-core/core_ext' require "merb-core/controller/exceptions" require "merb-core/controller/mixins/responder" require "merb-core/controller/mixins/render" require "merb-core/controller/mixins/authentication" require "merb-core/controller/mixins/conditional_get" require "merb-core/controller/mixins/controller" require "merb-core/controller/abstract_controller" require "merb-core/controller/template" require "merb-core/controller/merb_controller" require "merb-core/bootloader" require "merb-core/config" require "merb-core/constants" require "merb-core/dispatch/dispatcher" require "merb-core/plugins" require "merb-core/rack" require "merb-core/dispatch/request" require "merb-core/dispatch/request_parsers.rb" require "merb-core/dispatch/router" require "merb-core/dispatch/worker" module Merb autoload :Test, "merb-core/test" end # Require this rather than autoloading it so we can be sure the default template # gets registered module Merb module InlineTemplates; end end ruby-merb-core_1.1.3.orig/lib/merb-core/bootloader.rb000066400000000000000000001242701175250300200224700ustar00rootroot00000000000000module Merb class BootLoader # def self.subclasses # # :api: plugin cattr_accessor :subclasses, :after_load_callbacks, :before_load_callbacks, :finished, :before_worker_shutdown_callbacks, :before_master_shutdown_callbacks self.subclasses, self.after_load_callbacks, self.before_load_callbacks, self.finished, self.before_master_shutdown_callbacks, self.before_worker_shutdown_callbacks = [], [], [], [], [], [] class << self # Adds the inheriting class to the list of subclasses in a position # specified by the before and after methods. # # ==== Parameters # klass:: The class inheriting from Merb::BootLoader. # # ==== Returns # nil # # :api: plugin def inherited(klass) subclasses << klass.to_s super end # Execute this boot loader after the specified boot loader. # # ==== Parameters # klass<~to_s>:: # The boot loader class after which this boot loader should be run. # # ==== Returns # nil # # :api: plugin def after(klass) move_klass(klass, 1) nil end # Execute this boot loader before the specified boot loader. # # ==== Parameters # klass<~to_s>:: # The boot loader class before which this boot loader should be run. # # ==== Returns # nil # # :api: plugin def before(klass) move_klass(klass, 0) nil end # Move a class that is inside the bootloader to some place in the Array, # relative to another class. # # ==== Parameters # klass<~to_s>:: # The klass to move the bootloader relative to # where:: # 0 means insert it before; 1 means insert it after # # ==== Returns # nil # # :api: private def move_klass(klass, where) index = Merb::BootLoader.subclasses.index(klass.to_s) if index Merb::BootLoader.subclasses.delete(self.to_s) Merb::BootLoader.subclasses.insert(index + where, self.to_s) end nil end # Runs all boot loader classes by calling their run methods. # # ==== Returns # nil # # :api: plugin def run Merb.started = true subklasses = subclasses.dup until subclasses.empty? time = Time.now.to_i bootloader = subclasses.shift Merb.logger.debug!("Loading: #{bootloader}") if Merb.verbose_logging? Object.full_const_get(bootloader).run Merb.logger.debug!("It took: #{Time.now.to_i - time}") if Merb.verbose_logging? self.finished << bootloader end self.subclasses = subklasses nil end # Determines whether or not a specific bootloader has finished yet. # # ==== Parameters # bootloader:: The name of the bootloader to check. # # ==== Returns # Boolean:: Whether or not the bootloader has finished. # # :api: private def finished?(bootloader) self.finished.include?(bootloader.to_s) end # Set up the default framework # # ==== Returns # nil # # :api: plugin # @overridable def default_framework %w[view model helper controller mailer part].each do |component| Merb.push_path(component.to_sym, Merb.root_path("app/#{component}s")) end Merb.push_path(:application, Merb.root_path("app" / "controllers" / "application.rb")) Merb.push_path(:config, Merb.root_path("config"), nil) Merb.push_path(:router, Merb.dir_for(:config), (Merb::Config[:router_file] || "router.rb")) Merb.push_path(:lib, Merb.root_path("lib"), nil) Merb.push_path(:merb_session, Merb.root_path("merb" / "session")) Merb.push_path(:log, Merb.log_path, nil) Merb.push_path(:public, Merb.root_path("public"), nil) Merb.push_path(:stylesheet, Merb.dir_for(:public) / "stylesheets", nil) Merb.push_path(:javascript, Merb.dir_for(:public) / "javascripts", nil) Merb.push_path(:image, Merb.dir_for(:public) / "images", nil) nil end # Execute a block of code after the app loads. # # ==== Parameters # &block:: # A block to be added to the callbacks that will be executed after the # app loads. # # :api: public def after_app_loads(&block) after_load_callbacks << block end # Execute a block of code before the app loads but after dependencies load. # # ==== Parameters # &block:: # A block to be added to the callbacks that will be executed before the # app loads. # # :api: public def before_app_loads(&block) before_load_callbacks << block end # Execute a block of code before master process is shut down. # Only makes sense on platforms where Merb server can use forking. # # ==== Parameters # &block:: # A block to be added to the callbacks that will be executed # before master process is shut down. # # :api: public def before_master_shutdown(&block) before_master_shutdown_callbacks << block end # Execute a block of code before worker process is shut down. # Only makes sense on platforms where Merb server can use forking. # # ==== Parameters # &block:: # A block to be added to the callbacks that will be executed # before worker process is shut down. # # :api: public def before_worker_shutdown(&block) before_worker_shutdown_callbacks << block end end end end # Set up the logger. # # Place the logger inside of the Merb log directory (set up in # Merb::BootLoader::BuildFramework) class Merb::BootLoader::Logger < Merb::BootLoader # Sets Merb.logger to a new logger created based on the config settings. # # ==== Returns # nil # # :api: plugin def self.run Merb::Config[:log_level] ||= begin if Merb.environment == "production" Merb::Logger::Levels[:warn] else Merb::Logger::Levels[:debug] end end Merb::Config[:log_stream] = Merb::Config[:original_log_stream] || Merb.log_stream nil end end # Stores pid file. # # Only run if daemonization or clustering options specified on start. # Port is taken from Merb::Config and must be already set at this point. class Merb::BootLoader::DropPidFile < Merb::BootLoader class << self # Stores a PID file if Merb is running daemonized or clustered. # # ==== Returns # nil # # :api: plugin def run Merb::Server.store_pid("main") if Merb::Config[:daemonize] || Merb::Config[:cluster] nil end end end # Setup some useful defaults class Merb::BootLoader::Defaults < Merb::BootLoader # Sets up the defaults # # ==== Returns # nil # # :api: plugin def self.run Merb::Request.http_method_overrides.concat([ proc { |c| c.params[:_method] }, proc { |c| c.env['HTTP_X_HTTP_METHOD_OVERRIDE'] } ]) nil end end # Build the framework paths. # # By default, the following paths will be used: # application:: Merb.root/app/controller/application.rb # config:: Merb.root/config # lib:: Merb.root/lib # log:: Merb.root/log # view:: Merb.root/app/views # model:: Merb.root/app/models # controller:: Merb.root/app/controllers # helper:: Merb.root/app/helpers # mailer:: Merb.root/app/mailers # part:: Merb.root/app/parts # # To override the default, set Merb::Config[:framework] in your initialization # file. Merb::Config[:framework] takes a Hash whose key is the name of the # path, and whose values can be passed into Merb.push_path (see Merb.push_path # for full details). # # ==== Notes # All paths will default to Merb.root, so you can get a flat-file structure by # doing Merb::Config[:framework] = {}. # # ==== Example # Merb::Config[:framework] = { # :view => Merb.root / "views", # :model => Merb.root / "models", # :lib => Merb.root / "lib", # :public => [Merb.root / "public", nil] # :router => [Merb.root / "config", "router.rb"] # } # # That will set up a flat directory structure with the config files and # controller files under Merb.root, but with models, views, and lib with their # own folders off of Merb.root. class Merb::BootLoader::BuildFramework < Merb::BootLoader class << self # Builds the framework directory structure. # # ==== Returns # nil # # :api: plugin def run $:.push Merb.root unless Merb.root == File.expand_path(Dir.pwd) STDOUT.puts "Merb root at: #{Merb.root}" unless Merb.testing? build_framework nil end # Sets up merb paths to support the app's file layout. First, config/framework.rb is checked, # next we look for Merb.root/framework.rb, finally we use the default merb layout (Merb::BootLoader.default_framework) # # This method can be overriden to support other application layouts. # # ==== Returns # nil # # :api: plugin # @overridable def build_framework if File.exists?(Merb.root / "config" / "framework.rb") require Merb.root / "config" / "framework" elsif File.exists?(Merb.root / "framework.rb") require Merb.root / "framework" else Merb::BootLoader.default_framework end (Merb::Config[:framework] || {}).each do |name, path| path = Array(path) Merb.push_path(name, path.first, path.length == 2 ? path[1] : "**/*.rb") end nil end end end class Merb::BootLoader::Dependencies < Merb::BootLoader # ==== Returns # Array[Gem::Dependency]:: The dependencies registered in init.rb. # # As of Merb.1.1 these dependencies only get loaded when # Merb::Config[:kernel_dependencies] is set to true. # # This will be removed as of Merb 2.0 # # :api: plugin # @deprecated cattr_accessor :dependencies self.dependencies = [] # Load the init_file specified in Merb::Config or if not specified, the # init.rb file from the Merb configuration directory, and any environment # files and any after_app_loads hooks. # # Dependencies are loaded via Bunlder and managed in the Gemfile manifest. # By default manifest for Bundler is in the root directory of the app and # is called Gemfile. All dependencies MUST be definied there because all # dependency hangling was removed from Merb. # # ==== Deprecated (1.0.x) # Dependencies can hook into the bootloader process itself by using # before or after insertion methods. Since these are loaded from this # bootloader (Dependencies), they can only adapt the bootloaders that # haven't been loaded up until this point. # # ==== Returns # nil # # :api: plugin def self.run set_encoding load_dependencies unless Merb::disabled?(:initfile) load_initfile load_env_config end expand_ruby_path enable_json_gem unless Merb::disabled?(:json) update_logger nil end # Try to load the gem environment file (set via Merb::Config[:gemenv]) # defaults to ./gems/environment # # Load each the dependencies defined in the Merb::Config[:gemfile] # using the bundler gem's Bundler::require_env # # Falls back to rubygems if no bundler environment exists # # ==== Returns # nil # # :api: private def self.load_dependencies begin Bundler.require(:default, Merb.environment.to_sym) rescue Bundler::GemfileNotFound Merb.logger.error! "No Gemfile found! If you're generating new app with merb-gen " \ "this is fine, otherwise run: bundle init to create Gemfile" end nil end # Requires json or json_pure. # # ==== Returns # nil # # :api: private def self.enable_json_gem require "json" rescue LoadError Merb.logger.error! "You have enabled JSON but don't have json " \ "installed or don't have dependency in the Gemfile. " \ "Add \"gem 'json', '>= 1.1.7'\" or " \ "\"gem 'json_pure', '>= 1.1.7'\" to your Gemfile." end # Resets the logger and sets the log_stream to Merb::Config[:log_file] # if one is specified, falling back to STDOUT. # # ==== Returns # nil # # :api: private def self.update_logger Merb.reset_logger! # If log file is given, use it and not log stream we have. if Merb::Config[:log_file] log_file = Merb::Config[:log_file] raise "log file should be a string, got: #{log_file.inspect}" unless log_file.is_a?(String) STDOUT.puts "Logging to file at #{log_file}" unless Merb.testing? # try to create log directory (if it doesnt exist) log_directory = File.dirname(log_file) FileUtils.mkdir_p(log_directory) unless File.exists?(log_directory) Merb::Config[:log_stream] = File.open(log_file, "a") # but if it's not given, fallback to log stream or stdout else Merb::Config[:log_stream] ||= STDOUT end nil end # Default encoding to UTF8 if it has not already been set to something else. # # ==== Returns # nil # # :api: private def self.set_encoding unless RUBY_VERSION >= '1.9' $KCODE = 'UTF8' if $KCODE == 'NONE' || $KCODE.blank? end nil end private # Determines the path for the environment configuration file # # ==== Returns # String:: The path to the config file for the environment # # :api: private def self.env_config Merb.dir_for(:config) / "environments" / (Merb.environment + ".rb") end # Checks to see whether or not an environment configuration exists # # ==== Returns # Boolean:: Whether or not the environment configuration file exists. # # :api: private def self.env_config? Merb.environment && File.exist?(env_config) end # Loads the environment configuration file, if it is present # # ==== Returns # nil # # :api: private def self.load_env_config if env_config? env_config_path = relative_to_merb_path(env_config) STDOUT.puts "Loading #{env_config_path}" unless Merb.testing? load(env_config) end nil end # Determines the init file to use, if any. # By default Merb uses init.rb from application config directory. # # ==== Returns # nil # # :api: private def self.initfile if Merb::Config[:init_file] Merb::Config[:init_file].chomp(".rb") + ".rb" else Merb.dir_for(:config) / "init.rb" end end # Loads the init file, should one exist # # ==== Returns # nil # # :api: private def self.load_initfile return nil if Merb.const_defined?("INIT_RB_LOADED") if File.exists?(initfile) initfile_path = relative_to_merb_path(initfile) STDOUT.puts "Loading init file from #{initfile_path}" unless Merb.testing? load(initfile) Merb.const_set("INIT_RB_LOADED", true) elsif !Merb.testing? Merb.fatal! "You are not in a Merb application, or you are in " \ "a flat application and have not specified the init file. If you " \ "are trying to create a new merb application, use merb-gen app." end nil end # Expands Ruby path with framework directories (for models, lib, etc). Only run once. # # ==== Returns # nil # # :api: private def self.expand_ruby_path # Add models, controllers, helpers and lib to the load path unless @ran Merb.logger.info "Expanding RUBY_PATH..." if Merb::Config[:verbose] $LOAD_PATH.unshift Merb.dir_for(:model) $LOAD_PATH.unshift Merb.dir_for(:controller) $LOAD_PATH.unshift Merb.dir_for(:lib) $LOAD_PATH.unshift Merb.dir_for(:helper) end @ran = true nil end # Converts an absolute path to an path relative to Merbs root, if # the path is in the Merb root dir. Otherwise it will return the # absolute path. # # ==== Returns # String:: Relative path or absolute # # :api: private def self.relative_to_merb_path(path) absolute_path = File.expand_path(path) merb_root = File.expand_path(Merb.root) if absolute_path.slice(0, merb_root.length) == merb_root '.' + absolute_path.slice(merb_root.length..-1) else absolute_path end end end class Merb::BootLoader::MixinSession < Merb::BootLoader # Mixin the session functionality; this is done before BeforeAppLoads # so that SessionContainer and SessionStoreContainer can be subclassed by # plugin session stores for example - these need to be loaded in a # before_app_loads block or a BootLoader that runs after MixinSession. # # Note: access to Merb::Config is needed, so it needs to run after # Merb::BootLoader::Dependencies is done. # # ==== Returns # nil # # :api: plugin def self.run require 'merb-core/dispatch/session' Merb::Controller.send(:include, ::Merb::SessionMixin) Merb::Request.send(:include, ::Merb::SessionMixin::RequestMixin) end end class Merb::BootLoader::BeforeAppLoads < Merb::BootLoader # Call any before_app_loads hooks that were registered via before_app_loads # in any plugins. # # ==== Returns # nil # # :api: plugin def self.run Merb::BootLoader.before_load_callbacks.each { |x| x.call } nil end end # Load all classes inside the load paths. # # This is used in conjunction with Merb::BootLoader::ReloadClasses to track # files that need to be reloaded, and which constants need to be removed in # order to reload a file. # # This also adds the model, controller, and lib directories to the load path, # so they can be required in order to avoid load-order issues. class Merb::BootLoader::LoadClasses < Merb::BootLoader LOADED_CLASSES = {} MTIMES = {} FILES_LOADED = {} class << self # Load all classes from Merb's native load paths. # # If fork-based loading is used, every time classes are loaded this will return in a new spawner process # and boot loading will continue from this point in the boot loading process. # # If fork-based loading is not in use, this only returns once and does not fork a new # process. # # ==== Returns # Returns at least once: # nil # # :api: plugin def run # process name you see in ps output $0 = "merb#{" : " + Merb::Config[:name] if Merb::Config[:name]} : master" # Log the process configuration user defined signal 1 (SIGUSR1) is received. Merb.trap("USR1") do require "yaml" Merb.logger.fatal! "Configuration:\n#{Merb::Config.to_hash.merge(:pid => $$).to_yaml}\n\n" end if Merb::Config[:fork_for_class_load] && !Merb.testing? start_transaction else Merb.trap('INT') do Merb.logger.warn! "Reaping Workers" reap_workers end end # Load application file if it exists - for flat applications load_file Merb.dir_for(:application) if File.file?(Merb.dir_for(:application)) # Load classes and their requirements Merb.load_paths.each do |component, path| next if path.last.blank? || component == :application || component == :router load_classes(path.first / path.last) end Merb::Controller.send :include, Merb::GlobalHelpers nil end # Wait for any children to exit, remove the "main" PID, and # exit. # # ==== Returns # (Does not return.) # # :api: private def exit_gracefully # wait all workers to exit Process.waitall # remove master process pid Merb::Server.remove_pid("main") # terminate, workers remove their own pids # in on exit hook Merb::BootLoader.before_master_shutdown_callbacks.each do |cb| begin cb.call rescue Exception => e Merb.logger.fatal "before_master_shutdown callback crashed: #{e.message}" end end exit end # Set up the BEGIN point for fork-based loading and sets up # any signals in the parent and child. This is done by forking # the app. The child process continues on to run the app. The parent # process waits for the child process to finish and either forks again # # # ==== Returns # Parent Process: # (Does not return.) # Child Process returns at least once: # nil # # :api: private def start_transaction Merb.logger.warn! "Parent pid: #{Process.pid}" reader, writer = nil, nil # Enable REE garbage collection if GC.respond_to?(:copy_on_write_friendly=) GC.copy_on_write_friendly = true end loop do # create two connected endpoints # we use them for master/workers communication reader, @writer = IO.pipe pid = Kernel.fork # pid means we're in the parent; only stay in the loop if that is case break unless pid # writer must be closed so reader can generate EOF condition @writer.close # master process stores pid to merb.main.pid Merb::Server.store_pid("main") if Merb::Config[:daemonize] || Merb::Config[:cluster] if Merb::Config[:console_trap] Merb.trap("INT") {} else # send ABRT to worker on INT Merb.trap("INT") do Merb.logger.warn! "Reaping Workers" begin Process.kill(reap_workers_signal, pid) rescue SystemCallError end exit_gracefully end end Merb.trap("HUP") do Merb.logger.warn! "Doing a fast deploy\n" Process.kill("HUP", pid) end reader_ary = [reader] loop do # wait for worker to exit and capture exit status # # # WNOHANG specifies that wait2 exists without waiting # if no worker processes are ready to be noticed. if exit_status = Process.wait2(pid, Process::WNOHANG) # wait2 returns a 2-tuple of process id and exit # status. # # We do not care about specific pid here. exit_status[1] && exit_status[1].exitstatus == 128 ? break : exit end # wait for data to become available, timeout in 0.5 of a second if select(reader_ary, nil, nil, 0.5) begin # no open writers next if reader.eof? msg = reader.readline reader.close if msg.to_i == 128 Process.waitpid(pid, Process::WNOHANG) break else exit_gracefully end rescue SystemCallError exit_gracefully end end end end reader.close # add traps to the worker if Merb::Config[:console_trap] Merb::Server.add_irb_trap at_exit { reap_workers } else Merb.trap('INT') do Merb::BootLoader.before_worker_shutdown_callbacks.each { |cb| cb.call } end Merb.trap('ABRT') { reap_workers } Merb.trap('HUP') { reap_workers(128, "ABRT") } end end def reap_workers_signal Merb::Config[:reap_workers_quickly] ? "KILL" : "ABRT" end # Reap any workers of the spawner process and # exit with an appropriate status code. # # Note that exiting the spawner process with a status code # of 128 when a master process exists will cause the # spawner process to be recreated, and the app code reloaded. # # ==== Parameters # status:: The status code to exit with. Defaults to 0. # sig:: The signal to send to workers # # ==== Returns # (Does not return.) # # :api: private def reap_workers(status = 0, sig = reap_workers_signal) Merb.logger.info "Executed all before worker shutdown callbacks..." Merb::BootLoader.before_worker_shutdown_callbacks.each do |cb| begin cb.call rescue Exception => e Merb.logger.fatal "before worker shutdown callback crashed: #{e.message}" end end Merb.exiting = true unless status == 128 begin if @writer @writer.puts(status.to_s) @writer.close end rescue SystemCallError end threads = [] ($WORKERS || []).each do |p| threads << Thread.new do begin Process.kill(sig, p) Process.wait2(p) rescue SystemCallError end end end threads.each {|t| t.join } exit(status) end # Loads a file, tracking its modified time and, if necessary, the classes it declared. # # ==== Parameters # file:: The file to load. # # ==== Returns # nil # # :api: private def load_file(file, reload = false) Merb.logger.verbose! "#{reload ? "re" : ""}loading #{file}" # If we're going to be reloading via constant remove, # keep track of what constants were loaded and what files # have been added, so that the constants can be removed # and the files can be removed from $LOADED_FEAUTRES if !Merb::Config[:fork_for_class_load] if FILES_LOADED[file] FILES_LOADED[file].each {|lf| $LOADED_FEATURES.delete(lf)} end klasses = ObjectSpace.classes.dup files_loaded = $LOADED_FEATURES.dup end # If we're in the midst of a reload, remove the file # itself from $LOADED_FEATURES so it will get reloaded if reload $LOADED_FEATURES.delete(file) if reload end # Ignore the file for syntax errors. The next time # the file is changed, it'll be reloaded again begin require file rescue SyntaxError => e Merb.logger.error "Cannot load #{file} because of syntax error: #{e.message}" ensure if Merb::Config[:reload_classes] MTIMES[file] = File.mtime(file) end end # If we're reloading via constant remove, store off the details # after the file has been loaded unless Merb::Config[:fork_for_class_load] LOADED_CLASSES[file] = ObjectSpace.classes - klasses FILES_LOADED[file] = $LOADED_FEATURES - files_loaded end nil end # Load classes from given paths - using path/glob pattern. # # ==== Parameters # *paths:: # Array of paths to load classes from - may contain glob pattern # # ==== Returns # nil # # :api: private def load_classes(*paths) orphaned_classes = [] paths.flatten.each do |path| Dir[path].sort.each do |file| begin load_file file rescue NameError => ne Merb.logger.verbose! "Stashed file with missing requirements for later reloading: #{file}" ne.backtrace.each_with_index { |line, idx| Merb.logger.verbose! "[#{idx}]: #{line}" } orphaned_classes.unshift(file) end end end load_classes_with_requirements(orphaned_classes) end # Reloads the classes in the specified file. If fork-based loading is used, # this causes the current processes to be killed and and all classes to be # reloaded. If class-based loading is not in use, the classes declared in that file # are removed and the file is reloaded. # # ==== Parameters # file:: The file to reload. # # ==== Returns # When fork-based loading is used: # (Does not return.) # When fork-based loading is not in use: # nil # # :api: private def reload(file) if Merb::Config[:fork_for_class_load] reap_workers(128) else remove_classes_in_file(file) { |f| load_file(f, true) } end end # Removes all classes declared in the specified file. Any hashes which use classes as keys # will be protected provided they have been added to Merb.klass_hashes. These hashes have their # keys substituted with placeholders before the file's classes are unloaded. If a block is provided, # it is called before the substituted keys are reconstituted. # # ==== Parameters # file:: The file to remove classes for. # &block:: A block to call with the file that has been removed before klass_hashes are updated # to use the current values of the constants they used as keys. # # ==== Returns # nil # # :api: private def remove_classes_in_file(file, &block) Merb.klass_hashes.each { |x| x.protect_keys! } if klasses = LOADED_CLASSES.delete(file) klasses.each { |klass| remove_constant(klass) unless klass.to_s =~ /Router/ } end yield file if block_given? Merb.klass_hashes.each {|x| x.unprotect_keys!} nil end # Removes the specified class. # # Additionally, removes the specified class from the subclass list of every superclass that # tracks it's subclasses in an array returned by _subclasses_list. Classes that wish to use this # functionality are required to alias the reader for their list of subclasses # to _subclasses_list. Plugins for ORMs and other libraries should keep this in mind. # # ==== Parameters # const:: The class to remove. # # ==== Returns # nil # # :api: private def remove_constant(const) # This is to support superclasses (like AbstractController) that track # their subclasses in a class variable. superklass = const until (superklass = superklass.superclass).nil? if superklass.respond_to?(:_subclasses_list) superklass.send(:_subclasses_list).delete(klass) superklass.send(:_subclasses_list).delete(klass.to_s) end end parts = const.to_s.split("::") base = parts.size == 1 ? Object : Object.full_const_get(parts[0..-2].join("::")) object = parts[-1].to_s begin base.send(:remove_const, object) Merb.logger.debug("Removed constant #{object} from #{base}") rescue NameError Merb.logger.debug("Failed to remove constant #{object} from #{base}") end nil end private # "Better loading" of classes. If a file fails to load due to a NameError # it will be added to the failed_classes and load cycle will be repeated unless # no classes load. # # ==== Parameters # klasses:: Classes to load. # # ==== Returns # nil # # :api: private def load_classes_with_requirements(klasses) klasses.uniq! while klasses.size > 0 # Note size to make sure things are loading size_at_start = klasses.size # List of failed classes failed_classes = [] # Map classes to exceptions error_map = {} klasses.each do |klass| begin load_file klass rescue NameError => ne error_map[klass] = ne failed_classes.push(klass) end end klasses.clear # Keep list of classes unique failed_classes.each { |k| klasses.push(k) unless klasses.include?(k) } # Stop processing if nothing loads or if everything has loaded if klasses.size == size_at_start && klasses.size != 0 # Write all remaining failed classes and their exceptions to the log messages = error_map.only(*failed_classes).map do |klass, e| ["Could not load #{klass}:\n\n#{e.message} - (#{e.class})", "#{(e.backtrace || []).join("\n")}"] end messages.each { |msg, trace| Merb.logger.fatal!("#{msg}\n\n#{trace}") } Merb.fatal! "#{failed_classes.join(", ")} failed to load." end break if(klasses.size == size_at_start || klasses.size == 0) end nil end end end # Loads the router file. This needs to happen after everything else is loaded while merb is starting up to ensure # the router has everything it needs to run. class Merb::BootLoader::Router < Merb::BootLoader class << self # load the router file # # ==== Returns # nil # # :api: plugin def run Merb::BootLoader::LoadClasses.load_file(router_file) if router_file nil end # Tries to find the router file. # # ==== Returns # String:: The path to the router file if it exists, nil otherwise. # # :api: private def router_file @router_file ||= begin if File.file?(router = Merb.dir_for(:router) / Merb.glob_for(:router)) router end end end end end # Precompiles all non-partial templates. class Merb::BootLoader::Templates < Merb::BootLoader class << self # Loads all non-partial templates into the Merb::InlineTemplates module. # # ==== Returns # Array[String]:: The list of template files which were loaded. # # :api: plugin def run template_paths.each do |path| Merb::Template.inline_template(File.open(path)) end end # Finds a list of templates to load. # # ==== Returns # Array[String]:: All found template files whose basename does not begin with "_". # # :api: private def template_paths extension_glob = "{#{Merb::Template.template_extensions.join(',')}}" # This gets all templates set in the controllers template roots # We separate the two maps because most of controllers will have # the same _template_root, so it's silly to be globbing the same # path over and over. controller_view_paths = [] Merb::AbstractController._abstract_subclasses.each do |klass| next if (const = Object.full_const_get(klass))._template_root.blank? controller_view_paths += const._template_roots.map { |pair| pair.first } end template_paths = controller_view_paths.uniq.compact.map { |path| Dir["#{path}/**/*.#{extension_glob}"] } # This gets the templates that might be created outside controllers # template roots. eg app/views/shared/* template_paths << Dir["#{Merb.dir_for(:view)}/**/*.#{extension_glob}"] if Merb.dir_for(:view) # This ignores templates for partials, which need to be compiled at use time to generate # a preamble that assigns local variables template_paths.flatten.compact.uniq.grep(%r{^.*/[^_][^/]*$}) end end end # Register the default MIME types: # # By default, the mime-types include: # :all:: no transform, */* # :yaml:: to_yaml, application/x-yaml or text/yaml # :text:: to_text, text/plain # :html:: to_html, text/html or application/xhtml+xml or application/html # :xml:: to_xml, application/xml or text/xml or application/x-xml # :js:: to_json, text/javascript ot application/javascript or application/x-javascript # :json:: to_json, application/json or text/x-json class Merb::BootLoader::MimeTypes < Merb::BootLoader # Registers the default MIME types. # # ==== Returns # nil # # :api: plugin def self.run Merb.add_mime_type(:all, nil, %w[*/*]) Merb.add_mime_type(:yaml, :to_yaml, %w[application/x-yaml text/yaml], :charset => "utf-8") Merb.add_mime_type(:text, :to_text, %w[text/plain], :charset => "utf-8") Merb.add_mime_type(:html, :to_html, %w[text/html application/xhtml+xml application/html], :charset => "utf-8") Merb.add_mime_type(:xml, :to_xml, %w[application/xml text/xml application/x-xml], {:charset => "utf-8"}, 0.9998) Merb.add_mime_type(:js, :to_json, %w[text/javascript application/javascript application/x-javascript], :charset => "utf-8") Merb.add_mime_type(:json, :to_json, %w[application/json text/x-json], :charset => "utf-8") nil end end # Set up cookies support in Merb::Controller and Merb::Request class Merb::BootLoader::Cookies < Merb::BootLoader # Set up cookies support in Merb::Controller and Merb::Request # # ==== Returns # nil # # :api: plugin def self.run require 'merb-core/dispatch/cookies' Merb::Controller.send(:include, Merb::CookiesMixin) Merb::Request.send(:include, Merb::CookiesMixin::RequestMixin) nil end end class Merb::BootLoader::SetupSession < Merb::BootLoader # Enable the configured session container(s); any class that inherits from # SessionContainer will be considered by its session_store_type attribute. # # ==== Returns # nil # # :api: plugin def self.run # Require all standard session containers. Dir[Merb.framework_root / "merb-core" / "dispatch" / "session" / "*.rb"].each do |file| base_name = File.basename(file, ".rb") require file unless base_name == "container" || base_name == "store_container" end # Set some defaults. Merb::Config[:session_id_key] ||= "_session_id" # List of all session_stores from :session_stores and :session_store config options. config_stores = Merb::Config.session_stores # Register all configured session stores - any loaded session container class # (subclassed from Merb::SessionContainer) will be available for registration. Merb::SessionContainer.subclasses.each do |class_name| if(store = Object.full_const_get(class_name)) && config_stores.include?(store.session_store_type) Merb::Request.register_session_type(store.session_store_type, class_name) end end # Mixin the Merb::Session module to add app-level functionality to sessions overrides = (Merb::Session.instance_methods & Merb::SessionContainer.instance_methods) overrides.each do |m| Merb.logger.warn!("Warning: Merb::Session##{m} overrides existing " \ "Merb::SessionContainer##{m}") end Merb::SessionContainer.send(:include, Merb::Session) nil end end # In case someone's running a sparse app, the default exceptions require the # Exceptions class. This must run prior to the AfterAppLoads BootLoader # So that plugins may have ensured access in the after_app_loads block class Merb::BootLoader::SetupStubClasses < Merb::BootLoader # Declares empty Application and Exception controllers. # # ==== Returns # nil # # :api: plugin def self.run unless defined?(Exceptions) Object.class_eval <<-RUBY class Application < Merb::Controller abstract! end class Exceptions < Merb::Controller end RUBY end nil end end class Merb::BootLoader::AfterAppLoads < Merb::BootLoader # Call any after_app_loads hooks that were registered via after_app_loads in # init.rb. # # ==== Returns # nil # # :api: plugin def self.run Merb::BootLoader.after_load_callbacks.each {|x| x.call } nil end end class Merb::BootLoader::ChooseAdapter < Merb::BootLoader # Choose the Rack adapter/server to use and set Merb.adapter. # # ==== Returns # nil # # :api: plugin def self.run # Check if we running in IRB if so run IRB adapter Merb::Config[:adapter] = 'irb' if Merb.running_irb? Merb.adapter = Merb::Rack::Adapter.get(Merb::Config[:adapter]) end end class Merb::BootLoader::RackUpApplication < Merb::BootLoader # Setup the Merb Rack App or read a rackup file located at # Merb::Config[:rackup] with the same syntax as the # rackup tool that comes with rack. Automatically evals the file in # the context of a Rack::Builder.new { } block. Allows for mounting # additional apps or middleware. # # ==== Returns # nil # # :api: plugin def self.run require 'rack' if File.exists?(Merb.dir_for(:config) / "rack.rb") Merb::Config[:rackup] ||= Merb.dir_for(:config) / "rack.rb" end if Merb::Config[:rackup] rackup_code = File.read(Merb::Config[:rackup]) Merb::Config[:app] = eval("::Rack::Builder.new {( #{rackup_code}\n )}.to_app", TOPLEVEL_BINDING, Merb::Config[:rackup]) else Merb::Config[:app] = ::Rack::Builder.new { use Merb::Rack::Head # handle head requests use Merb::Rack::ContentLength # report content length if prefix = ::Merb::Config[:path_prefix] use Merb::Rack::PathPrefix, prefix end use Merb::Rack::Static, Merb.dir_for(:public) run Merb::Rack::Application.new }.to_app end nil end end class Merb::BootLoader::BackgroundServices < Merb::BootLoader # Start background services, such as the run_later worker thread. # # ==== Returns # nil # # :api: plugin def self.run Merb::Worker.start unless Merb.testing? || Merb::Worker.started? nil end end class Merb::BootLoader::ReloadClasses < Merb::BootLoader class TimedExecutor # Executes the associated block every @seconds@ seconds in a separate thread. # # ==== Parameters # seconds:: Number of seconds to sleep in between runs of &block. # &block:: The block to execute periodically. # # ==== Returns # Thread:: The thread executing the block periodically. # # :api: private def self.every(seconds, &block) Thread.new do loop do sleep( seconds ) yield end Thread.exit end end end # Set up the class reloader if class reloading is enabled. This checks periodically # for modifications to files loaded by the LoadClasses BootLoader and reloads them # when they are modified. # # ==== Returns # nil # # :api: plugin def self.run return unless Merb::Config[:reload_classes] TimedExecutor.every(Merb::Config[:reload_time] || 0.5) do GC.start reload! end nil end # Reloads all the files on the Merb application path # # ==== Returns # nil # # :api: private def self.reload! reload(build_paths) end # Reloads all files which have been modified since they were last loaded. # # ==== Returns # nil # # :api: private def self.reload(paths = []) paths.each do |file| next if LoadClasses::MTIMES[file] && LoadClasses::MTIMES[file] == File.mtime(file) LoadClasses.reload(file) end nil end # Returns a list of the paths on the merb application stack # # ==== Returns # nil # # :api: private def self.build_paths paths = [] Merb.load_paths.each do |path_name, file_info| path, glob = file_info next unless glob paths << Dir[path / glob] end if Merb.dir_for(:application) && File.file?(Merb.dir_for(:application)) paths << Merb.dir_for(:application) end paths.flatten! return paths end end ruby-merb-core_1.1.3.orig/lib/merb-core/config.rb000066400000000000000000000400371175250300200216010ustar00rootroot00000000000000require "optparse" module Merb class Config class << self # Returns the hash of default config values for Merb. # # ==== Returns # Hash:: The defaults for the config. # # :api: private def defaults @defaults ||= { :host => "0.0.0.0", :port => "4000", :adapter => "runner", :reload_classes => true, :fork_for_class_load => Merb.forking_environment?, :environment => "development", :merb_root => Dir.pwd, :use_mutex => true, :log_delimiter => " ~ ", :log_auto_flush => false, :log_level => :info, :log_stream => STDOUT, :disabled_components => Merb.on_windows? ? [:signals] : [], :deferred_actions => [], :verbose => false, :name => "merb", :kernel_dependencies => true, :gemfile => nil, :gemenv => nil } end # Yields the configuration. # # ==== Block parameters # c:: The configuration parameters. # # ==== Examples # Merb::Config.use do |config| # config[:exception_details] = false # config[:log_stream] = STDOUT # end # # ==== Returns # nil # # :api: public def use @configuration ||= {} yield @configuration nil end # Detects whether the provided key is in the config. # # ==== Parameters # key:: The key to check. # # ==== Returns # Boolean:: True if the key exists in the config. # # :api: public def key?(key) @configuration.key?(key) end # Retrieve the value of a config entry. # # ==== Parameters # key:: The key to retrieve the parameter for. # # ==== Returns # Object:: The value of the configuration parameter. # # :api: public def [](key) (@configuration ||= setup)[key] end # Set the value of a config entry. # # ==== Parameters # key:: The key to set the parameter for. # val:: The value of the parameter. # # :api: public def []=(key, val) (@configuration ||= setup)[key] = val end # Remove the value of a config entry. # # ==== Parameters # key:: The key of the parameter to delete. # # ==== Returns # Object:: The value of the removed entry. # # :api: public def delete(key) @configuration.delete(key) end # Retrieve the value of a config entry, returning the provided default if the key is not present # # ==== Parameters # key:: The key to retrieve the parameter for. # default:: # The default value to return if the parameter is not set. # # ==== Returns # Object:: The value of the configuration parameter or the default. # # :api: public def fetch(key, default) @configuration.fetch(key, default) end # Returns the configuration as a hash. # # ==== Returns # Hash:: The config as a hash. # # :api: public def to_hash @configuration end # Returns the config as YAML. # # ==== Returns # String:: The config as YAML. # # :api: public def to_yaml require "yaml" @configuration.to_yaml end # Sets up the configuration by storing the given settings. # # ==== Parameters # settings:: # Configuration settings to use. These are merged with the defaults. # # ==== Returns # The configuration as a hash. # # :api: private def setup(settings = {}) # Merge new settings with any existing configuration settings settings = @configuration.merge(settings) unless @configuration.nil? # Merge new settings with default settings config = defaults.merge(settings) unless config[:reload_classes] config[:fork_for_class_load] = false end dev_mode = config[:environment] == "development" unless config.key?(:reap_workers_quickly) config[:reap_workers_quickly] = dev_mode & !config[:cluster] end unless config.key?(:bind_fail_fatal) config[:bind_fail_fatal] = dev_mode end # Set mutex to dispatcher ::Merb::Dispatcher.use_mutex = config[:use_mutex] @configuration = config end # Parses the command line arguments and stores them in the config. # # ==== Parameters # argv:: The command line arguments. Defaults to +ARGV+. # # ==== Returns # The configuration as a hash. # # :api: private def parse_args(argv = ARGV) @configuration ||= {} # Our primary configuration hash for the length of this method options = {} # Environment variables always win options[:environment] = ENV["MERB_ENV"] if ENV["MERB_ENV"] # Build a parser for the command line arguments opts = OptionParser.new do |opts| opts.version = Merb::VERSION opts.banner = "Usage: merb [uGdcIpPhmailLerkKX] [argument]" opts.define_head "Merb. Pocket rocket web framework" opts.separator '*' * 80 opts.separator "If no flags are given, Merb starts in the " \ "foreground on port 4000." opts.separator '*' * 80 opts.on("-u", "--user USER", "This flag is for having merb run " \ "as a user other than the one currently logged in. Note: " \ "if you set this you must also provide a --group option " \ "for it to take effect.") do |user| options[:user] = user end opts.on("-G", "--group GROUP", "This flag is for having merb run " \ "as a group other than the one currently logged in. Note: " \ "if you set this you must also provide a --user option " \ "for it to take effect.") do |group| options[:group] = group end opts.on("-d", "--daemonize", "This will run a single merb in the " \ "background.") do |daemon| options[:daemonize] = true end opts.on("-N", "--no-daemonize", "This will allow you to run a " \ "cluster in console mode") do |no_daemon| options[:daemonize] = false end opts.on("-c", "--cluster-nodes NUM_MERBS", Integer, "Number of merb daemons to run.") do |nodes| options[:daemonize] = true unless options.key?(:daemonize) options[:cluster] = nodes end opts.on("-I", "--init-file FILE", "File to use for initialization " \ "on load, defaults to config/init.rb") do |init_file| options[:init_file] = init_file end opts.on("-p", "--port PORTNUM", Integer, "Port to run merb on, " \ "defaults to 4000.") do |port| options[:port] = port end opts.on("-o", "--socket-file FILE", "Socket file to run merb on, " \ "defaults to [Merb.root]/log/merb.sock. This is for " \ "web servers, like thin, that use sockets." \ "Specify this *only* if you *must*.") do |port| options[:socket_file] = port end opts.on("-s", "--socket SOCKNUM", Integer, "Socket number to run " \ "merb on, defaults to 0.") do |port| options[:socket] = port end opts.on("-n", "--name NAME", String, "Set the name of the application. "\ "This is used in the process title and log file names.") do |name| options[:name] = name end opts.on("-P", "--pid PIDFILE", "PID file, defaults to " \ "[Merb.root]/log/merb.main.pid for the master process and" \ "[Merb.root]/log/merb.[port number].pid for worker " \ "processes. For clusters, use %s to specify where " \ "in the file merb should place the port number. For " \ "instance: -P myapp.%s.pid") do |pid_file| options[:pid_file] = pid_file end opts.on("-h", "--host HOSTNAME", "Host to bind to " \ "(default is 0.0.0.0).") do |host| options[:host] = host end opts.on("-m", "--merb-root /path/to/approot", "The path to the " \ "Merb.root for the app you want to run " \ "(default is current working directory).") do |root| options[:merb_root] = File.expand_path(root) end adapters = [:mongrel, :emongrel, :thin, :ebb, :fastcgi, :webrick] opts.on("-a", "--adapter ADAPTER", "The rack adapter to use to run merb (default is thin)" \ "[#{adapters.join(', ')}]") do |adapter| options[:adapter] ||= adapter end opts.on("-R", "--rackup FILE", "Load an alternate Rack config " \ "file (default is config/rack.rb)") do |rackup| options[:rackup] = rackup end opts.on("-i", "--irb-console", "This flag will start merb in " \ "irb console mode. All your models and other classes will " \ "be available for you in an irb session.") do |console| options[:adapter] = 'irb' end opts.on("-S", "--sandbox", "This flag will enable a sandboxed irb " \ "console. If your ORM supports transactions, all edits will " \ "be rolled back on exit.") do |sandbox| options[:sandbox] = true end opts.on("-l", "--log-level LEVEL", "Log levels can be set to any of " \ "these options: debug < info < warn < error < " \ "fatal (default is info)") do |log_level| options[:log_level] = log_level.to_sym options[:force_logging] = true end opts.on("-L", "--log LOGFILE", "A string representing the logfile to " \ "use. Defaults to [Merb.root]/log/merb.[main].log for the " \ "master process and [Merb.root]/log/merb[port number].log" \ "for worker processes") do |log_file| options[:log_file] = log_file options[:force_logging] = true end opts.on("-e", "--environment STRING", "Environment to run Merb " \ "under [development, production, testing] " \ "(default is development)") do |env| options[:environment] = env end opts.on("-r", "--script-runner ['RUBY CODE'| FULL_SCRIPT_PATH]", "Command-line option to run scripts and/or code in the " \ "merb app.") do |code_or_file| options[:runner_code] = code_or_file options[:adapter] = 'runner' end opts.on("-K", "--graceful PORT or all", "Gracefully kill one " \ "merb proceses by port number. Use merb -K all to " \ "gracefully kill all merbs.") do |ports| options[:action] = :kill ports = "main" if ports == "all" options[:port] = ports end opts.on("-k", "--kill PORT", "Force kill one merb worker " \ "by port number. This will cause the worker to" \ "be respawned.") do |port| options[:action] = :kill_9 port = "main" if port == "all" options[:port] = port end opts.on("--fast-deploy", "Reload the code, but not your" \ "init.rb or gems") do options[:action] = :fast_deploy end # @todo Do we really need this flag? It seems unlikely to want to # change the mutex from the command-line. opts.on("-X", "--mutex on/off", "This flag is for turning the " \ "mutex lock on and off.") do |mutex| if mutex == "off" options[:use_mutex] = false else options[:use_mutex] = true end end opts.on("-D", "--debugger", "Run merb using rDebug.") do begin require "ruby-debug" Debugger.start # Load up any .rdebugrc files we find [".", ENV["HOME"], ENV["HOMEPATH"]].each do |script_dir| script_file = "#{script_dir}/.rdebugrc" Debugger.run_script script_file, StringIO.new if File.exists?(script_file) end if Debugger.respond_to?(:settings) Debugger.settings[:autoeval] = true end puts "Debugger enabled" rescue LoadError puts "You need to install ruby-debug to run the server in " \ "debugging mode. With gems, use `gem install ruby-debug'" exit end end opts.on("-V", "--verbose", "Print extra information") do options[:verbose] = true end opts.on("-C", "--console-trap", "Enter an irb console on ^C") do options[:console_trap] = true end opts.on("-?", "-H", "--help", "Show this help message") do puts opts exit end end # Parse what we have on the command line begin opts.parse!(argv) rescue OptionParser::InvalidOption => e Merb.fatal! e.message, e end Merb::Config.setup(options) end # :api: private attr_accessor :configuration # Set configuration parameters from a code block, where each method # evaluates to a config parameter. # # ==== Parameters # &block:: Configuration parameter block. # # ==== Examples # # Set environment and log level. # Merb::Config.configure do # environment "development" # log_level "debug" # log_file Merb.root / "log" / "special.log" # end # # ==== Returns # nil # # :api: public def configure(&block) ConfigBlock.new(self, &block) if block_given? nil end # Allows retrieval of single key config values via Merb.config. # Allows single key assignment via Merb.config. = ... # # ==== Parameters # method<~to_s>:: Method name as hash key value. # *args:: Value to set the configuration parameter to. # # ==== Returns # The value of the entry fetched or assigned to. # # :api: public def method_missing(method, *args) if method.to_s[-1,1] == '=' @configuration[method.to_s.tr('=','').to_sym] = *args else @configuration[method] end end end # class << self class ConfigBlock # Evaluates the provided block, where any call to a method causes # #[]= to be called on klass with the method name as the key and the arguments # as the value. # # ==== Parameters # klass:: The object on which to assign values. # &block:: The block which specifies the config values to set. # # ==== Returns # nil # # :api: private def initialize(klass, &block) @klass = klass instance_eval(&block) end # Assign args as the value of the entry keyed by method. # # :api: private def method_missing(method, *args) @klass[method] = *args end end # class Configurator end # Config end # Merb ruby-merb-core_1.1.3.orig/lib/merb-core/constants.rb000066400000000000000000000115251175250300200223500ustar00rootroot00000000000000# Most of this list is simply constants frozen for efficiency # and lowered memory consumption. Every time Ruby VM comes # across a string or a number or a regexp literal, # new object is created. # # This means if you refer to the same string 6 times per request # and your application takes 100 requests per second, there are # 600 objects for weak MRI garbage collector to work on. # # GC cycles take up to 80% (!) time of request processing in # some cases. Eventually Rubinius and maybe MRI 2.0 gonna # improve this situation but at the moment, all commonly used # strings, regexp and numbers used as constants so no extra # objects created and VM just operates pointers. module Merb module Const DEFAULT_SEND_FILE_OPTIONS = { :type => 'application/octet-stream'.freeze, :disposition => 'attachment'.freeze }.freeze RACK_INPUT = 'rack.input'.freeze SET_COOKIE = " %s=%s; path=/; expires=%s".freeze COOKIE_EXPIRATION_FORMAT = "%a, %d-%b-%Y %H:%M:%S GMT".freeze COOKIE_SPLIT = /[;,] */n.freeze COOKIE_REGEXP = /\s*(.+)=(.*)\s*/.freeze COOKIE_EXPIRED_TIME = Time.at(0).freeze ACCEPT_SPLIT = /,/.freeze SLASH_SPLIT = %r{/}.freeze MEDIA_RANGE = /\s*([^;\s]*)\s*(;\s*q=\s*(.*))?/.freeze HOUR = 60 * 60 DAY = HOUR * 24 WEEK = DAY * 7 MULTIPART_REGEXP = /\Amultipart\/form-data.*boundary=\"?([^\";,]+)/n.freeze HTTP_COOKIE = 'HTTP_COOKIE'.freeze QUERY_STRING = 'QUERY_STRING'.freeze JSON_MIME_TYPE_REGEXP = %r{^application/json|^text/x-json}.freeze XML_MIME_TYPE_REGEXP = %r{^application/xml|^text/xml}.freeze FORM_URL_ENCODED_REGEXP = %r{^application/x-www-form-urlencoded}.freeze LOCAL_IP_REGEXP = /^unknown$|^(127|10|172\.16|192\.168)\.|^(172\.(1[6-9]|2[0-9]|3[0-1]))\.|^(169\.254)\./i.freeze XML_HTTP_REQUEST_REGEXP = /XMLHttpRequest/i.freeze UPCASE_CONTENT_TYPE = 'CONTENT_TYPE'.freeze CONTENT_TYPE = "Content-Type".freeze DATE = 'Date'.freeze UPCASE_HTTPS = 'HTTPS'.freeze HTTPS = 'https'.freeze HTTP = 'http'.freeze ETAG = 'ETag'.freeze LAST_MODIFIED = "Last-Modified".freeze GET = "GET".freeze POST = "POST".freeze HEAD = "HEAD".freeze CONTENT_LENGTH = "CONTENT_LENGTH".freeze HTTP_CLIENT_IP = "HTTP_CLIENT_IP".freeze HTTP_X_REQUESTED_WITH = "HTTP_X_REQUESTED_WITH".freeze HTTP_X_FORWARDED_FOR = "HTTP_X_FORWARDED_FOR".freeze HTTP_X_FORWARDED_PROTO = "HTTP_X_FORWARDED_PROTO".freeze HTTP_X_FORWARDED_HOST = "HTTP_X_FORWARDED_HOST".freeze HTTP_IF_MODIFIED_SINCE = "HTTP_IF_MODIFIED_SINCE".freeze HTTP_IF_NONE_MATCH = "HTTP_IF_NONE_MATCH".freeze HTTP_CONTENT_TYPE = "HTTP_CONTENT_TYPE".freeze HTTP_CONTENT_LENGTH = "HTTP_CONTENT_LENGTH".freeze HTTP_REFERER = "HTTP_REFERER".freeze HTTP_USER_AGENT = "HTTP_USER_AGENT".freeze HTTP_HOST = "HTTP_HOST".freeze HTTP_CONNECTION = "HTTP_CONNECTION".freeze HTTP_KEEP_ALIVE = "HTTP_KEEP_ALIVE".freeze HTTP_ACCEPT = "HTTP_ACCEPT".freeze HTTP_ACCEPT_ENCODING = "HTTP_ACCEPT_ENCODING".freeze HTTP_ACCEPT_LANGUAGE = "HTTP_ACCEPT_LANGUAGE".freeze HTTP_ACCEPT_CHARSET = "HTTP_ACCEPT_CHARSET".freeze HTTP_CACHE_CONTROL = "HTTP_CACHE_CONTROL".freeze UPLOAD_ID = "upload_id".freeze PATH_INFO = "PATH_INFO".freeze HTTP_VERSION = "HTTP_VERSION".freeze GATEWAY_INTERFACE = "GATEWAY_INTERFACE".freeze SCRIPT_NAME = "SCRIPT_NAME".freeze SERVER_NAME = "SERVER_NAME".freeze SERVER_SOFTWARE = "SERVER_SOFTWARE".freeze SERVER_PROTOCOL = "SERVER_PROTOCOL".freeze SERVER_PORT = "SERVER_PORT".freeze REQUEST_URI = "REQUEST_URI".freeze REQUEST_PATH = "REQUEST_PATH".freeze REQUEST_METHOD = "REQUEST_METHOD".freeze REMOTE_ADDR = "REMOTE_ADDR".freeze BREAK_TAG = "
".freeze EMPTY_STRING = "".freeze NEWLINE = "\n".freeze SLASH = "/".freeze DOT = ".".freeze QUESTION_MARK = "?".freeze DOUBLE_NEWLINE = "\n\n".freeze LOCATION = "Location".freeze TEXT_SLASH_HTML = "text/html".freeze WIN_PLATFORM_REGEXP = /(:?mswin|mingw)/.freeze JAVA_PLATFORM_REGEXP = /java/.freeze end end ruby-merb-core_1.1.3.orig/lib/merb-core/controller/000077500000000000000000000000001175250300200221665ustar00rootroot00000000000000ruby-merb-core_1.1.3.orig/lib/merb-core/controller/abstract_controller.rb000066400000000000000000000605671175250300200265770ustar00rootroot00000000000000# ==== Why do we use Underscores? # In Merb, views are actually methods on controllers. This provides # not-insignificant speed benefits, as well as preventing us from # needing to copy over instance variables, which we think is proof # that everything belongs in one class to begin with. # # Unfortunately, this means that view helpers need to be included # into the Controller class. To avoid causing confusion # when your helpers potentially conflict with our instance methods, # we use an _ to disambiguate. As long as you don't begin your helper # methods with _, you only need to worry about conflicts with Merb # methods that are part of the public API. # # # # ==== Filters # #before is a class method that allows you to specify before filters in # your controllers. Filters can either be a symbol or string that # corresponds to a method name to call, or a proc object. if it is a method # name that method will be called and if it is a proc it will be called # with an argument of self where self is the current controller object. # When you use a proc as a filter it needs to take one parameter. # # #after is identical, but the filters are run after the action is invoked. # # ===== Examples # before :some_filter # before :authenticate, :exclude => [:login, :signup] # before :has_role, :with => ["Admin"], :exclude => [:index, :show] # before Proc.new { some_method }, :only => :foo # before :authorize, :unless => :logged_in? # # You can use either :only => :actionname or # :exclude => [:this, :that] but not both at once. # :only will only run before the listed actions and # :exclude will run for every action that is not listed. # # Merb's before filter chain is very flexible. To halt the filter chain you # use throw :halt. If throw is called with only one # argument of :halt the return value of the method # filters_halted will be what is rendered to the view. You can # override filters_halted in your own controllers to control what # it outputs. But the throw construct is much more powerful than # just that. # # throw :halt can also take a second argument. Here is what that # second argument can be and the behavior each type can have: # # * +String+: # when the second argument is a string then that string will be what # is rendered to the browser. Since merb's #render method returns # a string you can render a template or just use a plain string: # # throw :halt, "You don't have permissions to do that!" # throw :halt, render(:action => :access_denied) # # * +Symbol+: # If the second arg is a symbol, then the method named after that # symbol will be called # # throw :halt, :must_click_disclaimer # # * +Proc+: # If the second arg is a Proc, it will be called and its return # value will be what is rendered to the browser: # # throw :halt, proc { access_denied } # throw :halt, proc { Tidy.new(c.index) } # # ===== Filter Options (.before, .after, .add_filter, .if, .unless) # :only:: # A list of actions that this filter should apply to # # :exclude:: # Only apply the filter if the method named after the symbol or calling the proc evaluates to true # # :unless:: # Only apply the filter if the method named after the symbol or calling the proc evaluates to false # # :with:: # Arguments to be passed to the filter. Since we are talking method/proc calls, # filter method or Proc should to have the same arity # as number of elements in Array you pass to this option. # # ===== Types (shortcuts for use in this file) # Filter:: # # ==== params[:action] and params[:controller] deprecated # params[:action] and params[:controller] have been deprecated as of # the 0.9.0 release. They are no longer set during dispatch, and # have been replaced by action_name and controller_name respectively. module Merb module InlineTemplates; end class AbstractController include Merb::RenderMixin include Merb::InlineTemplates class_inheritable_accessor :_layout, :_template_root, :template_roots class_inheritable_accessor :_before_filters, :_after_filters class_inheritable_accessor :_before_dispatch_callbacks, :_after_dispatch_callbacks cattr_accessor :_abstract_subclasses # :api: plugin attr_accessor :body, :action_name, :_benchmarks # :api: private attr_accessor :_thrown_content # Stub so content-type support in RenderMixin doesn't throw errors # :api: private attr_accessor :content_type FILTER_OPTIONS = [:only, :exclude, :if, :unless, :with] self._before_filters, self._after_filters = [], [] self._before_dispatch_callbacks, self._after_dispatch_callbacks = [], [] #--- # We're using abstract_subclasses so that Merb::Controller can have its # own subclasses. We're using a Set so we don't have to worry about # uniqueness. self._abstract_subclasses = Set.new # ==== Returns # String:: The controller name in path form, e.g. "admin/items". # :api: public def self.controller_name() @controller_name ||= self.name.to_const_path end # ==== Returns # String:: The controller name in path form, e.g. "admin/items". # # :api: public def controller_name() self.class.controller_name end # This is called after the controller is instantiated to figure out where to # look for templates under the _template_root. Override this to define a new # structure for your app. # # ==== Parameters # context<~to_s>:: The controller context (the action or template name). # type<~to_s>:: The content type. Could be nil. # controller<~to_s>:: # The name of the controller. Defaults to being called with the controller_name. Set t # # # ==== Returns # String:: # Indicating where to look for the template for the current controller, # context, and content-type. # # ==== Notes # The type is irrelevant for controller-types that don't support # content-type negotiation, so we default to not include it in the # superclass. # # ==== Examples # def _template_location # "#{params[:controller]}.#{params[:action]}.#{content_type}" # end # # This would look for templates at controller.action.mime.type instead # of controller/action.mime.type # # :api: public # @overridable def _template_location(context, type, controller) controller ? "#{controller}/#{context}" : context end # The location to look for a template - override this method for particular behaviour. # # ==== Parameters # template:: The absolute path to a template - without template extension. # type<~to_s>:: # The mime-type of the template that will be rendered. Defaults to being called with nil. # # :api: public # @overridable def _absolute_template_location(template, type) template end # Resets the template roots to the template root passed in. # # ==== Parameters # root<~to_s>:: # The new path to set the template root to. # # :api: public def self._template_root=(root) @_template_root = root _reset_template_roots end # Reset the template root based on the @_template_root ivar. # # :api: private def self._reset_template_roots self.template_roots = [[self._template_root, :_template_location]] end # ==== Returns # roots:: # Template roots as pairs of template root path and template location # method. # # :api: plugin def self._template_roots self.template_roots || _reset_template_roots end # ==== Parameters # roots:: # Template roots as pairs of template root path and template location # method. # # :api: plugin def self._template_roots=(roots) self.template_roots = roots end # Returns the list of classes that have specifically subclassed AbstractController. # Does not include all decendents. # # ==== Returns # Set:: The subclasses. # # :api: private def self.subclasses_list() _abstract_subclasses end # ==== Parameters # klass:: # The controller that is being inherited from Merb::AbstractController # # :api: private def self.inherited(klass) _abstract_subclasses << klass.to_s helper_module_name = klass.to_s =~ /^(#|Merb::)/ ? "#{klass}Helper" : "Merb::#{klass}Helper" # support for unnamed module like "#::TestController" helper_module_name.gsub!(/(::)|[:#<>]/, "\\1") Object.make_module helper_module_name klass.class_eval <<-HERE include Object.full_const_get("#{helper_module_name}") rescue nil HERE super end # This will initialize the controller, it is designed to be overridden in subclasses (like MerbController) # ==== Parameters # *args:: The args are ignored in this class, but we need this so that subclassed initializes can have parameters # # :api: private def initialize(*args) @_benchmarks = {} @_caught_content = {} end # This will dispatch the request, calling internal before/after dispatch callbacks. # If the return value of _call_filters is not :filter_chain_completed the action is not called, and the return from the filters is used instead. # # ==== Parameters # action<~to_s>:: # The action to dispatch to. This will be #send'ed in _call_action. # Defaults to :to_s. # # ==== Returns # <~to_s>:: # Returns the string that was returned from the action. # # ==== Raises # ArgumentError:: Invalid result caught from before filters. # # :api: plugin def _dispatch(action) self.action_name = action self._before_dispatch_callbacks.each { |cb| cb.call(self) } caught = catch(:halt) do start = Time.now result = _call_filters(_before_filters) @_benchmarks[:before_filters_time] = Time.now - start if _before_filters @body = _call_action(action_name) if result == :filter_chain_completed result end @body = case caught when :filter_chain_completed then @body when String then caught # return *something* if you throw halt with nothing when nil then "

Filter Chain Halted!

" when Symbol then __send__(caught) when Proc then self.instance_eval(&caught) else raise ArgumentError, "Threw :halt, #{caught}. Expected String, nil, Symbol, Proc." end start = Time.now _call_filters(_after_filters) @_benchmarks[:after_filters_time] = Time.now - start if _after_filters self._after_dispatch_callbacks.each { |cb| cb.call(self) } @body end # This method exists to provide an overridable hook for ActionArgs. It uses #send to call the action method. # # ==== Parameters # action<~to_s>:: the action method to dispatch to # # :api: plugin # @overridable def _call_action(action) send(action) end # Calls a filter chain. # # ==== Parameters # filter_set:: # A set of filters in the form [[:filter, rule], [:filter, rule]] # # ==== Returns # Symbol:: :filter_chain_completed. # # ==== Notes # Filter rules can be Symbols, Strings, or Procs. # # Symbols or Strings:: # Call the method represented by the +Symbol+ or +String+. # Procs:: # Execute the +Proc+, in the context of the controller (self will be the # controller) # # :api: private def _call_filters(filter_set) (filter_set || []).each do |filter, rule| if _call_filter_for_action?(rule, action_name) && _filter_condition_met?(rule) case filter when Symbol, String if rule.key?(:with) args = rule[:with] send(filter, *args) else send(filter) end when Proc then self.instance_eval(&filter) end end end return :filter_chain_completed end # Determine whether the filter should be called for the current action using :only and :exclude. # # ==== Parameters # rule:: Rules for the filter (see below). # action_name<~to_s>:: The name of the action to be called. # # ==== Options (rule) # :only:: # Optional list of actions to fire. If given, action_name must be a part of # it for this function to return true. # :exclude:: # Optional list of actions not to fire. If given, action_name must not be a # part of it for this function to return true. # # ==== Returns # Boolean:: True if the action should be called. # # :api: private def _call_filter_for_action?(rule, action_name) # Both: # * no :only or the current action is in the :only list # * no :exclude or the current action is not in the :exclude list (!rule.key?(:only) || rule[:only].include?(action_name)) && (!rule.key?(:exclude) || !rule[:exclude].include?(action_name)) end # Determines whether the filter should be run based on the conditions passed (:if and :unless) # # ==== Parameters # rule:: Rules for the filter (see below). # # ==== Options (rule) # :if:: Optional conditions that must be met for the filter to fire. # :unless:: # Optional conditions that must not be met for the filter to fire. # # ==== Returns # Boolean:: True if the conditions are met. # # :api: private def _filter_condition_met?(rule) # Both: # * no :if or the if condition evaluates to true # * no :unless or the unless condition evaluates to false (!rule.key?(:if) || _evaluate_condition(rule[:if])) && (!rule.key?(:unless) || ! _evaluate_condition(rule[:unless])) end # Evaluates a filter condition (:if or :unless) # # ==== Parameters # condition:: The condition to evaluate. # # ==== Raises # ArgumentError:: condition not a Symbol or Proc. # # ==== Returns # Boolean:: True if the condition is met. # # ==== Alternatives # If condition is a symbol, it will be send'ed. If it is a Proc it will be # called directly with self as an argument. # # :api: private def _evaluate_condition(condition) case condition when Symbol then self.send(condition) when Proc then self.instance_eval(&condition) else raise ArgumentError, 'Filter condtions need to be either a Symbol or a Proc' end end # Adds a filter to the after filter chain # ==== Parameters # filter:: The filter to add. Defaults to nil. # opts:: # Filter options (see class documentation under Filter Options). # &block:: A block to use as a filter if filter is nil. # # ==== Notes # If the filter already exists, its options will be replaced with opts.; # # :api: public def self.after(filter = nil, opts = {}, &block) add_filter(self._after_filters, filter || block, opts) end # Adds a filter to the before filter chain. # # ==== Parameters # filter:: The filter to add. Defaults to nil. # opts:: # Filter options (see class documentation under Filter Options). # &block:: A block to use as a filter if filter is nil. # # ==== Notes # If the filter already exists, its options will be replaced with opts. # # :api: public def self.before(filter = nil, opts = {}, &block) add_filter(self._before_filters, filter || block, opts) end # Removes a filter from the after filter chain. This removes the # filter from the filter chain for the whole controller and does not # take any options. # # ==== Parameters # filter:: A filter name to skip. # # :api: public def self.skip_after(filter) skip_filter(self._after_filters, filter) end # Removes a filter from the before filter chain. This removes the # filter from the filter chain for the whole controller and does not # take any options. # # ==== Parameters # filter:: A filter name to skip. # # :api: public def self.skip_before(filter) skip_filter(self._before_filters , filter) end # There are three possible ways to use this method. First, if you have a named route, # you can specify the route as the first parameter as a symbol and any paramters in a # hash. Second, you can generate the default route by just passing the params hash, # just passing the params hash. Finally, you can use the anonymous parameters. This # allows you to specify the parameters to a named route in the order they appear in the # router. # # ==== Parameters(Named Route) # name:: # The name of the route. # args:: # Parameters for the route generation. # # ==== Parameters(Default Route) # args:: # Parameters for the route generation. This route will use the default route. # # ==== Parameters(Anonymous Parameters) # name:: # The name of the route. # args:: # An array of anonymous parameters to generate the route # with. These parameters are assigned to the route parameters # in the order that they are passed. # # ==== Returns # String:: The generated URL. # # ==== Examples # Named Route # # Merb::Router.prepare do # match("/articles/:title").to(:controller => :articles, :action => :show).name("articles") # end # # url(:articles, :title => "new_article") # # Default Route # # Merb::Router.prepare do # default_routes # end # # url(:controller => "articles", :action => "new") # # Anonymous Paramters # # Merb::Router.prepare do # match("/articles/:year/:month/:title").to(:controller => :articles, :action => :show).name("articles") # end # # url(:articles, 2008, 10, "test_article") # # :api: public def url(name, *args) args << {} Merb::Router.url(name, *args) end alias_method :relative_url, :url # Returns the absolute url including the passed protocol and host. # # This uses the same arguments as the url method, with added requirements # of protocol and host options. # # :api: public def absolute_url(*args) # FIXME: arrgh, why request.protocol returns http://? # :// is not part of protocol name options = extract_options_from_args!(args) || {} protocol = options.delete(:protocol) host = options.delete(:host) raise ArgumentError, "The :protocol option must be specified" unless protocol raise ArgumentError, "The :host option must be specified" unless host args << options protocol + "://" + host + url(*args) end # Generates a URL for a single or nested resource. # # ==== Parameters # resources:: The resources for which the URL # should be generated. These resources should be specified # in the router.rb file using #resources and #resource. # # options:: Any extra parameters that are needed to # generate the URL. # # ==== Returns # String:: The generated URL. # # ==== Examples # # Merb::Router.prepare do # resources :users do # resources :comments # end # end # # resource(:users) # => /users # resource(@user) # => /users/10 # resource(@user, :comments) # => /users/10/comments # resource(@user, @comment) # => /users/10/comments/15 # resource(:users, :new) # => /users/new # resource(:@user, :edit) # => /users/10/edit # # :api: public def resource(*args) args << {} Merb::Router.resource(*args) end # Calls the capture method for the selected template engine. # # ==== Parameters # *args:: Arguments to pass to the block. # &block:: The block to call. # # ==== Returns # String:: The output of a template block or the return value of a non-template block converted to a string. # # :api: public def capture(*args, &block) ret = nil captured = send("capture_#{@_engine}", *args) do |*args| ret = yield *args end # return captured value only if it is not empty captured.empty? ? ret.to_s : captured end # Calls the concatenate method for the selected template engine. # # ==== Parameters # str:: The string to concatenate to the buffer. # binding:: The binding to use for the buffer. # # :api: public def concat(str, binding) send("concat_#{@_engine}", str, binding) end private # adds a filter to the specified filter chain # ==== Parameters # filters:: The filter chain that this should be added to. # filter:: A filter that should be added. # opts:: # Filter options (see class documentation under Filter Options). # # ==== Raises # ArgumentError:: # Both :only and :exclude, or :if and :unless given, if filter is not a # Symbol, String or Proc, or if an unknown option is passed. # # :api: private def self.add_filter(filters, filter, opts={}) raise(ArgumentError, "You can specify either :only or :exclude but not both at the same time for the same filter.") if opts.key?(:only) && opts.key?(:exclude) raise(ArgumentError, "You can specify either :if or :unless but not both at the same time for the same filter.") if opts.key?(:if) && opts.key?(:unless) opts.each_key do |key| raise(ArgumentError, "You can only specify known filter options, #{key} is invalid.") unless FILTER_OPTIONS.include?(key) end opts = normalize_filters!(opts) case filter when Proc # filters with procs created via class methods have identical signature # regardless if they handle content differently or not. So procs just # get appended filters << [filter, opts] when Symbol, String if existing_filter = filters.find {|f| f.first.to_s == filter.to_s} filters[ filters.index(existing_filter) ] = [filter, opts] else filters << [filter, opts] end else raise(ArgumentError, 'Filters need to be either a Symbol, String or a Proc' ) end end # Skip a filter that was previously added to the filter chain. Useful in # inheritence hierarchies. # # ==== Parameters # filters:: The filter chain that this should be removed from. # filter:: A filter that should be removed. # # ==== Raises # ArgumentError:: filter not Symbol or String. # # :api: private def self.skip_filter(filters, filter) raise(ArgumentError, 'You can only skip filters that have a String or Symbol name.') unless [Symbol, String].include? filter.class Merb.logger.warn("Filter #{filter} was not found in your filter chain.") unless filters.reject! {|f| f.first.to_s[filter.to_s] } end # Ensures that the passed in hash values are always arrays. # # ==== Parameters # opts:: Options for the filters (see below). # # ==== Options (opts) # :only:: A list of actions. # :exclude:: A list of actions. # # ==== Examples # normalize_filters!(:only => :new) #=> {:only => [:new]} # # :api: public def self.normalize_filters!(opts={}) opts[:only] = Array(opts[:only]).map {|x| x.to_s} if opts[:only] opts[:exclude] = Array(opts[:exclude]).map {|x| x.to_s} if opts[:exclude] return opts end end endruby-merb-core_1.1.3.orig/lib/merb-core/controller/exceptions.rb000066400000000000000000000314531175250300200247020ustar00rootroot00000000000000class Exception # Returns the action_name that will be invoked on your Exceptions controller when this # exception is raised. Override this method to force a different action to be invoked. # # ==== Returns # String:: The name of the action in the Exceptions controller which will get invoked # when this exception is raised during a request. # # :api: public # @overridable def action_name() self.class.action_name end # ==== Returns # Boolean:: Whether or not this exception is the same as another. # # :api: public def same?(other) self.class == other.class && self.message == other.message && self.backtrace == other.backtrace end # Returns the action_name that will be invoked on your Exceptions controller when an instance # is raised during a request. # # ==== Returns # String:: The name of the action in the Exceptions controller which will get invoked # when an instance of this Exception sub/class is raised by an action. # # :api: public # @overridable def self.action_name if self == Exception return nil unless Object.const_defined?(:Exceptions) && Exceptions.method_defined?(:exception) end name = self.to_s.split('::').last.snake_case Object.const_defined?(:Exceptions) && Exceptions.method_defined?(name) ? name : superclass.action_name end # The status that will be sent in the response when an instance is # raised during a request. Override this to send a different status. # # ==== Returns # Integer:: The status code to send in the response. Defaults to 500. # # :api: public # @overridable def self.status 500 end end module Merb # ControllerExceptions are a way of simplifying controller code by placing # exception logic back into the MVC pattern. # # When a ControllerException is raised within your application merb will # attempt to re-route the request to your Exceptions controller to render # the error in a friendly manor. # # For example you might have an action in your app that raises NotFound # if a resource was not available # # def show # product = Product.find(params[:id]) # raise NotFound if product.nil? # [...] # end # # This would halt execution of your action and re-route it over to your # Exceptions controller which might look something like: # # class Exceptions < Merb::Controller # def not_found # render :layout => :none # end # end # # As usual, the not_found action will look for a template in # app/views/exceptions/not_found.html.erb # # Note: All standard ControllerExceptions have an HTTP status code associated # with them which is sent to the browser when the action is rendered. # # Note: If you do not specifiy how to handle raised ControllerExceptions # or an unhandlable exception occurs within your customised exception action # then they will be rendered using the built-in error template. # In development mode this "built in" template will show stack-traces for # any of the ServerError family of exceptions (you can force the stack-trace # to display in production mode using the :exception_details config option in # merb.yml) # # # ==== Internal Exceptions # # Any other rogue errors (not ControllerExceptions) that occur during the # execution of your app will be converted into the ControllerException # InternalServerError. And like all other exceptions, the ControllerExceptions # can be caught on your Exceptions controller. # # InternalServerErrors return status 500, a common use for customizing this # action might be to send emails to the development team, warning that their # application has exploded. Mock example: # # def internal_server_error # MySpecialMailer.deliver( # "team@cowboys.com", # "Exception occured at #{Time.now}", # self.request.exceptions.first) # render 'Something is wrong, but the team is on it!' # end # # Note: The special method +exceptions+ is available on Merb::Request instances # and contains the exceptions that was raised (this is handy if # you want to display the associated message or display more detailed info). # # # ==== Extending ControllerExceptions # # To extend the use of the ControllerExceptions one may extend any of the # HTTPError classes. # # As an example we can create an exception called AdminAccessRequired. # # class AdminAccessRequired < Merb::ControllerExceptions::Unauthorized; end # # Add the required action to our Exceptions controller # # class Exceptions < Merb::Controller # def admin_access_required # render # end # end # # In app/views/exceptions/admin_access_required.rhtml # #

You're not an administrator!

#

You tried to access <%= @tried_to_access %> but that URL is # restricted to administrators.

# module ControllerExceptions # Mapping of status code names to their numeric value. STATUS_CODES = {} class Base < StandardError #:doc: # === Returns # Integer:: The status-code of the error. # # @overridable # :api: plugin def status; self.class.status; end alias :to_i :status class << self # Get the actual status-code for an Exception class. # # As usual, this can come from a constant upwards in # the inheritance chain. # # ==== Returns # Fixnum:: The status code of this exception. # # :api: public def status const_get(:STATUS) rescue 0 end alias :to_i :status # Set the actual status-code for an Exception class. # # If possible, set the STATUS constant, and update # any previously registered (inherited) status-code. # # ==== Parameters # num<~to_i>:: The status code # # ==== Returns # (Integer, nil):: The status set on this exception, or nil if a status was already set. # # :api: private def status=(num) unless self.status? register_status_code(self, num) self.const_set(:STATUS, num.to_i) end end # See if a status-code has been defined (on self explicitly). # # ==== Returns # Boolean:: Whether a status code has been set # # :api: private def status? self.const_defined?(:STATUS) end # Registers any subclasses with status codes for easy lookup by # set_status in Merb::Controller. # # Inheritance ensures this method gets inherited by any subclasses, so # it goes all the way down the chain of inheritance. # # ==== Parameters # # subclass:: # The Exception class that is inheriting from Merb::ControllerExceptions::Base # # :api: public def inherited(subclass) # don't set the constant yet - any class methods will be called after self.inherited # unless self.status = ... is set explicitly, the status code will be inherited register_status_code(subclass, self.status) if self.status? end private # Register the status-code for an Exception class. # # ==== Parameters # num<~to_i>:: The status code # # :api: privaate def register_status_code(klass, code) name = self.to_s.split('::').last.snake_case STATUS_CODES[name.to_sym] = code.to_i end end end class Informational < Merb::ControllerExceptions::Base; end class Continue < Merb::ControllerExceptions::Informational; self.status = 100; end class SwitchingProtocols < Merb::ControllerExceptions::Informational; self.status = 101; end class Successful < Merb::ControllerExceptions::Base; end class OK < Merb::ControllerExceptions::Successful; self.status = 200; end class Created < Merb::ControllerExceptions::Successful; self.status = 201; end class Accepted < Merb::ControllerExceptions::Successful; self.status = 202; end class NonAuthoritativeInformation < Merb::ControllerExceptions::Successful; self.status = 203; end class NoContent < Merb::ControllerExceptions::Successful; self.status = 204; end class ResetContent < Merb::ControllerExceptions::Successful; self.status = 205; end class PartialContent < Merb::ControllerExceptions::Successful; self.status = 206; end class Redirection < Merb::ControllerExceptions::Base; end class MultipleChoices < Merb::ControllerExceptions::Redirection; self.status = 300; end class MovedPermanently < Merb::ControllerExceptions::Redirection; self.status = 301; end class MovedTemporarily < Merb::ControllerExceptions::Redirection; self.status = 302; end class SeeOther < Merb::ControllerExceptions::Redirection; self.status = 303; end class NotModified < Merb::ControllerExceptions::Redirection; self.status = 304; end class UseProxy < Merb::ControllerExceptions::Redirection; self.status = 305; end class TemporaryRedirect < Merb::ControllerExceptions::Redirection; self.status = 307; end class ClientError < Merb::ControllerExceptions::Base; end class BadRequest < Merb::ControllerExceptions::ClientError; self.status = 400; end class MultiPartParseError < Merb::ControllerExceptions::BadRequest; end class Unauthorized < Merb::ControllerExceptions::ClientError; self.status = 401; end class PaymentRequired < Merb::ControllerExceptions::ClientError; self.status = 402; end class Forbidden < Merb::ControllerExceptions::ClientError; self.status = 403; end class NotFound < Merb::ControllerExceptions::ClientError; self.status = 404; end class ActionNotFound < Merb::ControllerExceptions::NotFound; end class TemplateNotFound < Merb::ControllerExceptions::NotFound; end class LayoutNotFound < Merb::ControllerExceptions::NotFound; end class MethodNotAllowed < Merb::ControllerExceptions::ClientError; self.status = 405; end class NotAcceptable < Merb::ControllerExceptions::ClientError; self.status = 406; end class ProxyAuthenticationRequired < Merb::ControllerExceptions::ClientError; self.status = 407; end class RequestTimeout < Merb::ControllerExceptions::ClientError; self.status = 408; end class Conflict < Merb::ControllerExceptions::ClientError; self.status = 409; end class Gone < Merb::ControllerExceptions::ClientError; self.status = 410; end class LengthRequired < Merb::ControllerExceptions::ClientError; self.status = 411; end class PreconditionFailed < Merb::ControllerExceptions::ClientError; self.status = 412; end class RequestEntityTooLarge < Merb::ControllerExceptions::ClientError; self.status = 413; end class RequestURITooLarge < Merb::ControllerExceptions::ClientError; self.status = 414; end class UnsupportedMediaType < Merb::ControllerExceptions::ClientError; self.status = 415; end class RequestRangeNotSatisfiable < Merb::ControllerExceptions::ClientError; self.status = 416; end class ExpectationFailed < Merb::ControllerExceptions::ClientError; self.status = 417; end class ServerError < Merb::ControllerExceptions::Base; end class InternalServerError < Merb::ControllerExceptions::ServerError; self.status = 500; end class NotImplemented < Merb::ControllerExceptions::ServerError; self.status = 501; end class BadGateway < Merb::ControllerExceptions::ServerError; self.status = 502; end class ServiceUnavailable < Merb::ControllerExceptions::ServerError; self.status = 503; end class GatewayTimeout < Merb::ControllerExceptions::ServerError; self.status = 504; end class HTTPVersionNotSupported < Merb::ControllerExceptions::ServerError; self.status = 505; end end # Required to show exceptions in the log file # # e:: The exception that a message is being generated for # # :api: plugin def self.exception(e) "#{ e.message } - (#{ e.class })\n" << "#{(e.backtrace or []).join("\n")}" end end ruby-merb-core_1.1.3.orig/lib/merb-core/controller/merb_controller.rb000066400000000000000000000355251175250300200257150ustar00rootroot00000000000000class Merb::Controller < Merb::AbstractController class_inheritable_accessor :_hidden_actions, :_shown_actions, :_overridable, :_override_bang self._hidden_actions ||= [] self._shown_actions ||= [] self._overridable ||= [] self._override_bang ||= [] cattr_accessor :_subclasses self._subclasses = Set.new # :api: private def self.subclasses_list() _subclasses end include Merb::ResponderMixin include Merb::ControllerMixin include Merb::AuthenticationMixin include Merb::ConditionalGetMixin # ==== Parameters # klass:: # The Merb::Controller inheriting from the base class. # # :api: private def self.inherited(klass) _subclasses << klass.to_s super klass._template_root = Merb.dir_for(:view) unless self._template_root end # ==== Parameters # *names:: # an Array of method names that should be overridable in application # controllers. # # ==== Returns # Array:: The list of methods that are overridable # # :api: plugin def self.overridable(*names) self._overridable.push(*names) end # In an application controller, call override! before a method to indicate # that you want to override a method in Merb::Controller that is not # normally overridable. # # Doing this may potentially break your app in a future release of Merb, # and this is provided for users who are willing to take that risk. # Without using override!, Merb will raise an error if you attempt to # override a method defined on Merb::Controller. # # This is to help users avoid a common mistake of defining an action # that overrides a core method on Merb::Controller. # # ==== Parameters # *names:: # An Array of methods that will override Merb core classes on purpose # # ==== Example # # class Kontroller < Application # def status # render # end # end # # will raise a Merb::ReservedError, because #status is a method on # Merb::Controller. # # class Kontroller < Application # override! :status # def status # some_code || super # end # end # # will not raise a Merb::ReservedError, because the user specifically # decided to override the status method. # # :api: public def self.override!(*names) self._override_bang.push(*names) end # Hide each of the given methods from being callable as actions. # # ==== Parameters # *names<~to-s>:: Actions that should be added to the list. # # ==== Returns # Array[String]:: # An array of actions that should not be possible to dispatch to. # # :api: public def self.hide_action(*names) self._hidden_actions = self._hidden_actions | names.map { |n| n.to_s } end # Makes each of the given methods being callable as actions. You can use # this to make methods included from modules callable as actions. # # ==== Parameters # *names<~to-s>:: Actions that should be added to the list. # # ==== Returns # Array[String]:: # An array of actions that should be dispatched to even if they would not # otherwise be. # # ==== Example # module Foo # def self.included(base) # base.show_action(:foo) # end # # def foo # # some actiony stuff # end # # def foo_helper # # this should not be an action # end # end # # :api: public def self.show_action(*names) self._shown_actions = self._shown_actions | names.map {|n| n.to_s} end # The list of actions that are callable, after taking defaults, # _hidden_actions and _shown_actions into consideration. It is calculated # once, the first time an action is dispatched for this controller. # # ==== Returns # SimpleSet[String]:: A set of actions that should be callable. # # :api: public def self.callable_actions @callable_actions ||= Extlib::SimpleSet.new(_callable_methods) end # This is a stub method so plugins can implement param filtering if they want. # # ==== Parameters # params String}>:: A list of params # # ==== Returns # Hash{Symbol => String}:: A new list of params, filtered as desired # # :api: plugin # @overridable def self._filter_params(params) params end overridable :_filter_params # All methods that are callable as actions. # # ==== Returns # Array:: A list of method names that are also actions # # :api: private def self._callable_methods callables = [] klass = self begin callables << (klass.public_instance_methods(false) + klass._shown_actions).map{|m| m.to_s} - klass._hidden_actions klass = klass.superclass end until klass == Merb::AbstractController || klass == Object callables.flatten.reject{|action| action =~ /^_.*/}.map {|x| x.to_s} end # The location to look for a template for a particular controller, context, # and mime-type. This is overridden from AbstractController, which defines a # version of this that does not involve mime-types. # # ==== Parameters # context<~to_s>:: The name of the action or template basename that will be rendered. # type<~to_s>:: # The mime-type of the template that will be rendered. Defaults to nil. # controller<~to_s>:: # The name of the controller that will be rendered. Defaults to # controller_name. This will be "layout" for rendering a layout. # # ==== Notes # By default, this renders ":controller/:action.:type". To change this, # override it in your application class or in individual controllers. # # :api: public # @overridable def _template_location(context, type, controller) _conditionally_append_extension(controller ? "#{controller}/#{context}" : "#{context}", type) end overridable :_template_location # The location to look for a template and mime-type. This is overridden # from AbstractController, which defines a version of this that does not # involve mime-types. # # ==== Parameters # template:: # The absolute path to a template - without mime and template extension. # The mime-type extension is optional - it will be appended from the # current content type if it hasn't been added already. # type<~to_s>:: # The mime-type of the template that will be rendered. Defaults to nil. # # :api: public def _absolute_template_location(template, type) _conditionally_append_extension(template, type) end # Build a new controller. # # Sets the variables that came in through the dispatch as available to # the controller. # # ==== Parameters # request:: The Merb::Request that came in from Rack. # status:: An integer code for the status. Defaults to 200. # headers value}>:: # A hash of headers to start the controller with. These headers can be # overridden later by the #headers method. # # :api: plugin # @overridable def initialize(request, status=200, headers={'Content-Type' => 'text/html; charset=utf-8'}) super() @request, @_status, @headers = request, status, headers end overridable :initialize # Call the controller as a Rack endpoint. # # Expects: # env["merb.status"]:: the default status code to be returned # env["merb.action_name"]:: the action name to dispatch # env["merb.request_start"]:: a Time object representing the # start of the request. # # ==== Parameters # env:: A rack environment # # ==== Returns # Array[Integer, Hash, #each]:: A standard Rack response # # :api: public def self.call(env) new(Merb::Request.new(env), env["merb.status"])._call end # Dispatches the action and records benchmarks # # ==== Returns # Array[Integer, Hash, #each]:: A standard Rack response # # :api: private def _call _dispatch(request.env["merb.action_name"]) _benchmarks[:dispatch_time] = Time.now - request.env["merb.request_start"] Merb.logger.info { _benchmarks.inspect } Merb.logger.flush rack_response end # Dispatch the action. # # ==== Parameters # action<~to_s>:: An action to dispatch to. Defaults to :index. # # ==== Returns # String:: The string sent to the logger for time spent. # # ==== Raises # ActionNotFound:: The requested action was not found in class. # # :api: plugin def _dispatch(action=:index) Merb.logger.info { "Params: #{self.class._filter_params(request.params).inspect}" } start = Time.now if self.class.callable_actions.include?(action.to_s) super(action) else raise ActionNotFound, "Action '#{action}' was not found in #{self.class}" end @_benchmarks[:action_time] = Time.now - start self end # :api: public attr_reader :request, :headers # ==== Returns # Fixnum:: The response status code # # :api: public def status @_status end # Set the response status code. # # ==== Parameters # s:: A status-code or named http-status # # :api: public def status=(s) if s.is_a?(Symbol) && STATUS_CODES.key?(s) @_status = STATUS_CODES[s] elsif s.is_a?(Fixnum) @_status = s else raise ArgumentError, "Status should be of type Fixnum or Symbol, was #{s.class}" end end # ==== Returns # Hash:: The parameters from the request object # # :api: public def params() request.params end # There are three possible ways to use this method. First, if you have a named route, # you can specify the route as the first parameter as a symbol and any paramters in a # hash. Second, you can generate the default route by just passing the params hash, # just passing the params hash. Finally, you can use the anonymous parameters. This # allows you to specify the parameters to a named route in the order they appear in the # router. # # ==== Parameters(Named Route) # name:: # The name of the route. # args:: # Parameters for the route generation. # # ==== Parameters(Default Route) # args:: # Parameters for the route generation. This route will use the default route. # # ==== Parameters(Anonymous Parameters) # name:: # The name of the route. # args:: # An array of anonymous parameters to generate the route # with. These parameters are assigned to the route parameters # in the order that they are passed. # # ==== Returns # String:: The generated URL. # # ==== Examples # Named Route # # Merb::Router.prepare do # match("/articles/:title").to(:controller => :articles, :action => :show).name("articles") # end # # url(:articles, :title => "new_article") # # Default Route # # Merb::Router.prepare do # default_routes # end # # url(:controller => "articles", :action => "new") # # Anonymous Paramters # # Merb::Router.prepare do # match("/articles/:year/:month/:title").to(:controller => :articles, :action => :show).name("articles") # end # # url(:articles, 2008, 10, "test_article") # # :api: public def url(name, *args) args << params name = request.route if name == :this Merb::Router.url(name, *args) end # Generates a URL for a single or nested resource. # # ==== Parameters # resources:: The resources for which the URL # should be generated. These resources should be specified # in the router.rb file using #resources and #resource. # # options:: Any extra parameters that are needed to # generate the URL. # # ==== Returns # String:: The generated URL. # # ==== Examples # # Merb::Router.prepare do # resources :users do # resources :comments # end # end # # resource(:users) # => /users # resource(@user) # => /users/10 # resource(@user, :comments) # => /users/10/comments # resource(@user, @comment) # => /users/10/comments/15 # resource(:users, :new) # => /users/new # resource(:@user, :edit) # => /users/10/edit # # :api: public def resource(*args) args << params Merb::Router.resource(*args) end alias_method :relative_url, :url # Returns the absolute url including the passed protocol and host. # # This uses the same arguments as the url method, with added requirements # of protocol and host options. # # :api: public def absolute_url(*args) options = extract_options_from_args!(args) || {} options[:protocol] ||= request.protocol options[:host] ||= request.host args << options super(*args) end # The results of the controller's render, to be returned to Rack. # # ==== Returns # Array[Integer, Hash, String]:: # The controller's status code, headers, and body # # :api: private def rack_response [status, headers, Merb::Rack::StreamWrapper.new(body)] end # Sets a controller to be "abstract" # This controller will not be able to be routed to # and is used for super classing only # # :api: public def self.abstract! @_abstract = true end # Asks a controller if it is abstract # # === Returns # Boolean # true if the controller has been set as abstract # # :api: public def self.abstract? !!@_abstract end # Hide any methods that may have been exposed as actions before. hide_action(*_callable_methods) private # If not already added, add the proper mime extension to the template path. # # ==== Parameters # # template<~to_s> :: # The template path to append the mime type to. # type<~to_s> :: # The extension to append to the template path conditionally # # :api: private def _conditionally_append_extension(template, type) type && !template.match(/\.#{type.to_s.escape_regexp}$/) ? "#{template}.#{type}" : template end # When a method is added to a subclass of Merb::Controller (i.e. an app controller) that # is defined on Merb::Controller, raise a Merb::ReservedError. An error will not be raised # if the method is defined as overridable in the Merb API. # # This behavior can be overridden by using override! method_name before attempting to # override the method. # # ==== Parameters # meth<~to_sym> The method that is being added # # ==== Raises # Merb::ReservedError:: # If the method being added is in a subclass of Merb::Controller, # the method is defined on Merb::Controller, it is not defined # as overridable in the Merb API, and the user has not specified # that it can be overridden. # # ==== Returns # nil # # :api: private def self.method_added(meth) if self < Merb::Controller && Merb::Controller.method_defined?(meth) && !self._overridable.include?(meth.to_sym) && !self._override_bang.include?(meth.to_sym) raise Merb::ReservedError, "You tried to define #{meth} on " \ "#{self.name} but it was already defined on Merb::Controller. " \ "If you meant to override a core method, use override!" end end end ruby-merb-core_1.1.3.orig/lib/merb-core/controller/mime.rb000066400000000000000000000117711175250300200234510ustar00rootroot00000000000000module Merb class << self # Returns a hash of the available mime types. # # ==== Returns # Hash{Symbol => Hash{Symbol => Object}}:: The available mime types. # # ==== Notes # Each entry corresponds to a call to add_mime_type, having the mime type key (:html, :xml, :json, etc.) # as the key and a hash containing the following entries: # :accepts # the mime types that will be recognized by this entry # :transform_method # the method called on an object to convert it to content of this type (such as to_json) # :content_type # the value set to the "Content-Type" HTTP header when this mime is sent in a response # :response_headers # sent in a response using this content type # :default_quality # the scale factor used in describing content type preference # :response_block # the block to be called with the controller when a request responds to this mime type # # :api: public def available_mime_types ResponderMixin::TYPES end # ==== Returns # Hash{String => Symbol}:: # A hash mapping Content-Type values to the mime type key of the appropriate entry in #available_mime_types # # :api: public def available_accepts ResponderMixin::MIMES end # Any specific outgoing headers should be included here. These are not # the content-type header but anything in addition to it. # +transform_method+ should be set to a symbol of the method used to # transform a resource into this mime type. # For example for the :xml mime type an object might be transformed by # calling :to_xml, or for the :js mime type, :to_json. # If there is no transform method, use nil. # # ==== Autogenerated Methods # Adding a mime-type adds a render_type method that sets the content # type and calls render. # # By default this does: def render_all, def render_yaml, def render_text, # def render_html, def render_xml, def render_js, and def render_yaml # # ==== Parameters # key:: The name of the mime-type. This is used by the provides API # transform_method<~to_s>:: # The associated method to call on objects to convert them to the # appropriate mime-type. For instance, :json would use :to_json as its # transform_method. # mimes:: # A list of possible values sent in the Accept header, such as text/html, # that should be associated with this content-type. # new_response_headers:: # The response headers to set for the the mime type. For example: # 'Content-Type' => 'application/json; charset=utf-8'; As a shortcut for # the common charset option, use :charset => 'utf-8', which will be # correctly appended to the mimetype itself. # &block:: a block which recieves the current controller when the format # is set (in the controller's #content_type method) # # ==== Returns # nil # # :api: public def add_mime_type(key, transform_method, mimes, new_response_headers = {}, default_quality = 1, &block) enforce!(key => Symbol, mimes => Array) content_type = new_response_headers["Content-Type"] || mimes.first if charset = new_response_headers.delete(:charset) content_type += "; charset=#{charset}" end ResponderMixin::TYPES.update(key => {:accepts => mimes, :transform_method => transform_method, :content_type => content_type, :response_headers => new_response_headers, :default_quality => default_quality, :response_block => block }) mimes.each do |mime| ResponderMixin::MIMES.update(mime => key) end Merb::RenderMixin.class_eval <<-EOS, __FILE__, __LINE__ def render_#{key}(thing = nil, opts = {}) self.content_type = :#{key} render thing, opts end EOS nil end # Removes a MIME-type from the mime-type list. # # ==== Parameters # key:: The key that represents the mime-type to remove. # # ==== Returns # (Boolean, Hash{Symbol => Object}):: If it was present, the old specification of the MIME-type. Same structure # as a value in Merb.available_mime_types. False if the key was not present. # # ==== Notes # :all is the key for */*; It can't be removed. # # :api: public def remove_mime_type(key) return false if key == :all ResponderMixin::TYPES.delete(key) end # ==== Parameters # key:: The key that represents the mime-type. # # ==== Returns # Symbol:: The transform method for the mime type, e.g. :to_json. # # ==== Raises # ArgumentError:: The requested mime type is not valid. # # :api: private def mime_transform_method(key) raise ArgumentError, ":#{key} is not a valid MIME-type" unless ResponderMixin::TYPES.key?(key) ResponderMixin::TYPES[key][:transform_method] end end end ruby-merb-core_1.1.3.orig/lib/merb-core/controller/mixins/000077500000000000000000000000001175250300200234755ustar00rootroot00000000000000ruby-merb-core_1.1.3.orig/lib/merb-core/controller/mixins/authentication.rb000066400000000000000000000111261175250300200270420ustar00rootroot00000000000000module Merb::AuthenticationMixin # Attempts to authenticate the user via HTTP Basic authentication. Takes a # block with the username and password, if the block yields false the # authentication is not accepted and :halt is thrown. # # If no block is passed, +basic_authentication+, the +request+ and +authenticate+ # methods can be chained. These can be used to independently request authentication # or confirm it, if more control is desired. # # ==== Parameters # realm<~to_s>:: The realm to authenticate against. Defaults to 'Application'. # &authenticator:: A block to check if the authentication is valid. # # ==== Returns # Merb::AuthenticationMixin::BasicAuthentication # # ==== Examples # class Application < Merb::Controller # # before :authenticate # # protected # # def authenticate # basic_authentication("My App") do |username, password| # password == "secret" # end # end # # end # # class Application < Merb::Controller # # before :authenticate # # def authenticate # user = basic_authentication.authenticate do |username, password| # User.authenticate(username, password) # end # # if user # @current_user = user # else # basic_authentication.request # end # end # # end # # If you need to request basic authentication inside an action you need to use the request! method. # # ==== Example # # class Sessions < Application # # def new # case content_type # when :html # render # # else # user = basic_authentication.authenticate do |username, password| # User.authenticate(username, password) # end # # if user # display(user) # else # basic_authentication.request # end # end # end # # end # # # :api: public def basic_authentication(realm = "Application", &authenticator) @_basic_authentication ||= BasicAuthentication.new(self, realm, &authenticator) end class BasicAuthentication # So we can have access to the status codes include Merb::ControllerExceptions # :api: private def initialize(controller, realm = "Application", &authenticator) @controller = controller @realm = realm @auth = Rack::Auth::Basic::Request.new(@controller.request.env) authenticate_or_request(&authenticator) if authenticator end # Determines whether or not the user is authenticated using the criteria # in the provided authenticator block. # # ==== Parameters # &authenticator:: A block that decides whether the provided username and password # are valid. # # ==== Returns # Object:: False if basic auth is not provided, otherwise the return value of the authenticator block. # # @overridable # :api: public def authenticate(&authenticator) if @auth.provided? and @auth.basic? authenticator.call(*@auth.credentials) else false end end # Request basic authentication and halt the filter chain. This is for use in a before filter. # # ==== Throws # :halt with an "HTTP Basic: Access denied." message with no layout, and sets the status to Unauthorized. # # :api: public def request request! throw :halt, @controller.render("HTTP Basic: Access denied.\n", :status => Unauthorized.status, :layout => false) end # Sets headers to request basic auth. # # ==== Returns # String:: Returns the empty string to provide a response body. # # :api: public def request! @controller.status = Unauthorized.status @controller.headers['WWW-Authenticate'] = 'Basic realm="%s"' % @realm "" end # ==== Returns # Boolean:: Whether there has been any basic authentication credentials provided # # :api: public def provided? @auth.provided? end # ==== Returns # String:: The username provided in the request. # # :api: public def username provided? ? @auth.credentials.first : nil end # ==== Returns # String:: The password provided in the request. # # :api: public def password provided? ? @auth.credentials.last : nil end protected # :api: private def authenticate_or_request(&authenticator) authenticate(&authenticator) || request end end end ruby-merb-core_1.1.3.orig/lib/merb-core/controller/mixins/conditional_get.rb000066400000000000000000000062041175250300200271660ustar00rootroot00000000000000# Provides conditional get support in Merb core. # Conditional get support is intentionally # simple and does not do fancy stuff like making # ETag value from Ruby objects for you. # # The most interesting method for end user is # +request_fresh?+ that is used after setting of # last modification time or ETag: # # # @example # def show # self.etag = Digest::SHA1.hexdigest(calculate_cache_key(params)) # # if request_fresh? # self.status = 304 # return '' # else # @product = Product.get(params[:id]) # display @product # end # end module Merb::ConditionalGetMixin # Sets ETag response header by calling #to_s on the argument # # @param tag [#to_s] value of ETag header # # @return [String] value of ETag header enclosed in double quotes as required by the RFC # # @api public def etag=(tag) headers[Merb::Const::ETAG] = %("#{tag}") end # Value of the ETag header # # @return [String] Value of ETag response header if set. # @return [nil] If ETag header not set. # # @api public def etag headers[Merb::Const::ETAG] end # Test to see if the request's Etag matches the one supplied locally # # @return [true] if ETag response header equals If-None-Match request header # @return [true] if it does not. # # @api public def etag_matches?(tag = self.etag) tag == self.request.if_none_match end # Sets Last-Modified response header # # @param time [Time,DateTime] The last modified time of the resource # # @return [String] The last modified time of the resource in the format required by the RFC # # @api public def last_modified=(time) time = time.to_time if time.is_a?(DateTime) # time.utc.strftime("%a, %d %b %Y %X") if we could rely on locale being American headers[Merb::Const::LAST_MODIFIED] = time.httpdate end # Value of the Last-Modified header # # @return [Time] Value of Last-Modified response header if set. # @return [nil] If Last-Modified not set. # # @api public def last_modified last_mod = headers[Merb::Const::LAST_MODIFIED] Time.rfc2822(last_mod) if last_mod end # Test to see if the request's If-Modified-Since is satisfied # # @param time [Time] Time to test if the If-Modified-Since header against # # @return [true] Last-Modified response header is < than If-Modified-Since request header # @return [false] otherwise # # @api public def not_modified?(time = self.last_modified) if !request.if_modified_since.nil? and !time.nil? time <= request.if_modified_since else false end end # Tests freshness of response using all supplied validators # # A response with no validators is always stale. # # @return [true] ETag matches and entity is not modified # @return [false] One or more validators failed, or none were supplied # # @api public def request_fresh? # make sure we have something to compare too. return false unless last_modified or etag fresh = true # only check if we have set the right headers fresh &&= etag_matches?(self.etag) if etag fresh &&= not_modified?(self.last_modified) if last_modified fresh end end ruby-merb-core_1.1.3.orig/lib/merb-core/controller/mixins/controller.rb000066400000000000000000000321471175250300200262140ustar00rootroot00000000000000module Merb # Module that is mixed in to all implemented controllers. module ControllerMixin # Enqueu a block to run in a background thread outside of the request # response dispatch # # ==== Parameters # &blk:: proc to run later # # ==== Example # run_later do # SomeBackgroundTask.run # end # # :api: public def run_later(&blk) Merb.run_later(&blk) end # Renders the block given as a parameter using chunked encoding. # # ==== Parameters # &blk:: # A block that, when called, will use send_chunks to send chunks of data # down to the server. The chunking will terminate once the block returns. # # ==== Examples # def stream # prefix = '

' # suffix = "

\r\n" # render_chunked do # IO.popen("cat /tmp/test.log") do |io| # done = false # until done # sleep 0.3 # line = io.gets.chomp # # if line == 'EOF' # done = true # else # send_chunk(prefix + line + suffix) # end # end # end # end # end # # :api: public def render_chunked(&blk) must_support_streaming! headers['Transfer-Encoding'] = 'chunked' Proc.new { |response| @response = response response.send_status_no_connection_close('') response.send_header blk.call response.write("0\r\n\r\n") } end # Writes a chunk from +render_chunked+ to the response that is sent back to # the client. This should only be called within a +render_chunked+ block. # # ==== Parameters # data:: a chunk of data to return. # # :api: public def send_chunk(data) only_runs_on_mongrel! @response.write('%x' % data.size + "\r\n") @response.write(data + "\r\n") end # ==== Parameters # &blk:: # A proc that should get called outside the mutex, and which will return # the value to render. # # ==== Returns # Proc:: # A block that the server can call later, allowing Merb to release the # thread lock and render another request. # # :api: public def render_deferred(&blk) Proc.new do |response| response.write(blk.call) end end # Renders the passed in string, then calls the block outside the mutex and # after the string has been returned to the client. # # ==== Parameters # str:: A +String+ to return to the client. # &blk:: A block that should get called once the string has been returned. # # ==== Returns # Proc:: # A block that Mongrel can call after returning the string to the user. # # :api: public def render_then_call(str, &blk) Proc.new do |response| response.write(str) blk.call end end # ==== Parameters # url:: # URL to redirect to. It can be either a relative or fully-qualified URL. # opts:: An options hash (see below) # # ==== Options (opts) # :message:: # Messages to pass in url query string as value for "_message" # :permanent:: # When true, return status 301 Moved Permanently # :notice:: # Shorthand for common usage :message => {:notice => "..."} # :error:: # Shorthand for common usage :message => {:error => "..."} # :success:: # Shorthand for common usage :message => {:success => "..."} # :status:: # Status code to set for the response. Can be any valid redirect # status. Has precedence over the :permanent parameter, which is # retained for convenience. # # ==== Returns # String:: Explanation of redirect. # # ==== Examples # redirect("/posts/34") # redirect("/posts/34", :message => { :notice => 'Post updated successfully!' }) # redirect("http://www.merbivore.com/") # redirect("http://www.merbivore.com/", :permanent => true) # redirect("/posts/34", :notice => 'Post updated successfully!') # # :api: public def redirect(url, opts = {}) default_redirect_options = { :message => nil, :permanent => false } opts = default_redirect_options.merge(opts) url = handle_redirect_messages(url,opts) _status = opts[:status] if opts[:status] _status ||= opts[:permanent] ? 301 : 302 self.status = _status Merb.logger.info("Redirecting to: #{url} (#{self.status})") headers['Location'] = url "You are being redirected." end # Retreives the redirect message either locally or from the request. # # :api: public def message @_message = defined?(@_message) ? @_message : request.message end # Sends a file over HTTP. When given a path to a file, it will set the # right headers so that the static file is served directly. # # ==== Parameters # file:: Path to file to send to the client. # opts:: Options for sending the file (see below). # # ==== Options (opts) # :disposition:: # The disposition of the file send. Defaults to "attachment". # :filename:: # The name to use for the file. Defaults to the filename of file. # :type:: The content type. # # ==== Returns # IO:: An I/O stream for the file. # # :api: public def send_file(file, opts={}) opts.update(Merb::Const::DEFAULT_SEND_FILE_OPTIONS.merge(opts)) disposition = opts[:disposition].dup || 'attachment' disposition << %(; filename="#{opts[:filename] ? opts[:filename] : File.basename(file)}") headers.update( 'Content-Type' => opts[:type].strip, # fixes a problem with extra '\r' with some browsers 'Content-Disposition' => disposition, 'Content-Transfer-Encoding' => 'binary' ) Proc.new do |response| file = File.open(file, 'rb') while chunk = file.read(16384) response.write chunk end file.close end end # Send binary data over HTTP to the user as a file download. May set content type, # apparent file name, and specify whether to show data inline or download as an attachment. # # ==== Parameters # data:: Path to file to send to the client. # opts:: Options for sending the data (see below). # # ==== Options (opts) # :disposition:: # The disposition of the file send. Defaults to "attachment". # :filename:: # The name to use for the file. Defaults to the filename of file. # :type:: The content type. # # :api: public def send_data(data, opts={}) opts.update(Merb::Const::DEFAULT_SEND_FILE_OPTIONS.merge(opts)) disposition = opts[:disposition].dup || 'attachment' disposition << %(; filename="#{opts[:filename]}") if opts[:filename] headers.update( 'Content-Type' => opts[:type].strip, # fixes a problem with extra '\r' with some browsers 'Content-Disposition' => disposition, 'Content-Transfer-Encoding' => 'binary' ) data end # Streams a file over HTTP. # # ==== Parameters # opts:: Options for the file streaming (see below). # &stream:: # A block that, when called, will return an object that responds to # +get_lines+ for streaming. # # ==== Options # :disposition:: # The disposition of the file send. Defaults to "attachment". # :type:: The content type. # :content_length:: The length of the content to send. # :filename:: The name to use for the streamed file. # # ==== Examples # stream_file({ :filename => file_name, :type => content_type, # :content_length => content_length }) do |response| # AWS::S3::S3Object.stream(user.folder_name + "-" + user_file.unique_id, bucket_name) do |chunk| # response.write chunk # end # end # # :api: public def stream_file(opts={}, &stream) opts.update(Merb::Const::DEFAULT_SEND_FILE_OPTIONS.merge(opts)) disposition = opts[:disposition].dup || 'attachment' disposition << %(; filename="#{opts[:filename]}") headers.update( 'Content-Type' => opts[:type].strip, # fixes a problem with extra '\r' with some browsers 'Content-Disposition' => disposition, 'Content-Transfer-Encoding' => 'binary', # Rack specification requires header values to respond to :each 'CONTENT-LENGTH' => opts[:content_length].to_s ) Proc.new do |response| stream.call(response) end end # Uses the nginx specific +X-Accel-Redirect+ header to send a file directly # from nginx. # # ==== Notes # Unless Content-Disposition is set before calling this method, # it is set to attachment with streamed file name. # # For more information, see the nginx wiki: # http://wiki.codemongers.com/NginxXSendfile # # and the following sample gist: # http://gist.github.com/11225 # # there's also example application up on GitHub: # # http://github.com/michaelklishin/nginx-x-accel-redirect-example-application/tree/master # # ==== Parameters # path:: Path to file to send to the client. # content_type:: content type header value. By default is set to empty string to let # Nginx detect it. # # ==== Return # String:: precisely a single space. # # :api: public def nginx_send_file(path, content_type = "") # Let Nginx detect content type unless it is explicitly set headers['Content-Type'] = content_type headers["Content-Disposition"] ||= "attachment; filename=#{path.split('/').last}" headers['X-Accel-Redirect'] = path return ' ' end # Sets a cookie to be included in the response. # # If you need to set a cookie, then use the +cookies+ hash. # # ==== Parameters # name<~to_s>:: A name for the cookie. # value<~to_s>:: A value for the cookie. # expires<~gmtime:~strftime, Hash>:: An expiration time for the cookie, or a hash of cookie options. # # :api: public def set_cookie(name, value, expires) options = expires.is_a?(Hash) ? expires : {:expires => expires} cookies.set_cookie(name, value, options) end # Marks a cookie as deleted and gives it an expires stamp in the past. This # method is used primarily internally in Merb. # # Use the +cookies+ hash to manipulate cookies instead. # # ==== Parameters # name<~to_s>:: A name for the cookie to delete. # # :api: public def delete_cookie(name) set_cookie(name, nil, Merb::Const::COOKIE_EXPIRED_TIME) end # Escapes the string representation of +obj+ and escapes it for use in XML. # # ==== Parameter # obj<~to_s>:: The object to escape for use in XML. # # ==== Returns # String:: The escaped object. # # :api: public def escape_xml(obj) Merb::Parse.escape_xml(obj.to_s) end alias h escape_xml alias escape_html escape_xml private # Marks an output method that only runs on the Mongrel webserver. # # ==== Raises # NotImplemented:: The Rack adapter is not mongrel. # # :api: private def only_runs_on_mongrel! unless Merb::Config[:log_stream] == 'mongrel' raise(Merb::ControllerExceptions::NotImplemented, "Current Rack adapter is not mongrel. cannot support this feature") end end # Process a redirect url with options, appending messages onto the url as query params # # ==== Parameter # url:: the url being redirected to # # ==== Options (opts) # :message:: # A hash of key/value strings to be passed along within the redirect query params. # :notice:: # A shortcut to passing :message => {:notice => "..."} # :error:: # A shortcut to passing :message => {:error => "..."} # :success:: # A shortcut to passing :message => {:success => "..."} # # ==== Returns # String:: the new url with messages attached # # :api: private def handle_redirect_messages(url, opts={}) opts = opts.dup # check opts for message shortcut keys (and assign them to message) [:notice, :error, :success].each do |message_key| if opts[message_key] opts[:message] ||= {} opts[:message][message_key] = opts[message_key] end end # append message query param if message is passed if opts[:message] notice = Merb::Parse.escape([Marshal.dump(opts[:message])].pack("m")) u = ::URI.parse(url) u.query = u.query ? "#{u.query}&_message=#{notice}" : "_message=#{notice}" url = u.to_s end url end end end ruby-merb-core_1.1.3.orig/lib/merb-core/controller/mixins/render.rb000066400000000000000000000471241175250300200253110ustar00rootroot00000000000000module Merb::RenderMixin # So we can do raise TemplateNotFound include Merb::ControllerExceptions # ==== Parameters # base:: Module that is including RenderMixin (probably a controller) # # @private def self.included(base) base.extend(ClassMethods) base.class_eval do class_inheritable_accessor :_default_render_options end end module ClassMethods def _templates_for @_templates_for ||= {} end # Return the default render options. # # ==== Returns # Hash:: An options hash # # :api: public def default_render_options self._default_render_options ||= {} end # Set default render options at the class level. # # ==== Parameters # opts:: An options hash # # :api: public def render_options(opts) self._default_render_options = opts end # Set the default layout to use or nil/false to disable layout rendering. # This is a shortcut for render_options :layout => false. # # ==== Parameters # layout<~to_s>:: The layout that should be used for this class. # # ==== Notes # You can override by passing :layout => true to render method. # # ==== Returns # Hash:: The default render options. # # :api: public def layout(layout) self.default_render_options.update(:layout => (layout || false)) end # Enable the default layout logic - reset the layout option. # # ==== Returns # ~to_s:: The layout that was previously set. # # :api: public def default_layout self.default_render_options.delete(:layout) end end # Render the specified item, with the specified options. # # ==== Parameters # thing:: # The thing to render. This will default to the current action # opts:: An options hash (see below) # # ==== Options (opts) # :format:: A registered mime-type format # :template:: # The path to the template relative to the template root # :status<~to_i>:: # The status to send to the client. Typically, this would be an integer # (200), or a Merb status code (Accepted) # :layout<~to_s, FalseClass>:: # A layout to use instead of the default. This should be relative to the # layout root. By default, the layout will be either the controller_name or # application. If you want to use an alternative content-type than the one # that the base template was rendered as, you will need to do :layout => # "foo.#{content_type}" (i.e. "foo.json"). If you want to render without # layout, use :layout => false. This overrides layout set by +layout+ method. # # ==== Returns # String:: The rendered template, including layout, if appropriate. # # ==== Raises # TemplateNotFound:: There is no template for the specified location. # # ==== Alternatives # If you pass a Hash as the first parameter, it will be moved to opts and # "thing" will be the current action # # :api: public def render(thing = nil, opts = {}) # render :format => :xml means render nil, :format => :xml opts, thing = thing, nil if thing.is_a?(Hash) # Merge with class level default render options opts = self.class.default_render_options.merge(opts) # If you don't specify a thing to render, assume they want to render the current action thing ||= action_name.to_sym # Content negotiation self.content_type = opts[:format] if opts[:format] # Handle options (:status) _handle_options!(opts) # Do we have a template to try to render? if thing.is_a?(Symbol) || opts[:template] template_method, template_location = _template_for(thing, content_type, controller_name, opts[:template]) # Raise an error if there's no template unless template_method && self.respond_to?(template_method) template_files = Merb::Template.template_extensions.map { |ext| "#{template_location}.#{ext}" } raise TemplateNotFound, "Oops! No template found. Merb was looking for #{template_files.join(', ')} " + "for content type '#{content_type}'. You might have mispelled the template or file name. " + "Registered template extensions: #{Merb::Template.template_extensions.join(', ')}. " + "If you use Haml or some other template plugin, make sure you required Merb plugin dependency " + "in your init file." end # Call the method in question and throw the content for later consumption by the layout throw_content(:for_layout, self.send(template_method)) # Do we have a string to render? elsif thing.is_a?(String) # Throw it for later consumption by the layout throw_content(:for_layout, thing) end # If we find a layout, use it. Otherwise, just render the content thrown for layout. (layout = _get_layout(opts[:layout])) ? send(layout) : catch_content(:for_layout) end # Renders an object using to registered transform method based on the # negotiated content-type, if a template does not exist. For instance, if the # content-type is :json, Merb will first look for current_action.json.*. # Failing that, it will run object.to_json. # # ==== Parameter # object:: # An object that responds_to? the transform method registered for the # negotiated mime-type. # thing:: # The thing to attempt to render via #render before calling the transform # method on the object. Defaults to nil. # opts:: # An options hash that will be used for rendering # (passed on to #render or serialization methods like #to_json or #to_xml) # # ==== Returns # String:: # The rendered template or if no template is found, the transformed object. # # ==== Raises # NotAcceptable:: # If there is no transform method for the specified mime-type or the object # does not respond to the transform method. # # ==== Alternatives # A string in the second parameter will be interpreted as a template: # display @object, "path/to/foo" # #=> display @object, nil, :template => "path/to/foo" # # A hash in the second parameters will be interpreted as opts: # display @object, :layout => "zoo" # #=> display @object, nil, :layout => "zoo" # # If you need to pass extra parameters to serialization method, for instance, # to exclude some of attributes or serialize associations, just pass options # for it. # For instance, # # display @locations, :except => [:locatable_type, :locatable_id], :include => [:locatable] # # serializes object with polymorphic association, not raw locatable_* attributes. # # # ==== Options # # :template a template to use for rendering # :layout a layout to use for rendering # :status the status code to return (defaults to 200) # :location the value of the Location header # # all other options options that will be pass to serialization method # like #to_json or #to_xml # # ==== Notes # The transformed object will not be used in a layout unless a :layout is # explicitly passed in the opts. # # :api: public def display(object, thing = nil, opts = {}) template_opt = thing.is_a?(Hash) ? thing.delete(:template) : opts.delete(:template) case thing # display @object, "path/to/foo" means display @object, nil, :template => "path/to/foo" when String template_opt, thing = thing, nil # display @object, :template => "path/to/foo" means display @object, nil, :template => "path/to/foo" when Hash opts, thing = thing, nil end # Try to render without the object render(thing || action_name.to_sym, opts.merge(:template => template_opt)) # If the render fails (i.e. a template was not found) rescue TemplateNotFound => e # Merge with class level default render options # @todo can we find a way to refactor this out so we don't have to do it everywhere? opts = self.class.default_render_options.merge(opts) # Figure out what to transform and raise NotAcceptable unless there's a transform method assigned transform = Merb.mime_transform_method(content_type) if !transform raise NotAcceptable, "#{e.message} and there was no transform method registered for #{content_type.inspect}" elsif !object.respond_to?(transform) raise NotAcceptable, "#{e.message} and your object does not respond to ##{transform}" end layout_opt = opts.delete(:layout) _handle_options!(opts) throw_content(:for_layout, opts.empty? ? object.send(transform) : object.send(transform, opts)) meth, _ = _template_for(layout_opt, layout_opt.to_s.index(".") ? nil : content_type, "layout") if layout_opt meth ? send(meth) : catch_content(:for_layout) end # Render a partial template. # # ==== Parameters # template<~to_s>:: # The path to the template, relative to the current controller or the # template root; absolute path will work too. If the template contains a "/", # Merb will search for it relative to the template root; otherwise, # Merb will search for it relative to the current controller. # opts:: A hash of options (see below) # # ==== Options (opts) # :with:: # An object or an array of objects that will be passed into the partial. # :as<~to_sym>:: The local name of the :with Object inside of the partial. # :format:: The mime format that you want the partial to be in (:js, :html, etc.) # others:: # A Hash object names and values that will be the local names and values # inside the partial. # # ==== Examples # partial :foo, :hello => @object # # The "_foo" partial will be called, relative to the current controller, # with a local variable of +hello+ inside of it, assigned to @object. # # partial :bar, :with => ['one', 'two', 'three'] # # The "_bar" partial will be called once for each element of the array # specified by :with for a total of three iterations. Each element # of the array will be available in the partial via a local variable named # +bar+. Additionally, there will be two extra local variables: # +collection_index+ and +collection_size+. +collection_index+ is the index # of the object currently referenced by +bar+ in the collection passed to # the partial. +collection_size+ is the total size of the collection. # # By default, the object specified by :with will be available through a # local variable with the same name as the partial template. However, # this can be changed using the :as option. # # partial :bar, :with => "one", :as => :number # # In this case, "one" will be available in the partial through the local # variable named +number+. # # :api: public def partial(template, opts={}) # partial :foo becomes "#{controller_name}/_foo" # partial "foo/bar" becomes "foo/_bar" template = template.to_s if template =~ %r{^/} template_path = File.dirname(template) / "_#{File.basename(template)}" else kontroller = (m = template.match(/.*(?=\/)/)) ? m[0] : controller_name end template = "_#{File.basename(template)}" # This handles no :with as well with = [opts.delete(:with)].flatten as = (opts.delete(:as) || template.match(%r[(?:.*/)?_([^\./]*)])[1]).to_sym # Ensure that as is in the locals hash even if it isn't passed in here # so that it's included in the preamble. locals = opts.merge(:collection_index => -1, :collection_size => with.size, as => opts[as]) template_method, template_location = _template_for( template, opts.delete(:format) || content_type, kontroller, template_path, locals.keys) # this handles an edge-case where the name of the partial is _foo.* and your opts # have :foo as a key. named_local = opts.key?(as) sent_template = with.map do |temp| locals[as] = temp unless named_local if template_method && self.respond_to?(template_method) locals[:collection_index] += 1 send(template_method, locals) else raise TemplateNotFound, "Could not find template at #{template_location}.*" end end.join sent_template end # Take the options hash and handle it as appropriate. # # ==== Parameters # opts:: The options hash that was passed into render. # # ==== Options # :status<~to_i>:: # The status of the response will be set to opts[:status].to_i # # ==== Returns # Hash:: The options hash that was passed in. # # :api: private def _handle_options!(opts) self.status = opts.delete(:status).to_i if opts[:status] headers["Location"] = opts.delete(:location) if opts[:location] opts end # Get the layout that should be used. The content-type will be appended to # the layout unless the layout already contains a "." in it. # # If no layout was passed in, this method will look for one with the same # name as the controller, and finally one in "application.#{content_type}". # # ==== Parameters # layout<~to_s>:: A layout, relative to the layout root. Defaults to nil. # # ==== Returns # String:: The method name that corresponds to the found layout. # # ==== Raises # TemplateNotFound:: # If a layout was specified (either via layout in the class or by passing # one in to this method), and not found. No error will be raised if no # layout was specified, and the default layouts were not found. # # :api: private def _get_layout(layout = nil) return false if layout == false layout = layout.instance_of?(Symbol) && self.respond_to?(layout, true) ? send(layout) : layout layout = layout.to_s if layout # If a layout was provided, throw an error if it's not found if layout template_method, template_location = _template_for(layout, layout.index(".") ? nil : content_type, "layout") raise TemplateNotFound, "No layout found at #{template_location}" unless template_method template_method # If a layout was not provided, try the default locations else template, location = _template_for(controller_name, content_type, "layout") template, location = _template_for("application", content_type, "layout") unless template template end end # Iterate over the template roots in reverse order, and return the template # and template location of the first match. # # ==== Parameters # context:: The controller action or template (basename or absolute path). # content_type<~to_s>:: The content type (like html or json). # controller<~to_s>:: The name of the controller. Defaults to nil. # locals:: A list of locals to assign from the args passed into the compiled template. # # ==== Options (opts) # :template:: # The location of the template to use. Defaults to whatever matches this # context, content_type and controller. # # ==== Returns # Array[Symbol, String]:: # A pair consisting of the template method and location. # # :api: private def _template_for(context, content_type, controller=nil, template=nil, locals=[]) tmp = self.class._templates_for[[context, content_type, controller, template, locals]] return tmp if tmp template_method, template_location = nil, nil # absolute path to a template (:template => "/foo/bar") if template.is_a?(String) && template =~ %r{^/} template_location = self._absolute_template_location(template, content_type) return [_template_method_for(template_location, locals), template_location] end self.class._template_roots.reverse_each do |root, template_meth| # :template => "foo/bar.html" where root / "foo/bar.html.*" exists if template template_location = root / self.send(template_meth, template, content_type, nil) # :layout => "foo" where root / "layouts" / "#{controller}.html.*" exists else template_location = root / self.send(template_meth, context, content_type, controller) end break if template_method = _template_method_for(template_location.to_s, locals) end # template_location is a Pathname ret = [template_method, template_location.to_s] unless Merb::Config[:reload_templates] self.class._templates_for[[context, content_type, controller, template, locals]] = ret end ret end # Return the template method for a location, and check to make sure the current controller # actually responds to the method. # # ==== Parameters # template_location:: The phyical path of the template # locals:: A list of locals to assign from the args passed into the compiled template. # # ==== Returns # String:: The method, if it exists. Otherwise return nil. # # :api: private def _template_method_for(template_location, locals) meth = Merb::Template.template_for(template_location, [], locals) meth && self.respond_to?(meth) ? meth : nil end # Called in templates to get at content thrown in another template. The # results of rendering a template are automatically thrown into :for_layout, # so catch_content or catch_content(:for_layout) can be used inside layouts # to get the content rendered by the action template. # # ==== Parameters # obj:: The key in the thrown_content hash. Defaults to :for_layout. # # :api: public def catch_content(obj = :for_layout) @_caught_content[obj] || '' end # Called in templates to test for the existence of previously thrown content. # # ==== Parameters # obj:: The key in the thrown_content hash. Defaults to :for_layout. # # :api: public def thrown_content?(obj = :for_layout) @_caught_content.key?(obj) end # Called in templates to store up content for later use. Takes a string # and/or a block. First, the string is evaluated, and then the block is # captured using the capture() helper provided by the template languages. The # two are concatenated together. # # ==== Parameters # obj:: The key in the thrown_content hash. # string:: Textual content. Defaults to nil. # &block:: A block to be evaluated and concatenated to string. # # ==== Raises # ArgumentError:: Neither string nor block given. # # ==== Example # throw_content(:foo, "Foo") # catch_content(:foo) #=> "Foo" # # :api: public def throw_content(obj, string = nil, &block) unless string || block_given? raise ArgumentError, "You must pass a block or a string into throw_content" end @_caught_content[obj] = string.to_s << (block_given? ? capture(&block) : "") end # Called in templates to append content for later use. Works like throw_content. # # @param [Object] obj # Key used in the thrown_content hash. # @param [String] string # Textual content. Default to nil. # @yield # Evaluated with result concatenated to string. # # @raise [ArgumentError] # Neither string nor block given # # :api: public def append_content(obj, string = nil, &block) unless string || block_given? raise ArgumentError, "You must pass a block or a string into append_content" end @_caught_content[obj] = "" if @_caught_content[obj].nil? @_caught_content[obj] << string.to_s << (block_given? ? capture(&block) : "") end # Called when renderers need to be sure that existing thrown content is cleared # before throwing new content. This prevents double rendering of content when # multiple templates are rendered after each other. # # ==== Parameters # obj:: The key in the thrown_content hash. Defaults to :for_layout. # # :api: public def clear_content(obj = :for_layout) @_caught_content.delete(obj) unless @_caught_content[obj].nil? end end ruby-merb-core_1.1.3.orig/lib/merb-core/controller/mixins/responder.rb000066400000000000000000000400361175250300200260260ustar00rootroot00000000000000require 'enumerator' require 'merb-core/controller/mime' module Merb # The ResponderMixin adds methods that help you manage what # formats your controllers have available, determine what format(s) # the client requested and is capable of handling, and perform # content negotiation to pick the proper content format to # deliver. # # If you hear someone say "Use provides" they're talking about the # Responder. If you hear someone ask "What happened to respond_to?" # it was replaced by provides and the other Responder methods. # # == A simple example # # The best way to understand how all of these pieces fit together is # with an example. Here's a simple web-service ready resource that # provides a list of all the widgets we know about. The widget list is # available in 3 formats: :html (the default), plus :xml and :text. # # class Widgets < Application # provides :html # This is the default, but you can # # be explicit if you like. # provides :xml, :text # # def index # @widgets = Widget.fetch # render @widgets # end # end # # Let's look at some example requests for this list of widgets. We'll # assume they're all GET requests, but that's only to make the examples # easier; this works for the full set of RESTful methods. # # 1. The simplest case, /widgets.html # Since the request includes a specific format (.html) we know # what format to return. Since :html is in our list of provided # formats, that's what we'll return. +render+ will look # for an index.html.erb (or another template format # like index.html.mab; see the documentation on Template engines) # # 2. Almost as simple, /widgets.xml # This is very similar. They want :xml, we have :xml, so # that's what they get. If +render+ doesn't find an # index.xml.builder or similar template, it will call +to_xml+ # on @widgets. This may or may not do something useful, but you can # see how it works. # # 3. A browser request for /widgets # This time the URL doesn't say what format is being requested, so # we'll look to the HTTP Accept: header. If it's '*/*' (anything), # we'll use the first format on our list, :html by default. # # If it parses to a list of accepted formats, we'll look through # them, in order, until we find one we have available. If we find # one, we'll use that. Otherwise, we can't fulfill the request: # they asked for a format we don't have. So we raise # 406: Not Acceptable. # # == A more complex example # # Sometimes you don't have the same code to handle each available # format. Sometimes you need to load different data to serve # /widgets.xml versus /widgets.txt. In that case, you can use # +content_type+ to determine what format will be delivered. # # class Widgets < Application # def action1 # if content_type == :text # Widget.load_text_formatted(params[:id]) # else # render # end # end # # def action2 # case content_type # when :html # handle_html() # when :xml # handle_xml() # when :text # handle_text() # else # render # end # end # end # # You can do any standard Ruby flow control using +content_type+. If # you don't call it yourself, it will be called (triggering content # negotiation) by +render+. # # Once +content_type+ has been called, the output format is frozen, # and none of the provides methods can be used. module ResponderMixin TYPES = Dictionary.new MIMES = {} MIME_MUTEX = Mutex.new ACCEPT_RESULTS = {} class ContentTypeAlreadySet < StandardError; end # ==== Parameters # base:: The module that ResponderMixin was mixed into # # :api: private def self.included(base) base.extend(ClassMethods) base.class_eval do class_inheritable_accessor :class_provided_formats self.class_provided_formats = [] end base.reset_provides end module ClassMethods # Adds symbols representing formats to the controller's default list of # provided_formats. These will apply to every action in the controller, # unless modified in the action. If the last argument is a Hash or an # Array, these are regarded as arguments to pass to the to_ # method as needed. # # ==== Parameters # *formats:: # A list of mime-types that the controller should provide. # # ==== Returns # Array[Symbol]:: List of formats passed in. # # ==== Examples # provides :html, :xml # # :api: public def provides(*formats) self.class_provided_formats |= formats end # This class should only provide the formats listed here, despite any # other definitions previously or in superclasses. # # ==== Parameters # *formats:: Registered mime-types. # # ==== Returns # Array[Symbol]:: List of formats passed in. # # :api: public def only_provides(*formats) clear_provides provides(*formats) end # This class should not provide any of this list of formats, despite any. # other definitions previously or in superclasses. # # ==== Parameters # *formats:: Registered mime-types. # # ==== Returns # Array[Symbol]:: # List of formats that remain after removing the ones not to provide. # # :api: public def does_not_provide(*formats) self.class_provided_formats -= formats end # Clear the list of provides. # # ==== Returns # Array:: An empty Array. # # :api: public def clear_provides self.class_provided_formats.clear end # Reset the list of provides to include only :html. # # ==== Returns # Array[Symbol]:: [:html]. # # :api: public def reset_provides only_provides(:html) end end # ==== Returns # Array[Symbol]:: # The current list of formats provided for this instance of the # controller. It starts with what has been set in the controller (or # :html by default) but can be modifed on a per-action basis. # # :api: private def _provided_formats @_provided_formats ||= class_provided_formats.dup end # Adds formats to the list of provided formats for this particular request. # Usually used to add formats to a single action. See also the # controller-level provides that affects all actions in a controller. # # ==== Parameters # *formats:: # A list of formats to add to the per-action list of provided formats. # # ==== Raises # Merb::ResponderMixin::ContentTypeAlreadySet:: # Content negotiation already occured, and the content_type is set. # # ==== Returns # Array[Symbol]:: List of formats passed in. # # :api: public def provides(*formats) if @_content_type raise ContentTypeAlreadySet, "Cannot modify provided_formats because content_type has already been set" end @_provided_formats = self._provided_formats | formats # merges with class_provided_formats if not already end # Sets list of provided formats for this particular request. Usually used # to limit formats to a single action. See also the controller-level # only_provides that affects all actions in a controller. # # ==== Parameters # *formats:: # A list of formats to use as the per-action list of provided formats. # # ==== Returns # Array[Symbol]:: List of formats passed in. # # :api: public def only_provides(*formats) @_provided_formats = [] provides(*formats) end # Removes formats from the list of provided formats for this particular # request. Usually used to remove formats from a single action. See # also the controller-level does_not_provide that affects all actions in a # controller. # # ==== Parameters # *formats:: Registered mime-type # # ==== Returns # Array[Symbol]:: # List of formats that remain after removing the ones not to provide. # # :api: public def does_not_provide(*formats) @_provided_formats -= formats.flatten end def _accept_types accept = request.accept MIME_MUTEX.synchronize do return ACCEPT_RESULTS[accept] if ACCEPT_RESULTS[accept] end types = request.accept.split(Merb::Const::ACCEPT_SPLIT).map do |entry| entry =~ Merb::Const::MEDIA_RANGE media_range, quality = $1, $3 kind, sub_type = media_range.split(Merb::Const::SLASH_SPLIT) mime_sym = Merb.available_accepts[media_range] mime = Merb.available_mime_types[mime_sym] (quality ||= 0.0) if media_range == "*/*" quality = quality ? (quality.to_f * 100).to_i : 100 quality *= (mime && mime[:default_quality] || 1) [quality, mime_sym, media_range, kind, sub_type, mime] end accepts = types.sort_by {|x| x.first }.reverse!.map! {|x| x[1]} MIME_MUTEX.synchronize do ACCEPT_RESULTS[accept] = accepts.freeze end accepts end # Do the content negotiation: # 1. if params[:format] is there, and provided, use it # 2. Parse the Accept header # 3. If it's */*, use the first provided format # 4. Look for one that is provided, in order of request # 5. Raise 406 if none found # # :api: private def _perform_content_negotiation if fmt = params[:format] and !fmt.blank? accepts = [fmt.to_sym] else accepts = _accept_types end provided_formats = _provided_formats specifics = accepts & provided_formats return specifics.first unless specifics.length == 0 return provided_formats.first if accepts.include?(:all) && !provided_formats.empty? message = "A format (%s) that isn't provided (%s) has been requested. " message += "Make sure the action provides the format, and be " message += "careful of before filters which won't recognize " message += "formats provided within actions." raise Merb::ControllerExceptions::NotAcceptable, (message % [accepts.join(', '), provided_formats.join(', ')]) end # Returns the output format for this request, based on the # provided formats, params[:format] and the client's HTTP # Accept header. # # The first time this is called, it triggers content negotiation # and caches the value. Once you call +content_type+ you can # not set or change the list of provided formats. # # Called automatically by +render+, so you should only call it if # you need the value, not to trigger content negotiation. # # ==== Parameters # fmt:: # An optional format to use instead of performing content negotiation. # This can be used to pass in the values of opts[:format] from the # render function to short-circuit content-negotiation when it's not # necessary. This optional parameter should not be considered part # of the public API. # # ==== Returns # Symbol:: The content-type that will be used for this controller. # # :api: public def content_type(fmt = nil) self.content_type = (fmt || _perform_content_negotiation) unless @_content_type @_content_type end # Sets the content type of the current response to a value based on # a passed in key. The Content-Type header will be set to the first # registered header for the mime-type. # # ==== Parameters # type:: The content type. # # ==== Raises # ArgumentError:: type is not in the list of registered mime-types. # # ==== Returns # Symbol:: The content-type that was passed in. # # :api: plugin def content_type=(type) unless Merb.available_mime_types.has_key?(type) raise Merb::ControllerExceptions::NotAcceptable.new("Unknown content_type for response: #{type}") end @_content_type = type mime = Merb.available_mime_types[type] headers["Content-Type"] = mime[:content_type] # merge any format specific response headers mime[:response_headers].each { |k,v| headers[k] ||= v } # if given, use a block to finetune any runtime headers mime[:response_block].call(self) if mime[:response_block] @_content_type end end class Responder # Parses the raw accept header into an array of sorted AcceptType objects. # # ==== Parameters # accept_header<~to_s>:: The raw accept header. # # ==== Returns # Array[AcceptType]:: The accepted types. # # @private def self.parse(accept_header) headers = accept_header.split(/,/) idx, list = 0, [] while idx < headers.size list << AcceptType.new(headers[idx], idx) idx += 1 end list.sort end end class AcceptType attr_reader :media_range, :quality, :index, :type, :sub_type # ==== Parameters # entry:: The accept type pattern # index:: # The index used for sorting accept types. A lower value indicates higher # priority. # # :api: private def initialize(entry,index) @index = index entry =~ /\s*([^;\s]*)\s*(;\s*q=\s*(.*))?/ @media_range, quality = $1, $3 @type, @sub_type = @media_range.split(%r{/}) (quality ||= 0.0) if @media_range == "*/*" @quality = quality ? (quality.to_f * 100).to_i : 100 @quality *= (mime && mime[:default_quality] || 1) end # Compares two accept types for sorting purposes. # # ==== Parameters # entry:: The accept type to compare. # # ==== Returns # Fixnum:: # -1, 0 or 1, depending on whether entry has a lower, equal or higher # priority than the accept type being compared. # # :api: private def <=>(entry) if entry.quality == quality @index <=> entry.index else entry.quality <=> @quality end end # ==== Parameters # entry:: The accept type to compare. # # ==== Returns # Boolean:: # True if the accept types are equal, i.e. if the synonyms for this # accept type includes the entry media range. # # :api: private def eql?(entry) synonyms.include?(entry.media_range) end # An alias for eql?. # # :api: private def ==(entry); eql?(entry); end # ==== Returns # Fixnum:: A hash based on the super range. # # :api: private def hash; super_range.hash; end # ==== Returns # Array[String]:: # All Accept header values, such as "text/html", that match this type. # # :api: private def synonyms return @syns if @syns if _mime = mime @syns = _mime[:accepts] else @syns = [] end end # :api: private def mime @mime ||= Merb.available_mime_types[Merb::ResponderMixin::MIMES[@media_range]] end # ==== Returns # String:: # The primary media range for this accept type, i.e. either the first # synonym or, if none exist, the media range. # # :api: private def super_range synonyms.first || @media_range end # ==== Returns # Symbol: The type as a symbol, e.g. :html. # # :api: private def to_sym Merb.available_mime_types.select{|k,v| v[:accepts] == synonyms || v[:accepts][0] == synonyms[0]}.flatten.first end # ==== Returns # String:: The accept type as a string, i.e. the media range. # # :api: private def to_s @media_range end end end ruby-merb-core_1.1.3.orig/lib/merb-core/controller/template.rb000066400000000000000000000222101175250300200243230ustar00rootroot00000000000000module Merb::InlineTemplates end module Merb::Template EXTENSIONS = {} unless defined?(EXTENSIONS) METHOD_LIST = {} unless defined?(METHOD_LIST) SUPPORTED_LOCALS_LIST = Hash.new([].freeze) unless defined?(SUPPORTED_LOCALS_LIST) MTIMES = {} unless defined?(MTIMES) class << self # Get the template's method name from a full path. This replaces # non-alphanumeric characters with __ and "." with "_" # # Collisions are potentially possible with something like: # ~foo.bar and __foo.bar or !foo.bar. # # ==== Parameters # path:: A full path to convert to a valid Ruby method name # # ==== Returns # String:: The template name. # # # We might want to replace this with something that varies the # character replaced based on the non-alphanumeric character # to avoid edge-case collisions. # # :api: private def template_name(path) path = File.expand_path(path) path.gsub(/[^\.a-zA-Z0-9]/, "__").gsub(/\./, "_") end chainable do # For a given path, get an IO object that responds to #path. # # This is so that plugins can override this if they provide # mechanisms for specifying templates that are not just simple # files. The plugin is responsible for ensuring that the fake # path provided will work with #template_for, and thus the # RenderMixin in general. # # ==== Parameters # path:: A full path to find a template for. This is the # path that the RenderMixin assumes it should find the template # in. # # ==== Returns # IO#path:: An IO object that responds to path (File or VirtualFile). # # :api: plugin # @overridable def load_template_io(path) file = Dir["#{path}.{#{template_extensions.join(',')}}"].first File.open(file, "r") if file end end # Get the name of the template method for a particular path. # # ==== Parameters # path:: A full path to find a template method for. # template_stack:: The template stack. Not used. # locals:: The names of local variables # # ==== Returns # :: name of the method that inlines the template. # # :api: private def template_for(path, template_stack = [], locals=[]) path = File.expand_path(path) if needs_compilation?(path, locals) template_io = load_template_io(path) METHOD_LIST[path] = inline_template(template_io, locals) if template_io end METHOD_LIST[path] end # Decide if a template needs to be re/compiled. # # ==== Parameters # path:: The full path of the template to check support for. # locals:: The list of locals that need to be supported # # ==== Returns # Boolean:: Whether or not the template for the provided path needs to be recompiled # # :api: private def needs_compilation?(path, locals) return true if Merb::Config[:reload_templates] || !METHOD_LIST[path] current_locals = SUPPORTED_LOCALS_LIST[path] current_locals != locals && !(locals - current_locals).empty? end # Get all known template extensions # # ==== Returns # Array:: Extension strings. # # :api: plugin def template_extensions EXTENSIONS.keys end # Takes a template at a particular path and inlines it into a module and # adds it to the METHOD_LIST table to speed lookup later. # # ==== Parameters # io<#path>:: # An IO that responds to #path (File or VirtualFile) # locals:: # A list of local names that should be assigned in the template method # from the arguments hash. Defaults to []. # mod:: # The module to put the compiled method into. Defaults to # Merb::InlineTemplates # # ==== Returns # Symbol:: The name of the method that the template was compiled into. # # ==== Notes # Even though this method supports inlining into any module, the method # must be available to instances of AbstractController that will use it. # # :api: private def inline_template(io, locals=[], mod = Merb::InlineTemplates) full_file_path = File.expand_path(io.path) engine_neutral_path = full_file_path.gsub(/\.[^\.]*$/, "") local_list = (SUPPORTED_LOCALS_LIST[engine_neutral_path] |= locals) ret = METHOD_LIST[engine_neutral_path] = engine_for(full_file_path).compile_template(io, template_name(full_file_path), local_list, mod) io.close ret end # Finds the engine for a particular path. # # ==== Parameters # path:: The path of the file to find an engine for. # # ==== Returns # Class:: The engine. # # :api: private def engine_for(path) path = File.expand_path(path) EXTENSIONS[path.match(/\.([^\.]*)$/)[1]] end # Registers the extensions that will trigger a particular templating # engine. # # ==== Parameters # engine:: The class of the engine that is being registered # extensions:: # The list of extensions that will be registered with this templating # language # # ==== Raises # ArgumentError:: engine does not have a compile_template method. # # ==== Returns # nil # # ==== Example # Merb::Template.register_extensions(Merb::Template::Erubis, ["erb"]) # # :api: plugin def register_extensions(engine, extensions) raise ArgumentError, "The class you are registering does not have a compile_template method" unless engine.respond_to?(:compile_template) extensions.each{|ext| EXTENSIONS[ext] = engine } Merb::AbstractController.class_eval <<-HERE include #{engine}::Mixin HERE end end require 'erubis' class Erubis # Fixing bug in Erubis # http://rubyforge.org/tracker/index.php?func=detail&aid=21825&group_id=1320&atid=5201 XmlHelper = ::Erubis::XmlHelper # ==== Parameters # io<#path>:: An IO containing the full path of the template. # name:: The name of the method that will be created. # locals:: A list of locals to assign from the args passed into the compiled template. # mod:: The module that the compiled method will be placed into. # # :api: private def self.compile_template(io, name, locals, mod) template = ::Erubis::BlockAwareEruby.new(io.read) _old_verbose, $VERBOSE = $VERBOSE, nil assigns = locals.inject([]) do |assigns, local| assigns << "#{local} = _locals[#{local.inspect}]" end.join(";") code = "def #{name}(_locals={}); #{assigns}; #{template.src}; end" mod.module_eval code, File.expand_path(io.path) $VERBOSE = _old_verbose name end module Mixin # ==== Parameters # *args:: Arguments to pass to the block. # &block:: The template block to call. # # ==== Returns # String:: The output of the block. # # ==== Examples # Capture being used in a .html.erb page: # # <% @foo = capture do %> #

Some Foo content!

# <% end %> # # :api: private def capture_erb(*args, &block) _old_buf, @_erb_buf = @_erb_buf, "" block.call(*args) ret = @_erb_buf @_erb_buf = _old_buf ret end # :api: private def concat_erb(string, binding) @_erb_buf << string end end Merb::Template.register_extensions(self, %w[erb]) end end module Erubis module BlockAwareEnhancer # :api: private def add_preamble(src) src << "_old_buf, @_erb_buf = @_erb_buf, ''; " src << "@_engine = 'erb'; " end # :api: private def add_postamble(src) src << "\n" unless src[-1] == ?\n src << "_ret = @_erb_buf; @_erb_buf = _old_buf; _ret.to_s;\n" end # :api: private def add_text(src, text) src << " @_erb_buf.concat('" << escape_text(text) << "'); " end # :api: private def add_expr_escaped(src, code) src << ' @_erb_buf.concat(' << escaped_expr(code) << ');' end # :api: private def add_stmt2(src, code, tailch) src << code src << ") ).to_s; " if tailch == "=" src << ';' unless code[-1] == ?\n end # :api: private def add_expr_literal(src, code) if code =~ /(do|\{)(\s*\|[^|]*\|)?\s*\Z/ src << ' @_erb_buf.concat( (' << code << "; " else src << ' @_erb_buf.concat((' << code << ').to_s);' end end end class BlockAwareEruby < Eruby include BlockAwareEnhancer end # module RubyEvaluator # # # DOC # def def_method(object, method_name, filename=nil) # m = object.is_a?(Module) ? :module_eval : :instance_eval # setup = "@_engine = 'erb'" # object.__send__(m, "def #{method_name}(locals={}); #{setup}; #{@src}; end", filename || @filename || '(erubis)') # end # # end end ruby-merb-core_1.1.3.orig/lib/merb-core/core_ext.rb000066400000000000000000000006171175250300200221440ustar00rootroot00000000000000begin require "extlib" rescue LoadError => e puts "Merb-core 0.9.4 and later uses extlib for Ruby core class extensions. Install it from github.com/datamapper/extlib." exit end require File.dirname(__FILE__) / "core_ext" / "kernel" require File.dirname(__FILE__) / "core_ext" / "hash" require File.dirname(__FILE__) / "core_ext" / "class" require File.dirname(__FILE__) / "core_ext" / "time" ruby-merb-core_1.1.3.orig/lib/merb-core/core_ext/000077500000000000000000000000001175250300200216135ustar00rootroot00000000000000ruby-merb-core_1.1.3.orig/lib/merb-core/core_ext/class.rb000066400000000000000000000012251175250300200232450ustar00rootroot00000000000000class Class # Allows the definition of methods on a class that will be available via # super. # # ==== Examples # class Foo # chainable do # def hello # "hello" # end # end # end # # class Foo # def hello # super + " Merb!" # end # end # # Foo.new.hello #=> "hello Merb!" # # ==== Parameters # &blk:: # a block containing method definitions that should be # marked as chainable # # ==== Returns # Module:: The anonymous module that was created def chainable(&blk) mod = Module.new(&blk) include mod mod end endruby-merb-core_1.1.3.orig/lib/merb-core/core_ext/hash.rb000066400000000000000000000006011175250300200230600ustar00rootroot00000000000000class Hash # Returns the value of self for each argument and deletes those entries. # # ==== Parameters # *args:: the keys whose values should be extracted and deleted. # # ==== Returns # Array[Object]:: The values of the provided arguments in corresponding order. # # :api: public def extract!(*args) args.map do |arg| self.delete(arg) end end end ruby-merb-core_1.1.3.orig/lib/merb-core/core_ext/kernel.rb000066400000000000000000000163271175250300200234310ustar00rootroot00000000000000module Kernel # Loads the given string as a gem. # # :api: public # @deprecated def dependency(name, *opts, &blk) warn "DEPRECATED: Use bundler to setup and load dependency #{name}." options = opts.last.is_a?(Hash) ? opts.pop : {} version = opts.pop unless opts.empty? if version warn "DEPRECATED: You want to load gem #{name} with specific version " \ "#{version}. This feature is not supported and the LATEST VERSION " \ "OF THE GEM WILL BE LOADED." end require (options[:require_as] ? options[:require_as] : name) nil end # Loads both gem and library dependencies that are passed in as arguments. # # :api: public # @deprecated def dependencies(*args) args.map do |arg| case arg when String then dependency(arg) when Hash then arg.map { |r,v| dependency(r, v) } when Array then arg.map { |r| dependency(r) } end end nil end # Used in Merb.root/config/init.rb to tell Merb which ORM (Object Relational # Mapper) you wish to use. Currently Merb has plugins to support # ActiveRecord, DataMapper, and Sequel. # # ==== Parameters # orm:: The ORM to use. # # ==== Returns # nil # # ==== Example # use_orm :datamapper # # # This will use the DataMapper generator for your ORM # $ merb-gen model ActivityEvent # # ==== Notes # If for some reason this is called more than once, latter # call takes over other. # # :api: public def use_orm(orm) Merb.orm = orm nil end # Used in Merb.root/config/init.rb to tell Merb which testing framework to # use. Currently Merb has plugins to support RSpec and Test::Unit. # # ==== Parameters # test_framework:: # The test framework to use. Currently only supports :rspec and :test_unit. # # ==== Returns # nil # # ==== Example # use_test :rspec # # # This will now use the RSpec generator for tests # $ merb-gen model ActivityEvent # # :api: public def use_testing_framework(test_framework) Merb.test_framework = test_framework nil end def use_test(*args) use_testing_framework(*args) end # Used in Merb.root/config/init.rb to tell Merb which template engine to # prefer. # # ==== Parameters # template_engine # The template engine to use. # # ==== Returns # nil # # ==== Example # use_template_engine :haml # # # This will now use haml templates in generators where available. # $ merb-gen resource_controller Project # # :api: public def use_template_engine(template_engine) Merb.template_engine = template_engine nil end # @param i The caller number. Defaults to 1. # # @return The file, line and method of the caller. # # @example # __caller_info__(1) # # => ['/usr/lib/ruby/1.8/irb/workspace.rb', '52', 'irb_binding'] # # :api: private def __caller_info__(i = 1) file, line, meth = caller[i].scan(/(.*?):(\d+):in `(.*?)'/).first end # @param file The file to read. # @param line The line number to look for. # @param size # Number of lines to include above and below the the line to look for. # Defaults to 4. # # @return # Triplets containing the line number, the line and whether this was the # searched line. # # @example # __caller_lines__('/usr/lib/ruby/1.8/debug.rb', 122, 2) # => # [ # [ 120, " def check_suspend", false ], # [ 121, " return if Thread.critical", false ], # [ 122, " while (Thread.critical = true; @suspend_next)", true ], # [ 123, " DEBUGGER__.waiting.push Thread.current", false ], # [ 124, " @suspend_next = false", false ] # ] # # :api: private def __caller_lines__(file, line, size = 4) line = line.to_i if file =~ /\(erubis\)/ yield :error, "Template Error! Problem while rendering", false elsif !File.file?(file) || !File.readable?(file) yield :error, "File `#{file}' not available", false else lines = File.read(file).split("\n") first_line = (f = line - size - 1) < 0 ? 0 : f if first_line.zero? new_size = line - 1 lines = lines[first_line, size + new_size + 1] else new_size = nil lines = lines[first_line, size * 2 + 1] end lines && lines.each_with_index do |str, index| line_n = index + line line_n = (new_size.nil?) ? line_n - size : line_n - new_size yield line_n, str.chomp end end end # Takes a block, profiles the results of running the block # specified number of times and generates HTML report. # # @param name<#to_s> # The file name. The result will be written out to # Merb.root/"log/#{name}.html". # @param min # Minimum percentage of the total time a method must take for it to be # included in the result. Defaults to 1. # # @return # The result of the profiling. # # @note # Requires ruby-prof (sudo gem install ruby-prof) # # @example # __profile__("MyProfile", 5, 30) do # rand(10)**rand(10) # puts "Profile run" # end # # Assuming that the total time taken for #puts calls was less than 5% of the # total time to run, #puts won't appear in the profile report. # The code block will be run 30 times in the example above. # # :api: private def __profile__(name, min=1, iter=100) require 'ruby-prof' unless defined?(RubyProf) return_result = '' result = RubyProf.profile do iter.times{return_result = yield} end printer = RubyProf::GraphHtmlPrinter.new(result) path = File.join(Merb.root, 'log', "#{name}.html") File.open(path, 'w') do |file| printer.print(file, {:min_percent => min, :print_file => true}) end return_result end # Extracts an options hash if it is the last item in the args array. Used # internally in methods that take *args. # # @param args The arguments to extract the hash from. # # @example # def render(*args,&blk) # opts = extract_options_from_args!(args) || {} # # [...] # end # # :api: public def extract_options_from_args!(args) args.pop if (args.last.instance_of?(Hash) || args.last.instance_of?(Mash)) end # Checks that the given objects quack like the given conditions. # # @param opts # Conditions to enforce. Each key will receive a quacks_like? call with the # value (see Object#quacks_like? for details). # # @raise # An object failed to quack like a condition. # # :api: public def enforce!(opts = {}) opts.each do |k,v| raise ArgumentError, "#{k.inspect} doesn't quack like #{v.inspect}" unless k.quacks_like?(v) end end unless Kernel.respond_to?(:debugger) # Define debugger method so that code even works if debugger was not # requested. Drops a note to the logs that Debugger was not available. def debugger Merb.logger.info! "\n***** Debugger requested, but was not " + "available: Start server with --debugger " + "to enable *****\n" end end end ruby-merb-core_1.1.3.orig/lib/merb-core/core_ext/time.rb000066400000000000000000000002151175250300200230740ustar00rootroot00000000000000# Declared to bypass a rubygems 1.3.2 bug :( class Time def self.today t = Time.now t - ((t.to_f + t.gmt_offset) % 86400) end endruby-merb-core_1.1.3.orig/lib/merb-core/dispatch/000077500000000000000000000000001175250300200216025ustar00rootroot00000000000000ruby-merb-core_1.1.3.orig/lib/merb-core/dispatch/cookies.rb000066400000000000000000000110701175250300200235620ustar00rootroot00000000000000module Merb class Cookies < Mash # :api: private def initialize(constructor = {}) @_options_lookup = Mash.new @_cookie_defaults = { "domain" => Merb::Controller._default_cookie_domain, "path" => '/' } super constructor end # Implicit assignment of cookie key and value. # # ==== Parameters # name<~to_s>:: Name of the cookie. # value<~to_s>:: Value of the cookie. # # ==== Notes # By using this method, a cookie key is marked for being # included in the Set-Cookie response header. # # :api: public def []=(key, value) @_options_lookup[key] ||= {} super end # Explicit assignment of cookie key, value and options # # ==== Parameters # name<~to_s>:: Name of the cookie. # value<~to_s>:: Value of the cookie. # options:: Additional options for the cookie (see below). # # ==== Options (options) # :path:: The path for which this cookie applies. Defaults to "/". # :expires