flex_columns 1.0.6 → 1.0.7
Sign up to get free protection for your applications and to get access to all the features.
- 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
|