Module: Cubicle

Included in:
Aggregation
Defined in:
lib/cubicle.rb,
lib/cubicle/data.rb,
lib/cubicle/query.rb,
lib/cubicle/ratio.rb,
lib/cubicle/member.rb,
lib/cubicle/measure.rb,
lib/cubicle/version.rb,
lib/cubicle/date_time.rb,
lib/cubicle/dimension.rb,
lib/cubicle/data_level.rb,
lib/cubicle/aggregation.rb,
lib/cubicle/member_list.rb,
lib/cubicle/mongo_environment.rb,
lib/cubicle/calculated_measure.rb,
lib/cubicle/mongo_mapper/aggregate_plugin.rb

Defined Under Namespace

Modules: DateTime, MongoMapper Classes: Aggregation, CalculatedMeasure, Data, DataLevel, Dimension, Measure, Member, MemberList, MongoEnvironment, Query, Ratio

Constant Summary collapse

VERSION =
'0.1.0'

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.loggerObject



33
34
35
# File 'lib/cubicle.rb', line 33

def self.logger
  Cubicle.mongo.logger
end

.mongoObject



29
30
31
# File 'lib/cubicle.rb', line 29

def self.mongo
  @mongo ||= defined?(::MongoMapper::Document) ? ::MongoMapper : MongoEnvironment
end

.register_cubicle_directory(directory_path, recursive = true) ⇒ Object



24
25
26
27
# File 'lib/cubicle.rb', line 24

def self.register_cubicle_directory(directory_path, recursive=true)
  searcher = "#{recursive ? "*" : "**/*"}.rb"
  Dir[File.join(directory_path,searcher)].each {|cubicle| require cubicle}
end

Instance Method Details

#aggregation(*member_list) ⇒ Object



130
131
132
133
# File 'lib/cubicle.rb', line 130

def aggregation(*member_list)
  member_list = member_list[0] if member_list[0].is_a?(Array)
  aggregations << member_list
end

#aggregationsObject



58
59
60
# File 'lib/cubicle.rb', line 58

def aggregations
  return (@aggregations ||= [])
end

#average(*args) ⇒ Object Also known as: avg



110
111
112
113
114
115
116
117
# File 'lib/cubicle.rb', line 110

def average(*args)
  options = args.extract_options!
  options[:aggregation_method] = :average
  measure(*(args << options))
  #Averaged fields need a count of non-null values to properly calculate the average
  args[0] = "#{args[0]}_count".to_sym
  count *args
end

#collectionObject



41
42
43
# File 'lib/cubicle.rb', line 41

def collection
  database[target_collection_name]
end

#count(*args) ⇒ Object



104
105
106
107
108
# File 'lib/cubicle.rb', line 104

def count(*args)
  options = args.extract_options!
  options[:aggregation_method] = :count
  measure(*(args << options))
end

#databaseObject



37
38
39
# File 'lib/cubicle.rb', line 37

def database
  Cubicle.mongo.database
end

#dimension(*args) ⇒ Object



76
77
78
79
# File 'lib/cubicle.rb', line 76

def dimension(*args)
  dimensions << Cubicle::Dimension.new(*args)
  dimensions[-1]
end

#dimension_namesObject



81
82
83
# File 'lib/cubicle.rb', line 81

def dimension_names
  return @dimensions.map{|dim|dim.name.to_s}
end

#dimensions(*args) ⇒ Object



85
86
87
88
89
90
# File 'lib/cubicle.rb', line 85

def dimensions(*args)
  return (@dimensions ||= Cubicle::MemberList.new) if args.length < 1
  args = args[0] if args.length == 1 && args[0].is_a?(Array)
  args.each {|dim| dimension dim }
  @dimensions
end

#execute_query(query, options = {}) ⇒ Object



166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
# File 'lib/cubicle.rb', line 166

def execute_query(query,options={})
  count = 0

  find_options = {
          :limit=>query.limit || 0,
          :skip=>query.offset || 0
  }

  find_options[:sort] = prepare_order_by(query)
  filter = {}
  if query == self || query.transient?
    aggregation = aggregate(query,options)
  else
    process_if_required
    aggregation = aggregation_for(query)
    #if the query exactly matches the aggregation in terms of requested members, we can issue a simple find
    #otherwise, a second map reduce is required to reduce the data set one last time
    if ((aggregation.name.split("_")[-1].split(".")) - query.member_names - [:all_measures]).blank?
      filter = prepare_filter(query,options[:where] || {})
    else
      aggregation = aggregate(query,:source_collection=>collection.name)
    end
  end
  count = aggregation.count
  #noinspection RubyArgCount
  data = aggregation.find(filter,find_options).to_a
  #noinspection RubyArgCount
  aggregation.drop if aggregation.name =~ /^tmp.mr.*/
  Cubicle::Data.new(query, data, count)
end

#expire!Object



53
54
55
56
# File 'lib/cubicle.rb', line 53

def expire!
  collection.drop
  expire_aggregations!
end

#find_member(member_name) ⇒ Object



143
144
145
146
# File 'lib/cubicle.rb', line 143

def find_member(member_name)
  @dimensions[member_name] ||
          @measures[member_name]
end

#measure(*args) ⇒ Object



92
93
94
95
# File 'lib/cubicle.rb', line 92

def measure(*args)
  measures << Measure.new(*args)
  measures[-1]
end

#measures(*args) ⇒ Object



97
98
99
100
101
102
# File 'lib/cubicle.rb', line 97

def measures(*args)
  return (@measures ||= Cubicle::MemberList.new) if args.length < 1
  args = args[0] if args.length == 1 && args[0].is_a?(Array)
  args.each {|m| measure m}
  @measures
end

#process(options = {}) ⇒ Object



197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
# File 'lib/cubicle.rb', line 197

def process(options={})
  Cubicle.logger.info "Processing #{self.name} @ #{Time.now}"
  start = Time.now
  expire!
  aggregate(self,options)
  #Sort desc by length of array, so that larget
  #aggregations are processed first, hopefully increasing efficiency
  #of the processing step
  aggregations.sort!{|a,b|b.length<=>a.length}
  aggregations.each do |member_list|
    agg_start = Time.now
    aggregation_for(query(:defer=>true){select member_list})
    Cubicle.logger.info "#{self.name} aggregation #{member_list.inspect} processed in #{Time.now-agg_start} seconds"
  end
  duration = Time.now - start
  Cubicle.logger.info "#{self.name} processed @ #{Time.now}in #{duration} seconds."
end

#query(*args, &block) ⇒ Object



148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
# File 'lib/cubicle.rb', line 148

def query(*args,&block)
  options = args.extract_options!
  query = Cubicle::Query.new(self)
  query.source_collection_name = options.delete(:source_collection) if options[:source_collection]
  query.select(*args) if args.length > 0
  if block_given?
    block.arity == 1 ? (yield query) : (query.instance_eval(&block))
  end
  query.select_all unless query.selected?
  return query if options[:defer]
  results = execute_query(query,options)
  #If the 'by' clause was used in the the query,
  #we'll hierarchize by the members indicated,
  #as the next step would otherwise almost certainly
  #need to be a call to hierarchize anyway.
  query.respond_to?(:by) && query.by.length > 0 ? results.hierarchize(*query.by) : results
end

#ratio(member_name, numerator, denominator) ⇒ Object



126
127
128
# File 'lib/cubicle.rb', line 126

def ratio(member_name, numerator, denominator)
  measures << Ratio.new(member_name, numerator, denominator)
end

#source_collection_name(collection_name = nil) ⇒ Object Also known as: source_collection_name=

DSL



63
64
65
66
# File 'lib/cubicle.rb', line 63

def source_collection_name(collection_name = nil)
  return @source_collection = collection_name if collection_name
  @source_collection ||= name.chomp("Cubicle").chomp("Cube").underscore.pluralize
end

#sum(*args) ⇒ Object



120
121
122
123
124
# File 'lib/cubicle.rb', line 120

def sum(*args)
  options = args.extract_options!
  options[:aggregation_method] = :sum
  measure(*(args << options))
end

#target_collection_name(collection_name = nil) ⇒ Object Also known as: target_collection_name=



69
70
71
72
73
# File 'lib/cubicle.rb', line 69

def target_collection_name(collection_name = nil)
  return nil if transient?
  return @target_name = collection_name if collection_name
  @target_name ||= "#{name.blank? ? source_collection_name : name.underscore.pluralize}_cubicle"
end

#time_dimension(*args) ⇒ Object Also known as: time_dimension=, date, time



135
136
137
138
# File 'lib/cubicle.rb', line 135

def time_dimension(*args)
  return (@time_dimension ||= nil) unless args.length > 0
  @time_dimension = dimension(*args)
end

#transient!Object



49
50
51
# File 'lib/cubicle.rb', line 49

def transient!
  @transient = true
end

#transient?Boolean

Returns:

  • (Boolean)


45
46
47
# File 'lib/cubicle.rb', line 45

def transient?
  @transient ||= false
end