Class: IncomeTax::Models::Generic

Inherits:
Object
  • Object
show all
Extended by:
Forwardable, Helpers
Includes:
Helpers
Defined in:
lib/income_tax/models/generic.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(income: 0, income_type: :gross, **options) ⇒ Generic

Returns a new instance of Generic.

Raises:

  • (ArgumentError)


83
84
85
86
87
88
89
90
91
92
93
94
95
# File 'lib/income_tax/models/generic.rb', line 83

def initialize(income: 0, income_type: :gross, **options)
  raise ArgumentError, "income can't be negative" if income < 0
  @income_type = income_type
  @options     = options.dup

  set_default_options
  setup(income: income, income_type: income_type, **options)
  @options.freeze

  based_on?(:gross) ? set_gross_income(income) : set_net_income(income)
  cast_values
  validate
end

Instance Attribute Details

#gross_incomeObject (readonly)

Returns the value of attribute gross_income.



9
10
11
# File 'lib/income_tax/models/generic.rb', line 9

def gross_income
  @gross_income
end

#net_incomeObject (readonly)

Returns the value of attribute net_income.



9
10
11
# File 'lib/income_tax/models/generic.rb', line 9

def net_income
  @net_income
end

#optionsObject (readonly)

Returns the value of attribute options.



9
10
11
# File 'lib/income_tax/models/generic.rb', line 9

def options
  @options
end

#rateObject (readonly)

Returns the value of attribute rate.



9
10
11
# File 'lib/income_tax/models/generic.rb', line 9

def rate
  @rate
end

#taxesObject (readonly)

Returns the value of attribute taxes.



9
10
11
# File 'lib/income_tax/models/generic.rb', line 9

def taxes
  @taxes
end

Class Method Details

.currency(value = nil) ⇒ Object



60
61
62
63
# File 'lib/income_tax/models/generic.rb', line 60

def self.currency(value = nil)
  @currency = value if value
  @currency
end

.lazy(&block) ⇒ Object



65
66
67
68
# File 'lib/income_tax/models/generic.rb', line 65

def self.lazy(&block)
  @lazy_mutex = Mutex.new
  @lazy = block
end

.method_added(method) ⇒ Object



11
12
13
14
15
16
# File 'lib/income_tax/models/generic.rb', line 11

def self.method_added(method)
  return super if self == Generic
  return super if superclass.method_defined? method
  superclass.protected_method_defined?(method) ? protected(method) : private(method)
  super
end

.name(value = nil) ⇒ Object



18
19
20
21
# File 'lib/income_tax/models/generic.rb', line 18

def self.name(value = nil)
  @name = value if value
  @name
end

.namesObject



23
24
25
# File 'lib/income_tax/models/generic.rb', line 23

def self.names
  @names ||= []
end

.newObject



70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/income_tax/models/generic.rb', line 70

def self.new(*)
  if @lazy ||= nil
    @lazy_mutex.synchronize do
      if @lazy
        @lazy.call
        @lazy = nil
      end
    end
  end

  super
end

.other_namesObject



27
28
29
# File 'lib/income_tax/models/generic.rb', line 27

def self.other_names
  names.select { |n| n != name }
end

.register(*names) ⇒ Object



37
38
39
40
41
# File 'lib/income_tax/models/generic.rb', line 37

def self.register(*names)
  @name  ||= names.first
  self.names.concat(names)
  names.each { |name| register_on[name] = self }
end

.register_on(register = nil) ⇒ Object



32
33
34
35
# File 'lib/income_tax/models/generic.rb', line 32

def self.register_on(register = nil)
  @register_on = register if register
  @register_on ||= superclass.register_on
end

.wants_options(*options) ⇒ Object



43
44
45
46
47
48
49
50
51
52
53
54
55
# File 'lib/income_tax/models/generic.rb', line 43

def self.wants_options(*options)
  @wants_options ||= superclass.wants_options.dup

  if options.any?
    @wants_options.concat(options)
    options.each do |option|
      define_method(option)       { @options[option] } unless method_defined? option
      define_method("#{option}?") { !!send(option)   } unless method_defined? "#{option}?"
    end
  end

  @wants_options
end

Instance Method Details

#based_on?(type) ⇒ Boolean

Returns:

  • (Boolean)


173
174
175
# File 'lib/income_tax/models/generic.rb', line 173

def based_on?(type)
  @income_type == type
end

#cast_value(value) ⇒ Object



209
210
211
# File 'lib/income_tax/models/generic.rb', line 209

def cast_value(value)
  value == value.to_i ? value.to_i  : Rate.decimal(value)
end

#cast_valuesObject



202
203
204
205
206
207
# File 'lib/income_tax/models/generic.rb', line 202

def cast_values
  @rate         = Rate(rate)
  @gross_income = cast_value(gross_income)
  @net_income   = cast_value(net_income)
  @taxes        = cast_value(taxes)
end

#inspectObject



181
182
183
184
185
186
187
188
# File 'lib/income_tax/models/generic.rb', line 181

def inspect
  net   = net_income   .is_a?(BigDecimal) ? net_income.to_s("F")   : net_income.to_s
  gross = gross_income .is_a?(BigDecimal) ? gross_income.to_s("F") : gross_income.to_s

  "#<IncomeTax:%p, rate: %p, net: %s, gross: %s>" % [
    location_name, rate.to_s, net, gross
  ]
end

#location_nameObject



177
178
179
# File 'lib/income_tax/models/generic.rb', line 177

def location_name
  self.class.name
end

#set_default_optionsObject



122
123
124
125
126
127
128
129
130
131
132
133
134
135
# File 'lib/income_tax/models/generic.rb', line 122

def set_default_options
  options[:married]    = false if options[:married].nil?
  options[:children]   = 0     if options[:children] == false
  options[:children] ||= options[:married] ? 1 : 0
  options[:age]      ||= age_for(options[:birthday]) if options[:birthday]
  options[:age]      ||= 30
  options[:tax_year] ||= Time.now.year

  options.select! { |k,v| self.class.wants_options.include? k }

  options[:tax_year] &&= Integer(options[:tax_year])
  options[:age]      &&= Integer(options[:age])
  options[:children] &&= Integer(options[:children])
end

#setup(options) ⇒ Object



97
98
# File 'lib/income_tax/models/generic.rb', line 97

def setup(options)
end

#validateObject



100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
# File 'lib/income_tax/models/generic.rb', line 100

def validate
  raise "gross income can't be negative" if gross_income < 0
  raise "net income can't be negative"   if net_income   < 0
  raise "taxes can't be negative"        if taxes        < 0

  # devide by two to avoid off by one errors
  if (net_income + taxes).to_i / 3 != gross_income.to_i / 3
    raise "net income and taxes don't add up to gross income. " \
      "%s + %s was expected to result in %s, gave %s" % [
        net_income, taxes, gross_income, net_income + taxes
      ]
  end

  # allow a 0.01% mismatch
  if taxes > 0 and (1.0 - Rate(taxes, gross_income) / rate).abs > 0.0001
    raise "tax rate does not give appropriate taxes. " \
      "%s of %s is %s, not %s" % [
        rate, gross_income, rate.gross_taxes(gross_income), taxes
      ]
  end
end