flex_columns 1.0.0
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 +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
|