flex_columns 1.0.6 → 1.0.7
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 +5 -5
- data/CHANGES.md +4 -0
- data/README.md +2 -2
- data/lib/flex_columns/active_record/base.rb +1 -2
- data/lib/flex_columns/definition/fake_column.rb +29 -0
- data/lib/flex_columns/definition/flex_column_contents_class.rb +46 -16
- data/lib/flex_columns/has_flex_columns.rb +16 -2
- data/lib/flex_columns/version.rb +1 -1
- data/spec/flex_columns/helpers/system_helpers.rb +8 -0
- data/spec/flex_columns/system/basic_system_spec.rb +1 -2
- data/spec/flex_columns/system/dynamism_system_spec.rb +76 -0
- data/spec/flex_columns/system/performance_system_spec.rb +12 -12
- data/spec/flex_columns/unit/definition/fake_column_spec.rb +8 -0
- data/spec/flex_columns/unit/definition/flex_column_contents_class_spec.rb +42 -0
- data/spec/flex_columns/unit/has_flex_columns_spec.rb +37 -0
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
SHA512:
|
3
|
-
metadata.gz: a346cd4387b83db2754cd6d18db49a616015ca230a0b18134f0a7176b4f206778a7f778cec4b97e84c59dfb0358339a2106b1e8656be922a54b2d0143867b1da
|
4
|
-
data.tar.gz: bebc4830bc2ea67bfa2152cca4587d751dd13da67c4afe22ea288e4522079510aaf2aa42b32fbff72a6b2af4c930ada099fafadb063cb384bb84f30c1a3c05c4
|
5
2
|
SHA1:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d883b205cd22c7aa6a6bda071d3ca52c7084e14e
|
4
|
+
data.tar.gz: 88057e546d40a01a83ba499f0c9c4d4c5b0863af
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 040c456a7527585100159b68e0b1685e590fb30a75f1388107773de1501a6699d8b7903f891ccbc0b0e0f5a7cb44b647d734cf5e65279185723129580cb6f4be
|
7
|
+
data.tar.gz: 951bfb6887b746545fcc7d5b8036d9a1efa5bdc31369e1b68fddfcf1bc482b10464d5f11a2d43cb4135ac9e140471cb5490ddee61e8ff41730e4fa03c0f82bb2
|
data/CHANGES.md
CHANGED
@@ -1,5 +1,9 @@
|
|
1
1
|
# `flex_columns` Changelog
|
2
2
|
|
3
|
+
## 1.0.7, 2014-04-07
|
4
|
+
|
5
|
+
* Fixed an issue where, if you defined a model class when its table didn't exist, and then created its table while the Ruby process was still running, you still couldn't access any flex-column attributes — because we would simply skip defining them entirely if the table didn't exist. Now, we define them, assuming the columns exist and are of type `:string` (and `null`able) if the table doesn't exist, and replace them with the actual column definition once the table exists. (You need to call `.reset_column_information` on the model class to make this happen, just as you do with any changes to the underlying table of an ActiveRecord model.)
|
6
|
+
|
3
7
|
## 1.0.6, 2014-04-07
|
4
8
|
|
5
9
|
* Fixed an issue where Float::INFINITY and Float::NaN could not be stored in a flex column.
|
data/README.md
CHANGED
@@ -110,13 +110,13 @@ As a snapshot of all possibilities:
|
|
110
110
|
There's lots more, too:
|
111
111
|
|
112
112
|
* Complete validations support: the flex-column object includes ActiveModel::Validations, so every single Rails validation (or custom validations) will work perfectly
|
113
|
-
* Bulk operations, for avoiding ActiveRecord instantiation (efficiently operate using raw
|
113
|
+
* Bulk operations, for avoiding ActiveRecord instantiation (efficiently operate using raw `select_all` and `activerecord-import` or similar systems)
|
114
114
|
* Transparently compresses JSON data in the column using GZip, if it's typed as binary (`BINARY`, `VARBINARY`, `CLOB`, etc.); you can fully control this, or turn it off if you want
|
115
115
|
* Happily allows definition and redefinition of flex columns at any time, for full dynamism and compatibility with development mode of Rails
|
116
116
|
* Rich error hierarchy and detailed exception messages — you will know exactly what went wrong when something goes wrong
|
117
117
|
* Include flex columns across associations, with control over exactly what's delegated and visibility of those methods (public or private)
|
118
118
|
* Control whether attribute methods generated are public (default) or private (to encourage encapsulation)
|
119
|
-
* "Types": automatically adds validations that require fields to comply with database types like
|
119
|
+
* "Types": automatically adds validations that require fields to comply with database types like `:integer`, `:string`, `:timestamp`, etc.
|
120
120
|
* Decide whether to preserve (the default) or delete keys from the underlying JSON that aren't defined in the flex column — lets you ensure database data is of the highest quality, or be compatible with any other storage mechanisms
|
121
121
|
|
122
122
|
### Documentation
|
@@ -60,8 +60,7 @@ module FlexColumns
|
|
60
60
|
|
61
61
|
reason = nil
|
62
62
|
|
63
|
-
reason ||= :column if columns.detect { |c| c.name.to_s == base_name }
|
64
|
-
# return false if method_defined?(base_name) || method_defined?("#{base_name}=")
|
63
|
+
reason ||= :column if table_exists? && columns.detect { |c| c.name.to_s == base_name }
|
65
64
|
reason ||= :instance_method if instance_methods(false).map(&:to_s).include?(base_name.to_s)
|
66
65
|
|
67
66
|
(! reason)
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module FlexColumns
|
2
|
+
module Definition
|
3
|
+
# This is a class that complies with just enough of the ActiveRecord interface to columns to be able to be
|
4
|
+
# swapped in for it, in our code.
|
5
|
+
#
|
6
|
+
# We use this in just one case: when you declare a flex column on a model class whose underlying table doesn't
|
7
|
+
# exist. If you call +.reset_column_information+ on the model in question, we'll pick up the new, actual column
|
8
|
+
# (assuming the table exists now), but, until then, we'll use this.
|
9
|
+
class FakeColumn
|
10
|
+
attr_reader :name
|
11
|
+
|
12
|
+
def initialize(name)
|
13
|
+
@name = name
|
14
|
+
end
|
15
|
+
|
16
|
+
def null
|
17
|
+
true
|
18
|
+
end
|
19
|
+
|
20
|
+
def type
|
21
|
+
:string
|
22
|
+
end
|
23
|
+
|
24
|
+
def limit
|
25
|
+
nil
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'flex_columns/definition/fake_column'
|
2
|
+
|
1
3
|
module FlexColumns
|
2
4
|
module Definition
|
3
5
|
# When you declare a flex column, we actually generate a brand-new Class for that column; instances of that flex
|
@@ -198,25 +200,11 @@ module FlexColumns
|
|
198
200
|
|
199
201
|
raise ArgumentError, "Invalid column name: #{column_name.inspect}" unless column_name.kind_of?(Symbol)
|
200
202
|
|
201
|
-
|
202
|
-
|
203
|
-
raise FlexColumns::Errors::NoSuchColumnError, %{You're trying to define a flex column #{column_name.inspect}, but
|
204
|
-
the model you're defining it on, #{model_class.name}, seems to have no column
|
205
|
-
named that.
|
206
|
-
|
207
|
-
It has columns named: #{model_class.columns.map(&:name).sort_by(&:to_s).join(", ")}.}
|
208
|
-
end
|
209
|
-
|
210
|
-
unless column.type == :binary || column.text? || column.sql_type == "json" # for PostgreSQL >= 9.2, which has a native JSON data type
|
211
|
-
raise FlexColumns::Errors::InvalidColumnTypeError, %{You're trying to define a flex column #{column_name.inspect}, but
|
212
|
-
that column (on model #{model_class.name}) isn't of a type that accepts text.
|
213
|
-
That column is of type: #{column.type.inspect}.}
|
214
|
-
end
|
203
|
+
@model_class = model_class
|
204
|
+
@column = find_column(column_name)
|
215
205
|
|
216
206
|
validate_options(options)
|
217
207
|
|
218
|
-
@model_class = model_class
|
219
|
-
@column = column
|
220
208
|
@options = options
|
221
209
|
@field_set = FlexColumns::Definition::FieldSet.new(self)
|
222
210
|
|
@@ -232,6 +220,14 @@ module FlexColumns
|
|
232
220
|
block_result
|
233
221
|
end
|
234
222
|
|
223
|
+
# This method gets called when ActiveRecord::Base.reset_column_information is called on the underlying model;
|
224
|
+
# this simply updates our notion of what column is present. Most importantly, this will correctly switch us from
|
225
|
+
# a table-does-not-exist state to a table-exists state (if you migrate the table in), but it also will correctly
|
226
|
+
# switch from one column type to another, etc.
|
227
|
+
def reset_column_information
|
228
|
+
@column = find_column(column_name)
|
229
|
+
end
|
230
|
+
|
235
231
|
# Tells this class to re-publish all its methods to the DynamicMethodsModule it uses internally, and to the
|
236
232
|
# model class it's a part of.
|
237
233
|
#
|
@@ -275,6 +271,40 @@ module FlexColumns
|
|
275
271
|
end
|
276
272
|
end
|
277
273
|
|
274
|
+
# Given the name of a column, finds the column on the model and makes sure it complies with our
|
275
|
+
# requirements for columns we can store data in.
|
276
|
+
#
|
277
|
+
# However, if the underlying table doesn't currently exist, this creates a "fake" column object and returns it;
|
278
|
+
# this fake column object responds to just enough methods that we can use it successfully in this gem. This is
|
279
|
+
# used so that we can define flex columns on a model for a table that doesn't exist yet (typically, because it
|
280
|
+
# hasn't been migrated in yet), and effectively upgrade it using .reset_column_information, above, when it
|
281
|
+
# does exist.
|
282
|
+
def find_column(column_name)
|
283
|
+
return create_temporary_fake_column(column_name) if (! @model_class.table_exists?)
|
284
|
+
|
285
|
+
out = model_class.columns.detect { |c| c.name.to_s == column_name.to_s }
|
286
|
+
unless out
|
287
|
+
raise FlexColumns::Errors::NoSuchColumnError, %{You're trying to define a flex column #{column_name.inspect}, but
|
288
|
+
the model you're defining it on, #{model_class.name}, seems to have no column
|
289
|
+
named that.
|
290
|
+
|
291
|
+
It has columns named: #{model_class.columns.map(&:name).sort_by(&:to_s).join(", ")}.}
|
292
|
+
end
|
293
|
+
|
294
|
+
unless out.type == :binary || out.text? || out.sql_type == "json" # for PostgreSQL >= 9.2, which has a native JSON data type
|
295
|
+
raise FlexColumns::Errors::InvalidColumnTypeError, %{You're trying to define a flex column #{column_name.inspect}, but
|
296
|
+
that column (on model #{model_class.name}) isn't of a type that accepts text.
|
297
|
+
That column is of type: #{out.type.inspect}.}
|
298
|
+
end
|
299
|
+
|
300
|
+
out
|
301
|
+
end
|
302
|
+
|
303
|
+
# This creates a "fake" column that we can use if the underlying table doesn't exist yet.
|
304
|
+
def create_temporary_fake_column(column_name)
|
305
|
+
::FlexColumns::Definition::FakeColumn.new(column_name)
|
306
|
+
end
|
307
|
+
|
278
308
|
# Check all of our options to make sure they're correct. This is pretty defensive programming, but it is SO
|
279
309
|
# much nicer to get an error on startup if you've specified anything incorrectly than way on down the line,
|
280
310
|
# possibly in production, when it really matters.
|
@@ -17,6 +17,10 @@ module FlexColumns
|
|
17
17
|
included do
|
18
18
|
before_validation :_flex_columns_before_validation!
|
19
19
|
before_save :_flex_columns_before_save!
|
20
|
+
|
21
|
+
class << self
|
22
|
+
alias_method_chain :reset_column_information, :flex_columns
|
23
|
+
end
|
20
24
|
end
|
21
25
|
|
22
26
|
# Before we save this model, make sure each flex column has a chance to serialize itself up and assign itself
|
@@ -133,6 +137,12 @@ module FlexColumns
|
|
133
137
|
end
|
134
138
|
|
135
139
|
module ClassMethods
|
140
|
+
def reset_column_information_with_flex_columns
|
141
|
+
reset_column_information_without_flex_columns
|
142
|
+
_flex_column_classes.each { |c| c.reset_column_information }
|
143
|
+
_flex_columns_redefine_all_methods!
|
144
|
+
end
|
145
|
+
|
136
146
|
# Does this class have any flex columns? If this module has been included into a class, then the answer is true.
|
137
147
|
def has_any_flex_columns?
|
138
148
|
true
|
@@ -177,8 +187,6 @@ it has flex columns named: #{_all_flex_column_names.sort_by(&:to_s).inspect}.}
|
|
177
187
|
# FlexColumns::Definition::FlexColumnContentsClass#setup!, and so can contain any of the options that that method
|
178
188
|
# accepts. The block, if passed, will be evaluated in the context of the generated class.
|
179
189
|
def flex_column(flex_column_name, options = { }, &block)
|
180
|
-
return unless table_exists?
|
181
|
-
|
182
190
|
flex_column_name = _flex_column_normalize_name(flex_column_name)
|
183
191
|
|
184
192
|
new_class = Class.new(FlexColumns::Contents::FlexColumnContentsBase)
|
@@ -191,6 +199,12 @@ it has flex columns named: #{_all_flex_column_names.sort_by(&:to_s).inspect}.}
|
|
191
199
|
_flex_column_object_for(flex_column_name)
|
192
200
|
end
|
193
201
|
|
202
|
+
_flex_columns_redefine_all_methods!
|
203
|
+
end
|
204
|
+
|
205
|
+
# Defines, or redefines, all methods on the dynamic-methods module associated with this model. This gets called
|
206
|
+
# whenever we define a new flex column, or if you call .reset_column_information on the associated model.
|
207
|
+
def _flex_columns_redefine_all_methods!
|
194
208
|
_flex_column_dynamic_methods_module.remove_all_methods!
|
195
209
|
_flex_column_classes.each(&:sync_methods!)
|
196
210
|
end
|
data/lib/flex_columns/version.rb
CHANGED
@@ -14,6 +14,14 @@ module FlexColumns
|
|
14
14
|
end
|
15
15
|
end
|
16
16
|
|
17
|
+
def reset_schema_cache!(model)
|
18
|
+
if model.connection.respond_to?(:schema_cache)
|
19
|
+
model.connection.schema_cache.clear!
|
20
|
+
elsif model.connection.respond_to?(:clear_cache!)
|
21
|
+
model.connection.clear_cache!
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
17
25
|
def define_model_class(name, table_name, &block)
|
18
26
|
model_class = Class.new(::ActiveRecord::Base)
|
19
27
|
::Object.send(:remove_const, name) if ::Object.const_defined?(name)
|
@@ -280,8 +280,6 @@ describe "FlexColumns basic operations" do
|
|
280
280
|
user.name = 'User 1'
|
281
281
|
user.wants_email = [ 1, 2, 3 ]
|
282
282
|
|
283
|
-
$stderr.puts "ATTRIBUTES: #{user.attributes.keys.sort.inspect}"
|
284
|
-
|
285
283
|
user_json = JSON.dump(user)
|
286
284
|
parsed = JSON.parse(user_json)
|
287
285
|
|
@@ -308,6 +306,7 @@ describe "FlexColumns basic operations" do
|
|
308
306
|
field :bbb
|
309
307
|
end
|
310
308
|
end
|
309
|
+
define_model_class(:UserBackdoor, 'flexcols_spec_users') { }
|
311
310
|
|
312
311
|
::User.reset_column_information
|
313
312
|
|
@@ -26,6 +26,82 @@ describe "FlexColumns basic operations" do
|
|
26
26
|
end
|
27
27
|
end
|
28
28
|
|
29
|
+
it "should handle the case where a table comes into existence after being defined -- like it will when running a bunch of migrations at once" do
|
30
|
+
migrate do
|
31
|
+
drop_table :flexcols_coming_into_existence rescue nil
|
32
|
+
end
|
33
|
+
|
34
|
+
class ::Foo < ::ActiveRecord::Base
|
35
|
+
self.table_name = 'flexcols_coming_into_existence'
|
36
|
+
|
37
|
+
flex_column :foo do
|
38
|
+
field :att1
|
39
|
+
field :att2
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
migrate do
|
44
|
+
create_table :flexcols_coming_into_existence do |t|
|
45
|
+
t.string :name
|
46
|
+
t.string :foo
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
reset_schema_cache!(Foo)
|
51
|
+
Foo.reset_column_information
|
52
|
+
|
53
|
+
f2 = Foo.new
|
54
|
+
f2.att1 = "the_att1"
|
55
|
+
f2.att2 = "the_att2"
|
56
|
+
f2.save!
|
57
|
+
|
58
|
+
f2_again = Foo.find(f2.id)
|
59
|
+
f2_again.att1.should == "the_att1"
|
60
|
+
f2_again.att2.should == "the_att2"
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should handle the case where a table comes into existence after being defined, and properly respect things like :binary and compression" do
|
64
|
+
migrate do
|
65
|
+
drop_table :flexcols_coming_into_existence rescue nil
|
66
|
+
end
|
67
|
+
|
68
|
+
class ::Foo < ::ActiveRecord::Base
|
69
|
+
self.table_name = 'flexcols_coming_into_existence'
|
70
|
+
|
71
|
+
flex_column :foo do
|
72
|
+
field :att1
|
73
|
+
field :att2
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
migrate do
|
78
|
+
create_table :flexcols_coming_into_existence do |t|
|
79
|
+
t.string :name
|
80
|
+
t.binary :foo
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
reset_schema_cache!(Foo)
|
85
|
+
Foo.reset_column_information
|
86
|
+
|
87
|
+
f2 = Foo.new
|
88
|
+
f2.att1 = "the_att1"
|
89
|
+
f2.att2 = "the_att2" * 1000
|
90
|
+
f2.save!
|
91
|
+
|
92
|
+
f2_again = Foo.find(f2.id)
|
93
|
+
f2_again.att1.should == "the_att1"
|
94
|
+
f2_again.att2.should == "the_att2" * 1000
|
95
|
+
|
96
|
+
class ::FooBackdoor < ActiveRecord::Base
|
97
|
+
self.table_name = 'flexcols_coming_into_existence'
|
98
|
+
end
|
99
|
+
|
100
|
+
f2_backdoor = ::FooBackdoor.find(f2.id)
|
101
|
+
data = f2_backdoor.foo
|
102
|
+
data.should match(/^FC:01,1,/i)
|
103
|
+
end
|
104
|
+
|
29
105
|
it "should let you redefine flex columns, and obey the new settings" do
|
30
106
|
class ::User < ::ActiveRecord::Base
|
31
107
|
self.table_name = 'flexcols_spec_users'
|
@@ -130,8 +130,8 @@ describe "FlexColumns performance" do
|
|
130
130
|
|
131
131
|
before :each do
|
132
132
|
migrate do
|
133
|
-
drop_table :
|
134
|
-
create_table :
|
133
|
+
drop_table :flexcols_spec_users_2 rescue nil
|
134
|
+
create_table :flexcols_spec_users_2 do |t|
|
135
135
|
t.string :name, :null => false
|
136
136
|
t.text :text_attrs_nonnull, :null => false
|
137
137
|
t.text :text_attrs_null
|
@@ -140,9 +140,9 @@ describe "FlexColumns performance" do
|
|
140
140
|
end
|
141
141
|
end
|
142
142
|
|
143
|
-
::User
|
143
|
+
# reset_schema_cache!(::User) if defined?(::User)
|
144
144
|
|
145
|
-
define_model_class(:
|
145
|
+
define_model_class(:User2, 'flexcols_spec_users_2') do
|
146
146
|
flex_column :text_attrs_nonnull do
|
147
147
|
field :aaa
|
148
148
|
end
|
@@ -157,9 +157,9 @@ describe "FlexColumns performance" do
|
|
157
157
|
end
|
158
158
|
end
|
159
159
|
|
160
|
-
define_model_class(:
|
160
|
+
define_model_class(:User2Backdoor, 'flexcols_spec_users_2') { }
|
161
161
|
|
162
|
-
::
|
162
|
+
::User2Backdoor.reset_column_information
|
163
163
|
end
|
164
164
|
|
165
165
|
it "should be smart enough to store an empty JSON string to the database, if necessary, if the column is non-NULL" do
|
@@ -171,11 +171,11 @@ describe "FlexColumns performance" do
|
|
171
171
|
# those circumstances, rather than trying to work around this (pretty broken) behavior that's also a pretty rare
|
172
172
|
# edge case for us.
|
173
173
|
unless defined?(RUBY_ENGINE) && RUBY_ENGINE == 'jruby' && @dh.database_type == :mysql
|
174
|
-
my_user = ::
|
174
|
+
my_user = ::User2.new
|
175
175
|
my_user.name = 'User 1'
|
176
176
|
my_user.save!
|
177
177
|
|
178
|
-
user_bd = ::
|
178
|
+
user_bd = ::User2Backdoor.find(my_user.id)
|
179
179
|
user_bd.name.should == 'User 1'
|
180
180
|
user_bd.text_attrs_nonnull.should == ""
|
181
181
|
user_bd.text_attrs_null.should == nil
|
@@ -185,7 +185,7 @@ describe "FlexColumns performance" do
|
|
185
185
|
end
|
186
186
|
|
187
187
|
it "should store NULL or the empty string in the database, as appropriate, if there's no data left any more" do
|
188
|
-
my_user = ::
|
188
|
+
my_user = ::User2.new
|
189
189
|
my_user.name = 'User 1'
|
190
190
|
my_user.aaa = 'aaa1'
|
191
191
|
my_user.bbb = 'bbb1'
|
@@ -193,21 +193,21 @@ describe "FlexColumns performance" do
|
|
193
193
|
my_user.ddd = 'ddd1'
|
194
194
|
my_user.save!
|
195
195
|
|
196
|
-
user_bd = ::
|
196
|
+
user_bd = ::User2Backdoor.find(my_user.id)
|
197
197
|
user_bd.name.should == 'User 1'
|
198
198
|
check_text_column_data(user_bd.text_attrs_nonnull, 'aaa', 'aaa1')
|
199
199
|
check_text_column_data(user_bd.text_attrs_null, 'bbb', 'bbb1')
|
200
200
|
check_binary_column_data(user_bd.binary_attrs_nonnull, 'ccc', 'ccc1')
|
201
201
|
check_binary_column_data(user_bd.binary_attrs_null, 'ddd', 'ddd1')
|
202
202
|
|
203
|
-
user_again = ::
|
203
|
+
user_again = ::User2.find(my_user.id)
|
204
204
|
user_again.aaa = nil
|
205
205
|
user_again.bbb = nil
|
206
206
|
user_again.ccc = nil
|
207
207
|
user_again.ddd = nil
|
208
208
|
user_again.save!
|
209
209
|
|
210
|
-
user_bd_again = ::
|
210
|
+
user_bd_again = ::User2Backdoor.find(my_user.id)
|
211
211
|
user_bd_again.name.should == 'User 1'
|
212
212
|
user_bd_again.text_attrs_nonnull.should == ""
|
213
213
|
user_bd_again.text_attrs_null.should == nil
|
@@ -10,6 +10,7 @@ describe FlexColumns::Definition::FlexColumnContentsClass do
|
|
10
10
|
@klass.send(:extend, FlexColumns::Definition::FlexColumnContentsClass)
|
11
11
|
|
12
12
|
@model_class = double("model_class")
|
13
|
+
allow(@model_class).to receive(:table_exists?).with().and_return(true)
|
13
14
|
allow(@model_class).to receive(:kind_of?).with(Class).and_return(true)
|
14
15
|
allow(@model_class).to receive(:has_any_flex_columns?).with().and_return(true)
|
15
16
|
allow(@model_class).to receive(:name).with().and_return(:mcname)
|
@@ -121,6 +122,12 @@ describe FlexColumns::Definition::FlexColumnContentsClass do
|
|
121
122
|
e.message.should match(/integer/i)
|
122
123
|
end
|
123
124
|
|
125
|
+
it "should work if the table doesn't exist" do
|
126
|
+
allow(@model_class).to receive(:table_exists?).with().and_return(false)
|
127
|
+
allow(@model_class).to receive(:columns).and_raise(StandardError) # to make sure we don't touch this
|
128
|
+
@klass.setup!(@model_class, :foo) { }
|
129
|
+
end
|
130
|
+
|
124
131
|
it "should work on a text column" do
|
125
132
|
@klass.setup!(@model_class, :foo) { }
|
126
133
|
end
|
@@ -204,6 +211,41 @@ describe FlexColumns::Definition::FlexColumnContentsClass do
|
|
204
211
|
end
|
205
212
|
end
|
206
213
|
|
214
|
+
describe "reset_column_information" do
|
215
|
+
it "should still generate a fake column if the table still doesn't exist" do
|
216
|
+
allow(@model_class).to receive(:table_exists?).with().and_return(false)
|
217
|
+
@klass.setup!(@model_class, :bar) { }
|
218
|
+
c = @klass.column
|
219
|
+
c.name.should == :bar
|
220
|
+
c.type.should == :string
|
221
|
+
c.null.should == true
|
222
|
+
|
223
|
+
@klass.reset_column_information
|
224
|
+
c = @klass.column
|
225
|
+
c.name.should == :bar
|
226
|
+
c.type.should == :string
|
227
|
+
c.null.should == true
|
228
|
+
end
|
229
|
+
|
230
|
+
it "should pull a real column if the table does exist" do
|
231
|
+
allow(@column_bar).to receive(:null).with().and_return(false)
|
232
|
+
|
233
|
+
allow(@model_class).to receive(:table_exists?).with().and_return(false)
|
234
|
+
@klass.setup!(@model_class, :bar) { }
|
235
|
+
c = @klass.column
|
236
|
+
c.name.should == :bar
|
237
|
+
c.type.should == :string
|
238
|
+
c.null.should == true
|
239
|
+
|
240
|
+
allow(@model_class).to receive(:table_exists?).with().and_return(true)
|
241
|
+
@klass.reset_column_information
|
242
|
+
c = @klass.column
|
243
|
+
c.name.should == :bar
|
244
|
+
c.type.should == :binary
|
245
|
+
c.null.should == false
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
207
249
|
describe "_flex_columns_create_column_data" do
|
208
250
|
def expect_options_transform(class_options, length_limit, resulting_options, column_name = :foo, storage_string = double("storage_string"))
|
209
251
|
@klass.setup!(@model_class, column_name, class_options)
|
@@ -30,6 +30,10 @@ describe FlexColumns::HasFlexColumns do
|
|
30
30
|
def table_exists?
|
31
31
|
true
|
32
32
|
end
|
33
|
+
|
34
|
+
def reset_column_information
|
35
|
+
# nothing here
|
36
|
+
end
|
33
37
|
end
|
34
38
|
|
35
39
|
def _flex_column_object_for(column_name, create_if_needed = true)
|
@@ -59,6 +63,39 @@ describe FlexColumns::HasFlexColumns do
|
|
59
63
|
@klass.has_any_flex_columns?.should be
|
60
64
|
end
|
61
65
|
|
66
|
+
describe "#_flex_columns_redefine_all_methods" do
|
67
|
+
it "should remove all methods on the module, and then add them back" do
|
68
|
+
dmm = double("dmm")
|
69
|
+
expect(FlexColumns::Util::DynamicMethodsModule).to receive(:new).once.with(@klass, :FlexColumnsDynamicMethods).and_return(dmm)
|
70
|
+
|
71
|
+
fcc1 = double("fcc1", :column_name => :foo)
|
72
|
+
expect(Class).to receive(:new).once.ordered.with(FlexColumns::Contents::FlexColumnContentsBase).and_return(fcc1)
|
73
|
+
expect(fcc1).to receive(:setup!).once.ordered.with(@klass, :foo, { })
|
74
|
+
|
75
|
+
expect(dmm).to receive(:remove_all_methods!).once.ordered.with()
|
76
|
+
expect(fcc1).to receive(:sync_methods!).once.ordered.with()
|
77
|
+
|
78
|
+
@klass.flex_column(:foo)
|
79
|
+
|
80
|
+
fcc2 = double("fcc2", :column_name => :bar)
|
81
|
+
expect(Class).to receive(:new).once.ordered.with(FlexColumns::Contents::FlexColumnContentsBase).and_return(fcc2)
|
82
|
+
expect(fcc2).to receive(:setup!).once.ordered.with(@klass, :bar, { })
|
83
|
+
|
84
|
+
expect(dmm).to receive(:remove_all_methods!).once.ordered.with()
|
85
|
+
expect(fcc1).to receive(:sync_methods!).once.ordered.with()
|
86
|
+
expect(fcc2).to receive(:sync_methods!).once.ordered.with()
|
87
|
+
|
88
|
+
@klass.flex_column(:bar)
|
89
|
+
|
90
|
+
|
91
|
+
expect(dmm).to receive(:remove_all_methods!).once.ordered.with()
|
92
|
+
expect(fcc1).to receive(:sync_methods!).once.ordered.with()
|
93
|
+
expect(fcc2).to receive(:sync_methods!).once.ordered.with()
|
94
|
+
|
95
|
+
@klass._flex_columns_redefine_all_methods!
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
62
99
|
describe "#flex_column" do
|
63
100
|
it "should do nothing if the table doesn't exist" do
|
64
101
|
allow(@klass).to receive(:table_exists?).with().and_return(false)
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: flex_columns
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.7
|
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: 2014-04-
|
12
|
+
date: 2014-04-08 00:00:00 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: json
|
@@ -106,6 +106,7 @@ files:
|
|
106
106
|
- lib/flex_columns/active_record/base.rb
|
107
107
|
- lib/flex_columns/contents/column_data.rb
|
108
108
|
- lib/flex_columns/contents/flex_column_contents_base.rb
|
109
|
+
- lib/flex_columns/definition/fake_column.rb
|
109
110
|
- lib/flex_columns/definition/field_definition.rb
|
110
111
|
- lib/flex_columns/definition/field_set.rb
|
111
112
|
- lib/flex_columns/definition/flex_column_contents_class.rb
|
@@ -135,6 +136,7 @@ files:
|
|
135
136
|
- spec/flex_columns/unit/active_record/base_spec.rb
|
136
137
|
- spec/flex_columns/unit/contents/column_data_spec.rb
|
137
138
|
- spec/flex_columns/unit/contents/flex_column_contents_base_spec.rb
|
139
|
+
- spec/flex_columns/unit/definition/fake_column_spec.rb
|
138
140
|
- spec/flex_columns/unit/definition/field_definition_spec.rb
|
139
141
|
- spec/flex_columns/unit/definition/field_set_spec.rb
|
140
142
|
- spec/flex_columns/unit/definition/flex_column_contents_class_spec.rb
|
@@ -187,6 +189,7 @@ test_files:
|
|
187
189
|
- spec/flex_columns/unit/active_record/base_spec.rb
|
188
190
|
- spec/flex_columns/unit/contents/column_data_spec.rb
|
189
191
|
- spec/flex_columns/unit/contents/flex_column_contents_base_spec.rb
|
192
|
+
- spec/flex_columns/unit/definition/fake_column_spec.rb
|
190
193
|
- spec/flex_columns/unit/definition/field_definition_spec.rb
|
191
194
|
- spec/flex_columns/unit/definition/field_set_spec.rb
|
192
195
|
- spec/flex_columns/unit/definition/flex_column_contents_class_spec.rb
|