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,142 @@
|
|
1
|
+
require 'flex_columns'
|
2
|
+
require 'flex_columns/helpers/exception_helpers'
|
3
|
+
|
4
|
+
describe FlexColumns::Definition::FieldSet do
|
5
|
+
include FlexColumns::Helpers::ExceptionHelpers
|
6
|
+
|
7
|
+
def klass
|
8
|
+
FlexColumns::Definition::FieldSet
|
9
|
+
end
|
10
|
+
|
11
|
+
before :each do
|
12
|
+
@model_class = double("model_class")
|
13
|
+
allow(@model_class).to receive(:name).with().and_return("modname")
|
14
|
+
|
15
|
+
@flex_column_class = double("flex_column_class")
|
16
|
+
allow(@flex_column_class).to receive(:model_class).with().and_return(@model_class)
|
17
|
+
allow(@flex_column_class).to receive(:column_name).with().and_return("colname")
|
18
|
+
|
19
|
+
@instance = klass.new(@flex_column_class)
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should allow defining fields and returning them" do
|
23
|
+
@field_foo = double("field_foo")
|
24
|
+
allow(@field_foo).to receive(:json_storage_name).with().and_return(:foo_storage)
|
25
|
+
|
26
|
+
@field_bar = double("field_bar")
|
27
|
+
allow(@field_bar).to receive(:json_storage_name).with().and_return(:storage_bar)
|
28
|
+
|
29
|
+
expect(FlexColumns::Definition::FieldDefinition).to receive(:new).once.with(@flex_column_class, :foo, [ ], { }).and_return(@field_foo)
|
30
|
+
@instance.field(' fOo ')
|
31
|
+
|
32
|
+
expect(FlexColumns::Definition::FieldDefinition).to receive(:new).once.with(@flex_column_class, :bar, [ ], { }).and_return(@field_bar)
|
33
|
+
@instance.field(:bar)
|
34
|
+
|
35
|
+
@instance.all_field_names.sort_by(&:to_s).should == [ :foo, :bar ].sort_by(&:to_s)
|
36
|
+
|
37
|
+
@instance.field_named(:foo).should be(@field_foo)
|
38
|
+
@instance.field_named(' foO ').should be(@field_foo)
|
39
|
+
|
40
|
+
@instance.field_named(:bar).should be(@field_bar)
|
41
|
+
@instance.field_named('BAr ').should be(@field_bar)
|
42
|
+
|
43
|
+
@instance.field_with_json_storage_name(:foo).should_not be
|
44
|
+
@instance.field_with_json_storage_name(' fOo ').should_not be
|
45
|
+
@instance.field_with_json_storage_name(:foo_storage).should be(@field_foo)
|
46
|
+
|
47
|
+
@instance.field_with_json_storage_name(:bar_storage).should_not be
|
48
|
+
@instance.field_with_json_storage_name(:bar).should_not be
|
49
|
+
@instance.field_with_json_storage_name(:storage_bar).should be(@field_bar)
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should raise if there's a duplicate JSON storage name" do
|
53
|
+
@field_foo = double("field_foo")
|
54
|
+
allow(@field_foo).to receive(:json_storage_name).with().and_return(:foo_storage)
|
55
|
+
allow(@field_foo).to receive(:field_name).with().and_return(:foo)
|
56
|
+
|
57
|
+
@field_bar = double("field_bar")
|
58
|
+
allow(@field_bar).to receive(:json_storage_name).with().and_return(:foo_storage)
|
59
|
+
allow(@field_bar).to receive(:field_name).with().and_return(:bar)
|
60
|
+
|
61
|
+
expect(FlexColumns::Definition::FieldDefinition).to receive(:new).once.with(@flex_column_class, :foo, [ ], { }).and_return(@field_foo)
|
62
|
+
@instance.field(' fOo ')
|
63
|
+
|
64
|
+
expect(FlexColumns::Definition::FieldDefinition).to receive(:new).once.with(@flex_column_class, :bar, [ ], { }).and_return(@field_bar)
|
65
|
+
|
66
|
+
e = capture_exception(FlexColumns::Errors::ConflictingJsonStorageNameError) do
|
67
|
+
@instance.field(:bar)
|
68
|
+
end
|
69
|
+
|
70
|
+
e.model_class.should be(@model_class)
|
71
|
+
e.column_name.should == "colname"
|
72
|
+
e.new_field_name.should == :bar
|
73
|
+
e.existing_field_name.should == :foo
|
74
|
+
e.json_storage_name.should == :foo_storage
|
75
|
+
end
|
76
|
+
|
77
|
+
it "should allow redefining the same field, and the new field should win" do
|
78
|
+
@field_foo_1 = double("field_foo_1")
|
79
|
+
allow(@field_foo_1).to receive(:json_storage_name).with().and_return(:foo_storage)
|
80
|
+
allow(@field_foo_1).to receive(:field_name).with().and_return(:foo)
|
81
|
+
|
82
|
+
@field_foo_2 = double("field_foo_2")
|
83
|
+
allow(@field_foo_2).to receive(:json_storage_name).with().and_return(:foo_storage)
|
84
|
+
allow(@field_foo_2).to receive(:field_name).with().and_return(:foo)
|
85
|
+
|
86
|
+
expect(FlexColumns::Definition::FieldDefinition).to receive(:new).once.with(@flex_column_class, :foo, [ ], { }).and_return(@field_foo_1)
|
87
|
+
@instance.field(' fOo ')
|
88
|
+
|
89
|
+
expect(FlexColumns::Definition::FieldDefinition).to receive(:new).once.with(@flex_column_class, :foo, [ ], { :null => false }).and_return(@field_foo_2)
|
90
|
+
@instance.field(:foo, :null => false)
|
91
|
+
|
92
|
+
@instance.all_field_names.should == [ :foo ]
|
93
|
+
@instance.field_named(:foo).should be(@field_foo_2)
|
94
|
+
end
|
95
|
+
|
96
|
+
it "should call through to the fields on #add_delegated_methods!" do
|
97
|
+
@field_foo = double("field_foo")
|
98
|
+
allow(@field_foo).to receive(:json_storage_name).with().and_return(:foo)
|
99
|
+
|
100
|
+
@field_bar = double("field_bar")
|
101
|
+
allow(@field_bar).to receive(:json_storage_name).with().and_return(:bar)
|
102
|
+
|
103
|
+
expect(FlexColumns::Definition::FieldDefinition).to receive(:new).once.with(@flex_column_class, :foo, [ ], { }).and_return(@field_foo)
|
104
|
+
@instance.field(:foo)
|
105
|
+
|
106
|
+
expect(FlexColumns::Definition::FieldDefinition).to receive(:new).once.with(@flex_column_class, :bar, [ ], { }).and_return(@field_bar)
|
107
|
+
@instance.field(:bar)
|
108
|
+
|
109
|
+
flex_column_dmm = double("flex_column_dmm")
|
110
|
+
model_dmm = double("model_dmm")
|
111
|
+
|
112
|
+
expect(@field_foo).to receive(:add_methods_to_flex_column_class!).once.with(flex_column_dmm)
|
113
|
+
expect(@field_foo).to receive(:add_methods_to_model_class!).once.with(model_dmm, @model_class)
|
114
|
+
expect(@field_bar).to receive(:add_methods_to_flex_column_class!).once.with(flex_column_dmm)
|
115
|
+
expect(@field_bar).to receive(:add_methods_to_model_class!).once.with(model_dmm, @model_class)
|
116
|
+
|
117
|
+
@instance.add_delegated_methods!(flex_column_dmm, model_dmm, @model_class)
|
118
|
+
end
|
119
|
+
|
120
|
+
it "should call through to the fields on #include_fields_into!" do
|
121
|
+
@field_foo = double("field_foo")
|
122
|
+
allow(@field_foo).to receive(:json_storage_name).with().and_return(:foo)
|
123
|
+
|
124
|
+
@field_bar = double("field_bar")
|
125
|
+
allow(@field_bar).to receive(:json_storage_name).with().and_return(:bar)
|
126
|
+
|
127
|
+
expect(FlexColumns::Definition::FieldDefinition).to receive(:new).once.with(@flex_column_class, :foo, [ ], { }).and_return(@field_foo)
|
128
|
+
@instance.field(:foo)
|
129
|
+
|
130
|
+
expect(FlexColumns::Definition::FieldDefinition).to receive(:new).once.with(@flex_column_class, :bar, [ ], { }).and_return(@field_bar)
|
131
|
+
@instance.field(:bar)
|
132
|
+
|
133
|
+
dmm = double("dmm")
|
134
|
+
target_class = double("target_class")
|
135
|
+
options = double("options")
|
136
|
+
|
137
|
+
expect(@field_foo).to receive(:add_methods_to_included_class!).once.with(dmm, :assocname, target_class, options)
|
138
|
+
expect(@field_bar).to receive(:add_methods_to_included_class!).once.with(dmm, :assocname, target_class, options)
|
139
|
+
|
140
|
+
@instance.include_fields_into(dmm, :assocname, target_class, options)
|
141
|
+
end
|
142
|
+
end
|
@@ -0,0 +1,733 @@
|
|
1
|
+
require 'flex_columns'
|
2
|
+
require 'flex_columns/definition/flex_column_contents_class'
|
3
|
+
require 'flex_columns/helpers/exception_helpers'
|
4
|
+
|
5
|
+
describe FlexColumns::Definition::FlexColumnContentsClass do
|
6
|
+
include FlexColumns::Helpers::ExceptionHelpers
|
7
|
+
|
8
|
+
before :each do
|
9
|
+
@klass = Class.new
|
10
|
+
@klass.send(:extend, FlexColumns::Definition::FlexColumnContentsClass)
|
11
|
+
|
12
|
+
@model_class = double("model_class")
|
13
|
+
allow(@model_class).to receive(:kind_of?).with(Class).and_return(true)
|
14
|
+
allow(@model_class).to receive(:has_any_flex_columns?).with().and_return(true)
|
15
|
+
allow(@model_class).to receive(:name).with().and_return(:mcname)
|
16
|
+
|
17
|
+
@column_foo = double("column_foo")
|
18
|
+
allow(@column_foo).to receive(:name).with().and_return(:foo)
|
19
|
+
allow(@column_foo).to receive(:type).with().and_return(:text)
|
20
|
+
allow(@column_foo).to receive(:text?).with().and_return(true)
|
21
|
+
allow(@column_foo).to receive(:null).with().and_return(true)
|
22
|
+
allow(@column_foo).to receive(:sql_type).with().and_return('clob')
|
23
|
+
|
24
|
+
@column_bar = double("column_bar")
|
25
|
+
allow(@column_bar).to receive(:name).with().and_return(:bar)
|
26
|
+
allow(@column_bar).to receive(:type).with().and_return(:binary)
|
27
|
+
allow(@column_bar).to receive(:text?).with().and_return(false)
|
28
|
+
allow(@column_bar).to receive(:null).with().and_return(true)
|
29
|
+
allow(@column_bar).to receive(:sql_type).with().and_return('blob')
|
30
|
+
|
31
|
+
@column_baz = double("column_baz")
|
32
|
+
allow(@column_baz).to receive(:name).with().and_return(:baz)
|
33
|
+
allow(@column_baz).to receive(:type).with().and_return(:integer)
|
34
|
+
allow(@column_baz).to receive(:text?).with().and_return(false)
|
35
|
+
allow(@column_baz).to receive(:null).with().and_return(true)
|
36
|
+
allow(@column_baz).to receive(:sql_type).with().and_return('integer')
|
37
|
+
|
38
|
+
@column_quux = double("column_quux")
|
39
|
+
allow(@column_quux).to receive(:name).with().and_return(:quux)
|
40
|
+
allow(@column_quux).to receive(:type).with().and_return(:string)
|
41
|
+
allow(@column_quux).to receive(:text?).with().and_return(true)
|
42
|
+
allow(@column_quux).to receive(:null).with().and_return(true)
|
43
|
+
allow(@column_quux).to receive(:sql_type).with().and_return('varchar')
|
44
|
+
|
45
|
+
@column_ajson = double("column_ajson")
|
46
|
+
allow(@column_ajson).to receive(:name).with().and_return(:ajson)
|
47
|
+
allow(@column_ajson).to receive(:type).with().and_return(:json)
|
48
|
+
allow(@column_ajson).to receive(:text?).with().and_return(false)
|
49
|
+
allow(@column_ajson).to receive(:null).with().and_return(true)
|
50
|
+
allow(@column_ajson).to receive(:sql_type).with().and_return('json')
|
51
|
+
|
52
|
+
columns = [ @column_foo, @column_bar, @column_baz, @column_quux, @column_ajson ]
|
53
|
+
allow(@model_class).to receive(:columns).with().and_return(columns)
|
54
|
+
|
55
|
+
allow(@model_class).to receive(:const_defined?).and_return(false)
|
56
|
+
allow(@model_class).to receive(:const_set)
|
57
|
+
|
58
|
+
@field_set = double("field_set")
|
59
|
+
allow(FlexColumns::Definition::FieldSet).to receive(:new).and_return(@field_set)
|
60
|
+
end
|
61
|
+
|
62
|
+
describe "setup!" do
|
63
|
+
describe "pre-setup errors" do
|
64
|
+
def should_raise_if_not_set_up(&block)
|
65
|
+
block.should raise_error(/setup!/i)
|
66
|
+
end
|
67
|
+
|
68
|
+
it "should raise an error if any other method is called" do
|
69
|
+
should_raise_if_not_set_up { @klass._flex_columns_create_column_data(double("storage_string"), double("data_source")) }
|
70
|
+
should_raise_if_not_set_up { @klass.field(:foo) }
|
71
|
+
should_raise_if_not_set_up { @klass.field_named(:foo) }
|
72
|
+
should_raise_if_not_set_up { @klass.field_with_json_storage_name(:foo) }
|
73
|
+
should_raise_if_not_set_up { @klass.include_fields_into(double("dynamic_methods_module"),
|
74
|
+
double("association_name"), double("target_class"), { }) }
|
75
|
+
should_raise_if_not_set_up { @klass.object_for(double("model_instance")) }
|
76
|
+
should_raise_if_not_set_up { @klass.delegation_prefix }
|
77
|
+
should_raise_if_not_set_up { @klass.delegation_type }
|
78
|
+
should_raise_if_not_set_up { @klass.column_name }
|
79
|
+
should_raise_if_not_set_up { @klass.fields_are_private_by_default? }
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
it "should work with no options" do
|
84
|
+
@klass.setup!(@model_class, :foo) { }
|
85
|
+
end
|
86
|
+
|
87
|
+
it "should not allow itself to be called twice" do
|
88
|
+
@klass.setup!(@model_class, :foo) { }
|
89
|
+
|
90
|
+
lambda { @klass.setup!(@model_class, :foo) { } }.should raise_error(ArgumentError)
|
91
|
+
end
|
92
|
+
|
93
|
+
it "should require a model class that's a class" do
|
94
|
+
mc = double("model_class")
|
95
|
+
expect(mc).to receive(:kind_of?).with(Class).and_return(false)
|
96
|
+
lambda { @klass.setup!(mc, :foo) { } }.should raise_error(ArgumentError)
|
97
|
+
end
|
98
|
+
|
99
|
+
it "should require a model class that's an AR class" do
|
100
|
+
allow(@model_class).to receive(:has_any_flex_columns?).with().and_return(false)
|
101
|
+
lambda { @klass.setup!(@model_class, :foo) { } }.should raise_error(ArgumentError)
|
102
|
+
end
|
103
|
+
|
104
|
+
it "should require a column name that's a Symbol" do
|
105
|
+
lambda { @klass.setup!(@model_class, 'foo') { } }.should raise_error(ArgumentError)
|
106
|
+
end
|
107
|
+
|
108
|
+
it "should raise a nice error if passed something that isn't a column on the model" do
|
109
|
+
e = capture_exception(FlexColumns::Errors::NoSuchColumnError) { @klass.setup!(@model_class, :unknowncolumn) { } }
|
110
|
+
e.message.should match(/quux/i)
|
111
|
+
e.message.should match(/foo/i)
|
112
|
+
e.message.should match(/bar/i)
|
113
|
+
e.message.should match(/baz/i)
|
114
|
+
e.message.should match(/mcname/i)
|
115
|
+
end
|
116
|
+
|
117
|
+
it "should raise a nice error if passed a column of the wrong type" do
|
118
|
+
e = capture_exception(FlexColumns::Errors::InvalidColumnTypeError) { @klass.setup!(@model_class, :baz) { } }
|
119
|
+
e.message.should match(/mcname/i)
|
120
|
+
e.message.should match(/baz/i)
|
121
|
+
e.message.should match(/integer/i)
|
122
|
+
end
|
123
|
+
|
124
|
+
it "should work on a text column" do
|
125
|
+
@klass.setup!(@model_class, :foo) { }
|
126
|
+
end
|
127
|
+
|
128
|
+
it "should work on a binary column" do
|
129
|
+
@klass.setup!(@model_class, :bar) { }
|
130
|
+
end
|
131
|
+
|
132
|
+
it "should work on a JSON column" do
|
133
|
+
@klass.setup!(@model_class, :ajson) { }
|
134
|
+
end
|
135
|
+
|
136
|
+
it "should work on a string column" do
|
137
|
+
@klass.setup!(@model_class, :quux) { }
|
138
|
+
end
|
139
|
+
|
140
|
+
it "should create a new field set and name itself properly" do
|
141
|
+
expect(FlexColumns::Definition::FieldSet).to receive(:new).once.with(@klass).and_return(@field_set)
|
142
|
+
|
143
|
+
expect(@model_class).to receive(:const_defined?).with(:FooFlexContents).and_return(false)
|
144
|
+
expect(@model_class).to receive(:const_set).once.with(:FooFlexContents, @klass)
|
145
|
+
|
146
|
+
@klass.setup!(@model_class, :foo) { }
|
147
|
+
end
|
148
|
+
|
149
|
+
it "should run the block it's passed" do
|
150
|
+
expect(@klass).to receive(:foobar).once.with(:foo, :bar, :baz).and_return(:quux)
|
151
|
+
|
152
|
+
@klass.setup!(@model_class, :foo) do
|
153
|
+
foobar(:foo, :bar, :baz)
|
154
|
+
end.should == :quux
|
155
|
+
end
|
156
|
+
|
157
|
+
describe "options validation" do
|
158
|
+
def should_reject(options)
|
159
|
+
lambda { @klass.setup!(@model_class, :foo, options) { } }.should raise_error(ArgumentError)
|
160
|
+
end
|
161
|
+
|
162
|
+
it "should require a Hash" do
|
163
|
+
should_reject(123)
|
164
|
+
end
|
165
|
+
|
166
|
+
it "should reject unknown keys" do
|
167
|
+
should_reject(:foo => 123)
|
168
|
+
end
|
169
|
+
|
170
|
+
it "should require a valid option for :visibility" do
|
171
|
+
should_reject(:visibility => :foo)
|
172
|
+
should_reject(:visibility => true)
|
173
|
+
end
|
174
|
+
|
175
|
+
it "should require a valid option for :unknown_fields" do
|
176
|
+
should_reject(:unknown_fields => :foo)
|
177
|
+
should_reject(:unknown_fields => false)
|
178
|
+
end
|
179
|
+
|
180
|
+
it "should require a valid option for :compress" do
|
181
|
+
should_reject(:compress => :foo)
|
182
|
+
should_reject(:compress => "foo")
|
183
|
+
end
|
184
|
+
|
185
|
+
it "should require a valid option for :header" do
|
186
|
+
should_reject(:header => :foo)
|
187
|
+
should_reject(:header => "foo")
|
188
|
+
should_reject(:header => 123)
|
189
|
+
end
|
190
|
+
|
191
|
+
it "should require a valid option for :prefix" do
|
192
|
+
should_reject(:prefix => true)
|
193
|
+
should_reject(:prefix => 123)
|
194
|
+
end
|
195
|
+
|
196
|
+
it "should require a valid option for :delegate" do
|
197
|
+
should_reject(:delegate => :foo)
|
198
|
+
should_reject(:delegate => 123)
|
199
|
+
end
|
200
|
+
|
201
|
+
it "should reject incompatible :visibility and :delegate options" do
|
202
|
+
should_reject(:visibility => :private, :delegate => :public)
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
describe "_flex_columns_create_column_data" do
|
208
|
+
def expect_options_transform(class_options, length_limit, resulting_options, column_name = :foo, storage_string = double("storage_string"))
|
209
|
+
@klass.setup!(@model_class, column_name, class_options)
|
210
|
+
|
211
|
+
data_source = double("data_source")
|
212
|
+
|
213
|
+
allow(instance_variable_get("@column_#{column_name}")).to receive(:limit).with().and_return(length_limit)
|
214
|
+
|
215
|
+
resulting_options = { :storage_string => storage_string, :data_source => data_source }.merge(resulting_options)
|
216
|
+
|
217
|
+
expect(FlexColumns::Contents::ColumnData).to receive(:new).once.with(@field_set, resulting_options)
|
218
|
+
|
219
|
+
@klass._flex_columns_create_column_data(storage_string, data_source)
|
220
|
+
end
|
221
|
+
|
222
|
+
it "should create a new ColumnData object with correct default options" do
|
223
|
+
expect_options_transform({ }, nil, {
|
224
|
+
:unknown_fields => :preserve,
|
225
|
+
:length_limit => nil,
|
226
|
+
:storage => :text,
|
227
|
+
:binary_header => true,
|
228
|
+
:compress_if_over_length => 200,
|
229
|
+
:null => true
|
230
|
+
})
|
231
|
+
end
|
232
|
+
|
233
|
+
it "should allow a nil storage string" do
|
234
|
+
expect_options_transform({ }, nil, {
|
235
|
+
:unknown_fields => :preserve,
|
236
|
+
:length_limit => nil,
|
237
|
+
:storage => :text,
|
238
|
+
:binary_header => true,
|
239
|
+
:compress_if_over_length => 200,
|
240
|
+
:storage_string => nil,
|
241
|
+
:null => true
|
242
|
+
}, :foo, nil)
|
243
|
+
end
|
244
|
+
|
245
|
+
it "should pass through :unknown_fields correctly" do
|
246
|
+
expect_options_transform({ :unknown_fields => :delete }, nil, {
|
247
|
+
:unknown_fields => :delete,
|
248
|
+
:length_limit => nil,
|
249
|
+
:storage => :text,
|
250
|
+
:binary_header => true,
|
251
|
+
:compress_if_over_length => 200,
|
252
|
+
:null => true
|
253
|
+
})
|
254
|
+
end
|
255
|
+
|
256
|
+
it "should pass through the column limit correctly" do
|
257
|
+
expect_options_transform({ }, 123, {
|
258
|
+
:unknown_fields => :preserve,
|
259
|
+
:length_limit => 123,
|
260
|
+
:storage => :text,
|
261
|
+
:binary_header => true,
|
262
|
+
:compress_if_over_length => 200,
|
263
|
+
:null => true
|
264
|
+
})
|
265
|
+
end
|
266
|
+
|
267
|
+
it "should pass through the column type correctly for a binary column" do
|
268
|
+
expect_options_transform({ }, 123, {
|
269
|
+
:unknown_fields => :preserve,
|
270
|
+
:length_limit => 123,
|
271
|
+
:storage => :binary,
|
272
|
+
:binary_header => true,
|
273
|
+
:compress_if_over_length => 200,
|
274
|
+
:null => true
|
275
|
+
}, :bar)
|
276
|
+
end
|
277
|
+
|
278
|
+
it "should pass through the nullability setting correctly" do
|
279
|
+
allow(@column_foo).to receive(:null).with().and_return(false)
|
280
|
+
expect_options_transform({ }, 123, {
|
281
|
+
:unknown_fields => :preserve,
|
282
|
+
:length_limit => 123,
|
283
|
+
:storage => :text,
|
284
|
+
:binary_header => true,
|
285
|
+
:compress_if_over_length => 200,
|
286
|
+
:null => false
|
287
|
+
}, :foo)
|
288
|
+
end
|
289
|
+
|
290
|
+
it "should pass through the column type correctly for a JSON column" do
|
291
|
+
expect_options_transform({ }, 123, {
|
292
|
+
:unknown_fields => :preserve,
|
293
|
+
:length_limit => 123,
|
294
|
+
:storage => :json,
|
295
|
+
:binary_header => true,
|
296
|
+
:compress_if_over_length => 200,
|
297
|
+
:null => true
|
298
|
+
}, :ajson)
|
299
|
+
end
|
300
|
+
|
301
|
+
it "should pass through disabled compression correctly" do
|
302
|
+
expect_options_transform({ :compress => false }, nil, {
|
303
|
+
:unknown_fields => :preserve,
|
304
|
+
:length_limit => nil,
|
305
|
+
:storage => :text,
|
306
|
+
:binary_header => true,
|
307
|
+
:null => true
|
308
|
+
})
|
309
|
+
end
|
310
|
+
|
311
|
+
it "should pass through a compression setting correctly" do
|
312
|
+
expect_options_transform({ :compress => 234 }, nil, {
|
313
|
+
:unknown_fields => :preserve,
|
314
|
+
:length_limit => nil,
|
315
|
+
:storage => :text,
|
316
|
+
:binary_header => true,
|
317
|
+
:compress_if_over_length => 234,
|
318
|
+
:null => true
|
319
|
+
})
|
320
|
+
end
|
321
|
+
|
322
|
+
it "should pass through a no-binary-header setting correctly" do
|
323
|
+
expect_options_transform({ :header => false }, nil, {
|
324
|
+
:unknown_fields => :preserve,
|
325
|
+
:length_limit => nil,
|
326
|
+
:storage => :text,
|
327
|
+
:binary_header => false,
|
328
|
+
:compress_if_over_length => 200,
|
329
|
+
:null => true
|
330
|
+
})
|
331
|
+
end
|
332
|
+
end
|
333
|
+
|
334
|
+
describe "#delegation_prefix" do
|
335
|
+
it "should not return a prefix if there isn't one" do
|
336
|
+
@klass.setup!(@model_class, :foo) { }
|
337
|
+
@klass.delegation_prefix.should_not be
|
338
|
+
end
|
339
|
+
|
340
|
+
it "should return a prefix if there is one" do
|
341
|
+
@klass.setup!(@model_class, :foo, :prefix => :baz) { }
|
342
|
+
@klass.delegation_prefix.should == "baz"
|
343
|
+
end
|
344
|
+
end
|
345
|
+
|
346
|
+
describe "#delegation_type" do
|
347
|
+
it "should return :public by default" do
|
348
|
+
@klass.setup!(@model_class, :foo) { }
|
349
|
+
@klass.delegation_type.should == :public
|
350
|
+
end
|
351
|
+
|
352
|
+
it "should return nil if none by default" do
|
353
|
+
@klass.setup!(@model_class, :foo, :delegate => false) { }
|
354
|
+
@klass.delegation_type.should == nil
|
355
|
+
end
|
356
|
+
|
357
|
+
it "should return :public if explicitly public" do
|
358
|
+
@klass.setup!(@model_class, :foo, :delegate => true) { }
|
359
|
+
@klass.delegation_type.should == :public
|
360
|
+
end
|
361
|
+
|
362
|
+
it "should return :private if private" do
|
363
|
+
@klass.setup!(@model_class, :foo, :delegate => :private) { }
|
364
|
+
@klass.delegation_type.should == :private
|
365
|
+
end
|
366
|
+
end
|
367
|
+
|
368
|
+
describe "#fields_are_private_by_default?" do
|
369
|
+
it "should be false by default" do
|
370
|
+
@klass.setup!(@model_class, :foo) { }
|
371
|
+
@klass.fields_are_private_by_default?.should_not be
|
372
|
+
end
|
373
|
+
|
374
|
+
it "should be true if specified" do
|
375
|
+
@klass.setup!(@model_class, :foo, :visibility => :private) { }
|
376
|
+
@klass.fields_are_private_by_default?.should be
|
377
|
+
end
|
378
|
+
end
|
379
|
+
|
380
|
+
describe "#all_field_names" do
|
381
|
+
it "should delegate to the field set" do
|
382
|
+
@klass.setup!(@model_class, :foo) { }
|
383
|
+
expect(@field_set).to receive(:all_field_names).once.with().and_return([ :a, :x, :z, :q ])
|
384
|
+
@klass.all_field_names.should == [ :a, :x, :z, :q ]
|
385
|
+
end
|
386
|
+
end
|
387
|
+
|
388
|
+
describe "#sync_methods!" do
|
389
|
+
it "should create a dynamic-methods module and delegate to the field set" do
|
390
|
+
@klass.setup!(@model_class, :foo) { }
|
391
|
+
|
392
|
+
dmm = double("dmm")
|
393
|
+
expect(FlexColumns::Util::DynamicMethodsModule).to receive(:new).once.with(@klass, :FlexFieldsDynamicMethods).and_return(dmm)
|
394
|
+
expect(dmm).to receive(:remove_all_methods!).with().once
|
395
|
+
|
396
|
+
mc_dmm = double("mc_dmm")
|
397
|
+
allow(@model_class).to receive(:_flex_column_dynamic_methods_module).with().and_return(mc_dmm)
|
398
|
+
expect(@field_set).to receive(:add_delegated_methods!).once.with(dmm, mc_dmm, @model_class)
|
399
|
+
|
400
|
+
@klass.sync_methods!
|
401
|
+
end
|
402
|
+
|
403
|
+
it "should reuse the dynamic-methods module" do
|
404
|
+
@klass.setup!(@model_class, :foo) { }
|
405
|
+
|
406
|
+
dmm = double("dmm")
|
407
|
+
expect(FlexColumns::Util::DynamicMethodsModule).to receive(:new).once.with(@klass, :FlexFieldsDynamicMethods).and_return(dmm)
|
408
|
+
expect(dmm).to receive(:remove_all_methods!).with().once
|
409
|
+
|
410
|
+
mc_dmm = double("mc_dmm")
|
411
|
+
allow(@model_class).to receive(:_flex_column_dynamic_methods_module).with().and_return(mc_dmm)
|
412
|
+
expect(@field_set).to receive(:add_delegated_methods!).once.with(dmm, mc_dmm, @model_class)
|
413
|
+
|
414
|
+
@klass.sync_methods!
|
415
|
+
|
416
|
+
expect(dmm).to receive(:remove_all_methods!).with().once
|
417
|
+
expect(@field_set).to receive(:add_delegated_methods!).once.with(dmm, mc_dmm, @model_class)
|
418
|
+
|
419
|
+
@klass.sync_methods!
|
420
|
+
end
|
421
|
+
|
422
|
+
it "should add custom methods, with :visibility specified correctly" do
|
423
|
+
@klass.setup!(@model_class, :foo, :delegate => :private) do
|
424
|
+
def cm1(*args, &block)
|
425
|
+
"cm1!"
|
426
|
+
end
|
427
|
+
end
|
428
|
+
|
429
|
+
dmm = double("dmm")
|
430
|
+
expect(FlexColumns::Util::DynamicMethodsModule).to receive(:new).once.with(@klass, :FlexFieldsDynamicMethods).and_return(dmm)
|
431
|
+
expect(dmm).to receive(:remove_all_methods!).with().once
|
432
|
+
|
433
|
+
mc_dmm = Class.new
|
434
|
+
mc_dmm.class_eval do
|
435
|
+
class << self
|
436
|
+
public :define_method, :private
|
437
|
+
end
|
438
|
+
end
|
439
|
+
|
440
|
+
allow(@model_class).to receive(:_flex_column_dynamic_methods_module).with().and_return(mc_dmm)
|
441
|
+
expect(@field_set).to receive(:add_delegated_methods!).once.with(dmm, mc_dmm, @model_class)
|
442
|
+
|
443
|
+
allow(@model_class).to receive(:_flex_columns_safe_to_define_method?).with("cm1").and_return(true)
|
444
|
+
|
445
|
+
@klass.sync_methods!
|
446
|
+
|
447
|
+
fco = Object.new
|
448
|
+
class << fco
|
449
|
+
def cm1(*args, &block)
|
450
|
+
"cm1: #{args.join(", ")}: #{block.call(*args)}"
|
451
|
+
end
|
452
|
+
end
|
453
|
+
|
454
|
+
o = mc_dmm.new
|
455
|
+
expect(o).to receive(:_flex_column_object_for).with(:foo).and_return(fco)
|
456
|
+
|
457
|
+
lambda { o.cm1 }.should raise_error(NoMethodError)
|
458
|
+
result = o.send(:cm1, :foo, :bar) { |*args| args.join("X") }
|
459
|
+
result.should == "cm1: foo, bar: fooXbar"
|
460
|
+
end
|
461
|
+
end
|
462
|
+
|
463
|
+
it "should return the column name from #column_name" do
|
464
|
+
@klass.setup!(@model_class, :foo) { }
|
465
|
+
@klass.column_name.should == :foo
|
466
|
+
end
|
467
|
+
|
468
|
+
context "with a set-up class" do
|
469
|
+
before :each do
|
470
|
+
@klass.setup!(@model_class, :foo) { }
|
471
|
+
end
|
472
|
+
|
473
|
+
it "should pass through :field to the field set" do
|
474
|
+
expect(@field_set).to receive(:field).once.with(:foo, :bar, :baz => :quux)
|
475
|
+
@klass.field(:foo, :bar, :baz => :quux)
|
476
|
+
end
|
477
|
+
|
478
|
+
it "should pass through :field_named to the field set" do
|
479
|
+
expect(@field_set).to receive(:field_named).once.with(:quux).and_return(:bar)
|
480
|
+
@klass.field_named(:quux).should == :bar
|
481
|
+
end
|
482
|
+
|
483
|
+
it "should pass through :field_with_json_storage_name to the field set" do
|
484
|
+
expect(@field_set).to receive(:field_with_json_storage_name).once.with(:quux).and_return(:bar)
|
485
|
+
@klass.field_with_json_storage_name(:quux).should == :bar
|
486
|
+
end
|
487
|
+
|
488
|
+
it "should be a flex-column class" do
|
489
|
+
@klass.is_flex_column_class?.should be
|
490
|
+
end
|
491
|
+
|
492
|
+
describe "#requires_serialization_on_save?" do
|
493
|
+
it "should be true if there's an object and it has been touched" do
|
494
|
+
model = double("model")
|
495
|
+
fco = double("fco")
|
496
|
+
allow(model).to receive(:_flex_column_object_for).with(:foo, false).and_return(fco)
|
497
|
+
allow(fco).to receive(:touched?).with().and_return(true)
|
498
|
+
@klass.requires_serialization_on_save?(model).should be
|
499
|
+
end
|
500
|
+
|
501
|
+
it "should be false if there's an object but it hasn't been touched" do
|
502
|
+
model = double("model")
|
503
|
+
fco = double("fco")
|
504
|
+
allow(model).to receive(:_flex_column_object_for).with(:foo, false).and_return(fco)
|
505
|
+
allow(fco).to receive(:touched?).with().and_return(false)
|
506
|
+
@klass.requires_serialization_on_save?(model).should_not be
|
507
|
+
end
|
508
|
+
|
509
|
+
it "should be false if there's no object and the column is NULLable" do
|
510
|
+
model = double("model")
|
511
|
+
fco = double("fco")
|
512
|
+
allow(model).to receive(:_flex_column_object_for).with(:foo, false).and_return(nil)
|
513
|
+
allow(@column_foo).to receive(:null).with().and_return(true)
|
514
|
+
@klass.requires_serialization_on_save?(model).should_not be
|
515
|
+
end
|
516
|
+
|
517
|
+
it "should be false if there's no object and the column is not null, but there's data" do
|
518
|
+
model = double("model")
|
519
|
+
fco = double("fco")
|
520
|
+
allow(model).to receive(:_flex_column_object_for).with(:foo, false).and_return(nil)
|
521
|
+
allow(@column_foo).to receive(:null).with().and_return(false)
|
522
|
+
allow(model).to receive(:[]).with(:foo).and_return("some data")
|
523
|
+
@klass.requires_serialization_on_save?(model).should_not be
|
524
|
+
end
|
525
|
+
|
526
|
+
it "should be true if there's no object and the column is not null, and there's no data" do
|
527
|
+
model = double("model")
|
528
|
+
fco = double("fco")
|
529
|
+
allow(model).to receive(:_flex_column_object_for).with(:foo, false).and_return(nil)
|
530
|
+
allow(@column_foo).to receive(:null).with().and_return(false)
|
531
|
+
allow(model).to receive(:[]).with(:foo).and_return(nil)
|
532
|
+
@klass.requires_serialization_on_save?(model).should be
|
533
|
+
end
|
534
|
+
end
|
535
|
+
|
536
|
+
describe "#include_fields_into" do
|
537
|
+
before :each do
|
538
|
+
@dmm = Class.new
|
539
|
+
@dmm.class_eval do
|
540
|
+
def bar_return=(x)
|
541
|
+
@bar_return = x
|
542
|
+
end
|
543
|
+
|
544
|
+
def bar
|
545
|
+
@bar_return
|
546
|
+
end
|
547
|
+
|
548
|
+
def build_bar_return=(x)
|
549
|
+
@build_bar_return = x
|
550
|
+
end
|
551
|
+
|
552
|
+
def build_bar
|
553
|
+
@build_bar_return
|
554
|
+
end
|
555
|
+
|
556
|
+
def set_flex_column_object_for!(x, y)
|
557
|
+
@_flex_column_objects_for ||= { }
|
558
|
+
@_flex_column_objects_for[x] = y
|
559
|
+
end
|
560
|
+
|
561
|
+
def _flex_column_object_for(x)
|
562
|
+
@_flex_column_objects_for[x]
|
563
|
+
end
|
564
|
+
|
565
|
+
class << self
|
566
|
+
public :define_method, :private
|
567
|
+
end
|
568
|
+
end
|
569
|
+
|
570
|
+
@target_class = double("target_class")
|
571
|
+
@associated_object = double("associated_object")
|
572
|
+
end
|
573
|
+
|
574
|
+
it "should define a method that's safe to define, and nothing else, if :delegate => false" do
|
575
|
+
expect(@target_class).to receive(:_flex_columns_safe_to_define_method?).with("foo").and_return(true)
|
576
|
+
|
577
|
+
@klass.include_fields_into(@dmm, :bar, @target_class, { :delegate => false })
|
578
|
+
|
579
|
+
expect(@associated_object).to receive(:foo).once.and_return(:quux)
|
580
|
+
instance = @dmm.new
|
581
|
+
instance.bar_return = @associated_object
|
582
|
+
|
583
|
+
instance.foo.should == :quux
|
584
|
+
end
|
585
|
+
|
586
|
+
it "should not define a method that's not safe to define" do
|
587
|
+
expect(@target_class).to receive(:_flex_columns_safe_to_define_method?).with("foo").and_return(false)
|
588
|
+
|
589
|
+
@klass.include_fields_into(@dmm, :bar, @target_class, { :delegate => false })
|
590
|
+
|
591
|
+
instance = @dmm.new
|
592
|
+
lambda { instance.send(:foo) }.should raise_error(NoMethodError)
|
593
|
+
end
|
594
|
+
|
595
|
+
it "should define a method that falls back to build_<x>" do
|
596
|
+
expect(@target_class).to receive(:_flex_columns_safe_to_define_method?).with("foo").and_return(true)
|
597
|
+
|
598
|
+
@klass.include_fields_into(@dmm, :bar, @target_class, { :delegate => false })
|
599
|
+
|
600
|
+
expect(@associated_object).to receive(:foo).once.and_return(:quux)
|
601
|
+
instance = @dmm.new
|
602
|
+
instance.build_bar_return = @associated_object
|
603
|
+
instance.foo.should == :quux
|
604
|
+
end
|
605
|
+
|
606
|
+
it "should define a method that's private, if requested" do
|
607
|
+
defined_block = nil
|
608
|
+
|
609
|
+
expect(@target_class).to receive(:_flex_columns_safe_to_define_method?).with("foo").and_return(true)
|
610
|
+
|
611
|
+
@klass.include_fields_into(@dmm, :bar, @target_class, { :delegate => false, :visibility => :private })
|
612
|
+
|
613
|
+
expect(@associated_object).to receive(:foo).once.and_return(:quux)
|
614
|
+
instance = @dmm.new
|
615
|
+
instance.bar_return = @associated_object
|
616
|
+
|
617
|
+
lambda { instance.foo }.should raise_error(NoMethodError)
|
618
|
+
instance.send(:foo).should == :quux
|
619
|
+
end
|
620
|
+
|
621
|
+
it "should prefix the method name, if requested" do
|
622
|
+
defined_block = nil
|
623
|
+
|
624
|
+
expect(@target_class).to receive(:_flex_columns_safe_to_define_method?).with("baz_foo").and_return(true)
|
625
|
+
|
626
|
+
@klass.include_fields_into(@dmm, :bar, @target_class, { :delegate => false, :prefix => "baz" })
|
627
|
+
|
628
|
+
expect(@associated_object).to receive(:foo).once.and_return(:quux)
|
629
|
+
instance = @dmm.new
|
630
|
+
instance.bar_return = @associated_object
|
631
|
+
|
632
|
+
instance.baz_foo.should == :quux
|
633
|
+
end
|
634
|
+
|
635
|
+
it "should add custom methods, and prefix them if needed" do
|
636
|
+
@klass = Class.new
|
637
|
+
@klass.send(:extend, FlexColumns::Definition::FlexColumnContentsClass)
|
638
|
+
@klass.setup!(@model_class, :foo) { def cm1(*args); "cm1!: #{args.join(", ")}: #{yield *args}"; end }
|
639
|
+
|
640
|
+
defined_block = nil
|
641
|
+
cm_defined_block = nil
|
642
|
+
|
643
|
+
expect(@target_class).to receive(:_flex_columns_safe_to_define_method?).with("baz_foo").and_return(true)
|
644
|
+
expect(@target_class).to receive(:_flex_columns_safe_to_define_method?).with("baz_cm1").and_return(true)
|
645
|
+
|
646
|
+
expect(@field_set).to receive(:include_fields_into).once.with(@dmm, :bar, @target_class, { :prefix => "baz" })
|
647
|
+
|
648
|
+
@klass.include_fields_into(@dmm, :bar, @target_class, { :prefix => "baz" })
|
649
|
+
|
650
|
+
expect(@associated_object).to receive(:foo).once.and_return(:quux)
|
651
|
+
instance = @dmm.new
|
652
|
+
instance.bar_return = @associated_object
|
653
|
+
|
654
|
+
instance.baz_foo.should == :quux
|
655
|
+
|
656
|
+
flex_object = Object.new
|
657
|
+
class << flex_object
|
658
|
+
def cm1(*args, &b)
|
659
|
+
"cm1 - #{args.join(", ")} - #{b.call(*args)}"
|
660
|
+
end
|
661
|
+
end
|
662
|
+
|
663
|
+
instance.set_flex_column_object_for!(:foo, flex_object)
|
664
|
+
result = instance.baz_cm1(:bar, :baz) { |*args| args.join("X") }
|
665
|
+
result.should == "cm1 - bar, baz - barXbaz"
|
666
|
+
end
|
667
|
+
|
668
|
+
it "should not add custom methods if they aren't safe" do
|
669
|
+
@klass = Class.new
|
670
|
+
@klass.send(:extend, FlexColumns::Definition::FlexColumnContentsClass)
|
671
|
+
@klass.setup!(@model_class, :foo) { def cm1(*args); "cm1!: #{args.join(", ")}: #{yield *args}"; end }
|
672
|
+
|
673
|
+
defined_block = nil
|
674
|
+
cm_defined_block = nil
|
675
|
+
|
676
|
+
expect(@target_class).to receive(:_flex_columns_safe_to_define_method?).with("foo").and_return(true)
|
677
|
+
expect(@target_class).to receive(:_flex_columns_safe_to_define_method?).with("cm1").and_return(false)
|
678
|
+
|
679
|
+
expect(@field_set).to receive(:include_fields_into).once.with(@dmm, :bar, @target_class, { })
|
680
|
+
|
681
|
+
@klass.include_fields_into(@dmm, :bar, @target_class, { })
|
682
|
+
|
683
|
+
expect(@associated_object).to receive(:foo).once.and_return(:quux)
|
684
|
+
instance = @dmm.new
|
685
|
+
instance.bar_return = @associated_object
|
686
|
+
|
687
|
+
instance.foo.should == :quux
|
688
|
+
|
689
|
+
lambda { instance.send(:cm1) }.should raise_error(NoMethodError)
|
690
|
+
end
|
691
|
+
|
692
|
+
it "should make custom methods private if requested" do
|
693
|
+
@klass = Class.new
|
694
|
+
@klass.send(:extend, FlexColumns::Definition::FlexColumnContentsClass)
|
695
|
+
@klass.setup!(@model_class, :foo) { def cm1(*args); "cm1!: #{args.join(", ")}: #{yield *args}"; end }
|
696
|
+
|
697
|
+
defined_block = nil
|
698
|
+
cm_defined_block = nil
|
699
|
+
|
700
|
+
expect(@target_class).to receive(:_flex_columns_safe_to_define_method?).with("baz_foo").and_return(true)
|
701
|
+
expect(@target_class).to receive(:_flex_columns_safe_to_define_method?).with("baz_cm1").and_return(true)
|
702
|
+
|
703
|
+
expect(@field_set).to receive(:include_fields_into).once.with(@dmm, :bar, @target_class, { :prefix => "baz" })
|
704
|
+
|
705
|
+
@klass.include_fields_into(@dmm, :bar, @target_class, { :prefix => "baz" })
|
706
|
+
|
707
|
+
expect(@associated_object).to receive(:foo).once.and_return(:quux)
|
708
|
+
instance = @dmm.new
|
709
|
+
instance.bar_return = @associated_object
|
710
|
+
|
711
|
+
instance.baz_foo.should == :quux
|
712
|
+
|
713
|
+
flex_object = Object.new
|
714
|
+
class << flex_object
|
715
|
+
def cm1(*args, &b)
|
716
|
+
"cm1 - #{args.join(", ")} - #{b.call(*args)}"
|
717
|
+
end
|
718
|
+
end
|
719
|
+
|
720
|
+
instance.set_flex_column_object_for!(:foo, flex_object)
|
721
|
+
lambda { instance.baz_cm1 }.should raise_error(NoMethodError)
|
722
|
+
result = instance.send(:baz_cm1, :bar, :baz) { |*args| args.join("X") }
|
723
|
+
result.should == "cm1 - bar, baz - barXbaz"
|
724
|
+
end
|
725
|
+
end
|
726
|
+
|
727
|
+
it "should delegate to the model instance on #object_for" do
|
728
|
+
model_instance = double("model_instance")
|
729
|
+
expect(model_instance).to receive(:_flex_column_object_for).once.with(:foo).and_return(:quux)
|
730
|
+
@klass.object_for(model_instance).should == :quux
|
731
|
+
end
|
732
|
+
end
|
733
|
+
end
|