Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- --- !ruby/object:ExecutablePage
- filename: ctfc4kkn385z8hwx57sk3t77qeh497b8ukb
- tags:
- :calc:
- :date: 2011-03-26 20:04:26.507557 -07:00
- :log:
- :programming:
- :ruby:
- :spreadsheet:
- data:
- :code: |-
- class ::Calculations
- class UnknownReference < NameError ; end
- def self.children ; @children ||= {} ; end
- def self.[] name
- # puts "Fetching #{name} from #{@names.length} names"
- obj = children[name]
- raise UnknownReference, "No such named-object as '#{name.inspect}'" unless obj
- obj
- end
- def self.new name, value
- children.member?(name) ? children[name].value = value : children[name] = super
- end
- def self.wipe
- @children = nil
- end
- attr_reader :dependents, :name, :requirements, :value
- def initialize name, value
- @name = name
- @value = value
- @dependents = []
- @requirements = []
- self
- end
- def invalidate
- # p [:inv, name, @dependents.length]
- @requirements = []
- @result = nil
- @dependents.each {|n| Show(n).invalidate }
- @dependents = [] # They're no-longer dependent on us until they re-reference us
- end
- def value= val
- invalidate unless val == value
- @value = val
- end
- def bind bnd, nm
- # p [:bind, nm, :for, name, :bnd, bnd]
- bnd.eval "#{nm} = Show(:#{nm}).calc"
- end
- def bind_all bnd
- requirements.each {|n| bind bnd, n }
- end
- def add_requirement nm
- # p [:ar, name, nm]
- raise "Re-adding requirement #{nm} to #{name}" if requirements.member? nm
- Show(nm).register_a_dependent name
- requirements << nm
- end
- def register_a_dependent who
- nm = who.respond_to?(:name) ? who.name : who
- dependents << nm unless dependents.member? nm
- end
- def run
- # p [:Cs,self.class.constants - Object.constants]
- bnd = binding
- # p [:bnd, bnd]
- bind_all bnd
- begin
- # puts "Trying lambda"
- v = bnd.eval formula, "solving for #{name}"
- v
- rescue NameError => e
- # puts "Rescued " + e
- if e.class == NameError
- raise "Not the right error '#{e.message}'" unless e.message =~ /^undefined local variable or method `\w+' for /
- nm = e.message.scan(/`(\S+)'/).first.first.to_sym
- add_requirement nm
- bind bnd, nm
- retry
- else
- # puts "Rethrowing #{e.class}"
- raise
- end
- end
- end
- def formula
- return nil unless value.is_a?(String) && value[0..0] == '='
- value[( value[1..-1].index(/[^\s]/) + 1 )..-1]
- end
- def expand_formula recurse = 1, values = false
- # p [:ef1, name, :r, recurse, :v, values]
- # p [:v, value]
- calc rescue puts "Failed to fully graph #{name}" # resolve requirements as far as possible
- f = formula
- # p [:ef,:reql,requirements.length,:req,requirements]
- requirements.each {|n|
- r = Show(n)
- re = /#{n}/
- sf = if r.formula
- # p [:ef,:rf,r.formula]
- "(#{r.expand_formula(recurse - 1, values)})"
- else
- # p [:ef,:rv,r.value]
- "#{r.value.inspect}" if values
- end
- # p [:ef2, name, re, sf]
- f.gsub! re, sf if sf
- } unless recurse.zero?
- f
- end
- def calc
- @result ||= begin
- formula ? run : @value
- end
- end
- end
- def Set *a ; Calculations.new *a ; end
- def Show n ; Calculations[n] ; end
- def Calc n
- begin
- Show(n).calc
- rescue
- raise unless $!.class <= NameError
- puts $!.message
- end
- end
- :custom_methods:
- :redit:
- :args: "*a"
- :body: |-
- # p [:edit_wrapper, a]
- results = self.class.instance_method(:edit).bind(self).call *a
- Thread.new {
- # sleep 5
- # print "Checking diff"
- unless diff.empty?
- # print " writing"
- write
- end
- # puts " done"
- }
- run
- results
- :run:
- :body: |-
- eval data[:code]
- data[:tax].each {|n,v| Set n, v }
- nil
- :examples: |-
- Calculations.wipe
- Set :wage, 10.25
- Set :hours, 2000
- Set :gross, '= wage * hours'
- Set :tax_rate, 0.35
- Set :tax, '= gross * tax_rate'
- Set :net, '= gross - tax'
- Calc :net
- Set :wage, 10.75 # a raise!
- Calc :net # automatically recalculates
- Show(:net).expand_formula(-1)
- :tax:
- - - :refund
- - "= refund_or_balance_owing < 0 ? refund_or_balance_owing.abs : 0"
- - - :refund_or_balance_owing
- - = total_tax_payable - total_credits
- - - :total_tax_payable
- - = net_federal_tax + bc_tax
- - - :net_federal_tax
- - = federal_tax
- - - :federal_tax
- - = basic_federal_tax
- - - :total_credits
- - = total_income_tax_deducted + bc_credits
- - - :bc_credits
- - 0
- - - :total_income_tax_deducted
- - 4249.82
- - - :basic_federal_tax
- - = s1_39 - s1_44
- - - :s1_39
- - = s1_37
- - - :s1_44
- - = total_federal_nonrefundable_tax_credits
- - - :s1_37
- - = taxable_income * federal_tax_rate
- - - :federal_tax_rate
- - = basic_federal_tax_rate
- - - :basic_federal_tax_rate
- - 0.15
- - - :total_federal_nonrefundable_tax_credits
- - = s1_25 * basic_federal_tax_rate
- - - :s1_25
- - = federal_basic_personal_amount + spouse_amount + cpp_contributions + ei_premiums + employment_amount
- - - :cpp_contributions
- - 1420.57
- - - :ei_premiums
- - 528.53
- - - :federal_basic_personal_amount
- - 10382
- - - :spouse_amount
- - 10382
- - - :employment_amount
- - = [1051, total_employment_income].min
- - - :total_employment_income
- - = employment_income
- - - :employment_income
- - = t4_1_14
- - - :t4_1_14
- - 31571.07
- - - :taxable_income
- - = net_income
- - - :net_income
- - = net_income_before_adjustments
- - - :net_income_before_adjustments
- - = total_income - annual_dues
- - - :annual_dues
- - 528.55
- - - :total_income
- - = employment_income + ei_and_other_benefits
- - - :ei_and_other_benefits
- - 3681.0
- - - :bc_tax
- - = taxable_income * bc_tax_rate - bc_nonrefundable_tax_credits
- - - :bc_tax_rate
- - 0.0506
- - - :bc_nonrefundable_tax_credits_subtotal
- - = bc_basic_personal_amount + bc_spouse_amount + cpp_contributions + ei_premiums
- - - :bc_basic_personal_amount
- - 11000
- - - :bc_spouse_amount
- - = [9653, bc_spouse_amount_subtotal].min
- - - :bc_spouse_amount_subtotal
- - = bc_spouse_basic_amount - spouse_net_income
- - - :bc_spouse_basic_amount
- - 10618
- - - :spouse_net_income
- - 0
- - - :bc_nonrefundable_tax_credits
- - = bc_nonrefundable_tax_credits_subtotal * bc_tax_rate
- - - :unreclaimed_tax
- - = total_income_tax_deducted - refund
Add Comment
Please, Sign In to add comment