exchange 0.11.0 → 0.12.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.travis.yml +1 -6
- data/README.rdoc +1 -1
- data/html.html +1 -0
- data/iso4217.yml +418 -256
- data/iso4217_country_map.yml +493 -0
- data/lib/exchange.rb +1 -1
- data/lib/exchange/base.rb +1 -1
- data/lib/exchange/cache/configuration.rb +32 -1
- data/lib/exchange/cache/memcached.rb +8 -0
- data/lib/exchange/cache/redis.rb +9 -1
- data/lib/exchange/configurable.rb +6 -1
- data/lib/exchange/core_extensions/float/error_safe.rb +1 -1
- data/lib/exchange/core_extensions/numeric/conversability.rb +1 -5
- data/lib/exchange/{iso_4217.rb → iso.rb} +71 -30
- data/lib/exchange/money.rb +12 -7
- data/lib/exchange/typecasting.rb +5 -5
- data/spec/exchange/cache/configuration_spec.rb +38 -0
- data/spec/exchange/cache/memcached_spec.rb +10 -0
- data/spec/exchange/core_extensions/numeric/conversability_spec.rb +3 -3
- data/spec/exchange/iso_spec.rb +795 -0
- data/spec/exchange/money_spec.rb +32 -13
- metadata +77 -93
- data/spec/exchange/iso_4217_spec.rb +0 -233
data/lib/exchange.rb
CHANGED
data/lib/exchange/base.rb
CHANGED
@@ -8,8 +8,33 @@ module Exchange
|
|
8
8
|
#
|
9
9
|
class Configuration < Exchange::Configurable
|
10
10
|
attr_accessor :expire, :host, :port, :path
|
11
|
+
|
12
|
+
class << self
|
13
|
+
|
14
|
+
def wipe_client_before_setting *setters
|
15
|
+
|
16
|
+
setters.each do |setter|
|
17
|
+
define_method :"#{setter}_with_client_wipe=" do |data|
|
18
|
+
wipe_subclass_client!
|
19
|
+
send(:"#{setter}_without_client_wipe=", data)
|
20
|
+
end
|
21
|
+
alias_method :"#{setter}_without_client_wipe=", :"#{setter}="
|
22
|
+
alias_method :"#{setter}=", :"#{setter}_with_client_wipe="
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
11
28
|
|
12
29
|
def_delegators :instance, :expire, :expire=, :host, :host=, :port, :port=, :path, :path=
|
30
|
+
wipe_client_before_setting :host, :port
|
31
|
+
|
32
|
+
# Overrides the parent class method to wipe the client before setting
|
33
|
+
#
|
34
|
+
def set hash
|
35
|
+
wipe_subclass_client!
|
36
|
+
super
|
37
|
+
end
|
13
38
|
|
14
39
|
def parent_module
|
15
40
|
Cache
|
@@ -18,7 +43,13 @@ module Exchange
|
|
18
43
|
def key
|
19
44
|
:cache
|
20
45
|
end
|
21
|
-
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def wipe_subclass_client!
|
50
|
+
subclass.wipe_client! if subclass && subclass.respond_to?(:wipe_client!)
|
51
|
+
end
|
52
|
+
|
22
53
|
end
|
23
54
|
end
|
24
55
|
end
|
@@ -14,6 +14,8 @@ module Exchange
|
|
14
14
|
#
|
15
15
|
class Memcached < Base
|
16
16
|
|
17
|
+
def_delegators :instance, :client, :wipe_client!
|
18
|
+
|
17
19
|
# instantiates a memcached client and memoizes it in a class variable.
|
18
20
|
# Use this client to access memcached data. For further explanation of use visit the memcached gem documentation
|
19
21
|
# @example
|
@@ -25,6 +27,12 @@ module Exchange
|
|
25
27
|
@client ||= Dalli::Client.new("#{config.host}:#{config.port}")
|
26
28
|
end
|
27
29
|
|
30
|
+
# Wipe the client instance variable
|
31
|
+
#
|
32
|
+
def wipe_client!
|
33
|
+
@client = nil
|
34
|
+
end
|
35
|
+
|
28
36
|
# returns either cached data from the memcached client or calls the block and caches it in memcached.
|
29
37
|
# This method has to be the same in all the cache classes in order for the configuration binding to work
|
30
38
|
# @param [Exchange::ExternalAPI::Subclass] api The API class the data has to be stored for
|
data/lib/exchange/cache/redis.rb
CHANGED
@@ -12,7 +12,9 @@ module Exchange
|
|
12
12
|
# c.cache_port = 'Your redis port (an Integer)'
|
13
13
|
# end
|
14
14
|
class Redis < Base
|
15
|
-
|
15
|
+
|
16
|
+
def_delegators :instance, :client, :wipe_client!
|
17
|
+
|
16
18
|
# instantiates a redis client and memoizes it in a class variable.
|
17
19
|
# Use this client to access redis data. For further explanation of use visit the redis gem documentation
|
18
20
|
# @example
|
@@ -24,6 +26,12 @@ module Exchange
|
|
24
26
|
@client ||= ::Redis.new(:host => config.host, :port => config.port)
|
25
27
|
end
|
26
28
|
|
29
|
+
# Wipe the client instance variable
|
30
|
+
#
|
31
|
+
def wipe_client!
|
32
|
+
@client = nil
|
33
|
+
end
|
34
|
+
|
27
35
|
# returns either cached data from the redis client or calls the block and caches it in redis.
|
28
36
|
# This method has to be the same in all the cache classes in order for the configuration binding to work
|
29
37
|
# @param [Exchange::ExternalAPI::Subclass] api The API class the data has to be stored for
|
@@ -12,12 +12,15 @@ module Exchange
|
|
12
12
|
def_delegators :instance, :subclass, :subclass=, :set
|
13
13
|
|
14
14
|
def subclass_with_constantize
|
15
|
-
self.subclass = parent_module.const_get camelize(self.subclass_without_constantize) unless self.subclass_without_constantize.is_a?(Class)
|
15
|
+
self.subclass = parent_module.const_get camelize(self.subclass_without_constantize) unless !self.subclass_without_constantize || self.subclass_without_constantize.is_a?(Class)
|
16
16
|
subclass_without_constantize
|
17
17
|
end
|
18
18
|
alias_method :subclass_without_constantize, :subclass
|
19
19
|
alias_method :subclass, :subclass_with_constantize
|
20
20
|
|
21
|
+
# Set a configuration via a hash of options
|
22
|
+
# @params [Hash] hash The hash of options to set the configuration to
|
23
|
+
#
|
21
24
|
def set hash
|
22
25
|
hash.each_pair do |k,v|
|
23
26
|
self.send(:"#{k}=", v)
|
@@ -26,6 +29,8 @@ module Exchange
|
|
26
29
|
self
|
27
30
|
end
|
28
31
|
|
32
|
+
# Reset the configuration to a set of defaults
|
33
|
+
#
|
29
34
|
def reset
|
30
35
|
set Exchange::Configuration::DEFAULTS[key]
|
31
36
|
end
|
@@ -19,7 +19,7 @@ module Exchange
|
|
19
19
|
def self.prevent_errors_with_exchange_for base, meth
|
20
20
|
base.send(:define_method, :"#{meth}without_errors", lambda { |other|
|
21
21
|
if other.is_a?(Exchange::Money)
|
22
|
-
BigDecimal.new(self.to_s).send(meth, other).to_f
|
22
|
+
BigDecimal.new(self.to_s).send(meth, other.value).to_f
|
23
23
|
else
|
24
24
|
send(:"#{meth}with_errors", other)
|
25
25
|
end
|
@@ -29,11 +29,7 @@ module Exchange
|
|
29
29
|
# @version 0.10
|
30
30
|
#
|
31
31
|
def in currency, options={}
|
32
|
-
|
33
|
-
Money.new(self, currency, options)
|
34
|
-
else
|
35
|
-
raise Exchange::NoCurrencyError.new("#{currency} is not a currency")
|
36
|
-
end
|
32
|
+
Money.new(self, currency, options)
|
37
33
|
end
|
38
34
|
end
|
39
35
|
end
|
@@ -10,7 +10,7 @@ module Exchange
|
|
10
10
|
# @since 0.3
|
11
11
|
# @author Beat Richartz
|
12
12
|
#
|
13
|
-
class
|
13
|
+
class ISO
|
14
14
|
include Singleton
|
15
15
|
extend SingleForwardable
|
16
16
|
|
@@ -24,38 +24,34 @@ module Exchange
|
|
24
24
|
self.class_eval <<-EOV
|
25
25
|
def #{op}(amount, currency, precision=nil)
|
26
26
|
minor = definitions[currency][:minor_unit]
|
27
|
-
(amount.is_a?(BigDecimal) ? amount : BigDecimal.new(amount.to_s,
|
27
|
+
(amount.is_a?(BigDecimal) ? amount : BigDecimal.new(amount.to_s, precision_for(amount, currency))).#{op}(precision || minor)
|
28
28
|
end
|
29
29
|
EOV
|
30
30
|
end
|
31
31
|
|
32
32
|
end
|
33
33
|
|
34
|
-
# The ISO 4217 that have to be loaded.
|
34
|
+
# The ISO 4217 that have to be loaded. Use this method to get to the definitions
|
35
35
|
# They are static, so they can be stored in a class variable without many worries
|
36
|
-
# @return [Hash] The
|
36
|
+
# @return [Hash] The iso4217 Definitions with the currency code as keys
|
37
37
|
#
|
38
38
|
def definitions
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
@definitions[k.downcase.to_sym] = v
|
49
|
-
end
|
50
|
-
|
51
|
-
@definitions
|
39
|
+
@definitions ||= symbolize_keys(YAML.load_file(File.join(ROOT_PATH, 'iso4217.yml')))
|
40
|
+
end
|
41
|
+
|
42
|
+
# A map of country abbreviations to currency codes. Makes an instantiation of currency codes via a country code
|
43
|
+
# possible
|
44
|
+
# @return [Hash] The ISO3166 (1 and 2) country codes matched to a currency
|
45
|
+
#
|
46
|
+
def country_map
|
47
|
+
@country_map ||= symbolize_keys(YAML.load_file(File.join(ROOT_PATH, 'iso4217_country_map.yml')))
|
52
48
|
end
|
53
49
|
|
54
50
|
# All currencies defined by ISO 4217 as an array of symbols for inclusion testing
|
55
51
|
# @return [Array] An Array of currency symbols
|
56
52
|
#
|
57
53
|
def currencies
|
58
|
-
@currencies ||= definitions.keys.
|
54
|
+
@currencies ||= definitions.keys.sort_by(&:to_s)
|
59
55
|
end
|
60
56
|
|
61
57
|
# Check if a currency is defined by ISO 4217 standards
|
@@ -63,7 +59,15 @@ module Exchange
|
|
63
59
|
# @return [Boolean] true if the symbol matches a currency, false if not
|
64
60
|
#
|
65
61
|
def defines? currency
|
66
|
-
currencies.include? currency
|
62
|
+
currencies.include?(country_map[currency] ? country_map[currency] : currency)
|
63
|
+
end
|
64
|
+
|
65
|
+
# Asserts a given argument is a currency. Tries to match with a country code if the argument is not a currency
|
66
|
+
# @param [Symbol, String] arg The argument to assert
|
67
|
+
# @return [Symbol] The matching currency as a symbol
|
68
|
+
#
|
69
|
+
def assert_currency! arg
|
70
|
+
defines?(arg) ? (country_map[arg] || arg) : raise(Exchange::NoCurrencyError.new("#{arg} is not a currency nor a country code matchable to a currency"))
|
67
71
|
end
|
68
72
|
|
69
73
|
# Use this to instantiate a currency amount. For one, it is important that we use BigDecimal here so nothing gets lost because
|
@@ -72,10 +76,15 @@ module Exchange
|
|
72
76
|
# @param [String, Symbol] currency The currency you want to instantiate the money in
|
73
77
|
# @return [BigDecimal] The instantiated currency
|
74
78
|
# @example instantiate a currency from a string
|
75
|
-
# Exchange::
|
79
|
+
# Exchange::ISO.instantiate("4523", "usd") #=> #<Bigdecimal 4523.00>
|
80
|
+
# @note Reinstantiation is not needed in case the amount is already a big decimal. In this case, the maximum precision is already given.
|
76
81
|
#
|
77
82
|
def instantiate(amount, currency)
|
78
|
-
|
83
|
+
if amount.is_a?(BigDecimal)
|
84
|
+
amount
|
85
|
+
else
|
86
|
+
BigDecimal.new(amount.to_s, precision_for(amount, currency))
|
87
|
+
end
|
79
88
|
end
|
80
89
|
|
81
90
|
# Converts the currency to a string in ISO 4217 standardized format, either with or without the currency. This leaves you
|
@@ -86,17 +95,18 @@ module Exchange
|
|
86
95
|
# @option opts [Boolean] :amount_only Whether you want to have the currency in the string or not
|
87
96
|
# @return [String] The formatted string
|
88
97
|
# @example Convert a currency to a string
|
89
|
-
# Exchange::
|
98
|
+
# Exchange::ISO.stringify(49.567, :usd) #=> "USD 49.57"
|
90
99
|
# @example Convert a currency without minor to a string
|
91
|
-
# Exchange::
|
100
|
+
# Exchange::ISO.stringif(45, :jpy) #=> "JPY 45"
|
92
101
|
# @example Convert a currency with a three decimal minor to a string
|
93
|
-
# Exchange::
|
102
|
+
# Exchange::ISO.stringif(34.34, :omr) #=> "OMR 34.340"
|
94
103
|
# @example Convert a currency to a string without the currency
|
95
|
-
# Exchange::
|
104
|
+
# Exchange::ISO.stringif(34.34, :omr, :amount_only => true) #=> "34.340"
|
96
105
|
#
|
97
106
|
def stringify(amount, currency, opts={})
|
98
107
|
format = "%.#{definitions[currency][:minor_unit]}f"
|
99
|
-
|
108
|
+
pre = [opts[:amount_only] && '', opts[:symbol] && (definitions[currency][:symbol] || currency.to_s.upcase), currency.to_s.upcase + ' '].detect{|a| a.is_a?(String)}
|
109
|
+
"#{pre}#{format % amount}"
|
100
110
|
end
|
101
111
|
|
102
112
|
# Use this to round a currency amount. This allows us to round exactly to the number of minors the currency has in the
|
@@ -104,7 +114,7 @@ module Exchange
|
|
104
114
|
# @param [BigDecimal, Fixed, Float, String] amount The amount of money you want to round
|
105
115
|
# @param [String, Symbol] currency The currency you want to round the money in
|
106
116
|
# @example Round a currency with 2 minors
|
107
|
-
# Exchange::
|
117
|
+
# Exchange::ISO.round("4523.456", "usd") #=> #<Bigdecimal 4523.46>
|
108
118
|
|
109
119
|
install_operation :round
|
110
120
|
|
@@ -113,7 +123,7 @@ module Exchange
|
|
113
123
|
# @param [BigDecimal, Fixed, Float, String] amount The amount of money you want to ceil
|
114
124
|
# @param [String, Symbol] currency The currency you want to ceil the money in
|
115
125
|
# @example Ceil a currency with 2 minors
|
116
|
-
# Exchange::
|
126
|
+
# Exchange::ISO.ceil("4523.456", "usd") #=> #<Bigdecimal 4523.46>
|
117
127
|
|
118
128
|
install_operation :ceil
|
119
129
|
|
@@ -122,13 +132,44 @@ module Exchange
|
|
122
132
|
# @param [BigDecimal, Fixed, Float, String] amount The amount of money you want to floor
|
123
133
|
# @param [String, Symbol] currency The currency you want to floor the money in
|
124
134
|
# @example Floor a currency with 2 minors
|
125
|
-
# Exchange::
|
135
|
+
# Exchange::ISO.floor("4523.456", "usd") #=> #<Bigdecimal 4523.46>
|
126
136
|
|
127
137
|
install_operation :floor
|
128
138
|
|
129
139
|
# Forwards the assure_time method to the instance using singleforwardable
|
130
140
|
#
|
131
|
-
def_delegators :instance, :definitions, :instantiate, :stringify, :round, :ceil, :floor, :currencies, :defines
|
141
|
+
def_delegators :instance, :definitions, :instantiate, :stringify, :round, :ceil, :floor, :currencies, :country_map, :defines?, :assert_currency!
|
142
|
+
|
143
|
+
private
|
144
|
+
|
145
|
+
# symbolizes keys and returns a new hash
|
146
|
+
#
|
147
|
+
def symbolize_keys hsh
|
148
|
+
new_hsh = Hash.new
|
149
|
+
|
150
|
+
hsh.each_pair do |k,v|
|
151
|
+
if v.is_a?(Hash)
|
152
|
+
v.keys.each do |key|
|
153
|
+
v[key.to_sym] = v.delete(key)
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
new_hsh[k.downcase.to_sym] = v
|
158
|
+
end
|
159
|
+
|
160
|
+
new_hsh
|
161
|
+
end
|
162
|
+
|
163
|
+
# get a precision for a specified amount and a specified currency
|
164
|
+
# @params [Float, Integer] amount The amount to get the precision for
|
165
|
+
# @params [Symbol] currency the currency to get the precision for
|
166
|
+
#
|
167
|
+
def precision_for amount, currency
|
168
|
+
defined_minor_precision = definitions[currency][:minor_unit]
|
169
|
+
given_major_precision, given_minor_precision = amount.to_s.match(/^-?(\d*)\.?(\d*)$/).to_a[1..2].map(&:size)
|
170
|
+
|
171
|
+
given_major_precision + [defined_minor_precision, given_minor_precision].max
|
172
|
+
end
|
132
173
|
|
133
174
|
end
|
134
175
|
end
|
data/lib/exchange/money.rb
CHANGED
@@ -48,14 +48,16 @@ module Exchange
|
|
48
48
|
# Exchange::Money.new(40, :usd).to(:eur, :at => Time.gm(2012,9,1))
|
49
49
|
# #=> #<Exchange::Money @number=37.0 @currency=:usd @time=#<Time> @from=#<Exchange::Money @number=40.0 @currency=:usd>>
|
50
50
|
#
|
51
|
-
def initialize value, currency_arg=nil, opts={}, &block
|
51
|
+
def initialize value, currency_arg=nil, opts={}, &block
|
52
|
+
currency_arg = ISO.assert_currency!(currency_arg) if currency_arg
|
53
|
+
|
52
54
|
@from = opts[:from]
|
53
55
|
@api = Exchange.configuration.api.subclass
|
54
56
|
|
55
57
|
yield(self) if block_given?
|
56
58
|
|
57
59
|
self.time = Helper.assure_time(time || opts[:at], :default => :now)
|
58
|
-
self.value =
|
60
|
+
self.value = ISO.instantiate(value, currency || currency_arg)
|
59
61
|
self.currency = currency || currency_arg
|
60
62
|
end
|
61
63
|
|
@@ -81,6 +83,8 @@ module Exchange
|
|
81
83
|
# Exchange::Money.new(40,:nok).to(:sek, :at => Time.gm(2012,2,2))
|
82
84
|
#
|
83
85
|
def to other, options={}
|
86
|
+
other = ISO.assert_currency!(other)
|
87
|
+
|
84
88
|
if api_supports_currency?(other)
|
85
89
|
opts = { :at => time, :from => self }.merge(options)
|
86
90
|
Money.new(api.new.convert(value, currency, other, opts), other, opts)
|
@@ -88,6 +92,7 @@ module Exchange
|
|
88
92
|
raise_no_rate_error(other)
|
89
93
|
end
|
90
94
|
end
|
95
|
+
alias :in :to
|
91
96
|
|
92
97
|
class << self
|
93
98
|
|
@@ -98,7 +103,7 @@ module Exchange
|
|
98
103
|
#
|
99
104
|
def install_operation op
|
100
105
|
define_method op do |*precision|
|
101
|
-
Exchange::Money.new(
|
106
|
+
Exchange::Money.new(ISO.send(op, self.value, self.currency, precision.first), currency, :at => time, :from => self)
|
102
107
|
end
|
103
108
|
end
|
104
109
|
|
@@ -110,7 +115,7 @@ module Exchange
|
|
110
115
|
self.class_eval <<-EOV
|
111
116
|
def #{op}(other)
|
112
117
|
test_for_currency_mix_error(other)
|
113
|
-
new_value = value #{op} (other.kind_of?(Money) ? other.to(self.currency, :at => other.time) : BigDecimal.new(other.to_s))
|
118
|
+
new_value = value #{op} (other.kind_of?(Money) ? other.to(self.currency, :at => other.time).value : BigDecimal.new(other.to_s))
|
114
119
|
Exchange::Money.new(new_value, currency, :at => time, :from => self)
|
115
120
|
end
|
116
121
|
EOV
|
@@ -292,12 +297,12 @@ module Exchange
|
|
292
297
|
# @example Convert a currency with a three decimal minor to a string
|
293
298
|
# Exchange::Money.new(34.34, :omr).to_s #=> "OMR 34.340"
|
294
299
|
# @example Convert a currency to a string without the currency
|
295
|
-
# Exchange::
|
300
|
+
# Exchange::ISO.stringif(34.34, :omr).to_s(:iso) #=> "34.340"
|
296
301
|
#
|
297
302
|
def to_s format=:currency
|
298
303
|
[
|
299
|
-
format == :currency &&
|
300
|
-
format == :amount &&
|
304
|
+
format == :currency && ISO.stringify(value, currency),
|
305
|
+
format == :amount && ISO.stringify(value, currency, :amount_only => true)
|
301
306
|
].detect{|l| l.is_a?(String) }
|
302
307
|
end
|
303
308
|
|
data/lib/exchange/typecasting.rb
CHANGED
@@ -77,13 +77,13 @@ module Exchange
|
|
77
77
|
att = send(attribute)
|
78
78
|
attribute_setter = :"#{attribute}_without_exchange_typecasting="
|
79
79
|
|
80
|
-
if !data.respond_to?(:currency)
|
81
|
-
|
80
|
+
send(attribute_setter, if !data.respond_to?(:currency)
|
81
|
+
data
|
82
82
|
elsif att.currency == data.currency
|
83
|
-
|
83
|
+
data.value
|
84
84
|
elsif att.currency != data.currency
|
85
|
-
|
86
|
-
end
|
85
|
+
data.to(att.currency).value
|
86
|
+
end)
|
87
87
|
end
|
88
88
|
exchange_typecasting_alias_method_chain attribute, '='
|
89
89
|
end
|
@@ -39,6 +39,44 @@ describe "Exchange::Cache::Configuration" do
|
|
39
39
|
end
|
40
40
|
end
|
41
41
|
|
42
|
+
describe "setting and wiping the client" do
|
43
|
+
context "with a wipeable client" do
|
44
|
+
before(:each) do
|
45
|
+
subject.subclass = :memcached
|
46
|
+
subject.host = '127.0.0.1'
|
47
|
+
subject.port = 11211
|
48
|
+
end
|
49
|
+
after(:each) do
|
50
|
+
subject.subclass = :no_cache
|
51
|
+
end
|
52
|
+
it "should do so for the host" do
|
53
|
+
subject.subclass.client.should_not be_nil
|
54
|
+
subject.subclass.instance.instance_variable_get("@client").should_not be_nil
|
55
|
+
subject.host = 'new'
|
56
|
+
subject.subclass.instance.instance_variable_get("@client").should be_nil
|
57
|
+
end
|
58
|
+
it "should do so for the port" do
|
59
|
+
subject.subclass.client.should_not be_nil
|
60
|
+
subject.subclass.instance.instance_variable_get("@client").should_not be_nil
|
61
|
+
subject.port = 112
|
62
|
+
subject.subclass.instance.instance_variable_get("@client").should be_nil
|
63
|
+
end
|
64
|
+
end
|
65
|
+
context "without a wipeable client" do
|
66
|
+
before(:each) do
|
67
|
+
subject.subclass = :memory
|
68
|
+
end
|
69
|
+
it "should not fail for the host" do
|
70
|
+
subject.host = 'new'
|
71
|
+
subject.host.should == 'new'
|
72
|
+
end
|
73
|
+
it "should not fail for the port" do
|
74
|
+
subject.port = 11
|
75
|
+
subject.port.should == 11
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
42
80
|
describe "reset" do
|
43
81
|
before(:each) do
|
44
82
|
subject.set :subclass => :no_cache, :expire => :daily, :host => 'localhost', :port => 112211, :path => "PATH"
|