objectified_sessions 1.0.0 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA512:
3
- data.tar.gz: bff5500fbeed0f446febd09e23819d2b143d3592d3c957bcaedc836786d5bfdbb8c393c0659278f9b2c96fb2fd16cf1b81bddacbda97b9233c61dad7b5d0559b
4
- metadata.gz: f24564e7778790033ba6307ec1c339e66e9ec8d87aff6c6b0bcb833b9a47793c402a29bc0f9ccc1bc4e57782b16bea70276f45c4ccbf6e74d90cddfa241fc724
5
2
  SHA1:
6
- data.tar.gz: a7f49fbd4fd51d8854823f9fd4c7f01041ce022b
7
- metadata.gz: 557be601d1396648ece538afa384e65cc2f2ebe7
3
+ metadata.gz: 3ddbe03428f2939faa0bae986029767c4bcfa112
4
+ data.tar.gz: 8f562df0cc6716bcf4262d413a54375e1eca5810
5
+ SHA512:
6
+ metadata.gz: f10073ecd7bf153818d79d20d8470641e1f84c9493b8e2ec67f7e61fe1a38ec16ebeee57416b2abe39e172e08cc398a341a0e332b6d328d65940b0db69c83157
7
+ data.tar.gz: 39f589ecdb7e1422a4651843974c4c35bf10d720a9f3353eee551578b9d06fe12485a37e4f108410b3308526be2ded60c14b562671c73e7148314d2a0b7e7ed2
data/.travis.yml CHANGED
@@ -3,10 +3,11 @@ before_install:
3
3
  - gem update --system 2.1.11
4
4
  - gem --version
5
5
  rvm:
6
+ - "2.1.0"
6
7
  - "2.0.0"
7
8
  - "1.9.3"
8
9
  - "1.8.7"
9
- - "jruby-1.7.4"
10
+ - "jruby-1.7.9"
10
11
  env:
11
12
  - OBJECTIFIED_SESSIONS_RAILS_TEST_VERSION=3.0.20
12
13
  - OBJECTIFIED_SESSIONS_RAILS_TEST_VERSION=3.1.12
data/README.md CHANGED
@@ -36,6 +36,14 @@ And, best of all, you can migrate to ObjectifiedSessions completely incrementall
36
36
  traditional session-handling code. You can migrate call site by call site, at your own pace; there's no need to
37
37
  migrate all at once, or even migrate all code for a given session key all at once.
38
38
 
39
+ ObjectifiedSessions supports:
40
+
41
+ * Ruby 1.8.7, 1.9.3, 2.0.0, 2.1.0, or JRuby 1.7.9
42
+ * Rails 3.0.20, 3.1.12, 3.2.16, and 4.0.2.
43
+
44
+ These are, however, just the versions it's tested against; ObjectifiedSessions contains no code that should be at all
45
+ particularly dependent on exact Ruby or Rails versions, and should be compatible with a broad set of versions.
46
+
39
47
  Current build status: ![Current Build Status](https://api.travis-ci.org/ageweke/objectified_sessions.png?branch=master)
40
48
 
41
49
  ## Installation
@@ -199,6 +207,30 @@ to disappear_. (Hopefully this is obvious; this is because ObjectifiedSessions w
199
207
  key for that data.) It is, however, safe to do the reverse, by renaming a field and setting its storage alias to
200
208
  be its old name.
201
209
 
210
+ #### Value Types
211
+
212
+ By default, ObjectifiedSessions will let you store any arbitrary Ruby object in the session — just like the
213
+ default Rails session support will. However, this can cause significant issues, particularly with sessions; if you
214
+ put, for example, a User model into the session, and then pull it out later (perhaps months later!), any attributes
215
+ you added in the mean time will simply not be present. This is dangerous.
216
+
217
+ If you add this to your session class:
218
+
219
+ allowed_value_types :primitive
220
+
221
+ ...then you will receive an `ArgumentError` if you try to store anything in the session other than `nil`, `true`,
222
+ `false`, a `String`, a `Symbol`, a `Numeric` (including both integers and floating-point numbers), or a `Time`.
223
+
224
+ If you instead set this as follows:
225
+
226
+ allowed_value_types :primitive_and_compound
227
+
228
+ ...then the rules are relaxed to also include `Array`s and `Hash`es, as long as their constituent elements are valid
229
+ simple scalars or themselves `Array`s or `Hash`es. (In other words, you can nest these data types as deeply as you
230
+ would like.)
231
+
232
+ If, for some reason, you need it, `allowed_value_types :anything` is the default setting.
233
+
202
234
  #### Retiring Fields
203
235
 
204
236
  Let's say you (probably wisely) stop supporting custom background colors, and remove that field. So far, so good.
@@ -389,3 +421,14 @@ for Gems, plugins, or other code that may be using the session without your know
389
421
  3. Commit your changes (`git commit -am 'Add some feature'`)
390
422
  4. Push to the branch (`git push origin my-new-feature`)
391
423
  5. Create new Pull Request
424
+
425
+ ### Running Specs
426
+
427
+ ObjectifiedSessions is very thoroughly tested, including both system specs (that test the entire system at once) and
428
+ unit specs (that test each class individually).
429
+
430
+ To run these specs:
431
+
432
+ 1. `cd objectified_sessions` (the root of the gem).
433
+ 2. `bundle install`
434
+ 3. `bundle exec rspec spec` will run all specs. (Or just `rake`.)
@@ -116,10 +116,51 @@ module ObjectifiedSessions
116
116
  # ObjectifiedSessions::Errors::NoSuchFieldError.
117
117
  def []=(field_name, new_value)
118
118
  field = self.class._ensure_has_field_named(field_name)
119
+ validate_new_value_type!(new_value)
119
120
  _objectified_sessions_underlying_session(true)[field.storage_name] = new_value
120
121
  new_value
121
122
  end
122
123
 
124
+ # Validates that a new value being assigned to a field is acceptable, according to whatever #allowed_value_types
125
+ # setting you've set on this class. Does nothing if the data is valid; raises ArgumentError if it's invalid.
126
+ def validate_new_value_type!(new_value)
127
+ send("validate_new_value_type_for_#{self.class.allowed_value_types}!", new_value)
128
+ end
129
+
130
+ # Validates that a new value being assigned to a field is acceptable, according to the :anything
131
+ # #allowed_value_types setting. This allows storing anything, so this method is a no-op.
132
+ def validate_new_value_type_for_anything!(new_value)
133
+ # ok
134
+ end
135
+
136
+ # Validates that a new value being assigned to a field is acceptable, according to the :primitive
137
+ # #allowed_value_types setting. This raises an exception if passed anything but a simple scalar.
138
+ def validate_new_value_type_for_primitive!(new_value)
139
+ case new_value
140
+ when String, Symbol, Numeric, Time, true, false, nil then true
141
+ else
142
+ raise ArgumentError, "You've asked your ObjectifiedSession to only allow values of scalar types, but you're trying to store this: #{new_value.inspect}"
143
+ end
144
+ end
145
+
146
+ # Validates that a new value being assigned to a field is acceptable, according to the :primitive_and_compound
147
+ # #allowed_value_types setting. This does recursive examination of Arrays and Hashes. Raises an ArgumentError
148
+ # if there's an invalid value present.
149
+ def validate_new_value_type_for_primitive_and_compound!(new_value)
150
+ case new_value
151
+ when String, Symbol, Numeric, Time, true, false, nil then true
152
+ when Array then
153
+ new_value.each { |x| validate_new_value_type_for_primitive_and_compound!(x) }
154
+ when Hash then
155
+ new_value.each do |k,v|
156
+ validate_new_value_type_for_primitive_and_compound!(k)
157
+ validate_new_value_type_for_primitive_and_compound!(v)
158
+ end
159
+ else
160
+ raise ArgumentError, "You've asked your ObjectifiedSession to only allow values of scalar types, plus Arrays and Hashes, but you're trying to store this (possibly nested): #{new_value.inspect}"
161
+ end
162
+ end
163
+
123
164
  DYNAMIC_METHODS_MODULE_NAME = :ObjectifiedSessionsDynamicMethods
124
165
 
125
166
  class << self
@@ -204,6 +245,27 @@ module ObjectifiedSessions
204
245
  end
205
246
  end
206
247
 
248
+ ALLOWED_ALLOWED_VALUE_TYPES = %w{anything primitive_and_compound primitive}.map { |x| x.to_sym }
249
+
250
+ # Sets the allowed value types on this class, or returns the current setting if no argument is supplied.
251
+ # The valid settings are:
252
+ #
253
+ # [:anything] All values are allowed, including arbitrary Ruby objects.
254
+ # [:primitive] Only primitive, simple scalars are allowed: nil, true, false, Strings, Symbols, Numerics (including
255
+ # both integer and floating-point numbers), and Times. Arrays and Hashes are not allowed.
256
+ # [:primitive_and_compound] All primitive scalars, plus Arrays and Hashes composed entirely of primitive
257
+ # scalars, plus other Arrays and Hashes, are allowed.
258
+ def allowed_value_types(allowed = nil)
259
+ if allowed
260
+ allowed = allowed.to_s.strip.downcase.to_sym
261
+ raise ArgumentError, "Invalid value for allowed_value_types: #{allowed.inspect}; we allow: #{ALLOWED_ALLOWED_VALUE_TYPES.inspect}" unless ALLOWED_ALLOWED_VALUE_TYPES.include?(allowed)
262
+
263
+ @allowed_value_types = allowed
264
+ end
265
+
266
+ @allowed_value_types ||= :anything
267
+ end
268
+
207
269
  # Sets the prefix. If a prefix is set, then all field data is taken from (and stored into) a Hash bound to this
208
270
  # prefix within the session, rather than directly in the session; this segregates all your ObjectifiedSession
209
271
  # data from other usage of the session. This is not generally necessary, but can be useful in certain situations.
@@ -1,3 +1,3 @@
1
1
  module ObjectifiedSessions
2
- VERSION = "1.0.0"
2
+ VERSION = "1.0.1"
3
3
  end
@@ -0,0 +1,176 @@
1
+ require 'objectified_sessions'
2
+ require "objectified_sessions/helpers/controller_helper"
3
+ require "objectified_sessions/helpers/exception_helpers"
4
+
5
+ describe "ObjectifiedSessions storage types" do
6
+ include ObjectifiedSessions::Helpers::ControllerHelper
7
+ include ObjectifiedSessions::Helpers::ExceptionHelpers
8
+
9
+ before :each do
10
+ set_new_controller_instance
11
+ end
12
+
13
+ it "should have an object at #objsession, even with an empty class" do
14
+ define_objsession_class { }
15
+ @controller_instance.objsession.should be
16
+ end
17
+
18
+ it "should, by default, allow storing anything in the session" do
19
+ define_objsession_class { field :foo }
20
+
21
+ some_class = Class.new
22
+ some_object = some_class.new
23
+ some_object.instance_variable_set("@bar", 345)
24
+ some_object.instance_variable_set("@baz", /yo/)
25
+
26
+ expect(@underlying_session).to receive(:[]=).once.with('foo', some_object)
27
+ @controller_instance.objsession.foo = some_object
28
+ end
29
+
30
+ it "should allow storing anything in the session if explicitly told to" do
31
+ define_objsession_class do
32
+ field :foo
33
+ allowed_value_types :anything
34
+ end
35
+
36
+ some_class = Class.new
37
+ some_object = some_class.new
38
+ some_object.instance_variable_set("@bar", 345)
39
+ some_object.instance_variable_set("@baz", /yo/)
40
+
41
+ expect(@underlying_session).to receive(:[]=).once.with('foo', some_object)
42
+ @controller_instance.objsession.foo = some_object
43
+ end
44
+
45
+ describe ":primitive_and_compound" do
46
+ before :each do
47
+ define_objsession_class do
48
+ field :foo
49
+ field :bar
50
+
51
+ allowed_value_types :primitive_and_compound
52
+ end
53
+ end
54
+
55
+ it "should allow storing scalars" do
56
+ expect(@underlying_session).to receive(:[]=).once.with('foo', "foobar")
57
+ expect { @controller_instance.objsession.foo = "foobar" }.not_to raise_error
58
+
59
+ expect(@underlying_session).to receive(:[]=).once.with('bar', 134832.32)
60
+ expect { @controller_instance.objsession.bar = 134832.32 }.not_to raise_error
61
+
62
+ expect(@underlying_session).to receive(:[]=).once.with('foo', true)
63
+ expect { @controller_instance.objsession.foo = true }.not_to raise_error
64
+
65
+ expect(@underlying_session).to receive(:[]=).once.with('bar', false)
66
+ expect { @controller_instance.objsession.bar = false }.not_to raise_error
67
+
68
+ expect(@underlying_session).to receive(:[]=).once.with('foo', nil)
69
+ expect { @controller_instance.objsession.foo = nil }.not_to raise_error
70
+
71
+ expect(@underlying_session).to receive(:[]=).once.with('foo', :baz)
72
+ expect { @controller_instance.objsession.foo = :baz }.not_to raise_error
73
+
74
+ t = Time.now
75
+ expect(@underlying_session).to receive(:[]=).once.with('foo', t)
76
+ expect { @controller_instance.objsession.foo = t }.not_to raise_error
77
+ end
78
+
79
+ it "should allow storing Arrays of scalars" do
80
+ expect(@underlying_session).to receive(:[]=).once.with('foo', [ 3, 'foo', :zap ])
81
+ expect { @controller_instance.objsession.foo = [ 3, 'foo', :zap ] }.not_to raise_error
82
+ end
83
+
84
+ it "should allow storing Hashes of scalars" do
85
+ expect(@underlying_session).to receive(:[]=).once.with('foo', { :one => 1, 'two' => 2 })
86
+ expect { @controller_instance.objsession.foo = { :one => 1, 'two' => 2 } }.not_to raise_error
87
+ end
88
+
89
+ it "should allow storing compound Arrays" do
90
+ expect(@underlying_session).to receive(:[]=).once.with('foo', [ 3, [ 2, 4 ], { 'foo' => 'bar' } ])
91
+ expect { @controller_instance.objsession.foo = [ 3, [ 2, 4 ], { 'foo' => 'bar' } ] }.not_to raise_error
92
+ end
93
+
94
+ it "should allow storing compound Hashes" do
95
+ expect(@underlying_session).to receive(:[]=).once.with('foo', { [ 1, 2 ] => 'onetwo', 3 => { :bar => [ :foo, 'baz' ] } })
96
+ expect { @controller_instance.objsession.foo = { [ 1, 2 ] => 'onetwo', 3 => { :bar => [ :foo, 'baz' ] } } }.not_to raise_error
97
+ end
98
+
99
+ it "should not allow storing invalid scalars" do
100
+ expect { @controller_instance.objsession.foo = /yo/ }.to raise_error(ArgumentError)
101
+ end
102
+
103
+ it "should not allow storing invalid scalars inside an Array" do
104
+ expect { @controller_instance.objsession.foo = [ 1, 2, /yo/ ] }.to raise_error(ArgumentError)
105
+ end
106
+
107
+ it "should not allow storing invalid scalars inside a Hash" do
108
+ expect { @controller_instance.objsession.foo = { :foo => /yo/ } }.to raise_error(ArgumentError)
109
+ expect { @controller_instance.objsession.foo = { /yo/ => :foo } }.to raise_error(ArgumentError)
110
+ end
111
+ end
112
+
113
+ describe ":primitive" do
114
+ before :each do
115
+ define_objsession_class do
116
+ field :foo
117
+ field :bar
118
+
119
+ allowed_value_types :primitive
120
+ end
121
+ end
122
+
123
+ it "should allow storing scalars" do
124
+ expect(@underlying_session).to receive(:[]=).once.with('foo', "foobar")
125
+ expect { @controller_instance.objsession.foo = "foobar" }.not_to raise_error
126
+
127
+ expect(@underlying_session).to receive(:[]=).once.with('bar', 134832.32)
128
+ expect { @controller_instance.objsession.bar = 134832.32 }.not_to raise_error
129
+
130
+ expect(@underlying_session).to receive(:[]=).once.with('foo', true)
131
+ expect { @controller_instance.objsession.foo = true }.not_to raise_error
132
+
133
+ expect(@underlying_session).to receive(:[]=).once.with('bar', false)
134
+ expect { @controller_instance.objsession.bar = false }.not_to raise_error
135
+
136
+ expect(@underlying_session).to receive(:[]=).once.with('foo', nil)
137
+ expect { @controller_instance.objsession.foo = nil }.not_to raise_error
138
+
139
+ expect(@underlying_session).to receive(:[]=).once.with('foo', :baz)
140
+ expect { @controller_instance.objsession.foo = :baz }.not_to raise_error
141
+
142
+ t = Time.now
143
+ expect(@underlying_session).to receive(:[]=).once.with('foo', t)
144
+ expect { @controller_instance.objsession.foo = t }.not_to raise_error
145
+ end
146
+
147
+ it "should not allow storing Arrays of scalars" do
148
+ expect { @controller_instance.objsession.foo = [ 3, 'foo', :zap ] }.to raise_error(ArgumentError)
149
+ end
150
+
151
+ it "should not allow storing Hashes of scalars" do
152
+ expect { @controller_instance.objsession.foo = { :one => 1, 'two' => 2 } }.to raise_error(ArgumentError)
153
+ end
154
+
155
+ it "should not allow storing compound Arrays" do
156
+ expect { @controller_instance.objsession.foo = [ 3, [ 2, 4 ], { 'foo' => 'bar' } ] }.to raise_error(ArgumentError)
157
+ end
158
+
159
+ it "should not allow storing compound Hashes" do
160
+ expect { @controller_instance.objsession.foo = { [ 1, 2 ] => 'onetwo', 3 => { :bar => [ :foo, 'baz' ] } } }.to raise_error(ArgumentError)
161
+ end
162
+
163
+ it "should not allow storing invalid scalars" do
164
+ expect { @controller_instance.objsession.foo = /yo/ }.to raise_error(ArgumentError)
165
+ end
166
+
167
+ it "should not allow storing invalid scalars inside an Array" do
168
+ expect { @controller_instance.objsession.foo = [ 1, 2, /yo/ ] }.to raise_error(ArgumentError)
169
+ end
170
+
171
+ it "should not allow storing invalid scalars inside a Hash" do
172
+ expect { @controller_instance.objsession.foo = { :foo => /yo/ } }.to raise_error(ArgumentError)
173
+ expect { @controller_instance.objsession.foo = { /yo/ => :foo } }.to raise_error(ArgumentError)
174
+ end
175
+ end
176
+ end
@@ -111,7 +111,27 @@ describe ObjectifiedSessions::Base do
111
111
  end
112
112
 
113
113
  describe "retrieving field names" do
114
+ before :each do
115
+ @field_foo = expect_and_create_field!(:foo, 'foo', true, false, { :type => :normal, :visibility => :public })
116
+ @class.field :foo
117
+ @field_bar = expect_and_create_field!(:bar, 'bar', true, false, { :type => :normal, :visibility => :public })
118
+ @class.field :bar
119
+ @field_baz = expect_and_create_field!(:baz, 'baz', true, false, { :type => :normal, :visibility => :public })
120
+ @class.field :baz
121
+ @field_ret = expect_and_create_field!(:ret, 'ret', false, true, { :type => :retired, :visibility => :public })
122
+ @class.retired :ret
123
+ @field_ina = expect_and_create_field!(:ina, 'ina', false, false, { :type => :inactive, :visibility => :public })
124
+ @class.inactive :ina
125
+ end
126
+
127
+ it "should return all normal fields, but not active or retired, from the class" do
128
+ @class.accessible_field_names.sort_by { |x| x.to_s }.should == %w{foo bar baz}.map { |x| x.to_sym }.sort_by { |x| x.to_s }
129
+ end
114
130
 
131
+ it "should return all normal fields, but not active or retired, from the instance" do
132
+ instance = new_instance!
133
+ instance.field_names.sort_by { |x| x.to_s }.should == %w{foo bar baz}.map { |x| x.to_sym }.sort_by { |x| x.to_s }
134
+ end
115
135
  end
116
136
 
117
137
  describe "reading fields" do
@@ -393,6 +413,64 @@ describe ObjectifiedSessions::Base do
393
413
  @class.unknown_fields.should == :preserve
394
414
  end
395
415
 
416
+ it "should allow setting allowed_value_types to any valid value, but not invalid values, and return it" do
417
+ @class.allowed_value_types.should == :anything
418
+ @class.allowed_value_types :primitive
419
+ @class.allowed_value_types.should == :primitive
420
+ @class.allowed_value_types :primitive_and_compound
421
+ @class.allowed_value_types.should == :primitive_and_compound
422
+ @class.allowed_value_types :anything
423
+ @class.allowed_value_types.should == :anything
424
+ end
425
+
426
+ describe "new-value type validation" do
427
+ before :each do
428
+ @field_foo = expect_and_create_field!(:foo, 'foo', true, false, { :type => :normal, :visibility => :public })
429
+ @class.field :foo
430
+
431
+ @instance = new_instance!
432
+
433
+ @scalars = [ "string", :symbol, true, false, nil, Time.now ]
434
+ @compound = [ [ 1, 2, 3 ], { 'foo' => 123 }, [ 1, [ 2, 3 ], 4 ], { 'foo' => [ 1, 2, 3 ] } ]
435
+
436
+ my_class = Class.new
437
+ @arbitrary = [ /something/, my_class.new, [ 1, 2, /foo/ ], { 'foo' => /foo/ } ]
438
+ end
439
+
440
+ it "should allow anything by default" do
441
+ (@scalars + @compound + @arbitrary).each do |value|
442
+ expect(@underlying_session).to receive(:[]=).once.with('foo', value)
443
+ @instance.send(:[]=, :foo, value)
444
+ end
445
+ end
446
+
447
+ it "should allow only simple scalars for :primitive" do
448
+ @class.allowed_value_types :primitive
449
+
450
+ (@scalars).each do |value|
451
+ expect(@underlying_session).to receive(:[]=).once.with('foo', value)
452
+ @instance.send(:[]=, :foo, value)
453
+ end
454
+
455
+ (@compound + @arbitrary).each do |value|
456
+ lambda { @instance.send(:[]=, :foo, value) }.should raise_error(ArgumentError)
457
+ end
458
+ end
459
+
460
+ it "should allow simple scalars and compounds of those for :primitive_and_compound" do
461
+ @class.allowed_value_types :primitive_and_compound
462
+
463
+ (@scalars + @compound).each do |value|
464
+ expect(@underlying_session).to receive(:[]=).once.with('foo', value)
465
+ @instance.send(:[]=, :foo, value)
466
+ end
467
+
468
+ (@arbitrary).each do |value|
469
+ lambda { @instance.send(:[]=, :foo, value) }.should raise_error(ArgumentError)
470
+ end
471
+ end
472
+ end
473
+
396
474
  it "should return only fields in #accessible_field_names, return fields by name or storage name appropriately, and raise NoSuchFieldError when appropriate" do
397
475
  @field_foo = expect_and_create_field!(:foo, 'stg1', true, false, { :type => :normal, :visibility => :public, :storage => :stg1 })
398
476
  @class.field :foo, :storage => :stg1
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: objectified_sessions
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Geweke
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2013-12-29 00:00:00 Z
12
+ date: 2014-02-06 00:00:00 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
@@ -85,6 +85,7 @@ files:
85
85
  - spec/objectified_sessions/system/prefix_system_spec.rb
86
86
  - spec/objectified_sessions/system/retired_inactive_system_spec.rb
87
87
  - spec/objectified_sessions/system/setup_system_spec.rb
88
+ - spec/objectified_sessions/system/storage_types_system_spec.rb
88
89
  - spec/objectified_sessions/system/strings_symbols_system_spec.rb
89
90
  - spec/objectified_sessions/system/unknown_data_system_spec.rb
90
91
  - spec/objectified_sessions/system/visibility_system_spec.rb