mochigome 0.0.2

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 (39) hide show
  1. data/.autotest +14 -0
  2. data/Gemfile +16 -0
  3. data/Gemfile.lock +71 -0
  4. data/LICENSE +674 -0
  5. data/README.rdoc +11 -0
  6. data/Rakefile +74 -0
  7. data/TODO +6 -0
  8. data/lib/data_node.rb +106 -0
  9. data/lib/exceptions.rb +6 -0
  10. data/lib/mochigome.rb +7 -0
  11. data/lib/mochigome_ver.rb +3 -0
  12. data/lib/model_extensions.rb +211 -0
  13. data/lib/query.rb +199 -0
  14. data/test/app_root/app/controllers/application_controller.rb +2 -0
  15. data/test/app_root/app/controllers/owners_controller.rb +2 -0
  16. data/test/app_root/app/models/boring_datum.rb +3 -0
  17. data/test/app_root/app/models/category.rb +7 -0
  18. data/test/app_root/app/models/owner.rb +17 -0
  19. data/test/app_root/app/models/product.rb +21 -0
  20. data/test/app_root/app/models/sale.rb +9 -0
  21. data/test/app_root/app/models/store.rb +13 -0
  22. data/test/app_root/app/models/store_product.rb +11 -0
  23. data/test/app_root/config/boot.rb +130 -0
  24. data/test/app_root/config/database-pg.yml +8 -0
  25. data/test/app_root/config/database.yml +6 -0
  26. data/test/app_root/config/environment.rb +14 -0
  27. data/test/app_root/config/environments/test.rb +20 -0
  28. data/test/app_root/config/offroad.yml +6 -0
  29. data/test/app_root/config/preinitializer.rb +20 -0
  30. data/test/app_root/config/routes.rb +4 -0
  31. data/test/app_root/db/migrate/20110817163830_create_tables.rb +66 -0
  32. data/test/app_root/vendor/plugins/mochigome/init.rb +2 -0
  33. data/test/factories.rb +39 -0
  34. data/test/test.watchr +6 -0
  35. data/test/test_helper.rb +66 -0
  36. data/test/unit/data_node_test.rb +144 -0
  37. data/test/unit/model_extensions_test.rb +367 -0
  38. data/test/unit/query_test.rb +202 -0
  39. metadata +143 -0
@@ -0,0 +1,367 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
2
+
3
+ describe "an ActiveRecord model" do
4
+ before do
5
+ @model_class = Class.new(ActiveRecord::Base)
6
+ @model_class.class_eval do
7
+ set_table_name :fake
8
+ def name
9
+ "Moby"
10
+ end
11
+ def last_name
12
+ "Dick"
13
+ end
14
+ end
15
+ Whale = @model_class
16
+ end
17
+
18
+ after do
19
+ Object.send(:remove_const, :Whale)
20
+ end
21
+
22
+ it "indicates if it acts_as_mochigome_focus or not" do
23
+ refute @model_class.acts_as_mochigome_focus?
24
+ @model_class.class_eval do
25
+ acts_as_mochigome_focus
26
+ end
27
+ assert @model_class.acts_as_mochigome_focus?
28
+ end
29
+
30
+ it "cannot call acts_as_mochigome_focus more than once" do
31
+ @model_class.class_eval do
32
+ acts_as_mochigome_focus
33
+ end
34
+ assert_raises Mochigome::ModelSetupError do
35
+ @model_class.class_eval do
36
+ acts_as_mochigome_focus
37
+ end
38
+ end
39
+ end
40
+
41
+ it "inherits a parent's report focus settings" do
42
+ @model_class.class_eval do
43
+ acts_as_mochigome_focus do |f|
44
+ f.type_name "Foobar"
45
+ end
46
+ end
47
+ @sub_class = Class.new(@model_class)
48
+ i = @sub_class.new
49
+ assert_equal "Foobar", i.mochigome_focus.type_name
50
+ end
51
+
52
+ it "can override a parent's report focus settings" do
53
+ @model_class.class_eval do
54
+ acts_as_mochigome_focus do |f|
55
+ f.type_name "Foobar"
56
+ end
57
+ end
58
+ @sub_class = Class.new(@model_class)
59
+ @sub_class.class_eval do
60
+ acts_as_mochigome_focus do |f|
61
+ f.type_name "Narfbork"
62
+ end
63
+ end
64
+ i = @sub_class.new
65
+ assert_equal "Narfbork", i.mochigome_focus.type_name
66
+ end
67
+
68
+ it "uses its class name as the default type name" do
69
+ @model_class.class_eval do
70
+ acts_as_mochigome_focus
71
+ end
72
+ i = @model_class.new
73
+ assert_equal "Whale", i.mochigome_focus.type_name.split("::").last
74
+ end
75
+
76
+ it "can override the default type name" do
77
+ @model_class.class_eval do
78
+ acts_as_mochigome_focus do |f|
79
+ f.type_name "Thingie"
80
+ end
81
+ end
82
+ i = @model_class.new
83
+ assert_equal "Thingie", i.mochigome_focus.type_name
84
+ end
85
+
86
+ it "cannot specify a nonsense type name" do
87
+ assert_raises Mochigome::ModelSetupError do
88
+ @model_class.class_eval do
89
+ acts_as_mochigome_focus do |f|
90
+ f.type_name 12345
91
+ end
92
+ end
93
+ end
94
+ end
95
+
96
+ it "uses the attribute 'name' as the default focus name" do
97
+ @model_class.class_eval do
98
+ acts_as_mochigome_focus
99
+ end
100
+ i = @model_class.new
101
+ assert_equal "Moby", i.mochigome_focus.name
102
+ end
103
+
104
+ it "can override the focus name with another method_name" do
105
+ @model_class.class_eval do
106
+ acts_as_mochigome_focus do |f|
107
+ f.name :last_name
108
+ end
109
+ end
110
+ i = @model_class.new
111
+ assert_equal "Dick", i.mochigome_focus.name
112
+ end
113
+
114
+ it "can override the focus name with a custom implementation" do
115
+ @model_class.class_eval do
116
+ acts_as_mochigome_focus do |f|
117
+ f.name lambda {|obj| "#{obj.name} #{obj.last_name}"}
118
+ end
119
+ end
120
+ i = @model_class.new
121
+ assert_equal "Moby Dick", i.mochigome_focus.name
122
+ end
123
+
124
+ it "can specify fields" do
125
+ @model_class.class_eval do
126
+ acts_as_mochigome_focus do |f|
127
+ f.fields ["a", "b"]
128
+ end
129
+ end
130
+ i = @model_class.new(:a => "abc", :b => "xyz")
131
+ expected = ActiveSupport::OrderedHash.new
132
+ expected["a"] = "abc"
133
+ expected["b"] = "xyz"
134
+ assert_equal expected, i.mochigome_focus.field_data
135
+ end
136
+
137
+ it "has no report focus data if no fields are specified" do
138
+ @model_class.class_eval do
139
+ acts_as_mochigome_focus
140
+ end
141
+ i = @model_class.new(:a => "abc", :b => "xyz")
142
+ assert_empty i.mochigome_focus.field_data
143
+ end
144
+
145
+ it "can specify only some of its fields" do
146
+ @model_class.class_eval do
147
+ acts_as_mochigome_focus do |f|
148
+ f.fields ["b"]
149
+ end
150
+ end
151
+ i = @model_class.new(:a => "abc", :b => "xyz")
152
+ expected = ActiveSupport::OrderedHash.new
153
+ expected["b"] = "xyz"
154
+ assert_equal expected, i.mochigome_focus.field_data
155
+ end
156
+
157
+ it "can specify fields in a custom order" do
158
+ @model_class.class_eval do
159
+ acts_as_mochigome_focus do |f|
160
+ f.fields ["b", "a"]
161
+ end
162
+ end
163
+ i = @model_class.new(:a => "abc", :b => "xyz")
164
+ expected = ActiveSupport::OrderedHash.new
165
+ expected["b"] = "xyz"
166
+ expected["a"] = "abc"
167
+ assert_equal expected, i.mochigome_focus.field_data
168
+ end
169
+
170
+ it "can specify fields with multiple calls" do
171
+ @model_class.class_eval do
172
+ acts_as_mochigome_focus do |f|
173
+ f.fields ["a"]
174
+ f.fields ["b"]
175
+ end
176
+ end
177
+ i = @model_class.new(:a => "abc", :b => "xyz")
178
+ expected = ActiveSupport::OrderedHash.new
179
+ expected["a"] = "abc"
180
+ expected["b"] = "xyz"
181
+ assert_equal expected, i.mochigome_focus.field_data
182
+ end
183
+
184
+ it "can specify fields with custom names" do
185
+ @model_class.class_eval do
186
+ acts_as_mochigome_focus do |f|
187
+ f.fields [{:Abraham => :a}, {:Barcelona => :b}]
188
+ end
189
+ end
190
+ i = @model_class.new(:a => "abc", :b => "xyz")
191
+ expected = ActiveSupport::OrderedHash.new
192
+ expected["Abraham"] = "abc"
193
+ expected["Barcelona"] = "xyz"
194
+ assert_equal expected, i.mochigome_focus.field_data
195
+ end
196
+
197
+ it "can specify fields with custom implementations" do
198
+ @model_class.class_eval do
199
+ acts_as_mochigome_focus do |f|
200
+ f.fields [{:concat => lambda {|obj| obj.a + obj.b}}]
201
+ end
202
+ end
203
+ i = @model_class.new(:a => "abc", :b => "xyz")
204
+ expected = ActiveSupport::OrderedHash.new
205
+ expected["concat"] = "abcxyz"
206
+ assert_equal expected, i.mochigome_focus.field_data
207
+ end
208
+
209
+ it "cannot call f.fields with nonsense" do
210
+ assert_raises Mochigome::ModelSetupError do
211
+ @model_class.class_eval do
212
+ acts_as_mochigome_focus do |f|
213
+ f.fields 123
214
+ end
215
+ end
216
+ end
217
+ assert_raises Mochigome::ModelSetupError do
218
+ @model_class.class_eval do
219
+ acts_as_mochigome_focus do |f|
220
+ f.fields [789]
221
+ end
222
+ end
223
+ end
224
+ end
225
+
226
+ [:name, :id, :type, :internal_type].each do |n|
227
+ it "cannot specify fields named the same as reserved term '#{n}'" do
228
+ assert_raises Mochigome::ModelSetupError do
229
+ @model_class.class_eval do
230
+ acts_as_mochigome_focus do |f|
231
+ f.fields [n]
232
+ end
233
+ end
234
+ end
235
+ assert_raises Mochigome::ModelSetupError do
236
+ @model_class.class_eval do
237
+ acts_as_mochigome_focus do |f|
238
+ f.fields [n.to_s.titleize]
239
+ end
240
+ end
241
+ end
242
+ assert_raises Mochigome::ModelSetupError do
243
+ @model_class.class_eval do
244
+ acts_as_mochigome_focus do |f|
245
+ f.fields [{n => :foo}]
246
+ end
247
+ end
248
+ end
249
+ end
250
+ end
251
+
252
+ it "appears in Mochigome's global model list if it acts_as_mochigome_focus" do
253
+ assert !Mochigome.reportFocusModels.include?(@model_class)
254
+ @model_class.class_eval do
255
+ acts_as_mochigome_focus
256
+ end
257
+ assert Mochigome.reportFocusModels.include?(@model_class)
258
+ end
259
+
260
+ it "can specify aggregated data to be collected" do
261
+ @model_class.class_eval do
262
+ has_mochigome_aggregations [:average_x, :Count, "sum x"]
263
+ end
264
+ # Peeking in past API to make sure it set the expressions correctly
265
+ assert_equal [
266
+ {:name => "Whales average x", :expr => "avg(x)"},
267
+ {:name => "Whales Count", :expr => "count()"},
268
+ {:name => "Whales sum x", :expr => "sum(x)"}
269
+ ], @model_class.mochigome_aggregations
270
+ end
271
+
272
+ it "can specify aggregations with custom names" do
273
+ @model_class.class_eval do
274
+ has_mochigome_aggregations [{"Mean X" => "avg x"}]
275
+ end
276
+ assert_equal [
277
+ {:name => "Mean X", :expr => "avg(x)"}
278
+ ], @model_class.mochigome_aggregations
279
+ end
280
+
281
+ it "can specify aggregations with custom SQL expressions" do
282
+ @model_class.class_eval do
283
+ has_mochigome_aggregations [{"The Answer" => "7*6"}]
284
+ end
285
+ assert_equal [
286
+ {:name => "The Answer", :expr => "7*6"}
287
+ ], @model_class.mochigome_aggregations
288
+ end
289
+
290
+ it "can specify aggregations with custom conditions" do
291
+ @model_class.class_eval do
292
+ has_mochigome_aggregations [{"Blue Sales" => ["count", "color='blue'"]}]
293
+ end
294
+ assert_equal [
295
+ {:name => "Blue Sales", :expr => "count()", :conditions => "color='blue'"}
296
+ ], @model_class.mochigome_aggregations
297
+ end
298
+
299
+ it "cannot call has_mochigome_aggregations with nonsense" do
300
+ assert_raises Mochigome::ModelSetupError do
301
+ @model_class.class_eval do
302
+ has_mochigome_aggregations 3
303
+ end
304
+ end
305
+ assert_raises Mochigome::ModelSetupError do
306
+ @model_class.class_eval do
307
+ has_mochigome_aggregations [42]
308
+ end
309
+ end
310
+ end
311
+
312
+ describe "with some aggregatable data" do
313
+ before do
314
+ @store1 = create(:store)
315
+ @store2 = create(:store)
316
+ @product_a = create(:product, :name => "Product A", :price => 30)
317
+ @product_b = create(:product, :name => "Product B", :price => 50)
318
+ @sp1A = create(:store_product, :store => @store1, :product => @product_a)
319
+ @sp1B = create(:store_product, :store => @store1, :product => @product_b)
320
+ @sp2A = create(:store_product, :store => @store2, :product => @product_a)
321
+ @sp2B = create(:store_product, :store => @store2, :product => @product_b)
322
+ [
323
+ [2, @sp1A],
324
+ [4, @sp1B],
325
+ [7, @sp2A],
326
+ [3, @sp2B]
327
+ ].each do |num, sp|
328
+ num.times { create(:sale, :store_product => sp) }
329
+ end
330
+ end
331
+
332
+ it "can collect aggregate data from a report focus through an association" do
333
+ assert_equal 9, @product_a.mochigome_focus.aggregate_data('sales')['Sales count']
334
+ assert_equal 7, @product_b.mochigome_focus.aggregate_data('sales')['Sales count']
335
+ end
336
+
337
+ it "can collect aggregate data through all known associations with :all keyword" do
338
+ assert_equal 9, @product_a.mochigome_focus.aggregate_data(:all)['Sales count']
339
+ end
340
+
341
+ it "returns both field data and all aggregate data with the data method" do
342
+ data = @product_a.mochigome_focus.data
343
+ assert_equal 9, data['Sales count']
344
+ assert_equal 30, data['price']
345
+ end
346
+
347
+ it "can return data aggregated in the context of another class with similar assoc" do
348
+ focus = @product_a.mochigome_focus
349
+ assert_equal 2, focus.aggregate_data('sales', :context => [@sp1A])['Sales count']
350
+ end
351
+
352
+ it "can return data aggregated in the context through the data method" do
353
+ focus = @product_a.mochigome_focus
354
+ assert_equal 2, focus.data(:context => [@sp1A])['Sales count']
355
+ end
356
+
357
+ it "can return data aggregated using a custom sql expression" do
358
+ focus = @store1.mochigome_focus
359
+ assert_equal 9001, focus.data['Power level']
360
+ end
361
+
362
+ it "can return data aggregated using custom conditions" do
363
+ focus = @store1.mochigome_focus
364
+ assert_equal 1, focus.data['Expensive products']
365
+ end
366
+ end
367
+ end
@@ -0,0 +1,202 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
2
+
3
+ describe Mochigome::Query do
4
+ before do
5
+ @category1 = create(:category, :name => "Category 1")
6
+ @product_a = create(:product, :name => "Product A", :category => @category1)
7
+ @product_b = create(:product, :name => "Product B", :category => @category1)
8
+
9
+ # Belongs to a category, but fails Category's has_many(:products) conditions
10
+ @product_x = create(:product, :name => "Product X", :category => @category1, :categorized => false)
11
+
12
+ @category2 = create(:category, :name => "Category 2")
13
+ @product_c = create(:product, :name => "Product C", :category => @category2)
14
+ @product_d = create(:product, :name => "Product D", :category => @category2)
15
+
16
+ @product_e = create(:product, :name => "Product E") # No category
17
+
18
+ @john = create(:owner, :first_name => "John", :last_name => "Smith")
19
+ @store_x = create(:store, :name => "John's Store", :owner => @john)
20
+
21
+ @jane = create(:owner, :first_name => "Jane", :last_name => "Doe")
22
+ @store_y = create(:store, :name => "Jane's Store (North)", :owner => @jane)
23
+ @store_z = create(:store, :name => "Jane's Store (South)", :owner => @jane)
24
+
25
+ @sp_xa = create(:store_product, :store => @store_x, :product => @product_a)
26
+ @sp_xc = create(:store_product, :store => @store_x, :product => @product_c)
27
+ @sp_ya = create(:store_product, :store => @store_y, :product => @product_a)
28
+ @sp_yb = create(:store_product, :store => @store_y, :product => @product_b)
29
+ @sp_ye = create(:store_product, :store => @store_y, :product => @product_e)
30
+ @sp_zc = create(:store_product, :store => @store_z, :product => @product_c)
31
+ @sp_zd = create(:store_product, :store => @store_z, :product => @product_d)
32
+
33
+ [
34
+ [@sp_xa, 5],
35
+ [@sp_xc, 3],
36
+ [@sp_ya, 4],
37
+ [@sp_yb, 6],
38
+ [@sp_ye, 1],
39
+ [@sp_zc, 2],
40
+ [@sp_zd, 3]
41
+ ].each do |sp, n|
42
+ n.times{create(:sale, :store_product => sp)}
43
+ end
44
+ end
45
+
46
+ # Convenience function to check DataSet output validity
47
+ def assert_equal_objs(a, b)
48
+ assert_equal a.size, b.size
49
+ # Not checking aggregate data because we don't know about a's context here
50
+ a.zip(b).each do |obj, fields|
51
+ obj.mochigome_focus.field_data.each do |k,v|
52
+ assert_equal v, fields[k]
53
+ end
54
+ end
55
+ end
56
+
57
+ it "returns an empty DataNode if no objects given" do
58
+ q = Mochigome::Query.new([Category, Product])
59
+ data_node = q.run([])
60
+ assert_empty data_node
61
+ assert_empty data_node.children
62
+ end
63
+
64
+ it "can build a one-layer DataNode" do
65
+ q = Mochigome::Query.new([Product])
66
+ data_node = q.run(@product_a)
67
+ assert_equal_objs [@product_a], data_node.children
68
+ assert_empty data_node.children[0].children
69
+ end
70
+
71
+ it "uses the model focus's type name for the DataNode's type name" do
72
+ q = Mochigome::Query.new([Store])
73
+ data_node = q.run(@store_x)
74
+ assert_equal "Storefront", data_node.children[0].type_name.to_s
75
+ end
76
+
77
+ it "adds an internal_type attribute containing the model class's name" do
78
+ q = Mochigome::Query.new([Store])
79
+ data_node = q.run(@store_x)
80
+ assert_equal "Store", data_node.children[0][:internal_type]
81
+ end
82
+
83
+ it "can build a two-layer tree from a record with a belongs_to association" do
84
+ q = Mochigome::Query.new([Category, Product])
85
+ data_node = q.run(@product_a)
86
+ assert_equal_objs [@category1], data_node.children
87
+ assert_equal_objs [@product_a], data_node.children[0].children
88
+ assert_empty data_node.children[0].children[0].children
89
+ end
90
+
91
+ it "can build a two-layer tree from an array of records in the second layer" do
92
+ q = Mochigome::Query.new([Category, Product])
93
+ data_node = q.run([@product_a, @product_d, @product_b])
94
+ assert_equal_objs [@category1, @category2], data_node.children
95
+ assert_equal_objs [@product_a, @product_b], data_node.children[0].children
96
+ assert_equal_objs [@product_d], data_node.children[1].children
97
+ end
98
+
99
+ it "can build a two-layer tree from a record with a has_many association" do
100
+ q = Mochigome::Query.new([Category, Product])
101
+ data_node = q.run(@category1)
102
+ assert_equal_objs [@category1], data_node.children
103
+ assert_equal_objs [@product_a, @product_b], data_node.children[0].children
104
+ assert_empty data_node.children[0].children[0].children
105
+ end
106
+
107
+ it "cannot build a DataNode tree when given disconnected layers" do
108
+ q = Mochigome::Query.new([Category, BoringDatum])
109
+ assert_raises Mochigome::QueryError do
110
+ data_node = q.run(@category1)
111
+ end
112
+ end
113
+
114
+ it "can build a three-layer tree from any layer" do
115
+ q = Mochigome::Query.new([Owner, Store, Product])
116
+ [
117
+ [@john, @jane],
118
+ [@store_x, @store_y, @store_z],
119
+ [@product_a, @product_b, @product_c, @product_d, @product_e]
120
+ ].each do |tgt|
121
+ data_node = q.run(tgt)
122
+ assert_equal_objs [@john, @jane], data_node.children
123
+ assert_equal_objs [@store_x], data_node.children[0].children
124
+ assert_equal_objs [@store_y, @store_z], data_node.children[1].children
125
+ assert_equal_objs [@product_a, @product_c],
126
+ data_node.children[0].children[0].children
127
+ assert_equal_objs [@product_c, @product_d],
128
+ data_node.children[1].children[1].children
129
+ end
130
+ end
131
+
132
+ it "collects aggregate data in the context of all layers when traversing down" do
133
+ q = Mochigome::Query.new([Owner, Store, Product])
134
+ data_node = q.run([@john, @jane])
135
+ # Store X, Product C
136
+ assert_equal "Product C", data_node.children[0].children[0].children[1].name
137
+ assert_equal 3, data_node.children[0].children[0].children[1]['Sales count']
138
+ # Store Z, Product C
139
+ assert_equal "Product C", data_node.children[1].children[1].children[0].name
140
+ assert_equal 2, data_node.children[1].children[1].children[0]['Sales count']
141
+ end
142
+
143
+ it "collects aggregate data in the context of all layers when traversing up" do
144
+ q = Mochigome::Query.new([Owner, Store, Product])
145
+ data_node = q.run(@product_c)
146
+ # Store X, Product C
147
+ assert_equal "Product C", data_node.children[0].children[0].children[0].name
148
+ assert_equal 3, data_node.children[0].children[0].children[0]['Sales count']
149
+ # Store Z, Product C
150
+ assert_equal "Product C", data_node.children[1].children[0].children[0].name
151
+ assert_equal 2, data_node.children[1].children[0].children[0]['Sales count']
152
+ end
153
+
154
+ it "collects aggregate data in the context of distant layers" do
155
+ # TODO: Implement me! I think this is necessary to justify focus_data_node_objs passing obj_stack
156
+ end
157
+
158
+ it "puts a comment on the root node describing the query" do
159
+ q = Mochigome::Query.new([Owner, Store, Product])
160
+ data_node = q.run([@store_x, @store_y, @store_z])
161
+ c = data_node.comment
162
+ assert_match c, /^Mochigome Version: #{Mochigome::VERSION}\n/
163
+ assert_match c, /\nTime: \w{3} \w{3} \d+ .+\n/
164
+ assert_match c, /\nLayers: Owner => Store => Product\n/
165
+ assert_match c, /\nAR Association Path:\n\* <- Owner.+\n\* == Store.+\n\* -> Product.+\n/
166
+ end
167
+
168
+ it "puts a descriptive comment on the first node of each layer" do
169
+ q = Mochigome::Query.new([Owner, Store, Product])
170
+ data_node = q.run([@store_x, @store_y, @store_z])
171
+
172
+ owner_comment = data_node.children[0].comment
173
+ assert owner_comment
174
+ assert_nil data_node.children[1].comment # No comment on second owner
175
+
176
+ store_comment = data_node.children[0].children[0].comment
177
+ assert store_comment
178
+ assert_nil data_node.children[1].children[0].comment # No comment on second store
179
+
180
+ product_comment = data_node.children[0].children[0].children[0].comment
181
+ assert product_comment
182
+ assert_nil data_node.children[0].children[0].children[1].comment # No comment on 2nd product
183
+
184
+ [owner_comment, store_comment, product_comment].each do |comment|
185
+ assert_match comment, /^Context:\nOwner:#{@john.id}.*\n/ # Owner is always in context
186
+ end
187
+ end
188
+
189
+ it "will not allow a query on targets of different types" do
190
+ q = Mochigome::Query.new([Owner, Store, Product])
191
+ assert_raises Mochigome::QueryError do
192
+ q.run([@store_x, @john])
193
+ end
194
+ end
195
+
196
+ it "will not allow a query on targets not in the layer list" do
197
+ q = Mochigome::Query.new([Product])
198
+ assert_raises Mochigome::QueryError do
199
+ q.run(@category1)
200
+ end
201
+ end
202
+ end
metadata ADDED
@@ -0,0 +1,143 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mochigome
3
+ version: !ruby/object:Gem::Version
4
+ hash: 27
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 2
10
+ version: 0.0.2
11
+ platform: ruby
12
+ authors:
13
+ - David Mike Simon
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-11-14 00:00:00 Z
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ requirement: &id001 !ruby/object:Gem::Requirement
22
+ none: false
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ hash: 3
27
+ segments:
28
+ - 0
29
+ version: "0"
30
+ version_requirements: *id001
31
+ name: ruport
32
+ prerelease: false
33
+ type: :runtime
34
+ - !ruby/object:Gem::Dependency
35
+ requirement: &id002 !ruby/object:Gem::Requirement
36
+ none: false
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ hash: 3
41
+ segments:
42
+ - 0
43
+ version: "0"
44
+ version_requirements: *id002
45
+ name: nokogiri
46
+ prerelease: false
47
+ type: :runtime
48
+ - !ruby/object:Gem::Dependency
49
+ requirement: &id003 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ hash: 3
55
+ segments:
56
+ - 0
57
+ version: "0"
58
+ version_requirements: *id003
59
+ name: rgl
60
+ prerelease: false
61
+ type: :runtime
62
+ description: Mochigome builds sophisticated report datasets from your ActiveRecord models
63
+ email: david.mike.simon@gmail.com
64
+ executables: []
65
+
66
+ extensions: []
67
+
68
+ extra_rdoc_files: []
69
+
70
+ files:
71
+ - .autotest
72
+ - Gemfile
73
+ - Gemfile.lock
74
+ - LICENSE
75
+ - README.rdoc
76
+ - Rakefile
77
+ - TODO
78
+ - lib/data_node.rb
79
+ - lib/exceptions.rb
80
+ - lib/mochigome.rb
81
+ - lib/mochigome_ver.rb
82
+ - lib/model_extensions.rb
83
+ - lib/query.rb
84
+ - test/app_root/app/controllers/application_controller.rb
85
+ - test/app_root/app/controllers/owners_controller.rb
86
+ - test/app_root/app/models/boring_datum.rb
87
+ - test/app_root/app/models/category.rb
88
+ - test/app_root/app/models/owner.rb
89
+ - test/app_root/app/models/product.rb
90
+ - test/app_root/app/models/sale.rb
91
+ - test/app_root/app/models/store.rb
92
+ - test/app_root/app/models/store_product.rb
93
+ - test/app_root/config/boot.rb
94
+ - test/app_root/config/database-pg.yml
95
+ - test/app_root/config/database.yml
96
+ - test/app_root/config/environment.rb
97
+ - test/app_root/config/environments/test.rb
98
+ - test/app_root/config/offroad.yml
99
+ - test/app_root/config/preinitializer.rb
100
+ - test/app_root/config/routes.rb
101
+ - test/app_root/db/migrate/20110817163830_create_tables.rb
102
+ - test/app_root/vendor/plugins/mochigome/init.rb
103
+ - test/factories.rb
104
+ - test/test.watchr
105
+ - test/test_helper.rb
106
+ - test/unit/data_node_test.rb
107
+ - test/unit/model_extensions_test.rb
108
+ - test/unit/query_test.rb
109
+ homepage: http://github.com/DavidMikeSimon/mochigome
110
+ licenses: []
111
+
112
+ post_install_message:
113
+ rdoc_options: []
114
+
115
+ require_paths:
116
+ - lib
117
+ required_ruby_version: !ruby/object:Gem::Requirement
118
+ none: false
119
+ requirements:
120
+ - - ">="
121
+ - !ruby/object:Gem::Version
122
+ hash: 3
123
+ segments:
124
+ - 0
125
+ version: "0"
126
+ required_rubygems_version: !ruby/object:Gem::Requirement
127
+ none: false
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ hash: 3
132
+ segments:
133
+ - 0
134
+ version: "0"
135
+ requirements: []
136
+
137
+ rubyforge_project: "[none]"
138
+ rubygems_version: 1.8.6
139
+ signing_key:
140
+ specification_version: 3
141
+ summary: User-customizable report generator
142
+ test_files: []
143
+