Permalink
Browse files

Merge branch 'master' of git://github.com/wycats/merb

  • Loading branch information...
2 parents 3c61f7a + e0895a0 commit 61e1e5670e335b7e1c953a8bc486885277314091 @pk pk committed Sep 17, 2009
View
@@ -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.
View
@@ -43,14 +43,14 @@ merb_release = {
"merb-helpers",
"merb-mailer",
"merb-param-protection",
+ "merb-actionorm",
"merb_datamapper",
"merb",
- "merb-more",
- "merb-actionorm"
+ "merb-more"
]
}
-merb_gem_paths = %w[merb merb-core merb_datamapper] + merb_more_gem_paths
+merb_gem_paths = %w[merb merb-core] + merb_more_gem_paths + %w[merb_datamapper]
merb_gems = merb_gem_paths.map { |p| File.basename(p) }
merb_more_gems = merb_more_gem_paths.map { |p| File.basename(p) }
@@ -89,8 +89,9 @@ def clone
#
# Use :buffer_requests option to use bufferring,
# :no_block to use non-blocking async I/O.
+ # :support_cas to support CAS
def connect(config = {})
- @memcached = ::Memcached.new(@servers, config.only(:buffer_requests, :no_block).merge(:namespace => @namespace))
+ @memcached = ::Memcached.new(@servers, config.only(:buffer_requests, :no_block, :support_cas).merge(:namespace => @namespace))
end
# Returns cache key calculated from base key
@@ -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]
@@ -37,6 +37,7 @@ def []=(key, value)
# :expires<Time>:: Cookie expiry date.
# :domain<String>:: The domain for which this cookie applies.
# :secure<Boolean>:: Security flag.
+ # :http_only<Boolean>:: HttpOnly cookies
#
# ==== Notes
# By using this method, a cookie key is marked for being
@@ -77,10 +78,12 @@ def extract_headers(controller_defaults = {})
options["expires"] = expiry.gmtime.strftime(Merb::Const::COOKIE_EXPIRATION_FORMAT)
end
secure = options.delete("secure")
+ http_only = options.delete("http_only")
kookie = "#{name}=#{Merb::Parse.escape(value)}; "
# WebKit in particular doens't like empty cookie options - skip them.
options.each { |k, v| kookie << "#{k}=#{v}; " unless v.blank? }
- kookie << 'secure' if secure
+ kookie << 'secure; ' if secure
+ kookie << 'HttpOnly; ' if http_only
cookies << kookie.rstrip
end
cookies.empty? ? {} : { 'Set-Cookie' => cookies }
@@ -43,14 +43,16 @@ class Request
@@mutex = Mutex.new
+ attr_reader :start
+
# Handles request routing and action dispatch.
#
# ==== Returns
# Array[Integer, Hash, #each]:: A Rack response
#
# :api: private
def handle
- start = env["merb.request_start"] = Time.now
+ @start = env["merb.request_start"] = Time.now
Merb.logger.info { "Started request handling: #{start.to_s}" }
find_route!
@@ -119,11 +119,14 @@ def self.included(base)
base.cattr_accessor :registered_session_types
base.registered_session_types = Dictionary.new
base.class_inheritable_accessor :_session_id_key, :_session_secret_key,
- :_session_expiry
+ :_session_expiry, :_session_secure,
+ :_session_http_only
base._session_id_key = Merb::Config[:session_id_key] || '_session_id'
base._session_expiry = Merb::Config[:session_expiry] || 0
base._session_secret_key = Merb::Config[:session_secret_key]
+ base._session_secure = Merb::Config[:session_secure] || false
+ base._session_http_only = Merb::Config[:session_http_only] || false
end
module ClassMethods
@@ -246,7 +249,9 @@ def default_cookies
# :api: private
def set_session_cookie_value(value, options = {})
defaults = {}
- defaults[:expires] = Time.now + _session_expiry if _session_expiry > 0
+ defaults[:expires] = Time.now + _session_expiry if _session_expiry > 0
+ defaults[:secure] = _session_secure
+ defaults[:http_only] = _session_http_only
cookies.set_cookie(_session_id_key, value, defaults.merge(options))
end
alias :set_session_id_cookie :set_session_cookie_value
@@ -13,6 +13,7 @@ class FakeRequest < Request
def initialize(env = {}, req = StringIO.new)
env.environmentize_keys!
env['rack.input'] = req
+ @start = Time.now
super(DEFAULT_ENV.merge(env))
end
@@ -1,5 +1,5 @@
module Merb
VERSION = '1.1' unless defined?(Merb::VERSION)
- DM_VERSION = '0.9.11' unless defined?(Merb::DM_VERSION)
- DO_VERSION = '0.9.11' unless defined?(Merb::DO_VERSION)
+ DM_VERSION = '0.10.0' unless defined?(Merb::DM_VERSION)
+ DO_VERSION = '0.10.0' unless defined?(Merb::DO_VERSION)
end
@@ -11,6 +11,7 @@ def store_cookies
cookies[:foo] = 'bar'
cookies.set_cookie(:oldcookie, 'this is really old', :expires => Time.utc(2020))
cookies.set_cookie(:safecook, 'no-hackers-here', :secure => true)
+ cookies.set_cookie(:xsscook, 'only-through-http', :http_only => true)
end
def destroy_cookies
@@ -27,7 +27,7 @@
it "should set all the cookies for a request" do
controller = dispatch_to(Merb::Test::Fixtures::Controllers::CookiesController, :store_cookies)
- controller.headers['Set-Cookie'].length.should == 4
+ controller.headers['Set-Cookie'].length.should == 5
end
it "should set a simple cookie" do
@@ -54,7 +54,13 @@
it "should append secure to the end of the cookie header when marked as such" do
controller = dispatch_to(Merb::Test::Fixtures::Controllers::CookiesController, :store_cookies)
cookie = controller.headers['Set-Cookie'].sort[3]
- cookie.should match(/secure$/)
+ cookie.should match(/secure;$/)
+ end
+
+ it "should append HttpOnly to the end of the cookie header when marked as such" do
+ controller = dispatch_to(Merb::Test::Fixtures::Controllers::CookiesController, :store_cookies)
+ cookie = controller.headers['Set-Cookie'].sort[4]
+ cookie.should match(/HttpOnly;$/)
end
it "sets the Set-Cookie response header - and ignores blank options" do
@@ -150,6 +150,11 @@
describe Merb::Request, " misc" do
+ it "should contain the request start" do
+ request = fake_request
+ request.start.should be_instance_of(Time)
+ end
+
it "should know if a request is an XHR" do
request = fake_request({:http_x_requested_with => "XMLHttpRequest"})
request.should be_xhr
@@ -132,7 +132,9 @@ def process_form_attrs(attrs)
# Use a fake PUT if the object is not new, otherwise use the method
# passed in. Defaults to :post if no method is set.
standardized_object = ActionORM.for(@obj)
- method ||= (!standardized_object.nil? && standardized_object.new_record?) || (@obj.respond_to?(:new?) && @obj.new?) ? :post : :put
+
+ method ||= :post if standardized_object.nil?
+ method ||= standardized_object.new_record? || (@obj.respond_to?(:new?) && @obj.new?) ? :post : :put
attrs[:enctype] = "multipart/form-data" if attrs.delete(:multipart) || @multipart
@@ -0,0 +1,3 @@
+<%= form_for(:obj, :action => "/some/url") do %>
+Hello
+<% end =%>
@@ -188,6 +188,13 @@ class MyClass; end
form.should_not have_selector("input[type=hidden][name=_method]")
end
+ it "should use POST if the object passed in is nil" do
+ @c.instance_variable_set(:@obj, nil)
+ form = @c.render :advanced
+ form.should have_selector("form[method=post]")
+ form.should_not have_selector("input[type=hidden][value=put][name=_method]")
+ end
+
it "should support PUT if the object passed in is not a new_record? via a hidden field" do
form = @c.render :basic
form.should have_selector("form[method=post]")
@@ -103,7 +103,9 @@ def attach(file_or_files, filename = file_or_files.is_a?(File) ? File.basename(f
@mail.add_attachment_as *v
end
else
- raise ArgumentError, "You did not pass in a file. Instead, you sent a #{file_or_files.class}" if !file_or_files.is_a?(File)
+ if !file_or_files.is_a?(File) && !file_or_files.is_a?(StringIO)
+ raise ArgumentError, "You did not pass in a file. Instead, you sent a #{file_or_files.class}"
+ end
@mail.add_attachment_as(file_or_files, filename, type, headers)
end
end
@@ -89,6 +89,18 @@ def setup_test_mailer klass = TestMailer
attachments.last["headers"].should include("Content-ID: <license.txt>")
end
+ it "should be able to accept objects that respond to :read as attachments" do
+ setup_test_mailer
+ @m.attach StringIO.new('This is some dummy text'), 'readme', 'text/plain', 'Content-ID: <readme.txt>'
+ @m.deliver!
+ delivery = TestMailer.deliveries.last
+ attachments = delivery.instance_variable_get("@attachments")
+ attachments.size.should == 1
+ attachments.first["mimetype"].should eql("text/plain")
+ attachments.first["filename"].should eql("readme")
+ attachments.first["headers"].should include("Content-ID: <readme.txt>")
+ end
+
it "should be able to send mails via SMTP" do
setup_test_mailer TestSMTPMailer
Net::SMTP.stub!(:start).and_return(true)
@@ -17,7 +17,7 @@ GEM_VERSION = Merb::VERSION + PKG_BUILD
RELEASE_NAME = "REL #{GEM_VERSION}"
-GEM_DEPENDENCIES = [["dm-core", ">=0.9.5"], ["dm-migrations", ">=0.9.5"], ["merb-core", "~> #{GEM_VERSION}"], ["merb-actionorm", "~> #{GEM_VERSION}"]]
+GEM_DEPENDENCIES = [["dm-core", ">=0.10.0"], ["dm-migrations", ">=0.10.0"], ["merb-core", "~> #{GEM_VERSION}"], ["merb-actionorm", "~> #{GEM_VERSION}"]]
require "extlib/tasks/release"
@@ -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
@@ -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<Object> 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
@@ -1,9 +1,8 @@
if defined?(Merb::Plugins)
- dependency 'dm-core'
+ require 'dm-core'
require 'merb-actionorm'
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"
ActionORM.use :driver => :compliant, :for => DataMapper::Resource
@@ -21,6 +20,14 @@
Merb::Plugins.config[:merb_datamapper][:session_repository_name] = :default
end
+ module DataMapper
+ module Resource
+
+ # actionorm compliance
+ alias new_record? new?
+
+ end
+ end
class Merb::Orms::DataMapper::Connect < Merb::BootLoader
after BeforeAppLoads
@@ -39,7 +46,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
@@ -55,18 +62,15 @@ 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
@@ -88,21 +92,4 @@ def _call_action(*)
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? || ActionORM.for(self).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
Oops, something went wrong.

0 comments on commit 61e1e56

Please sign in to comment.