pixeltrix-thinking-sphinx 1.1.5 → 1.2.1

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.
Files changed (76) hide show
  1. data/README.textile +147 -0
  2. data/lib/thinking_sphinx/active_record/attribute_updates.rb +48 -0
  3. data/lib/thinking_sphinx/active_record/delta.rb +14 -1
  4. data/lib/thinking_sphinx/active_record/scopes.rb +37 -0
  5. data/lib/thinking_sphinx/active_record.rb +46 -12
  6. data/lib/thinking_sphinx/adapters/abstract_adapter.rb +9 -1
  7. data/lib/thinking_sphinx/adapters/mysql_adapter.rb +3 -2
  8. data/lib/thinking_sphinx/adapters/postgresql_adapter.rb +12 -5
  9. data/lib/thinking_sphinx/association.rb +20 -0
  10. data/lib/thinking_sphinx/attribute.rb +187 -116
  11. data/lib/thinking_sphinx/class_facet.rb +15 -0
  12. data/lib/thinking_sphinx/configuration.rb +46 -14
  13. data/lib/thinking_sphinx/core/string.rb +3 -10
  14. data/lib/thinking_sphinx/deltas/datetime_delta.rb +3 -3
  15. data/lib/thinking_sphinx/deltas/default_delta.rb +9 -6
  16. data/lib/thinking_sphinx/deltas/delayed_delta/delta_job.rb +1 -1
  17. data/lib/thinking_sphinx/deltas/delayed_delta.rb +4 -2
  18. data/lib/thinking_sphinx/deltas.rb +14 -6
  19. data/lib/thinking_sphinx/deploy/capistrano.rb +98 -0
  20. data/lib/thinking_sphinx/excerpter.rb +22 -0
  21. data/lib/thinking_sphinx/facet.rb +68 -18
  22. data/lib/thinking_sphinx/facet_search.rb +134 -0
  23. data/lib/thinking_sphinx/field.rb +7 -97
  24. data/lib/thinking_sphinx/index/builder.rb +255 -201
  25. data/lib/thinking_sphinx/index.rb +28 -343
  26. data/lib/thinking_sphinx/property.rb +160 -0
  27. data/lib/thinking_sphinx/rails_additions.rb +7 -4
  28. data/lib/thinking_sphinx/search.rb +593 -587
  29. data/lib/thinking_sphinx/search_methods.rb +421 -0
  30. data/lib/thinking_sphinx/source/internal_properties.rb +46 -0
  31. data/lib/thinking_sphinx/source/sql.rb +128 -0
  32. data/lib/thinking_sphinx/source.rb +150 -0
  33. data/lib/thinking_sphinx/tasks.rb +45 -11
  34. data/lib/thinking_sphinx.rb +88 -14
  35. data/rails/init.rb +14 -0
  36. data/spec/{unit → lib}/thinking_sphinx/active_record/delta_spec.rb +7 -7
  37. data/spec/{unit → lib}/thinking_sphinx/active_record/has_many_association_spec.rb +0 -0
  38. data/spec/lib/thinking_sphinx/active_record/scopes_spec.rb +92 -0
  39. data/spec/{unit → lib}/thinking_sphinx/active_record_spec.rb +115 -42
  40. data/spec/{unit → lib}/thinking_sphinx/association_spec.rb +4 -5
  41. data/spec/lib/thinking_sphinx/attribute_spec.rb +465 -0
  42. data/spec/{unit → lib}/thinking_sphinx/configuration_spec.rb +118 -7
  43. data/spec/{unit → lib}/thinking_sphinx/core/string_spec.rb +0 -0
  44. data/spec/lib/thinking_sphinx/excerpter_spec.rb +49 -0
  45. data/spec/lib/thinking_sphinx/facet_search_spec.rb +176 -0
  46. data/spec/lib/thinking_sphinx/facet_spec.rb +302 -0
  47. data/spec/{unit → lib}/thinking_sphinx/field_spec.rb +26 -17
  48. data/spec/lib/thinking_sphinx/index/builder_spec.rb +355 -0
  49. data/spec/{unit → lib}/thinking_sphinx/index/faux_column_spec.rb +0 -0
  50. data/spec/{unit → lib}/thinking_sphinx/index_spec.rb +3 -12
  51. data/spec/lib/thinking_sphinx/rails_additions_spec.rb +191 -0
  52. data/spec/lib/thinking_sphinx/search_methods_spec.rb +152 -0
  53. data/spec/lib/thinking_sphinx/search_spec.rb +887 -0
  54. data/spec/lib/thinking_sphinx/source_spec.rb +217 -0
  55. data/spec/{unit → lib}/thinking_sphinx_spec.rb +30 -8
  56. data/tasks/distribution.rb +20 -1
  57. data/tasks/testing.rb +7 -15
  58. data/vendor/after_commit/init.rb +3 -0
  59. data/vendor/after_commit/lib/after_commit/active_record.rb +27 -4
  60. data/vendor/after_commit/lib/after_commit/connection_adapters.rb +1 -1
  61. data/vendor/after_commit/lib/after_commit.rb +4 -1
  62. data/vendor/riddle/lib/riddle/client/message.rb +4 -3
  63. data/vendor/riddle/lib/riddle/client.rb +3 -0
  64. data/vendor/riddle/lib/riddle/configuration/section.rb +8 -2
  65. data/vendor/riddle/lib/riddle/controller.rb +1 -1
  66. data/vendor/riddle/lib/riddle.rb +1 -1
  67. metadata +75 -39
  68. data/README +0 -107
  69. data/lib/thinking_sphinx/active_record/search.rb +0 -57
  70. data/lib/thinking_sphinx/collection.rb +0 -142
  71. data/lib/thinking_sphinx/facet_collection.rb +0 -44
  72. data/spec/unit/thinking_sphinx/active_record/search_spec.rb +0 -107
  73. data/spec/unit/thinking_sphinx/attribute_spec.rb +0 -212
  74. data/spec/unit/thinking_sphinx/collection_spec.rb +0 -14
  75. data/spec/unit/thinking_sphinx/index/builder_spec.rb +0 -5
  76. data/spec/unit/thinking_sphinx/search_spec.rb +0 -59
@@ -0,0 +1,355 @@
1
+ require 'spec/spec_helper'
2
+
3
+ describe ThinkingSphinx::Index::Builder do
4
+ describe ".generate without source scope" do
5
+ before :each do
6
+ @index = ThinkingSphinx::Index::Builder.generate(Person) do
7
+ indexes first_name, last_name
8
+ has birthday
9
+ has id, :as => :internal_id
10
+
11
+ set_property :sql_range_step => 1000
12
+
13
+ where "birthday <= NOW()"
14
+ group_by "first_name"
15
+ end
16
+
17
+ @source = @index.sources.first
18
+ end
19
+
20
+ it "should return an index" do
21
+ @index.should be_a_kind_of(ThinkingSphinx::Index)
22
+ end
23
+
24
+ it "should have one source for the index" do
25
+ @index.sources.length.should == 1
26
+ end
27
+
28
+ it "should have two fields" do
29
+ @source.fields.length.should == 2
30
+ @source.fields[0].unique_name.should == :first_name
31
+ @source.fields[1].unique_name.should == :last_name
32
+ end
33
+
34
+ it "should have two attributes alongside the four internal ones" do
35
+ @source.attributes.length.should == 6
36
+ @source.attributes[4].unique_name.should == :birthday
37
+ @source.attributes[5].unique_name.should == :internal_id
38
+ end
39
+
40
+ it "should have one condition" do
41
+ @source.conditions.length.should == 1
42
+ @source.conditions.first.should == "birthday <= NOW()"
43
+ end
44
+
45
+ it "should have one grouping" do
46
+ @source.groupings.length.should == 1
47
+ @source.groupings.first.should == "first_name"
48
+ end
49
+
50
+ it "should have one option" do
51
+ @source.options.length.should == 1
52
+ @source.options[:sql_range_step].should == 1000
53
+ end
54
+ end
55
+
56
+ describe "sortable field" do
57
+ before :each do
58
+ @index = ThinkingSphinx::Index::Builder.generate(Person) do
59
+ indexes first_name, :sortable => true
60
+ end
61
+
62
+ @source = @index.sources.first
63
+ end
64
+
65
+ it "should have one field" do
66
+ @source.fields.length.should == 1
67
+ end
68
+
69
+ it "should have one attribute alongside the four internal ones" do
70
+ @source.attributes.length.should == 5
71
+ end
72
+
73
+ it "should set the attribute name to have the _sort suffix" do
74
+ @source.attributes.last.unique_name.should == :first_name_sort
75
+ end
76
+
77
+ it "should set the attribute column to be the same as the field" do
78
+ @source.attributes.last.columns.length.should == 1
79
+ @source.attributes.last.columns.first.__name.should == :first_name
80
+ end
81
+ end
82
+
83
+ describe "faceted field" do
84
+ before :each do
85
+ @index = ThinkingSphinx::Index::Builder.generate(Person) do
86
+ indexes first_name, :facet => true
87
+ end
88
+
89
+ @source = @index.sources.first
90
+ end
91
+
92
+ after :each do
93
+ Person.sphinx_facets.delete_at(-1)
94
+ end
95
+
96
+ it "should have one field" do
97
+ @source.fields.length.should == 1
98
+ end
99
+
100
+ it "should have one attribute alongside the four internal ones" do
101
+ @source.attributes.length.should == 5
102
+ end
103
+
104
+ it "should set the attribute name to have the _facet suffix" do
105
+ @source.attributes.last.unique_name.should == :first_name_facet
106
+ end
107
+
108
+ it "should set the attribute type to integer" do
109
+ @source.attributes.last.type.should == :integer
110
+ end
111
+
112
+ it "should set the attribute column to be the same as the field" do
113
+ @source.attributes.last.columns.length.should == 1
114
+ @source.attributes.last.columns.first.__name.should == :first_name
115
+ end
116
+ end
117
+
118
+ describe "faceted integer attribute" do
119
+ before :each do
120
+ @index = ThinkingSphinx::Index::Builder.generate(Alpha) do
121
+ indexes :name
122
+ has value, :facet => true
123
+ end
124
+
125
+ @source = @index.sources.first
126
+ end
127
+
128
+ after :each do
129
+ Alpha.sphinx_facets.delete_at(-1)
130
+ end
131
+
132
+ it "should have just one attribute alongside the four internal ones" do
133
+ @source.attributes.length.should == 5
134
+ end
135
+ end
136
+
137
+ describe "faceted timestamp attribute" do
138
+ before :each do
139
+ @index = ThinkingSphinx::Index::Builder.generate(Person) do
140
+ indexes first_name
141
+ has birthday, :facet => true
142
+ end
143
+
144
+ @source = @index.sources.first
145
+ end
146
+
147
+ after :each do
148
+ Person.sphinx_facets.delete_at(-1)
149
+ end
150
+
151
+ it "should have just one attribute alongside the four internal ones" do
152
+ @source.attributes.length.should == 5
153
+ end
154
+ end
155
+
156
+ describe "faceted boolean attribute" do
157
+ before :each do
158
+ @index = ThinkingSphinx::Index::Builder.generate(Beta) do
159
+ indexes :name
160
+ has delta, :facet => true
161
+ end
162
+
163
+ @source = @index.sources.first
164
+ end
165
+
166
+ after :each do
167
+ Beta.sphinx_facets.delete_at(-1)
168
+ end
169
+
170
+ it "should have just one attribute alongside the four internal ones" do
171
+ @source.attributes.length.should == 5
172
+ end
173
+ end
174
+
175
+ describe "faceted float attribute" do
176
+ before :each do
177
+ @index = ThinkingSphinx::Index::Builder.generate(Alpha) do
178
+ indexes :name
179
+ has cost, :facet => true
180
+ end
181
+
182
+ @source = @index.sources.first
183
+ end
184
+
185
+ after :each do
186
+ Alpha.sphinx_facets.delete_at(-1)
187
+ end
188
+
189
+ it "should have just one attribute alongside the four internal ones" do
190
+ @source.attributes.length.should == 5
191
+ end
192
+ end
193
+
194
+ describe "faceted string attribute" do
195
+ before :each do
196
+ @index = ThinkingSphinx::Index::Builder.generate(Person) do
197
+ indexes first_name
198
+ has last_name, :facet => true
199
+ end
200
+
201
+ @source = @index.sources.first
202
+ end
203
+
204
+ after :each do
205
+ Person.sphinx_facets.delete_at(-1)
206
+ end
207
+
208
+ it "should have two attributes alongside the four internal ones" do
209
+ @source.attributes.length.should == 6
210
+ end
211
+
212
+ it "should set the facet attribute name to have the _facet suffix" do
213
+ @source.attributes.last.unique_name.should == :last_name_facet
214
+ end
215
+
216
+ it "should set the attribute type to integer" do
217
+ @source.attributes.last.type.should == :integer
218
+ end
219
+
220
+ it "should set the attribute column to be the same as the field" do
221
+ @source.attributes.last.columns.length.should == 1
222
+ @source.attributes.last.columns.first.__name.should == :last_name
223
+ end
224
+ end
225
+
226
+ describe "no fields" do
227
+ it "should raise an exception" do
228
+ lambda {
229
+ ThinkingSphinx::Index::Builder.generate(Person) do
230
+ #
231
+ end
232
+ }.should raise_error
233
+ end
234
+ end
235
+
236
+ describe "explicit source" do
237
+ before :each do
238
+ @index = ThinkingSphinx::Index::Builder.generate(Person) do
239
+ define_source do
240
+ indexes first_name, last_name
241
+ has birthday
242
+ has id, :as => :internal_id
243
+
244
+ set_property :delta => true
245
+
246
+ where "birthday <= NOW()"
247
+ group_by "first_name"
248
+ end
249
+ end
250
+
251
+ @source = @index.sources.first
252
+ end
253
+
254
+ it "should return an index" do
255
+ @index.should be_a_kind_of(ThinkingSphinx::Index)
256
+ end
257
+
258
+ it "should have one source for the index" do
259
+ @index.sources.length.should == 1
260
+ end
261
+
262
+ it "should have two fields" do
263
+ @source.fields.length.should == 2
264
+ @source.fields[0].unique_name.should == :first_name
265
+ @source.fields[1].unique_name.should == :last_name
266
+ end
267
+
268
+ it "should have two attributes alongside the four internal ones" do
269
+ @source.attributes.length.should == 6
270
+ @source.attributes[4].unique_name.should == :birthday
271
+ @source.attributes[5].unique_name.should == :internal_id
272
+ end
273
+ end
274
+
275
+ describe "multiple sources" do
276
+ before :each do
277
+ @index = ThinkingSphinx::Index::Builder.generate(Person) do
278
+ define_source do
279
+ indexes first_name
280
+ has birthday
281
+ end
282
+
283
+ define_source do
284
+ indexes last_name
285
+ has :id, :as => :internal_id
286
+ end
287
+ end
288
+ end
289
+
290
+ it "should have two sources" do
291
+ @index.sources.length.should == 2
292
+ end
293
+
294
+ it "should have two fields" do
295
+ @index.fields.length.should == 2
296
+ end
297
+
298
+ it "should have one field in each source" do
299
+ @index.sources.each do |source|
300
+ source.fields.length.should == 1
301
+ end
302
+ end
303
+
304
+ it "should have two attributes alongside the eight internal ones" do
305
+ @index.attributes.length.should == 10
306
+ end
307
+
308
+ it "should have one attribute in each source alongside the four internal ones" do
309
+ @index.sources.each do |source|
310
+ source.attributes.length.should == 5
311
+ end
312
+ end
313
+ end
314
+
315
+ describe "index options" do
316
+ before :each do
317
+ @index = ThinkingSphinx::Index::Builder.generate(Person) do
318
+ indexes first_name
319
+
320
+ set_property :charset_type => "utf16"
321
+ set_property :group_concat_max_len => 1024
322
+ end
323
+ end
324
+
325
+ it "should store the index setting for the index" do
326
+ @index.local_options[:charset_type].should == "utf16"
327
+ end
328
+
329
+ it "should store non-Sphinx settings for the index" do
330
+ @index.local_options[:group_concat_max_len].should == 1024
331
+ end
332
+ end
333
+
334
+ describe "delta options" do
335
+ before :each do
336
+ @index = ThinkingSphinx::Index::Builder.generate(Person) do
337
+ indexes first_name
338
+
339
+ set_property :delta => true
340
+ end
341
+ end
342
+
343
+ it "should not keep the delta setting in source options" do
344
+ @index.sources.first.options.should be_empty
345
+ end
346
+
347
+ it "should not keep the delta setting in index options" do
348
+ @index.local_options.should be_empty
349
+ end
350
+
351
+ it "should set the index delta object set" do
352
+ @index.delta_object.should be_a_kind_of(ThinkingSphinx::Deltas::DefaultDelta)
353
+ end
354
+ end
355
+ end
@@ -1,15 +1,6 @@
1
1
  require 'spec/spec_helper'
2
2
 
3
3
  describe ThinkingSphinx::Index do
4
- describe "generated sql_query" do
5
- it "should include explicit groupings if requested" do
6
- @index = ThinkingSphinx::Index.new(Person)
7
-
8
- @index.groupings << "custom_sql"
9
- @index.to_riddle_for_core(0, 0).sql_query.should match(/GROUP BY.+custom_sql/)
10
- end
11
- end
12
-
13
4
  describe "prefix_fields method" do
14
5
  before :each do
15
6
  @index = ThinkingSphinx::Index.new(Person)
@@ -18,7 +9,7 @@ describe ThinkingSphinx::Index do
18
9
  @field_b = ThinkingSphinx::Field.stub_instance(:prefixes => false)
19
10
  @field_c = ThinkingSphinx::Field.stub_instance(:prefixes => true)
20
11
 
21
- @index.fields = [@field_a, @field_b, @field_c]
12
+ @index.stub_method(:fields => [@field_a, @field_b, @field_c])
22
13
  end
23
14
 
24
15
  it "should return fields that are flagged as prefixed" do
@@ -39,7 +30,7 @@ describe ThinkingSphinx::Index do
39
30
  @field_b = ThinkingSphinx::Field.stub_instance(:infixes => false)
40
31
  @field_c = ThinkingSphinx::Field.stub_instance(:infixes => true)
41
32
 
42
- @index.fields = [@field_a, @field_b, @field_c]
33
+ @index.stub_method(:fields => [@field_a, @field_b, @field_c])
43
34
  end
44
35
 
45
36
  it "should return fields that are flagged as infixed" do
@@ -51,4 +42,4 @@ describe ThinkingSphinx::Index do
51
42
  @index.infix_fields.should_not include(@field_b)
52
43
  end
53
44
  end
54
- end
45
+ end
@@ -0,0 +1,191 @@
1
+ require 'spec/spec_helper'
2
+
3
+ describe ThinkingSphinx::HashExcept do
4
+ before(:each) do
5
+ @hash = { :number => 20, :letter => 'b', :shape => 'rectangle' }
6
+ end
7
+
8
+ describe "except method" do
9
+ it "returns a hash without the specified keys" do
10
+ new_hash = @hash.except(:number)
11
+ new_hash.should_not have_key(:number)
12
+ end
13
+ end
14
+
15
+ describe "except! method" do
16
+ it "modifies hash removing specified keys" do
17
+ @hash.except!(:number)
18
+ @hash.should_not have_key(:number)
19
+ end
20
+ end
21
+
22
+ describe "extends Hash" do
23
+ before :each do
24
+ @instance_methods = Hash.instance_methods.collect { |m| m.to_s }
25
+ end
26
+
27
+ it 'with except' do
28
+ @instance_methods.include?('except').should be_true
29
+ end
30
+
31
+ it 'with except!' do
32
+ @instance_methods.include?('except!').should be_true
33
+ end
34
+ end
35
+ end
36
+
37
+ describe ThinkingSphinx::ArrayExtractOptions do
38
+ describe 'extract_options! method' do
39
+ it 'returns a hash' do
40
+ array = []
41
+ array.extract_options!.should be_kind_of(Hash)
42
+ end
43
+
44
+ it 'returns the last option if it is a hash' do
45
+ array = ['a', 'b', {:c => 'd'}]
46
+ array.extract_options!.should == {:c => 'd'}
47
+ end
48
+ end
49
+
50
+ describe "extends Array" do
51
+ it 'with extract_options!' do
52
+ Array.instance_methods.collect { |m| m.to_s }.include?('extract_options!').should be_true
53
+ end
54
+ end
55
+ end
56
+
57
+ describe ThinkingSphinx::AbstractQuotedTableName do
58
+ describe 'quote_table_name method' do
59
+ it 'calls quote_column_name' do
60
+ adapter = ActiveRecord::ConnectionAdapters::AbstractAdapter.new(defined?(JRUBY_VERSION) ? 'jdbcmysql' : 'mysql')
61
+ adapter.should_receive(:quote_column_name).with('messages')
62
+ adapter.quote_table_name('messages')
63
+ end
64
+ end
65
+
66
+ describe "extends ActiveRecord::ConnectionAdapters::AbstractAdapter" do
67
+ it 'with quote_table_name' do
68
+ ActiveRecord::ConnectionAdapters::AbstractAdapter.instance_methods.collect { |m|
69
+ m.to_s
70
+ }.include?('quote_table_name').should be_true
71
+ end
72
+ end
73
+ end
74
+
75
+ describe ThinkingSphinx::MysqlQuotedTableName do
76
+ describe "quote_table_name method" do
77
+ it 'correctly quotes' do
78
+ adapter = ActiveRecord::Base.connection
79
+ adapter.quote_table_name('thinking_sphinx.messages').should == "`thinking_sphinx`.`messages`"
80
+ end
81
+ end
82
+
83
+ describe "extends ActiveRecord::ConnectionAdapters::MysqlAdapter" do
84
+ it 'with quote_table_name' do
85
+ adapter = defined?(JRUBY_VERSION) ? :JdbcAdapter : :MysqlAdapter
86
+ ActiveRecord::ConnectionAdapters.const_get(adapter).instance_methods.collect { |m|
87
+ m.to_s
88
+ }.include?("quote_table_name").should be_true
89
+ end
90
+ end
91
+ end
92
+
93
+ describe ThinkingSphinx::ActiveRecordQuotedName do
94
+ describe "quoted_table_name method" do
95
+ it 'returns table name wrappd in quotes' do
96
+ Person.quoted_table_name.should == '`people`'
97
+ end
98
+ end
99
+
100
+ describe "extends ActiveRecord::Base" do
101
+ it 'with quoted_table_name' do
102
+ ActiveRecord::Base.respond_to?("quoted_table_name").should be_true
103
+ end
104
+ end
105
+ end
106
+
107
+ describe ThinkingSphinx::ActiveRecordStoreFullSTIClass do
108
+ describe "store_full_sti_class method" do
109
+ it 'returns false' do
110
+ Person.store_full_sti_class.should be_false
111
+ end
112
+ end
113
+
114
+ describe "extends ActiveRecord::Base" do
115
+ it 'with store_full_sti_class' do
116
+ ActiveRecord::Base.respond_to?(:store_full_sti_class).should be_true
117
+ end
118
+ end
119
+ end
120
+
121
+ class TestModel
122
+ @@squares = 89
123
+ @@circles = 43
124
+
125
+ def number_of_polygons
126
+ @@polygons
127
+ end
128
+ end
129
+
130
+ describe ThinkingSphinx::ClassAttributeMethods do
131
+ describe "cattr_reader method" do
132
+ it 'creates getters' do
133
+ TestModel.cattr_reader :herbivores
134
+ test_model = TestModel.new
135
+ test_model.respond_to?(:herbivores).should be_true
136
+ end
137
+
138
+ it 'sets the initial value to nil' do
139
+ TestModel.cattr_reader :carnivores
140
+ test_model = TestModel.new
141
+ test_model.carnivores.should be_nil
142
+ end
143
+
144
+ it 'does not override an existing definition' do
145
+ TestModel.cattr_reader :squares
146
+ test_model = TestModel.new
147
+ test_model.squares.should == 89
148
+ end
149
+ end
150
+
151
+ describe "cattr_writer method" do
152
+ it 'creates setters' do
153
+ TestModel.cattr_writer :herbivores
154
+ test_model = TestModel.new
155
+ test_model.respond_to?(:herbivores=).should be_true
156
+ end
157
+
158
+ it 'does not override an existing definition' do
159
+ TestModel.cattr_writer :polygons
160
+ test_model = TestModel.new
161
+ test_model.polygons = 100
162
+ test_model.number_of_polygons.should == 100
163
+ end
164
+ end
165
+
166
+ describe "cattr_accessor method" do
167
+ it 'calls cattr_reader' do
168
+ Class.should_receive(:cattr_reader).with('polygons')
169
+ Class.cattr_accessor('polygons')
170
+ end
171
+
172
+ it 'calls cattr_writer' do
173
+ Class.should_receive(:cattr_writer).with('polygons')
174
+ Class.cattr_accessor('polygons')
175
+ end
176
+ end
177
+
178
+ describe "extends Class" do
179
+ it 'with cattr_reader' do
180
+ Class.respond_to?('cattr_reader').should be_true
181
+ end
182
+
183
+ it 'with cattr_writer' do
184
+ Class.respond_to?('cattr_writer').should be_true
185
+ end
186
+
187
+ it 'with cattr_accessor' do
188
+ Class.respond_to?('cattr_accessor').should be_true
189
+ end
190
+ end
191
+ end