flex_columns 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +18 -0
- data/.travis.yml +38 -0
- data/Gemfile +17 -0
- data/LICENSE.txt +22 -0
- data/README.md +124 -0
- data/Rakefile +6 -0
- data/flex_columns.gemspec +72 -0
- data/lib/flex_columns.rb +15 -0
- data/lib/flex_columns/active_record/base.rb +57 -0
- data/lib/flex_columns/contents/column_data.rb +376 -0
- data/lib/flex_columns/contents/flex_column_contents_base.rb +188 -0
- data/lib/flex_columns/definition/field_definition.rb +316 -0
- data/lib/flex_columns/definition/field_set.rb +89 -0
- data/lib/flex_columns/definition/flex_column_contents_class.rb +327 -0
- data/lib/flex_columns/errors.rb +236 -0
- data/lib/flex_columns/has_flex_columns.rb +187 -0
- data/lib/flex_columns/including/include_flex_columns.rb +179 -0
- data/lib/flex_columns/util/dynamic_methods_module.rb +86 -0
- data/lib/flex_columns/util/string_utils.rb +31 -0
- data/lib/flex_columns/version.rb +4 -0
- data/spec/flex_columns/helpers/database_helper.rb +174 -0
- data/spec/flex_columns/helpers/exception_helpers.rb +20 -0
- data/spec/flex_columns/helpers/system_helpers.rb +47 -0
- data/spec/flex_columns/system/basic_system_spec.rb +245 -0
- data/spec/flex_columns/system/bulk_system_spec.rb +153 -0
- data/spec/flex_columns/system/compression_system_spec.rb +218 -0
- data/spec/flex_columns/system/custom_methods_system_spec.rb +120 -0
- data/spec/flex_columns/system/delegation_system_spec.rb +175 -0
- data/spec/flex_columns/system/dynamism_system_spec.rb +158 -0
- data/spec/flex_columns/system/error_handling_system_spec.rb +117 -0
- data/spec/flex_columns/system/including_system_spec.rb +285 -0
- data/spec/flex_columns/system/json_alias_system_spec.rb +171 -0
- data/spec/flex_columns/system/performance_system_spec.rb +218 -0
- data/spec/flex_columns/system/postgres_json_column_type_system_spec.rb +85 -0
- data/spec/flex_columns/system/types_system_spec.rb +93 -0
- data/spec/flex_columns/system/unknown_fields_system_spec.rb +126 -0
- data/spec/flex_columns/system/validations_system_spec.rb +111 -0
- data/spec/flex_columns/unit/active_record/base_spec.rb +32 -0
- data/spec/flex_columns/unit/contents/column_data_spec.rb +520 -0
- data/spec/flex_columns/unit/contents/flex_column_contents_base_spec.rb +253 -0
- data/spec/flex_columns/unit/definition/field_definition_spec.rb +617 -0
- data/spec/flex_columns/unit/definition/field_set_spec.rb +142 -0
- data/spec/flex_columns/unit/definition/flex_column_contents_class_spec.rb +733 -0
- data/spec/flex_columns/unit/errors_spec.rb +297 -0
- data/spec/flex_columns/unit/has_flex_columns_spec.rb +365 -0
- data/spec/flex_columns/unit/including/include_flex_columns_spec.rb +144 -0
- data/spec/flex_columns/unit/util/dynamic_methods_module_spec.rb +105 -0
- data/spec/flex_columns/unit/util/string_utils_spec.rb +23 -0
- metadata +286 -0
@@ -0,0 +1,31 @@
|
|
1
|
+
module FlexColumns
|
2
|
+
module Util
|
3
|
+
# Contains a single method for abbreviating strings.
|
4
|
+
#
|
5
|
+
# Yes, this is very un-Ruby-like -- to define a separate utility function, rather than just adding a method to
|
6
|
+
# String. However, this method is used in such limited context (generating exception messages) that polluting the
|
7
|
+
# namespace of one of the most important classes in Ruby is probably a pretty bad idea.
|
8
|
+
class StringUtils
|
9
|
+
class << self
|
10
|
+
MAX_LENGTH_FOR_ABBREVIATED_STRING = 100
|
11
|
+
ABBREVIATED_STRING_SEPARATOR = "..."
|
12
|
+
|
13
|
+
# Returns a string of length no more than MAX_LENGTH_FOR_ABBREVIATED_STRING, by eliding, if necessary,
|
14
|
+
# characters from the middle. This is used when throwing exceptions: +flex_columns+ can generate very long
|
15
|
+
# strings of JSON data, and having many kilobytes (or even megabytes) of JSON make its way into an exception
|
16
|
+
# message is probably a really bad idea.
|
17
|
+
def abbreviated_string(s)
|
18
|
+
if s && s.length > MAX_LENGTH_FOR_ABBREVIATED_STRING
|
19
|
+
before_separator_length = ((MAX_LENGTH_FOR_ABBREVIATED_STRING - ABBREVIATED_STRING_SEPARATOR.length) / 2.0).floor
|
20
|
+
out = s[0..(before_separator_length - 1)] + ABBREVIATED_STRING_SEPARATOR
|
21
|
+
remaining = MAX_LENGTH_FOR_ABBREVIATED_STRING - out.length
|
22
|
+
out << s[(-remaining + 1)..-1]
|
23
|
+
out
|
24
|
+
else
|
25
|
+
s
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,174 @@
|
|
1
|
+
module FlexColumns
|
2
|
+
module Helpers
|
3
|
+
class DatabaseHelper
|
4
|
+
class InvalidDatabaseConfigurationError < StandardError; end
|
5
|
+
|
6
|
+
class << self
|
7
|
+
def maybe_database_gem_name
|
8
|
+
begin
|
9
|
+
dh = new
|
10
|
+
dh.database_gem_name
|
11
|
+
rescue InvalidDatabaseConfigurationError => idce
|
12
|
+
nil
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def initialize
|
18
|
+
config # make sure we raise on instantiation if configuration is invalid
|
19
|
+
end
|
20
|
+
|
21
|
+
def database_type
|
22
|
+
case database_gem_name
|
23
|
+
when /mysql/i then :mysql
|
24
|
+
when /sqlite/i then :sqlite
|
25
|
+
when /pg/i, /postgres/i then :postgres
|
26
|
+
else raise "Unknown database type for Gem name: #{database_gem_name.inspect}"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def setup_activerecord!
|
31
|
+
require 'active_record'
|
32
|
+
require config[:require]
|
33
|
+
::ActiveRecord::Base.establish_connection(config[:config])
|
34
|
+
|
35
|
+
require 'logger'
|
36
|
+
require 'stringio'
|
37
|
+
@logs = StringIO.new
|
38
|
+
::ActiveRecord::Base.logger = Logger.new(@logs)
|
39
|
+
|
40
|
+
if config[:config][:adapter] == 'sqlite3'
|
41
|
+
sqlite_version = ::ActiveRecord::Base.connection.send(:sqlite_version).instance_variable_get("@version").inspect rescue "unknown"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def table_name(name)
|
46
|
+
"flexcols_spec_#{name}"
|
47
|
+
end
|
48
|
+
|
49
|
+
def database_gem_name
|
50
|
+
config[:database_gem_name]
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
def config
|
55
|
+
config_from_config_file || travis_ci_config_from_environment || invalid_config_file!
|
56
|
+
end
|
57
|
+
|
58
|
+
def config_from_config_file
|
59
|
+
return nil unless File.exist?(config_file_path)
|
60
|
+
require config_file_path
|
61
|
+
|
62
|
+
return nil unless defined?(FLEX_COLUMNS_SPEC_DATABASE_CONFIG)
|
63
|
+
return nil unless FLEX_COLUMNS_SPEC_DATABASE_CONFIG.kind_of?(Hash)
|
64
|
+
|
65
|
+
return nil unless FLEX_COLUMNS_SPEC_DATABASE_CONFIG[:require]
|
66
|
+
return nil unless FLEX_COLUMNS_SPEC_DATABASE_CONFIG[:database_gem_name]
|
67
|
+
|
68
|
+
return nil unless FLEX_COLUMNS_SPEC_DATABASE_CONFIG
|
69
|
+
FLEX_COLUMNS_SPEC_DATABASE_CONFIG
|
70
|
+
end
|
71
|
+
|
72
|
+
def travis_ci_config_from_environment
|
73
|
+
dbtype = (ENV['FLEX_COLUMNS_TRAVIS_CI_DATABASE_TYPE'] || '').strip.downcase
|
74
|
+
is_jruby = defined?(RUBY_ENGINE) && RUBY_ENGINE == 'jruby'
|
75
|
+
|
76
|
+
if is_jruby
|
77
|
+
case dbtype
|
78
|
+
when 'mysql'
|
79
|
+
{
|
80
|
+
:require => 'activerecord-jdbcmysql-adapter',
|
81
|
+
:database_gem_name => 'activerecord-jdbcmysql-adapter',
|
82
|
+
:config => {
|
83
|
+
:adapter => 'jdbcmysql',
|
84
|
+
:database => 'myapp_test',
|
85
|
+
:username => 'travis',
|
86
|
+
:encoding => 'utf8'
|
87
|
+
}
|
88
|
+
}
|
89
|
+
when 'postgres', 'postgresql'
|
90
|
+
{
|
91
|
+
:require => 'activerecord-jdbcpostgresql-adapter',
|
92
|
+
:database_gem_name => 'activerecord-jdbcpostgresql-adapter',
|
93
|
+
:config => {
|
94
|
+
:adapter => 'jdbcpostgresql',
|
95
|
+
:database => 'myapp_test',
|
96
|
+
:username => 'postgres'
|
97
|
+
}
|
98
|
+
}
|
99
|
+
when 'sqlite'
|
100
|
+
{
|
101
|
+
:require => 'activerecord-jdbcsqlite3-adapter',
|
102
|
+
:database_gem_name => 'activerecord-jdbcsqlite3-adapter',
|
103
|
+
:config => {
|
104
|
+
:adapter => 'jdbcsqlite3',
|
105
|
+
:database => ':memory:'
|
106
|
+
}
|
107
|
+
}
|
108
|
+
when '', nil then nil
|
109
|
+
else
|
110
|
+
raise "Unknown Travis CI database type: #{dbtype.inspect}"
|
111
|
+
end
|
112
|
+
else
|
113
|
+
case dbtype
|
114
|
+
when 'postgres', 'postgresql'
|
115
|
+
{
|
116
|
+
:require => 'pg',
|
117
|
+
:database_gem_name => 'pg',
|
118
|
+
:config => {
|
119
|
+
:adapter => 'postgresql',
|
120
|
+
:database => 'myapp_test',
|
121
|
+
:username => 'postgres',
|
122
|
+
:min_messages => 'WARNING'
|
123
|
+
}
|
124
|
+
}
|
125
|
+
when 'mysql'
|
126
|
+
{
|
127
|
+
:require => 'mysql2',
|
128
|
+
:database_gem_name => 'mysql2',
|
129
|
+
:config => {
|
130
|
+
:adapter => 'mysql2',
|
131
|
+
:database => 'myapp_test',
|
132
|
+
:username => 'travis',
|
133
|
+
:encoding => 'utf8'
|
134
|
+
}
|
135
|
+
}
|
136
|
+
when 'sqlite'
|
137
|
+
{
|
138
|
+
:require => 'sqlite3',
|
139
|
+
:database_gem_name => 'sqlite3',
|
140
|
+
:config => {
|
141
|
+
:adapter => 'sqlite3',
|
142
|
+
:database => ':memory:',
|
143
|
+
:timeout => 500
|
144
|
+
}
|
145
|
+
}
|
146
|
+
when '', nil then nil
|
147
|
+
else
|
148
|
+
raise "Unknown Travis CI database type: #{dbtype.inspect}"
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
def config_file_path
|
154
|
+
@config_file_path ||= File.expand_path(File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_database_config.rb'))
|
155
|
+
end
|
156
|
+
|
157
|
+
def invalid_config_file!
|
158
|
+
raise Errno::ENOENT, %{In order to run specs for FlexColumns, you need to create a file at:
|
159
|
+
|
160
|
+
#{config_file_path}
|
161
|
+
|
162
|
+
...that defines a top-level FLEX_COLUMNS_SPEC_DATABASE_CONFIG hash, with members:
|
163
|
+
|
164
|
+
:require => 'name_of_adapter_to_require',
|
165
|
+
:database_gem_name => 'name_of_gem_for_adapter',
|
166
|
+
:config => { ...whatever ActiveRecord::Base.establish_connection should be passed... }
|
167
|
+
|
168
|
+
Alternatively, if you're running under Travis CI, you can set the environment variable
|
169
|
+
FLEX_COLUMNS_TRAVIS_CI_DATABASE_TYPE to 'postgres', 'mysql', or 'sqlite', and it will
|
170
|
+
use the correct configuration for testing on Travis CI.}
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module FlexColumns
|
2
|
+
module Helpers
|
3
|
+
module ExceptionHelpers
|
4
|
+
def capture_exception(required_class = Exception, &block)
|
5
|
+
e = nil
|
6
|
+
begin
|
7
|
+
block.call
|
8
|
+
rescue required_class => x
|
9
|
+
e = x
|
10
|
+
end
|
11
|
+
|
12
|
+
unless e
|
13
|
+
raise "Expected an exception of class #{required_class.inspect}, but none was raised"
|
14
|
+
end
|
15
|
+
|
16
|
+
e
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'active_record'
|
2
|
+
require 'active_record/migration'
|
3
|
+
|
4
|
+
module FlexColumns
|
5
|
+
module Helpers
|
6
|
+
module SystemHelpers
|
7
|
+
def migrate(&block)
|
8
|
+
migration_class = Class.new(::ActiveRecord::Migration)
|
9
|
+
metaclass = migration_class.class_eval { class << self; self; end }
|
10
|
+
metaclass.instance_eval { define_method(:up, &block) }
|
11
|
+
|
12
|
+
::ActiveRecord::Migration.suppress_messages do
|
13
|
+
migration_class.migrate(:up)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def define_model_class(name, table_name, &block)
|
18
|
+
model_class = Class.new(::ActiveRecord::Base)
|
19
|
+
::Object.send(:remove_const, name) if ::Object.const_defined?(name)
|
20
|
+
::Object.const_set(name, model_class)
|
21
|
+
model_class.table_name = table_name
|
22
|
+
model_class.class_eval(&block)
|
23
|
+
end
|
24
|
+
|
25
|
+
def create_standard_system_spec_tables!
|
26
|
+
migrate do
|
27
|
+
drop_table :flexcols_spec_users rescue nil
|
28
|
+
create_table :flexcols_spec_users do |t|
|
29
|
+
t.string :name, :null => false
|
30
|
+
t.text :user_attributes
|
31
|
+
t.text :more_attributes
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def create_standard_system_spec_models!
|
37
|
+
define_model_class(:User, 'flexcols_spec_users') { }
|
38
|
+
end
|
39
|
+
|
40
|
+
def drop_standard_system_spec_tables!
|
41
|
+
migrate do
|
42
|
+
drop_table :flexcols_spec_users rescue nil
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,245 @@
|
|
1
|
+
require 'flex_columns'
|
2
|
+
require 'flex_columns/helpers/system_helpers'
|
3
|
+
|
4
|
+
describe "FlexColumns basic operations" do
|
5
|
+
include FlexColumns::Helpers::SystemHelpers
|
6
|
+
|
7
|
+
before :each do
|
8
|
+
@dh = FlexColumns::Helpers::DatabaseHelper.new
|
9
|
+
@dh.setup_activerecord!
|
10
|
+
|
11
|
+
create_standard_system_spec_tables!
|
12
|
+
end
|
13
|
+
|
14
|
+
after :each do
|
15
|
+
drop_standard_system_spec_tables!
|
16
|
+
end
|
17
|
+
|
18
|
+
context "with a very simple column definition" do
|
19
|
+
before :each do
|
20
|
+
define_model_class(:User, 'flexcols_spec_users') do
|
21
|
+
flex_column :user_attributes do
|
22
|
+
field :wants_email
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should be able to serialize and deserialize a very simple example" do
|
28
|
+
define_model_class(:UserBackdoor, 'flexcols_spec_users') { }
|
29
|
+
|
30
|
+
user = ::User.new
|
31
|
+
user.name = 'User 1'
|
32
|
+
user.user_attributes['wants_email'] = 'sometimes'
|
33
|
+
user.user_attributes['wants_email'].should == 'sometimes'
|
34
|
+
user.save!
|
35
|
+
|
36
|
+
user.user_attributes['wants_email'].should == 'sometimes'
|
37
|
+
|
38
|
+
user2 = ::User.find(user.id)
|
39
|
+
user2.user_attributes['wants_email'].should == 'sometimes'
|
40
|
+
user2.user_attributes.keys.should == [ :wants_email ]
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should store its data as standard JSON" do
|
44
|
+
user = ::User.new
|
45
|
+
user.name = 'User 1'
|
46
|
+
user.user_attributes['wants_email'] = 'sometimes'
|
47
|
+
user.save!
|
48
|
+
|
49
|
+
bd = ::UserBackdoor.find(user.id)
|
50
|
+
bd.should be
|
51
|
+
bd.id.should == user.id
|
52
|
+
|
53
|
+
string = bd.user_attributes
|
54
|
+
string.should be
|
55
|
+
string.length.should > 0
|
56
|
+
|
57
|
+
contents = JSON.parse(string)
|
58
|
+
contents.class.should == Hash
|
59
|
+
contents.keys.should == [ 'wants_email' ]
|
60
|
+
contents['wants_email'].should == 'sometimes'
|
61
|
+
end
|
62
|
+
|
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
|
64
|
+
define_model_class(:UserBackdoor, 'flexcols_spec_users') { }
|
65
|
+
|
66
|
+
weirdly_spaced_json = ' { "wants_email" : "boop" } '
|
67
|
+
|
68
|
+
user_bd = ::UserBackdoor.new
|
69
|
+
user_bd.name = 'User 1'
|
70
|
+
user_bd.user_attributes = weirdly_spaced_json
|
71
|
+
user_bd.save!
|
72
|
+
|
73
|
+
user = ::User.find(user_bd.id)
|
74
|
+
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!
|
84
|
+
user.save!
|
85
|
+
|
86
|
+
user_bd_again = ::UserBackdoor.find(user_bd.id)
|
87
|
+
user_bd_again.name.should == 'User 1'
|
88
|
+
user_bd_again.user_attributes.should == '{"wants_email":"boop"}'
|
89
|
+
end
|
90
|
+
|
91
|
+
it "should provide access to attributes as methods" do
|
92
|
+
user = ::User.new
|
93
|
+
user.name = 'User 1'
|
94
|
+
user.user_attributes.wants_email = 'sometimes'
|
95
|
+
user.user_attributes.wants_email.should == 'sometimes'
|
96
|
+
user.user_attributes['wants_email'].should == 'sometimes'
|
97
|
+
user.save!
|
98
|
+
|
99
|
+
user.user_attributes.wants_email.should == 'sometimes'
|
100
|
+
|
101
|
+
user2 = ::User.find(user.id)
|
102
|
+
user2.user_attributes.wants_email.should == 'sometimes'
|
103
|
+
user2.user_attributes.keys.should == [ :wants_email ]
|
104
|
+
end
|
105
|
+
|
106
|
+
it "should delegate methods to attributes automatically" do
|
107
|
+
user = ::User.new
|
108
|
+
user.name = 'User 1'
|
109
|
+
user.wants_email = 'sometimes'
|
110
|
+
user.wants_email.should == 'sometimes'
|
111
|
+
user.user_attributes['wants_email'].should == 'sometimes'
|
112
|
+
user.save!
|
113
|
+
|
114
|
+
user.wants_email.should == 'sometimes'
|
115
|
+
|
116
|
+
user2 = ::User.find(user.id)
|
117
|
+
user2.wants_email.should == 'sometimes'
|
118
|
+
user2.user_attributes.keys.should == [ :wants_email ]
|
119
|
+
end
|
120
|
+
|
121
|
+
it "should have a reasonable class name for contents" do
|
122
|
+
class_name = ::User.new.user_attributes.class.name
|
123
|
+
class_name.should match(/^user::/i)
|
124
|
+
class_name.should match(/userattributes/i)
|
125
|
+
class_name.should match(/flexcontents/i)
|
126
|
+
end
|
127
|
+
|
128
|
+
it "should let you make flex-column accessors private one-by-one" do
|
129
|
+
define_model_class(:User, 'flexcols_spec_users') do
|
130
|
+
flex_column :user_attributes do
|
131
|
+
field :wants_email, :visibility => :private
|
132
|
+
field :another_thing
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
user = ::User.new
|
137
|
+
user.user_attributes.respond_to?(:wants_email).should_not be
|
138
|
+
lambda { user.user_attributes.wants_email }.should raise_error(NoMethodError)
|
139
|
+
|
140
|
+
user.user_attributes.send(:wants_email).should be_nil
|
141
|
+
user.user_attributes.send("wants_email=", "foobar").should == "foobar"
|
142
|
+
user.user_attributes.send(:wants_email).should == "foobar"
|
143
|
+
|
144
|
+
user.user_attributes.another_thing = 123
|
145
|
+
user.user_attributes.another_thing.should == 123
|
146
|
+
|
147
|
+
user.respond_to?(:wants_email).should_not be
|
148
|
+
user.respond_to?(:another_thing).should be
|
149
|
+
end
|
150
|
+
|
151
|
+
it "should let you make flex-column accessors private en masse, and override it one-by-one" do
|
152
|
+
define_model_class(:User, 'flexcols_spec_users') do
|
153
|
+
flex_column :user_attributes, :visibility => :private do
|
154
|
+
field :wants_email
|
155
|
+
field :another_thing, :visibility => :public
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
user = ::User.new
|
160
|
+
user.user_attributes.respond_to?(:wants_email).should_not be
|
161
|
+
lambda { user.user_attributes.wants_email }.should raise_error(NoMethodError)
|
162
|
+
|
163
|
+
user.user_attributes.send(:wants_email).should be_nil
|
164
|
+
user.user_attributes.send("wants_email=", "foobar").should == "foobar"
|
165
|
+
user.user_attributes.send(:wants_email).should == "foobar"
|
166
|
+
|
167
|
+
user.user_attributes.another_thing = 123
|
168
|
+
user.user_attributes.another_thing.should == 123
|
169
|
+
|
170
|
+
user.respond_to?(:wants_email).should_not be
|
171
|
+
user.respond_to?(:another_thing).should be
|
172
|
+
end
|
173
|
+
|
174
|
+
it "should return Symbols as Strings, so that saving to the database and reading from it doesn't produce a different result (since Symbols are stored in JSON as Strings)" do
|
175
|
+
user = ::User.new
|
176
|
+
user.name = 'User 1'
|
177
|
+
user.wants_email = :bonko
|
178
|
+
user.wants_email.should == 'bonko'
|
179
|
+
user.save!
|
180
|
+
|
181
|
+
user_again = ::User.find(user.id)
|
182
|
+
user_again.wants_email.should == 'bonko'
|
183
|
+
end
|
184
|
+
|
185
|
+
it "should allow storing an Array happily" do
|
186
|
+
user = ::User.new
|
187
|
+
user.name = 'User 1'
|
188
|
+
user.wants_email = [ 123, "foo", 47.2, { 'foo' => 'bar' } ]
|
189
|
+
user.save!
|
190
|
+
|
191
|
+
user_again = ::User.find(user.id)
|
192
|
+
user_again.wants_email.should == [ 123, 'foo', 47.2, { 'foo' => 'bar' } ]
|
193
|
+
end
|
194
|
+
|
195
|
+
it "should allow storing a Hash happily" do
|
196
|
+
user = ::User.new
|
197
|
+
user.name = 'User 1'
|
198
|
+
user.wants_email = { 'foo' => 47.2, '13' => 'bar', 'baz' => [ 'a', 'b', 'c' ] }
|
199
|
+
user.save!
|
200
|
+
|
201
|
+
user_again = ::User.find(user.id)
|
202
|
+
output = user_again.wants_email
|
203
|
+
output.class.should == Hash
|
204
|
+
output.keys.sort.should == [ '13', 'baz', 'foo' ].sort
|
205
|
+
output['13'].should == 'bar'
|
206
|
+
output['baz'].should == [ 'a', 'b', 'c' ]
|
207
|
+
output['foo'].should == 47.2
|
208
|
+
end
|
209
|
+
|
210
|
+
it "should remove keys entirely when they're set to nil, but not if they're set to false" do
|
211
|
+
define_model_class(:User, 'flexcols_spec_users') do
|
212
|
+
flex_column :user_attributes do
|
213
|
+
field :aaa
|
214
|
+
field :bbb
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
::User.reset_column_information
|
219
|
+
|
220
|
+
user = ::User.new
|
221
|
+
user.name = 'User 1'
|
222
|
+
user.aaa = 'aaa1'
|
223
|
+
user.bbb = 'bbb1'
|
224
|
+
user.save!
|
225
|
+
|
226
|
+
user_bd = ::UserBackdoor.find(user.id)
|
227
|
+
JSON.parse(user_bd.user_attributes).keys.sort.should == %w{aaa bbb}.sort
|
228
|
+
|
229
|
+
user.aaa = false
|
230
|
+
user.save!
|
231
|
+
|
232
|
+
user_bd = ::UserBackdoor.find(user.id)
|
233
|
+
parsed = JSON.parse(user_bd.user_attributes)
|
234
|
+
parsed.keys.sort.should == %w{aaa bbb}.sort
|
235
|
+
parsed['aaa'].should == false
|
236
|
+
|
237
|
+
user.aaa = nil
|
238
|
+
user.save!
|
239
|
+
|
240
|
+
user_bd = ::UserBackdoor.find(user.id)
|
241
|
+
parsed = JSON.parse(user_bd.user_attributes)
|
242
|
+
parsed.keys.sort.should == %w{bbb}.sort
|
243
|
+
end
|
244
|
+
end
|
245
|
+
end
|