cubicle 0.1.4 → 0.1.5

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.
data/CHANGELOG.rdoc CHANGED
@@ -1,3 +1,10 @@
1
+ ==0.1.5
2
+ * Added duration_since (aliased as elapsed, age_since) to calculate the time elapsed since any
3
+ given timestamp and the current execution time of the query.
4
+
5
+ == 0.1.4
6
+ * Cached aggregations were being stored on disk, but not properly utilized. This is now fixed.
7
+
1
8
  == 0.1.3
2
9
  * Formalized flat (Cubicle::Data::Table) and hierarchical (Cubicle::Data::Hierarchy) data results from cubicle queries,
3
10
  and added client side support for rolling up measure values in hierarchical data so that no matter how a given
data/cubicle.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{cubicle}
8
- s.version = "0.1.4"
8
+ s.version = "0.1.5"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Nathan Stults"]
12
- s.date = %q{2010-03-25}
12
+ s.date = %q{2010-03-29}
13
13
  s.description = %q{Cubicle provides a dsl and aggregation caching framework for automating the generation, execution and caching of map reduce queries when using MongoDB in Ruby. Cubicle also includes a MongoMapper plugin for quickly performing ad-hoc, multi-level group-by queries against a MongoMapper model.}
14
14
  s.email = %q{hereiam@sonic.net}
15
15
  s.extra_rdoc_files = [
@@ -1,108 +1,117 @@
1
- module Cubicle
2
- module Aggregation
3
- module Dsl
4
-
5
- def source_collection_name(collection_name = nil)
6
- return @source_collection = collection_name if collection_name
7
- @source_collection ||= name.chomp("Cubicle").chomp("Cube").chomp("Aggregation").underscore.pluralize
8
- end
9
- alias source_collection_name= source_collection_name
10
-
11
- def target_collection_name(collection_name = nil)
12
- return nil if transient?
13
- return @target_name = collection_name if collection_name
14
- @target_name ||= "#{name.blank? ? source_collection_name : name.underscore.pluralize}_cubicle"
15
- end
16
- alias target_collection_name= target_collection_name
17
-
18
- def dimension(*args)
19
- dimensions << Cubicle::Dimension.new(*args)
20
- dimensions[-1]
21
- end
22
-
23
- def dimensions(*args)
24
- return (@dimensions ||= Cubicle::MemberList.new) if args.length < 1
25
- args = args[0] if args.length == 1 && args[0].is_a?(Array)
26
- args.each {|dim| dimension dim }
27
- @dimensions
28
- end
29
-
30
- def measure(*args)
31
- measures << Measure.new(*args)
32
- measures[-1]
33
- end
34
-
35
- def measures(*args)
36
- return (@measures ||= Cubicle::MemberList.new) if args.length < 1
37
- args = args[0] if args.length == 1 && args[0].is_a?(Array)
38
- args.each {|m| measure m}
39
- @measures
40
- end
41
-
42
- def count(*args)
43
- options = args.extract_options!
44
- options[:aggregation_method] = :count
45
- measure(*(args << options))
46
- end
47
-
48
- def average(*args)
49
- options = args.extract_options!
50
- options[:aggregation_method] = :average
51
- measure(*(args << options))
52
- #Averaged fields need a count of non-null values to properly calculate the average
53
- args[0] = "#{args[0]}_count".to_sym
54
- count *args
55
- end
56
- alias avg average
57
-
58
- def sum(*args)
59
- options = args.extract_options!
60
- options[:aggregation_method] = :sum
61
- measure(*(args << options))
62
- end
63
-
64
- def duration(*args)
65
- options = args.extract_options!
66
- options[:in] ||= durations_in
67
- args << options
68
- measures << (dur = Duration.new(*args))
69
- count("#{dur.name}_count".to_sym, :expression=>dur.expression) if dur.aggregation_method == :average
70
- end
71
-
72
- def average_duration(*args)
73
- duration(*args)
74
- end
75
- alias avg_duration average_duration
76
-
77
- def total_duration(*args)
78
- options = args.extract_options!
79
- options[:aggregation_method] = :sum
80
- duration(*(args<<options))
81
- end
82
-
83
- def durations_in(unit_of_time = nil)
84
- return (@duration_unit ||= :seconds) unless unit_of_time
85
- @duration_unit = unit_of_time.to_s.pluralize.to_sym
86
- end
87
- alias :duration_unit :durations_in
88
-
89
-
90
- def ratio(member_name, numerator, denominator)
91
- measures << Ratio.new(member_name, numerator, denominator)
92
- end
93
-
94
- def aggregation(*member_list)
95
- member_list = member_list[0] if member_list[0].is_a?(Array)
96
- aggregations << member_list
97
- end
98
-
99
- def time_dimension(*args)
100
- return (@time_dimension ||= nil) unless args.length > 0
101
- @time_dimension = dimension(*args)
102
- end
103
- alias time_dimension= time_dimension
104
- alias date time_dimension
105
- alias time time_dimension
106
- end
107
- end
1
+ module Cubicle
2
+ module Aggregation
3
+ module Dsl
4
+
5
+ def source_collection_name(collection_name = nil)
6
+ return @source_collection = collection_name if collection_name
7
+ @source_collection ||= name.chomp("Cubicle").chomp("Cube").chomp("Aggregation").underscore.pluralize
8
+ end
9
+ alias source_collection_name= source_collection_name
10
+
11
+ def target_collection_name(collection_name = nil)
12
+ return nil if transient?
13
+ return @target_name = collection_name if collection_name
14
+ @target_name ||= "#{name.blank? ? source_collection_name : name.underscore.pluralize}_cubicle"
15
+ end
16
+ alias target_collection_name= target_collection_name
17
+
18
+ def dimension(*args)
19
+ dimensions << Cubicle::Dimension.new(*args)
20
+ dimensions[-1]
21
+ end
22
+
23
+ def dimensions(*args)
24
+ return (@dimensions ||= Cubicle::MemberList.new) if args.length < 1
25
+ args = args[0] if args.length == 1 && args[0].is_a?(Array)
26
+ args.each {|dim| dimension dim }
27
+ @dimensions
28
+ end
29
+
30
+ def measure(*args)
31
+ measures << Measure.new(*args)
32
+ measures[-1]
33
+ end
34
+
35
+ def measures(*args)
36
+ return (@measures ||= Cubicle::MemberList.new) if args.length < 1
37
+ args = args[0] if args.length == 1 && args[0].is_a?(Array)
38
+ args.each {|m| measure m}
39
+ @measures
40
+ end
41
+
42
+ def count(*args)
43
+ options = args.extract_options!
44
+ options[:aggregation_method] = :count
45
+ measure(*(args << options))
46
+ end
47
+
48
+ def average(*args)
49
+ options = args.extract_options!
50
+ options[:aggregation_method] = :average
51
+ measure(*(args << options))
52
+ #Averaged fields need a count of non-null values to properly calculate the average
53
+ args[0] = "#{args[0]}_count".to_sym
54
+ count *args
55
+ end
56
+ alias avg average
57
+
58
+ def sum(*args)
59
+ options = args.extract_options!
60
+ options[:aggregation_method] = :sum
61
+ measure(*(args << options))
62
+ end
63
+
64
+ def duration(*args)
65
+ options = args.extract_options!
66
+ options[:in] ||= durations_in
67
+ args << options
68
+ measures << (dur = Duration.new(*args))
69
+ count("#{dur.name}_count".to_sym, :expression=>dur.expression) if dur.aggregation_method == :average
70
+ end
71
+
72
+ def average_duration(*args)
73
+ duration(*args)
74
+ end
75
+ alias avg_duration average_duration
76
+
77
+ def total_duration(*args)
78
+ options = args.extract_options!
79
+ options[:aggregation_method] = :sum
80
+ duration(*(args<<options))
81
+ end
82
+
83
+ def duration_since(*args)
84
+ options = args.extract_options!
85
+ ms1 = args.length > 1 ? args.delete_at(1) : args.shift
86
+ options[ms1] = :now
87
+ duration(*(args<<options))
88
+ end
89
+ alias age_since duration_since
90
+ alias elapsed duration_since
91
+
92
+ def durations_in(unit_of_time = nil)
93
+ return (@duration_unit ||= :seconds) unless unit_of_time
94
+ @duration_unit = unit_of_time.to_s.pluralize.to_sym
95
+ end
96
+ alias :duration_unit :durations_in
97
+
98
+
99
+ def ratio(member_name, numerator, denominator)
100
+ measures << Ratio.new(member_name, numerator, denominator)
101
+ end
102
+
103
+ def aggregation(*member_list)
104
+ member_list = member_list[0] if member_list[0].is_a?(Array)
105
+ aggregations << member_list
106
+ end
107
+
108
+ def time_dimension(*args)
109
+ return (@time_dimension ||= nil) unless args.length > 0
110
+ @time_dimension = dimension(*args)
111
+ end
112
+ alias time_dimension= time_dimension
113
+ alias date time_dimension
114
+ alias time time_dimension
115
+ end
116
+ end
108
117
  end
@@ -23,7 +23,7 @@ module Cubicle
23
23
  cond = " && (#{self.condition})" unless self.condition.blank?
24
24
  #prefix these names for the expression
25
25
  prefix = "#{self.timestamp_prefix}#{self.timestamp_prefix.blank? ? '' : '.'}"
26
- ms1,ms2 = [self.begin_milestone,self.end_milestone].map{|ms|"this.#{prefix}#{ms}"}
26
+ ms1,ms2 = [self.begin_milestone,self.end_milestone].map{|ms|ms.to_s=='now' ? "new Date(#{Time.now.to_i*1000})" : "this.#{prefix}#{ms}"}
27
27
  @expression = "(#{ms1} && #{ms2}#{cond}) ? (#{ms2}-#{ms1})/#{denominator} : null"
28
28
  end
29
29
 
@@ -1,3 +1,3 @@
1
1
  module Cubicle
2
- VERSION = '0.1.4'
2
+ VERSION = '0.1.5'
3
3
  end
@@ -1,47 +1,69 @@
1
- require "test_helper"
2
-
3
- class DurationTest < ActiveSupport::TestCase
4
- context "Querying a cubicle with durations" do
5
- setup do
6
- #record 1, ms1 = 1/1/2000, ms2 = 1/2/2000, ms3=1/4/2000
7
- #record 2, ms1 = 1/1/2000, ms2 = 1/3/2000, ms3=1/5/2000
8
- Defect.create_duration_test_data
9
- end
10
- should "correctly calculate durations for each activity" do
11
- results = DefectCubicle.query do
12
- select :all
13
- by :operator
14
- end
15
- a1 = results["a"][0]
16
- a2 = results["b"][0]
17
-
18
- assert_equal 1 * 60 * 60 * 24, a1["ms1_to_ms2_average"]
19
- assert_equal 2 * 60 * 60 * 24, a1["ms2_to_ms3_sum"]
20
- assert_equal 3, a1["total_duration"]
21
-
22
- assert_equal 2 * 60 * 60 * 24, a2["ms1_to_ms2_average"]
23
- assert_equal 2 * 60 * 60 * 24, a2["ms2_to_ms3_sum"]
24
- assert_equal 4, a2["total_duration"]
25
- end
26
- should "correctly aggregate durations" do
27
- results = DefectCubicle.query do
28
- select :all_measures, :product
29
- end
30
- results = results[0]
31
-
32
- assert_equal 1.5 * 60 * 60 * 24, results["ms1_to_ms2_average"]
33
- assert_equal 4 * 60 * 60 * 24, results["ms2_to_ms3_sum"]
34
- assert_equal 3.5, results["total_duration"]
35
-
36
- end
37
- should "respect the condition argument" do
38
- results = DefectCubicle.query do
39
- select :all_measures, :product
40
- end
41
- results = results[0]
42
-
43
- assert_equal 3, results["conditional_duration"]
44
- end
45
- end
46
-
1
+ require "test_helper"
2
+
3
+ class DurationTest < ActiveSupport::TestCase
4
+ context "Querying a cubicle with durations" do
5
+ setup do
6
+ #record 1, ms1 = 1/1/2000, ms2 = 1/2/2000, ms3=1/4/2000
7
+ #record 2, ms1 = 1/1/2000, ms2 = 1/3/2000, ms3=1/5/2000
8
+ Defect.create_duration_test_data
9
+ end
10
+ should "correctly calculate durations for each activity" do
11
+ results = DefectCubicle.query do
12
+ select :all
13
+ by :operator
14
+ end
15
+ a1 = results["a"][0]
16
+ a2 = results["b"][0]
17
+
18
+ assert_equal 1 * 60 * 60 * 24, a1["ms1_to_ms2_average"]
19
+ assert_equal 2 * 60 * 60 * 24, a1["ms2_to_ms3_sum"]
20
+ assert_equal 3, a1["total_duration"]
21
+
22
+ assert_equal 2 * 60 * 60 * 24, a2["ms1_to_ms2_average"]
23
+ assert_equal 2 * 60 * 60 * 24, a2["ms2_to_ms3_sum"]
24
+ assert_equal 4, a2["total_duration"]
25
+ end
26
+ should "correctly aggregate durations" do
27
+ results = DefectCubicle.query do
28
+ select :all_measures, :product
29
+ end
30
+ results = results[0]
31
+
32
+ assert_equal 1.5 * 60 * 60 * 24, results["ms1_to_ms2_average"]
33
+ assert_equal 4 * 60 * 60 * 24, results["ms2_to_ms3_sum"]
34
+ assert_equal 3.5, results["total_duration"]
35
+
36
+ end
37
+ should "respect the condition argument" do
38
+ results = DefectCubicle.query do
39
+ select :all_measures, :product
40
+ end
41
+ results = results[0]
42
+
43
+ assert_equal 3, results["conditional_duration"]
44
+ end
45
+ should "calculate duration_since via elapsed" do
46
+ Time.now = "1/10/2000"
47
+ results = DefectCubicle.query do
48
+ select :all_measures, :product
49
+ end
50
+ puts results.inspect
51
+ results = results[0]
52
+
53
+ assert_equal((6+5)/2.0, results["ms3_to_now_average"])
54
+
55
+ end
56
+ should "calculate named duration_since via age_since" do
57
+ Time.now = "1/10/2000"
58
+ results = DefectCubicle.query do
59
+ select :all_measures, :product
60
+ end
61
+ puts results.inspect
62
+ results = results[0]
63
+
64
+ assert_equal((6+5)/2.0, results["avg_time_since_ms3"])
65
+
66
+ end
67
+ end
68
+
47
69
  end
@@ -1,32 +1,34 @@
1
- class DefectCubicle
2
- extend Cubicle::Aggregation
3
-
4
- date :manufacture_date, :field_name=>'manufacture_date', :alias=>:date
5
- dimension :month, :expression=>'this.manufacture_date.substring(0,7)'
6
- dimension :year, :expression=>'this.manufacture_date.substring(0,4)'
7
-
8
- dimension :manufacture_time
9
-
10
- dimension :product, :field_name=>'product.name'
11
- dimension :region, :field_name=>'plant.address.region'
12
-
13
- dimensions :operator, :outcome
14
-
15
- count :total_defects, :field_name=>'defect_id'
16
- count :preventable_defects, :expression=>'this.root_cause != "act_of_god"'
17
- sum :total_cost, :field_name=>'cost'
18
- avg :avg_cost, :field_name=>'cost'
19
-
20
- #calculated fields
21
- ratio :preventable_pct, :preventable_defects, :total_defects
22
-
23
- #durations
24
- average_duration :ms1 => :ms2
25
- total_duration :ms2 => :ms3
26
- duration :total_duration, :ms1 => :ms3, :in=>:days
27
- duration :conditional_duration, :ms1 => :ms3, :in=>:days, :condition=>"this.defect_id != 2"
28
-
29
- #pre-cached aggregations
30
- aggregation :month, :year, :product
31
- aggregation :month, :region
1
+ class DefectCubicle
2
+ extend Cubicle::Aggregation
3
+
4
+ date :manufacture_date, :field_name=>'manufacture_date', :alias=>:date
5
+ dimension :month, :expression=>'this.manufacture_date.substring(0,7)'
6
+ dimension :year, :expression=>'this.manufacture_date.substring(0,4)'
7
+
8
+ dimension :manufacture_time
9
+
10
+ dimension :product, :field_name=>'product.name'
11
+ dimension :region, :field_name=>'plant.address.region'
12
+
13
+ dimensions :operator, :outcome
14
+
15
+ count :total_defects, :field_name=>'defect_id'
16
+ count :preventable_defects, :expression=>'this.root_cause != "act_of_god"'
17
+ sum :total_cost, :field_name=>'cost'
18
+ avg :avg_cost, :field_name=>'cost'
19
+
20
+ #calculated fields
21
+ ratio :preventable_pct, :preventable_defects, :total_defects
22
+
23
+ #durations
24
+ average_duration :ms1 => :ms2
25
+ total_duration :ms2 => :ms3
26
+ duration :total_duration, :ms1 => :ms3, :in=>:days
27
+ duration :conditional_duration, :ms1 => :ms3, :in=>:days, :condition=>"this.defect_id != 2"
28
+ elapsed :ms3, :in=>:days
29
+ age_since :avg_time_since_ms3, :ms3, :in=>:days
30
+
31
+ #pre-cached aggregations
32
+ aggregation :month, :year, :product
33
+ aggregation :month, :region
32
34
  end