module Crunchr

Crunch statistics with fun

@author Harotg de Mik

Public Class Methods

included(base) click to toggle source
# File lib/crunchr.rb, line 9
def self.included(base)
  base.extend(ClassMethods)
end

Public Instance Methods

calculate(key) click to toggle source

given a string like ‘keys - doors’, returns the amount of spare keys

You can group calculations by surrounding them with (), eg:

(doors - keys) / (inhabitants - keys)

Pass in real numbers if you like

(doors + 2) / keys

@note

The result is *always* a float.
If anything fails, 0.0 is returned.

@param String key The calculation to perform @return Float result

# File lib/crunchr.rb, line 96
def calculate(key)
  while key =~ /\(/ && key =~ /\)/
    key.gsub!(/\(([^\(\)]+)\)/) do |calculation|
      calculate(calculation.gsub(/[\(\)]/, ''))
    end
  end

  (left, op, right) = key.split(/\s/)

  left = (
    left =~ /[^\d.]/ ? self.fetch(left) : BigDecimal.new(left)
  ) || zero()

  right = (
    right =~ /[^\d.]/ ? self.fetch(right) : BigDecimal.new(right)
  ) || zero()

  op = op == ":" ? "/" : op
  op = op == "x" ? "*" : op

  # make sure at least 1 hand is a float
  left *= 1.0 if [left.class, right.class].include?(Fixnum)

  value = ( left.send(op, right) ) rescue zero()
  return checked(value)
end
checked(val) click to toggle source
# File lib/crunchr.rb, line 14
def checked(val); self.class.checked(val); end
delta(other) click to toggle source
# File lib/crunchr.rb, line 16
def delta(other)
  return nil if other.respond_to?(:data) && !other.data.is_a?(Hash)
  return nil unless self.data.is_a?(Hash)

  delta      = self.class.new
  delta.data = self.data.dup.delta(other.data)

  # make it read-only
  delta.readonly! if delta.respond_to?(:readonly!)

  return delta
end
fetch(key) click to toggle source

Get the value from the data

# Given a data tree that looks like
{ number: 1
  collection: {
    depth: 2
  }
  list: [ 1, 2, 3 ]
}

fetch("number")           # => 1
fetch("collection/depth") # => 2
fetch("n'existe pas")     # => nil
fetch("collection")       # => { depth: 2 }
fetch("list")             # => nil - NaN && !Hash

When you supply a calculation to fetch, it will delegate to calculate

fetch("number : collection") # => 0.5 (1 / 2)
# File lib/crunchr.rb, line 48
def fetch(key)
  return calculate(key) if key =~ / [*\/:x+-] /

  key = key.split(/\//).collect(&:to_sym) if key =~ /\//
  value = nil

  # fetch directly
  if [String, Symbol].include?(key.class)
    if self.data.has_key?(key)
      value = self.data.fetch(key)
    else
      value = self.data.fetch(key.to_sym) rescue nil
    end

  else
    value = self.data
    key.each do |sub|
      value = value.fetch(sub) rescue nil
    end
  end

  if value.is_a?(Numeric) || value.is_a?(Hash)
    return value
  end

rescue => ex
  if self.class.respond_to?(:logger) && !self.class.logger.nil?
    self.class.logger.error "Error in #{self.class}.fetch(#{key}) for #{data}"
  end
end
zero() click to toggle source
# File lib/crunchr.rb, line 13
def zero; self.class.zero; end