diff --git a/CHANGELOG b/CHANGELOG index 904338e0..2ae209b3 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,64 @@ +== 1.0.13 "The weekend has landed" 2009-10-30 + +* [merb_datamapper] Support for dm-0.10.x (identity map wrapping is now perforemd at the rack level) +* [merb-core] Fix run_later to work on servers other than just 'merb' (Thin or Phusion Passenger for example) +* [merb-gen] Don't add resource route to config/routes.rb when using -p or -d with merb-gen resource +* [merb-gen] Explain how to load dependencies in (very) flat apps +* [merb] Fixed failing rake install due to missing merb-more +* [merb] rake uninstall now uninstalls everything that got rake install'ed +* [merb-core] Allow testing without webrat +* [merb-haml] Fixed compilation of sass files +* [merb-helpers] Select the correct field in bound select tags + +* [merb-core] -i and --irb-console take precedence over config in init.rb. + + This change allows you to have default adapter set + in the init.rb and still if you want to run Merb in + IRB you can do it. Currently you can't because setting + adapter in init.rb override the config value from ARGV + parsing. + +* [merb-helpers] Generate valid html id attributes + + This patch changes any occurrence of '[' or ']' in id attributes to '_'. + The brackets are not valid characters in an HTML id attribute value. + +* [merb-core] Fix potential timing attack on cookie sessions + + This patch fixes a potential timing attack on the HMAC authentication + used to verify cookie session contents by ensuring a constant time + algorithm is used to compare the hashes. For more information see: + + http://codahale.com/a-lesson-in-timing-attacks/ + +* [merb-auth-slice-password] Use proper config value + + Without this change, the default password strategy + is always activated because the wrong config key is + used. + +* [merb-gen] Fixing generated thor task to work with RubyGems 1.3.5. + + Setting thor dependency to "~> 0.9.9", as newer versions will break + the default merb-gen app bundling tasks + +* [merb-core] Fixed multipart specs (including spec10) + + The previous version of the spec was wrong in expecting that + + file_params[:tempfile].should be_a_kind_of(File) + + This spec only passed because of a now resolved bug in older versions of rspec. + The correct spec for the tempfile param now reads: + + file_params[:tempfile].should be_a_kind_of(Tempfile) + +* To run merb's specsuite (rake spec or rake specs:oneoh) you will either need webrat-0.3.1 or webrat-0.4.0 + installed. webrat-0.4 is recommended for use in your app's specs, using newer versions of webrat may be + possible but is not explicitly supported. + +* Minor docfixes + == 1.0.1 * generate unique session_id_key with new apps diff --git a/LICENSE b/LICENSE index e69de29b..988298b9 100644 --- a/LICENSE +++ b/LICENSE @@ -0,0 +1,20 @@ +Copyright (c) 2008 Engine Yard + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/Rakefile b/Rakefile index ac105988..ff11e308 100644 --- a/Rakefile +++ b/Rakefile @@ -43,12 +43,11 @@ merb_release = { "merb-mailer", "merb-param-protection", "merb_datamapper", - "merb", - "merb-more" + "merb" ] } -merb_gem_paths = %w[merb merb-core merb_datamapper] + merb_more_gem_paths +merb_gem_paths = %w[merb-core merb_datamapper] + merb_more_gem_paths + %w[merb] merb_gems = merb_gem_paths.map { |p| File.basename(p) } merb_more_gems = merb_more_gem_paths.map { |p| File.basename(p) } @@ -115,11 +114,17 @@ task :install do merb_gems.each do |gem| Merb::RakeHelper.install(gem, :version => Merb::VERSION) end - puts %x{sudo gem install pkg/merb-more-#{Merb::VERSION}.gem} end desc "Uninstall all gems" -task :uninstall => ['uninstall:core', 'uninstall:more'] +task :uninstall do + merb_gems.each do |gem| + Merb::RakeHelper.uninstall(gem, :version => Merb::VERSION) + end + Merb::RakeHelper.uninstall('merb-auth-slice-password', :version => Merb::VERSION) + Merb::RakeHelper.uninstall('merb-auth-more', :version => Merb::VERSION) + Merb::RakeHelper.uninstall('merb-auth-core', :version => Merb::VERSION) +end desc "Build the merb-more gems" task :build_gems do diff --git a/merb-action-args/Rakefile b/merb-action-args/Rakefile index c2581a9f..cd155c10 100644 --- a/merb-action-args/Rakefile +++ b/merb-action-args/Rakefile @@ -31,7 +31,7 @@ spec = Gem::Specification.new do |s| s.author = AUTHOR s.email = EMAIL s.homepage = PROJECT_URL - s.add_dependency('merb-core', ">= #{Merb::VERSION}") + s.add_dependency('merb-core', "~> #{Merb::VERSION}") s.add_dependency('ruby2ruby', '>= 1.1.9') s.add_dependency('ParseTree', '>= 2.1.1') s.require_path = 'lib' diff --git a/merb-assets/Rakefile b/merb-assets/Rakefile index 77f353c6..d08d5b86 100644 --- a/merb-assets/Rakefile +++ b/merb-assets/Rakefile @@ -31,7 +31,7 @@ spec = Gem::Specification.new do |s| s.author = GEM_AUTHOR s.email = GEM_EMAIL s.homepage = PROJECT_URL - s.add_dependency('merb-core', ">= #{Merb::VERSION}") + s.add_dependency('merb-core', "~> #{Merb::VERSION}") s.require_path = 'lib' s.files = %w(LICENSE README Rakefile TODO) + Dir.glob("{lib,spec}/**/*") end diff --git a/merb-assets/spec/merb-assets_spec.rb b/merb-assets/spec/merb-assets_spec.rb index 64aab37f..91608f9e 100644 --- a/merb-assets/spec/merb-assets_spec.rb +++ b/merb-assets/spec/merb-assets_spec.rb @@ -73,8 +73,8 @@ end it "should convert objects that respond to to_json to json" do - js({'user' => 'Lewis', 'page' => 'home'}).should == - "{\"user\":\"Lewis\",\"page\":\"home\"}" + expected = {'user' => 'Lewis', 'page' => 'home'} + JSON.parse(js(expected)).should == expected end it "should convert objects using inspect that don't respond to_json to json" do diff --git a/merb-auth/merb-auth-more/lib/merb-auth-more/mixins/salted_user/dm_salted_user.rb b/merb-auth/merb-auth-more/lib/merb-auth-more/mixins/salted_user/dm_salted_user.rb index 6a222cd6..3cc6d6ea 100644 --- a/merb-auth/merb-auth-more/lib/merb-auth-more/mixins/salted_user/dm_salted_user.rb +++ b/merb-auth/merb-auth-more/lib/merb-auth-more/mixins/salted_user/dm_salted_user.rb @@ -5,8 +5,8 @@ module DMClassMethods def self.extended(base) base.class_eval do - property :crypted_password, String - property :salt, String + property :crypted_password, String, :length => 60 + property :salt, String validates_present :password, :if => proc{|m| m.password_required?} validates_is_confirmed :password, :if => proc{|m| m.password_required?} diff --git a/merb-auth/merb-auth-slice-password/lib/merb-auth-slice-password.rb b/merb-auth/merb-auth-slice-password/lib/merb-auth-slice-password.rb index 2b5f3965..5b50e7b8 100644 --- a/merb-auth/merb-auth-slice-password/lib/merb-auth-slice-password.rb +++ b/merb-auth/merb-auth-slice-password/lib/merb-auth-slice-password.rb @@ -36,7 +36,7 @@ def self.loaded # Initialization hook - runs before AfterAppLoads BootLoader def self.init require 'merb-auth-more/mixins/redirect_back' - unless MerbAuthSlicePassword[:no_default_strategies] + unless ::Merb::Slices::config[:"merb-auth-slice-password"][:no_default_strategies] ::Merb::Authentication.activate!(:default_password_form) end end diff --git a/merb-cache/Rakefile b/merb-cache/Rakefile index 1297c16d..03ca979f 100644 --- a/merb-cache/Rakefile +++ b/merb-cache/Rakefile @@ -31,7 +31,7 @@ spec = Gem::Specification.new do |s| s.author = GEM_AUTHOR s.email = GEM_EMAIL s.homepage = PROJECT_URL - s.add_dependency('merb-core', ">= #{Merb::VERSION}") + s.add_dependency('merb-core', "~> #{Merb::VERSION}") s.require_path = 'lib' s.files = %w(LICENSE README Rakefile TODO) + Dir.glob("{lib,spec}/**/*") end diff --git a/merb-cache/spec/merb-cache/stores/strategy/action_store_spec.rb b/merb-cache/spec/merb-cache/stores/strategy/action_store_spec.rb index 6443a778..2fc2d3c7 100644 --- a/merb-cache/spec/merb-cache/stores/strategy/action_store_spec.rb +++ b/merb-cache/spec/merb-cache/stores/strategy/action_store_spec.rb @@ -158,7 +158,7 @@ def ticker end it "should cache the stats action by team, start_date & end_date parameters" do - start_date, end_date = Time.today.to_s, Time.now.to_s + start_date, end_date = (Time.now - 60).to_s, Time.now.to_s dispatch_to(MLBScores, :stats, :start_date => start_date, :end_date => end_date) @dummy.data("MLBScores#stats", :team => :all, :start_date => start_date, :end_date => end_date).should == "MLBScores stats(all, #{start_date}, #{end_date})" diff --git a/merb-core/Rakefile b/merb-core/Rakefile index f8231fc1..b07d8eeb 100644 --- a/merb-core/Rakefile +++ b/merb-core/Rakefile @@ -66,7 +66,7 @@ spec = Gem::Specification.new do |s| s.add_dependency "rspec" s.add_dependency "rack" s.add_dependency "mime-types" - s.add_dependency "thor", ">= 0.9.9" + s.add_dependency "thor", "~> 0.9.9" # this escalates to "regular" dependencies, comment it out # for now. RubyGems need some love. #s.add_development_dependency "libxml-ruby" @@ -352,7 +352,7 @@ def contributors(since_release = nil) git_log(since_release).split("\n").uniq.sort end -PREVIOUS_RELEASE = '0.9.9' +PREVIOUS_RELEASE = '0.9.10' namespace :history do namespace :update do desc "updates contributors list" diff --git a/merb-core/lib/merb-core.rb b/merb-core/lib/merb-core.rb index 164592bd..4c20831f 100644 --- a/merb-core/lib/merb-core.rb +++ b/merb-core/lib/merb-core.rb @@ -154,6 +154,9 @@ def start(argv = ARGV) 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] @@ -786,6 +789,11 @@ def on_windows? def run_later(&blk) Merb::Dispatcher.work_queue << blk end + + # :api: private + def running_irb? + @running_irb + end end end diff --git a/merb-core/lib/merb-core/bootloader.rb b/merb-core/lib/merb-core/bootloader.rb index 36dda680..13e235e4 100644 --- a/merb-core/lib/merb-core/bootloader.rb +++ b/merb-core/lib/merb-core/bootloader.rb @@ -418,6 +418,7 @@ def self.enable_json_gem rescue LoadError gem "json_pure" require "json/pure" + require "merb-core/core_ext/json_pure_fix" end # Resets the logger and sets the log_stream to Merb::Config[:log_file] @@ -1268,6 +1269,8 @@ class Merb::BootLoader::ChooseAdapter < Merb::BootLoader # # :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 @@ -1306,6 +1309,19 @@ def self.run 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 diff --git a/merb-core/lib/merb-core/config.rb b/merb-core/lib/merb-core/config.rb index a94e3a6b..de3ed8e5 100644 --- a/merb-core/lib/merb-core/config.rb +++ b/merb-core/lib/merb-core/config.rb @@ -151,6 +151,10 @@ def to_yaml # # :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] diff --git a/merb-core/lib/merb-core/constants.rb b/merb-core/lib/merb-core/constants.rb index 463ce5d9..168c98a2 100644 --- a/merb-core/lib/merb-core/constants.rb +++ b/merb-core/lib/merb-core/constants.rb @@ -38,7 +38,7 @@ module Const 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)\./i.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 diff --git a/merb-core/lib/merb-core/core_ext.rb b/merb-core/lib/merb-core/core_ext.rb index 75957307..e3581547 100644 --- a/merb-core/lib/merb-core/core_ext.rb +++ b/merb-core/lib/merb-core/core_ext.rb @@ -1,7 +1,7 @@ begin 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/sam/extlib." + puts "Merb-core 0.9.4 and later uses extlib for Ruby core class extensions. Install it from github.com/datamapper/extlib." exit end diff --git a/merb-core/lib/merb-core/core_ext/json_pure_fix.rb b/merb-core/lib/merb-core/core_ext/json_pure_fix.rb new file mode 100644 index 00000000..ea6969bc --- /dev/null +++ b/merb-core/lib/merb-core/core_ext/json_pure_fix.rb @@ -0,0 +1,14 @@ +if defined?(JSON::Pure::Parser::STRING) + class JSON::Pure::Parser + if JSON::Pure::Parser::STRING.source.include?('\\[\x20-\xff]') + remove_const(:STRING) + STRING = /" ((?:[^\x0-\x1f"\\] | + \\["\\\/bfnrt] | + \\u[0-9a-fA-F]{4} | + \\[\x20-\x21\x23-\x2e\x30-\x5b\x5d-\x61\x63-\x65\x67-\x6d\x6f-\x71\x73\x75-\xff])*) + "/nx + warn("You are running an outdated an vulnerable version of JSON::Pure. Merb has fixed the vulnerability, but " \ + "you should upgrade to the latest version of JSON::Pure or use the json gem") + end + end +end \ No newline at end of file diff --git a/merb-core/lib/merb-core/core_ext/kernel.rb b/merb-core/lib/merb-core/core_ext/kernel.rb index a964868f..7c606898 100644 --- a/merb-core/lib/merb-core/core_ext/kernel.rb +++ b/merb-core/lib/merb-core/core_ext/kernel.rb @@ -436,7 +436,7 @@ def __profile__(name, min=1, iter=100) # # :api: public def extract_options_from_args!(args) - args.pop if Hash === args.last + args.pop if (args.last.instance_of?(Hash) || args.last.instance_of?(Mash)) end # Checks that the given objects quack like the given conditions. diff --git a/merb-core/lib/merb-core/dispatch/router/behavior.rb b/merb-core/lib/merb-core/dispatch/router/behavior.rb index 4b7b6a54..33113053 100644 --- a/merb-core/lib/merb-core/dispatch/router/behavior.rb +++ b/merb-core/lib/merb-core/dispatch/router/behavior.rb @@ -303,7 +303,7 @@ def match(path = {}, conditions = {}, &block) # r:: +optional+ - The to behavior object. # # ==== Returns - # Route:: It registers a new route and returns it. + # Behavior:: The route definition behavior defining the created route # # ==== Examples # match('/:controller/:id).to(:action => 'show') diff --git a/merb-core/lib/merb-core/dispatch/router/route.rb b/merb-core/lib/merb-core/dispatch/router/route.rb index 4b84ec43..ca309b2c 100644 --- a/merb-core/lib/merb-core/dispatch/router/route.rb +++ b/merb-core/lib/merb-core/dispatch/router/route.rb @@ -183,7 +183,7 @@ def identify(obj, param_key = nil) def identifier_for(obj) return if obj.is_a?(String) || obj.is_a?(Symbol) || obj.is_a?(Numeric) || obj.is_a?(TrueClass) || obj.is_a?(FalseClass) || obj.is_a?(NilClass) || - obj.is_a?(Array) || obj.is_a?(Hash) + obj.is_a?(Array) || obj.instance_of?(Hash) @identifiers.each do |klass, identifier| return identifier if obj.is_a?(klass) diff --git a/merb-core/lib/merb-core/dispatch/session/cookie.rb b/merb-core/lib/merb-core/dispatch/session/cookie.rb index 7db4f6f7..85797733 100644 --- a/merb-core/lib/merb-core/dispatch/session/cookie.rb +++ b/merb-core/lib/merb-core/dispatch/session/cookie.rb @@ -148,6 +148,36 @@ def to_cookie def generate_digest(data) OpenSSL::HMAC.hexdigest(DIGEST, @secret, data) end + + # Securely compare two digests using a constant time algorithm. + # This avoids leaking information about the calculated HMAC + # + # Based on code by Michael Koziarski + # http://github.com/rails/rails/commit/674f780d59a5a7ec0301755d43a7b277a3ad2978 + # + # ==== Parameters + # a, b<~to_s>:: digests to compare. + # + # ==== Returns + # Boolean:: Do the digests validate? + def secure_compare(a, b) + if a.length == b.length + + # unpack to forty characters. + # needed for 1.8 and 1.9 compat + a_bytes = a.unpack('C*') + b_bytes = b.unpack('C*') + + result = 0 + for i in 0..(a_bytes.length - 1) + result |= a_bytes[i] ^ b_bytes[i] + end + result == 0 + else + false + end + end + # Unmarshal cookie data to a hash and verify its integrity. # @@ -167,7 +197,7 @@ def unmarshal(cookie) else data, digest = Merb::Parse.unescape(cookie).split('--') return {} if data.blank? || digest.blank? - unless digest == generate_digest(data) + unless secure_compare(generate_digest(data), digest) clear unless Merb::Config[:ignore_tampered_cookies] raise TamperedWithCookie, "Maybe the site's session_secret_key has changed?" diff --git a/merb-core/lib/merb-core/dispatch/worker.rb b/merb-core/lib/merb-core/dispatch/worker.rb index 82be684e..f972d888 100644 --- a/merb-core/lib/merb-core/dispatch/worker.rb +++ b/merb-core/lib/merb-core/dispatch/worker.rb @@ -21,6 +21,14 @@ def start end @worker end + + # ==== Returns + # Whether the Merb::Worker instance is already started. + # + # :api: private + def started? + !@worker.nil? + end end # Creates a new worker thread that loops over the work queue. diff --git a/merb-core/lib/merb-core/logger.rb b/merb-core/lib/merb-core/logger.rb index 8e6afaca..160b6cdb 100755 --- a/merb-core/lib/merb-core/logger.rb +++ b/merb-core/lib/merb-core/logger.rb @@ -16,7 +16,9 @@ def verbose(message, level = :warn) # ==== Public Merb Logger API # # To replace an existing logger with a new one: -# Merb::Logger.set_log(log{String, IO},level{Symbol, String}) +# Merb.logger.set_log(log{String, IO},level{Symbol, String}) +# for example: +# Merb.logger.set_log($stdout, Merb::Logger::Levels[:fatal]) # # Available logging levels are # Merb::Logger::{ Fatal, Error, Warn, Info, Debug } diff --git a/merb-core/lib/merb-core/rack/adapter/abstract.rb b/merb-core/lib/merb-core/rack/adapter/abstract.rb index cf9f0513..fd0849db 100644 --- a/merb-core/lib/merb-core/rack/adapter/abstract.rb +++ b/merb-core/lib/merb-core/rack/adapter/abstract.rb @@ -152,12 +152,14 @@ def self.start(opts={}) pid, status = @pids[port + i], nil poller = Merb::System::PortablePoller.new(pid) begin + tick = 1 loop do # Watch for the pid to exit. _, status = Process.wait2(pid, Process::WNOHANG) break if status - if Merb::Config[:max_memory] && poller.memory > Merb::Config[:max_memory] + if (tick % 120 == 0) && Merb::Config[:max_memory] && poller.memory > Merb::Config[:max_memory] + tick = 1 Process.kill("INT", pid) if (Process.kill(0, pid) rescue false) sleep Merb::Config[:hang_time] || 5 @@ -168,6 +170,7 @@ def self.start(opts={}) status = Struct.new(:exitstatus).new(nil) break end + tick += 1 sleep 0.25 end @@ -214,8 +217,6 @@ def self.start_at_port(port, opts = @opts) Merb::Server.remove_pid(port) end - Merb::Worker.start unless Merb.testing? - # If Merb is daemonized, trap INT. If it's not daemonized, # we let the master process' ctrl-c control the cluster # of workers. diff --git a/merb-core/lib/merb-core/test/matchers.rb b/merb-core/lib/merb-core/test/matchers.rb index 89525b44..4ba757ec 100644 --- a/merb-core/lib/merb-core/test/matchers.rb +++ b/merb-core/lib/merb-core/test/matchers.rb @@ -7,8 +7,8 @@ module Merb::Test::Rspec; end Merb::Test::ControllerHelper.send(:include, Merb::Test::Rspec::ControllerMatchers) Merb::Test::RouteHelper.send(:include, Merb::Test::Rspec::RouteMatchers) -if defined?(::Webrat) - module Merb::Test::ViewHelper +module Merb::Test::ViewHelper + if defined?(::Webrat) include ::Webrat::Matchers include ::Webrat::HaveTagMatcher end diff --git a/merb-core/lib/merb-core/test/run_specs.rb b/merb-core/lib/merb-core/test/run_specs.rb index 18906b7e..3f1a91d6 100644 --- a/merb-core/lib/merb-core/test/run_specs.rb +++ b/merb-core/lib/merb-core/test/run_specs.rb @@ -14,12 +14,6 @@ require 'rack' require 'fileutils' -begin - require 'json' -rescue - require 'json/pure' -end - Merb::Dispatcher module Merb diff --git a/merb-core/lib/merb-core/version.rb b/merb-core/lib/merb-core/version.rb index 2d2e2219..57cce86c 100644 --- a/merb-core/lib/merb-core/version.rb +++ b/merb-core/lib/merb-core/version.rb @@ -1,5 +1,5 @@ module Merb - VERSION = '1.0.9' unless defined?(Merb::VERSION) - DM_VERSION = '0.9.10' unless defined?(Merb::DM_VERSION) - DO_VERSION = '0.9.11' unless defined?(Merb::DO_VERSION) + VERSION = '1.0.13' unless defined?(Merb::VERSION) + DM_VERSION = '0.10' unless defined?(Merb::DM_VERSION) + DO_VERSION = '0.10' unless defined?(Merb::DO_VERSION) end diff --git a/merb-core/spec/private/core_ext/kernel_spec.rb b/merb-core/spec/private/core_ext/kernel_spec.rb index eda37b3f..6bfbdd25 100644 --- a/merb-core/spec/private/core_ext/kernel_spec.rb +++ b/merb-core/spec/private/core_ext/kernel_spec.rb @@ -23,18 +23,6 @@ end - -describe "Kernel#debugger" do - it "should throw a useful error if there's no debugger" do - Merb.logger.should_receive(:info!).with "\n***** Debugger requested, but was not " + - "available: Start server with --debugger " + - "to enable *****\n" - Kernel.debugger - end -end - - - describe "Kernel#dependencies" do it "deferres load of dependencies given as String" do self.should_receive(:dependency).with("hpricot").and_return(true) diff --git a/merb-core/spec/public/boot_loader/boot_loader_spec.rb b/merb-core/spec/public/boot_loader/boot_loader_spec.rb index 78d06727..aea22285 100644 --- a/merb-core/spec/public/boot_loader/boot_loader_spec.rb +++ b/merb-core/spec/public/boot_loader/boot_loader_spec.rb @@ -31,4 +31,11 @@ def self.run Merb::BootLoader.subclasses.index("Merb::BootLoader::BeforeTest").should == idx - 1 end -end \ No newline at end of file + describe Merb::BootLoader::ChooseAdapter do + it "should check if we're running irb and if so set irb as adapter" do + Merb.stub!(:running_irb?).and_return(true) + Merb::BootLoader::ChooseAdapter.run + Merb::Config[:adapter].should eql 'irb' + end + end +end diff --git a/merb-core/spec/public/core/merb_core_spec.rb b/merb-core/spec/public/core/merb_core_spec.rb index 0045bcdf..2c6660ce 100644 --- a/merb-core/spec/public/core/merb_core_spec.rb +++ b/merb-core/spec/public/core/merb_core_spec.rb @@ -1,46 +1,62 @@ require File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "spec_helper")) -startup_merb -describe "Merb.env helpers" do - before(:all) do - @orig_env = Merb.environment - end - after(:all) do - Merb.environment = @orig_env - end - - it "should pickup the environment from env" do - %w(development test production staging demo).each do |e| - Merb.environment = e - Merb.env.should == e +describe "Merb" do + + describe "Merb.environment, Merb.env helpers" do + before(:all) do + startup_merb + @orig_env = Merb.environment end - end - - it "should correctly answer the question about which env it's in with symbol or string" do - %w(development test production staging demo custom).each do |e| - Merb.environment = e - Merb.env?(e).should be true - Merb.env?(e.to_sym).should be_true + after(:all) do + Merb.environment = @orig_env end - end - - it "should answer false if asked for an environment that is not current" do - %w(development test production staging demo custom).each do |e| - Merb.environment = e - Merb.env?(:not_it).should be_false + + it "should pickup the environment from env" do + %w(development test production staging demo).each do |e| + Merb.environment = e + Merb.env.should == e + end + end + + it "should correctly answer the question about which env it's in with symbol or string" do + %w(development test production staging demo custom).each do |e| + Merb.environment = e + Merb.env?(e).should be true + Merb.env?(e.to_sym).should be_true + end + end + + it "should answer false if asked for an environment that is not current" do + %w(development test production staging demo custom).each do |e| + Merb.environment = e + Merb.env?(:not_it).should be_false + end + end + + it "should allow an environment to merge another environments settings" do + %w(development test production staging demo custom).each do |e| + + Merb.environment = e + Merb.start_environment + Merb.merge_env "some_other_env" + Merb.environment_info.nil?.should be_false + Merb.environment_info[:merged_envs].first.should == "some_other_env" + end end end - - it "should allow an environment to merge another environments settings" do - %w(development test production staging demo custom).each do |e| - Merb.environment = e - Merb.start_environment - Merb.merge_env "some_other_env" - Merb.environment_info.nil?.should be_false - Merb.environment_info[:merged_envs].first.should == "some_other_env" + describe "#runnig_irb?" do + it "should be false if running different adapter than irb" do + startup_merb + Merb.running_irb?.should be_false + end + + %w{-i --irb-console}.each do |option| + it "should be true if merb is run with CLI option #{option}" do + Merb::Server.stub!(:start) + Merb.start([option]) + Merb.running_irb?.should be_true + end end end - - -end \ No newline at end of file +end diff --git a/merb-core/spec/public/core_ext/json_pure_spec.rb b/merb-core/spec/public/core_ext/json_pure_spec.rb new file mode 100644 index 00000000..33b249a3 --- /dev/null +++ b/merb-core/spec/public/core_ext/json_pure_spec.rb @@ -0,0 +1,34 @@ +require File.join(File.dirname(__FILE__), "spec_helper") + +require "benchmark" + +begin + gem "json_pure", "<= 1.1.6" +rescue LoadError + Merb.fatal! "This test is testing a vulnerability that was present in JSON::Pure 1.1.6 but not in later " \ + "versions. In order to run this test, you must have json_pure 1.1.6 or lower on your system." +end + +class Merb::BootLoader::Dependencies + extend(Module.new do + def require(name) + raise LoadError if name == "json/ext" + super + end + end) +end + +startup_merb + +describe "JSON pure vulnerability" do + it "can finish parsing a JSON document that could be exploited" do + ["\\/", "\\\\", "\\\"", "\\b", "\\n", "\\f", "\\r", "\\t"].each do |char| + bad_json = "{\"a\":\"" + (char * 20) + "\000\"}" + + success = false + + time = Benchmark.measure { JSON.parse(bad_json) rescue nil }.real + time.should_not > 0.1 + end + end +end \ No newline at end of file diff --git a/merb-core/spec/public/request/request_spec.rb b/merb-core/spec/public/request/request_spec.rb index ef59aa48..6fbcc7f3 100644 --- a/merb-core/spec/public/request/request_spec.rb +++ b/merb-core/spec/public/request/request_spec.rb @@ -116,12 +116,22 @@ it "should be able to get the remote IP when some of the X_FORWARDED_FOR are local" do request = fake_request({:http_x_forwarded_for => "192.168.2.1,127.0.0.1,www.example.com"}) request.remote_ip.should == "www.example.com" + + %w(212.183.134.130 82.132.136.215).each do |addr| + request = fake_request({:http_x_forwarded_for => addr}) + request.remote_ip.should == addr + end end it "should be able to get the remote IP when it's in REMOTE_ADDR" do request = fake_request({:remote_addr => "www.example.com"}) request.remote_ip.should == "www.example.com" end + + it "filters private IPs from X_FORWARDED_FOR" do + request = fake_request({:http_x_forwarded_for => "10.0.0.0,10.255.255.255,169.254.1.2,172.16.0.0,172.24.0.0,172.31.255.255,192.168.0.0,192.168.255.255,www.example.com"}) + request.remote_ip.should == 'www.example.com' + end end describe Merb::Request, "#cookies" do diff --git a/merb-core/spec/public/test/20_multipart_request_helper_spec.rb b/merb-core/spec/public/test/20_multipart_request_helper_spec.rb index 7443784f..d1d08d30 100644 --- a/merb-core/spec/public/test/20_multipart_request_helper_spec.rb +++ b/merb-core/spec/public/test/20_multipart_request_helper_spec.rb @@ -36,7 +36,7 @@ file_params = controller.params[:my_file] file_params[:content_type].should == "text/plain" file_params[:size].should == File.size(file_name) - file_params[:tempfile].should be_a_kind_of(File) + file_params[:tempfile].should be_a_kind_of(Tempfile) file_params[:filename].should == "multipart_upload_text_file.txt" end end diff --git a/merb-core/spec/public/test/multipart_request_helper_spec.rb b/merb-core/spec/public/test/multipart_request_helper_spec.rb index 6e35277a..11e1d13b 100644 --- a/merb-core/spec/public/test/multipart_request_helper_spec.rb +++ b/merb-core/spec/public/test/multipart_request_helper_spec.rb @@ -35,7 +35,7 @@ file_params = controller.params[:my_file] file_params[:content_type].should == "text/plain" file_params[:size].should == File.size(file_name) - file_params[:tempfile].should be_a_kind_of(File) + file_params[:tempfile].should be_a_kind_of(Tempfile) file_params[:filename].should == "multipart_upload_text_file.txt" end end @@ -67,7 +67,7 @@ file_params = controller.params[:my_file] file_params[:content_type].should == "text/plain" file_params[:size].should == File.size(file_name) - file_params[:tempfile].should be_a_kind_of(File) + file_params[:tempfile].should be_a_kind_of(Tempfile) file_params[:filename].should == "multipart_upload_text_file.txt" end end @@ -101,7 +101,7 @@ file_params = controller.params[:my_file] file_params[:content_type].should == "text/plain" file_params[:size].should == File.size(file_name) - file_params[:tempfile].should be_a_kind_of(File) + file_params[:tempfile].should be_a_kind_of(Tempfile) file_params[:filename].should == "multipart_upload_text_file.txt" end end diff --git a/merb-core/spec10/public/test/multipart_request_helper_spec.rb b/merb-core/spec10/public/test/multipart_request_helper_spec.rb index 6e35277a..11e1d13b 100644 --- a/merb-core/spec10/public/test/multipart_request_helper_spec.rb +++ b/merb-core/spec10/public/test/multipart_request_helper_spec.rb @@ -35,7 +35,7 @@ file_params = controller.params[:my_file] file_params[:content_type].should == "text/plain" file_params[:size].should == File.size(file_name) - file_params[:tempfile].should be_a_kind_of(File) + file_params[:tempfile].should be_a_kind_of(Tempfile) file_params[:filename].should == "multipart_upload_text_file.txt" end end @@ -67,7 +67,7 @@ file_params = controller.params[:my_file] file_params[:content_type].should == "text/plain" file_params[:size].should == File.size(file_name) - file_params[:tempfile].should be_a_kind_of(File) + file_params[:tempfile].should be_a_kind_of(Tempfile) file_params[:filename].should == "multipart_upload_text_file.txt" end end @@ -101,7 +101,7 @@ file_params = controller.params[:my_file] file_params[:content_type].should == "text/plain" file_params[:size].should == File.size(file_name) - file_params[:tempfile].should be_a_kind_of(File) + file_params[:tempfile].should be_a_kind_of(Tempfile) file_params[:filename].should == "multipart_upload_text_file.txt" end end diff --git a/merb-exceptions/Rakefile b/merb-exceptions/Rakefile index 33892a4f..461b0a75 100644 --- a/merb-exceptions/Rakefile +++ b/merb-exceptions/Rakefile @@ -28,7 +28,7 @@ spec = Gem::Specification.new do |s| s.author = GEM_AUTHOR s.email = GEM_EMAIL s.homepage = PROJECT_URL - s.add_dependency('merb-core', ">= #{Merb::VERSION}") + s.add_dependency('merb-core', "~> #{Merb::VERSION}") s.require_path = 'lib' s.files = %w(LICENSE README.markdown Rakefile) + Dir.glob("{lib,spec}/**/*") end diff --git a/merb-gen/lib/generators/resource_controller.rb b/merb-gen/lib/generators/resource_controller.rb index 99f6ba32..e7689d9e 100644 --- a/merb-gen/lib/generators/resource_controller.rb +++ b/merb-gen/lib/generators/resource_controller.rb @@ -30,10 +30,9 @@ def self.source_root template :controller_none, :orm => :none do |template| template.source = "app/controllers/%file_name%.rb" template.destination = "app/controllers" / base_path / "#{file_name}.rb" - - self.add_resource_route(self.plural_model) + self.add_resource_route(self.plural_model) unless skip_route_definition? end - + [:index, :show, :edit, :new].each do |view| template "view_#{view}_none".to_sym, :template_engine => :erb, :orm => :none do |template| template.source = "app/views/%file_name%/#{view}.html.erb" @@ -86,7 +85,11 @@ def params_for_get def properties [] end - + + def skip_route_definition? + options[:pretend] || options[:delete] + end + end add :resource_controller, ResourceControllerGenerator diff --git a/merb-gen/lib/generators/templates/application/common/merb_thor/gem_ext.rb b/merb-gen/lib/generators/templates/application/common/merb_thor/gem_ext.rb index 6b605d7c..a3471939 100644 --- a/merb-gen/lib/generators/templates/application/common/merb_thor/gem_ext.rb +++ b/merb-gen/lib/generators/templates/application/common/merb_thor/gem_ext.rb @@ -78,7 +78,7 @@ def find_gems_with_sources(dep) class ::Gem::SpecFetcher alias old_fetch fetch - def fetch(dependency, all = false, matching_platform = true) + def fetch(dependency, all = false, matching_platform = true, prerelease = false) idx = Gem::SourceIndex.from_installed_gems reqs = dependency.version_requirements.requirements diff --git a/merb-gen/lib/generators/templates/application/common/merb_thor/main.thor b/merb-gen/lib/generators/templates/application/common/merb_thor/main.thor index a4c5e103..d8bc9960 100644 --- a/merb-gen/lib/generators/templates/application/common/merb_thor/main.thor +++ b/merb-gen/lib/generators/templates/application/common/merb_thor/main.thor @@ -95,7 +95,8 @@ module Merb end rescue ::Gem::LoadError => e self.class.error "Configuration could not be confirmed: #{e.message}" - self.class.rollback_trans + # Don't rollback since its possibly the confirmation is just broken + # self.class.rollback_trans end self.class.info "Confirmed" end diff --git a/merb-gen/lib/generators/templates/application/merb_core/spec/spec.opts b/merb-gen/lib/generators/templates/application/merb_core/spec/spec.opts index e69de29b..e0f74bb3 100644 --- a/merb-gen/lib/generators/templates/application/merb_core/spec/spec.opts +++ b/merb-gen/lib/generators/templates/application/merb_core/spec/spec.opts @@ -0,0 +1,2 @@ +--format specdoc +--colour diff --git a/merb-gen/lib/generators/templates/application/merb_flat/config/init.rb b/merb-gen/lib/generators/templates/application/merb_flat/config/init.rb index 06e3525d..a4beb3f0 100644 --- a/merb-gen/lib/generators/templates/application/merb_flat/config/init.rb +++ b/merb-gen/lib/generators/templates/application/merb_flat/config/init.rb @@ -4,6 +4,10 @@ use_test :<%= testing_framework %> use_template_engine :<%= template_engine %> +# If you need to use dependency immediately in this file you must add :immediate => true +# to dependency definition: +# dependency "merb-slices", :immediate => true +# # Specify a specific version of a dependency # dependency "RedCloth", "> 3.0" diff --git a/merb-gen/lib/generators/templates/application/merb_stack/config/dependencies.rb b/merb-gen/lib/generators/templates/application/merb_stack/config/dependencies.rb index 743289c8..06a0031d 100644 --- a/merb-gen/lib/generators/templates/application/merb_stack/config/dependencies.rb +++ b/merb-gen/lib/generators/templates/application/merb_stack/config/dependencies.rb @@ -1,7 +1,7 @@ # dependencies are generated using a strict version, don't forget to edit the dependency versions when upgrading. merb_gems_version = "<%= merb_gems_version %>" -dm_gems_version = "<%= dm_gems_version %>" -do_gems_version = "<%= do_gems_version %>" +dm_gems_version = "~> <%= dm_gems_version %>" +do_gems_version = "~> <%= do_gems_version %>" # For more information about each component, please read http://wiki.merbivore.com/faqs/merb_components dependency "merb-core", merb_gems_version diff --git a/merb-gen/lib/generators/templates/application/merb_stack/spec/spec.opts b/merb-gen/lib/generators/templates/application/merb_stack/spec/spec.opts index e69de29b..e0f74bb3 100644 --- a/merb-gen/lib/generators/templates/application/merb_stack/spec/spec.opts +++ b/merb-gen/lib/generators/templates/application/merb_stack/spec/spec.opts @@ -0,0 +1,2 @@ +--format specdoc +--colour diff --git a/merb-gen/lib/generators/templates/application/merb_very_flat/application.rbt b/merb-gen/lib/generators/templates/application/merb_very_flat/application.rbt index 2ea4d454..9f3613ef 100644 --- a/merb-gen/lib/generators/templates/application/merb_very_flat/application.rbt +++ b/merb-gen/lib/generators/templates/application/merb_very_flat/application.rbt @@ -33,6 +33,13 @@ <%= "# " unless template_engine == :erb %>use_template_engine :erb <%= "# " unless template_engine == :haml %>use_template_engine :haml +# If you need to use dependency immediately in this file you must add :immediate => true +# to dependency definition: +# dependency "merb-slices", :immediate => true +# +# Specify a specific version of a dependency +# dependency "RedCloth", "> 3.0" + Merb::Config.use { |c| c[:framework] = { :public => [Merb.root / "public", nil] } c[:session_store] = 'none' @@ -56,4 +63,4 @@ class <%= class_name %> < Merb::Controller def index "Hi, I am 'very flat' Merb application. I have everything in one single file and well suited for dynamic stub pages." end -end \ No newline at end of file +end diff --git a/merb-haml/Rakefile b/merb-haml/Rakefile index b7a49106..a9d4d247 100644 --- a/merb-haml/Rakefile +++ b/merb-haml/Rakefile @@ -31,7 +31,7 @@ spec = Gem::Specification.new do |s| s.author = GEM_AUTHOR s.email = GEM_EMAIL s.homepage = PROJECT_URL - s.add_dependency('merb-core', "= #{Merb::VERSION}") + s.add_dependency('merb-core', "~> #{Merb::VERSION}") s.add_dependency('haml', '>= 2.0.3') s.require_path = 'lib' s.files = %w(LICENSE README Rakefile TODO Generators) + Dir.glob("{lib}/**/*") diff --git a/merb-haml/lib/merb-haml.rb b/merb-haml/lib/merb-haml.rb index 2753a0c1..4039c75a 100644 --- a/merb-haml/lib/merb-haml.rb +++ b/merb-haml/lib/merb-haml.rb @@ -9,7 +9,7 @@ Merb::BootLoader.after_app_loads do if File.directory?(Merb::Plugins.config[:sass][:template_location] || Merb.dir_for(:stylesheet) / "sass") - require "sass/plugin" + require "sass" if Merb::Config[:sass] Merb.logger.info("Please define your sass settings in Merb::Plugins.config[:sass] not Merb::Config") Sass::Plugin.options = Merb::Config[:sass] diff --git a/merb-helpers/Rakefile b/merb-helpers/Rakefile index da624296..2d59e6e7 100644 --- a/merb-helpers/Rakefile +++ b/merb-helpers/Rakefile @@ -31,7 +31,7 @@ spec = Gem::Specification.new do |s| s.author = GEM_AUTHOR s.email = GEM_EMAIL s.homepage = PROJECT_URL - s.add_dependency('merb-core', ">= #{Merb::VERSION}") + s.add_dependency('merb-core', "~> #{Merb::VERSION}") s.require_path = 'lib' s.files = %w(LICENSE README Rakefile TODO) + Dir.glob("{lib,spec}/**/*") end diff --git a/merb-helpers/lib/merb-helpers/form/builder.rb b/merb-helpers/lib/merb-helpers/form/builder.rb index 7485b1fe..2a73fb46 100644 --- a/merb-helpers/lib/merb-helpers/form/builder.rb +++ b/merb-helpers/lib/merb-helpers/form/builder.rb @@ -131,7 +131,7 @@ def process_form_attrs(attrs) attrs[:method] = :post unless attrs[:method] == :get # Use a fake PUT if the object is not new, otherwise use the method # passed in. Defaults to :post if no method is set. - method ||= (@obj.respond_to?(:new_record?) && !@obj.new_record?) || (@obj.respond_to?(:new?) && !@obj.new?) ? :put : :post + method ||= (@obj.respond_to?(:new?) && !@obj.new?) || (@obj.respond_to?(:new_record?) && !@obj.new_record?) ? :put : :post attrs[:enctype] = "multipart/form-data" if attrs.delete(:multipart) || @multipart @@ -164,7 +164,7 @@ def update_bound_check_box(method, attrs) def update_bound_select(method, attrs) attrs[:value_method] ||= method attrs[:text_method] ||= attrs[:value_method] || :to_s - attrs[:selected] ||= control_value(attrs[:value_method]) + attrs[:selected] ||= control_value(method) end def update_unbound_controls(attrs, type) @@ -374,8 +374,10 @@ def update_bound_controls(method, attrs, type) end def update_unbound_controls(attrs, type) - attrs.merge!(:id => attrs[:name]) if attrs[:name] && !attrs[:id] - + if attrs[:name] && !attrs[:id] + # '[' and ']' are illegal in HTML id attributes + attrs.merge!(:id => attrs[:name].to_s.gsub(/(\[|\])/, '_')) + end case type when "text", "radio", "password", "hidden", "checkbox", "file" add_css_class(attrs, type) diff --git a/merb-helpers/spec/fixture/app/views/bound_select_specs/selected.html.erb b/merb-helpers/spec/fixture/app/views/bound_select_specs/selected.html.erb new file mode 100644 index 00000000..0ade98f6 --- /dev/null +++ b/merb-helpers/spec/fixture/app/views/bound_select_specs/selected.html.erb @@ -0,0 +1,3 @@ +<%= form_for @obj do %> +<%= select( :bar, :collection => @collection, :text_method => :bar, :value_method => :foo ) %> +<% end =%> diff --git a/merb-helpers/spec/fixture/app/views/select_specs/label.html.erb b/merb-helpers/spec/fixture/app/views/select_specs/label.html.erb new file mode 100644 index 00000000..5ed44628 --- /dev/null +++ b/merb-helpers/spec/fixture/app/views/select_specs/label.html.erb @@ -0,0 +1 @@ +<%= select(:name => "foo", :collection => %w(one two three), :selected => "three", :label => 'LABEL') %> diff --git a/merb-helpers/spec/merb_helpers_form_spec.rb b/merb-helpers/spec/merb_helpers_form_spec.rb index c32c4991..2b8829c3 100644 --- a/merb-helpers/spec/merb_helpers_form_spec.rb +++ b/merb-helpers/spec/merb_helpers_form_spec.rb @@ -745,7 +745,7 @@ radio = @c.render :hash radio.scan( /(Five|Bar)<\/label>/ ).size.should == 2 radio.scan(/<[^>]*>/).size.should == 6 - radio.should match_tag(:input, :value => 5) + radio.should match_tag(:input, :value => '5') radio.should match_tag(:label) radio.should match_tag(:input, :value => 'bar', :id => 'bar_id') radio.should match_tag(:label, :for => 'bar_id') @@ -809,7 +809,7 @@ r = @c.render :hashes r.scan( /(Five|Bar)<\/label>/ ).size.should == 2 r.scan(/<[^>]*>/)[2..-2].size.should == 6 - r.should match_tag(:input, :value => 5) + r.should match_tag(:input, :value => '5') r.should match_tag(:label) r.should match_tag(:input, :value => 'bar', :id => 'bar_id') r.should match_tag(:label, :for => 'bar_id') @@ -979,6 +979,19 @@ form.should have_selector("label[for=fake_model_foo]:contains('LABEL')") end + it "should render a select tag with correct field selected" do + a = FakeModel3.new; a.bar = "A"; a.foo = 4 + b = FakeModel3.new; b.bar = "B"; b.foo = 2 + c = FakeModel3.new; c.bar = "C"; c.foo = 7 + + @c.instance_variable_set(:@collection, [a,b,c]) + + r = @c.render :selected + r.should_not have_selector("select[id=fake_model_bar] option[selected]:contains('A')") + r.should_not have_selector("select[id=fake_model_bar] option[selected]:contains('B')") + r.should have_selector("select[id=fake_model_bar] option[selected]:contains('C')") + end + # Not sure how this makes any sense # --------------------------------- # @@ -1080,7 +1093,7 @@ it "should provide selected options by value" do r = @c.render :selected r.should match_tag( :option, :value => 'rabbit', :selected => 'selected', :content => 'Rabbit' ) - r.should_not match_tag( :option, :value => 'chicken', :selected => nil, :content => 'Chicken' ) + r.should_not match_tag( :option, :value => 'chicken', :selected => '', :content => 'Chicken' ) end it "should handle arrays for selected when :multiple is true" do diff --git a/merb-mailer/Rakefile b/merb-mailer/Rakefile index c959ea1d..6b9b9b83 100644 --- a/merb-mailer/Rakefile +++ b/merb-mailer/Rakefile @@ -31,7 +31,7 @@ spec = Gem::Specification.new do |s| s.author = GEM_AUTHOR s.email = GEM_EMAIL s.homepage = PROJECT_URL - s.add_dependency('merb-core', ">= #{Merb::VERSION}") + s.add_dependency('merb-core', "~> #{Merb::VERSION}") s.add_dependency('mailfactory', '>= 1.2.3') s.require_path = 'lib' s.files = %w(LICENSE README.textile Rakefile TODO Generators) + Dir.glob("{lib,spec}/**/*") diff --git a/merb-param-protection/Rakefile b/merb-param-protection/Rakefile index 036ea455..8d18c5ec 100644 --- a/merb-param-protection/Rakefile +++ b/merb-param-protection/Rakefile @@ -31,7 +31,7 @@ spec = Gem::Specification.new do |s| s.author = GEM_AUTHOR s.email = GEM_EMAIL s.homepage = PROJECT_URL - s.add_dependency('merb-core', ">= #{Merb::VERSION}") + s.add_dependency('merb-core', "~> #{Merb::VERSION}") s.require_path = 'lib' s.files = %w(LICENSE README Rakefile) + Dir.glob("{lib,specs}/**/*") end diff --git a/merb-slices/Rakefile b/merb-slices/Rakefile index 75a192b5..fa45b502 100644 --- a/merb-slices/Rakefile +++ b/merb-slices/Rakefile @@ -31,7 +31,7 @@ spec = Gem::Specification.new do |s| s.author = GEM_AUTHOR s.email = GEM_EMAIL s.homepage = PROJECT_URL - s.add_dependency('merb-core', ">= #{Merb::VERSION}") + s.add_dependency('merb-core', "~> #{Merb::VERSION}") s.require_path = 'lib' s.files = %w(LICENSE README Rakefile Generators TODO) + Dir.glob("{lib,spec}/**/*") s.bindir = "bin" diff --git a/merb/Rakefile b/merb/Rakefile index c122d253..5fb44db6 100644 --- a/merb/Rakefile +++ b/merb/Rakefile @@ -23,9 +23,8 @@ DM_VERSION = Merb::DM_VERSION RELEASE_NAME = "REL #{GEM_VERSION}" gems = [ - ["merb_datamapper", "= #{GEM_VERSION}"], ["merb-core", "= #{GEM_VERSION}"], - ["merb-more", "= #{GEM_VERSION}"], + ["merb_datamapper", "= #{GEM_VERSION}"], ["dm-core", "~> #{DM_VERSION}"], ["do_sqlite3", "~> #{DM_VERSION}"], ["dm-timestamps", "~> #{DM_VERSION}"], diff --git a/merb/lib/merb.rb b/merb/lib/merb.rb index 5ebe827c..6186c026 100644 --- a/merb/lib/merb.rb +++ b/merb/lib/merb.rb @@ -1,7 +1,6 @@ ### AUTOMATICALLY GENERATED. DO NOT EDIT! -require 'merb_datamapper' require 'merb-core' -require 'merb-more' +require 'merb_datamapper' require 'dm-core' require 'do_sqlite3' require 'dm-timestamps' diff --git a/merb_datamapper/Rakefile b/merb_datamapper/Rakefile index 78ce8658..8df814e4 100644 --- a/merb_datamapper/Rakefile +++ b/merb_datamapper/Rakefile @@ -8,16 +8,20 @@ PROJECT_URL = "http://merbivore.com" PROJECT_SUMMARY = "DataMapper plugin providing DataMapper support for Merb" PROJECT_DESCRIPTION = PROJECT_SUMMARY -GEM_AUTHOR = "Jason Toy" -GEM_EMAIL = "jtoy@rubynow.com" +GEM_AUTHOR = "Jason Toy" +GEM_EMAIL = "jtoy@rubynow.com" -GEM_NAME = "merb_datamapper" -PKG_BUILD = ENV['PKG_BUILD'] ? '.' + ENV['PKG_BUILD'] : '' -GEM_VERSION = Merb::VERSION + PKG_BUILD +GEM_NAME = "merb_datamapper" +PKG_BUILD = ENV['PKG_BUILD'] ? '.' + ENV['PKG_BUILD'] : '' +GEM_VERSION = Merb::VERSION + PKG_BUILD -RELEASE_NAME = "REL #{GEM_VERSION}" +RELEASE_NAME = "REL #{GEM_VERSION}" -GEM_DEPENDENCIES = [["dm-core", ">=0.9.5"], ["dm-migrations", ">=0.9.5"], ["merb-core", "~> #{GEM_VERSION}"]] +GEM_DEPENDENCIES = [ + ["dm-core", "~> #{Merb::DM_VERSION}"], + ["dm-migrations", "~> #{Merb::DM_VERSION}"], + ["merb-core", "~> #{GEM_VERSION}"] +] require "extlib/tasks/release" diff --git a/merb_datamapper/lib/generators/data_mapper_model.rb b/merb_datamapper/lib/generators/data_mapper_model.rb index e6d1f8bf..93072342 100644 --- a/merb_datamapper/lib/generators/data_mapper_model.rb +++ b/merb_datamapper/lib/generators/data_mapper_model.rb @@ -7,7 +7,9 @@ def datamapper_type(type) end def after_generation - STDOUT << message("Don't forget to define the model schema in your #{ Extlib::Inflection.camelize(file_name) } class") + if orm == :datamapper + STDOUT << message("Don't forget to define the model schema in your #{ Extlib::Inflection.camelize(file_name) } class") + end end end diff --git a/merb_datamapper/lib/generators/data_mapper_resource_controller.rb b/merb_datamapper/lib/generators/data_mapper_resource_controller.rb index cad8773d..573e34db 100644 --- a/merb_datamapper/lib/generators/data_mapper_resource_controller.rb +++ b/merb_datamapper/lib/generators/data_mapper_resource_controller.rb @@ -14,8 +14,7 @@ def properties Merb::Generators::ResourceControllerGenerator.template :controller_datamapper, :orm => :datamapper do |t| t.source = File.join(File.dirname(__FILE__), "templates/resource_controller.rb") t.destination = File.join("app/controllers", base_path, "#{file_name}.rb") - - self.add_resource_route(self.plural_model) + self.add_resource_route(self.plural_model) unless skip_route_definition? end [:index, :show, :edit, :new].each do |view| diff --git a/merb_datamapper/lib/generators/templates/resource_controller.rb b/merb_datamapper/lib/generators/templates/resource_controller.rb index a90aee44..ea5a0f07 100644 --- a/merb_datamapper/lib/generators/templates/resource_controller.rb +++ b/merb_datamapper/lib/generators/templates/resource_controller.rb @@ -39,7 +39,7 @@ def create(<%= singular_model %>) def update(id, <%= singular_model %>) @<%= singular_model %> = <%= model_class_name %>.get(id) raise NotFound unless @<%= singular_model %> - if @<%= singular_model %>.update_attributes(<%= singular_model %>) + if @<%= singular_model %>.update(<%= singular_model %>) redirect resource(@<%= singular_model %>) else display @<%= singular_model %>, :edit diff --git a/merb_datamapper/lib/merb/session/data_mapper_session.rb b/merb_datamapper/lib/merb/session/data_mapper_session.rb index d2819061..19fef2f2 100644 --- a/merb_datamapper/lib/merb/session/data_mapper_session.rb +++ b/merb_datamapper/lib/merb/session/data_mapper_session.rb @@ -1,13 +1,16 @@ require 'merb-core/dispatch/session' -require "dm-core" + module Merb class DataMapperSessionStore include ::DataMapper::Resource - table_name = Merb::Plugins.config[:merb_datamapper][:session_storage_name] || 'sessions' - storage_names[default_repository_name] = table_name + def self.default_repository_name + Merb::Plugins.config[:merb_datamapper][:session_repository_name] + end + + storage_names[default_repository_name] = Merb::Plugins.config[:merb_datamapper][:session_storage_name] - property :session_id, String, :size => 32, :nullable => false, :key => true + property :session_id, String, :length => 32, :nullable => false, :key => true property :data, Object, :default => {}, :lazy => false property :created_at, DateTime, :default => Proc.new { |r, p| DateTime.now } @@ -31,7 +34,7 @@ def self.retrieve_session(session_id) # @param data The data to be stored in the session. Probably a hash def self.store_session(session_id, data) if session = get(session_id) - session.update_attributes(:data => data) + session.update(:data => data) else create(:session_id => session_id, :data => data) end @@ -44,10 +47,6 @@ def self.store_session(session_id, data) def self.delete_session(session_id) all(:session_id => session_id).destroy! end - - def self.default_repository_name - Merb::Plugins.config[:merb_datamapper][:session_repository_name] || :default - end end class DataMapperSession < SessionStoreContainer diff --git a/merb_datamapper/lib/merb_datamapper.rb b/merb_datamapper/lib/merb_datamapper.rb index 01d5bc48..d42debe8 100644 --- a/merb_datamapper/lib/merb_datamapper.rb +++ b/merb_datamapper/lib/merb_datamapper.rb @@ -1,8 +1,7 @@ if defined?(Merb::Plugins) - dependency 'dm-core' + require 'dm-core' require File.dirname(__FILE__) / "merb" / "orms" / "data_mapper" / "connection" - require File.dirname(__FILE__) / "merb" / "session" / "data_mapper_session" Merb::Plugins.add_rakefiles "merb_datamapper" / "merbtasks" # conditionally assign things, so as not to override previously set options. @@ -37,7 +36,7 @@ def self.run # if we use a datamapper session store, require it. Merb.logger.verbose! "Checking if we need to use DataMapper sessions" - if Merb::Config.session_stores.include?(:datamapper) + if Merb::Config.session_store == 'datamapper' Merb.logger.verbose! "Using DataMapper sessions" require File.dirname(__FILE__) / "merb" / "session" / "data_mapper_session" end @@ -53,54 +52,41 @@ class Merb::Orms::DataMapper::Associations < Merb::BootLoader after LoadClasses def self.run - Merb.logger.verbose! 'Merb::Orms::DataMapper::Associations block' - - # make sure all relationships are initialized after loading - descendants = DataMapper::Resource.descendants.dup - descendants.dup.each do |model| - descendants.merge(model.descendants) if model.respond_to?(:descendants) - end - descendants.each do |model| + Merb.logger.verbose! 'Merb::Orms::DataMapper::Associations - defining lazy relationship properties' + + DataMapper::Model.descendants.each do |model| model.relationships.each_value { |r| r.child_key } end - Merb.logger.verbose! 'Merb::Orms::DataMapper::Associations complete' + Merb.logger.verbose! 'Merb::Orms::DataMapper::Associations - complete' + end end if Merb::Plugins.config[:merb_datamapper][:use_repository_block] - # wrap action in repository block to enable identity map - class Application < Merb::Controller - override! :_call_action - def _call_action(*) - repository do |r| - Merb.logger.debug "In repository block #{r.name}" - super + + class Merb::Orms::DataMapper::IdentityMapSupport < Merb::BootLoader + + after RackUpApplication + + def self.run + + app = Merb::Config[:app] + def app.call(env) + DataMapper.repository do |r| + Merb.logger.debug "In repository block #{r.name}" + super + end end + end end + end generators = File.join(File.dirname(__FILE__), 'generators') Merb.add_generators generators / 'data_mapper_model' Merb.add_generators generators / 'data_mapper_resource_controller' Merb.add_generators generators / 'data_mapper_migration' - - # Override bug in DM::Timestamps - Merb::BootLoader.after_app_loads do - module DataMapper - module Timestamp - private - - def set_timestamps - return unless dirty? || new_record? - TIMESTAMP_PROPERTIES.each do |name,(_type,proc)| - if model.properties.has_property?(name) - model.properties[name].set(self, proc.call(self, model.properties[name])) unless attribute_dirty?(name) - end - end - end - end - end - end + end diff --git a/merb_datamapper/lib/merb_datamapper/merbtasks.rb b/merb_datamapper/lib/merb_datamapper/merbtasks.rb index 04d40a9e..c7289a31 100644 --- a/merb_datamapper/lib/merb_datamapper/merbtasks.rb +++ b/merb_datamapper/lib/merb_datamapper/merbtasks.rb @@ -16,17 +16,16 @@ end desc "Perform automigration" task :automigrate => :merb_env do - ::DataMapper::AutoMigrator.auto_migrate + ::DataMapper.auto_migrate! end desc "Perform non destructive automigration" task :autoupgrade => :merb_env do - ::DataMapper::AutoMigrator.auto_upgrade + ::DataMapper.auto_upgrade! end namespace :migrate do task :load => :merb_env do - gem 'dm-migrations' - require 'migration_runner' + require 'dm-migrations/migration_runner' FileList["schema/migrations/*.rb"].each do |migration| load migration end @@ -66,7 +65,7 @@ desc "Drop the database (postgres only)" task :drop do config = Merb::Orms::DataMapper.config - puts "Droping database '#{config[:database]}'" + puts "Dropping database '#{config[:database]}'" case config[:adapter] when 'postgres' `dropdb -U #{config[:username]} #{config[:database]}` diff --git a/merb_datamapper/spec/session_spec.rb b/merb_datamapper/spec/session_spec.rb index d0bc6adf..0ec52814 100644 --- a/merb_datamapper/spec/session_spec.rb +++ b/merb_datamapper/spec/session_spec.rb @@ -1,6 +1,6 @@ require File.dirname(__FILE__) + "/spec_helper" #require 'merb-core/dispatch/session/store_container' -#require File.join( File.dirname(__FILE__), "..", "lib", 'merb', 'session', 'sequel_session') +require File.join( File.dirname(__FILE__), "..", "lib", 'merb', 'session', 'data_mapper_session') describe Merb::DataMapperSession do diff --git a/merb_datamapper/spec/session_store_spec.rb b/merb_datamapper/spec/session_store_spec.rb index 0f18f73b..d4c5bc71 100644 --- a/merb_datamapper/spec/session_store_spec.rb +++ b/merb_datamapper/spec/session_store_spec.rb @@ -7,7 +7,6 @@ end before(:each) do - Merb::Plugins.config[:merb_datamapper] = {} @session_container = Merb::DataMapperSessionStore @session_container.auto_migrate! @sess_id = 'a'*32