flex_columns 1.0.1 → 1.0.2

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
2
  SHA1:
3
- metadata.gz: d79e3b16e2f818cfee4e0cdf530a78ebc49bfbdd
4
- data.tar.gz: 03593078cb27e5cac1d7b38090147ac5590f7b8f
3
+ metadata.gz: acb66f010a776e668841ca7f12dc0854cad5b4c9
4
+ data.tar.gz: 91492dda4eab46d062ae8958c62c5e31da33a339
5
5
  SHA512:
6
- metadata.gz: 4072eb037511e12a1adfc2d34982568445bfcedb386013d2d50ded737e40f4fa259df9c5a87cf39dff86b4d2c82da01caec0c2055473cfd4d819be501e5b9e10
7
- data.tar.gz: aea2b505ba4af83bbd3408d066402bdded39d4a06309d5ba4b2341a17ad00ccfbd0098bfe7149ba93ecee28c45f7d6c40dde03da22b27d3b56dc02b71d5a1f0e
6
+ metadata.gz: 4469119cb126a4e5767910b6ce4df02037afa3003d735be05baf0a0158ee45c3871b5c29292181c09823ac416184cb2e692f8ad31c9dfd66cea0187d65b5e3d6
7
+ data.tar.gz: 6614f83b721f635efa9e80f4f194237436890e66f35a662af0ed100d4d5bc4e90436abe859e89332ecc5f913134903e041bb66332a7d424560e64a5187bf0908
data/.gitignore CHANGED
@@ -15,4 +15,4 @@ spec/reports
15
15
  test/tmp
16
16
  test/version_tmp
17
17
  tmp
18
- /spec_database_config.rb
18
+ /spec_database_config.rb*
data/flex_columns.gemspec CHANGED
@@ -45,20 +45,6 @@ Gem::Specification.new do |s|
45
45
 
46
46
  s.add_dependency "activesupport", ">= 3.0", "<= 4.99.99"
47
47
 
48
- ar_import_version = case ar_version
49
- when nil then nil
50
- when 'master', /^4\.0\./ then '~> 0.4.1'
51
- when /^3\.0\./ then '~> 0.2.11'
52
- when /^3\.1\./, /^3\.2\./ then '~> 0.3.1'
53
- else raise "Don't know what activerecord-import version to require for activerecord version #{ar_version.inspect}!"
54
- end
55
-
56
- if ar_import_version
57
- s.add_dependency("activerecord-import", ar_import_version)
58
- else
59
- s.add_dependency("activerecord-import")
60
- end
61
-
62
48
  require File.expand_path(File.join(File.dirname(__FILE__), 'spec', 'flex_columns', 'helpers', 'database_helper'))
63
49
  database_gem_name = FlexColumns::Helpers::DatabaseHelper.maybe_database_gem_name
64
50
 
@@ -80,7 +80,6 @@ module FlexColumns
80
80
 
81
81
  @field_contents_by_field_name = nil
82
82
  @unknown_field_contents_by_key = nil
83
- @touched = false
84
83
  end
85
84
 
86
85
  # Returns the data for the given +field_name+. Raises FlexColumns::Errors::NoSuchFieldError if there is no field
@@ -109,8 +108,6 @@ module FlexColumns
109
108
 
110
109
  old_value = field_contents_by_field_name[field_name]
111
110
 
112
- @touched = true if old_value != new_value
113
-
114
111
  # We deliberately delete from the hash anything that's being set to +nil+; this is so that we don't end up just
115
112
  # binding keys to +nil+, and returning them in #keys, etc. (Yes, this means that you can't distinguish a key
116
113
  # explicitly set to +nil+ from a key that's not present; this is different from Ruby's semantics for a Hash,
@@ -129,17 +126,56 @@ module FlexColumns
129
126
  field_contents_by_field_name.keys
130
127
  end
131
128
 
129
+ # Returns a representation of this data as a Hash. This should *not* be used in +flex_columns+ to manipulate
130
+ # data, as it does not contain a full representation of a column (in particular, unknown-field data is not
131
+ # represented in the returned Hash); however, it's useful to construct a string (e.g.,
132
+ # FlexColumnsContentsBase#inspect) to help with debugging.
133
+ def to_hash
134
+ deserialize_if_necessary!
135
+ field_contents_by_field_name.dup.with_indifferent_access
136
+ end
137
+
132
138
  # Does nothing, other than making sure the JSON has been deserialized. This therefore has the effect both of
133
139
  # ensuring that the stored data (if any) is valid, and also will remove any unknown keys (on save) if
134
140
  # +:unknown_fields+ was set to +:delete+.
135
141
  def touch!
136
142
  deserialize_if_necessary!
137
- @touched = true
138
143
  end
139
144
 
140
- # Has this object been modified in any way?
141
- def touched?
142
- !! @touched
145
+ # Has this object been deserialized? If it's been deserialized, then we need to do things like run validations
146
+ # on it, save it back to the database when someone calls #save! on the parent object, and so on.
147
+ #
148
+ # Not at all obvious: originally, we had a method called #touched? that let you know whether the given object
149
+ # had been changed at all. It simply got set on +#[]=+, above. The problem with this is that very frequently,
150
+ # +flex_columns+ is used to store complex data structures (because that's one of the things that's dramatically
151
+ # easier in a serialized JSON blob than in a traditional relational structure). But if you have an array stored,
152
+ # and you call #<< on it to append an element, then +#[]=+ never gets called at all -- because it's still the
153
+ # same object, just with different contents.
154
+ #
155
+ # We could have worked around this by saving off a copy of each field when we deserialized, then comparing them
156
+ # using a deep equality (#== should work just fine) to determine if they've changed. However, this adds very
157
+ # significant overhead to each and every single use of a +flex_column+ object, whether or not you rely on or
158
+ # care about this kind of tracking -- we would have to #dup every flex column field every single time we
159
+ # deserialized, and, if you have large objects in there, that can get extremely expensive.
160
+ #
161
+ # Since almost every object in Ruby is mutable -- even Strings -- there aren't really any easy wins here.
162
+ # Numbers are the only commonplace object that aren't, and it's not going to be a common use case that someone
163
+ # uses a +flex_column+ with fields that each simply store one single number. (Storing an array or a hash of
164
+ # numbers is much more common, but then you're talking about Arrays and Hashes, which are back to being mutable.)
165
+ #
166
+ # Another option would be to #freeze all of the fields on a flex column, thus requiring clients to reassign them
167
+ # with a new object if they wanted to change them at all. That, however, presents an API that most users would
168
+ # hate -- I don't want to say <tt>user.prefs_map = user.prefs_map.merge(:foo => bar)</tt>; I want to just say
169
+ # <tt>user.prefs_map[:foo] = bar</tt>.
170
+ #
171
+ # Instead, once we deserialize a field, we just assume that it has changed. While this may end up causing the
172
+ # client to do extra work at times, it's much higher-performance than doing the tracking every time.
173
+ #
174
+ # (There is definitely room to add code that would make this configurable, on a per-flex-column or even per-field
175
+ # basis. As always, patches are welcome; as of this writing, it seems likely that it might just not be an issue
176
+ # big enough to worry about.)
177
+ def deserialized?
178
+ !! field_contents_by_field_name
143
179
  end
144
180
 
145
181
  # Returns a String with the current contents of this object as JSON. (This will deserialize from JSON, if it
@@ -181,7 +217,8 @@ module FlexColumns
181
217
  end
182
218
  end
183
219
 
184
- if length_limit && out.length > length_limit
220
+ actual_length = out ? out.length : 0
221
+ if length_limit && actual_length > length_limit
185
222
  raise FlexColumns::Errors::JsonTooLongError.new(data_source, length_limit, out)
186
223
  end
187
224
 
@@ -345,7 +382,7 @@ module FlexColumns
345
382
  # If we haven't yet deserialized the JSON string, do it now, and store the data appropriately. This also
346
383
  # checks for a validly-encoded string.
347
384
  def deserialize_if_necessary!
348
- unless field_contents_by_field_name
385
+ unless deserialized?
349
386
  raw_data = storage_string || ''
350
387
 
351
388
  # PostgreSQL's JSON data type, combined with recent-enough adapters and ActiveRecord, will return JSON as a
@@ -108,23 +108,18 @@ module FlexColumns
108
108
  column_data[field_name] = new_value
109
109
  end
110
110
 
111
- # A flex column has been "touched" if it has had at least one field changed to a different value than it had
112
- # before, or if someone has called #touch! on it. If a column has not been touched, validations are not run on it,
113
- # nor is it re-serialized back out to the database on save!. Generally, this is a good thing: it increases
114
- # performance substantially for times when you haven't actually changed the flex column's contents at all. It does
115
- # mean that invalid data won't be detected and unknown fields won't be removed (if you've specified
116
- # <tt>:unknown_fields => delete</tt>), however.
117
- #
118
- # There may be times, however, when you want to make sure the column is stored back out (including removing any
119
- # unknown fields, if you selected that option), or to make sure that validations get run, no matter what.
120
- # In this case, you can call #touch!.
111
+ # Sometimes you want to deserialize a flex column explicitly, without actually changing anything in it. (For
112
+ # example, if you set <tt>:unknown_fields => :delete</tt>, then unknown fields are removed from a column only if
113
+ # it has been deserialized before you save it.) While you could accomplish this by simply accessing any field
114
+ # of the column, it's cleaner and more clear what you're doing to just call this method.
121
115
  def touch!
122
116
  column_data.touch!
123
117
  end
124
118
 
125
- # Has at least one field in the column been changed, or has someone called #touch! ?
126
- def touched?
127
- column_data.touched?
119
+ # Has the column been deserialized? A column is deserialized if someone has tried to read from or write to it,
120
+ # or if someone has called #touch!.
121
+ def deserialized?
122
+ column_data.deserialized?
128
123
  end
129
124
 
130
125
  # Called via the ActiveRecord::Base#before_validation hook that gets installed on the enclosing model instance.
@@ -139,6 +134,25 @@ module FlexColumns
139
134
  end
140
135
  end
141
136
 
137
+ INSPECT_MAXIMUM_LENGTH_FOR_ANY_ATTRIBUTE_VALUE = 100
138
+
139
+ # **NOTE**: This method *WILL* deserialize the contents of the column, if it hasn't already been deserialized.
140
+ # This is extremely useful for debugging, and almost certainly what you want, but if, for some reason, you
141
+ # call #inspect on every single instance of a flex-column you get back from the database, you'll incur a
142
+ # needless performance penalty. You have been warned.
143
+ def inspect
144
+ string_hash = { }
145
+ column_data.to_hash.each do |k,v|
146
+ v_string = v.to_s
147
+ if v_string.length > INSPECT_MAXIMUM_LENGTH_FOR_ANY_ATTRIBUTE_VALUE
148
+ v_string = "#{v_string[0..(INSPECT_MAXIMUM_LENGTH_FOR_ANY_ATTRIBUTE_VALUE - 1)]}..."
149
+ end
150
+ string_hash[k] = v_string
151
+ end
152
+
153
+ "<#{self.class.name}: #{string_hash.inspect}>"
154
+ end
155
+
142
156
  # Returns a JSON string representing the current contents of this flex column. Note that this is _not_ always
143
157
  # exactly what gets stored in the database, because of binary columns and compression; for that, use
144
158
  # #to_stored_data, below.
@@ -146,11 +146,11 @@ module FlexColumns
146
146
 
147
147
  # Given a model instance, do we need to save this column? This is true under one of two cases:
148
148
  #
149
- # * Someone has changed ("touched") at least one of the flex-column fields (or called #touch! on it);
149
+ # * Someone has deserialized the column by accessing it (or calling #touch! on it);
150
150
  # * The column is non-NULL, and there's no data in it right now. (Saving it will populate it with an empty string.)
151
151
  def requires_serialization_on_save?(model)
152
152
  maybe_flex_object = model._flex_column_object_for(column_name, false)
153
- out = true if maybe_flex_object && maybe_flex_object.touched?
153
+ out = true if maybe_flex_object && maybe_flex_object.deserialized?
154
154
  out ||= true if ((! column.null) && (! model[column_name]))
155
155
  out
156
156
  end
@@ -38,7 +38,7 @@ module FlexColumns
38
38
  # whether you've changed that particular attribute or not.
39
39
  def _flex_columns_before_validation!
40
40
  _all_present_flex_column_objects.each do |flex_column_object|
41
- flex_column_object.before_validation! if flex_column_object.touched?
41
+ flex_column_object.before_validation!
42
42
  end
43
43
  end
44
44
 
@@ -72,6 +72,25 @@ module FlexColumns
72
72
  @_flex_column_objects = { }
73
73
  end
74
74
 
75
+ # This little-know ActiveRecord method gets called to produce a string for #inspect for a particular attribute.
76
+ # Because the default implementation uses #read_attribute, if we don't override it, it will simply return our
77
+ # actual string in the database; if this is compressed data, this is meaningless to a programmer. So we override
78
+ # this to instead deserialize the column and call #inspect on the actual FlexColumnContentsBase object, which
79
+ # shows interesting information.
80
+ #
81
+ # **NOTE**: See the warning comment above FlexColumnContentsBase#inspect, which points out that this will
82
+ # deserialize the column if it hasn't already -- so calling this has a performance penalty. This should be fine,
83
+ # since calling #inspect in bulk isn't something a program should be doing in production mode anyway, but it's
84
+ # worth noting.
85
+ def attribute_for_inspect(attr_name)
86
+ cn = self.class._all_flex_column_names
87
+ if cn.include?(attr_name.to_sym)
88
+ _flex_column_object_for(attr_name).inspect
89
+ else
90
+ super(attr_name)
91
+ end
92
+ end
93
+
75
94
  private
76
95
  # Returns the Hash that we keep flex-column objects in, indexed by column name.
77
96
  def _flex_column_objects
@@ -1,4 +1,4 @@
1
1
  module FlexColumns
2
2
  # The current version of FlexColumns.
3
- VERSION = "1.0.1"
3
+ VERSION = "1.0.2"
4
4
  end
@@ -40,6 +40,57 @@ describe "FlexColumns basic operations" do
40
40
  user2.user_attributes.keys.should == [ :wants_email ]
41
41
  end
42
42
 
43
+ it "shouldn't complain if there is no data, but you still touch a field" do
44
+ user = ::User.new
45
+ user.name = 'User 1'
46
+ user.user_attributes.wants_email
47
+ user.save!
48
+ end
49
+
50
+ # This test case was created from a found bug: we were assuming that unless you called "#{method}=" on one of
51
+ # the attributes of a flex column, then we didn't need to serialize and save the flex column. However, that's not
52
+ # true, for exactly the reasons seen below (maybe you modified an object that was referred to from the field,
53
+ # but didn't change that field itself). See also the comment above ColumnData#deserialized?.
54
+ it "should still save its data even if you change something nested down deep" do
55
+ user = ::User.new
56
+ user.name = 'User 1'
57
+ user.user_attributes.wants_email = { 'foo' => { 'bar' => [ 1, 2, 3 ] } }
58
+ user.save!
59
+
60
+ user_again = ::User.find(user.id)
61
+ user_again.user_attributes.wants_email['foo']['bar'] << 4
62
+ user_again.save!
63
+
64
+ user_yet_again = ::User.find(user.id)
65
+ user_yet_again.user_attributes.wants_email['foo']['bar'].should == [ 1, 2, 3, 4 ]
66
+ end
67
+
68
+ it "should return useful data for the column on #inspect, deserializing if necessary" do
69
+ user = ::User.new
70
+ user.name = 'User 1'
71
+ user.wants_email = 'whatEVER, yo'
72
+ user.save!
73
+
74
+ user_again = ::User.find(user.id)
75
+ s = user_again.user_attributes.inspect
76
+ s.should match(/UserAttributesFlexContents/i)
77
+ s.should match(/wants_email/i)
78
+ s.should match(/whatEVER, yo/)
79
+ end
80
+
81
+ it "should return useful data for the column on #inspect from the parent AR model" do
82
+ user = ::User.new
83
+ user.name = 'User 1'
84
+ user.wants_email = 'whatEVER, yo'
85
+ user.save!
86
+
87
+ user_again = ::User.find(user.id)
88
+ s = user_again.inspect
89
+ s.should match(/UserAttributesFlexContents/i)
90
+ s.should match(/wants_email/i)
91
+ s.should match(/whatEVER, yo/)
92
+ end
93
+
43
94
  it "should store its data as standard JSON" do
44
95
  user = ::User.new
45
96
  user.name = 'User 1'
@@ -60,7 +111,7 @@ describe "FlexColumns basic operations" do
60
111
  contents['wants_email'].should == 'sometimes'
61
112
  end
62
113
 
63
- it "should not modify that JSON if you don't write to it with a different value, but should if you touch it" do
114
+ it "should not modify that JSON if you don't touch it, but should if you do" do
64
115
  define_model_class(:UserBackdoor, 'flexcols_spec_users') { }
65
116
 
66
117
  weirdly_spaced_json = ' { "wants_email" : "boop" } '
@@ -72,15 +123,7 @@ describe "FlexColumns basic operations" do
72
123
 
73
124
  user = ::User.find(user_bd.id)
74
125
  user.name.should == 'User 1'
75
- user.wants_email.should == 'boop'
76
- user.wants_email = 'boop'
77
- user.save!
78
-
79
- user_bd_again = ::UserBackdoor.find(user_bd.id)
80
- user_bd_again.name.should == 'User 1'
81
- user_bd_again.user_attributes.should == weirdly_spaced_json
82
-
83
- user.user_attributes.touch!
126
+ user.wants_email
84
127
  user.save!
85
128
 
86
129
  user_bd_again = ::UserBackdoor.find(user_bd.id)
@@ -99,6 +99,33 @@ describe "FlexColumns compression operations" do
99
99
  data.should_not match(/bar/)
100
100
  end
101
101
 
102
+ describe "#inspect" do
103
+ it "should decompress and deserialize data for #inspect on the column itself, but should abbreviate" do
104
+ user = ::User.new
105
+ user.name = 'User 1'
106
+ user.foo = 'foo' * 1000
107
+ user.save!
108
+
109
+ user_again = ::User.find(user.id)
110
+ s = user_again.user_attributes.inspect
111
+ s.should match(/UserAttributesFlexContents/i)
112
+ s.should match(/foofoofoofoo/i)
113
+ s.length.should < 1000
114
+ end
115
+
116
+ it "should decompress and deserialize data for #inspect on the parent, too" do
117
+ user = ::User.new
118
+ user.name = 'User 1'
119
+ user.foo = 'foo' * 1000
120
+ user.save!
121
+
122
+ user_again = ::User.find(user.id)
123
+ s = user_again.inspect
124
+ s.should match(/UserAttributesFlexContents/i)
125
+ s.should match(/foofoofoofoo/i)
126
+ end
127
+ end
128
+
102
129
  it "should read compressed data fine, even if told not to compress new data" do
103
130
  user = ::User.new
104
131
  user.name = 'User 1'
@@ -63,7 +63,7 @@ describe "FlexColumns performance" do
63
63
  @deserializations[0][:raw_data].should == user_again.user_attributes.to_json
64
64
  end
65
65
 
66
- it "should not deserialize columns if they aren't touched" do
66
+ it "should not deserialize columns if they aren't accessed" do
67
67
  user = ::User.new
68
68
  user.name = 'User 1'
69
69
  user.wants_email = 'foo'
@@ -75,7 +75,7 @@ describe "FlexColumns unknown fields" do
75
75
  user_bd_again.some_unknown_attribute.should be_nil
76
76
  end
77
77
 
78
- it "should not delete unknown fields if asked to, but we only read from the model" do
78
+ it "should delete unknown fields if asked to, even if we only read from the model" do
79
79
  @user_bd.wants_email = 'foo'
80
80
  @user_bd.save!
81
81
 
@@ -98,7 +98,7 @@ describe "FlexColumns unknown fields" do
98
98
 
99
99
  user_bd_again = ::UserBackdoor.find(@user_bd.id)
100
100
  user_bd_again.wants_email.should == 'foo'
101
- user_bd_again.some_unknown_attribute.should == 'bongo'
101
+ user_bd_again.some_unknown_attribute.should_not be
102
102
  end
103
103
 
104
104
  it "should have a method that explicitly will purge unknown methods, even if deserialization hasn't happened for any other reason, but not before then" do
@@ -131,22 +131,16 @@ describe FlexColumns::Contents::ColumnData do
131
131
  lambda { instance.touch! }.should raise_error(FlexColumns::Errors::UnparseableJsonInDatabaseError)
132
132
  end
133
133
 
134
- it "should not be touched if you simply read from it" do
135
- @instance.touched?.should_not be
134
+ it "should be deserialized if you simply read from it" do
135
+ @instance.deserialized?.should_not be
136
136
  @instance[:foo]
137
- @instance.touched?.should_not be
137
+ @instance.deserialized?.should be
138
138
  end
139
139
 
140
- it "should not be touched if you set a field to the same thing" do
141
- @instance.touched?.should_not be
142
- @instance[:foo] = 'bar'
143
- @instance.touched?.should_not be
144
- end
145
-
146
- it "should be touched if you set a field to something different" do
147
- @instance.touched?.should_not be
140
+ it "should be deserialized if you set a field to something different" do
141
+ @instance.deserialized?.should_not be
148
142
  @instance[:foo] = 'baz'
149
- @instance.touched?.should be
143
+ @instance.deserialized?.should be
150
144
  end
151
145
  end
152
146
 
@@ -159,13 +153,34 @@ describe FlexColumns::Contents::ColumnData do
159
153
  parsed['baz'].should == 'quux'
160
154
  end
161
155
 
162
- it "should return JSON data with #to_json" do
163
- json = @instance.to_json
164
- parsed = JSON.parse(json)
165
- parsed.keys.sort.should == %w{foo bar baz}.sort
166
- parsed['foo'].should == 'bar'
167
- parsed['bar'].should == 123
168
- parsed['baz'].should == 'quux'
156
+ describe "#to_hash" do
157
+ it "should return a hash with the data in it, with indifferent access" do
158
+ h = @instance.to_hash
159
+ h.keys.sort.should == %w{foo bar baz}.sort
160
+ h['foo'].should == 'bar'
161
+ h['bar'].should == 123
162
+ h['baz'].should == 'quux'
163
+ h[:foo].should == 'bar'
164
+ h[:bar].should == 123
165
+ h[:baz].should == 'quux'
166
+ end
167
+
168
+ it "should deserialize if needed" do
169
+ h = new_with_string(@json_string).to_hash
170
+ h.keys.sort.should == %w{foo bar baz}.sort
171
+ h['foo'].should == 'bar'
172
+ h['bar'].should == 123
173
+ h['baz'].should == 'quux'
174
+ end
175
+
176
+ it "should not return unknown fields" do
177
+ h = new_with_string({ 'foo' => 'bar', 'baz' => 123, 'quux' => 'whatever' }.to_json).to_hash
178
+ h.keys.sort.should == %w{foo baz}.sort
179
+ h['foo'].should == 'bar'
180
+ h['baz'].should == 123
181
+ h['bar'].should be_nil
182
+ h['quux'].should be_nil
183
+ end
169
184
  end
170
185
 
171
186
  it "should accept a Hash as JSON, already parsed by the database stack" do
@@ -188,11 +188,11 @@ describe FlexColumns::Contents::FlexColumnContentsBase do
188
188
  allow(@model_instance).to receive(:_flex_column_object_for).with(:fcn, false).and_return(@instance)
189
189
  end
190
190
 
191
- it "should tell you if it's been touched" do
192
- expect(@column_data).to receive(:touched?).once.with().and_return(true)
193
- @instance.touched?.should be
194
- expect(@column_data).to receive(:touched?).once.with().and_return(false)
195
- @instance.touched?.should_not be
191
+ it "should tell you if it's been deserialized" do
192
+ expect(@column_data).to receive(:deserialized?).once.with().and_return(true)
193
+ @instance.deserialized?.should be
194
+ expect(@column_data).to receive(:deserialized?).once.with().and_return(false)
195
+ @instance.deserialized?.should_not be
196
196
  end
197
197
 
198
198
  it "should save if the class tells it to" do
@@ -224,6 +224,25 @@ describe FlexColumns::Contents::FlexColumnContentsBase do
224
224
  @instance[:xxx].should == :yyy
225
225
  end
226
226
 
227
+ it "should return a useful string for #inspect" do
228
+ expect(@column_data).to receive(:to_hash).once.and_return({ :aaa => 'bbb', :ccc => 'ddd'})
229
+ i = @instance.inspect
230
+ i.should match(/aaa/)
231
+ i.should match(/bbb/)
232
+ i.should match(/ccc/)
233
+ i.should match(/ddd/)
234
+ end
235
+
236
+ it "should abbreviate that hash, if necessary" do
237
+ expect(@column_data).to receive(:to_hash).once.and_return({ :aaa => 'bbb', :ccc => ('ddd' * 1_000)})
238
+ i = @instance.inspect
239
+ i.should match(/aaa/)
240
+ i.should match(/bbb/)
241
+ i.should match(/ccc/)
242
+ i.should match(/ddddddddd/)
243
+ i.length.should < 1_000
244
+ end
245
+
227
246
  it "should delegate to the column data on []=" do
228
247
  expect(@column_data).to receive(:[]=).once.with(:xxx, :yyy).and_return(:zzz)
229
248
  (@instance[:xxx] = :yyy).should == :yyy
@@ -490,19 +490,19 @@ describe FlexColumns::Definition::FlexColumnContentsClass do
490
490
  end
491
491
 
492
492
  describe "#requires_serialization_on_save?" do
493
- it "should be true if there's an object and it has been touched" do
493
+ it "should be true if there's an object and it has been deserialized" do
494
494
  model = double("model")
495
495
  fco = double("fco")
496
496
  allow(model).to receive(:_flex_column_object_for).with(:foo, false).and_return(fco)
497
- allow(fco).to receive(:touched?).with().and_return(true)
497
+ allow(fco).to receive(:deserialized?).with().and_return(true)
498
498
  @klass.requires_serialization_on_save?(model).should be
499
499
  end
500
500
 
501
- it "should be false if there's an object but it hasn't been touched" do
501
+ it "should be false if there's an object but it hasn't been deserialized" do
502
502
  model = double("model")
503
503
  fco = double("fco")
504
504
  allow(model).to receive(:_flex_column_object_for).with(:foo, false).and_return(fco)
505
- allow(fco).to receive(:touched?).with().and_return(false)
505
+ allow(fco).to receive(:deserialized?).with().and_return(false)
506
506
  @klass.requires_serialization_on_save?(model).should_not be
507
507
  end
508
508
 
@@ -168,28 +168,30 @@ describe FlexColumns::HasFlexColumns do
168
168
  @klass._flex_column_dynamic_methods_module.should be(@dmm)
169
169
  end
170
170
 
171
- it "should call through on before_validation to only flex column objects that have been touched" do
171
+ it "should call through on before_validation to all flex column objects, whether or not they've been deserialized" do
172
172
  instance = @klass.new
173
173
  instance._flex_columns_before_validation!
174
174
 
175
175
  fcc_foo_instance = double("fcc_foo_instance")
176
176
  expect(@fcc_foo).to receive(:new).once.with(instance).and_return(fcc_foo_instance)
177
177
  instance._flex_column_object_for(:foo).should be(fcc_foo_instance)
178
- allow(fcc_foo_instance).to receive(:touched?).with().and_return(false)
178
+ allow(fcc_foo_instance).to receive(:deserialized?).with().and_return(false)
179
179
 
180
+ expect(fcc_foo_instance).to receive(:before_validation!).once.with()
180
181
  instance._flex_columns_before_validation!
181
182
 
182
183
 
183
184
  fcc_bar_instance = double("fcc_bar_instance")
184
185
  expect(@fcc_bar).to receive(:new).once.with(instance).and_return(fcc_bar_instance)
185
186
  instance._flex_column_object_for(:bar).should be(fcc_bar_instance)
186
- allow(fcc_bar_instance).to receive(:touched?).with().and_return(true)
187
+ allow(fcc_bar_instance).to receive(:deserialized?).with().and_return(true)
187
188
 
189
+ expect(fcc_foo_instance).to receive(:before_validation!).once.with()
188
190
  expect(fcc_bar_instance).to receive(:before_validation!).once.with()
189
191
  instance._flex_columns_before_validation!
190
192
 
191
- allow(fcc_foo_instance).to receive(:touched?).with().and_return(true)
192
- allow(fcc_bar_instance).to receive(:touched?).with().and_return(true)
193
+ allow(fcc_foo_instance).to receive(:deserialized?).with().and_return(true)
194
+ allow(fcc_bar_instance).to receive(:deserialized?).with().and_return(true)
193
195
 
194
196
  expect(fcc_foo_instance).to receive(:before_validation!).once.with()
195
197
  expect(fcc_bar_instance).to receive(:before_validation!).once.with()
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: flex_columns
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 1.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Geweke
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-12-22 00:00:00.000000000 Z
11
+ date: 2014-01-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: json
@@ -148,20 +148,6 @@ dependencies:
148
148
  - - <=
149
149
  - !ruby/object:Gem::Version
150
150
  version: 4.99.99
151
- - !ruby/object:Gem::Dependency
152
- name: activerecord-import
153
- requirement: !ruby/object:Gem::Requirement
154
- requirements:
155
- - - '>='
156
- - !ruby/object:Gem::Version
157
- version: '0'
158
- type: :runtime
159
- prerelease: false
160
- version_requirements: !ruby/object:Gem::Requirement
161
- requirements:
162
- - - '>='
163
- - !ruby/object:Gem::Version
164
- version: '0'
165
151
  - !ruby/object:Gem::Dependency
166
152
  name: mysql2
167
153
  requirement: !ruby/object:Gem::Requirement
@@ -251,7 +237,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
251
237
  version: '0'
252
238
  requirements: []
253
239
  rubyforge_project:
254
- rubygems_version: 2.1.11
240
+ rubygems_version: 2.2.1
255
241
  signing_key:
256
242
  specification_version: 4
257
243
  summary: Schema-free, structured JSON storage inside a RDBMS.
@@ -284,3 +270,4 @@ test_files:
284
270
  - spec/flex_columns/unit/including/include_flex_columns_spec.rb
285
271
  - spec/flex_columns/unit/util/dynamic_methods_module_spec.rb
286
272
  - spec/flex_columns/unit/util/string_utils_spec.rb
273
+ has_rdoc: