Module: Exchange::Typecasting

Defined in:
lib/exchange/typecasting.rb

Overview

Allows to access properties of an object as currencies The setter takes care of passing the right values to the original setter method, The getter takes care of instantiating a currency of the original getter method, This is framework agnostic. It works in ActiveRecord/Rails, Datamapper, Ohm, Your own, whatever you want

Examples:

The setter converts the currency automatically when the currency is not the one set (example in Active Record)

class MyClass < ActiveRecord::Base
  extend Exchange::Typecasting
  money :price, :currency => lambda { |s| s.manager.currency }

  has_one :manager

  attr_accessible :price

end

MyClass.find(1).update_attributes :price => 1.in(:usd)
MyClass.find(1).price #=> 0.77 EUR

The getter sets the currency automatically to the currency set in the definition (example in Ohm)

class MyClass < Ohm::Model
  extend Exchange::Typecasting
  reference :manager, Manager
  attribute :price

  money :price, :currency => :manager_currency

  def manager_currency
    manager.currency
  end

end

my_instance = MyClass[0]
my_instance.price #=> instance of exchange currency in eur

manager = my_instance.manager
managermanager.update :currency => :usd
my_instance.price #=> instance of exchange currency in usd

Author:

  • Beat Richartz

Since:

  • 0.9.0

Version:

  • 0.9.0

Instance Method Summary collapse

Instance Method Details

#attribute(data) ⇒ Object

Installs a money setter


54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
# File 'lib/exchange/typecasting.rb', line 54

def install_money_getter attribute, options={}
  
  define_method :"#{attribute}_with_exchange_typecasting" do
    currency = evaluate_money_option(options[:currency]) if options[:currency]
    
    test_for_currency_error(currency, attribute)
    
    time     = evaluate_money_option(options[:at]) if options[:at]
    
    if value = send(:"#{attribute}_without_exchange_typecasting")
      Exchange::Money.new(value) do |c|
        c.currency = currency
        c.time     = time if time
      end
    end
  end
  exchange_typecasting_alias_method_chain attribute
  
end

#evaluate_money_optionObject


108
109
110
111
112
# File 'lib/exchange/typecasting.rb', line 108

def install_money_option_eval
  define_method :evaluate_money_option do |option|
    option.is_a?(Proc) ? instance_eval(&option) : send(option)
  end
end

#exchange_typecasting_alias_method_chain(attribute, setter = nil) ⇒ Object

Install an alias method chain for an attribute

Parameters:

  • attribute (String, Symbol)

    The attribute to install the alias method chain for

  • setter (String) (defaults to: nil)

    The setter sign ('=') if this is a setter

Since:

  • 0.9.0


100
101
102
103
# File 'lib/exchange/typecasting.rb', line 100

def exchange_typecasting_alias_method_chain attribute, setter=nil
  alias_method :"#{attribute}_without_exchange_typecasting#{setter}", :"#{attribute}#{setter}"
  alias_method :"#{attribute}#{setter}", :"#{attribute}_with_exchange_typecasting#{setter}"
end

#install_currency_error_testerObject

Since:

  • 0.9.0


117
118
119
120
121
# File 'lib/exchange/typecasting.rb', line 117

def install_currency_error_tester
  define_method :test_for_currency_error do |currency, attribute|
    raise NoCurrencyError.new("No currency is given for typecasting #{attribute}. Make sure a currency is present") unless currency
  end
end

#install_money_getter(attribute, options = {}) ⇒ Object

Installs a money getter

Since:

  • 0.9.0


54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
# File 'lib/exchange/typecasting.rb', line 54

def install_money_getter attribute, options={}
  
  define_method :"#{attribute}_with_exchange_typecasting" do
    currency = evaluate_money_option(options[:currency]) if options[:currency]
    
    test_for_currency_error(currency, attribute)
    
    time     = evaluate_money_option(options[:at]) if options[:at]
    
    if value = send(:"#{attribute}_without_exchange_typecasting")
      Exchange::Money.new(value) do |c|
        c.currency = currency
        c.time     = time if time
      end
    end
  end
  exchange_typecasting_alias_method_chain attribute
  
end

#install_money_option_evalObject

Since:

  • 0.9.0


108
109
110
111
112
# File 'lib/exchange/typecasting.rb', line 108

def install_money_option_eval
  define_method :evaluate_money_option do |option|
    option.is_a?(Proc) ? instance_eval(&option) : send(option)
  end
end

#install_money_setter(attribute, options = {}) ⇒ Object

Installs a money setter

Since:

  • 0.9.0


78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/exchange/typecasting.rb', line 78

def install_money_setter attribute, options={}
  define_method :"#{attribute}_with_exchange_typecasting=" do |data|
    att      = send(attribute)
    currency = evaluate_money_option(options[:currency])
    
    attribute_setter = :"#{attribute}_without_exchange_typecasting="
    
    send(attribute_setter, if !data.respond_to?(:currency)
      data
    elsif currency == data.currency
      data.value
    elsif currency != data.currency
      data.to(currency).value
    end)
  end
  exchange_typecasting_alias_method_chain attribute, '='
end

#money(*attributes, options = {}) ⇒ Object

installs a setter and a getter for the attribute you want to typecast as exchange money

Examples:

configure money with symbols, the currency option here will call the method currency in the object context

money :price, :currency => :currency, :time => :created_at

configure money with a proc, the proc will be called with the object as an argument. This is equivalent to the example above

money :price, :currency => lambda {|o| o.currency}, :time => lambda{|o| o.created_at}

Parameters:

  • attributes (Symbol)

    The attributes you want to typecast as money.

  • options (Hash) (defaults to: {})

    Pass a hash as last argument as options

Options Hash (options):

  • :currency (Symbol, Proc)

    The currency to evaluate the money with. Can be a symbol or a proc

  • :at (Symbol, Proc)

    The time at which the currency should be casted. All conversions of this currency will take place at this time

Raises:

  • (NoCurrencyError)

    if no currency option is given or the currency evals to nil

Since:

  • 0.9.0


135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
# File 'lib/exchange/typecasting.rb', line 135

def money *attributes
  
  options = attributes.last.is_a?(Hash) ? attributes.pop : {}
  
  attributes.each do |attribute|
    
    # Get the attribute typecasted into money 
    # @return [Exchange::Money] an instance of money
    #
    install_money_getter attribute, options
    
    # Set the attribute either with money or just any data
    # Implicitly converts values given that are not in the same currency as the currency option evaluates to
    # @param [Exchange::Money, String, Numberic] data The data to set the attribute to
    # 
    install_money_setter attribute, options
    
  end
  
  # Evaluates options given either as symbols or as procs
  # @param [Symbol, Proc] option The option to evaluate
  #
  install_money_option_eval
  
  # Evaluates whether an error should be raised because there is no currency present
  # @param [Symbol] currency The currency, if given
  #
  install_currency_error_tester
end

#test_for_currency_errorObject


117
118
119
120
121
# File 'lib/exchange/typecasting.rb', line 117

def install_currency_error_tester
  define_method :test_for_currency_error do |currency, attribute|
    raise NoCurrencyError.new("No currency is given for typecasting #{attribute}. Make sure a currency is present") unless currency
  end
end