objectified_sessions 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/.travis.yml +21 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +391 -0
- data/Rakefile +6 -0
- data/lib/objectified_session_generator.rb +139 -0
- data/lib/objectified_sessions/base.rb +299 -0
- data/lib/objectified_sessions/errors.rb +55 -0
- data/lib/objectified_sessions/field_definition.rb +105 -0
- data/lib/objectified_sessions/version.rb +3 -0
- data/lib/objectified_sessions.rb +157 -0
- data/objectified_sessions.gemspec +43 -0
- data/spec/objectified_sessions/helpers/controller_helper.rb +55 -0
- data/spec/objectified_sessions/helpers/exception_helpers.rb +20 -0
- data/spec/objectified_sessions/system/basic_system_spec.rb +135 -0
- data/spec/objectified_sessions/system/error_handling_system_spec.rb +217 -0
- data/spec/objectified_sessions/system/prefix_system_spec.rb +62 -0
- data/spec/objectified_sessions/system/retired_inactive_system_spec.rb +188 -0
- data/spec/objectified_sessions/system/setup_system_spec.rb +65 -0
- data/spec/objectified_sessions/system/strings_symbols_system_spec.rb +73 -0
- data/spec/objectified_sessions/system/unknown_data_system_spec.rb +65 -0
- data/spec/objectified_sessions/system/visibility_system_spec.rb +61 -0
- data/spec/objectified_sessions/unit/objectified_session_generator_spec.rb +121 -0
- data/spec/objectified_sessions/unit/objectified_sessions/base_spec.rb +484 -0
- data/spec/objectified_sessions/unit/objectified_sessions/errors_spec.rb +75 -0
- data/spec/objectified_sessions/unit/objectified_sessions/field_definition_spec.rb +138 -0
- data/spec/objectified_sessions/unit/objectified_sessions_spec.rb +149 -0
- metadata +120 -0
@@ -0,0 +1,138 @@
|
|
1
|
+
require 'objectified_sessions'
|
2
|
+
|
3
|
+
describe ObjectifiedSessions::FieldDefinition do
|
4
|
+
def klass
|
5
|
+
ObjectifiedSessions::FieldDefinition
|
6
|
+
end
|
7
|
+
|
8
|
+
before :each do
|
9
|
+
@session_class = double("session_class")
|
10
|
+
allow(@session_class).to receive(:kind_of?).with(Class).and_return(true)
|
11
|
+
|
12
|
+
@dmm = Module.new do
|
13
|
+
class << self
|
14
|
+
public :define_method, :private
|
15
|
+
end
|
16
|
+
end
|
17
|
+
allow(@session_class).to receive(:_dynamic_methods_module).with().and_return(@dmm)
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should normalize field names properly" do
|
21
|
+
lambda { klass.normalize_name(nil) }.should raise_error(ArgumentError)
|
22
|
+
lambda { klass.normalize_name(12345) }.should raise_error(ArgumentError)
|
23
|
+
|
24
|
+
klass.normalize_name(" fOo ").should == :fOo
|
25
|
+
klass.normalize_name(:' fOo ').should == :fOo
|
26
|
+
klass.normalize_name(:foo).should == :foo
|
27
|
+
klass.normalize_name("foo").should == :foo
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should validate its constructor arguments appropriately" do
|
31
|
+
lambda { klass.new(double("not_a_class"), :foo, { :type => :normal, :visibility => :private }) }.should raise_error(ArgumentError, /not_a_class/i)
|
32
|
+
lambda { klass.new(@session_class, 12345, { :type => :normal, :visibility => :private }) }.should raise_error(ArgumentError, /12345/i)
|
33
|
+
lambda { klass.new(@session_class, :foo, { :type => :whatever, :visibility => :private }) }.should raise_error(ArgumentError, /whatever/i)
|
34
|
+
lambda { klass.new(@session_class, :foo, { :visibility => :private }) }.should raise_error(ArgumentError, /:type/i)
|
35
|
+
lambda { klass.new(@session_class, :foo, { :type => :normal, :visibility => :whatever }) }.should raise_error(ArgumentError, /whatever/i)
|
36
|
+
lambda { klass.new(@session_class, :foo, { :type => :normal }) }.should raise_error(ArgumentError, /:visibility/i)
|
37
|
+
lambda { klass.new(@session_class, :foo, { :type => :normal, :visibility => :public, :foo => :bar }) }.should raise_error(ArgumentError, /foo/i)
|
38
|
+
lambda { klass.new(@session_class, :foo, { :type => :normal, :visibility => :public, :storage => 12345 }) }.should raise_error(ArgumentError, /12345/i)
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should return the right storage name" do
|
42
|
+
klass.new(@session_class, :foo, { :type => :normal, :visibility => :public }).storage_name.should == 'foo'
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should return the right storage name if aliased" do
|
46
|
+
klass.new(@session_class, :foo, { :type => :normal, :visibility => :public, :storage => :bar }).storage_name.should == 'bar'
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should return the right value for #delete_data_with_storage_name?" do
|
50
|
+
klass.new(@session_class, :foo, { :type => :normal, :visibility => :public }).delete_data_with_storage_name?.should_not be
|
51
|
+
klass.new(@session_class, :foo, { :type => :inactive, :visibility => :public }).delete_data_with_storage_name?.should_not be
|
52
|
+
klass.new(@session_class, :foo, { :type => :retired, :visibility => :public }).delete_data_with_storage_name?.should be
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should return the right value for #allow_access_to_data?" do
|
56
|
+
klass.new(@session_class, :foo, { :type => :normal, :visibility => :public }).allow_access_to_data?.should be
|
57
|
+
klass.new(@session_class, :foo, { :type => :inactive, :visibility => :public }).allow_access_to_data?.should_not be
|
58
|
+
klass.new(@session_class, :foo, { :type => :retired, :visibility => :public }).allow_access_to_data?.should_not be
|
59
|
+
end
|
60
|
+
|
61
|
+
context "with dynamic-methods module testing" do
|
62
|
+
before :each do
|
63
|
+
dmm = @dmm
|
64
|
+
@underlying_session = double("underlying_session")
|
65
|
+
|
66
|
+
@dmm_class = Class.new do
|
67
|
+
include dmm
|
68
|
+
|
69
|
+
def initialize(h)
|
70
|
+
@h = h
|
71
|
+
end
|
72
|
+
|
73
|
+
def [](x)
|
74
|
+
@h[x]
|
75
|
+
end
|
76
|
+
|
77
|
+
def []=(x, y)
|
78
|
+
@h[x] = y
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
@instance = @dmm_class.new(@underlying_session)
|
83
|
+
end
|
84
|
+
|
85
|
+
it "should create methods on the dynamic-methods module for a normal field" do
|
86
|
+
field = klass.new(@session_class, :foo, { :type => :normal, :visibility => :public })
|
87
|
+
|
88
|
+
expect(@underlying_session).to receive(:[]).once.with(:foo).and_return(:xxx)
|
89
|
+
@instance.foo.should == :xxx
|
90
|
+
|
91
|
+
expect(@underlying_session).to receive(:[]=).once.with(:foo, :zzz).and_return(:yyy)
|
92
|
+
(@instance.foo = :zzz).should == :zzz
|
93
|
+
end
|
94
|
+
|
95
|
+
it "should downcase the field name on the dynamic-methods module for a normal field" do
|
96
|
+
field = klass.new(@session_class, :FoO, { :type => :normal, :visibility => :public })
|
97
|
+
|
98
|
+
expect(@underlying_session).to receive(:[]).once.with(:FoO).and_return(:xxx)
|
99
|
+
@instance.foo.should == :xxx
|
100
|
+
|
101
|
+
expect(@underlying_session).to receive(:[]=).once.with(:FoO, :zzz).and_return(:yyy)
|
102
|
+
(@instance.foo = :zzz).should == :zzz
|
103
|
+
end
|
104
|
+
|
105
|
+
it "should create private methods on the dynamic-methods module for a normal field if marked as private" do
|
106
|
+
field = klass.new(@session_class, :foo, { :type => :normal, :visibility => :private })
|
107
|
+
|
108
|
+
@instance.respond_to?(:foo).should_not be
|
109
|
+
lambda { @instance.foo }.should raise_error(NoMethodError)
|
110
|
+
@instance.respond_to?(:foo=).should_not be
|
111
|
+
lambda { @instance.foo = 123 }.should raise_error(NoMethodError)
|
112
|
+
|
113
|
+
expect(@underlying_session).to receive(:[]).once.with(:foo).and_return(:xxx)
|
114
|
+
@instance.send(:foo).should == :xxx
|
115
|
+
|
116
|
+
expect(@underlying_session).to receive(:[]=).once.with(:foo, :zzz).and_return(:yyy)
|
117
|
+
(@instance.send(:foo=, :zzz)).should == :zzz
|
118
|
+
end
|
119
|
+
|
120
|
+
it "should not create methods on the dynamic-methods module for an inactive field" do
|
121
|
+
field = klass.new(@session_class, :foo, { :type => :inactive, :visibility => :public })
|
122
|
+
|
123
|
+
@instance.respond_to?(:foo).should_not be
|
124
|
+
lambda { @instance.send(:foo) }.should raise_error(NoMethodError)
|
125
|
+
@instance.respond_to?(:foo=).should_not be
|
126
|
+
lambda { @instance.send(:foo=, 123) }.should raise_error(NoMethodError)
|
127
|
+
end
|
128
|
+
|
129
|
+
it "should not create methods on the dynamic-methods module for a retired field" do
|
130
|
+
field = klass.new(@session_class, :foo, { :type => :retired, :visibility => :public })
|
131
|
+
|
132
|
+
@instance.respond_to?(:foo).should_not be
|
133
|
+
lambda { @instance.send(:foo) }.should raise_error(NoMethodError)
|
134
|
+
@instance.respond_to?(:foo=).should_not be
|
135
|
+
lambda { @instance.send(:foo=, 123) }.should raise_error(NoMethodError)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
@@ -0,0 +1,149 @@
|
|
1
|
+
require 'objectified_sessions'
|
2
|
+
require 'objectified_sessions/helpers/exception_helpers'
|
3
|
+
|
4
|
+
describe ObjectifiedSessions do
|
5
|
+
include ObjectifiedSessions::Helpers::ExceptionHelpers
|
6
|
+
|
7
|
+
describe "session_class" do
|
8
|
+
before :each do
|
9
|
+
ObjectifiedSessions.instance_variable_set("@session_class", nil)
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should return the default name, by default" do
|
13
|
+
ObjectifiedSessions.session_class.should == "Objsession"
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should accept a String and return that" do
|
17
|
+
ObjectifiedSessions.session_class = "Foo"
|
18
|
+
ObjectifiedSessions.session_class.should == "Foo"
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should accept a Symbol and return a String" do
|
22
|
+
ObjectifiedSessions.session_class = :Foo
|
23
|
+
ObjectifiedSessions.session_class.should == 'Foo'
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should camelize its input" do
|
27
|
+
ObjectifiedSessions.session_class = "foo/bar_baz"
|
28
|
+
ObjectifiedSessions.session_class.should == "Foo::BarBaz"
|
29
|
+
|
30
|
+
ObjectifiedSessions.session_class = :"foo/bar_baz"
|
31
|
+
ObjectifiedSessions.session_class.should == "Foo::BarBaz"
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should accept a Class and return that" do
|
35
|
+
class FooBar; end
|
36
|
+
|
37
|
+
ObjectifiedSessions.session_class = FooBar
|
38
|
+
ObjectifiedSessions.session_class.should == FooBar
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe "_create_new_objsession" do
|
43
|
+
before :each do
|
44
|
+
@underlying_session = double("underlying_session")
|
45
|
+
|
46
|
+
@session_class_instance = double("session_class_instance")
|
47
|
+
|
48
|
+
@session_class = Class.new(::ObjectifiedSessions::Base)
|
49
|
+
allow(@session_class).to receive(:new).once.with(@underlying_session).and_return(@session_class_instance)
|
50
|
+
allow(@session_class).to receive(:name).with().and_return("scname")
|
51
|
+
|
52
|
+
allow(@session_class_instance).to receive(:kind_of?).with(::ObjectifiedSessions::Base).and_return(true)
|
53
|
+
|
54
|
+
ObjectifiedSessions.session_class = @session_class
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should happily return a new instance of a valid class, and return new ones each time" do
|
58
|
+
ObjectifiedSessions._create_new_objsession(@underlying_session).should be(@session_class_instance)
|
59
|
+
|
60
|
+
new_instance = double("session_class_instance_2")
|
61
|
+
allow(new_instance).to receive(:kind_of?).with(::ObjectifiedSessions::Base).and_return(true)
|
62
|
+
|
63
|
+
expect(@session_class).to receive(:new).once.with(@underlying_session).and_return(new_instance)
|
64
|
+
ObjectifiedSessions._create_new_objsession(@underlying_session).should be(new_instance)
|
65
|
+
end
|
66
|
+
|
67
|
+
it "should pass through the underlying session correctly" do
|
68
|
+
ObjectifiedSessions._create_new_objsession(@underlying_session).should be(@session_class_instance)
|
69
|
+
|
70
|
+
session_class_instance_2 = double("session_class_instance_2")
|
71
|
+
allow(session_class_instance_2).to receive(:kind_of?).with(::ObjectifiedSessions::Base).and_return(true)
|
72
|
+
|
73
|
+
underlying_session_2 = double("underlying_session_2")
|
74
|
+
allow(@session_class).to receive(:new).once.with(underlying_session_2).and_return(session_class_instance_2)
|
75
|
+
|
76
|
+
ObjectifiedSessions._create_new_objsession(underlying_session_2).should be(session_class_instance_2)
|
77
|
+
end
|
78
|
+
|
79
|
+
it "should fail with a nice exception if #new fails" do
|
80
|
+
class FooError < StandardError; end
|
81
|
+
|
82
|
+
allow(@session_class).to receive(:new).once.with(@underlying_session) do |*args|
|
83
|
+
raise FooError, "kaboomba"
|
84
|
+
end
|
85
|
+
|
86
|
+
e = capture_exception(ObjectifiedSessions::Errors::CannotCreateSessionError) { ObjectifiedSessions._create_new_objsession(@underlying_session) }
|
87
|
+
e.message.should match(/fooerror/i)
|
88
|
+
e.message.should match(/kaboomba/i)
|
89
|
+
e.message.should match(/scname/i)
|
90
|
+
end
|
91
|
+
|
92
|
+
it "should fail with a nice exception if the returned instance isn't of the right type" do
|
93
|
+
allow(@session_class_instance).to receive(:kind_of?).with(::ObjectifiedSessions::Base).and_return(false)
|
94
|
+
allow(@session_class_instance).to receive(:class).with().and_return(@session_class)
|
95
|
+
allow(@session_class_instance).to receive(:inspect).with().and_return("sciinspect")
|
96
|
+
|
97
|
+
e = capture_exception(ObjectifiedSessions::Errors::CannotCreateSessionError) { ObjectifiedSessions._create_new_objsession(@underlying_session) }
|
98
|
+
e.message.should match(/scname/i)
|
99
|
+
e.message.should match(/sciinspect/i)
|
100
|
+
end
|
101
|
+
|
102
|
+
context "with constantization needed" do
|
103
|
+
before :each do
|
104
|
+
@class_name_string = "foo/bar_baz"
|
105
|
+
allow(@class_name_string).to receive(:to_s).with().and_return(@class_name_string)
|
106
|
+
|
107
|
+
@underscored_class_name_string = "bonko"
|
108
|
+
|
109
|
+
@camelized_class_name_string = "Foo::BarBaz"
|
110
|
+
allow(@class_name_string).to receive(:camelize).with().and_return(@camelized_class_name_string)
|
111
|
+
allow(@camelized_class_name_string).to receive(:constantize).once.with().and_return(@session_class)
|
112
|
+
allow(@camelized_class_name_string).to receive(:underscore).with().and_return(@underscored_class_name_string)
|
113
|
+
|
114
|
+
ObjectifiedSessions.session_class = @class_name_string
|
115
|
+
end
|
116
|
+
|
117
|
+
it "should require paths to classes, convert between underscored and camelized, and call #constantize properly" do
|
118
|
+
expect(::ObjectifiedSessions).to receive(:require).once.with(@underscored_class_name_string)
|
119
|
+
ObjectifiedSessions._create_new_objsession(@underlying_session).should be(@session_class_instance)
|
120
|
+
end
|
121
|
+
|
122
|
+
it "should raise an error if the class can't be #constantize'd" do
|
123
|
+
expect(::ObjectifiedSessions).to receive(:require).once.with(@underscored_class_name_string)
|
124
|
+
allow(@camelized_class_name_string).to receive(:constantize).once.with() do |*args|
|
125
|
+
raise NameError, "noway"
|
126
|
+
end
|
127
|
+
|
128
|
+
e = capture_exception(NameError) { ObjectifiedSessions._create_new_objsession(@underlying_session) }
|
129
|
+
e.message.should match(/noway/)
|
130
|
+
e.message.should match(/#{@camelized_class_name_string}/)
|
131
|
+
end
|
132
|
+
|
133
|
+
it "should include a LoadError, if there is one" do
|
134
|
+
expect(::ObjectifiedSessions).to receive(:require).once.with(@underscored_class_name_string) do |*args|
|
135
|
+
raise LoadError, "blahblahload"
|
136
|
+
end
|
137
|
+
|
138
|
+
allow(@camelized_class_name_string).to receive(:constantize).once.with() do |*args|
|
139
|
+
raise NameError, "noway"
|
140
|
+
end
|
141
|
+
|
142
|
+
e = capture_exception(NameError) { ObjectifiedSessions._create_new_objsession(@underlying_session) }
|
143
|
+
e.message.should match(/noway/)
|
144
|
+
e.message.should match(/#{@camelized_class_name_string}/)
|
145
|
+
e.message.should match(/blahblahload/)
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
metadata
ADDED
@@ -0,0 +1,120 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: objectified_sessions
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Andrew Geweke
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2013-12-29 00:00:00 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: bundler
|
16
|
+
prerelease: false
|
17
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: "1.3"
|
22
|
+
type: :development
|
23
|
+
version_requirements: *id001
|
24
|
+
- !ruby/object:Gem::Dependency
|
25
|
+
name: rake
|
26
|
+
prerelease: false
|
27
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
28
|
+
requirements:
|
29
|
+
- &id005
|
30
|
+
- ">="
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: "0"
|
33
|
+
type: :development
|
34
|
+
version_requirements: *id002
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: rspec
|
37
|
+
prerelease: false
|
38
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
39
|
+
requirements:
|
40
|
+
- - ~>
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: "2.14"
|
43
|
+
type: :development
|
44
|
+
version_requirements: *id003
|
45
|
+
- !ruby/object:Gem::Dependency
|
46
|
+
name: rails
|
47
|
+
prerelease: false
|
48
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
49
|
+
requirements:
|
50
|
+
- - ">="
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: "3.0"
|
53
|
+
- - <=
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: 4.99.99
|
56
|
+
type: :runtime
|
57
|
+
version_requirements: *id004
|
58
|
+
description: Encapsulate and carefully manage access to your Rails session.
|
59
|
+
email:
|
60
|
+
- andrew@geweke.org
|
61
|
+
executables: []
|
62
|
+
|
63
|
+
extensions: []
|
64
|
+
|
65
|
+
extra_rdoc_files: []
|
66
|
+
|
67
|
+
files:
|
68
|
+
- .gitignore
|
69
|
+
- .travis.yml
|
70
|
+
- Gemfile
|
71
|
+
- LICENSE.txt
|
72
|
+
- README.md
|
73
|
+
- Rakefile
|
74
|
+
- lib/objectified_session_generator.rb
|
75
|
+
- lib/objectified_sessions.rb
|
76
|
+
- lib/objectified_sessions/base.rb
|
77
|
+
- lib/objectified_sessions/errors.rb
|
78
|
+
- lib/objectified_sessions/field_definition.rb
|
79
|
+
- lib/objectified_sessions/version.rb
|
80
|
+
- objectified_sessions.gemspec
|
81
|
+
- spec/objectified_sessions/helpers/controller_helper.rb
|
82
|
+
- spec/objectified_sessions/helpers/exception_helpers.rb
|
83
|
+
- spec/objectified_sessions/system/basic_system_spec.rb
|
84
|
+
- spec/objectified_sessions/system/error_handling_system_spec.rb
|
85
|
+
- spec/objectified_sessions/system/prefix_system_spec.rb
|
86
|
+
- spec/objectified_sessions/system/retired_inactive_system_spec.rb
|
87
|
+
- spec/objectified_sessions/system/setup_system_spec.rb
|
88
|
+
- spec/objectified_sessions/system/strings_symbols_system_spec.rb
|
89
|
+
- spec/objectified_sessions/system/unknown_data_system_spec.rb
|
90
|
+
- spec/objectified_sessions/system/visibility_system_spec.rb
|
91
|
+
- spec/objectified_sessions/unit/objectified_session_generator_spec.rb
|
92
|
+
- spec/objectified_sessions/unit/objectified_sessions/base_spec.rb
|
93
|
+
- spec/objectified_sessions/unit/objectified_sessions/errors_spec.rb
|
94
|
+
- spec/objectified_sessions/unit/objectified_sessions/field_definition_spec.rb
|
95
|
+
- spec/objectified_sessions/unit/objectified_sessions_spec.rb
|
96
|
+
homepage: https://github.com/ageweke/objectified_sessions
|
97
|
+
licenses:
|
98
|
+
- MIT
|
99
|
+
metadata: {}
|
100
|
+
|
101
|
+
post_install_message:
|
102
|
+
rdoc_options: []
|
103
|
+
|
104
|
+
require_paths:
|
105
|
+
- lib
|
106
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- *id005
|
109
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
110
|
+
requirements:
|
111
|
+
- *id005
|
112
|
+
requirements: []
|
113
|
+
|
114
|
+
rubyforge_project:
|
115
|
+
rubygems_version: 2.0.14
|
116
|
+
signing_key:
|
117
|
+
specification_version: 4
|
118
|
+
summary: Encapsulate and carefully manage access to your Rails session.
|
119
|
+
test_files: []
|
120
|
+
|