class ESA::Context

The Context provides a persisted filtered view on the objects related to a Chart.

@author Lenno Nagel

Public Instance Methods

amounts() click to toggle source
# File app/models/esa/context.rb, line 56
def amounts
  self.apply(self.unscoped_amounts)
end
apply(relation) click to toggle source
# File app/models/esa/context.rb, line 60
def apply(relation)
  self.effective_contexts.inject(relation) do |r,context|
    context.inject_filters(r)
  end
end
can_be_persisted?() click to toggle source
# File app/models/esa/context.rb, line 181
def can_be_persisted?
  self.type.present?
end
change_total() click to toggle source
# File app/models/esa/context.rb, line 173
def change_total
  if self.debits_total.present? and self.credits_total.present?
    self.debits_total - self.credits_total
  else
    nil
  end
end
check_freshness(depth=0, options = {}) click to toggle source
# File app/models/esa/context.rb, line 82
def check_freshness(depth=0, options = {})
  if self.is_update_needed? or not has_subcontext_namespaces?(options[:namespace])
    self.update!(options)
  else
    self.update_freshness_timestamp!
  end

  if depth > 0 and self.last_transaction_time.present?
    self.subcontexts.each do |sub|
      if sub.freshness.nil? or sub.freshness <= self.last_transaction_time
        sub.check_freshness(depth - 1)
      end
    end
  end
end
closing_context() click to toggle source
# File app/models/esa/context.rb, line 165
def closing_context
  if self.effective_end_date.present?
    Contexts::OpenCloseContext.new(chart: self.chart, parent: self, end_date: self.effective_end_date, namespace: 'closing')
  else
    Contexts::OpenCloseContext.new(chart: self.chart, parent: self, namespace: 'closing')
  end
end
effective_contexts() click to toggle source
# File app/models/esa/context.rb, line 140
def effective_contexts
  self.parents_and_self
end
effective_end_date() click to toggle source
# File app/models/esa/context.rb, line 152
def effective_end_date
  self.effective_contexts.map(&:end_date).compact.min
end
effective_path() click to toggle source
# File app/models/esa/context.rb, line 144
def effective_path
  self.effective_contexts.map{|ctx| ctx.namespace || ""}
end
effective_start_date() click to toggle source
# File app/models/esa/context.rb, line 148
def effective_start_date
  self.effective_contexts.map(&:start_date).compact.max
end
events() click to toggle source
# File app/models/esa/context.rb, line 44
def events
  self.apply(self.unscoped_events)
end
flags() click to toggle source
# File app/models/esa/context.rb, line 48
def flags
  self.apply(self.unscoped_flags)
end
has_subcontext_namespaces?(*namespaces) click to toggle source
# File app/models/esa/context.rb, line 78
def has_subcontext_namespaces?(*namespaces)
  (namespaces.flatten.compact - subcontext_namespaces).none?
end
is_fresh?(time=Time.zone.now) click to toggle source
# File app/models/esa/context.rb, line 74
def is_fresh?(time=Time.zone.now)
  self.freshness.present? and (self.freshness + ESA.configuration.context_freshness_threshold) > time
end
is_root?() click to toggle source
# File app/models/esa/context.rb, line 36
def is_root?
  self.parent_id.nil?
end
is_subcontext?() click to toggle source
# File app/models/esa/context.rb, line 40
def is_subcontext?
  self.parent_id.present?
end
is_update_needed?() click to toggle source
# File app/models/esa/context.rb, line 98
def is_update_needed?
  if self.freshness.present?
    if self.last_transaction_time.present?
      self.freshness <= self.last_transaction_time
    else
      false
    end
  else
    true
  end
end
last_transaction_time() click to toggle source
# File app/models/esa/context.rb, line 66
def last_transaction_time
  if defined? @last_transaction_time
    @last_transaction_time
  else
    @last_transaction_time = self.transactions.maximum(:created_at)
  end
end
next_freshness_timestamp() click to toggle source
# File app/models/esa/context.rb, line 128
def next_freshness_timestamp
  if self.parent.present?
    [self.freshness, self.parent.try(:freshness)].compact.max
  else
    Time.zone.now
  end
end
opening_context() click to toggle source
# File app/models/esa/context.rb, line 156
def opening_context
  if self.effective_start_date.present?
    end_date = self.effective_start_date - 1.day
    Contexts::OpenCloseContext.new(chart: self.chart, parent: self, end_date: end_date, namespace: 'opening')
  else
    Contexts::EmptyContext.new(chart: self.chart, parent: self, namespace: 'opening')
  end
end
subcontext_namespaces() click to toggle source
# File app/models/esa/context.rb, line 136
def subcontext_namespaces
  self.subcontexts.pluck(:namespace).compact.uniq
end
transactions() click to toggle source
# File app/models/esa/context.rb, line 52
def transactions
  self.apply(self.unscoped_transactions)
end
update!(options = {}) click to toggle source
# File app/models/esa/context.rb, line 110
def update!(options = {})
  self.freshness = self.next_freshness_timestamp

  ESA.configuration.context_checkers.each do |checker|
    if checker.respond_to? :check
      checker.check(self, options)
    end
  end

  self.update_name
  self.save if self.can_be_persisted?
end
update_freshness_timestamp!() click to toggle source
# File app/models/esa/context.rb, line 123
def update_freshness_timestamp!
  self.freshness = self.next_freshness_timestamp
  self.save if self.can_be_persisted?
end

Protected Instance Methods

default_name() click to toggle source
# File app/models/esa/context.rb, line 207
def default_name
  if self.type.nil?
    self.chart.name unless self.chart.nil?
  else
    "#{self.type.demodulize} \##{self.id}"
  end
end
default_namespace() click to toggle source
# File app/models/esa/context.rb, line 199
def default_namespace
  (self.type || self.class.name).demodulize.underscore.gsub(/_context$/, '')
end
default_position() click to toggle source
# File app/models/esa/context.rb, line 219
def default_position
  nil
end
enforce_persistence_rule() click to toggle source
# File app/models/esa/context.rb, line 245
def enforce_persistence_rule
  if not self.can_be_persisted?
    raise "#{self.class.name} objects are not intended to be persisted"
  end
end
initialize_defaults() click to toggle source
# File app/models/esa/context.rb, line 193
def initialize_defaults
  self.chart ||= self.parent.chart if self.chart_id.nil? and not self.parent_id.nil?
  self.namespace ||= self.default_namespace
  self.position ||= self.default_position
end
initialize_filters() click to toggle source
# File app/models/esa/context.rb, line 223
def initialize_filters
  @filters = []
end
inject_filters(relation) click to toggle source
# File app/models/esa/context.rb, line 227
def inject_filters(relation)
  @filters.select{|f| f.is_a? Proc}.
  inject(relation) do |r,filter|
    filter.call(r)
  end
end
parents_and_self() click to toggle source
# File app/models/esa/context.rb, line 234
  def parents_and_self
    contexts = [self]
    while contexts.last.parent_id.present? and
          not contexts.last.parent_id.in? contexts.map(&:id) and
          contexts.count < 16 do
      # found a valid parent
      contexts << contexts.last.parent
    end
    contexts.reverse
  end

  def enforce_persistence_rule
    if not self.can_be_persisted?
      raise "#{self.class.name} objects are not intended to be persisted"
    end
  end
end
update_name() click to toggle source
# File app/models/esa/context.rb, line 203
def update_name
  self.name = self.default_name
end
update_position() click to toggle source
# File app/models/esa/context.rb, line 215
def update_position
  self.position = self.default_position
end
validate_parent() click to toggle source
# File app/models/esa/context.rb, line 187
def validate_parent
  if self.parent == self
    errors[:parent] = "cannot self-reference, that would create a loop"
  end
end