objectified_sessions 1.0.0 → 1.0.1

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 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