Class: Counter::Definition

Inherits:
Object
  • Object
show all
Includes:
Singleton
Defined in:
lib/counter/definition.rb

Overview

Example usage…

class ProductCounter

include Counter::Definition
# This specifies the association we're counting
count :products
sum :price   # optional
as "my_counter"

end

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#association_nameObject

Attributes set by Counters#counter integration:



14
15
16
# File 'lib/counter/definition.rb', line 14

def association_name
  @association_name
end

#calculated_fromObject

The block to call to calculate the counter



36
37
38
# File 'lib/counter/definition.rb', line 36

def calculated_from
  @calculated_from
end

#calculated_valueObject

The block used to manually set the value



38
39
40
# File 'lib/counter/definition.rb', line 38

def calculated_value
  @calculated_value
end

#column_to_countObject

When using sum, set the column we’re summing



22
23
24
# File 'lib/counter/definition.rb', line 22

def column_to_count
  @column_to_count
end

#conditional=(value) ⇒ Object (writeonly)

Sets the attribute conditional

Parameters:

  • value

    the value to set the attribute conditional to.



25
26
27
# File 'lib/counter/definition.rb', line 25

def conditional=(value)
  @conditional = value
end

#conditionsObject



98
99
100
101
# File 'lib/counter/definition.rb', line 98

def conditions
  @conditions ||= {}
  @conditions
end

#countable_modelObject

Set the thing we’re counting (set by Counters#counter)



18
19
20
# File 'lib/counter/definition.rb', line 18

def countable_model
  @countable_model
end

#counter_hooksObject



108
109
110
111
# File 'lib/counter/definition.rb', line 108

def counter_hooks
  @counter_hooks ||= []
  @counter_hooks
end

#dependent_countersObject



113
114
115
116
# File 'lib/counter/definition.rb', line 113

def dependent_counters
  @dependent_counters ||= []
  @dependent_counters
end

#global_countersObject



103
104
105
106
# File 'lib/counter/definition.rb', line 103

def global_counters
  @global_counters ||= []
  @global_counters
end

#inverse_associationObject

Set the inverse association (i.e., from the products to the user)



20
21
22
# File 'lib/counter/definition.rb', line 20

def inverse_association
  @inverse_association
end

#method_nameObject

Set the name of the counter (used as the method name)



27
28
29
# File 'lib/counter/definition.rb', line 27

def method_name
  @method_name
end

#modelObject

Set the model we’re attached to (set by Counters#counter)



16
17
18
# File 'lib/counter/definition.rb', line 16

def model
  @model
end

#nameObject

Returns the value of attribute name.



28
29
30
# File 'lib/counter/definition.rb', line 28

def name
  @name
end

#record_nameObject

What we record in Counter::Value#name



91
92
93
94
95
96
# File 'lib/counter/definition.rb', line 91

def record_name
  return @record_name if @record_name.present?
  return name if global?
  return "#{model.name.underscore}-#{association_name}" if association_name.present?
  "#{model.name.underscore}-#{name}"
end

Class Method Details

.after_change(block) ⇒ Object



188
189
190
# File 'lib/counter/definition.rb', line 188

def self.after_change block
  instance.counter_hooks << block
end

.as(name) ⇒ Object

Set the name of the counter



162
163
164
165
# File 'lib/counter/definition.rb', line 162

def self.as name
  instance.name = name.to_s
  instance.method_name = name.to_s
end

.association_nameObject

Get the name of the association we’re counting



168
169
170
# File 'lib/counter/definition.rb', line 168

def self.association_name
  instance.association_name
end

.calculated_from(*dependent_counters, &block) ⇒ Object



141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
# File 'lib/counter/definition.rb', line 141

def self.calculated_from *dependent_counters, &block
  instance.dependent_counters = dependent_counters
  instance.calculated_from = block

  dependent_counters.each do |dependent_counter|
    # Install after_change hooks on the dependent counters
    dependent_counter.after_change :update_calculated_counters
    dependent_counter.define_method :update_calculated_counters do |counter, _old_value, _new_value|
      # Fetch all the counters which depend on this one
      calculated_counters = counter.parent.class.counter_configs.select { |c|
        c.dependent_counters.include?(counter.definition.class)
      }

      calculated_counters = calculated_counters.map { |c| counter.parent.counters.find_or_create_counter!(c) }
      # calculate the new values
      calculated_counters.each(&:calculate!)
    end
  end
end

.calculated_value(calculation, association: nil) ⇒ Object



126
127
128
129
130
# File 'lib/counter/definition.rb', line 126

def self.calculated_value(calculation, association: nil)
  instance.association_name = association
  instance.calculated_value = calculation
  set_default_name
end

.count(association_name, as: "#{association_name}_counter") ⇒ Object

Set the association we’re counting



119
120
121
122
123
124
# File 'lib/counter/definition.rb', line 119

def self.count association_name, as: "#{association_name}_counter"
  instance.association_name = association_name
  instance.name = as.to_s
  # How the counter can be accessed e.g. counter.products_counter
  instance.method_name = as.to_s
end

.counterObject

Access the counter value for global counters



80
81
82
83
84
# File 'lib/counter/definition.rb', line 80

def self.counter
  raise "Unable to find counter instances via #{name}#counter. Use must use #{instance.model}#find_counter or #{instance.model}##{instance.counter_name}" unless instance.global?

  Counter::Value.find_counter self
end

.find_definition(name) ⇒ Object

for global counter instances to find their definition



75
76
77
# File 'lib/counter/definition.rb', line 75

def self.find_definition name
  Counter::Definition.instance.global_counters.find { |c| c.name == name }
end

.globalObject



137
138
139
# File 'lib/counter/definition.rb', line 137

def self.global
  Counter::Definition.instance.global_counters << instance
end

.on(action, &block) ⇒ Object

Define a conditional filter



178
179
180
181
182
183
184
185
186
# File 'lib/counter/definition.rb', line 178

def self.on action, &block
  instance.conditional = true

  conditions = Counter::Conditions.new
  conditions.instance_eval(&block)

  instance.conditions[action] ||= []
  instance.conditions[action] << conditions
end

.record_name(value) ⇒ Object



86
87
88
# File 'lib/counter/definition.rb', line 86

def self.record_name(value)
  instance.record_name = value.to_s
end

.set_default_nameObject



132
133
134
135
# File 'lib/counter/definition.rb', line 132

def self.set_default_name
  instance.name ||= to_s.underscore
  instance.method_name ||= to_s.underscore
end

.sum(column_name) ⇒ Object

Set the column we’re summing. Leave blank to count the number of items



173
174
175
# File 'lib/counter/definition.rb', line 173

def self.sum column_name
  instance.column_to_count = column_name
end

Instance Method Details

#calculated?Boolean

Is this counter calculated from other counters?

Returns:

  • (Boolean)


63
64
65
# File 'lib/counter/definition.rb', line 63

def calculated?
  !@calculated_from.nil?
end

#calculated_value?Boolean

Is this counter using a calculated value?

Returns:

  • (Boolean)


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

def calculated_value?
  @calculated_value.present?
end

#conditional?Boolean

Is this counter conditional?

Returns:

  • (Boolean)


53
54
55
# File 'lib/counter/definition.rb', line 53

def conditional?
  @conditional
end

#global?Boolean

Is this a global counter? i.e., not attached to a model

Returns:

  • (Boolean)


48
49
50
# File 'lib/counter/definition.rb', line 48

def global?
  model.nil?
end

#manual?Boolean

Is this a manual counter? Manual counters are not automatically updated from an association or calculated from other counters

Returns:

  • (Boolean)


70
71
72
# File 'lib/counter/definition.rb', line 70

def manual?
  association_name.nil? && !calculated?
end

#sum?Boolean

Is this a counter which sums a column?

Returns:

  • (Boolean)


43
44
45
# File 'lib/counter/definition.rb', line 43

def sum?
  column_to_count.present?
end