Skip to content

Commit

Permalink
Remove SessionHash inheritance from Hash
Browse files Browse the repository at this point in the history
Previous api provided by SessionHash was inconsistent. All methods
provided by Hash which were not rewritten in SessionHash were behaving
incorrectly when session was not loaded yet. For example, #replace, #each,
 #keep_if and many more. So by dropping Hash inheritance we provide
clean api with all methods working without regard to whether session was
loaded or not.
  • Loading branch information
brainopia committed Feb 18, 2012
1 parent 098d583 commit e5b4d96
Showing 1 changed file with 23 additions and 18 deletions.
41 changes: 23 additions & 18 deletions lib/rack/session/abstract/id.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,20 +20,17 @@ module Abstract

# SessionHash is responsible to lazily load the session from store.

class SessionHash < Hash
class SessionHash
attr_writer :id

def initialize(by, env)
super()
@by = by
@env = env
@loaded = false
@id_loaded = false
end

def id
return @id if @loaded or @id_loaded
@id_loaded = true
return @id if @loaded or instance_variable_defined?(:@id)
@id = @by.send(:extract_session_id, @env)
end

Expand All @@ -43,24 +40,26 @@ def options

def [](key)
load_for_read!
super(key.to_s)
@data[key.to_s]
end
alias :fetch :[]

def has_key?(key)
load_for_read!
super(key.to_s)
@data.has_key?(key.to_s)
end
alias :key? :has_key?
alias :include? :has_key?

def []=(key, value)
load_for_write!
super(key.to_s, value)
@data[key.to_s] = value
end
alias :store :[]=

def clear
load_for_write!
super
@data.clear
end

def destroy
Expand All @@ -70,29 +69,36 @@ def destroy

def to_hash
load_for_read!
Hash[self].delete_if { |k,v| v.nil? }
@data.dup
end

def update(hash)
load_for_write!
super(stringify_keys(hash))
@data.update(stringify_keys(hash))
end
alias :merge! :update

def replace(hash)
load_for_write!
@data.replace(stringify_keys(hash))
end

def delete(key)
load_for_write!
super(key.to_s)
@data.delete(key.to_s)
end

def inspect
if loaded?
super
@data.inspect
else
"#<#{self.class}:0x#{self.object_id.to_s(16)} not yet loaded>"
end
end

def exists?
return @exists if instance_variable_defined?(:@exists)
@data = {}
@exists = @by.send(:session_exists?, @env)
end

Expand All @@ -102,7 +108,7 @@ def loaded?

def empty?
load_for_read!
super
@data.empty?
end

private
Expand All @@ -117,7 +123,7 @@ def load_for_write!

def load!
@id, session = @by.send(:load_session, @env)
replace(stringify_keys(session))
@data = stringify_keys(session)
@loaded = true
end

Expand Down Expand Up @@ -297,7 +303,6 @@ def commit_session(env, status, headers, body)
options = session.options

if options[:drop] || options[:renew]
# if there is no session.id then we have nothing to destroy?!
session_id = destroy_session(env, session.id || generate_sid, options)
return [status, headers, body] unless session_id
end
Expand All @@ -306,9 +311,9 @@ def commit_session(env, status, headers, body)

session.send(:load!) unless loaded_session?(session)
session_id ||= session.id || generate_sid
session = session.to_hash
session_data = session.to_hash.delete_if { |k,v| v.nil? }

if not data = set_session(env, session_id, session, options)
if not data = set_session(env, session_id, session_data, options)
env["rack.errors"].puts("Warning! #{self.class.name} failed to save session. Content dropped.")
elsif options[:defer] and not options[:renew]
env["rack.errors"].puts("Defering cookie for #{session_id}") if $VERBOSE
Expand Down

0 comments on commit e5b4d96

Please sign in to comment.